Skip to main content

Command Palette

Search for a command to run...

Podman Quadlet: Modern systemd Integration

Updated
3 min read
Podman Quadlet: Modern systemd Integration

Quadlet replaces the old podman generate systemd approach with a cleaner, more declarative configuration system.

How Quadlet Works

Quadlet uses .container, .volume, .network, and .pod files that systemd automatically converts to service units at boot time.

File Locations

Place your Quadlet files in:

  • System-wide: /etc/containers/systemd/

  • User-specific: ~/.config/containers/systemd/

Basic Container Example

Create a file: /etc/containers/systemd/nginx.container

[Unit]
Description=Nginx Web Server
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/library/nginx:latest
PublishPort=8080:80
Volume=/var/www/html:/usr/share/nginx/html:ro
Environment=MY_ENV_VAR=value

[Service]
Restart=always
TimeoutStartSec=900

[Install]
WantedBy=multi-user.target default.target

Activate it:

# Reload systemd to discover the new unit
sudo systemctl daemon-reload

# Start the container
sudo systemctl start nginx

# Enable on boot
sudo systemctl enable nginx

# Check status
sudo systemctl status nginx

Pod Example with Quadlet

Create: /etc/containers/systemd/webapp.pod

[Unit]
Description=Web Application Pod

[Pod]
PublishPort=8080:80
Network=webapp-net.network

[Install]
WantedBy=multi-user.target default.target

Create: /etc/containers/systemd/webapp-nginx.container

[Unit]
Description=Nginx in webapp pod
Requires=webapp.pod
After=webapp.pod

[Container]
Image=nginx:latest
Pod=webapp.pod

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Create: /etc/containers/systemd/webapp-redis.container

[Unit]
Description=Redis in webapp pod
Requires=webapp.pod
After=webapp.pod

[Container]
Image=redis:latest
Pod=webapp.pod

[Service]
Restart=always

[Install]
WantedBy=multi-user.target default.target

Activate the pod:

sudo systemctl daemon-reload
sudo systemctl start webapp.pod
sudo systemctl enable webapp.pod

Network Example

Create: /etc/containers/systemd/webapp-net.network

[Unit]
Description=Web application network

[Network]
Subnet=10.89.0.0/24
Gateway=10.89.0.1

Volume Example

Create: /etc/containers/systemd/data.volume

[Unit]
Description=Data volume

[Volume]
User=1000
Group=1000

Complete Django + PostgreSQL Example

1. Network: /etc/containers/systemd/django-net.network

[Network]
Subnet=10.88.0.0/24

2. Volume: /etc/containers/systemd/postgres-data.volume

[Volume]

3. Database: /etc/containers/systemd/postgres.container

[Unit]
Description=PostgreSQL Database
After=network-online.target
Wants=network-online.target

[Container]
Image=docker.io/library/postgres:15
Volume=postgres-data.volume:/var/lib/postgresql/data
Network=django-net.network
Environment=POSTGRES_PASSWORD=secret
Environment=POSTGRES_USER=django
Environment=POSTGRES_DB=myapp

[Service]
Restart=always
TimeoutStartSec=120

[Install]
WantedBy=multi-user.target default.target

4. Django App: /etc/containers/systemd/django.container

[Unit]
Description=Django Application
After=postgres.service
Requires=postgres.service

[Container]
Image=localhost/mydjango:latest
PublishPort=8000:8000
Network=django-net.network
Environment=DATABASE_HOST=postgres
Environment=DATABASE_NAME=myapp
Environment=DATABASE_USER=django
Environment=DATABASE_PASSWORD=secret
Volume=/app/media:/app/media
Volume=/app/static:/app/static

[Service]
Restart=always
TimeoutStartSec=300

[Install]
WantedBy=multi-user.target default.target

Activate:

sudo systemctl daemon-reload
sudo systemctl enable --now postgres django

Useful Quadlet Options

Container Section Options:

[Container]
Image=docker.io/library/nginx:latest
ContainerName=my-nginx
PublishPort=8080:80
PublishPort=443:443
Volume=/host/path:/container/path:ro
Volume=myvolume:/data
Environment=KEY=VALUE
EnvironmentFile=/path/to/env/file
Network=mynetwork.network
Pod=mypod.pod
User=1000
Group=1000
Exec=/custom/entrypoint.sh
AddCapability=NET_ADMIN
DropCapability=ALL
SecurityLabelDisable=true

Service Section Options:

[Service]
Restart=always
RestartSec=10
TimeoutStartSec=900
Type=notify
NotifyAccess=all

User Mode (Rootless) Quadlet

For running containers as a regular user:

1. Create directory:

mkdir -p ~/.config/containers/systemd

2. Create: ~/.config/containers/systemd/myapp.container

[Unit]
Description=My User Application

[Container]
Image=myapp:latest
PublishPort=8080:8080

[Service]
Restart=always

[Install]
WantedBy=default.target

3. Activate:

systemctl --user daemon-reload
systemctl --user enable --now myapp
loginctl enable-linger $USER  # Keep services running after logout

Migration from Old Generate Systemd

Old way (deprecated):

podman generate systemd --name mycontainer > mycontainer.service

New way with Quadlet:

  1. Create .container file instead

  2. Let systemd-generator handle the conversion

  3. Much cleaner and more maintainable

Advantages of Quadlet

Declarative configuration - Easy to read and maintain
Automatic dependency management - systemd handles ordering
Native systemd integration - Works like any other service
Git-friendly - Configuration files, not generated scripts
Supports all Podman features - Pods, networks, volumes
Better for GitOps - Store configs in version control

Checking and Debugging

# See generated service units
systemctl cat nginx

# Check logs
journalctl -u nginx -f

# Reload after changes
systemctl daemon-reload
systemctl restart nginx

# List all container services
systemctl list-units 'quadlet-*'

This is the modern, recommended approach for managing Podman containers with systemd! 🚀

Feel free to criticize and share your opinions! Stay safe

More from this blog

W

Whats wrong with ...?

6 posts

A programming blog where I debug problems, share solutions, and learn in public. Join me as I explore what's wrong with code, concepts, and my own understanding—then fix it together.