Goodbye ‘podman generate systemd’: How to Use Quadlet for Professional Container Management on Fedora

Fedora tutorial - IT technology blog
Fedora tutorial - IT technology blog

Why I Ditched ‘podman generate systemd’ for Quadlet

If you’re running containers on Fedora, you’re likely familiar with the podman generate systemd command. This used to be the standard approach, but it leaves behind a lot of “technical debt.” The generated unit files are often dozens of lines long, containing hardcoded container IDs and making them extremely difficult to maintain. Every time you need to change an environment variable or mount an additional volume, editing the unit file feels like a nightmare.

I’ve used Fedora as my primary dev machine for over two years. When Podman 4.4 introduced Quadlet, I migrated all my personal services to this tool. Quadlet allows you to define containers via concise .container files, similar to systemd configuration. The system automatically compiles them into actual systemd units whenever you reload. It’s very clean and modern.

The biggest advantage is the ability to run rootless (without needing root privileges). On Fedora, Quadlet significantly boosts security without burdening DevOps engineers with complex, specialized configurations.

Preparing the Environment on Fedora

Most Fedora versions from 38 onwards come with the latest Podman pre-integrated. You can quickly check the version with the command:

podman --version

As long as you have version 4.4 or higher, Quadlet is ready to go. If you are using Fedora Minimal, install the necessary package:

sudo dnf install -y podman

An important note for rootless mode: To ensure containers start automatically with the system without requiring a login (via SSH or GUI), enable the linger feature:

loginctl enable-linger $USER

Deploying Your First Container with Quadlet

Forget Docker Compose or long-winded podman run commands. With standard user permissions, you only need to work in the directory: ~/.config/containers/systemd/.

Create the configuration directory if it doesn’t exist:

mkdir -p ~/.config/containers/systemd/

Let’s try setting up an Nginx instance as a personal web server. Create the my-web.container file:

nano ~/.config/containers/systemd/my-web.container

Copy the following configuration content:

[Unit]
Description=Nginx Web Server running with Quadlet
After=network-online.target

[Container]
Image=docker.io/library/nginx:latest
PublishPort=8080:80
Volume=/home/user/html:/usr/share/nginx/html:Z
Environment=FOO=BAR

[Install]
WantedBy=default.target

Key parameters to note:

  • [Unit]: After=network-online.target ensures the container waits for network availability before starting.
  • [Container]: This is the heart of the file.
    • Image: Declares the image to use.
    • PublishPort: Maps port 8080 on the host to port 80 inside the container.
    • Volume: The :Z suffix is a lifesaver on Fedora. It helps Podman handle SELinux labels automatically, completely avoiding frustrating “Permission denied” errors.

Activating and Managing the Service

After saving the file, Quadlet doesn’t apply changes immediately. You need to tell systemd to rescan the configuration:

systemctl --user daemon-reload

At this point, a service named my-web.service has been automatically created. You can control it like any normal system service:

# Start the service
systemctl --user start my-web.service

# Check operational status
systemctl --user status my-web.service

# Automatically run on boot
systemctl --user enable my-web.service

This process is incredibly smooth. To update the image, just run podman pull nginx:latest and then systemctl --user restart my-web. The system handles destroying the old container and creating a new one; no manual ID management required.

Inspection & Monitoring

Container logs are now part of the systemd journal. Centralized management makes it much easier to track down errors:

journalctl -f --user-unit my-web.service

If you want a closer look from a Podman perspective, the podman ps command still works perfectly. If the service doesn’t appear after a reload, use Quadlet’s debug tool:

/usr/libexec/podman/quadlet -user --dry-run

This command renders the raw systemd unit file. If there are syntax errors in your .container file, you’ll see error messages here instead of having to guess.

Practical Notes on SELinux and Ports

Many people disable SELinux because they find volume mounting annoying. Don’t do that. Instead of setenforce 0, use :Z for private volumes or :z for shared volumes. Fedora will automatically relabel them to protect the system while still allowing container access.

Regarding Ports, Fedora by default blocks non-root users from using ports below 1024 (like 80, 443). The best approach is to use high ports like 8080 or 8443, then use a Reverse Proxy like Caddy or Nginx in front to route traffic. This is both secure and follows rootless standards.

Moving to Quadlet is the right move if you want to manage containers professionally and achieve long-term stability on the Fedora ecosystem.

Share: