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:
- Create
.containerfile instead - Let systemd-generator handle the conversion
- 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
Top comments (0)