HTTP to HTTPS redirect for single service not working

Hello! I want to enable https via let'sEncrypt and make a permanent http->https redirect for one of my services.

My static config:

version: '3'

services:
  reverse-proxy:
    image: traefik:v3.1
    command:
      # Traefik config
      - "--api.insecure=false"
      - "--providers.swarm.endpoint=unix:///var/run/docker.sock"
      - "--providers.swarm.exposedbydefault=false"
      - "--providers.swarm.network=proxynet"
      - "--log.level=DEBUG"
      - "--metrics.prometheus=true"
      # Traefik entrypoints
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
#      - "--entrypoints.mysql.address=:3306"
      # SSL Let'sEncrypt:
      - "--certificatesresolvers.le.acme.email=***"
      - "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
      - "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"

    ports:
      - "80:80"
      - "443:443"
#      - "3306:3306"
    networks:
      - proxynet
    deploy:
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.mydomain.com`)"
        - "traefik.http.routers.traefik-dashboard.entrypoints=web"
        - "traefik.http.routers.traefik-dashboard.service=api@internal"
        - "traefik.http.services.nginx.loadbalancer.server.port=80"
        - "traefik.http.routers.traefik-dashboard.middlewares=auth"
        - "traefik.http.middlewares.auth.basicauth.users=admin:***"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - letsencrypt_storage:/letsencrypt

networks:
  proxynet:
    external: true
volumes:
  letsencrypt_storage:
    external: false

Dynamic config of my service:

version: "3"
services:
  php:
    image: ***
    depends_on:
      - mysql
    volumes:
      - laravel_storage:/var/www/storage
#      - vendor:/var/www/vendor
#      - laravel_public:/var/www/public
    networks:
      - netmonitor
    deploy:
      mode: replicated
      replicas: 1

  nginx:
    image: ***
    depends_on:
      - php
#    volumes:
#      - laravel_public:/var/www/public
    networks:
      - netmonitor
      - proxynet
    deploy:
      mode: replicated
      replicas: 1
      labels:
        - "traefik.enable=true"
        - "traefik.http.routers.nginx.tls=true"
        - "traefik.http.routers.nginx.rule=Host(`mydomain.com`)"
        - "traefik.http.routers.nginx.entrypoints=web"
        - "traefik.http.routers.nginx.entrypoints=websecure"
        - "traefik.http.routers.nginx.tls.certresolver=le"
        - "traefik.http.routers.nginx.middlewares=nginx-redir"
        - "traefik.http.services.nginx.loadbalancer.server.port=80"
        - "traefik.http.middlewares.nginx-redir.redirectscheme.scheme=https"
        - "traefik.http.middlewares.nginx-redir.redirectscheme.permanent=true"
        - "traefik.http.middlewares.nginx-redir.redirectscheme.port=443"

  mysql:
    image: mysql:8.0.39
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
    volumes:
      - db_data_2:/var/lib/mysql
    networks:
      - netmonitor
      - proxynet
    deploy:
      mode: replicated
      replicas: 1
#      labels:
#        - "traefik.enable=true"
#        - "traefik.tcp.routers.mysql.rule=HostSNI(`*`)"
#        - "traefik.tcp.routers.mysql.entrypoints=mysql"
#        - "traefik.tcp.services.mysql.loadbalancer.server.port=3306"

networks:
  netmonitor:
  proxynet:
    external: true

volumes:
  laravel_public:
    external: false
  laravel_storage:
    external: false
  vendor:
    external: false
  db_data_2:
    external: false

If I request a domain via https, I either get a normal response or 404 not found:

nkl@mortar-II (14:28) ~ $ curl https://mydomain.com -vvv
*   Trying 109.248.213.210:443...
* Connected to mydomain.com (109.248.213.210) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=mydomain.com
*  start date: Oct 14 06:19:37 2024 GMT
*  expire date: Jan 12 06:19:36 2025 GMT
*  subjectAltName: host "mydomain.com" matched cert's "mydomain.com"
*  issuer: C=US; O=Let's Encrypt; CN=R10
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x5c136a763eb0)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/2
> Host: mydomain.com
> user-agent: curl/7.81.0
> accept: */*
> 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 401 
< cache-control: no-cache, private
< content-type: application/json
< date: Mon, 14 Oct 2024 09:28:23 GMT
< server: nginx
< set-cookie: XSRF-TOKEN=eyJpdiI6IkY4Kzc4T3RoaUQxMWtPUDRjZlYzalE9PSIsInZhbHVlIjoiUzJmYll5TlhUUzRVd3hPVVlVOXZZeFYwUWdGVE45TXFGaHd0Unp1MkxZem5BalFVbTBWN3ozOGlMUmVUOEtGWE0yaGtqMUJNMEFwR0h2VmlLelZIbDF5K1B5ampEUUg0MHhmOU9TWlpma2R1VU15RWhpYW84bFo0M0czcC9PZ3oiLCJtYWMiOiI5MWM5YmYxNjBjZGZhY2QxYTQ5NDc1MDM1ZGQyM2U4MDE2NTg3YTMyZWFmMjBhMzRjYzVkNGVmMDliZTk4MDIwIiwidGFnIjoiIn0%3D; expires=Mon, 14-Oct-2024 11:28:23 GMT; Max-Age=7200; path=/; samesite=lax
< set-cookie: laravel_session=eyJpdiI6ImFsOEZBQjJSclFZMWdGUktvaWZ5SkE9PSIsInZhbHVlIjoiVGM5eVg1NEZuTHltVzlGdnkxY2U2cVdLa012S2hscHpkNzdOUWtieWU5TzBycFNpVWw5TlFtaC9GdGVvQUJ3TVBDcURjc3MzT0lyZnBjdWVlcTBneHhxTHd3TndwVm9wYW1ONDlXcXR4L1ZuVzJ3VnRKY0REWmREMmpFKzZ4bEEiLCJtYWMiOiJiNjRkMzI2ZDIzNzNmNmU1NzY0ODI2NTFmMTBjNzUzYzZmNDhjMjllNmMxNzQwNWU3ZDc3MmViOGVmODc3YzhhIiwidGFnIjoiIn0%3D; expires=Mon, 14-Oct-2024 11:28:23 GMT; Max-Age=7200; path=/; httponly; samesite=lax
< x-powered-by: PHP/8.2.24
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection #0 to host mydomain.com left intact
{"message":"Unauthenticated."}
nkl@mortar-II (14:28) ~ $ curl https://mydomain.com -vvv
*   Trying 109.248.213.210:443...
* Connected to mydomain.com (109.248.213.210) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_128_GCM_SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=mydomain.com
*  start date: Oct 14 06:19:37 2024 GMT
*  expire date: Jan 12 06:19:36 2025 GMT
*  subjectAltName: host "mydomain.com" matched cert's "mydomain.com"
*  issuer: C=US; O=Let's Encrypt; CN=R10
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x5a8736b0eeb0)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET / HTTP/2
> Host: mydomain.com
> user-agent: curl/7.81.0
> accept: */*
> 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 404 
< content-type: text/plain; charset=utf-8
< date: Mon, 14 Oct 2024 09:28:26 GMT
< x-content-type-options: nosniff
< content-length: 19
< 
* TLSv1.2 (IN), TLS header, Supplemental data (23):
404 page not found
* Connection #0 to host mydomain.com left intact
nkl@mortar-II (14:28) ~ $ 

If I request a domain via http, I always get 404 not found in response:

nkl@mortar-II (14:28) ~ $ curl http://mydomain.com -vvv
*   Trying 109.248.213.210:80...
* Connected to mydomain.com (109.248.213.210) port 80 (#0)
> GET / HTTP/1.1
> Host: mydomain.com
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Mon, 14 Oct 2024 09:33:56 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host mydomain.com left intact
nkl@mortar-II (14:33) ~ $ curl http://mydomain.com -vvv
*   Trying 109.248.213.210:80...
* Connected to mydomain.com (109.248.213.210) port 80 (#0)
> GET / HTTP/1.1
> Host: mydomain.com
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Content-Type: text/plain; charset=utf-8
< X-Content-Type-Options: nosniff
< Date: Mon, 14 Oct 2024 09:34:00 GMT
< Content-Length: 19
< 
404 page not found
* Connection #0 to host mydomain.com left intact

I solve my problem with this solution:

services:
#...
    nginx:
    image: registry.gitlab.com/lifan2029/api.netmonitor:nginx
    depends_on:
      - php
#    volumes:
#      - laravel_public:/var/www/public
    networks:
      - netmonitor
      - proxynet
    deploy:
      mode: replicated
      replicas: 1
      labels:
        # Dynamic config to unprotected connections
        - "traefik.enable=true"
        - "traefik.http.middlewares.nginx-redir.redirectscheme.scheme=https"
        - "traefik.http.middlewares.nginx-redir.redirectscheme.permanent=true"
        - "traefik.http.routers.nginx.middlewares=nginx-redir"
        - "traefik.http.routers.nginx.rule=Host(`geo.cellmap.kz`)"
        - "traefik.http.routers.nginx.entrypoints=web"
        # Dynamic config to protected connections
        - "traefik.http.routers.nginx-secure.rule=Host(`geo.cellmap.kz`)"
        - "traefik.http.routers.nginx-secure.entrypoints=websecure"
        - "traefik.http.routers.nginx-secure.tls.certresolver=le"
        - "traefik.http.routers.nginx-secure.tls=true"
        - "traefik.http.services.nginx-secure.loadbalancer.server.port=80"
#...

I personally prefer to have the http-to-https redirect and TLS globally on the entrypoint, see simple Traefik example, saves a lot of repetition.

This is how it should work in an ideal world. But there are still services that do not fully support https

This topic was automatically closed 3 days after the last reply. New replies are no longer allowed.