server { listen 80; # Only ever reached via the server's shared Nginx Proxy Manager, which # terminates TLS and forwards traffic for this domain here - this container # itself doesn't need to know about HTTPS or other domains. server_name dmtools.fvandenberg.nl; root /var/www/html/public; location / { try_files $uri /index.php$is_args$args; } location ~ ^/index\.php(/|$) { # A plain "fastcgi_pass php:9000" resolves once at worker start and # caches that IP forever - if the php container is recreated without # also restarting nginx, every request 502s. Routing through a variable # forces re-resolution per the resolver TTL. 127.0.0.11 is Compose's # embedded DNS. Use the globally-unique container name, not the bare # "php" alias: this nginx is also on the shared proxy network where # another project may also have a service called "php". resolver 127.0.0.11 valid=10s; set $php_upstream dmtools-php:9000; fastcgi_pass $php_upstream; fastcgi_split_path_info ^(.+\.php)(/.*)$; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $document_root; # fastcgi_params never forwards Host - forward the real one explicitly. fastcgi_param HTTP_HOST $http_host; # fastcgi_pass does NOT auto-forward incoming headers. Without these, # Symfony can't tell the original request was HTTPS and redirects to # itself forever. if_not_empty: NPM omits some of these entirely, and an # empty-but-present header can behave differently from an absent one. fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto if_not_empty; fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for if_not_empty; fastcgi_param HTTP_X_FORWARDED_HOST $http_x_forwarded_host if_not_empty; fastcgi_param HTTP_X_FORWARDED_PORT $http_x_forwarded_port if_not_empty; fastcgi_read_timeout 120; internal; } # Everything else under public/ (compiled assets, favicon, robots) is served # straight off disk; only index.php is ever executed. location ~ \.php$ { return 404; } # Proxies the puzzle relay's WebSocket connections (src/Command/ # PuzzleRelayCommand.php, a separate long-running container - see # docker-compose.yml) through this same domain, so the browser can use a # plain wss://dmtools.fvandenberg.nl/puzzle-ws/ URL instead of a second # exposed port. NPM must also have "Websockets Support" enabled for this # proxy host, or the Upgrade header never reaches here. location /puzzle-ws/ { resolver 127.0.0.11 valid=10s; set $puzzle_relay dmtools-puzzle-relay:8091; proxy_pass http://$puzzle_relay/; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_read_timeout 1h; proxy_send_timeout 1h; } error_log /var/log/nginx/dmtools_error.log; access_log /var/log/nginx/dmtools_access.log; client_max_body_size 10M; }