meson / p.onni.me

Last active 3 weeks ago

Like 0

Revision 375fe7c4f8d3854467b610e4fce3997b340218d8

p.onni.me Raw
1# ── Rate limiting zones (http-context; fine here since this file is
2# included inside the http {} block via sites-enabled) ──
3#limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
4#limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
5server {
6 listen 80;
7 listen [::]:80;
8 server_name p.onni.me;
9
10 add_header X-Content-Type-Options nosniff always;
11 add_header X-Frame-Options DENY always;
12
13 access_log /var/log/nginx/p.onni.me.log combined if=$loggable;
14 error_log /var/log/nginx/_error_p.onni.me.log warn;
15
16 # Keep ACME challenge reachable for certbot webroot/HTTP-01 renewal
17 location ^~ /.well-known/acme-challenge/ {
18 root /home/www-data/p.onni.me;
19 default_type "text/plain";
20 allow all;
21 }
22
23 return 301 https://$server_name$request_uri;
24}
25
26# ── Main HTTPS server ──
27server {
28 # HTTP/2 over TCP
29 listen 443 ssl;
30 listen [::]:443 ssl;
31
32 # HTTP/3 over QUIC/UDP
33 listen 443 quic;
34 listen [::]:443 quic;
35
36 http2 on;
37 http3 on;
38
39 add_header Alt-Svc 'h3=":443"; ma=86400' always;
40
41 server_name p.onni.me;
42
43 root /home/www-data/p.onni.me;
44
45 # SSL Certificate Configuration (Certbot managed)
46
47 include /etc/letsencrypt/options-ssl-nginx.conf;
48 ssl_certificate /etc/letsencrypt/live/p.onni.me/fullchain.pem;
49 ssl_certificate_key /etc/letsencrypt/live/p.onni.me/privkey.pem;
50 ssl_dhparam /etc/letsencrypt/dh/tau.pem;
51
52 # Security headers
53 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
54 add_header X-Content-Type-Options nosniff always;
55 add_header X-Frame-Options SAMEORIGIN always;
56 add_header X-XSS-Protection "1; mode=block" always;
57 add_header X-Robots-Tag "noindex, nofollow" always;
58 add_header X-Download-Options noopen always;
59 add_header X-Permitted-Cross-Domain-Policies none always;
60 add_header Referrer-Policy "strict-origin-when-cross-origin" always;
61
62 # CSP for SnowShare (Next.js). Adjust img-src/connect-src if you enable
63 # S3-compatible storage on a different origin, or add Plausible's host
64 # if TELEMETRY=true and it's not self-hosted under this domain.
65 add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https:; frame-src 'self'; object-src 'none'; base-uri 'self';" always;
66
67 # Global body size ceiling — set to your intended max upload size.
68 # This must be >= whatever you configure in SnowShare's admin panel,
69 # or nginx will 413 before the app ever gets to enforce its own limit.
70 client_max_body_size 1G;
71 client_body_timeout 300s;
72 client_header_timeout 60s;
73
74 proxy_connect_timeout 60s;
75 proxy_send_timeout 300s;
76 proxy_read_timeout 300s;
77 send_timeout 60s;
78
79 proxy_buffering on;
80 proxy_buffer_size 4k;
81 proxy_buffers 8 4k;
82 proxy_busy_buffers_size 8k;
83 proxy_max_temp_file_size 1024m;
84 proxy_temp_file_write_size 64k;
85
86 access_log /var/log/nginx/p.onni.me.log combined if=$loggable;
87 error_log /var/log/nginx/_error_p.onni.me.log warn;
88
89 gzip on;
90 gzip_vary on;
91 gzip_comp_level 6;
92 gzip_min_length 1000;
93 gzip_proxied any;
94 gzip_types
95 text/plain
96 text/css
97 text/xml
98 text/javascript
99 application/json
100 application/javascript
101 application/xml+rss
102 application/atom+xml
103 image/svg+xml;
104
105 # ── Main SnowShare proxy ──
106 location / {
107 # limit_req zone=api burst=20 nodelay;
108
109 proxy_pass http://127.0.0.1:3000;
110 proxy_http_version 1.1;
111
112 proxy_set_header Host $host;
113 proxy_set_header X-Real-IP $remote_addr;
114 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
115 proxy_set_header X-Forwarded-Proto $scheme;
116 proxy_set_header X-Forwarded-Host $host;
117 proxy_set_header X-Forwarded-Port $server_port;
118
119 # Large-upload tuning: don't buffer the whole request body to disk
120 # before forwarding — matters far more than response buffering for
121 # a file-sharing app. Keep this in sync with whatever max size you
122 # set in SnowShare's admin panel and the client_max_body_size above.
123 client_max_body_size 1G;
124 proxy_request_buffering off;
125 proxy_buffering off;
126 proxy_redirect off;
127 proxy_cache_bypass $http_upgrade;
128 }
129
130 # Login / auth endpoints — stricter rate limiting
131 location ~ ^/(api/auth|rest/login) {
132 # limit_req zone=login burst=3 nodelay;
133
134 proxy_pass http://127.0.0.1:3000;
135 proxy_http_version 1.1;
136
137 proxy_set_header Host $host;
138 proxy_set_header X-Real-IP $remote_addr;
139 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
140 proxy_set_header X-Forwarded-Proto $scheme;
141 proxy_set_header X-Forwarded-Host $host;
142
143 proxy_redirect off;
144 }
145
146 # Static assets with caching
147 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|map)$ {
148 proxy_pass http://127.0.0.1:3000;
149
150 proxy_set_header Host $host;
151 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
152 proxy_set_header X-Forwarded-Proto $scheme;
153
154 expires 30d;
155 add_header Cache-Control "public, no-transform";
156 add_header Vary Accept-Encoding;
157 add_header Access-Control-Allow-Origin "*";
158 }
159
160 # Health check
161 location = /healthz {
162 access_log off;
163 return 200 "healthy\n";
164 add_header Content-Type text/plain;
165 }
166
167 # Block access to dotfiles / VCS metadata — NOT /admin, which is a
168 # legitimate SnowShare route. Trim this list further if you don't
169 # run PHP or WordPress anywhere else under this vhost.
170 location ~ /\.(ht|env|git|svn) {
171 deny all;
172 return 404;
173 }
174
175 location ~ ^/(wp-admin|phpmyadmin) {
176 deny all;
177 return 404;
178 }
179}