Linux Tutorials

Install Podman on Fedora 45 / 44: Rootless, Quadlet and Firewall

Podman is the container engine Fedora ships and supports. It runs containers without a daemon, and as a normal user by default. Fedora 45 carries Podman 6.1 and Fedora 44 carries Podman 5.8. The install is one command on both. The parts that catch people out come after the install: published ports that firewalld blocks for one user and not for another, containers that die when you log out, and search settings in registries.conf that Fedora 45 now overrides. Tested on Fedora 45 and Fedora 44 in October 2026; every output below is a real capture from those two VMs.

Original content from computingforgeeks.com - post 20885

What you get on Fedora 45 and Fedora 44

Both releases use the same stack: netavark for networking, pasta for rootless networking, SQLite for the container database and cgroup v2. The difference is the Podman major version and where the default config lives.

ComponentFedora 44Fedora 45
Podman5.8.76.1.3
netavark1.17.22.1.0
crun1.281.30.1
containers-common0.67.20.69.2
Rootless networkpastapasta (slirp4netns removed in Podman 6)
Default config files/etc/containers//usr/share/containers/*.conf.d/00-vendor.conf

Podman 6 dropped slirp4netns, the iptables firewall driver and the old BoltDB database. If you are upgrading a Fedora 44 machine that already has containers, read how to fix Podman containers after a Fedora upgrade first. The full list of upstream removals is in Podman 6 breaking changes.

Install Podman

Fedora Workstation pulls Podman in for Toolbx, and the Fedora Cloud images we used had it installed through the image package group. Check before you install anything:

rpm -q podman

On a minimal install, or after removing it, install it from the Fedora repos:

sudo dnf install -y podman

On Fedora 45 that pulled 45 packages and used 256 MiB. Most of the size is qemu-user-static, a weak dependency that lets Podman run images built for other CPU architectures. Fedora 44 pulled 45 packages for 247 MiB. If you only run x86_64 images, skip the weak dependencies:

sudo dnf install -y --setopt=install_weak_deps=False podman

That drops the transaction to 19 packages and 78 MiB. Rootless containers, pasta networking and overlay storage all worked on the slim install. What you lose is foreign-architecture images. Without the emulator, an arm64 image pulls fine and then fails at exec. The pull progress lines are left out below:

podman run --rm --platform linux/arm64 docker.io/library/alpine:latest uname -m

The run ends with:

{
  "msg": "exec container process `/bin/uname`: Exec format error",
  "level": "error",
  "time": "2026-10-04T15:03:58.396550Z"
}

Install the emulator for the architecture you need and the same command works:

sudo dnf install -y qemu-user-static-aarch64
podman run --rm --platform linux/arm64 docker.io/library/alpine:latest uname -m

Leaving out the dnf transaction, the container reports its architecture:

aarch64

One detail from testing: removing the emulator package doesn’t unregister it from the running kernel. Right after dnf remove, the same arm64 run still printed aarch64. After a reboot, the same run failed as shown above.

Verify the install

Check the version and the components behind it:

podman version
rpm -q podman passt netavark aardvark-dns crun conmon containers-common-extra

Output on Fedora 45:

Client:        Podman Engine
Version:       6.1.3
API Version:   6.1.3
Go Version:    go1.27.1-X:nodwarf5
Git Commit:    85b994955e0b4e30fbce9c8351cab85676140ede
Built:         Tue Sep 29 00:00:00 2026
Build Origin:  Fedora Project
OS/Arch:       linux/amd64
podman-6.1.3-1.fc45.x86_64
passt-0^20261002.gcba3570-1.fc45.x86_64
netavark-2.1.0-1.fc45.x86_64
aardvark-dns-2.1.0-1.fc45.x86_64
crun-1.30.1-1.fc45.x86_64
conmon-2.2.1-2.fc45.x86_64
containers-common-extra-0.69.2-1.fc45.noarch

Then confirm the storage driver, network backend, rootless network command, database and cgroup version in one line:

podman info --format "{{.Store.GraphDriverName}} {{.Host.NetworkBackend}} {{.Host.RootlessNetworkCmd}} {{.Host.DatabaseBackend}} {{.Host.CgroupsVersion}}"

