user app; worker_processes auto; pid /run/nginx.pid; error_log /dev/stderr warn; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; access_log /dev/stdout; sendfile on; tcp_nopush on; keepalive_timeout 65; server_tokens off; client_max_body_size 100m; server { listen 80 default_server; server_name _; root /var/www/html/public; index index.php; charset utf-8; # Terminal sidecar websocket (xterm.js ↔ PTY). Same origin; the sidecar authorizes the # single-use token before opening the PTY. Long read timeout — sessions are long-lived. location = /terminal/ws { resolver 127.0.0.11 valid=10s; set $terminal_upstream terminal:3000; proxy_pass http://$terminal_upstream; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } # Reverb (Pusher protocol) over the SAME origin — mirrors Caddy in prod so the # browser reaches Reverb through this front door (/app/* = WS, /apps/* = events). # A resolver + variable defers DNS to request time, so nginx still starts if the # reverb container is momentarily unresolvable. location ~ ^/(app|apps)/ { resolver 127.0.0.11 valid=10s; set $reverb_upstream reverb:8080; proxy_pass http://$reverb_upstream; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_read_timeout 600s; } location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } # Correct MIME for the PWA manifest (the bundled mime.types maps .webmanifest # to octet-stream). Per-file default_type avoids replacing the global types map. location = /site.webmanifest { default_type application/manifest+json; access_log off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; fastcgi_param DOCUMENT_ROOT $realpath_root; fastcgi_hide_header X-Powered-By; fastcgi_read_timeout 120; } # deny dotfiles except .well-known location ~ /\.(?!well-known).* { deny all; } } }