dqzboy/Docker-Proxy: a self-hosted registry mirror with a web control panel
自建 Docker 镜像加速与管理服务。零磁盘缓存、可视化面板、支持上游账号认证,支持一键部署Docker、K8s、Quay、Ghcr、Mcr、elastic、nvcr等镜像加速
At a glance
- What is it?
- Docker-Proxy is a Go registry reverse proxy plus a Node.js admin UI that routes pulls to Docker Hub, GHCR, Quay, K8s, MCR, Elastic and NVCR by Host header. The README claims zero disk cache, which is true only while cache.enabled stays false.
- Who is it for?
- Adopt it if you run a server outside mainland China, want one Host-routed endpoint for Docker Hub, GHCR, Quay, K8s, MCR, Elastic and NVCR, and are willing to manage the .env secrets yourself. Do not adopt it if you need a disk-backed registry mirror with guaranteed repeat pulls, or if you cannot expose port 5001 to the UI only.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 27, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The pull-rate problem dqzboy/Docker-Proxy is built around
Anyone who has pulled a base image across a slow or rate-limited link has hit the same wall: the registry you need is not the registry you can reach quickly, and Docker Hub throttles anonymous pulls. The usual workaround is a public mirror, which means trusting someone else's uptime and someone else's logging. dqzboy/Docker-Proxy takes the other route. You run the mirror yourself on a server outside mainland China, and the project's README is explicit that the host should be one that is not blocked, with no ICP filing needed for the domain.
The intended user is a self-hoster or a small platform team that already runs Docker somewhere and wants a single endpoint in front of several upstream registries. The README lists Docker Hub, GHCR, Quay, K8s, MCR, Elastic and NVCR as the routed upstreams. That list matters more than the proxy itself: most people need two or three of those, and stitching them together by hand means separate configs, separate auth, and separate TLS certificates.
Host-based routing, token exchange and the zero-disk claim
The architecture is two processes plus an optional reverse proxy. The first is go-proxy, a Go service that listens on :5000 for the OCI registry path /v2/ and on :5001 for a management API with the endpoints /-/healthz, /-/config, /-/reload, /-/stats and /-/credentials. The README states that the management port is meant for the internal network only. The second is hubcmdui, a Node.js panel that talks to go-proxy over GO_PROXY_ADMIN_URL, which docker-compose.yaml sets to http://go-proxy:5001.
Routing works on the Host header. A single process inspects the incoming request and forwards it to the matching public registry, so one IP and one certificate can serve several upstreams. Authentication is handled server-side: when you configure upstream credentials, the proxy exchanges them for a Bearer Token and uses that to pull private Docker Hub images and to reduce the effect of the official rate limit. The README describes the transfer as streaming, with nothing written to disk.
That zero-disk claim deserves a caveat the README itself supplies. docker-compose.yaml mounts ./data/go-proxy-cache into the container at /app/cache and notes that the volume is written only when caching is enabled, since the default configuration has cache.enabled=false. So the headline feature is a default, not an invariant. Turn caching on and you are back to managing a disk-backed mirror, with the eviction and growth questions that come with it.
Installing dqzboy/Docker-Proxy and reaching the admin panel
The shortest path is the compose file in the repository root. Download docker-compose.yaml, keep it next to a .env, and bring the stack up:
docker compose up -dThe compose file defines two services, go-proxy and hubcmd-ui, on a shared registry-net network. It publishes 50000 on the host to the proxy's 5000, and 30080 to the UI's 3000. Because the environment block falls back to ${GO_PROXY_ADMIN_TOKEN:-change-me-to-a-strong-random-token}, a bare compose up starts with a placeholder token, which the management API rejects at startup. The .env.example file is the template for the two secrets:
cp .env.example .envAfter the containers are healthy, the README says the panel is at http://<server-ip>:30080/admin, with the default account root and password admin@123. The README asks you to change both immediately; the UI is documented as showing a password-change prompt on first login.
There is also an interactive installer at install/DockerProxy_Install.sh. On a Debian or Ubuntu host you install curl and run it:
apt -y install curl
bash -c "$(curl -fsSL https://raw.githubusercontent.com/dqzboy/Docker-Proxy/main/install/DockerProxy_Install.sh)"The script checks for and installs Docker and Docker Compose, generates a random GO_PROXY_ADMIN_TOKEN into .env, and optionally renders an Nginx or Caddy reverse proxy. The README offers a jsDelivr CDN URL and a ghp.ci GitHub proxy URL as alternatives for networks where raw.githubusercontent.com is slow. Choose Caddy in the menu and HTTPS is configured for you; choose Nginx and you supply your own certificate.
Where the design bites back
The admin token check is the sharpest constraint in the project. The README says startup fails outright if GO_PROXY_ADMIN_TOKEN is a placeholder such as change-me, admin or an empty string, or if it is shorter than 16 characters. That is a sensible guard, but it turns a missing .env into a container that will not come up, and the error surfaces at process start rather than at request time.
Configuration persistence has a related trap. The config lives on the host at ./config/go-proxy/ and inside the container at /app/config.d/config.yaml. On first start, if no host file exists, the container seeds one from the image default. To reset to defaults you delete ./config/go-proxy/config.yaml and recreate the container. The README does not document a rollback path for a configuration change made through the panel, so treat the host file as the thing to back up.
The panel mounts /var/run/docker.sock into hubcmd-ui. That is what lets it show container state and manage containers, and it is also the broadest permission in the stack: anything that compromises the UI has the same Docker access. The README does not describe a socket proxy or a read-only socket option. If your threat model does not accept that, run the compose file without the hubcmd-ui service and drive go-proxy through its management API instead.
Finally, the whole model assumes the server is reachable from the clients that pull images. A mirror that is itself behind the same restrictive network it was meant to bypass solves nothing.
How it differs from a plain Nginx or Caddy reverse proxy
The obvious alternative is a hand-written Nginx or Caddy config in front of each upstream registry. That approach is well understood and needs no extra process, but it puts registry-specific work on you: the token exchange for private Docker Hub pulls, the per-registry Host rewriting, and the credential handling all become your config. Docker-Proxy bundles those into one binary with a config file and a UI.
A second comparison point is the registry mirror built into Docker itself, configured through daemon.json. That path is narrower. It typically points at one mirror endpoint for Docker Hub, and it does not give you a panel, per-registry credentials, IP allow and deny lists, or traffic dashboards. dqzboy/Docker-Proxy is aimed at the case where you want several upstreams and want to see what is being pulled.
The trade-off is process count and moving parts. Nginx is already on many hosts. Docker-Proxy adds a Go service, a Node.js service, a SQLite database under ./data/hubcmd-ui, and a Docker socket mount. If all you need is to make one registry faster, that is a lot of surface area for the job.
Maintenance, licensing and upgrade mechanics
The repository is not archived, and the last push was on 2026-09-22, with releases v5.1.9 on 2026-09-22, v5.1.8 on 2026-09-09 and v5.1.7 on 2026-09-03. That is a steady release cadence, and the project ships both docker-compose.yaml and docker-compose-build.yaml, the latter for building images locally.
The licence is Apache-2.0. That permits commercial use and modification, and it includes an explicit patent grant and a requirement to state changes. It is not a copyleft licence, so linking or shipping the code does not obligate you to publish your own source. This is a description of the licence text, not legal advice; if you redistribute the images or embed the panel in a product, have counsel read the NOTICE and attribution requirements.
Upgrade cost is mostly about configuration drift. The README's reset procedure (delete ./config/go-proxy/config.yaml, recreate the container) means a bad config is recoverable, but any panel-side settings you made are lost with it. The UI's own runtime data lives in ./data/hubcmd-ui, so a UI container replacement keeps the SQLite state as long as that volume is intact. Note that changing SESSION_SECRET invalidates every existing login session, which .env.example states directly.
Editorial conclusion
Adopt it if you run a server outside mainland China, want one Host-routed endpoint for Docker Hub, GHCR, Quay, K8s, MCR, Elastic and NVCR, and are willing to manage the .env secrets yourself. Do not adopt it if you need a disk-backed registry mirror with guaranteed repeat pulls, or if you cannot expose port 5001 to the UI only. Before rollout, verify that your GO_PROXY_ADMIN_TOKEN and SESSION_SECRET are not the placeholder values from .env.example, since the proxy refuses to start on a placeholder or short admin token.
Frequently asked questions
What is dqzboy/Docker-Proxy?
It is a self-hosted Docker image acceleration and management service. A Go process routes requests by Host header to Docker Hub, GHCR, Quay, K8s, MCR, Elastic and NVCR, and a web panel called HubCMD-UI manages the proxy and server settings.
How do I set up dqzboy/Docker-Proxy?
Download docker-compose.yaml and run docker compose up -d, or run the interactive installer at install/DockerProxy_Install.sh. The README says the panel is then reachable at http://<server-ip>:30080/admin.
Where is the dqzboy/Docker-Proxy configuration file?
It is mounted from the host directory ./config/go-proxy/ and appears inside the container at /app/config.d/config.yaml. On first start with no host file present, the container seeds one from the default built into the image.
Can I use Nginx as a reverse proxy in front of dqzboy/Docker-Proxy?
Yes. The one-click installer can deploy Nginx or Caddy and render the matching configuration, including HTTPS and Host rewriting. The README notes that choosing Nginx means you provide your own SSL certificate, while Caddy configures HTTPS automatically.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/dqzboy-docker-proxy)