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
.container
file 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)