Fedora 45 and Fedora 44 returned the same answer:

overlay netavark pasta sqlite v2

Both checks on the Fedora 45 VM:

Podman 6.1.3 version and package versions on Fedora 45

Run your first rootless container

No group membership and no sudo is needed. Rootless Podman maps container users through the ranges in /etc/subuid and /etc/subgid, which useradd fills in for local users. Accounts from FreeIPA, LDAP or SSSD get no entries there and need them added. Confirm your entry exists:

grep "^$USER:" /etc/subuid /etc/subgid

Run a container with a fully qualified image name:

podman run --rm docker.io/library/alpine:latest cat /etc/alpine-release

Use the full name in scripts. Fedora enforces short-name resolution, so a bare name that has no alias stops when there is no terminal to prompt on:

podman pull adminer

It fails straight away:

Error: short-name resolution enforced but cannot prompt without a TTY

Common names like nginx and busybox work because they are listed in the shipped alias file. The next section shows how to add your own aliases and search registries.

Configure registries on Fedora 45

This is the change most likely to break an existing setup. On Fedora 44, /etc/containers/registries.conf holds the defaults and you edit it in place. On Fedora 45, containers-common ships no registries.conf or policy.json in /etc/containers. The defaults sit in drop-ins under /usr/share/containers:

ls /etc/containers/ /usr/share/containers/

The two directories on Fedora 45:

/etc/containers/:
certs.d
networks
oci
registries.conf.d
registries.d
systemd

/usr/share/containers/:
containers.conf
containers.conf.d
mounts.conf
podman-sequoia
policy.json
registries.conf
registries.conf.d
registries.d
seccomp.json
selinux
storage.conf
storage.conf.d
storage.rootful.conf.d
storage.rootless.conf.d
systemd

The search list and the short-name mode now come from /usr/share/containers/registries.conf.d/00-vendor.conf. Drop-ins are applied after the main file. So if you create, or carry over, a full /etc/containers/registries.conf, the vendor drop-in overrides its search list and short-name mode. Registry tables in it, such as mirrors, still apply. We tested that with a main file that sets a single search registry and permissive mode:

printf "unqualified-search-registries = [\"docker.io\"]\nshort-name-mode = \"permissive\"\n" | sudo tee /etc/containers/registries.conf >/dev/null
podman pull adminer

The pull still stops at the short-name check:

Error: short-name resolution enforced but cannot prompt without a TTY

Both settings were overridden. The fix is to put the same lines in a drop-in whose file name sorts after 00-vendor.conf. Drop-ins from all the directories are sorted together by file name, so a file called 00-local.conf would lose again:

sudo mv /etc/containers/registries.conf /etc/containers/registries.conf.d/50-search.conf
podman pull adminer

The first two lines of the pull:

Resolving "adminer" using unqualified-search registries (/etc/containers/registries.conf.d/50-search.conf)
Trying to pull docker.io/library/adminer:latest...

A single user can add aliases without root. Files in ~/.config/containers/registries.conf.d/ apply to that user only:

mkdir -p ~/.config/containers/registries.conf.d
printf "[aliases]\n  \"adminer\" = \"docker.io/library/adminer\"\n" > ~/.config/containers/registries.conf.d/50-aliases.conf
podman pull adminer

The first two lines again show where the name came from:

Resolved "adminer" as an alias (/home/josphat/.config/containers/registries.conf.d/50-aliases.conf)
Trying to pull docker.io/library/adminer:latest...

The full search order, including the per-UID rootless directories, is in man 5 containers-registries.conf. On Fedora 44, editing /etc/containers/registries.conf still works as before.

Fedora 45 overriding the search settings in /etc/containers/registries.conf until they move to a drop-in

Publish ports from rootless containers

Rootless containers cannot bind ports below 1024. The error comes from pasta, and it is identical on Fedora 44 and Fedora 45:

podman run -d --name web -p 80:80 docker.io/library/nginx:latest

Pasta refuses the bind:

Error: pasta failed with exit code 1:
Listen failed for HOST TCP port */80: Permission denied
Couldn't listen on requested ports

