Search code examples
symfonysslnginxtraefiktraefik-ingress

Symfony app not getting HTTPS traffic behind Traefik and Nginx proxy


I currently try to deploy a Symfony app in a Docker setup. The current setup is:

[ Traefik ] -> [ Nginx ] -> [ PHP-FPM ]

  • Traefik is the ingres point, handling SSL certificates (using the dnsChallenge option).
  • Nginx handles serving of static files (assets and that stuff), has a traefik.frontend.rule as label to assign the domain
  • PHP-FPM runs the PHP code

The generation of certificate by Traefik works without any problem, ex. the Traefik Dashboard and Portainer work without any problems. However, when I access the Symfony app through a browser, Symfony thinks it's not on a HTTPS connection. The url field in the browser has https://foo.example.tld in it, but the content controlled by Symfony falls back to http, ex. the image assets or urls that where generate using the absolute path.

var_dump($request->getScheme(), $request->getSchemeAndHttpHost()); // 'http' and 'http://example.tld'

I guess this kind of makes sense, as the connection between Traefik and Nginx is using port 80. If I assign port 443 to Nginx and have Nginx listen on that one instead of port 80, I get the same result.

So the question is, how do I fix this? Do I have to generate a local SSL certificate, and have Nginx load that and tell Traefik to use that? Is there another way? Do I need to forward anything else on either Traefik or Nginx

// docker-compose.yml (shortened)
version: '3.7'

services:
  traefik:
    image: traefik:1.7
    container_name: traefik
    command: --api --docker --docker.exposedbydefault=false
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./config/traefik.prod.toml:/traefik.toml
      - acme-storage:/acme:rw
    labels:
      - traefik.enable=true
      - traefik.backend=medison-traefik
      - traefik.frontend.rule=Host:dashboard.example.tld
      - traefik.port=8080
    restart: always

  webserver:
    image: nginx:alpine
    container_name: webserver
    volumes:
      - ./storage/uploads:/var/www/html/web/uploads:ro
      - ./config/nginx.prod.conf:/etc/nginx/conf.d/default.conf:ro
    working_dir: /var/www/html/web
    depends_on:
      - php-fpm
    labels:
      - traefik.enable=true
      - traefik.backend=webserver
      - traefik.frontend.rule=Host:foo.example.tld
    restart: always

  php-fpm:
    image: user/image:master
    container_name: php-fpm
    volumes:
      - ./storage/uploads:/var/www/html/web/uploads:rw
      - ./logs/php:/var/www/var/logs:rw
    working_dir: /var/www/html/web
    restart: always

volumes:
  acme-storage:
// nginx.prod.conf
server {
    listen 80 default;

    client_max_body_size 108M;

    access_log /var/log/nginx/application.access.log;

    root /var/www/html/web;
    index app.php;

    if (!-e $request_filename) {
        rewrite ^.*$ /app.php last;
    }

    location ~ \.php$ {
        fastcgi_pass php-fpm:9000;
        fastcgi_index app.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PHP_VALUE "error_log=/var/log/nginx/application_php_errors.log";
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        include fastcgi_params;
    }

}

For the test with port 443, I changed in nginx.prod.conf line 2 listen 80 default; to listen 443 default; and added - traefik.port=443 to docker-compose.yml after - traefik.frontend.rule=Host:foo.example.tld


Solution

  • I had a same problem with redirect from htts to http, when I moved project to kubernetes with Ingress. I set trusted proxies to request. And it's helped.
    https://symfony.com/doc/4.4/deployment/proxies.html

    // public/index.php
    
    // ...
    Request::setTrustedProxies(
        // trust *all* requests (the 'REMOTE_ADDR' string is replaced at
        // run time by $_SERVER['REMOTE_ADDR'])
        ['127.0.0.1', 'REMOTE_ADDR'],
    
        // if you're using ELB, otherwise use a constant from above
        Request::HEADER_X_FORWARDED_AWS_ELB
    );