Traefik 2/ LetsEncrypt / IOS issue

My setup has some docker containers behind Traefik 2, certificates are generated using LetsEncrypt. My router has a port forward to the docker machine.

This setup is working perfectly fine when accessing the docker container using a Windows machine. When trying the same with an Iphone or Ipad I receive an SSL error.

Investigations:

  • the IP address is resolved correctly on IOS
  • the certificate which causes the SSL issue seems to be the self signed certificate coming from the router, not the one from Traefik

Any idea what I can do to solve this?

Kind regards
Dirk

Is your Windows machine connecting from home or from outside your home? Is iPhone not working with Wi-Fi (at home) and mobile (external)?

I just tried - interesting results:

  1. Windows machine is connected from home (LAN cable), certificate is working (using the domain name, not the internal IP of the docker machine)
  2. Iphone using WLAN (same VLAN as Windows computer) does NOT work
  3. Iphone using mobile IS working

I would have understood, if both Windows and Iphone/WLAN would not work, but not this result...

Kind regards

Dirk

Maybe post your configs?

Which of them? There are quite a lot... Docker?

How should we know your config and find a potential error, if you don’t post it?

Traefik static and dynamic config, docker-compose.yml if used.

Just wanted to avoid flooding the forum with unnecessary configs. Here is what I am using:

myhostname: in reality there is my FQDN entered

XXX: internal IP part

If there is anything missing, please notify me, I will publish the files.

Vault is one of the services running when using LAN or an external connection like mobile and NOT running, when connecting via WLAN. I am using Unifi SDN, LAN and WLAN are utilizing the same VLAN settings.

Kind regards

Dirk

app-webserver.toml

[http.routers]
  [http.routers.webserver-rtr]
      entryPoints = ["websecure"]
      rule = "Host(`myhostname`)"
      service = "webserver-svc"
      middlewares = ["chain-authelia@file"]
      [http.routers.webserver-rtr.tls]
        certresolver = "myresolver"

[http.services]
  [http.services.webserver-svc]
    [http.services.webserver-svc.loadBalancer]
      passHostHeader = true
      [[http.services.webserver-svc.loadBalancer.servers]]
        url = "http://192.168.1.XXX:80"

middleware-chains.toml

[http.middlewares]
  [http.middlewares.chain-no-auth]
    [http.middlewares.chain-no-auth.chain]
      middlewares = [ "middlewares-rate-limit", "middlewares-secure-headers", "middlewares-redirect-scheme"]

  [http.middlewares.chain-basic-auth]
    [http.middlewares.chain-basic-auth.chain]
      middlewares = [ "middlewares-rate-limit", "middlewares-secure-headers", "middlewares-basic-auth", "middlewares-redirect-scheme"]

  [http.middlewares.chain-authelia]
    [http.middlewares.chain-authelia.chain]
      middlewares = ["middlewares-rate-limit", "middlewares-secure-headers", "middlewares-authelia", "middlewares-redirect-scheme"]

middlewares.toml

[http.middlewares]
  [http.middlewares.middlewares-basic-auth]
    [http.middlewares.middlewares-basic-auth.basicAuth]
      realm = "Traefik2 Basic Auth"
      usersFile = "/shared/.htpasswd" #be sure to mount the volume through docker-compose.yml

  [http.middlewares.middlewares-authelia]
    [http.middlewares.middlewares-authelia.forwardAuth]
      address = "http://authelia:9091/api/verify?rd=https://authelia.myhostname"
      trustForwardHeader = true
      authResponseHeaders = ["Remote-User", "Remote-Groups"]

  [http.middlewares.middlewares-rate-limit]
    [http.middlewares.middlewares-rate-limit.rateLimit]
      average = 100
      burst = 50

  [http.middlewares.middlewares-redirect-scheme]
    [http.middlewares.middlewares-redirect-scheme.redirectScheme]
      scheme = "https"
      permanent = true

  [http.middlewares.middlewares-secure-headers]
    [http.middlewares.middlewares-secure-headers.headers]
      accessControlAllowMethods= ["GET", "OPTIONS", "PUT"]
      accessControlMaxAge = 100
      hostsProxyHeaders = ["X-Forwarded-Host"]
#       sslRedirect = true
      stsSeconds = 63072000
      stsIncludeSubdomains = true
      stsPreload = true
      forceSTSHeader = true
#      frameDeny = true #overwritten by customFrameOptionsValue
      customFrameOptionsValue = "allow-from https:drallard.eu" #CSP takes care of this but may be needed for organizr.
      contentTypeNosniff = true
      browserXssFilter = true
#      sslForceHost = true # add sslHost to all of the services
#      sslHost = "example.com"
      referrerPolicy = "same-origin"
