···518518##### Alpine Preset
519519520520Add [`workarounds:doNotUpgradeFromAlpineStableToEdge`](https://docs.renovatebot.com/presets-workarounds/#workaroundsdonotupgradefromalpinestabletoedge) to the `renovate.json` `extends` list to prevent PRs that try to upgrade alpine images.
521521+522522+## (Optional) Reducing Registry API Calls with Caching
523523+524524+If you have a *very large* homelab, say 50+ stacks or 70+ images total, you may want to consider adding a caching layer between Renovate and upstream registries.
525525+526526+Dockerhub already has pretty restrictive rate limiting and quotas per day. Using a caching layer, especially if you end up pinning many images to digests, can help speed up Renovate's duration and drastically reduce calls to the registry and avoid rate limiting. This is especially useful when first creating your renovate config as you may be invoking Renovate many times to observe created PRs and iterating on your config.
527527+528528+> If you don't want to go to the trouble of caching during initial renovate config iteration/setup then I would suggest creating a *testing* repository to have Renovate run on. Include only a few stacks with all the image update scenarios you want to detect and use that to iterate on config building, rather than using your entire homelab monorepo as the testing grounds.
529529+{: .prompt-tip}
530530+531531+When Renovate is fetching updates it is making plain HTTP/S calls to the upstream registries *and not* using the Docker Daemon API. Therefore, we can't use existing docker registry proxies transparently.
532532+533533+Instead, we will use [CNCF's `distribution`](https://distribution.github.io/distribution/) image as a [pull through cache](https://distribution.github.io/distribution/recipes/mirror) in order to cache image manifest information from [each upstream registry](https://distribution.github.io/distribution/recipes/mirror/#gotcha) we want to cache for.
534534+535535+In this example I am using `distribution` as a cache for Dockerhub and setting up the container behind Traefik as the reverse proxy. In a docker compose stack:
536536+537537+```yaml
538538+services:
539539+ dockerio-distribution-mirror:
540540+ image: distribution/distribution:latest
541541+ networks:
542542+ - traefik_overlay
543543+ - default
544544+ volumes:
545545+ # file store for cached data
546546+ - ./distribution-proxy/registries/dockerio:/var/lib/registry
547547+ labels:
548548+ traefik.enable: true
549549+ # URL to be used for dockerhub registry mirror
550550+ traefik.http.routers.distribution-docker.rule: Host(`registry-docker.example.com`)
551551+ traefik.http.services.distribution-docker.loadbalancer.server.port: 5000
552552+ traefik.docker.network: internal_overlay
553553+ environment:
554554+ REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io # the upstream registry to cache
555555+ REGISTRY_PROXY_USERNAME: foxxmd
556556+ REGISTRY_PROXY_PASSWORD: ${DOCKERHUB_PASSWORD}
557557+ REGISTRY_PROXY_TTL: 12h # how long to cache manifests for
558558+ REGISTRY_TAGS_MAXTAGS: 10000 # REQUIRED for use with renovatebot
559559+560560+ # valkey service and config below is optional
561561+ REGISTRY_REDIS_ADDRS: "[distribution-valkey:6379]"
562562+ REGISTRY_STORAGE_DELETE_ENABLED: true
563563+ REGISTRY_STORAGE_CACHE_BLOBDESCRIPTOR: redis
564564+ distribution-valkey:
565565+ image: valkey/valkey:9.0.3
566566+ networks:
567567+ - default
568568+ volumes:
569569+ - ./distribution-proxy/redis:/data
570570+```
571571+572572+Next, in `renovate.json` we add [`registryAliases`](https://docs.renovatebot.com/configuration-options/#registryaliases) to `docker-compose` to tell Renovate that when it sees the `docker.io` registry in an image it should instead use our mirror:
573573+574574+```json
575575+"registryAliases": {
576576+ "index.docker.io": "registry-docker.example.com",
577577+ "docker.io": "registry-docker.example.com"
578578+}
579579+```
580580+{: file='docker-compose in renovate.json'}
581581+582582+EX: For `image: docker.io/library/redis:7` it should instead use `registry-docker.example.com/library.redis:7`
583583+584584+Finally, we give an explicit hint to Renovate what the default registry is by configuring [`registryUrls`](https://docs.renovatebot.com/configuration-options/#registryurls). Without this config Renovate will still try to use `docker.io/...` when no registry prefix is present. The `registryAliases` config above only tells it what to do when the prefix is *explicitly* in the image.
585585+586586+Add to **the beginning** of `packageRules`:
587587+588588+```json
589589+{
590590+ "matchDatasources": ["docker"],
591591+ "registryUrls": [
592592+ "https://registry-docker.example.com"
593593+ ]
594594+}
595595+```
596596+{: file='docker-compose.packageRules in renovate.json'}
597597+598598+> To cache for more registries you will need to:
599599+>
600600+> * Add an additional compose service for each registry
601601+> * Add a new mapping to `registryAliases`
602602+{: .prompt-tip}