How To Use Traefik as a Reverse Proxy for Podman (rootless)
Introduction⌗
Traefik is a leading modern reverse proxy and load balancer that makes deploying microservices easy. Traefik integrates with your existing infrastructure components and configures itself automatically and dynamically. [1]
Podman is a daemonless, open source, Linux native tool designed to make it easy to find, run, build, share and deploy applications using Open Containers Initiative (OCI) Containers and Container Images. Podman provides a command line interface (CLI) familiar to anyone who has used the Docker Container Engine. Containers under the control of Podman can either be run by root or by a non-privileged user. [2]
In this tutorial I’m using Fedora 35 for host OS with enabled SELinux and Firewalld. This means that we will need to execute few commands with root to allow rootless container (traefik) to listen on privileged ports (80, 443). We also will enable LetsEncrypt and HTTPS redirect in Treafik.
Install podman⌗
You can install it using the following command:
root# dnf install -y podman
After installation, run the hello world image to ensure everything is working:
root# podman run hello-world
Create a regualr user for containers⌗
Create a regular user or use existing one. In this tutorial I will use user “container” with UID 1000.
root# useradd containers
root# passwd containers
Note: We need to login via SSH or Console with the new user. You cannot use “su - user” as this does not create a proper user session and custom exports for DBUS are required. In this tutorial I will use ssh containers@localhost.
Allow privileges ports binding for non-root users⌗
root# echo 'net.ipv4.ip_unprivileged_port_start=80' >> /etc/sysctl.conf
root# sysctl -p
Allow port 80 and 443 in Firewalld⌗
root# firewall-cmd --add-service={http,https} --permanent
root# firewall-cmd --reload
Enable lingering for user container⌗
root# loginctl enable-linger containers
This allows users who are not logged in to run long-running services, otherwise containers will stop once you logout.
Enable Podman.socket⌗
containers$ systemctl --user enable --now podman.socket
This will create a podman socket in /run/user/1000/podman/podman.sock, where 1000 is your UID.
Create a Traefik container⌗
Create podman netwok web⌗
containers$ podman network create web
Create an empty acme.json file with privileges 600⌗
containers$ touch acme.json
containers$ chmod 0600 acme.json
Run Traefik⌗
Make sure that email is properly set, otherwise you will get an error.
We need to run this container with an SELinux context that allows it to talk the podman socket, otherwise SELinux will block traefik communitaction with the podman.socket.
If you don’t add security opt label, you will get a similar error in SELinux
type=AVC msg=audit(1643875799.990:1912): avc: denied { connectto } for pid=26594 comm="traefik" path="/run/user/1000/podman/podman.sock" scontext=system_u:system_r:container_t:s0:c41,c864 tcontext=unconfined_u:system_r:container_runtime_t:s0-s0:c0.c1023 tclass=unix_stream_socket permissive=0
Create Traefik container⌗
containers$ podman run --name=traefik -d \
--security-opt label=type:container_runtime_t \
-v /run/user/1000/podman/podman.sock:/var/run/docker.sock:z \
-v ./acme.json:/acme.json:z \
--net web \
-p 80:80 \
-p 443:443 \
--restart always \
docker.io/library/traefik:latest \
--entrypoints.web.address=":80" \
--entrypoints.web.http.redirections.entryPoint.to=websecure \
--entrypoints.web.http.redirections.entryPoint.scheme=https \
--entrypoints.websecure.address=":443" \
--providers.docker=true \
--certificatesresolvers.le.acme.email=your@email.local \
--certificatesresolvers.le.acme.storage=/acme.json \
--certificatesresolvers.le.acme.tlschallenge=true
Create a systemd unit for the traefik container⌗
containers$ mkdir -p ~/.config/systemd/user/
containers$ cd ~/.config/systemd/user/
containers$ podman generate systemd -f -n traefik
containers$ systemctl --user enable container-traefik.service
Now, lets stop podman container and start it via systemd
containers$ podman stop traefik
containers$ systemctl --user start container-traefik.service
You can verify that the traefik is running with the one of the following commands:
containers$ podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
759a25c8c203 docker.io/library/traefik:latest --entrypoints.web... 2 minutes ago Up 2 minutes ago 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp traefik
or
containers$ systemctl --user status container-traefik.service
● container-traefik.service - Podman container-traefik.service
Loaded: loaded (/home/containers/.config/systemd/user/container-traefik.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2022-02-03 07:39:02 UTC; 2min 48s ago
Docs: man:podman-generate-systemd(1)
Process: 21755 ExecStart=/usr/bin/podman start traefik (code=exited, status=0/SUCCESS)
Main PID: 21920 (conmon)
Tasks: 16 (limit: 1112)
Memory: 30.4M
CPU: 510ms
... cut
Examples⌗
After configuring the traefik reverse proxy, we will create a few examples. Examples will not follow the best practices, they will be run only for test purpose, so no persistent volumes will be used.
In order for Traefik to route our traffic correctly, we will need a few things:
- Container should be in network “web”
- Labels should be set
- Port should be exposed
- Traefik should known on which port to route traffic
Ghost CMS⌗
Our Ghost platform will run with the following host: ghost.podman.gerov.eu, so you should replace hostname in the example below:
containers$ podman run -d --name ghost \
--network=web \
-l traefik.http.routers.ghost.rule=Host\(\`ghost.podman.gerov.eu\`\) \
-l traefik.http.services.ghost.loadbalancer.server.port=2368 \
-l traefik.http.routers.ghost.tls.certresolver=le \
-l traefik.http.routers.ghost.tls=true \
-e url=https://ghost.podman.gerov.eu \
--expose=2368 \
docker.io/library/ghost:latest
We will wait a minute and test if Ghost is running over HTTPS with valid Let’s Encrypt certificate.
containers$ curl -I https://ghost.podman.gerov.eu/
HTTP/2 200
cache-control: public, max-age=0
content-type: text/html; charset=utf-8
date: Thu, 03 Feb 2022 07:58:54 GMT
etag: W/"5eac-sKMD98knbLhfiGj86JrLrs+J4Ow"
vary: Accept-Encoding
x-powered-by: Express
content-length: 24236
PHP 7.4 & Apache⌗
containers$ podman run -d --name php74-apache \
--network=web \
-l traefik.http.routers.php74.rule=Host\(\`php.podman.gerov.eu\`\) \
-l traefik.http.services.php74.loadbalancer.server.port=80 \
-l traefik.http.routers.php74.tls.certresolver=le \
-l traefik.http.routers.php74.tls=true \
--expose=80 \
php:7.4-apache
References:⌗
[1] https://traefik.io/traefik/
[2] https://docs.podman.io/en/latest/
[3] Photo: Robin Pierre