Files
webmail-client/docker/nginx.conf
T

87 lines
2.8 KiB
Nginx Configuration File
Raw Normal View History

# Webmail front door: static SPA + reverse proxy to the API container.
#
# This file is dropped into /etc/nginx/conf.d/, i.e. it is already inside the
# `http` block — hence the bare `map` below.
#
# TWO LISTENERS, one app:
#
# :80 public — the mail client. Neither the admin bundle nor /api/admin/*
# is served here; both 404.
# :81 admin — the admin panel (its own bundle, its own sign-in), and the
# /api/admin/* endpoints it needs.
#
# The compose file publishes :80 as WEB_PORT and :81 as ADMIN_PORT, and the
# firewall is what makes the split mean anything: allow ADMIN_PORT from the LAN
# only, leave WEB_PORT as exposed as you like (docs/nas-install.md §5.1).
#
# Note what this boundary is and is not. It is nginx refusing paths on one
# listener — good enough to keep the admin panel and its API off an
# internet-facing port, and it fails closed if the app forgets a permission
# check. It is NOT process isolation: both listeners proxy to the same API
# container, so anything that can reach :81 can reach every admin route. The
# panel still demands an administrator sign-in, and the API's own `CurrentAdmin`
# dependency still guards each route; this is the outer layer, not the only one.
map $http_x_forwarded_proto $fwd_proto {
default $scheme;
https https;
http http;
}
# Connection header for the WebSocket upgrade dance on /api/ws.
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream webmail_api {
server api:8000;
keepalive 16;
}
# ---- :80 — public -----------------------------------------------------------
server {
listen 80;
server_name _;
# Regex locations beat prefix ones, so this wins over `location /api/`
# regardless of order. `(/|$)` keeps it to /api/admin and /api/admin/...,
# never a future /api/administrators. 404 rather than 403: a port open to
# the internet shouldn't confirm which endpoints exist.
location ~ ^/api/admin(/|$) {
access_log off;
return 404;
}
# The admin bundle ships in the same dist; don't hand it out here.
location = /admin.html {
access_log off;
return 404;
}
include /etc/nginx/webmail-app.conf;
# SPA fallback -> the mail client.
location / {
try_files $uri $uri/ /index.html;
}
}
# ---- :81 — admin ------------------------------------------------------------
server {
listen 81;
server_name _;
include /etc/nginx/webmail-app.conf;
location = /admin.html {
add_header Cache-Control "no-store, must-revalidate";
}
# SPA fallback -> the admin panel. `/` on this port IS the panel; the mail
# client is not reachable here at all.
location / {
try_files $uri /admin.html;
}
}