Initial commit 🚀
This commit is contained in:
commit
fd58a8d32f
235 files changed
+19775
No files matched your search
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Runs the contact handler next to nginx. The handler is restarted if it crashes, but not when it
|
||||
# exits for missing configuration (code 78); the static site is served either way.
|
||||
(
|
||||
cd /srv/contact || exit
|
||||
while :; do
|
||||
node contact.mjs
|
||||
code=$?
|
||||
[ "$code" -eq 78 ] && { echo "contact: not started, SMTP is not configured." >&2; exit; }
|
||||
echo "contact: exited with $code, restarting in 5 s." >&2
|
||||
sleep 5
|
||||
done
|
||||
) &
|
||||
|
||||
exec nginx -g 'daemon off;'
|
||||
@@ -0,0 +1,114 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# TLS terminates at Dokploy's Traefik; keep redirects relative so they stay on https.
|
||||
absolute_redirect off;
|
||||
|
||||
# The client address arrives in X-Forwarded-For from Traefik on the private network.
|
||||
set_real_ip_from 10.0.0.0/8;
|
||||
set_real_ip_from 172.16.0.0/12;
|
||||
set_real_ip_from 192.168.0.0/16;
|
||||
real_ip_header X-Forwarded-For;
|
||||
real_ip_recursive on;
|
||||
server_tokens off;
|
||||
|
||||
gzip on;
|
||||
gzip_comp_level 6;
|
||||
gzip_min_length 1024;
|
||||
gzip_types text/plain text/css text/xml application/xml application/javascript application/json image/svg+xml;
|
||||
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
|
||||
location = /healthz {
|
||||
access_log off;
|
||||
default_type text/plain;
|
||||
return 200 "ok\n";
|
||||
}
|
||||
|
||||
# The contact form is the one dynamic path: server/contact.mjs, sending by SMTP.
|
||||
location = /contact {
|
||||
limit_except POST { deny all; }
|
||||
client_max_body_size 64k;
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 30s;
|
||||
proxy_intercept_errors on;
|
||||
error_page 502 503 504 = @contact_down;
|
||||
}
|
||||
# The proof-of-work challenge the form solves before it sends; issued by the same handler.
|
||||
location = /contact/challenge {
|
||||
limit_except GET { deny all; }
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
# The alpha sign-up, same handler: the form posts here.
|
||||
location = /notify {
|
||||
limit_except POST { deny all; }
|
||||
client_max_body_size 64k;
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 30s;
|
||||
proxy_intercept_errors on;
|
||||
error_page 502 503 504 = @notify_down;
|
||||
}
|
||||
# The link in the confirmation email; opening it confirms.
|
||||
location = /notify/verify {
|
||||
limit_except GET { deny all; }
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 30s;
|
||||
proxy_intercept_errors on;
|
||||
error_page 502 503 504 = @notify_down;
|
||||
}
|
||||
# Links sent before the confirmation moved off the button page.
|
||||
location ~ ^(/de)?/notify/confirm$ { return 302 /notify/verify$is_args$args; }
|
||||
location @notify_down {
|
||||
if ($http_referer ~ "/de(/|$|#)") { return 303 /de/notify/error; }
|
||||
return 303 /notify/error;
|
||||
}
|
||||
# Handler not running: send the visitor to the error page in their language.
|
||||
location @contact_down {
|
||||
if ($http_referer ~ "/de(/|$|#)") { return 303 /de/contact/error; }
|
||||
return 303 /contact/error;
|
||||
}
|
||||
|
||||
# trailingSlash: 'never' — /team is served from /team/index.html; /team/ redirects to /team.
|
||||
location ~ ^(.+)/$ {
|
||||
return 301 $1$is_args$args;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri.html $uri/index.html =404;
|
||||
}
|
||||
|
||||
# Astro's hashed build assets never change.
|
||||
location ^~ /_astro/ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location ~* \.(?:woff2|mp4|webm|avif|webp|jpg|jpeg|png|svg)$ {
|
||||
add_header Cache-Control "public, max-age=2592000" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
location = /404.html {
|
||||
internal;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user