Pull-through cache for Docker images
Pull once.
Never twice.
Stashito sits between your machines and your upstream registries — Docker Hub, GHCR, Quay, anything OCI. The first pull fetches an image from upstream and keeps every layer on disk — every pull after that is served from your own network. No rate limits, no wasted bandwidth, no waiting on the internet.
free · source-available · single Go binary · ☕ buy me a coffee
Why bother
The same layers, over and over
Every CI job, every homelab node, every rebuilt VM pulls the same base images from the same registry across the same internet connection.
Rate limits stop hurting
Docker Hub caps anonymous pulls. Behind Stashito, upstream sees one pull per image — your fleet can hammer the cache all day.
LAN speed, not WAN speed
Cached layers come off local disk over your own network. Pulling a ~150 MB image takes seconds, not minutes.
Survives a dead internet
Images you've pulled before keep working when your uplink — or the registry — doesn't. Deploys don't wait on someone else's outage.
How it works
A registry that remembers
Stashito speaks the OCI Distribution Spec — the same HTTP API every registry speaks. Docker talks to Stashito like any registry; Stashito only talks to upstream when it has to.
Your machines
docker, CI runners, k8s nodes — anything that pulls images.
Stashito
Checks its filesystem cache for the manifest and each blob. Hits are served straight from disk.
Upstream registry
Docker Hub, GHCR, Quay, GAR, ACR — sees each manifest and blob once. Then never again.
Run it
Two minutes to a warm cache
1 start stashito
# docker-compose.yml services: stashito: image: stashito environment: PORT: "8080" STORAGE_PATH: "/data/stashito" LOG_LEVEL: "info" TAG_TTL: "60s" UPSTREAM_DOCKERHUB_HOST: "registry-1.docker.io" volumes: - stashito_data:/data/stashito ports: - "8080:8080" volumes: stashito_data:
2 pull through it
# prefix the image path with the upstream docker pull localhost:8080/dockerhub/library/postgres:16 docker pull localhost:8080/dockerhub/library/redis:7
The first segment names an upstream you configured —
dockerhub here maps to UPSTREAM_DOCKERHUB_HOST.
Everything after it is the ordinary image path.
First pull fills the cache; every later pull, from any machine that can
reach Stashito, is local.
Config
A handful of variables. That's it.
- PORT
- HTTP port Stashito listens on.
- STORAGE_PATH
- Directory where cached manifests and blobs live. Point it at a volume you're happy to let grow.
- LOG_LEVEL
debug,info,warnorerror.- TAG_TTL
- How long a cached tag is served without checking upstream for a newer
digest. Go duration, e.g.
60s. Digests and blobs are immutable and never revalidated. - UPSTREAM_<ALIAS>_HOST
- One per upstream registry. The lowercased alias becomes the image-path
prefix. Add
_USERNAME/_PASSWORDfor private registries — GHCR, Quay, GAR and ACR all work.
Everything is explicit — Stashito never guesses defaults for you.