You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
On the repository page (tag list), each tag row shows the full docker pull <registry>/<group>/<repo>:<tag> command with a Copy button.
Registry URL is taken from VITE_REGISTRY_URL when set; otherwise the current host in production or localhost:5000 in development.
Optional env: see .env.example for VITE_REGISTRY_URL.
Nginx template: registry proxy
/v2 location proxies to the backend with:
proxy_request_buffering off – streams large PATCH bodies (layer uploads) instead of buffering, reducing server-to-server push retries.
client_max_body_size 0 – no upload size limit.
Long timeouts (900s) for connect, send, and read.
Use this when exposing the registry via the frontend (e.g. NPM → refity-frontend → backend).
Backend
Docker push from same host (connection reuse)
Fix: When the Docker daemon and Refity registry run on the same host, docker push could retry on the first layer; the POST (initiate blob
upload) succeeded but the following PATCH (upload blob) did not reach the handler.
Cause: Docker reuses the same TCP connection for POST then PATCH. The handler did not read the POST body, which can break connection reuse
for the next request.
Change: The initiate-blob-upload handler now drains the request body (io.Copy(io.Discard, r.Body) and r.Body.Close()) before handling,
so the connection is ready for the PATCH.
No API or config change; upgrade and redeploy to benefit.
Fix:docker push through a reverse proxy (e.g. Cloudflare → Nginx Proxy Manager → Refity) failed with short copy: wrote 1 of 2294 while
pushing via direct IP worked fine.
Cause: Three issues combined:
Absolute Location URLs – Upload handlers returned Location: https://host/v2/... with scheme and host. If the proxy didn't set X-Forwarded-Proto correctly or the scheme mismatched, the Docker client followed the Location to the wrong endpoint and the connection was reset
after 1 byte.
Monolithic uploads ignored in async mode – Docker sends small blobs (config, ~2 KB) via POST /v2/.../uploads/?digest=sha256:...
(monolithic). The handler only accepted this when SFTP_SYNC_UPLOAD=true; in the default async mode it discarded the body and returned 202,
forcing an unnecessary PATCH round-trip that could fail through proxies.
Manual 100-Continue – The PATCH handler called w.WriteHeader(100) manually, which interfered with Nginx's own Expect: 100-continue
handling and could produce duplicate or garbled interim responses.
Changes:
All Location headers now use relative paths (/v2/...) instead of absolute URLs — matches the official Docker Distribution (registry)
behavior and works behind any proxy without configuration.
Monolithic blob uploads (POST with ?digest=) now work in both sync and async modes. In async mode the blob is written to local staging
first, then uploaded to SFTP in the background.
Removed manual w.WriteHeader(http.StatusContinue) — Go's net/http sends 100 Continue automatically when r.Body is read.
No API or config change; upgrade and redeploy to benefit.
Summary
Area
Change
Frontend
Per-tag docker pull copy on repository page
Frontend
Nginx /v2 proxy: stream body, long timeouts
Backend
Drain POST body in initiateBlobUpload for same-host push