| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64passt-1.2.2-2.el10.x86_64 |
| Applies to | Any Linux host with Podman installed |
| Privilege | Rootful examples as root; rootless pasta examples as testuser |
| Scope | Container-to-host connectivity with host.containers.internal, host-gateway, /etc/hosts inspection, bind-address checks, rootless pasta behavior, --network=host, and troubleshooting. Does not cover container-to-container DNS, outbound Internet routing, port publishing, or full pasta configuration. |
| Related guides | Create and manage Podman networks Install Podman on RHEL |
An application inside a Podman container often needs to call a database, API, or dev server that still runs on the host. That path is outbound from the container to the host — the opposite of port mapping, which publishes container ports to the host. This guide shows the supported hostname, what to do when it is missing, and why rootless pasta networking breaks the obvious guess of using the host main IP.
The lab image is docker.io/library/alpine:3.20 with --platform linux/amd64 on the rootful host. Rootless examples run as testuser with pasta as the default rootless network stack.
Quick answer: reach the Podman host with host.containers.internal
Inside most normal Podman containers, point your client at:
host.containers.internalPodman also adds host.docker.internal as a compatibility alias on the same address. Do not guess a bridge gateway IP on Linux before trying these names.
Start a simple HTTP server on the host bound to all interfaces:
python3 -m http.server 8080 --bind 0.0.0.0From a container, request that service through the internal hostname:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 wget -qO- http://host.containers.internal:8080/The lab returns an HTML directory listing:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Directory listing for /</title>That confirms the container reached the host process. Stop the Python server when you finish testing.
localhost inside a container is not the host
In a normal bridge or pasta container, 127.0.0.1 refers to the container own network namespace, not the Podman host. A client inside the container that calls http://127.0.0.1:8080 looks for a listener in that container.
With the host server still bound to 0.0.0.0:8080, try the container loopback from inside a rootless pasta container:
podman run --rm docker.io/library/alpine:3.20 wget -qO- --timeout=2 http://127.0.0.1:8080/Nothing is listening on the container loopback, so wget reports:
wget: can't connect to remote host (127.0.0.1): Connection refusedExceptions where 127.0.0.1 can mean the host include --network=host and deliberate namespace-sharing setups covered later. For default podman run networking, use host.containers.internal instead of localhost when you mean the host.
How host.containers.internal works
Podman does not rely on Aardvark DNS for host access. It writes managed entries into the container /etc/hosts file and picks a host-gateway address that container traffic can use to reach the host.
Inspect what Podman injected:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 cat /etc/hostsOn the lab rootful bridge network, the internal hostnames sit on the bridge gateway:
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
10.88.0.1 host.containers.internal host.docker.internal
10.88.2.146 34ae5b6f5d87 clever_williamsThe last line is the container own hostname entry. The 10.88.0.1 line is what you care about for host access.
Confirm name resolution through the libc hosts database:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internal10.88.0.1 host.containers.internal host.containers.internalThat address is Podman host-gateway mapping for this network mode. It is not the same mechanism as container-name DNS with Aardvark on a user-defined bridge.
What if host.containers.internal is missing?
Podman can omit these names when it cannot determine a suitable host-gateway address, when --no-hosts is used, or when host_containers_internal_ip="none" is configured. A missing name does not automatically mean DNS is broken — check /etc/hosts first.
Look up the name:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internalWhen no line prints and the exit status is non-zero, inspect the hosts file:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 cat /etc/hostsIf the internal names are absent:
- try
--add-host myhost:host-gatewaywhen Podman can determine a gateway — the same automatic logic applies, and there is no guarantee Podman can resolvehost-gatewayon every host - set
host_containers_internal_ipincontainers.confwhen automatic gateway detection is unsuitable or unavailable - use
--network=hostonly when sharing the host network namespace is appropriate
Use --add-host with host-gateway
When you need a custom hostname or Podman did not add the defaults, map a name to the host through Podman gateway logic:
podman run --rm --add-host myhost:host-gateway --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts myhost10.88.0.1 myhost myhosthost-gateway asks Podman to resolve a host address suitable for container-to-host access. That avoids hard-coding a bridge address when Podman can determine a suitable host gateway automatically.
With the host HTTP server listening on 0.0.0.0:8080, connect through the custom name:
podman run --rm --add-host myhost:host-gateway --platform linux/amd64 docker.io/library/alpine:3.20 wget -qO- http://myhost:8080/The HTML listing returns again, which shows the alias reaches the same host service as host.containers.internal.
Override the host internal address in containers.conf
When automatic host-gateway detection returns an unsuitable address for your environment, you can pin it in containers.conf:
host_containers_internal_ip="203.0.113.50"Use this only when you have confirmed the automatic mapping is wrong. Treat it as an environment-specific override, not the default teaching path. The full containers.conf reference is outside this article.
The host service must listen on a reachable address
Before blaming Podman, confirm which address the host application actually binds. A service on host loopback is not automatically reachable through the address mapped to host.containers.internal.
On the host, list listeners:
ss -lntpWith one server on all interfaces and another on loopback only, the lab shows:
LISTEN 0 5 0.0.0.0:8080 0.0.0.0:* users:(("python3",pid=190383,fd=3))
LISTEN 0 5 127.0.0.1:8081 0.0.0.0:* users:(("python3",pid=190528,fd=3))A container can reach 0.0.0.0:8080 through host.containers.internal when that name maps to a host-facing gateway address. Traffic to 127.0.0.1:8081 on the host is a different path.
Start only the loopback-bound server on port 8081:
python3 -m http.server 8081 --bind 127.0.0.1From a rootful container, try the internal hostname on that port:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 wget -qO- --timeout=3 http://host.containers.internal:8081/The gateway address is not the host loopback, so the connection fails:
wget: can't connect to remote host (10.88.0.1): Connection refusedBind the service to 0.0.0.0 or a host interface address when containers must reach it through host.containers.internal, or use --network=host when that model fits your workload.
Rootless Podman with pasta
Since Podman 5.0, pasta is the default rootless network stack. Pasta copies host interface addresses, routes, and characteristics into the container network namespace.
That creates an important consequence on simple single-interface hosts: the container may hold the same main IP as the host. Traffic to that address can route toward the container itself instead of the host service.
Check which rootless backend is active:
podman info --format 'RootlessNetworkCmd={{.Host.RootlessNetworkCmd}}'On the lab host:
RootlessNetworkCmd=pastaInside a rootless container, list IPv4 addresses:
podman run --rm docker.io/library/alpine:3.20 ip -4 addr showPasta copied the host enp0s3 address into the container:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
inet 127.0.0.1/8 scope host lo
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN qlen 1000
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute enp0s3The host main IP 10.0.2.15 is local inside the pasta namespace. This is expected pasta behavior, not a random single-NIC bug.
How Podman maps host access through pasta
On current Podman releases using pasta, Podman passes a dedicated guest-address mapping so host.containers.internal can reach the host even though normal gateway access is disabled by default.
Inside a rootless container, read the managed hosts entry:
podman run --rm docker.io/library/alpine:3.20 grep host.containers.internal /etc/hosts169.254.1.2 host.containers.internal host.docker.internalPodman selected a link-local style address for this mapping. Do not hard-code that value in application config — always prefer host.containers.internal so upgrades and network changes stay portable.
The flow looks like this:
host.containers.internal
│
▼
special guest address (managed by Podman)
│
▼
pasta host mapping
│
▼
host serviceWhy the host main IP fails but host.containers.internal works
This is the most common rootless pasta surprise. With the host HTTP server on 0.0.0.0:8080, try the host main IP from inside a rootless container:
podman run --rm docker.io/library/alpine:3.20 wget -qO- --timeout=3 http://10.0.2.15:8080/The address is local to the pasta namespace, so wget fails:
wget: can't connect to remote host (10.0.2.15): Connection refusedNow use the internal hostname Podman provides:
podman run --rm docker.io/library/alpine:3.20 wget -qO- http://host.containers.internal:8080/<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Directory listing for /</title>The main host IP and host.containers.internal are not interchangeable under pasta. The internal hostname uses a dedicated mapping for host access.
Advanced: pasta with --map-gw
Podman normally invokes pasta with gateway-to-host mapping disabled (--no-map-gw). For advanced cases you can enable gateway mapping explicitly:
podman run --rm --network pasta:--map-gw docker.io/library/alpine:3.20 ip route--map-gw here is a Podman pasta-network option that overrides Podman's default --no-map-gw behavior; it is not a standalone pasta(1) flag.
default via 10.0.2.2 dev enp0s3 metric 116
10.0.2.0/24 dev enp0s3 scope link metric 116This can provide another host-access path through the container default gateway. Prefer host.containers.internal where it already works. Treat --map-gw as a deliberate override, not the first fix.
Access host services with --network=host
--network=host removes the normal network-namespace boundary. The container shares the host network stack, so host loopback is reachable from inside the container.
Start a server bound only to host loopback:
python3 -m http.server 8082 --bind 127.0.0.1Run a container on the host network and call that loopback address:
podman run --rm --network host --platform linux/amd64 docker.io/library/alpine:3.20 wget -qO- http://127.0.0.1:8082/<!DOCTYPE HTML>
<html lang="en">
<head>127.0.0.1 now refers to the host because the namespaces are shared. Use this mode only when you want that coupling — not because host.containers.internal was mistyped.
Host access from rootful bridge containers
Rootful bridge networking normally has a bridge gateway Podman can use for the internal hostnames. Verify the mapping the same way as in the earlier sections:
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internal10.88.0.1 host.containers.internal host.containers.internalThe exact gateway address varies by host and network. Read it from getent or /etc/hosts instead of assuming a fixed value such as 10.88.0.1 on every installation.
With the host service on 0.0.0.0:8080, a rootful container reaches it through the internal hostname the same way as in the quick-answer section.
Custom hostname with --add-host
You can map an arbitrary name to a literal host address when an application expects a fixed hostname:
podman run --rm --add-host database-host:10.0.2.15 --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts database-host10.0.2.15 database-host database-hostThat works when the address is actually reachable from the container network mode you use. Under pasta, a literal main-interface IP may fail even though the name resolves, which is why host-gateway and host.containers.internal are better defaults for reaching the Podman host itself.
Troubleshoot container-to-host connectivity
Work through these checks in order when a container cannot reach a host service.
| Symptom | Likely cause | Fix |
|---|---|---|
getent hosts host.containers.internal returns nothing |
Host-gateway entries omitted or unavailable | Try --add-host myhost:host-gateway when Podman can resolve it; otherwise set host_containers_internal_ip in containers.conf |
| Name resolves but connection refused | Host service bound to 127.0.0.1 only |
Bind to 0.0.0.0 or a host interface, or use --network=host |
| Rootless failure to host main IP | Pasta copied that IP into the container | Use host.containers.internal instead of the main interface address |
127.0.0.1 fails inside a normal container |
Container loopback is not the host | Use host.containers.internal or --network=host |
Works with --network=host only |
Namespace isolation blocked the earlier path | Fix bind address and hostname choice for your intended network mode |
| Outbound Internet also broken | Routing or DNS outside this scope | See general connectivity troubleshooting; this article covers host access only |
First command to run inside the failing container:
getent hosts host.containers.internalIf a line appears, inspect the hosts file for the mapped address:
cat /etc/hostsOn the host, confirm the service listens where you expect:
ss -lntpFor rootless setups, confirm pasta is in use:
podman info --format 'RootlessNetworkCmd={{.Host.RootlessNetworkCmd}}'Then test with the real client your application uses, such as curl or wget, against host.containers.internal and the correct port.
References
- Podman networking documentation
- podman-run man page — host-gateway and network options
- containers.conf man page
- passt documentation
Summary
Reaching the Podman host from a container starts with host.containers.internal. Podman normally writes host.containers.internal and host.docker.internal into /etc/hosts using a host-gateway address suited to the active network mode. That path is separate from Aardvark container-name DNS and separate from port publishing on the host.
The bind address on the host service matters as much as the container hostname. A process listening only on 127.0.0.1 stays invisible to containers that reach the host through a gateway mapping. Check ss -lntp before chasing Podman flags.
Rootless pasta adds a twist competitors often skip: the host main interface IP can appear inside the container, so curling that IP may loop locally while host.containers.internal still works through Podman dedicated mapping. When the default names are missing, try --add-host myhost:host-gateway if Podman can resolve it, pin host_containers_internal_ip when automatic detection fails, and use --network=host only when sharing the host network namespace is what you actually want.
For name resolution between containers on the same bridge, continue with Podman container DNS. For how traffic leaves the container toward the Internet, see Podman networking modes.

