{"title":"Podman Quadlets","url":"https://seanbehan.ca/posts/quadlets","description":"Quadlets describe a container as a systemd unit, so systemd owns the lifecycle instead of Podman.","author":"Sean Behan","published":"2025-03-28T14:39:58.000Z","updated":null,"draft":false,"tags":["containers","linux","podman","quadlet","systemd"],"readingMinutes":3,"image":null,"sections":[{"id":"what-are-quadlets","text":"What are Quadlets?","level":2},{"id":"container-quadlets","text":"Container Quadlets","level":2},{"id":"pod-quadlets","text":"Pod Quadlets","level":2},{"id":"dependencies","text":"Dependencies","level":2},{"id":"example-nginx-and-certbot","text":"Example: Nginx and Certbot","level":2},{"id":"nginx-container","text":"Nginx Container","level":2},{"id":"certbot-container","text":"Certbot Container","level":2},{"id":"nginx-with-ssl","text":"Nginx with SSL","level":2},{"id":"automatic-certificate-renewal","text":"Automatic Certificate Renewal","level":2}],"content_format":"text/markdown","content_url":"https://seanbehan.ca/posts/quadlets.md","content":"### What are Quadlets?\n\nIn this post I'll show you what a quadlet is and how you can use it to manage\n\nyour containers.\n\nQuadlets are a new way to manage containers using systemd. They are a new\n\nformat for systemd units that allow you to manage containers using systemd.\n\n### Container Quadlets\n\nHere's an example of a container quadlet.\n\n```systemd\n[Container]\nImage=docker.io/library/alpine:latest\nExec=sleep infinity\nAutoUpdate=registry\n```\n\nIf you put this in ~/.config/containers/systemd/alpine.container you can start\n\nit with `systemctl --user start alpine` and it will start a new container.\n\nJust make sure to `systemctl --user daemon-reload` to reload the systemd daemon\n\nafter you create the quadlet. You have to do this every time, I won't repeat\n\nthis throughout the blog post.\n\n### Pod Quadlets\n\nYou can also use quadlets to manage pods. Here's an example of a pod quadlet.\n\n```systemd\n[Pod]\n```\n\nYep, that's it. If you put it in `~/.config/containers/systemd/mypod.pod` you can\n\nstart it with `systemctl --user start mypod-pod` and it will start a new pod.\n\nBut the best part is this. If you want to add a container to a pod all you have\n\nto do is this.\n\n```systemd\n[Container]\nImage=docker.io/library/alpine:latest\nExec=sleep infinity\nAutoUpdate=registry\nPod=mypod.pod\n```\n\nNow when you start `mypod-pod` it will start the container as well.\n\n### Dependencies\n\nYou can add dependencies.\n\n```systemd\n[Unit]\nAfter=alpine.service\n\n[Container]\nImage=docker.io/library/archlinux:latest\nExec=sleep infinity\nAutoUpdate=registry\nPod=mypod.pod\n```\n\nNow archlinux will start after alpine.\n\nThere are even more options. You can start .kube, .network, and .build quadlets\n\ntoo and they can depend on each other. See the\n\n[docs](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html)\n\nfor more info!\n\n---\n\n### Example: Nginx and Certbot\n\nOkay so now lets run something useful :)\n\nHow about an nginx container and a certbot container to get a certificate for it?\n\n### Nginx Container\n\nFirst lets create a directory to hold our files.\n\n```sh\nmkdir -p ~/.config/containers/systemd/www\n```\n\nNext we create a quadlet for our nginx container.\n\n```systemd\n[Container]\nImage=docker.io/nginx:latest\nPublishPort=80:80\nPublishPort=443:443\nAutoUpdate=registry\nVolume=./www:/usr/share/nginx/html\n```\n\nThis will run a web server for us. If you aren't root, you'll need to enable unprivleged ports.\n\n```sh\nsudo sysctl net.ipv4.ip_unprivileged_port_start=0\n```\n\nNow we can start it with `systemctl --user start nginx` and it will start a new container.\n\nIf you browse to `http://localhost` you should see the nginx welcome page.\n\n### Certbot Container\n\nNow we need to get a certificate for it. We can use certbot for this.\n\n```systemd\n[Container]\nImage=docker.io/certbot/certbot:latest\nVolume=letsencrypt:/etc/letsencrypt\nVolume=./www:/mnt\nExec=certonly --webroot --webroot-path /mnt --agree-tos --email your@email.com -d your.domain.com\nAutoUpdate=registry\n```\n\nMake sure to replace your@email.com and your.domain.com with your own email and domain.\n\nThen start the container with `systemctl --user start certbot` and it will get a certificate for you.\n\n### Nginx with SSL\n\nNow you can use the certificate in your nginx container.\n\n```systemd\n[Container]\nImage=docker.io/nginx:latest\nPublishPort=80:80\nPublishPort=443:443\nAutoUpdate=registry\nVolume=letsencrypt:/etc/letsencrypt\n```\n\nThat's great, but now we need to configure nginx to use the certificate. We can\n\ndo this by adding a volume for the configuration file.\n\n```systemd\n[Container]\nImage=docker.io/nginx:latest\nPublishPort=80:80\nPublishPort=443:443\nAutoUpdate=registry\nVolume=letsencrypt:/etc/nginx/certs\nVolume=./nginx.conf:/etc/nginx/conf.d\n```\n\nAlong with a configuration file for nginx.\n\n```nginx\nserver {\n    listen 443 ssl;\n    server_name your.domain.com;\n\n    ssl_certificate /etc/nginx/certs/live/your.domain.com/fullchain.pem;\n    ssl_certificate_key /etc/nginx/certs/live/your.domain.com/privkey.pem;\n\n    location / {\n        root /usr/share/nginx/html;\n        index index.html;\n    }\n}\n```\n\nAgain, make sure to replace your.domain.com with your own domain.\n\nNow you can start the container with `systemctl --user start nginx` and it will\n\nstart a new container with the certificate. You can verify this by going to\n\n`https://your.domain.com`.\n\nNow you have a web server with HTTPS.\n\n### Automatic Certificate Renewal\n\nIf you want to renew your certificate automatically it's as simple as this.\n\n```systemd\n[Container]\nImage=docker.io/certbot/certbot:latest\nExec=renew\nAutoUpdate=registry\nVolume=letsencrypt:/etc/letsencrypt\n```\n\nNow you can create a timer for it in `~/.config/systemd/user/certbot.timer`.\n\n```systemd\n[Unit]\nDescription=Renew Certbot certificates\n\n[Timer]\nOnCalendar=Sun 00:00:00\nPersistent=true\nUnit=certbot.service\n\n[Install]\nWantedBy=timers.target\n```\n\nNow you enable the timer.\n\n```sh\nsystemctl --user enable --now certbot.timer\n```\n\nNow your certificate will be renewed every Sunday at midnight.\n\nThat's it! Now you have a web server with HTTPS and a certificate that will be\n\nrenewed automatically.\n"}