Traefik Reverse Proxy – Hosting HTTPS web services yourself

2021-04-26

There are many ways to access web services that run in our home from the Internet.
The worst possibility would be portforwarding and forwarding to a device with an unencrypted protocol such as HTTP or FTP. You should really avoid simple port forwarding on HTTP or FTP.
SFTP and / or a VPN would be better. Both require certificates to authorize clients and the datatransfer is encrypted.
With many routers and devices, however, the setup is complex and, for example, the in-house VPN of a AVM FritzBox, which uses IPSec, is not particularly modern or fast.
PiVPN is a really easy solution for the Pi / ei23 Smart Home Server, with which WireGuard or OpenVPN can be easily installed.

A VPN doesn’t solve all problems
What if an indefinite number of clients should access our system, or we don’t want to provide a certificate to every user manually?
Or what if we run a service that at times requires more resources than a small Raspberry Pi can provide?
This is where reverse proxies and SSL certificates come into play.
With a reverse proxy, for example, a domain or subdomain can be called and the reverse proxy then decides which content is made available to the user. In addition, the content can be encrypted via SSL.
For example, it is possible to use multiple domains even if you have only one external ip available. Traefik Architecture Traefik Architecture (Soruce: traefik.io) There are of course other solutions, such as via Nginx. However, since the ei23 Smart Home Server runs many programs as Docker containers, we use Traefik. Which has some advantages for programs in Docker and which has a good visual interface.

Proxy Configuration of Docker-Containers

To configure a Docker container for Traefik, it is only necessary to adapt of the /home/pi/ei23-dockerdocker-compose.yaml.
I show how this works in the video for version 1 of the Smart Home script

Docker-Compose Example for Bitwarden

  bitwarden:
    image: bitwardenrs/server:latest
    container_name: bitwarden
    restart: unless-stopped
    # ports:*
        # - 2223:80
    labels:
        - traefik.enable=true
        - traefik.http.routers.bitwarden.rule=Host(`example.com`)
        - traefik.http.routers.bitwarden.entrypoints=web-secured
        - traefik.http.routers.bitwarden.tls=true
        - traefik.http.routers.bitwarden.tls.certresolver=letsEncrypt
    volumes:
        - ./volumes/bitwarden:/data

With Traefik it is not necessary to give access to the *ports via Docker as long as Traefik is in the same Docker network as the container. Therefore these are commented out with # in the example above. Example: Websit in your LAN (in this case the ei23 Dashboard)

labels:
    - traefik.enable=true
    - traefik.http.routers.ei23-lan.rule=(Host(`192.168.178.10`) || Host(`smarthome`))
    - traefik.http.routers.ei23-lan.priority=1
    - traefik.http.routers.ei23-lan.entrypoints=lan

Docker-Compose Example for Grafana

labels:
    - traefik.enable=true
    - traefik.http.routers.grafana.rule=Host(`grafana.example.com`)
    - traefik.http.services.grafana.loadbalancer.server.port=3000
    - traefik.http.routers.grafana.entrypoints=web-secured
    - traefik.http.routers.grafana.tls=true
    - traefik.http.routers.grafana.tls.certresolver=letsEncrypt

Docker-Compose Example for Nextcloud

labels:
    - traefik.enable=true
    - traefik.http.routers.nextcloud.middlewares=nextcloud,nextcloud_redirect
    - traefik.http.routers.nextcloud.tls.certresolver=letsEncrypt
    - traefik.http.routers.nextcloud.rule=Host(`nextcloud.example.com`)
    - traefik.http.routers.nextcloud.entrypoints=web, web-secured
    - traefik.http.routers.nextcloud.tls=true
    - traefik.http.middlewares.nextcloud.headers.stsSeconds=15552000
    - traefik.http.middlewares.nextcloud.headers.stsPreload=true
    - traefik.http.middlewares.nextcloud_redirect.redirectregex.permanent=true
    - traefik.http.middlewares.nextcloud_redirect.redirectregex.regex=^https://(.*)/.well-known/(card|cal)dav
    - traefik.http.middlewares.nextcloud_redirect.redirectregex.replacement=https://$${1}/remote.php/dav/

