« Previous 1 2 3 4 Next »
Run rootless Podman containers as systemd services
Power Up
Defining a First Container
After all this preparation, you can now define your first systemd unit file for a container. As an example, set up FreshRSS [7], a self-hosted RSS feed aggregator (Figure 2). To have this service start automatically in a Podman container, define the systemd unit shown in Listing 1 in the file ~/.config/containers/systemd/freshrss.container
.

Listing 1
freshrss.container
01 [Unit] 02 Description=FreshRSS feed aggregator 03 04 [Container] 05 Image=docker.io/freshrss/freshrss:1.25.0 06 ContainerName=freshrss 07 HostName=freshrss 08 Volume=%h/containers/freshrss/data:/var/www/FreshRSS/data:Z 09 Volume=%h/containers/freshrss/extensions:/var/www/FreshRSS/extensions:Z 10 Environment=TZ=Europe/Brussels 11 Environment=CRON_MIN=1,31 12 PublishPort=80:80 13 14 [Service] 15 Restart=always 16 17 [Install] 18 WantedBy=default.target
If you are familiar with systemd unit files for services, you'll notice a new section: [Container]
. The file name also uses the .container
extension instead of .service
to indicate that it's a container unit.
The [Container]
section has various options for your container, documented extensively in the Podman Quadlet [4] man page. In this example, I define the container image, name, hostname, volumes, environment variables, and ports you want to publish.
The Volume
statement in line 8 indicates that the directory containers/freshrss/data
in the host's home directory (%h
) of the user is mounted at /var/www/FreshRSS/data
within the container. On an SELinux-enabled system, the Z
option specifies that this directory is used only by this container, ensuring it receives the proper labeling. If the directory is shared with other containers, use the lowercase z
option instead, and use ro
for a read-only mount within the container.
Under the user's home directory, create these directories on your host system:
$ mkdir -p ~/containers/freshrss/{data,extensions}
I typically create a ~/containers
directory within the user's home directory with a subdirectory for each rootless container. If you prefer a different setup, adjust the volumes in the container unit file accordingly.
Next, the [Container]
section of the unit file has a line for each environment variable and then a line to publish the container's port (line 12). In this case, container port 80 (defined after the colon) from the container is exposed to port 80 on the host (defined before the colon).
The [Service]
and [Install]
sections of the unit file are familiar from service unit files. The [Install]
section in particular is important: The WantedBy=default.target
option ensures the container starts on boot.
Starting the Service
After saving the container file in Listing 1 and creating the directories for the container's volumes, you need to inform systemd of the new unit file for the user:
$ systemctl --user daemon-reload
This command generates a service for the container in the background, with the same name as your .container
unit file but with the .service
extension. You can view its content with:
$ systemctl --user cat freshrss.service
You'll see, for instance, that the service unit file contains an extensive [Service]
section with the ExecStart
option consisting of a podman run
command that starts the container with various options like volumes, environment variables, and so on.
You can now also start the container by starting this generated service:
$ systemctl --user start freshrss.service
The startup might take some time if the container image needs to be downloaded first.
If all goes well, the FreshRSS web interface is available on port 80 of your container host. If not, consult the logfiles with journalctl
or take a look at the output of:
systemctl --user status freshrss.service
Always remember to use the --user
flag in your systemctl
commands; because you're working with rootless containers, the corresponding systemd services are running with user privileges.
Creating a Podman Network
You can similarly define unit files for volumes, networks, pods, and more. As an example, I'll define a Podman network in a systemd unit file. Instead of letting all your containers publish their ports directly on the host, connect them all to a Podman network and then run a container with a reverse proxy to access all those containers externally.
Define a .config/containers/systemd/reverse-proxy.network
file in your home directory with the content:
[Unit] Description=Reverse proxy network [Network] NetworkName=reverse-proxy
Additional options are documented in the aforementioned Podman Quadlet man page. Now change the unit file of your FreshRSS container to include the following line in the [Container]
section to use this network:
Network=reverse-proxy.network
Remove the PublishPort
line because the container's port shouldn't be exposed on the host anymore: That will be the reverse proxy's task.
« Previous 1 2 3 4 Next »
Buy this article as PDF
(incl. VAT)