Podman `registries.conf` Explained: Search, Aliases and Mirrors

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:

text
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:

bash
grep -E 'unqualified-search-registries|short-name-mode' /etc/containers/registries.conf

Sample output:

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:

bash
find /etc/containers/registries.conf.d -maxdepth 1 -type f -print

RHEL 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:

text
alpine
docker.io/library/alpine:latest

The 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:

toml
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]:

toml
[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:

bash
podman pull demo:latest

Sample output:

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 destination

Resolution flow:

text
short name  →  fully qualified repository  →  tag/digest from your command

short-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:

bash
printf 'n\n' | podman pull bogus-unqualified-lab-image:999

Sample output:

output
Error: short-name resolution enforced but cannot prompt without a TTY

Full 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:

  1. An administrator adds or changes [aliases] in a drop-in.
  2. podman pull shortname still contacts the old registry.
  3. The cache file still overrides the drop-in.

Inspect the cache before blaming registries.conf:

bash
cat /var/cache/containers/short-name-aliases.conf

Sample content (lab simulation):

output
# 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:

bash
grep stale-lab-short /var/cache/containers/short-name-aliases.conf

Remove 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:

toml
[[registry]]
location = "localhost:5000"
insecure = true

insecure = 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:

bash
podman pull localhost:5000/registry:2

Sample output:

output
Trying to pull localhost:5000/registry:2...
Getting image source signatures
Copying blob sha256:ce980a8f5545faa3125a489aad32c00d6cf13d80a302308c3963b524085657af
Copying config sha256:0030ba3d620c647159c935ee778991c68ef3e51a274703753b0bc530104ef5e5
Writing manifest to image destination

Scope the stanza to the exact host:port — not a wildcard across all registries.


Block a registry

Deny pulls from a registry host entirely:

toml
[[registry]]
location = "blocked-registry.lab"
blocked = true

A blocked stanza still needs location set to the host you intend to block. Test the rule:

bash
podman pull blocked-registry.lab/denied/image:latest

Sample output:

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.d

Blocking 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:

toml
[[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:

bash
podman --log-level=debug pull prefixlab.example.com/lab/images/hello:latest

Relevant lines:

output
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:

text
registry
registry/namespace
registry/namespace/repository

The 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:

toml
[[registry]]
prefix = "example.com/lab"
location = "quay.io/podman"

You request:

text
example.com/lab/hello:v1

Podman retrieves from quay.io/podman/hello:v1 while storing the image under the logical name you passed. Verify with a pull:

bash
podman pull example.com/lab/hello:latest

Sample output:

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 destination

Mirrors 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:

toml
[[registry]]
prefix = "docker.io/library/alpine"
location = "docker.io/library/alpine"

[[registry.mirror]]
location = "localhost:5000/alpine"
insecure = true

Pull the official Alpine tag:

bash
podman pull docker.io/library/alpine:3.20

With debug logging, Podman tries the mirror first:

bash
podman --log-level=debug pull docker.io/library/alpine:3.20

Sample lines:

output
Trying to access "localhost:5000/alpine:3.20"
GET http://localhost:5000/v2/alpine/manifests/3.20

The 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:

toml
[[registry]]
prefix = "example.com/team"
location = "example.com/team"

[[registry.mirror]]
location = "mirror1.example.com/team"

[[registry.mirror]]
location = "mirror2.example.com/team"
insecure = true

Podman 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:

toml
[[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:

text
docker.io/alpine

normalizes to:

text
docker.io/library/alpine

A mirror stanza with:

toml
prefix = "docker.io/alpine"

does not match pulls of docker.io/alpine:3.20. Debug output on this host shows the normalization:

text
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 pulling

Use:

toml
prefix = "docker.io/library/alpine"

or the broader:

toml
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:

toml
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:

bash
podman pull docker.io/library/alpine:3.20

Use a short name when testing aliases:

bash
podman pull demo:latest

Add debug logging to see alias choice, prefix match, mirror try order, and contacted host:

bash
podman --log-level=debug pull demo:latest

Alias resolution shows the mapped repository before any network call:

output
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


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.


Frequently Asked Questions

1. Does registries.conf store registry passwords?

No. registries.conf controls how Podman resolves image names and routes pulls — search order, aliases, mirrors, insecure and blocked registries. Credentials live in auth.json or credential helpers; see the login guide for authentication mechanics.

2. What is the difference between prefix and location in registries.conf?

prefix is the logical image reference pattern that selects a registry stanza — for example docker.io/library. location is the physical registry host and repository path Podman contacts when that stanza matches. Mirrors add alternate locations tried before or instead of the primary endpoint.

3. Why does my alias in registries.conf not take effect?

A machine-generated entry in short-name-aliases.conf under the containers cache directory overrides the same alias name in registries.conf. Inspect that cache file and remove or update the stale alias entry, then retry the pull.

4. What does short-name-mode enforcing mean on RHEL?

enforcing requires an unambiguous alias for short names. In scripts and CI without a TTY, Podman cannot prompt and the pull fails instead of guessing from unqualified-search-registries. permissive allows fallback search; disabled skips prompting and searches configured registries directly.

5. Why does prefix docker.io/alpine not match my Docker Hub mirror?

Docker Hub normalizes docker.io/alpine to docker.io/library/alpine for official images. Mirror and remap prefixes must use docker.io/library/alpine or the broader docker.io/library prefix, not docker.io/alpine alone.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)