As you can see, there are “routers, services, and middleware” for Traefik. Each service requires at least one traefik router of its own.

Proxy configuration of load balancers / external (IP) addresses and other devices in the network

For example, an external load balancer is created in /home/pi/ei23-docker/volumes/traefik/traefik/dynamic/config.yml (attention! The line indentation must be correct – the Yaml parser wants it that way)

http:
  routers:
    home-assistant:
      rule: Host(`homeassistant.example.com`)
      service: home-assistant
      tls:
        certresolver: letsEncrypt

  services:
    home-assistant:
      loadBalancer:
        servers:
          - url: http://172.17.0.1:8123 # 172.17.0.1 is the default Docker gateway

Instead of a Docker container, this refers to an http url. This is then also encrypted via SSL via the “certresolver”.

Initialising Traefik / creating SSL certificates

Traefik itself is operated as a Docker container and in the current version of the ei23 Smart Home Server, Traefik is already preconfigured, only small changes need to be made. Traefik’s Docker-Compose

traefik:
    image: traefik:v2.4
    container_name: traefik
    ports:
      - "80:80" # as internal http
      - "591:591" # as external http
      - "2280:8080" # config port
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./volumes/traefik/traefik/:/etc/traefik/
      - ./volumes/traefik/letsencrypt:/letsencrypt
    restart: unless-stopped

Under /home/pi/ei23-docker/volumes/traefik/traefik/ you find the traefik.yaml

[...]
entryPoints:
  lan:
    address: :80
  web:
    address: :591
    http:
      redirections:
        entrypoint:
          to: web-secured
          scheme: https
  web-secured:
    address: :443

certificatesResolvers:
  letsEncrypt:
    acme:
      email: mail@example.com
      storage: /letsencrypt/acme.json
      caserver: https://acme-staging-v02.api.letsencrypt.org/directory # this is for testing
      # caserver: https://acme-v02.api.letsencrypt.org/directory
      httpChallenge:
        entryPoint: web
[...]

Three entrypoints are defined here.

  • Port 80 (lan) is reserved for HTTP in the home network (LAN)
  • Port 591 (web) is reserved for external HTTP (WAN), the external port 80 must be forwarded to the internal port 591 of the Raspberry Pi. Since we only want to use encrypted connections, we use Traefik to force a redirection to the web-secured entrypoint (443).
  • Port 443 (web-secured) is finally the port for HTTPS. This must be accesable from the outside on the router and a forwarding to the Raspberry Pi on port 443

The encryption works with SSL.
After running Docker Compose (ei23 dc) and restarting Traefik, the labels are read in by Traefik and the certificates are created.
But! Before a certificate can be created at all, an email address must be entered. You will be informed about the expiry of a certificate or other warnings regarding security. The Let’s Encrypt service is so kind as to provide us with the otherwise very expensive certificates free of charge. However, there is a daily and weekly limit, as long as we only test whether everything works, we should use the “staging” caserver.
No official certificate is issued here. A good web browser shows a warning when the certificate is not valid.
Because it is just testing, you can accept this warning and all the desired services are still available, then you can switch from staging caserver to the official one.
Official certificates are then created and the web services are officially encrypted and accessible after a short time. If Traefik and the port forwarding have been configured correctly according to these instructions, then in the file /home/pi/ei23-docker/volumes/traefik/letsencrypt/acme.json something like this will appear for each domain after some time:

[...]
   "Certificates": [
      {
        "domain": {
          "main": "nextcloud.example.com"
        },
        "certificate":
[...]

This basic configuration should already offer more than enough functionality for your home server applications, if you still want to get into the matter further:
Traefik has a very good documentation:
doc.traefik.io/traefik


Comments are closed.