This catches people out: the failed run still creates the container. Retry with a different port and the name is taken:

podman run -d --name web -p 8080:80 docker.io/library/nginx:latest

Podman refuses the name:

Error: creating container storage: the container name "web" is already in use by a50122b9d2154503734873b280afe1868318b6add884feaadd09e82078365260. You have to remove that container to be able to reuse that name: that name is already in use, or use --replace to instruct Podman to do so.

Add --replace, or remove the leftover with podman rm web:

podman run -d --replace --name web -p 8080:80 docker.io/library/nginx:latest
curl -sI http://127.0.0.1:8080 | head -1

The new container ID, then the response:

ed8d2095c35ddb29704bf099b38a89302565351b49e273c61160fc0c2413cd05
HTTP/1.1 200 OK

If a rootless container must own port 80, lower the unprivileged port floor for the whole host:

echo "net.ipv4.ip_unprivileged_port_start = 80" | sudo tee /etc/sysctl.d/90-unprivileged-ports.conf
sudo sysctl --system

After that, -p 80:80 worked as a normal user. Every user on the host can then bind ports 80 to 1023, so prefer a reverse proxy on a single box shared by several people.

Open the firewall for published ports

Fedora Server and Workstation run firewalld. Rootless and rootful containers behave differently behind it, and the difference surprises people in both directions. Our Fedora 45 VM ran firewalld with the public zone, ran a rootless nginx on ports 80 and 8080, and a rootful nginx on port 8081:

sudo podman run -d --name rootweb -p 8081:80 docker.io/library/nginx:latest

From a second machine on the same network:

for p in 80 8080 8081; do printf "port %s: " $p; curl -s -o /dev/null -m 4 -w "%{http_code}\n" http://f45-01:$p/ || echo; done

Results:

port 80: 000

port 8080: 000

port 8081: 200

The rootless ports were blocked, which is what you want. The rootful port was reachable even though 8081 is not open in the zone. Netavark writes its own nftables DNAT rules, and firewalld accepts DNAT traffic:

sudo nft list ruleset | grep -E "table|dnat" | head

The relevant lines from the ruleset:

