Run the Astro Node standalone server as a hardened systemd service on 127.0.0.1:4322, behind the existing nginx which terminates TLS and proxies the bifrost-portal.fenja.ai hostname. Coexists with the other Fenja site; its config is untouched. - deploy/bifrost-portal.service: systemd unit (bifrost user, EnvironmentFile, ProtectSystem, ReadWritePaths to the data dir only) - deploy/nginx/bifrost-portal.fenja.ai.conf: HTTP->HTTPS + proxy site block - .env.production.example: prod env vars (secret, db path, uploads, host/port) - scripts/deploy.sh: server-side pull -> install (rebuild native dep) -> build -> migrate -> restart; persistent data untouched - scripts/backup.sh: nightly online .backup, 30-day retention - DEPLOY.md: full runbook (port check, DNS, provision, TLS, backups, rollback) Persistent data (db, uploads, backups) lives in /var/lib/bifrost-portal, outside the /opt/bifrost-portal build dir, so redeploys never wipe it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
66 lines
2.5 KiB
Text
66 lines
2.5 KiB
Text
# nginx site for bifrost-portal.fenja.ai
|
|
# Reverse-proxies to the Bifrost portal Node server on 127.0.0.1:4322.
|
|
# Coexists with other Fenja sites on this box — it only claims this hostname.
|
|
#
|
|
# Install:
|
|
# sudo cp deploy/nginx/bifrost-portal.fenja.ai.conf /etc/nginx/sites-available/
|
|
# sudo ln -s /etc/nginx/sites-available/bifrost-portal.fenja.ai.conf /etc/nginx/sites-enabled/
|
|
# sudo nginx -t && sudo systemctl reload nginx
|
|
#
|
|
# TLS: obtain the cert first (see DEPLOY.md). Either run
|
|
# sudo certbot --nginx -d bifrost-portal.fenja.ai
|
|
# (certbot edits this file in place), OR issue with --webroot and keep the
|
|
# 443 block below as-is. The :80 block must exist before certbot runs.
|
|
|
|
# HTTP — ACME challenge + redirect everything else to HTTPS.
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name bifrost-portal.fenja.ai;
|
|
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/html;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://$host$request_uri;
|
|
}
|
|
}
|
|
|
|
# HTTPS — terminates TLS, proxies to the Node app.
|
|
server {
|
|
listen 443 ssl;
|
|
listen [::]:443 ssl;
|
|
http2 on;
|
|
server_name bifrost-portal.fenja.ai;
|
|
|
|
ssl_certificate /etc/letsencrypt/live/bifrost-portal.fenja.ai/fullchain.pem;
|
|
ssl_certificate_key /etc/letsencrypt/live/bifrost-portal.fenja.ai/privkey.pem;
|
|
# Modern TLS defaults (Mozilla "intermediate"). If certbot manages this
|
|
# file it may append its own ssl_* includes — harmless duplicates aside.
|
|
ssl_protocols TLSv1.2 TLSv1.3;
|
|
ssl_prefer_server_ciphers off;
|
|
|
|
# Event photo uploads can be a few MB; keep headroom above the app's limit.
|
|
client_max_body_size 12m;
|
|
|
|
# Security headers. HSTS only after you've confirmed HTTPS works end-to-end.
|
|
add_header X-Content-Type-Options nosniff always;
|
|
add_header X-Frame-Options SAMEORIGIN always;
|
|
add_header Referrer-Policy strict-origin-when-cross-origin always;
|
|
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:4322;
|
|
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_set_header X-Forwarded-Host $host;
|
|
# Upgrade headers in case any route uses them; harmless otherwise.
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_read_timeout 60s;
|
|
}
|
|
}
|