#      Setting contentSecurityPolicy is more secure but it can break things. Proper auth will reduce the risk.
#      the below line also breaks some apps due to 'none' - sonarr, radarr, etc.
#      contentSecurityPolicy = "frame-ancestors '*.example.com:*';object-src 'none';script-src 'none';"
      permissionsPolicy = "camera 'none'; geolocation 'none'; microphone 'none'; payment 'none'; usb 'none'; vr 'none';"
      [http.middlewares.middlewares-secure-headers.headers.customResponseHeaders]
        X-Robots-Tag = "none,noarchive,nosnippet,notranslate,noimageindex,"
        server = ""

docker-compose.yml

version: "3.7"

########################### NETWORKS
networks:
  t2_proxy:
    external:
      name: t2_proxy
  default:
    driver: bridge

########################### SECRETS
secrets:
  authelia_jwt_secret:
    file: /home/dirk/docker/secrets/authelia_jwt_secret
  authelia_session_secret:
    file: /home/dirk/docker/secrets/authelia_session_secret
  authelia_notifier_smtp_password:
    file: /home/dirk/docker/secrets/authelia_notifier_smtp_password
  POSTGRES_PASSWORD:
    file: /home/dirk/docker/secrets/POSTGRES_PASSWORD
########################### SERVICES
services:
  # All services / apps go below this line

  # WHOAMI Service
  whoami:
    image: "traefik/whoami"
    container_name: "simple-service"
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.whoami.rule=Host(`recipe.MYHOSTNAME`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      - "traefik.http.routers.whoami.tls.certresolver=myresolver"
    networks:
      - t2_proxy
  # WHOAMI Service Ende

  # TRAEFIK Service
  traefik:
    image: "traefik:latest"
    container_name: "traefik"
    restart: "unless-stopped"

    command:
      - "--global.checkNewVersion=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      - "--entrypoints.traefik.address=:8080"
      - "--api=true"
      - "--log=true"
      - "--log.level=WARN"
      - "--accessLog=true"
      - "--accessLog.filePath=/traefik.log"
      - "--accessLog.bufferingSize=100"
      - "--accessLog.filters.statusCodes=400-499"
      - "--providers.docker=true"
      - "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - --providers.docker.defaultrule=Host(`{{ index .Labels "com.docker.compose.service" }}.$DOMAINNAME`)
      - "--providers.docker.exposedByDefault=false"
      - "--providers.docker.network=t2_proxy"
      - "--providers.docker.swarmMode=false"
      - "--providers.file.directory=/rules"
      - "--providers.file.watch=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge=true"
      - "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
#       - "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - "--certificatesresolvers.myresolver.acme.email=MYADDRESS"
      - "--certificatesresolvers.myresolver.acme.storage=/acme.json"

    networks:
      - t2_proxy

    security_opt:
      - no-new-privileges:true

    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host
      - target: 443
        published: 443
        protocol: tcp
        mode: host
      - target: 8080
        published: 8080
        protocol: tcp
        mode: host

    volumes:
      - "/home/dirk/docker/traefik2/rules:/rules"
      - "/home/dirk/docker/traefik2/acme/acme.json:/acme.json"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "/home/dirk/docker/traefik2/traefik.log:/traefik.log"
      - "/home/dirk/docker/shared:/shared"

    labels:
      - "traefik.enable=true"
      # HTTP-to-HTTPS Redirect
      - "traefik.http.routers.http-catchall.entrypoints=web"
      - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)"
      - "traefik.http.routers.http-catchall.middlewares=redirect-to-https"
      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      # HTTP Routers
      - "traefik.http.routers.traefik-rtr.entrypoints=websecure"
      - "traefik.http.routers.traefik-rtr.rule=Host(`traefik.MYHOSTNAME`)"
      - "traefik.http.routers.traefik-rtr.tls=true"
      - "traefik.http.routers.traefik-rtr.tls.certresolver=myresolver"
#      - "traefik.http.routers.traefik-rtr.tls.domains[0].main=$DOMAINNAME"
#      - "traefik.http.routers.traefik-rtr.tls.domains[0].sans=*.$DOMAINNAME"

      ## Services - API
      - "traefik.http.routers.traefik-rtr.service=api@internal"

      ## Middlewares
