# Stashito > Free, open-source pull-through cache for Docker/OCI images. Pull once — > every later pull is served from your own disk, over your own network. Stashito is a caching registry proxy — a pull-through cache, or registry mirror. It implements the OCI Distribution Spec, so docker, containerd and podman pull through it unchanged, and any OCI registry can sit upstream: Docker Hub, GHCR, Quay, Google Artifact Registry, Azure ACR. Ships as a single Go binary, distributed as the Docker image `rcm7/stashito`. Why run it: dodge Docker Hub rate limits (upstream sees one pull per image), LAN-speed pulls for CI and homelabs, deploys keep working through registry outages or a dead uplink, and images stay deployable after they vanish upstream — a yanked tag, a deleted repo, a left-pad moment. ## Run it ```yaml services: stashito: image: rcm7/stashito environment: PORT: "8080" STORAGE_PATH: "/data/stashito" LOG_LEVEL: "info" LOG_FORMAT: "text" TAG_TTL: "60s" UPSTREAM_DOCKERHUB_HOST: "registry-1.docker.io" volumes: - stashito_data:/data/stashito ports: - "8080:8080" volumes: stashito_data: ``` Or a single command: ```sh docker run -d --name stashito -p 8080:8080 \ -v stashito_data:/data/stashito \ -e PORT=8080 -e STORAGE_PATH=/data/stashito \ -e LOG_LEVEL=info -e LOG_FORMAT=text -e TAG_TTL=60s \ -e UPSTREAM_DOCKERHUB_HOST=registry-1.docker.io \ rcm7/stashito ``` ## Pull through it ```sh docker pull localhost:8080/dockerhub/library/postgres:16 ``` The first path segment is the lowercased `` from an `UPSTREAM__HOST` variable. Everything after it is the ordinary image path on that upstream. ## Configuration All env vars are required unless marked optional. No other defaults. - `PORT` — HTTP listen port. - `STORAGE_PATH` — filesystem root for cached data. - `LOG_LEVEL` — `debug`, `info`, `warn` or `error`. - `LOG_FORMAT` — `text` or `json`; `json` emits structured logs for machine parsing. - `TAG_TTL` — Go duration (e.g. `60s`). Tag manifests are served from cache without upstream revalidation within this window; after it expires the next request revalidates via upstream HEAD (digest compare). Digest manifests and blobs are immutable and never revalidated. - `UPSTREAM__HOST` — one per upstream registry host (e.g. `registry-1.docker.io`). At least one required. - `UPSTREAM__USERNAME` / `_PASSWORD` — optional basic-auth pair for private upstreams. Docker Hub / GHCR / Quay: username + PAT or robot token. GAR: `_json_key` + service account JSON key. ACR: service principal id + secret. AWS ECR not supported yet (rotating credentials). - `METRICS_ENABLED` — optional, default `false`. `true` exposes Prometheus metrics at `GET /metrics` (`stashito_` prefix): cache hits/misses, upstream requests, HTTP totals and latency, storage size. A Grafana dashboard ships in the repo (`grafana/dashboard.json`). - `METRICS_PORT` — optional. Serve `/metrics` on this separate port; unset serves it on `PORT`. ## Behavior - Cache hits are served from disk without contacting upstream. - If upstream is unreachable, cached content is served stale. - Layers stay cached even if the image is later deleted upstream. ## Endpoints - `GET /healthz` — JSON health check: `status` (`ok` or `degraded`), configured `upstreams`, `storage_path`, `storage_writable`; `503` when degraded. - `GET /v2/` — OCI version check; `200` means the instance is up. - `GET/HEAD /v2//manifests/` — manifest by tag or digest. - `GET/HEAD /v2//blobs/` — blob (layer/config data). - `GET /metrics` — Prometheus metrics; only when `METRICS_ENABLED=true`, on `METRICS_PORT` when set. ## Links - Website: https://stashito.com - Docker image: https://hub.docker.com/r/rcm7/stashito - License: GNU AGPL-3.0 — free to use, copy, modify and distribute; running a modified version as a network service requires offering its source to that service's users.