events {} http { server { listen 80 default_server; listen [::]:80 default_server; server_name _; # ACME challenge — must come before the redirect location /.well-known/acme-challenge/ { root /var/www/acme; } # Everything else redirects to HTTPS location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; listen [::]:443 ssl; ssl_certificate /certs/nginx_certificate.pem; ssl_certificate_key /certs/nginx_key.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;"; server_tokens off; client_max_body_size 50M; location / { proxy_pass http://overleaf:80; proxy_set_header X-Forwarded-Proto $scheme; 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 $proxy_add_x_forwarded_for; proxy_read_timeout 3m; proxy_send_timeout 3m; proxy_hide_header Cache-Control; add_header Cache-Control "no-store" always; } location /ub/ { alias /var/www/static/ub/; try_files $uri =404; types { image/svg+xml svg; } } # Bundled Wakapi (WakaTime-compatible server) — UI + API under /wakapi. # Wakapi 2.18.2 contract: the app serves its routes at / and uses # WAKAPI_BASE_PATH=/wakapi only for the URLs/cookies it generates — # so the proxy must STRIP the prefix (trailing slash on proxy_pass): # /wakapi/login → /login, while its links stay /wakapi/… end-to-end. # Security: strip any client-supplied identity header — only the overleaf # container (pinned source IP) may use the trusted-header identity. # /wakapi (exact) → canonical form with trailing slash location = /wakapi { return 301 /wakapi/; } location /wakapi/ { proxy_pass http://wakapi:3000/; proxy_set_header Remote-User ""; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_http_version 1.1; } # Bundled Grafana (monitoring UI) — same-origin under /grafana/. # Unlike /wakapi the prefix is NOT stripped: grafana runs with # GF_SERVER_SERVE_FROM_SUB_PATH=true + GF_SERVER_ROOT_URL ending in # /grafana/, so it serves its routes at /grafana/... itself; the raw # :3000 port is not published to the host (grafana compose). location = /grafana { return 301 /grafana/; } location /grafana/ { proxy_pass http://grafana:3000; 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-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_read_timeout 5m; proxy_send_timeout 5m; } } }