#      - "traefik.http.routers.traefik-rtr.middlewares=chain-basic-auth@file"
      - "traefik.http.routers.traefik-rtr.middlewares=chain-authelia@file"
  # TRAEFIK service Ende
  # Authelia (Lite) - Self-Hosted Single Sign-On and Two-Factor Authentication
  authelia:
    container_name: authelia
    image: authelia/authelia:latest
    # image: authelia/authelia:4.21.0
    restart: always
    networks:
      - t2_proxy
  #  depends_on:
  #    - mariadb
  #    - redis
    volumes:
      - $DOCKERDIR/authelia:/config
    environment:
      - TZ=$TZ
      - AUTHELIA_JWT_SECRET_FILE=/run/secrets/authelia_jwt_secret
      - AUTHELIA_SESSION_SECRET_FILE=/run/secrets/authelia_session_secret
  #     - AUTHELIA_STORAGE_MYSQL_PASSWORD_FILE=/run/secrets/authelia_storage_mysql_password
      - AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE=/run/secrets/authelia_notifier_smtp_password
  #     - AUTHELIA_DUO_API_SECRET_KEY_FILE=/run/secrets/authelia_duo_api_secret_key
    secrets:
      - authelia_jwt_secret
      - authelia_session_secret
  #    - authelia_storage_mysql_password
      - authelia_notifier_smtp_password
  #    - authelia_duo_api_secret_key
    labels:
      - "traefik.enable=true"
      ## HTTP Routers
      - "traefik.http.routers.authelia-rtr.entrypoints=websecure"
      - "traefik.http.routers.authelia-rtr.rule=HostHeader(`authelia.MYHOSTNAME`)"
      - "traefik.http.routers.authelia-rtr.tls=true"
      - "traefik.http.routers.authelia-rtr.tls.certresolver=myresolver"
      ## Middlewares
      - "traefik.http.routers.authelia-rtr.middlewares=chain-authelia@file"
      ## HTTP Services
      - "traefik.http.routers.authelia-rtr.service=authelia-svc"
      - "traefik.http.services.authelia-svc.loadbalancer.server.port=9091"

  # PORTAINER Service
  portainer:
    container_name: portainer
    image: portainer/portainer-ce:latest
    restart: unless-stopped
    command: -H unix:///var/run/docker.sock
    networks:
      - t2_proxy
    security_opt:
      - no-new-privileges:true
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - /home/dirk/docker/portainer/data:/data
    environment:
      - TZ=$TZ
    ports:
      - 9000:9000
 #PORTAINER Service Ende

  # VAULTWARDEN Service
  vaultwarden:
    image: vaultwarden/server:latest
    restart: unless-stopped
    container_name: vaultwarden2
    networks:
      - t2_proxy
    ports:
      - 5500:80
    volumes:
      - /home/dirk/docker/vaultwarden:/data
    labels:
      - traefik.enable=true
      - traefik.http.routers.vaultwarden-ui-https.rule=Host(`vault.MYHOSTNAME`)
      - traefik.http.routers.vaultwarden-ui-https.entrypoints=websecure
      - traefik.http.routers.vaultwarden-ui-https.tls=true
      - traefik.http.routers.vaultwarden-ui-https.service=vaultwarden-ui
      - traefik.http.services.vaultwarden-ui.loadbalancer.server.port=80
      - traefik.http.routers.vaultwarden-websocket-https.rule=Host(`vault.MYHOSTNAME`) && Path(`/notifications/hub`)
      - traefik.http.routers.vaultwarden-websocket-https.entrypoints=websecure
      - traefik.http.routers.vaultwarden-websocket-https.tls=true
      - traefik.http.routers.vaultwarden-websocket-https.service=vaultwarden-websocket
      - traefik.http.services.vaultwarden-websocket.loadbalancer.server.port=3012
      - "traefik.http.routers.vaultwarden-ui-https.tls.certresolver=myresolver"
      - "traefik.http.routers.vaultwarden-websocket-https.tls.certresolver=myresolver"
      ## Middlewares
      - "traefik.http.routers.vaultwarden-ui-https.middlewares=chain-no-auth@file"
      - "traefik.http.routers.vaultwarden-websocket-https.middlewares=chain-no-auth@file"
  #VAULTWARDEN Service Ende

networks:
  t2_proxy:
    external: true

No idea? I hoped you would find an obvious error in my configuration...

I see Docker secrets, are you running in Docker Swarm? On multiple nodes?

No swarm, no multiple nodes. The secrets are just in not to have passwords in the config file.

Strange, docker documentation for secret [1, 2] states:

This command works with the Swarm orchestrator

Docker secrets are only available to swarm services, not to standalone containers.

Well, fact is, it works. I did not invent this, got it from a tutorial. Perhaps it is a swarm of 1 :wink:

Nevertheless this does not explain the unusual certificate issues - or do you think so?

Enable Traefik debug log and access log (optionally in json format, less readable but more infos) and check what's happening when you access with the different devices.

Looking at this I can conclude, that this is not a traefik issue. Trying to access a site managed with docker/traefik I do not even create a log file entry when using WLAN. It seems to be an issue with port forwarding. Thanks anyhow for your help.

Dirk