June 2, 2025
4 min read time

How to cache container images in a self-hosted environment

Last updated: November 2nd 2026

To cache container images in a self-hosted environment, run a pull-through cache between your clients and your registries. The cache stores image layers and manifests on the first pull and serves them locally after that. Varnish Virtual Registry (formerly Varnish Orca) does this for Docker Hub, private registries and Kubernetes clusters. You deploy it on your own infrastructure and point Docker or containerd at it.

Why cache container images?

CI pipelines and Kubernetes nodes pull the same base images over and over. If a parallel build pulls a 40 MB base image 100 times, that’s around 4 GB of identical traffic to your registry from a single burst. Without a cache, that repetition causes:

  • Slow job starts, because every runner waits on the same downloads.
  • Rate limits, because Docker Hub throttles anonymous pulls per IP address.
  • Registry load, because shared registries slow down when build surges hit them in parallel.
  • Egress costs, because the same layers cross the network again and again.

What are your options for caching images?

Option What it does Trade-off
Docker’s open-source registry in proxy mode Pull-through cache for one upstream registry One upstream per instance; no access-control checks against private registries
Harbor proxy cache projects Caches images inside a Harbor installation Requires running and maintaining Harbor
Artifactory or Nexus remote repositories Proxies upstream registries inside your repository manager Adds load to the repository manager you may be trying to protect
A virtual registry in front of your registries Caches pulls from Docker Hub and private registries close to your runners Extra component to deploy; tags are still checked upstream (see below)

How does Virtual Registry cache container images?

Virtual Registry sits between your clients and your registries as a pull-through cache:

  • Layers are cached once. Layers are identified by their SHA digest, so a layer shared by many images is stored and served once.
  • Tags stay current. A tag like :latest can change, so its manifest is checked with the upstream registry on every request by default. Digest-pinned images never change, so they’re cached long term.
  • Private images keep their access control. Before serving a private image from cache, Virtual Registry checks with the registry that the user has pull access, even if the whole image is already cached. This works automatically.
  • Docker Hub outages are absorbed. The default configuration falls back to Google’s Docker Hub mirror if Docker Hub is unavailable.
  • Rate limits can be lifted. You can configure a Docker Hub account so pulls count against that account’s limit rather than the anonymous per-IP limit.

How do you set it up?

  1. Deploy Virtual Registry close to your runners or cluster. It’s available as a Docker image, a Helm chart, and DEB and RPM packages. Configuration is a single config.yaml file, and the default configuration already includes Docker Hub.
  2. Point your clients at it. For Docker, set Virtual Registry as a registry mirror in the Docker daemon configuration. For Kubernetes, add it as a mirror in containerd’s hosts.toml.
  3. Pull as normal. The first pull fills the cache, and later pulls are served from it.

Step-by-step guides: Docker cache tutorial and using Virtual Registry as a bootstrap cache for Kubernetes.

What does a pull-through cache not do?

  • It doesn’t cache pushes. Images you push go straight through to the registry and are cached when they’re first pulled.
  • It doesn’t remove every upstream request. Tag lookups are checked with the registry on every request by default, although these checks are lightweight.
  • It needs client configuration. Docker’s registry-mirror setting only applies to Docker Hub images. Images from other registries need their address changed, or a DNS change, to go through the cache.

FAQ

Can I cache images from private registries?

Yes. Virtual Registry checks each user’s pull access with the registry before serving a cached image, so access control is kept without separate cached copies per user.

Will cached images go stale?

Not by default. Tags are checked with the registry on every request, so a changed :latest is picked up immediately. Digest-pinned images never change.

Does it help with Docker Hub rate limits?

Yes, in two ways. Repeat pulls are served from cache, and you can configure a Docker Hub account so pulls no longer count against the anonymous per-IP limit.

Does it work with Kubernetes?

Yes. Configure containerd on each node to use Virtual Registry as a mirror, and image pulls during scale-ups are served from the cache.

Next steps

Follow the Docker cache tutorial, see how Varnish Virtual Registry fits your software delivery and CI/CD pipeline, or talk to an expert.

Running Artifactory as well? See how to reduce load on Artifactory without adding nodes.