table inet netavark {
		tcp dport 8081 jump nv_2f259bab_10_88_0_0_nm16_dnat
	chain nv_2f259bab_10_88_0_0_nm16_dnat {
		tcp dport 8081 ct mark set meta mark | 0x00001000 dnat ip to 10.88.0.2:80
table inet firewalld { # progname firewalld
		ct status dnat accept
		ct status dnat accept
		ct status dnat accept

Fedora 44 with Podman 5.8 gave the same result: rootless 8080 blocked, rootful 8081 open. So treat every rootful -p as a public port. Bind it to one address when it should stay local, for example -p 127.0.0.1:8081:80.

Rootless ports need a normal firewalld rule:

sudo firewall-cmd --permanent --add-port={80,8080}/tcp
sudo firewall-cmd --reload

The same curl loop from the second machine, run for ports 80 and 8080, now gets an answer:

port 80: 200
port 8080: 200

The zone matters too. The FedoraWorkstation zone already allows TCP and UDP 1025 to 65535, so on a desktop install rootless ports above 1024 are reachable without any rule. The FedoraServer zone allows only cockpit, dhcpv6-client and ssh.

Published port test from a second machine: rootless ports blocked by firewalld, rootful port open, then both rootless ports open after the rule

Use SELinux labels on bind mounts

SELinux is enforcing on Fedora. A host directory mounted without a label is unreadable inside the container. Nginx returned 403 for a page in the home directory:

mkdir -p ~/site && echo "hello from f45-01" > ~/site/index.html
podman run -d --replace --name site -p 8082:80 -v ~/site:/usr/share/nginx/html:ro docker.io/library/nginx:latest
curl -s http://127.0.0.1:8082/ | grep -o "<title>.*</title>"

Nginx cannot read the file:

<title>403 Forbidden</title>

Add Z to the mount options. Podman relabels the directory with a private container_file_t context:

podman run -d --replace --name site -p 8082:80 -v ~/site:/usr/share/nginx/html:ro,Z docker.io/library/nginx:latest
curl -s http://127.0.0.1:8082/
ls -Z ~/site/index.html

The page loads, and the file carries the new label:

hello from f45-01
system_u:object_r:container_file_t:s0:c170,c261 /home/josphat/site/index.html

Use a lowercase z when several containers share the directory. Never use either option on a system path like /home or /etc. For more SELinux detail, see Podman SELinux contexts.

Keep rootless containers running after logout

On a server this one bites. Rootless containers belong to your systemd user session. Without lingering, systemd stops that session about ten seconds after your last login closes, and the containers go with it. Our web container was started over SSH. When we logged back in 30 seconds later, it had already exited:

podman ps -a --format "{{.Names}} {{.Status}}"

Both containers had exited:

web80 Exited (0) 49 seconds ago
web Exited (0) 20 seconds ago

Enable lingering for the user. Run it with sudo; from a non-interactive SSH session a plain request from the user fails:

loginctl enable-linger

Over SSH, the request is refused:

Could not enable linger: Access denied

Run it with sudo instead:

sudo loginctl enable-linger $USER
loginctl show-user $USER -p Linger

Lingering is now on:

Linger=yes

With lingering on, both containers were still up after the session closed. Lingering keeps them alive. It does not start them again after a reboot. For that, use Quadlet.

Run a container as a systemd service with Quadlet

Quadlet turns a small .container file into a systemd unit. Create one in the Quadlet directory for your user:

mkdir -p ~/.config/containers/systemd
vi ~/.config/containers/systemd/web.container

The unit serves the same ~/site directory and opts into automatic image updates:

[Unit]
Description=nginx web

[Container]
Image=docker.io/library/nginx:latest
PublishPort=8080:80
Volume=%h/site:/usr/share/nginx/html:ro,Z
AutoUpdate=registry

[Install]
WantedBy=default.target

Preview the generated podman run line, then load and start the service:

/usr/libexec/podman/quadlet -dryrun -user 2>&1 | grep -E "^(ExecStart|---)" | head -3
systemctl --user daemon-reload
systemctl --user start web.service

The generated command line:

---web.service---
ExecStart=/usr/bin/podman run --name systemd-%N --replace --rm --cgroups=split --sdnotify=conmon -d -v %h/site:/usr/share/nginx/html:ro,Z --label io.containers.autoupdate=registry --publish 8080:80 docker.io/library/nginx:latest

Don’t run systemctl --user enable on it. The unit is generated:

systemctl --user enable web.service

Systemd refuses it:

Failed to enable unit: Unit /run/user/1001/systemd/generator/web.service is transient or generated

The [Install] section already does the job. After a reboot, with lingering on, the service started at boot on its own:

uptime -p; systemctl --user is-active web.service
podman ps --format "{{.Names}} {{.Status}} {{.Ports}}"
curl -s http://127.0.0.1:8080/

After the reboot:

up 0 minute
active
systemd-web Up 22 seconds 0.0.0.0:8080->80/tcp
hello from f45-01

The same unit file worked unchanged on Fedora 44. Pods, networks, volumes and .kube units are covered in Podman Quadlet with systemd on Fedora.

Quadlet web.service running after a reboot on Fedora 45

Turn on automatic image updates

The AutoUpdate=registry line labels the container, but nothing checks for updates until the timer runs. It is disabled by default on both releases. Check what would update:

podman auto-update --dry-run

One container is labelled for updates:

            UNIT         CONTAINER                   IMAGE                           POLICY      UPDATED
            web.service  272a6073c7e6 (systemd-web)  docker.io/library/nginx:latest  registry    false

Then enable the daily timer for the user:

systemctl --user enable --now podman-auto-update.timer
systemctl --user list-timers podman-auto-update.timer --no-pager

The timer list is cut to its first two lines:

Created symlink '/home/josphat/.config/systemd/user/timers.target.wants/podman-auto-update.timer' → '/usr/lib/systemd/user/podman-auto-update.timer'.
NEXT                        LEFT LAST PASSED UNIT                     ACTIVATES
Mon 2026-10-05 00:00:19 UTC   8h -         - podman-auto-update.timer podman-auto-update.service

When a newer image appears, Podman pulls it and restarts the service. If the restarted unit fails, Podman rolls back to the previous image. That check relies on systemd readiness, so an app that crashes after its container reports ready is not caught.

Use Docker tools with Podman

Many tools expect a docker command or a Docker socket. Podman covers both. The podman-docker package adds a docker wrapper:

sudo dnf install -y podman-docker
docker ps --format "{{.Names}}"

Skipping the dnf transaction, the docker call prints:

Emulate Docker CLI using podman. Create /etc/containers/nodocker to quiet msg.
web80
web

Create the file it mentions to silence the notice: sudo touch /etc/containers/nodocker. For tools that talk to the Docker API, start the user API socket:

systemctl --user enable --now podman.socket
curl -s --unix-socket $XDG_RUNTIME_DIR/podman/podman.sock http://d/_ping

The socket answers the ping:

Created symlink '/home/josphat/.config/systemd/user/sockets.target.wants/podman.socket' → '/usr/lib/systemd/user/podman.socket'.
OK

The socket answered the Docker-compatible API at version 1.44 on Podman 6.1.3. Point Docker clients at it with DOCKER_HOST when you run them directly. podman compose sets up that connection for its provider by itself, and it calls the Fedora docker-compose package when that is installed. We exported the variable anyway in our run. Our test project in ~/demo/compose.yaml was a single nginx service:

services:
  web:
    image: docker.io/library/nginx:latest
    ports:
      - "8083:80"

Install the provider and bring it up:

sudo dnf install -y docker-compose
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
cd ~/demo && podman compose up -d

The compose run prints:

 Container demo-web-1 Creating
 Container demo-web-1 Created
 Container demo-web-1 Starting
 Container demo-web-1 Started

That output is the last four lines. The compose file and the choice between docker-compose and podman-compose are covered in Podman Compose on Fedora. If you need the real Docker Engine instead, follow install Docker on Fedora. Do not run both engines for the same workloads.

Troubleshooting

Error: short-name resolution enforced but cannot prompt without a TTY

The image name has no registry and no alias. Use the full name, such as docker.io/library/adminer, or add an alias or search registry in a drop-in as shown above. On Fedora 45, the search list and short-name mode in a full /etc/containers/registries.conf are overridden by the vendor drop-in.

Listen failed for HOST TCP port */80: Permission denied

A rootless container asked for a port below 1024. Publish a high port, or lower net.ipv4.ip_unprivileged_port_start. Remove the container left in Created state before you retry.

Containers stop a few seconds after you log out

Lingering is off for the user. Run sudo loginctl enable-linger $USER, and use Quadlet for anything that must survive a reboot.

slirp4netns support has been removed

The container or containers.conf still asks for slirp4netns, which Podman 6 dropped. Run podman system migrate and remove the setting. The full walkthrough, including Quadlet files and the iptables firewall driver error, is in fix Podman after a Fedora upgrade.

Next steps

Podman also powers Toolbx on Fedora. If you want mutable development shells next to the host, read Distrobox and Toolbx on Fedora. For the rest of a new install, the things to do after installing Fedora 45 list covers repos, codecs and updates, and the dnf5 cheatsheet covers package management. Release changes beyond containers are summarised in what is new in Fedora 45. On other distributions, see Podman on Ubuntu 26.04 and Podman and Buildah on Rocky Linux and AlmaLinux.

Keep reading

Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Fedora Enable RPM Fusion and Install Multimedia Codecs on Fedora 45 / 44 / 43 Best UI Applications for Managing Docker Containers Containers Best UI Applications for Managing Docker Containers Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Fedora Harden Fedora 45 / 44 for Desktop and Server: Complete Guide Install Coolify on Ubuntu 26.04 LTS (Self-Hosted PaaS) Cloud Install Coolify on Ubuntu 26.04 LTS (Self-Hosted PaaS) Install COSMIC Desktop on Fedora: Spin, Atomic or dnf group Desktop Install COSMIC Desktop on Fedora: Spin, Atomic or dnf group How To Install Docker CE on RHEL 7 Linux Containers How To Install Docker CE on RHEL 7 Linux

Leave a Comment

Press ESC to close