Dim-Jones Blog
Back to blog

Using Quadlet for Podman and SystemD Integration

2 min read

When running containers with Podman in rootless mode, a significant challenge emerges: containers started in a user session will stop when the session ends, even if they have the restart=always policy. This occurs because rootless containers are bound to the user session by default and do not persist across logouts or reboots.

SystemD and Quadlet address this limitation. Introduced in Podman 4.4, Quadlet simplifies SystemD service integration by replacing the deprecated podman generate systemd command. With Quadlet, we can ensure that rootless containers persist across reboots and user logouts, leveraging SystemD’s service management capabilities.

Setting Up a Container as a Rootless SystemD Service

To integrate a Podman container with SystemD using Quadlet, create .container files in the ~/.config/containers/systemd/ directory. The following example demonstrates an NGINX web server setup.

Step 1: Create the Quadlet Configuration File

Create webserver.container:

[Unit]
Description=Webserver

[Container]
Image=docker.io/library/nginx:alpine
PublishPort=8080:80

[Service]
Restart=always

[Install]
WantedBy=default.target

Why WantedBy=default.target?

For rootless services, using WantedBy=default.target is critical. Specifying only multi-user.target will prevent the service from starting automatically after reboot, since this target applies to system-wide (rootful) services, not user services.

To verify proper enablement at boot:

systemctl --user is-enabled webserver

An output of “enabled” confirms correct configuration.

Step 2: Reload and Start the Service

systemctl --user daemon-reload
systemctl --user enable --now webserver

Step 3: Verify Service Creation

Unlike systemctl --user daemon-reload, which provides no error messages for invalid files, you can verify proper service generation with:

systemctl --user cat webserver

If this command fails to return expected unit content, syntax errors or missing directives likely exist in the .container file.

Note: Even journalctl --user often provides little useful information, making systemctl --user cat one of the most effective diagnostic tools for Quadlet service issues.

Adding a PostgreSQL Database with Persistent Storage

A more complex example demonstrates deploying a PostgreSQL container with persistent volumes.

Step 1: Define the Database Container

Create project-postgres.container:

[Unit]
Description=Postgres DB Project

[Container]
Image=docker.io/library/postgres:14-alpine
Environment=POSTGRES_USER=podman
Environment=POSTGRES_PASSWORD=mysecretpassword
Environment=POSTGRES_DB=training
PublishPort=5432:5432
Volume=project-postgres.volume:/var/lib/postgresql/data

[Install]
WantedBy=default.target

Step 2: Define the Persistent Volume

Create project-postgres.volume:

[Unit]
Description=Postgres Project Volume

[Volume]

Step 3: Reload and Enable Services

systemctl --user daemon-reload
systemctl --user enable --now project-postgres

Verify proper service creation:

systemctl --user cat project-postgres

Rootless vs. Rootful Considerations

Configuration locations and commands differ between rootless and rootful services:

Rootless services are placed in ~/.config/containers/systemd/ with user-scoped commands:

systemctl --user daemon-reload
systemctl --user enable --now webserver

Rootful services go into /etc/containers/systemd/ with privileged commands:

sudo systemctl daemon-reload
sudo systemctl enable --now webserver

What’s Next?

A forthcoming article will demonstrate deploying multiple interconnected containers, creating pods, and automating Quadlet file generation using Podlet.

For additional information, consult the official Podman SystemD Unit documentation.

Dim-Jones

Dim-Jones

Digital engineering agency specialized in DevOps, software development and AI.

Visit dim-jones.com