services: # 1) Desktop site puzzle-desk: build: context: /opt/apps/puzzle dockerfile: Dockerfile.desktop container_name: puzzle-desk restart: unless-stopped networks: [ traefik_net ] volumes: - /opt/apps/puzzle/desk:/usr/share/nginx/html:ro labels: - "traefik.enable=true" - "traefik.http.routers.puzzle-desk.rule=Host(`desk-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-desk.entrypoints=websecure" - "traefik.http.routers.puzzle-desk.tls=true" - "traefik.http.routers.puzzle-desk.tls.certresolver=letsencrypt" - "traefik.http.services.puzzle-desk.loadbalancer.server.port=80" - "traefik.http.routers.puzzle-desk-http.rule=Host(`desk-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-desk-http.entrypoints=web" - "traefik.http.routers.puzzle-desk-http.middlewares=redirect-to-https@file" # 2) Tablet site puzzle-tab: build: context: /opt/apps/puzzle dockerfile: Dockerfile.tablet container_name: puzzle-tab restart: unless-stopped networks: [ traefik_net ] volumes: - /opt/apps/puzzle/tab:/usr/share/nginx/html:ro labels: - "traefik.enable=true" - "traefik.http.routers.puzzle-tab.rule=Host(`tab-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-tab.entrypoints=websecure" - "traefik.http.routers.puzzle-tab.tls=true" - "traefik.http.routers.puzzle-tab.tls.certresolver=letsencrypt" - "traefik.http.services.puzzle-tab.loadbalancer.server.port=80" - "traefik.http.routers.puzzle-tab-http.rule=Host(`tab-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-tab-http.entrypoints=web" - "traefik.http.routers.puzzle-tab-http.middlewares=redirect-to-https@file" # 3) Mobile site puzzle-mobile: build: context: /opt/apps/puzzle dockerfile: Dockerfile.mobile container_name: puzzle-mobile restart: unless-stopped networks: [ traefik_net ] volumes: - /opt/apps/puzzle/mobile:/usr/share/nginx/html:ro labels: - "traefik.enable=true" - "traefik.http.routers.puzzle-mobile.rule=Host(`mobile-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-mobile.entrypoints=websecure" - "traefik.http.routers.puzzle-mobile.tls=true" - "traefik.http.routers.puzzle-mobile.tls.certresolver=letsencrypt" - "traefik.http.services.puzzle-mobile.loadbalancer.server.port=80" - "traefik.http.routers.puzzle-mobile-http.rule=Host(`mobile-puzzle.appmodel.nl`)" - "traefik.http.routers.puzzle-mobile-http.entrypoints=web" - "traefik.http.routers.puzzle-mobile-http.middlewares=redirect-to-https@file" # 4) Entry domain: puzzle.appmodel.nl -> redirect to the right subdomain by User-Agent # (this container never really serves content; it just hosts the redirect routers/middlewares) puzzle-entry: build: context: /opt/apps/puzzle dockerfile: Dockerfile container_name: puzzle-entry restart: unless-stopped networks: [ traefik_net ] labels: - "traefik.enable=true" # Redirect middlewares (302 while testing; switch to true for 301) - "traefik.http.middlewares.pz-redir-mobile.redirectregex.regex=^https?://puzzle\\.appmodel\\.nl/(.*)" - "traefik.http.middlewares.pz-redir-mobile.redirectregex.replacement=https://mobile-puzzle.appmodel.nl/$$1" - "traefik.http.middlewares.pz-redir-mobile.redirectregex.permanent=false" - "traefik.http.middlewares.pz-redir-tab.redirectregex.regex=^https?://puzzle\\.appmodel\\.nl/(.*)" - "traefik.http.middlewares.pz-redir-tab.redirectregex.replacement=https://tab-puzzle.appmodel.nl/$$1" - "traefik.http.middlewares.pz-redir-tab.redirectregex.permanent=false" - "traefik.http.middlewares.pz-redir-desk.redirectregex.regex=^https?://puzzle\\.appmodel\\.nl/(.*)" - "traefik.http.middlewares.pz-redir-desk.redirectregex.replacement=https://desk-puzzle.appmodel.nl/$$1" - "traefik.http.middlewares.pz-redir-desk.redirectregex.permanent=false" # HTTPS routers (priority matters) - "traefik.http.routers.pz-mobile.rule=Host(`puzzle.appmodel.nl`) && HeadersRegexp(`User-Agent`,`(?i)(mobi|iphone|ipod|windows phone|android.*mobile)`)" - "traefik.http.routers.pz-mobile.entrypoints=websecure" - "traefik.http.routers.pz-mobile.priority=100" - "traefik.http.routers.pz-mobile.middlewares=pz-redir-mobile" - "traefik.http.routers.pz-mobile.tls=true" - "traefik.http.routers.pz-mobile.tls.certresolver=letsencrypt" - "traefik.http.routers.pz-tab.rule=Host(`puzzle.appmodel.nl`) && HeadersRegexp(`User-Agent`,`(?i)(ipad|tablet|kindle|silk|android(?!.*mobile))`)" - "traefik.http.routers.pz-tab.entrypoints=websecure" - "traefik.http.routers.pz-tab.priority=90" - "traefik.http.routers.pz-tab.middlewares=pz-redir-tab" - "traefik.http.routers.pz-tab.tls=true" - "traefik.http.routers.pz-tab.tls.certresolver=letsencrypt" - "traefik.http.routers.pz-desk.rule=Host(`puzzle.appmodel.nl`)" - "traefik.http.routers.pz-desk.entrypoints=websecure" - "traefik.http.routers.pz-desk.priority=10" - "traefik.http.routers.pz-desk.middlewares=pz-redir-desk" - "traefik.http.routers.pz-desk.tls=true" - "traefik.http.routers.pz-desk.tls.certresolver=letsencrypt" # Optional: HTTP routers too (prevents extra hop via your http-catchall) - "traefik.http.routers.pz-mobile-http.rule=Host(`puzzle.appmodel.nl`) && HeadersRegexp(`User-Agent`,`(?i)(mobi|iphone|ipod|windows phone|android.*mobile)`)" - "traefik.http.routers.pz-mobile-http.entrypoints=web" - "traefik.http.routers.pz-mobile-http.priority=100" - "traefik.http.routers.pz-mobile-http.middlewares=pz-redir-mobile" - "traefik.http.routers.pz-tab-http.rule=Host(`puzzle.appmodel.nl`) && HeadersRegexp(`User-Agent`,`(?i)(ipad|tablet|kindle|silk|android(?!.*mobile))`)" - "traefik.http.routers.pz-tab-http.entrypoints=web" - "traefik.http.routers.pz-tab-http.priority=90" - "traefik.http.routers.pz-tab-http.middlewares=pz-redir-tab" - "traefik.http.routers.pz-desk-http.rule=Host(`puzzle.appmodel.nl`)" - "traefik.http.routers.pz-desk-http.entrypoints=web" - "traefik.http.routers.pz-desk-http.priority=10" - "traefik.http.routers.pz-desk-http.middlewares=pz-redir-desk" networks: traefik_net: external: true name: traefik_net