meson / p.onni.me

Last active 3 weeks ago

Like 0

meson revised this gist 3 weeks ago · 375fe7c

1 file changed, 179 insertions

p.onni.me (file created)
@@ -0,0 +1,179 @@
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;
5 + server {
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 ──
27 + server {
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 + }