project-bifrost-platform/deploy/nginx/bifrost-portal.fenja.ai.conf
Arlind 6f656b7121 chore(deploy): align deploy artifacts to the target server's conventions
Recon of the live box (Ubuntu 24.04 x86_64, nginx 1.24, certbot 2.9)
showed established conventions from the existing fenja / bifrost-customer
services. Match them so the portal looks like a first-class citizen:

- service runs as the existing `fenja` user, journald logging + full
  hardening block (ProtectKernelModules, LockPersonality), ExecStart on
  /usr/bin/node (box upgraded globally to Node 22)
- code in /opt/bifrost-portal, in-dir .env (EnvironmentFile), data under
  the shared /opt/fenja/data/bifrost-portal (ReadWritePaths)
- nginx: 1.24 `listen ... ssl http2` syntax, certbot options-ssl-nginx +
  dhparam includes, server_tokens off, sites-available/bifrost-portal (no
  .conf) symlinked; 12m body size for photo uploads; port 4322 (free)
- deploy.sh / backup.sh point at the new paths
- DEPLOY.md rewritten as a server-specific runbook incl. the global Node 22
  upgrade + retest of the existing apps, and pnpm via corepack

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 13:16:57 +02:00

63 lines
2.4 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 the existing project-bifrost.fenja.ai site; only claims this
# hostname. Matches that site's conventions (nginx 1.24, certbot TLS includes).
#
# Install (no .conf extension, to match the existing sites-available layout):
# sudo cp deploy/nginx/bifrost-portal.fenja.ai.conf /etc/nginx/sites-available/bifrost-portal
# sudo ln -s /etc/nginx/sites-available/bifrost-portal /etc/nginx/sites-enabled/bifrost-portal
# sudo nginx -t && sudo systemctl reload nginx
#
# TLS: the :80 block must be live first so certbot's ACME challenge succeeds.
# Then: sudo certbot --nginx -d bifrost-portal.fenja.ai (edits this file).
server {
listen 80;
listen [::]:80;
server_name bifrost-portal.fenja.ai;
# Let certbot's renewals reach .well-known/acme-challenge on port 80
location /.well-known/acme-challenge/ {
root /var/www/html;
}
# Everything else goes to HTTPS
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
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;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# ─── Security headers ───
# HSTS — confirm the cert + redirect loop is solid before relying on it.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
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;
# Event photo uploads can be a few MB (the existing site uses 32k — this
# site accepts image uploads, so it needs headroom).
client_max_body_size 12m;
# Don't leak nginx version
server_tokens off;
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_read_timeout 60s;
}
}