Access the Host from a Podman Container

Tested on Red Hat Enterprise Linux 10.2 (Coughlan)
Package podman-5.8.2-5.el10_2.x86_64
passt-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:

text
host.containers.internal

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

bash
python3 -m http.server 8080 --bind 0.0.0.0

From a container, request that service through the internal hostname:

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

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

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

output
wget: can't connect to remote host (127.0.0.1): Connection refused

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

bash
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 cat /etc/hosts

On the lab rootful bridge network, the internal hostnames sit on the bridge gateway:

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

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

bash
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internal
output
10.88.0.1         host.containers.internal  host.containers.internal

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

bash
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internal

When no line prints and the exit status is non-zero, inspect the hosts file:

bash
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 cat /etc/hosts

If the internal names are absent:

  • try --add-host myhost:host-gateway when Podman can determine a gateway — the same automatic logic applies, and there is no guarantee Podman can resolve host-gateway on every host
  • set host_containers_internal_ip in containers.conf when automatic gateway detection is unsuitable or unavailable
  • use --network=host only 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:

bash
podman run --rm --add-host myhost:host-gateway --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts myhost
output
10.88.0.1         myhost  myhost

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

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

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

bash
ss -lntp

With one server on all interfaces and another on loopback only, the lab shows:

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

bash
python3 -m http.server 8081 --bind 127.0.0.1

From a rootful container, try the internal hostname on that port:

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

output
wget: can't connect to remote host (10.88.0.1): Connection refused

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

bash
podman info --format 'RootlessNetworkCmd={{.Host.RootlessNetworkCmd}}'

On the lab host:

output
RootlessNetworkCmd=pasta

Inside a rootless container, list IPv4 addresses:

bash
podman run --rm docker.io/library/alpine:3.20 ip -4 addr show

Pasta copied the host enp0s3 address into the container:

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

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

bash
podman run --rm docker.io/library/alpine:3.20 grep host.containers.internal /etc/hosts
output
169.254.1.2	host.containers.internal host.docker.internal

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

text
host.containers.internal
special guest address (managed by Podman)
pasta host mapping
host service

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

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

output
wget: can't connect to remote host (10.0.2.15): Connection refused

Now use the internal hostname Podman provides:

bash
podman run --rm docker.io/library/alpine:3.20 wget -qO- http://host.containers.internal:8080/
output
<!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:

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

output
default via 10.0.2.2 dev enp0s3  metric 116 
10.0.2.0/24 dev enp0s3 scope link  metric 116

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

bash
python3 -m http.server 8082 --bind 127.0.0.1

Run a container on the host network and call that loopback address:

bash
podman run --rm --network host --platform linux/amd64 docker.io/library/alpine:3.20 wget -qO- http://127.0.0.1:8082/
output
<!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:

bash
podman run --rm --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts host.containers.internal
output
10.88.0.1         host.containers.internal  host.containers.internal

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

bash
podman run --rm --add-host database-host:10.0.2.15 --platform linux/amd64 docker.io/library/alpine:3.20 getent hosts database-host
output
10.0.2.15         database-host  database-host

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

bash
getent hosts host.containers.internal

If a line appears, inspect the hosts file for the mapped address:

bash
cat /etc/hosts

On the host, confirm the service listens where you expect:

bash
ss -lntp

For rootless setups, confirm pasta is in use:

bash
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


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.


Frequently Asked Questions

1. How does a Podman container reach the host?

Use host.containers.internal in the container URL. Podman normally adds host.containers.internal and host.docker.internal to /etc/hosts using its host-gateway logic. If Podman cannot determine a suitable address, the entries may be absent; --add-host myhost:host-gateway provides an explicit mapping when Podman can resolve it.

2. Why cannot my container curl the host at 127.0.0.1?

In a normal bridge or pasta container, 127.0.0.1 is the container own loopback, not the host. Use host.containers.internal unless you started the container with --network=host, which shares the host network namespace.

3. Why does host.containers.internal work but my host IP does not in rootless Podman?

Rootless pasta often copies the host main interface address into the container namespace. Traffic to that address can loop inside the container instead of reaching the host. host.containers.internal uses a separate Podman and pasta mapping intended for host access.

4. Is host.containers.internal the same as Aardvark DNS?

No. host.containers.internal is added through managed /etc/hosts entries and host-gateway logic. Aardvark DNS resolves other container names on DNS-enabled bridge networks. See the Podman container DNS guide for name resolution between containers.

5. My host service listens on 127.0.0.1 only. Can the container reach it?

Usually not through host.containers.internal on bridge or pasta networking, because the mapped host address is not the host loopback. Bind the service to 0.0.0.0 or a host interface address, use --network=host when appropriate, or expose the service another way.
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)