I’m guessing that you’re here because you want to run an application in a Podman container, and access it from the host.
For example, you’re running Podman on Linux, and you want to be able to run a component in a rootless container – such as a database, a message broker, or a data cache – and access it from your application.
You can do this with port publishing, but how do you do it without needing to do that?
One solution is to choose your networking option wisely. There is one network mode which makes host networking rather simple. Let’s have a quick look at network modes first.
Here’s a quick table of contents so you can jump straight to the part you need:
Network modes control how your container interacts with other systems
The thing you need to know about Podman is that, like docker, it has a few different network modes.
A mode changes the networking capabilities of the container – like which other containers it can interact with, or whether it can see the host.
Podman has a few different network modes which you can set on a container:
|What it does
|Creates a network stack on the default bridge network
|No networking is set up at all
|Uses the same network as another container with ID
|Uses the host’s network stack
|Uses a user-defined network (which you can create using
podman network create ...)
|Joins a network namespace found at path
|Creates a new network namespace for the container
|Creates a user network stack with
slirp4netns (This is the default option for rootless containers.)
As you can see there’s a mind-boggling array of options.
The mode I’ve highlighted, the
host mode, is the simplest solution for host-to-container and container-to-host networking. We’ll look at that next.
For simple container-to-host networking, connect your container to the host network
In the ‘host’ network mode, a container shares the host’s networking namespace; which means it shares the same network interface, routing tables and so on, so it can ‘see’ the same things that the host can.
Being able to sharing the same network interface and routing tables can be really useful, because it means that your container can see and access services as if it was a regular (non-container) process. And your host can see and access services running in containers.
Security heads-up! Connecting a container to the host network is generally considered insecure, as your container can basically access other ports. And it opens you up to a bunch of risks (OMG!)
The man page (
man podman-run) also agrees:
Note: the host mode gives the container full access to local system services such as D-bus and is therefore considered insecure;
For this reason, it’s best used only in development. And you definitely shouldn’t use it for running containers in production.
Use the host network to access the container’s port from the host
Let’s see the host network in action, to see how we can access a service running in a container, from the host.
podman run to run a process in a new, rootless container, and add
--network=host to attach it to the host network:
podman run --network=host nginxinc/nginx-unprivileged
The Nginx web server is now running on port 8080, inside a container.
nginx-unprivileged image is a variation on the standard
nginx image, which is configured to run Nginx on an unprivileged port.)
If I go to my web browser on the host and access http://localhost:8080, I’ll see the nginx welcome page:
How is that? I didn’t configure any port publishing or forwarding…..
Since the container is connected to the
host network, it binds to a port in the host’s network namespace. This is another way of saying that it binds to a port on the host.
You don’t need to set up any extra port publishing, or forwarding, or anything like that. With host network mode, the network is shared between the host and the container. Stuff on localhost in the container can be accessed on localhost from the host.
Heads-up! Since we’re running a rootless container, you must make sure that the application doesn’t attempt to bind (run) on a privileged port, like port 80. If it does try to bind to a privileged port, you’ll see an error like:
bind() to 0.0.0.0:80 failed (13: Permission denied)
So you’ll need to configure your app to bind on a non-privileged port, which is a port number starting from 1024.
Why is this? Because you’re running as a non-privileged (i.e. non-root) user.
From the manpages for
man 7 ip (it took me ages to find exactly where this is described in the manpages!):
The port numbers below 1024 are called privileged ports (or sometimes: reserved ports). Only a privileged process (on Linux: a process that has the CAP_NET_BIND_SERVICE capability in the user namespace governing its network namespace) may bind(2) to these sockets.
On the host network, a container can also access ports on the host
When you use the host network mode, you can also access ports on the host from inside the container.
(This is why it’s considered somewhat insecure.)
On my host operating system, I’m running Apache web server on port 80. I use
curl to make a request to the server and get a silly little test page I created:
$ curl http://localhost:80
Hello, internet friend!
Now what happens when I run that same
curl http://localhost:80 command, but inside a container that’s configured with the host network mode?
$ podman exec -it 8918c8ebbbfd curl http://localhost:80
Hello, internet friend!
I get the same result! My container able to hit the web server that’s running on my host, simply using localhost.
So when a rootless container uses the host network mode, it can access ports on the host, too, using the localhost address.
I hope you got 🌠 VALUE 🌠 out of this article and it’s helped save you some time when setting up ports and networking with your rootless Podman containers.
Don’t forget you shouldn’t really use this in production. But it’s a time-saver for development and lets you run software in containers very easily without fiddling about with port publishing.
Want to learn something else next? I recommend these: