Two things eventually force you to deal with registry credentials: Docker Hub's anonymous pull limits, and your own private images.
The rate limit problem
Anonymous pulls are counted per IP. On a VPS that is fine until it is not — a redeploy loop, or a shared NAT address, and suddenly pulls fail with a toomanyrequests error that looks like a network fault. Logging in with even a free account raises the limit substantially.
GHCR and other private registries
Use a token scoped to package read only. A personal access token with repo write on it, sitting in a config file on a hosting server, is a supply chain incident waiting for an excuse.
Where the credentials actually live
Panelica stores registry credentials through the panel rather than leaving them in a dotfile, which is the same idea — the point is that the token should not be sitting in a world-readable place, however you get there.
The tag discipline that saves you later
Private registry plus
The rate limit problem
Anonymous pulls are counted per IP. On a VPS that is fine until it is not — a redeploy loop, or a shared NAT address, and suddenly pulls fail with a toomanyrequests error that looks like a network fault. Logging in with even a free account raises the limit substantially.
Code:
docker login
# then verify it took
cat ~/.docker/config.json
GHCR and other private registries
Code:
echo "$GITHUB_TOKEN" | docker login ghcr.io -u YOUR_USERNAME --password-stdin
docker pull ghcr.io/yourorg/yourapp:1.4.2
Use a token scoped to package read only. A personal access token with repo write on it, sitting in a config file on a hosting server, is a supply chain incident waiting for an excuse.
Where the credentials actually live
docker login writes to ~/.docker/config.json of the user who ran it, base64-encoded — which is encoding, not encryption. Anyone who can read that file has your registry token. On a multi-tenant machine that matters: it should be root-owned and mode 600, and it should not be in a home directory that gets backed up into a customer-accessible archive.Panelica stores registry credentials through the panel rather than leaving them in a dotfile, which is the same idea — the point is that the token should not be sitting in a world-readable place, however you get there.
The tag discipline that saves you later
Private registry plus
:latest is the worst combination available. You cannot tell which build is running, you cannot roll back, and a redeploy quietly changes the application. Tag with a version or a commit hash, always. The thirty seconds it costs at build time is the difference between a rollback and an outage.