posts
How To Use Traefik as a Reverse Proxy for Podman (rootless)
February 3, 2022
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