| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Any Linux host with Podman installed |
| Privilege | Rootful examples for system registries.conf.d drop-ins; rootless cache paths noted where they differ |
| Scope | How Podman resolves image references with registries.conf and drop-ins — unqualified-search-registries, [aliases], short-name-mode, machine-generated short-name-aliases.conf, insecure, blocked, prefix and location remapping, [[registry.mirror]], pull-from-mirror, credential-helper preference, and debug verification. Does not cover private-registry TLS setup, login internals, push workflows, or full short-name error remediation. |
| Related guides | Pull images with podman pull |
When you type podman pull alpine, Podman does not contact a registry named alpine. It reads registries.conf first — search lists, aliases, mirrors, block rules — and only then opens a network connection. This page explains that resolution path so you can control where short names land, route pulls through internal mirrors, and debug surprises without guessing.
What registries.conf controls
Think of the file as a routing layer between your image reference and the registry API:
User enters image reference
│
▼
registries.conf (+ drop-ins, alias cache)
│
├── short-name search / alias
├── block / insecure policy
├── prefix match (longest wins)
├── location remapping
└── mirrors
│
▼
Registry endpoint(s)registries.conf does not store registry passwords. Authentication belongs to auth.json, credential helpers, and podman login — see Log in to a container registry. This file answers which registry host and repository path a name resolves to, not which username to send.
registries.conf file locations
Podman loads configuration from several paths:
| Scope | Main file | Drop-ins |
|---|---|---|
| System | /etc/containers/registries.conf |
/etc/containers/registries.conf.d/*.conf |
| User | $HOME/.config/containers/registries.conf |
$HOME/.config/containers/registries.conf.d/*.conf (when supported) |
If $HOME/.config/containers/registries.conf exists, it replaces /etc/containers/registries.conf for that user. In that case, only $HOME/.config/containers/registries.conf.d/*.conf drop-ins are loaded afterward. Without a user main file, system drop-ins are loaded first and user drop-ins can layer on top. For a small customization on a shared host, prefer a system drop-in such as /etc/containers/registries.conf.d/10-team-mirrors.conf instead of editing the distribution file in place.
Inspect the effective distribution configuration
Before you add aliases or mirrors, read what the distribution already ships. On RHEL 10.2 the main file sets search order and short-name policy:
grep -E 'unqualified-search-registries|short-name-mode' /etc/containers/registries.confSample output:
unqualified-search-registries = ["registry.access.redhat.com", "registry.redhat.io", "docker.io"]
short-name-mode = "enforcing"List drop-ins that layer on top of the main file:
find /etc/containers/registries.conf.d -maxdepth 1 -type f -printRHEL also ships short-name alias drop-ins such as 000-shortnames.conf and 001-rhel-shortnames.conf. Do not assume an upstream Podman default file matches your host — always inspect the running configuration, especially for short-name-mode, unqualified-search-registries, and [aliases].
Prefer fully qualified image names
Compare these references:
alpine
docker.io/library/alpine:latestThe short form has no intrinsic registry identity. If unqualified-search-registries lists multiple hosts, Podman must guess or prompt. A squatted repository with the same name on an earlier search registry can win over the image you intended.
Production scripts, systemd units, and Quadlet files should use fully qualified names (registry/repository:tag or @sha256:...). Use short names and aliases only where you accept the resolution policy on that host — and document the alias in registries.conf when you do.
unqualified-search-registries
When no alias matches a short name, Podman searches registries in list order:
unqualified-search-registries = [
"registry.access.redhat.com",
"registry.redhat.io",
"docker.io"
]Order matters: the first registry that answers with a matching repository wins. Do not add random public registries for convenience — every entry is a namespace where an unexpected name collision can redirect pulls. On RHEL the list above is tuned for Red Hat content before Docker Hub.
Under short-name-mode = "enforcing", unqualified search is not a silent fallback in non-interactive sessions — ambiguous short names fail instead of probing the list. That behavior is why CI jobs need aliases or fully qualified references.
Short-name aliases
Map a short name to one fully qualified repository in [aliases]:
[aliases]
"demo" = "quay.io/podman/hello"
"ubi" = "registry.access.redhat.com/ubi9/ubi"The alias value is repository only — no tag or digest. Podman appends :latest or the tag you pass on the command line.
Pull using the short name:
podman pull demo:latestSample output:
Trying to pull quay.io/podman/hello:latest...
Getting image source signatures
Copying blob sha256:2114fc8b70586b9325dde6fd26066d9951414dcdfb3995f41d51d1995cf3bd9d
Copying config sha256:5dd467fce50b56951185da365b5feee75409968cbab5767b9b59e325fb2ecbc0
Writing manifest to image destinationResolution flow:
short name → fully qualified repository → tag/digest from your commandshort-name-mode
short-name-mode controls what happens when a short name is not covered by an alias:
| Mode | Interactive session | Non-interactive (CI, scripts) |
|---|---|---|
enforcing |
Can prompt to choose or record an alias | Fails if a prompt would be required |
permissive |
Can prompt | Falls back to unqualified-search-registries |
disabled |
No prompt | Searches configured registries directly |
Upstream containers/image defaults to permissive when the setting is absent. RHEL 10.2 ships short-name-mode = "enforcing" explicitly — inspect your host rather than assuming upstream defaults.
On this lab host, an unqualified pull without an alias and without a TTY fails immediately:
printf 'n\n' | podman pull bogus-unqualified-lab-image:999Sample output:
Error: short-name resolution enforced but cannot prompt without a TTYFull remediation patterns for short-name errors live in Fix Podman short-name resolution errors. This page covers the configuration that drives those errors.
Machine-generated short-name-aliases.conf
When short-name-mode allows prompting and you choose a resolution interactively, Podman can write the selected mapping to a cache file:
| Store | Path |
|---|---|
| Rootful | /var/cache/containers/short-name-aliases.conf |
| Rootless | $HOME/.cache/containers/short-name-aliases.conf |
A machine-generated alias for a given short name takes precedence over the same name in registries.conf. That precedence causes a recurring surprise:
- An administrator adds or changes
[aliases]in a drop-in. podman pull shortnamestill contacts the old registry.- The cache file still overrides the drop-in.
Inspect the cache before blaming registries.conf:
cat /var/cache/containers/short-name-aliases.confSample content (lab simulation):
# Machine-generated short-name aliases (lab simulation)
[aliases]
"stale-lab-short" = "quay.io/podman/stable"Remove or edit the specific stale entry — do not delete the entire cache directory unless you intend to drop every recorded short-name choice.
Fix a stale short-name alias
Suppose stale-lab-short was resolved interactively to quay.io/podman/stable, but your drop-in now maps it elsewhere. The cache entry wins until you fix it.
Check what the cache still records:
grep stale-lab-short /var/cache/containers/short-name-aliases.confRemove that line or update the value to match your new policy, then retry the pull. If you rely on administrator-defined aliases only, keep the cache file empty of conflicting names or set short-name-mode so users cannot create new cached entries unintentionally.
After the correction, podman --log-level=debug pull stale-lab-short:latest should show the registry from your registries.conf alias, not the old cached target.
Configure an insecure registry
Mark a specific registry scope as insecure when it serves plain HTTP or uses TLS that Podman cannot verify:
[[registry]]
location = "localhost:5000"
insecure = trueinsecure = true is not the same as installing a trusted CA. It permits HTTP and skips certificate verification for that scope. Use it for controlled labs — see Configure a private registry for the TLS + certs.d path that keeps verification enabled.
Pull from the lab HTTP registry after the stanza is in place:
podman pull localhost:5000/registry:2Sample output:
Trying to pull localhost:5000/registry:2...
Getting image source signatures
Copying blob sha256:ce980a8f5545faa3125a489aad32c00d6cf13d80a302308c3963b524085657af
Copying config sha256:0030ba3d620c647159c935ee778991c68ef3e51a274703753b0bc530104ef5e5
Writing manifest to image destinationScope the stanza to the exact host:port — not a wildcard across all registries.
Block a registry
Deny pulls from a registry host entirely:
[[registry]]
location = "blocked-registry.lab"
blocked = trueA blocked stanza still needs location set to the host you intend to block. Test the rule:
podman pull blocked-registry.lab/denied/image:latestSample output:
Trying to pull blocked-registry.lab/denied/image:latest...
Error: unable to copy from source docker://blocked-registry.lab/denied/image:latest: initializing source docker://blocked-registry.lab/denied/image:latest: registry blocked-registry.lab is blocked in /etc/containers/registries.conf or /root/.config/containers/registries.conf.dBlocking is name-based routing policy — not cryptographic image signing. Signature and trust policy belong in Podman image signing when you need verified publishers.
Understand prefix matching
[[registry]] stanzas match image references by prefix. Podman selects the stanza whose prefix is the longest match for the reference you passed.
Overlapping example:
[[registry]]
prefix = "prefixlab.example.com/lab"
location = "prefixlab.example.com/lab"
[[registry]]
prefix = "prefixlab.example.com/lab/images"
location = "quay.io/podman"A pull for prefixlab.example.com/lab/images/hello:latest matches the longer second prefix. Debug output shows the physical endpoint Podman contacts:
podman --log-level=debug pull prefixlab.example.com/lab/images/hello:latestRelevant lines:
Trying to pull prefixlab.example.com/lab/images/hello:latest...
Trying to access "quay.io/podman/hello:latest"A reference under prefixlab.example.com/lab/other/... matches only the shorter prefix and keeps the logical hostname — useful when you remap only a subtree.
Prefix can scope at different depths:
registry
registry/namespace
registry/namespace/repositoryThe longest matching prefix always wins among configured stanzas.
Remap registry locations with location
prefix selects which references the stanza applies to. location sets where Podman actually pulls:
[[registry]]
prefix = "example.com/lab"
location = "quay.io/podman"You request:
example.com/lab/hello:v1Podman retrieves from quay.io/podman/hello:v1 while storing the image under the logical name you passed. Verify with a pull:
podman pull example.com/lab/hello:latestSample output:
Trying to pull example.com/lab/hello:latest...
Getting image source signatures
Copying blob sha256:2114fc8b70586b9325dde6fd26066d9951414dcdfb3995f41d51d1995cf3bd9d
Copying config sha256:5dd467fce50b56951185da365b5feee75409968cbab5767b9b59e325fb2ecbc0
Writing manifest to image destinationMirrors and remapping affect pull sources. Push destination semantics are separate — see Push images to a registry.
Configure registry mirrors
Mirrors try alternate registry paths before or instead of the primary location. Define the primary stanza, then attach mirrors:
[[registry]]
prefix = "docker.io/library/alpine"
location = "docker.io/library/alpine"
[[registry.mirror]]
location = "localhost:5000/alpine"
insecure = truePull the official Alpine tag:
podman pull docker.io/library/alpine:3.20With debug logging, Podman tries the mirror first:
podman --log-level=debug pull docker.io/library/alpine:3.20Sample lines:
Trying to access "localhost:5000/alpine:3.20"
GET http://localhost:5000/v2/alpine/manifests/3.20The mirror location must include the repository path (localhost:5000/alpine), not just the host — a mirror of localhost:5000 alone produces an invalid reference. If the mirror lacks the image, Podman falls back to docker.io/library/alpine.
Multiple mirrors
Chain fallbacks by declaring several [[registry.mirror]] entries on the same prefix:
[[registry]]
prefix = "example.com/team"
location = "example.com/team"
[[registry.mirror]]
location = "mirror1.example.com/team"
[[registry.mirror]]
location = "mirror2.example.com/team"
insecure = truePodman tries mirrors in configuration order, then the primary location. Marking only a lab mirror insecure = true keeps production endpoints verified while a broken internal cache can still serve blobs over HTTP in testing.
pull-from-mirror
pull-from-mirror is configured on each [[registry.mirror]] entry, allowing different mirrors in the same chain to participate only for tag pulls, digest pulls, or both:
[[registry]]
prefix = "example.com/team"
location = "example.com/team"
[[registry.mirror]]
location = "mirror1.example.com/team"
pull-from-mirror = "digest-only"Supported values:
| Value | Behavior |
|---|---|
all |
This mirror participates in both tag and digest pulls. This is the default when pull-from-mirror is omitted. |
digest-only |
Mirror path for digest-pinned references; primary for mutable tags |
tag-only |
Mirror path for tag pulls; primary for digest-pinned references |
digest-only can suit cache architectures where digest pulls must hit an immutable mirror copy while :latest still resolves from upstream. Do not combine per-mirror pull-from-mirror with mirror-by-digest-only on the parent [[registry]]; upstream treats them as alternative configuration styles.
Docker Hub /library mirror trap
Official images on Docker Hub live under the library namespace. The reference:
docker.io/alpinenormalizes to:
docker.io/library/alpineA mirror stanza with:
prefix = "docker.io/alpine"does not match pulls of docker.io/alpine:3.20. Debug output on this host shows the normalization:
Found image "docker.io/alpine:3.20" as "docker.io/library/alpine:3.20" in local containers storage
Image docker.io/alpine:3.20 resolved to local image docker.io/library/alpine:3.20 which will be used for pullingUse:
prefix = "docker.io/library/alpine"or the broader:
prefix = "docker.io/library"when you mirror Docker Hub official images. The same rule applies to remap and block stanzas — match the normalized path, not the shorthand users type.
Registry credential helpers
At the top level of registries.conf, credential helpers set global lookup order:
credential-helpers = [
"pass",
"containers-auth.json"
]containers-auth.json means fall back to normal auth.json lookup. Helper configuration does not replace podman login — it changes where Podman searches for stored credentials after login. Authentication mechanics stay in Log in to a container registry.
Test registries.conf changes
Editing the file is not enough — prove behavior with pulls.
Use a fully qualified reference when testing mirrors on a known image:
podman pull docker.io/library/alpine:3.20Use a short name when testing aliases:
podman pull demo:latestAdd debug logging to see alias choice, prefix match, mirror try order, and contacted host:
podman --log-level=debug pull demo:latestAlias resolution shows the mapped repository before any network call:
Image demo:latest resolved to local image quay.io/podman/hello:latest which will be used for pulling
Trying to access "quay.io/podman/hello:latest"Run the same debug pull after each drop-in change so you have evidence of which stanza matched — not just whether the pull eventually succeeded.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Alias in drop-in ignored | Stale entry in short-name-aliases.conf |
Edit or remove the specific cached alias |
registry … is blocked |
blocked = true on that location |
Remove block stanza or pull from a different registry |
| Mirror never used | Wrong prefix (Docker Hub /library trap) or mirror location missing repo path |
Fix prefix to normalized path; use host:port/repository mirror location |
| Pull hits unexpected registry | Longer prefix stanza or cached alias wins |
podman --log-level=debug pull and read Trying to access line |
References
- containers-registries.conf(5) — full
registries.confformat - Podman registries.conf tutorial — upstream walkthrough
- Red Hat documentation — Building, running, and managing containers — RHEL registry configuration
- Distribution registry configuration — registry server side (mirrors pull from registry APIs)
Summary
registries.conf sits between your image reference and the registry API. It defines search order, aliases, insecure and blocked hosts, prefix-based remapping, and mirror chains — but not passwords. On RHEL 10.2, short-name-mode = "enforcing" and a curated unqualified-search-registries list mean short names in scripts need aliases or fully qualified references.
The details that save the most debugging time are longest-prefix matching, the Docker Hub library normalization trap, and machine-generated short-name-aliases.conf overriding drop-in aliases. When behavior looks wrong, podman --log-level=debug pull shows which stanza matched and which URL Podman contacted.
For TLS trust and registry deployment, use the private-registry guide. For login and auth.json, use the login guide. For error messages about unresolved short names, use the short-name troubleshooting article. Keep production automation on fully qualified image names and treat registries.conf as the policy layer that shapes how those names resolve on each host.

