map $http_upgrade $connection_upgrade { default upgrade; '' close; } # Redirect all HTTP to HTTPS server { listen 80; listen [::]:80; server_name rss.meson.one; location / { return 301 https://$host$request_uri; } } server { # HTTP/2 over TCP listen 443 ssl; listen [::]:443 ssl; # HTTP/3 over QUIC/UDP listen 443 quic; listen [::]:443 quic; http2 on; http3 on; add_header Alt-Svc 'h3=":443"; ma=86400' always; server_name rss.meson.one; root /home/www-data/rss.meson.one; include /etc/letsencrypt/options-ssl-nginx.conf; ssl_certificate /etc/letsencrypt/live/rss.meson.one/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/rss.meson.one/privkey.pem; ssl_trusted_certificate /etc/letsencrypt/live/rss.meson.one/chain.pem; # Security headers add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header X-XSS-Protection "1; mode=block" always; # Logging access_log /var/log/nginx/rss.meson.one.log combined if=$loggable; error_log /var/log/nginx/_error_rss.meson.one.log warn; # Gzip for the Vue SPA assets and JSON API responses gzip on; gzip_vary on; gzip_comp_level 5; gzip_min_length 256; gzip_types application/javascript application/json text/css text/plain application/xml text/xml image/svg+xml font/woff2; # Allow larger bodies (OPML imports, avatar uploads, etc.) client_max_body_size 20m; # --- Fever / Google Reader API + MCP endpoint: no buffering, longer timeouts --- location ~ ^/(api/fever|api/greader|mcp) { proxy_pass http://127.0.0.1:3030; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_read_timeout 300s; proxy_send_timeout 300s; } # --- Everything else: main app + REST API --- location / { proxy_pass http://127.0.0.1:3030; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # Dynamic WebSocket support (only upgrades when client requests it) proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_connect_timeout 60s; proxy_read_timeout 60s; proxy_send_timeout 60s; proxy_buffer_size 16k; proxy_buffers 8 16k; proxy_busy_buffers_size 32k; } # Deny access to hidden files location ~ /\.(?!well-known) { deny all; } }