| 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 pulling from a TLS registry — private registry, mirror, or corporate proxy endpoint |
| Privilege | [sudo](/sudo-command-in-linux/) for system-wide /etc/containers/certs.d/; rootless users can add registry-specific trust under ~/.config/containers/certs.d/ and may also use system paths when no conflicting user directory exists |
| Scope | TLS trust failures — x509: certificate signed by unknown authority, hostname SAN mismatch, http: server gave HTTP response to HTTPS client, certs.d CA layout, .crt versus .cert, debug pulls, --tls-verify=false as a diagnostic only, corporate MITM CA trust, rootful versus rootless cert paths, and mirror endpoint identification. Does not cover private registry deployment, full PKI design, login mechanics, or image signature policy. |
| Related guides | Log in to a container registry Pull images with podman pull Push images to a registry |
Podman reached the registry host, but TLS verification failed before any image layers downloaded. Match the error string you see to the layer that broke:
- Untrusted CA —
x509: certificate signed by unknown authority - Hostname mismatch — certificate valid for a different name than you connected to
- Protocol mismatch — plain HTTP registry answering an HTTPS client
This guide maps each case to the configuration change that belongs on a production host.
x509: certificate signed by unknown authority
Pull from a TLS registry whose CA is not in Podman's trust store. On this lab host the HTTPS registry listens on localhost:5443 with a self-signed lab CA not yet installed:
podman pull localhost:5443/ubi-minimal:latestSample output:
Trying to pull localhost:5443/ubi-minimal:latest...
Error: unable to copy from source docker://localhost:5443/ubi-minimal:latest: initializing source docker://localhost:5443/ubi-minimal:latest: pinging container registry localhost:5443: Get "https://localhost:5443/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authorityThe same wording appears on podman login before credentials are checked:
podman login --username testuser --password-stdin localhost:5443Sample output when the CA is still missing:
Error: authenticating creds for "localhost:5443": pinging container registry localhost:5443: Get "https://localhost:5443/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authorityPodman never got past the registry /v2/ ping — the failure is certificate trust, not authentication or a missing image tag.
First identify which registry actually failed
Mirrors can make the registry endpoint differ from the hostname in your original image reference. Authentication can also introduce a separate token-service hostname, so first identify whether TLS failed while contacting the registry/mirror or while obtaining an authentication token. Raise log level and pull again:
podman --log-level=debug pull localhost:5443/ubi-minimal:latest 2>&1 | grep -iE 'Trying to access|GET https|Ping https|x509|certs.d'Sample output:
Trying to pull localhost:5443/ubi-minimal:latest...
time="..." level=debug msg="Trying to access \"localhost:5443/ubi-minimal:latest\""
time="..." level=debug msg="Looking for TLS certificates and private keys in /etc/docker/certs.d/localhost:5443"
time="..." level=debug msg="GET https://localhost:5443/v2/"
time="..." level=debug msg="Ping https://localhost:5443/v2/ err Get \"https://localhost:5443/v2/\": tls: failed to verify certificate: x509: certificate signed by unknown authority (...)"For a registry or mirror /v2/ request, the registry endpoint determines the certs.d/HOST:PORT/ directory. If the failure instead occurs while Podman is contacting a separate authentication/token service, inspect that certificate chain separately; do not assume that creating certs.d for the token-service hostname is the correct fix. If registries.conf remaps docker.io to an internal mirror, trust the mirror's certificate, not only the public name you typed.
Podman's registry CA directory
Podman loads per-registry TLS material from certs.d. The directory name must match the registry endpoint exactly, including a non-default port.
| Search order | Path pattern |
|---|---|
| User-specific (rootless, checked first) | $HOME/.config/containers/certs.d/HOST:PORT/ |
| System | /etc/containers/certs.d/HOST:PORT/ |
| Legacy system | /etc/docker/certs.d/HOST:PORT/ |
Rootless Podman checks the user-specific directory first. If it exists for that registry, it takes precedence over the system directory rather than merging with it. Rootful Podman uses the system locations.
For registry.example.test:5000 (the hostname used in the private registry guide):
/etc/containers/certs.d/registry.example.test:5000/ca.crtPlace one or more PEM-encoded CA certificates as *.crt files in that directory. Podman also checks legacy /etc/docker/certs.d/HOST:PORT/ paths in debug output — prefer the containers path for new configuration.
Install the registry CA
Obtain the CA certificate that signed the registry server certificate — from your registry operator, your PKI team, or the CA.crt file you generated in the private-registry lab. Create the directory and copy the PEM file:
sudo mkdir -p /etc/containers/certs.d/localhost:5443Copy the PEM into the directory name that matches your registry endpoint:
sudo cp registry-ca.crt /etc/containers/certs.d/localhost:5443/ca.crtRetry the pull:
podman pull localhost:5443/ubi-minimal:latestSample output after trust is wired:
Trying to pull localhost:5443/ubi-minimal:latest...
Getting image source signatures
Copying blob sha256:b02c58b1810d6d9c787b6e23d8ac6f4f454a1969867e2c1d9e78cbe380cfab0a
Copying config sha256:591c6dfb4400e422f10f911ff8d95aead6e1d80975bb11cfabd1ba918133f8c5
Writing manifest to image destination
591c6dfb4400e422f10f911ff8d95aead6e1d80975bb11cfabd1ba918133f8c5Confirm Podman loaded your CA from the expected path:
podman --log-level=debug pull localhost:5443/ubi-minimal:latest 2>&1 | grep 'crt:'Sample output:
crt: /etc/containers/certs.d/localhost:5443/ca.crtpodman login against the same endpoint should reach Login Succeeded! once TLS verification passes — credential errors after that point are a separate topic.
.crt versus .cert versus .key
Podman uses filename suffixes to distinguish trust material from client authentication:
| Suffix | Purpose |
|---|---|
*.crt |
Trusted CA certificate (what you install for registry trust) |
*.cert |
Client certificate for mutual TLS |
*.key |
Private key matching a client certificate |
Name the registry CA ca.crt, not ca.cert — the .cert suffix signals client certificate material, not a trusted issuer.
Certificate hostname mismatch
A sibling error means the chain is trusted but the name does not match. Pull against a registry that presents a certificate for a different hostname:
podman pull localhost:5444/ubi-minimal:latestSample output:
Error: ... tls: failed to verify certificate: x509: certificate is valid for wronghost.example.com, not localhostThis is not an unknown-CA problem. The server presented a certificate Podman could verify against a known issuer, but the DNS name or IP you connected to is absent from the certificate's Subject Alternative Name (SAN) list.
Inspect what the registry actually presents:
openssl s_client -connect localhost:5444 -servername localhost </dev/null 2>&1 | openssl x509 -noout -subject -ext subjectAltNameSample output on a misconfigured lab registry:
subject=CN=wronghost.example.com
X509v3 Subject Alternative Name:
DNS:wronghost.example.comThe fix is to reissue the server certificate with the correct DNS: and IP: SAN entries for the hostname clients use — or connect using a name already in the SAN. Do not disable TLS verification to work around a hostname mismatch in production.
http: server gave HTTP response to HTTPS client
A different failure mode — protocol mismatch, not untrusted CA. Pull from a registry that speaks plain HTTP while Podman expects HTTPS:
podman pull localhost:5001/ubi-minimal:latestSample output:
Trying to pull localhost:5001/ubi-minimal:latest...
Error: unable to copy from source docker://localhost:5001/ubi-minimal:latest: initializing source docker://localhost:5001/ubi-minimal:latest: pinging container registry localhost:5001: Get "https://localhost:5001/v2/": http: server gave HTTP response to HTTPS clientPodman tried https://; the registry answered with HTTP. Installing a CA does not fix this.
Fix an intentional HTTP lab registry
For a controlled lab registry that will stay on HTTP, declare it explicitly in registries.conf:
[[registry]]
location = "localhost:5001"
insecure = truePlace the stanza in a drop-in such as /etc/containers/registries.conf.d/10-lab-http.conf. After that, podman pull localhost:5001/... uses HTTP without TLS.
One-time diagnostic bypass (not a production fix):
podman pull --tls-verify=false localhost:5443/ubi-minimal:latestThat pull can succeed even when no CA is installed — which confirms the network path works and TLS verification was the failing layer. For a real private registry, enable HTTPS on the server, install the trusted CA in certs.d, and leave verification on.
Why --tls-verify=false is not the final fix
--tls-verify=false skips certificate chain validation for that command. It does not add trust — it removes the check that failed. Anyone on the network path could present a different certificate and Podman would accept it.
Use the flag briefly to separate connectivity from trust:
- Pull with
--tls-verify=false— if it succeeds, TLS verification was the blocker. - Install
ca.crtundercerts.d/HOST:PORT/. - Repeat the pull without the flag.
Keep verification enabled in scripts, CI, Quadlet units, and production systemd services.
Corporate TLS inspection and MITM proxies
Corporate networks sometimes terminate TLS on a proxy and re-encrypt with an enterprise CA. Typical symptoms:
- Browsers trust the site because they use a browser-specific or enterprise-managed trust store
podman pullfails withx509: certificate signed by unknown authorityopenssl s_clientshows an issuer naming your organization's CA, not a public CA
That pattern does not mean Podman ignores OS trust in general. Podman uses normal system certificate trust plus custom registry CAs. If the corporate root is properly installed in the Linux trust store Podman uses, it should normally be trusted there as well. The failure usually means the CA is missing from that Linux trust store, or the registry-specific certs.d configuration for the affected endpoint does not contain the required CA.
Fix with either approach:
- Install the enterprise CA into the host OS trust store using your distribution's supported mechanism.
- Install the CA specifically for the affected registry under
certs.d/HOST:PORT/.
Install registry-specific trust for the hostname shown in the TLS request or debug output. If registries.conf rewrites the pull to a mirror, that may be the mirror hostname. Do not export and trust a one-off certificate from a single browser session; use the approved CA bundle from your security team.
Rootless versus rootful CA trust
The same image reference can succeed for one invocation and fail for another when trust files differ.
Rootless Podman checks $HOME/.config/containers/certs.d/HOST:PORT/ before system locations such as /etc/containers/certs.d/ and legacy /etc/docker/certs.d/. If a user-specific directory for that registry exists, it takes precedence over the system directory rather than merging with it. Rootful Podman uses the system locations.
A CA installed only under your home directory fixes rootless pulls but not sudo podman. Install under /etc/containers/certs.d/ when every user on the host needs the same registry trust. If rootful pulls work but rootless pulls fail despite a system CA, inspect whether an incomplete user-specific certs.d/HOST:PORT/ directory is shadowing the system configuration.
Registry mirrors
When registries.conf redirects pulls — for example from docker.io to mirror.example.com — TLS errors may reference the mirror hostname. Debug output shows the physical GET https:// target. Install the CA for that mirror endpoint, not only for the logical name in your image reference.
Diagnostic decision tree
x509: certificate signed by unknown authority
→ correct HOST:PORT in image reference?
→ certs.d directory name matches HOST:PORT exactly?
→ CA file named *.crt (e.g. ca.crt)?
→ server sends full chain (or you trust the issuing CA)?
→ corporate MITM — need organization CA?
x509: certificate is valid for X, not Y
→ SAN/hostname mismatch — reissue cert or use name in SAN
→ not fixed by installing CA alone
http: server gave HTTP response to HTTPS client
→ registry is plain HTTP — use TLS on server or insecure lab stanza
→ not a CA trust problemTroubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
x509: certificate signed by unknown authority |
CA not in certs.d for that HOST:PORT |
Copy issuer CA to /etc/containers/certs.d/HOST:PORT/ca.crt |
Pull works with --tls-verify=false only |
Missing CA trust | Install CA; remove permanent use of the flag |
certificate is valid for X, not Y |
SAN does not include connected hostname | Reissue server cert with correct SAN; use matching hostname |
HTTP response to HTTPS client |
Registry serves HTTP on that port | Enable TLS on registry or insecure = true for lab HTTP only |
Rootless works, sudo podman fails |
CA only in ~/.config/containers/certs.d |
Copy CA to /etc/containers/certs.d/ |
| Rootful works, rootless fails | User certs.d/HOST:PORT/ shadows incomplete system trust |
Inspect $HOME/.config/containers/certs.d/HOST:PORT/; fix or remove the incomplete user-specific directory |
| Error persists after CA install | Wrong HOST:PORT directory name | Match directory to debug GET https:// host:port exactly |
| Mirror in use | Trust needed for mirror endpoint | Debug pull; install CA for mirror from registries.conf |
References
Summary
When Podman reports x509: certificate signed by unknown authority, the registry TLS handshake failed because Podman does not trust the certificate issuer. Install the signing CA as ca.crt under certs.d/HOST:PORT/ where HOST:PORT matches the endpoint from podman --log-level=debug — including non-default ports and mirror hostnames.
Hostname errors (certificate is valid for X, not Y) need a certificate reissue or a corrected client hostname, not merely a new CA file. http: server gave HTTP response to HTTPS client means Podman used HTTPS against a plain HTTP registry — fix the protocol or mark a lab registry insecure, not the CA store.
Use --tls-verify=false only to confirm that connectivity works and TLS was the failing layer, then install proper trust and pull again with verification enabled. Rootless Podman checks user-specific certs.d directories before system paths; an incomplete user directory can shadow system trust. For the full private-registry TLS lab that generates the CA, continue with Run a private container registry.

