Refer to this guide (Anand at SmartHomeBeginner).
NOTE: Although there is specific data for the Docker compose file below, it is best to look at the actual Docker compose files on the system as amendments may have been made there and not added here. It also has a greater level of commenting
Pre-Requisites
- Host system: Ubuntu Server on Proxmox
- Docker and Docker Plugin installed
- Domain Name acquired
- Proper DNS Records (A-type Record pointing to WAN IP, CNAME-type record wildcard * pointing to root domain)
- Cloudflare SSL settings at Full SSL
- Port 80 and 443 forwarded to Traefik on Router (server IP)
- Folders/Environment as per initial Docker Setup
Getting Started With Traefik 2
- Keep It Simple: Sometimes it can be difficult to troubleshoot a problem when a lot of things are changed at once. Start with a basic example and access the Traefik dashboard first, then continue to add services from there
- Traefik Dashboard/API Auth Required: The Traefik dashboard must be protected by authentication, otherwise you will need to use the insecure flag. By following this guide we will have a secure configuration and will not need to use this flag.
- Go Formatting: Traefik is written in Go, and therefore we need to use Go formatting depending on the input type (string, boolean, array). This means, for example, that your hostname must be defined with backticks, such as
traefik.example.com
(apostrophes will not work!)
Preparatory Work
- Create Basic HTTP Authentication Credentials
- Go to this website for the MD5 hashed password generator
- Enter Username: [STRONGBOX]
- Enter Password: [STRONGBOX]
- Select Mode: Apache MD5
- Click Create .htpasswd file button, copy the username:password string
- This will be used below, note the need to ‘escape’ $ signs by putting $$
- Go to this website for the MD5 hashed password generator
- Create Traefik 2 Environmental Variables
- Open the central environmental variables file created in initial setup
1
sudo nano ~/docker/.env
- Add the following parameters for Traefik:
1 2 3 4 5 6
LOCAL_IPS=127.0.0.1/32,10.0.0.0/8,192.168.0.0/16,172.16.0.0/12 DOMAINNAME_CLOUD_SERVER=[STRONGBOX] CLOUDFLARE_EMAIL=[STRONGBOX] CLOUDFLARE_API_KEY=>[STRONGBOX] CLOUDFLARE_IPS=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22
- The Cloudflare API key is obtained from the Profile page (person icon upper right)
- Click dropdown, My Profile
- Click API Tokens in left menu
- Click View button against the Global API Key entry
- Popup will require Cloudflare password and then show the API key
- The list of IPs are those that Traefik can trust, and are pretty standard. Double check that all system IPs are covered in LOCAL_IPS, and add as necessary
- Open the central environmental variables file created in initial setup
- Prepare Traefik 2 Folders and Files
- The following commands will create new folders and files under the ~/docker/appdata folder and set appropriate permissions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
cd ~/docker mkdir traefik mkdir traefik/acme mkdir traefik/rules touch traefik/acme/acme.json chmod 644 traefik/acme/acme.json mkdir logs/traefik touch logs/traefik/traefik.log touch logs/traefik/access.log # Add reverse proxy network: sudo docker network create traefik_proxy
-
The acme.json file is an empty file for Traefik to use to store the Let’s Encrypt certificates generated. The traefik.log and access.log files are empty log files
-
The traefik_proxy network is declared as external in Docker compose files to come, so needs to be defined in advance
Docker Compose YAML
- Open new file called dc-traefik.yml in docker root folder (default Docker compose file name is docker-compose.yml, but using separate DC file for each service)
1
sudo nano ~/docker/dc-traefik.yml
- Add the following YAML code, note spacing:
- Define Docker Version
1
version: "3.9"
- Define Networks : define as external so can be referenced by multiple containers
1 2 3
networks: traefik_proxy: external: true
- Add Service Container: each service is defined under the heading services:
- Define Docker Version
- Add the following YAML code, note spacing:
Setup Service: TRAEFIK 2
- Add Traefik Service Basics. Defining a specific version prevents the latest version breaking your installation if unexpected changes are made. Can test updated versions periodically in a controlled manner
1 2 3 4 5 6 7
services: traefik: container_name: traefik image: traefik:2.10 restart: unless-stopped security_opt: - no-new-privileges:true
-
Add CLI Arguments
-
log.level set to DEBUG initially, change to WARNING when all working ok
-
tls.options refer next para below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
command: # CLI arguments (STATIC Configuration) # # GLOBAL - --global.checkNewVersion=true - --global.sendAnonymousUsage=false # # SERVER TRANSPORT - --serversTransport.insecureSkipVerify=true # # ENTRYPOINTS - --entryPoints.web_http.address=:80 # HTTP - --entryPoints.web_http.http.redirections.entryPoint.to=web_https - --entryPoints.web_http.http.redirections.entryPoint.scheme=https # Default - --entryPoints.web_https.address=:443 # HTTPS # Edited out for Authelia - --entrypoints.web_https.forwardedHeaders.trustedIPs=$CLOUDFLARE_IPS,$LOCAL_IPS # Allow these IPs to set the X-Forwarded-* headers - Cloudflare IPs: https://www.cloudflare.com/ips/ #- --entryPoints.web_https.forwardedHeaders.insecure=false #- --entryPoints.web_https.proxyProtocol.insecure=false - --entrypoints.web_https.http.tls.options=tls-opts@file # # PROVIDERS - --providers.docker=true - --providers.docker.endpoint=unix:///var/run/docker.sock - --providers.docker.exposedByDefault=false - --providers.file.directory=/rules - --providers.file.watch=true # Watch for dynamic configuration changes in /rules folder # # API - --api=true - --api.dashboard=true #- --api.debug=true # # LOG - --log=true - --log.level=WARNING # DEBUG, INFO, WARNING, default->ERROR, CRITICAL - --log.filePath=/logs/traefik.log # # ACCESS LOG - --accessLog=true - --accessLog.filePath=/logs/access.log - --accessLog.bufferingSize=100 - --accessLog.filters.statusCodes=204-299,400-499,500-599 # # CERTIFICATE RESOLVERS #- --certificatesResolvers.cloudflare.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory - --certificatesResolvers.cloudflare.acme.email=$CLOUDFLARE_EMAIL - --certificatesResolvers.cloudflare.acme.storage=/acme.json - --certificatesResolvers.cloudflare.acme.dnsChallenge.provider=cloudflare - --certificatesResolvers.cloudflare.acme.dnsChallenge.resolvers=1.1.1.1:53,1.0.0.1:53
- TLS options section needs a tls-opts.yml file created in appdata/traefik/rules. Enter the options as specified below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
tls: options: tls-opts: minVersion: VersionTLS12 cipherSuites: - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 - TLS_AES_128_GCM_SHA256 - TLS_AES_256_GCM_SHA384 - TLS_CHACHA20_POLY1305_SHA256 - TLS_FALLBACK_SCSV # Client is doing version fallback. See RFC 7507 curvePreferences: - CurveP521 - CurveP384 sniStrict: true
- Setup Network for Traefik Dashboard. This references the external traefik_proxy network setup above
1 2
networks: - traefik_proxy
- Traefik Ports. Traefik needs three ports: 80, 443 and 8080. The last one is optional as the Traefik dashboard will be put behind its subdomain later instead of accessing it through port :8080.
1 2 3
ports: - 80:80 - 443:443
- Traefik Volumes. This section maps folders on the host to paths in the docker container. The basic HTTP authentication credentials are in /shared
1 2 3 4 5
volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - $DOCKERDIR/traefik/rules:/rules # Dynamic config - $DOCKERDIR/traefik/acme/acme.json:/acme.json # Certificates file - $DOCKERDIR/logs/traefik:/logs
- Traefik Environment Variables. DOMAINNAME_CLOUD_SERVER will be used to simplify adding other apps behind Traefik reverse proxy, offering the domain name as a variable
1 2 3 4
environment: - TZ=$TZ - CF_API_EMAIL=$CLOUDFLARE_EMAIL - CF_API_KEY=$CLOUDFLARE_API_KEY
- Traefik Docker Labels.
- The first line enables or disables Traefik for services. When the container starts a route will automatically be created
- Add routers for entry points, certificate resolving and domain information. In this case Traefik will only listen on the secure HTTPS entrypoint. Note rules have to follow GO formatting, hence the backticks, not apostrophes!
- Next define where to find services to be proxied, i.e. internally
- The last section uses the HTTP authentication credentials created above
1 2 3 4 5 6 7 8 9 10 11 12 13
labels: # DYNAMIC Configuration - "traefik.enable=true" # HTTPS - "traefik.http.routers.traefik-secure.entrypoints=web_https" - "traefik.http.routers.traefik-secure.rule=Host(`traefik.$DOMAINNAME_CLOUD_SERVER`)" - "traefik.http.routers.traefik-secure.tls=true" - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare" - "traefik.http.routers.traefik-secure.tls.domains[0].main=$DOMAINNAME_CLOUD_SERVER" - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.$DOMAINNAME_CLOUD_SERVER" - "traefik.http.routers.traefik-secure.service=api@internal" # MIDDLEWARES; rate limit, compress, basic authentication #- "traefik.http.routers.traefik-secure.middlewares=middlewares-rate-limit@file,middlewares-basic-auth@file,middlewares-compress@file" - "traefik.http.routers.traefik-secure.middlewares=authelia@docker"
-
-
Testing Docker Traefik Setup
-
Save the compose file and run the first command from the docker root folder:
1
sudo docker compose -f >dc-traefik.yml up -d
- Some messages in the log show that everything went well:
- Waiting for DNS record propagation
- The server validated our request
- Validations succeeded, requesting certificates
- Server responded with a certificate
- Some messages in the log show that everything went well:
- Test the Traefik dashboard by going to traefik.bbproj.org. Ensure port forward has been setup in router to forward ports 80 and 443 to Traefik (server 192.168.0.22)
- RESULTS: contrary to the guide, the padlock icon in the URL was locked showing the site was secure already. As recommended commented out two entries anyhow:
- Removed ACME staging URL to get Let’s Encrypt real server:
1
# – –certificatesResolvers.dns-cloudflare.acme.caServer=https://**acme-staging-v02**.api.letsencrypt.org/directory
- Force use of wildcard certificates (*.bbproj.org) instead of creating a separate certificate for each sub-domain:
1
# – “traefik.http.routers.traefik-rtr.tls.certresolver=cloudflare”
- Re-test to see if Traefik dashboard worked ok… SUCCESS!
Securing Traefik Dashboard
- Rate Limit. The rate limit middleware ensures that services will receive a fair number of requests. This is helpful if intentionally (eg. security breach) or unintentionally if services are being bombarded with requests causing a denial of service (DDoS) situation
- Add the following to a */traefik/rules/middlewares.yml file
1 2 3 4
middlewares-rate-limit: rateLimit: average: 100 burst: 50
- Modify the labels: area of the compose file with line below. This puts rate-limiting as the first line of defence
1
- "traefik.http.routers.traefik-secure.middlewares=middlewares-rate-limit@file,traefik-auth"
- Compression. Compress the output to reduce bandwidth and increase speed.
- Add the following to the */rules/middlewares.yml file
1 2
middlewares-compress: compress: {}
- Modify the labels: area of the compose file with line below
1
- "traefik.http.routers.traefik-secure.middlewares=middlewares-rate-limit@file,traefik-auth,middlewares-compress@file"
- Having got the Reverse Proxy working, can then go on to installing other apps