Podman – Quadlets – The Basics
Having been playing with Docker recently and ended up down the root/rootless container rabbit hole, I then stumbled across Podman.
Quadlets
Whilst rootless Podman can work with your existing docker-compose.yml file, v4.4 (I believe) and newer allow you to write Quadlet files which are turned into systemd services. You can then stop / start containers using systemctl rather than docker or podman commands eg:
systemctl --user start <container service name>
So rather than use or try to convert an existing docker-compose.yml, I thought I would start from scratch with Quadlets.
Podman Installation
I’ve been testing this on Ubuntu 24 LTS which lags the most recent releases of Podman. Running
sudo apt install podman
installed v4.9, whereas the most recent release is (as I type this) v5.7.1. A non-LTS Ubuntu image (eg 25) should get v5.3 or newer. Alternatively, other Linux distributions will have 5.x in their repo’s so if you want the latest features before Ubuntu 26 LTS arrives, Ubuntu LTS is probably not the best choice.
Once installed, you can check the installed version via:
podman --version
At this point I created another user called podman to use. All the containers will run under this user. This user will not have the ability to sudo, so the containers will be rootless. Creating the new user is done under my usual login which can sudo:
sudo useradd -m -s /bin/bash podman sudo passwd podman
To ensure containers can run when our podman user isn’t logged in (eg after a reboot), we need to enable linger:
sudo loginctl enable-linger podman
The guides I found (useful one here) required you to edit the /etc/subuid and /etc/subgid files and adding an extra line for your new user. However, I found these already created. To check:
cat /etc/subuid chris:100000:65536 podman:165536:65536
cat /etc/subgid chris:100000:65536 podman:165536:65536
My (admittedly limited!) understanding is that the ID values shouldn’t overlap, so the UID for chris starts at 100000 and provides 65536 IDs (so ends as 165535). The podman user than has the same ammount of space starting at 165536. You can edit these files as sudo to add the extra mapping if required.
If you want a Podman container to use a privileged port, then edit /etc/sysctl.conf and add the line to allow ports upwards from 80 to be used:
net.ipv4.ip_unprivileged_port_start=80
Getting Started
This example will launch a Nginx container.
At this point we should login as our new user, podman.
Podman will look in a few places for the Quadlet configuration files depending if you are root or rootless (see here). I’ve gone with the option to store these inside the Podman user home folder, so the path to create is:
mkdir -p $HOME/.config/containers/systemd
We can create a simple network configuration to use with our container. I’m going to call the network Skynet.
nano .config/containers/systemd/skynet.network
Into this file we can put the following configuration.
[Unit] Description=Skynet After=network-online.target [Network] NetworkName=skynet [Install] WantedBy=default.target
To explain some of the above:
- After=network-online.target ensures the service waits for the host network at startup
- WantedBy=default.target sets the service to start at bootup
If we wanted to, we could specify the IP subnet to use with appropriate gateway, DNS and other settings in the [Network] section but we don’t have to. When left blank, Podman will create them for us and use a private subnet.
Now we can create the Quadlet for our Nginx container:
nano .config/containers/systemd/nginx.container
The contents being:
[Unit] Description=Nginx Webserver [Container] ContainerName=Nginx Image=docker.io/nginx Network=skynet PublishPort=80:80 [Service] Restart=on-failure [Install] WantedBy=default.target
Notice how we are using an image from the docker.io repository – Podman uses the same standards (Open Container Initiative) as Docker, so the same container image can be used on both platforms. We haven’t specified a version of the Nginx container to use, so it will default to latest. To specify a version, add the version you need to the end of the Image line eg “nginx:1.29.4”. The container will be part of our Skynet network and port 80 will be published via the hosting VM.
At this point we can reload systemd to pick up the configuration files, then start the network and container.
systemctl --user daemon-reload
All being well, you’ll see no response from reloading. Now to start the services.
systemctl --user start skynet
Gotcha alert! I got this far in my initial testing and spent an age trying to figure out why when trying to start the network, I kept getting told “Failed to start skynet.service: Unit skynet.service not found.” I was Googling, looking in logfiles – all the usual stuff trying to find a clue. Then I realised how your Quadlets are converted into services.
- nginx.container becomes nginx.service (or just nginx)
- skynet.network becomes skynet-network.service (or just skynet-network)
Yes, I was trying to start a service that didn’t exist. So, the correct commands are:
systemctl --user start skynet-network systemctl --user start nginx
On the first run, the nginx service might be slow starting as it will pull the image from the docker.io repo’, so useful commands to see what is happening are:
systemctl --user status skynet-network systemctl --user status nginx podman ps
As an example, here is podman ps showing everything looking good:

Now to test Nginx using Curl:
curl http://0.0.0.0:80
Curl should return the raw HTML for the standard Nginx “Welcome to Nginx” page . Alternatively, a web browser pointed at the IP of your Podman host VM should also show the Nginx page (firewalls etc allowing).
That should be a very simple test but gives a foundation for building more advanced configurations include mapping host volumes into a container, multiple container environments and the like.
Making Changes
If you edit your config files (.eg container), you need to execute systemctl –user daemon-reload before trying to restart the service (systemctl –user restart <service-name>) otherwise you will see the message:
“Warning: The unit file, source configuration file or drop-ins of <service-name> changed on disk. Run ‘systemctl –user daemon-reload’ to reload units.”
Podman Command Reference
| Command | Operation |
| podman exec | Run a command on the container. For instance, to run a shell you might use: podman exec -it <container_name> /bin/bash |
| podman images | List local container images |
| podman logs <container_name> podman logs <container_id> | View the logs for the specified container. Container name is case-sensitive. Obtain the Container ID using podman ps |
| podman ps | List details of the running containers |
