Following Techno Tim’s tutorial. I found that some parts were confusing so I’m documenting how I did it. This is assuming Docker and Docker-Compose were already installed. There should also be an A record or CNAME record pointing to your Traefik server

sudo mkdir traefik
cd traefik
sudo mkdir data
cd data
sudo touch acme.json
sudo chmod 600 acme.json
sudo touch traefik.yml
sudo nano traefik.yml

In the traefik.yml file paste in the following. Replace the email with your Cloudflare email.

api:
  dashboard: true
  debug: true
entryPoints:
  http:
    address: ":80"
  https:
    address: ":443"
serversTransport:
  insecureSkipVerify: true
providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    filename: /config.yml
certificatesResolvers:
  cloudflare:
    acme:
      email: you@example.com
      storage: acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "1.0.0.1:53"

Save by pressing Ctrl+X, Y, then Enter.

cd ..
docker network create proxy
sudo touch docker-compose.yml

First, you’ll need to get a Basic Auth User and Password. Replace the highlighted with your desired Username and Password.

sudo apt-get update -y
sudo apt-get install -y apache2-utils
echo $(htpasswd -nB user password) | sed -e s/\\$/\\$\\$/g
sudo nano docker-compose.yml

Copy the output and replace USER:BASIC_AUTH_PASSWORD. Replace the other highlighted text:

version: '3'
services:
  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    security_opt:
      - no-new-privileges:true
    networks:
      - proxy
    ports:
      - 80:80
      - 443:443
    environment:
      - CF_API_EMAIL=user@example.com
      - CF_API_KEY=YOUR_API_KEY
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/username/traefik/data/traefik.yml:/traefik.yml:ro
      - /home/username/traefik/data/acme.json:/acme.json
      - /home/username/traefik/data/config.yml:/config.yml:ro
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.entrypoints=http"
      - "traefik.http.routers.traefik.rule=Host(`traefik-dashboard.local.example.com`)"
      - "traefik.http.middlewares.traefik-auth.basicauth.users=USER:BASIC_AUTH_PASSWORD"
      - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https"
      - "traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.routers.traefik.middlewares=traefik-https-redirect"
      - "traefik.http.routers.traefik-secure.entrypoints=https"
      - "traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.local.example.com`)"
      - "traefik.http.routers.traefik-secure.middlewares=traefik-auth"
      - "traefik.http.routers.traefik-secure.tls=true"
      - "traefik.http.routers.traefik-secure.tls.certresolver=cloudflare"
      - "traefik.http.routers.traefik-secure.tls.domains[0].main=local.example.com"
      - "traefik.http.routers.traefik-secure.tls.domains[0].sans=*.local.example.com"
      - "traefik.http.routers.traefik-secure.service=api@internal"

Save by pressing Ctrl+X, Y, then Enter.

docker-compose up -d
cd data
sudo nano config.yml

Replace the highlighted with the A record you set in PiHole and the IP of the server.

http:
 #region routers
  routers:
    proxmox:
      entryPoints:
        - "https"
      rule: "Host(`proxmox.local.example.com`)"
      middlewares:
        - default-headers
      tls: {}
      service: proxmox
    pihole:
      entryPoints:
        - "https"
      rule: "Host(`pihole.local.example.com`)"
      middlewares:
        - default-headers
        - addprefix-pihole
      tls: {}
      service: pihole
#endregion
#region services
  services:
    proxmox:
      loadBalancer:
        servers:
          - url: "https://192.168.0.100:8006"
        passHostHeader: true
    pihole:
      loadBalancer:
        servers:
          - url: "http://192.168.0.101:80"
        passHostHeader: true
#endregion
  middlewares:
    addprefix-pihole:
      addPrefix:
        prefix: "/admin"
    https-redirect:
      redirectScheme:
        scheme: https
    default-headers:
      headers:
        frameDeny: true
        sslRedirect: true
        browserXssFilter: true
        contentTypeNosniff: true
        forceSTSHeader: true
        stsIncludeSubdomains: true
        stsPreload: true
        stsSeconds: 15552000
        customFrameOptionsValue: SAMEORIGIN
        customRequestHeaders:
          X-Forwarded-Proto: https
    default-whitelist:
      ipWhiteList:
        sourceRange:
        - "10.0.0.0/8"
        - "192.168.0.0/16"
        - "172.16.0.0/12"
    secured:
      chain:
        middlewares:
        - default-whitelist
        - default-headers

Save by pressing Ctrl+X, Y, then Enter.

docker-compose up -d --force-recreate

You can test by going to the A record you specified.