bunker-admin 5642a24c8f Sync CCP templates with production configs for complete instance provisioning
Closes 12 template drift gaps between the Control Panel templates and
production configs. New instances now provision with full monitoring
(alerts fire properly), correct Gitea DB type (postgres not mysql),
social sharing previews (OG meta bot routes), Excalidraw subdomain
routing, docker-socket-proxy for Homepage, and complete Grafana/
Alertmanager/Prometheus config copying.

Key changes:
- Rewrite Prometheus template: add alerting, rule_files, 5 scrape jobs
- Add cAdvisor, node-exporter, redis-exporter, gotify, docker-socket-proxy
- Fix Gitea env from mysql to postgres to match docker-compose
- Add OG bot detection + rewrite routes for campaigns/pages/gallery
- Add Excalidraw nginx server block + Pangolin draw subdomain
- Add embed port to discovery portConfig + emailTestMode to registration
- Copy alerts.yml, alertmanager.yml, Grafana dashboards to templates
- Add Listmonk proxy port and upgrade volume to API service

Bunker Admin
2026-03-05 08:32:49 -07:00

605 lines
19 KiB
Handlebars

# Changemaker Lite Nginx — Instance: {{name}}
# Subdomain routing for Pangolin tunnel + local port access
# ─── Subdomain Server Blocks ──────────────────────────────
# These enable proper routing when accessed via Pangolin tunnel.
# Requests come in as app.domain.org → nginx:80 → upstream service.
# Admin + Public App
server {
listen 80;
server_name app.{{domain}};
add_header X-Frame-Options "SAMEORIGIN" always;
# Bot detection for OG meta previews
set $is_bot 0;
if ($http_user_agent ~* "(Twitterbot|facebookexternalhit|LinkedInBot|Slackbot|TelegramBot|WhatsApp|Discordbot|Googlebot|bingbot|Pinterest)") {
set $is_bot 1;
}
# Campaign OG meta
location ~ ^/campaign/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/campaign/(.*)$ /api/og/campaign/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
# Landing page OG meta
location ~ ^/p/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/p/(.*)$ /api/og/page/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{#if enableMedia}}
# Gallery video OG meta
location ~ ^/gallery/watch/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/gallery/watch/(.*)$ /api/og/gallery/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{/if}}
location / {
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{#if enableMedia}}
location /api/media/ {
set $upstream_media http://{{containerPrefix}}-media-api:4100;
rewrite ^/api/media/(.*) /api/$1 break;
proxy_pass $upstream_media;
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;
client_max_body_size 10G;
proxy_read_timeout 3600s;
proxy_connect_timeout 75s;
proxy_request_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /media/ {
set $upstream_media_default http://{{containerPrefix}}-media-api:4100;
rewrite ^/media/(.*) /api/$1 break;
proxy_pass $upstream_media_default;
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;
client_max_body_size 10G;
proxy_read_timeout 3600s;
proxy_connect_timeout 75s;
proxy_request_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
{{/if}}
location /api/ {
set $upstream_api http://{{containerPrefix}}-api:4000;
proxy_pass $upstream_api;
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 3600s;
}
}
# API (direct subdomain access)
server {
listen 80;
server_name api.{{domain}};
location / {
set $upstream_api http://{{containerPrefix}}-api:4000;
proxy_pass $upstream_api;
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 3600s;
}
}
{{#if enableMedia}}
# Media API
server {
listen 80;
server_name media.{{domain}};
client_max_body_size 10G;
location / {
set $upstream_media http://{{containerPrefix}}-media-api:4100;
proxy_pass $upstream_media;
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 3600s;
proxy_connect_timeout 75s;
proxy_request_buffering off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
{{/if}}
# Documentation (MkDocs dev server)
server {
listen 80;
server_name docs.{{domain}};
location / {
set $upstream_mkdocs http://{{containerPrefix}}-mkdocs:8000;
proxy_pass $upstream_mkdocs;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# NocoDB Data Browser
server {
listen 80;
server_name db.{{domain}};
location / {
set $upstream_nocodb http://{{containerPrefix}}-nocodb:8080;
proxy_pass $upstream_nocodb;
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;
}
}
# MailHog
server {
listen 80;
server_name mail.{{domain}};
location / {
set $upstream_mailhog http://{{containerPrefix}}-mailhog:8025;
proxy_pass $upstream_mailhog;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Mini QR
server {
listen 80;
server_name qr.{{domain}};
location / {
set $upstream_qr http://{{containerPrefix}}-mini-qr:8080;
proxy_pass $upstream_qr;
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;
}
}
{{#if enableMeet}}
# Jitsi Meet
server {
listen 80;
server_name meet.{{domain}};
location / {
set $upstream_jitsi http://{{containerPrefix}}-jitsi-web:80;
proxy_pass $upstream_jitsi;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
{{/if}}
{{#if enableChat}}
# Rocket.Chat
server {
listen 80;
server_name chat.{{domain}};
client_max_body_size 100m;
location / {
set $upstream_rocketchat http://{{containerPrefix}}-rocketchat:3000;
proxy_pass $upstream_rocketchat;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
{{/if}}
{{#if enableGancio}}
# Gancio Events
server {
listen 80;
server_name events.{{domain}};
location / {
set $upstream_gancio http://{{containerPrefix}}-gancio:13120;
proxy_pass $upstream_gancio;
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;
}
}
{{/if}}
{{#if enableListmonk}}
# Listmonk Newsletter
server {
listen 80;
server_name listmonk.{{domain}};
location / {
set $upstream_listmonk http://{{containerPrefix}}-listmonk:9000;
proxy_pass $upstream_listmonk;
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;
}
}
{{/if}}
{{#if enableMonitoring}}
# Grafana
server {
listen 80;
server_name grafana.{{domain}};
location / {
set $upstream_grafana http://{{containerPrefix}}-grafana:3000;
proxy_pass $upstream_grafana;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
{{/if}}
{{#if enableDevTools}}
# Code Server
server {
listen 80;
server_name code.{{domain}};
location / {
set $upstream_code http://{{containerPrefix}}-code-server:8080;
proxy_pass $upstream_code;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Gitea
server {
listen 80;
server_name git.{{domain}};
client_max_body_size 2048M;
location / {
set $upstream_gitea http://{{containerPrefix}}-gitea:3000;
proxy_pass $upstream_gitea;
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;
}
}
# n8n
server {
listen 80;
server_name n8n.{{domain}};
location / {
set $upstream_n8n http://{{containerPrefix}}-n8n:5678;
proxy_pass $upstream_n8n;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Vaultwarden
server {
listen 80;
server_name vault.{{domain}};
location / {
set $upstream_vault http://{{containerPrefix}}-vaultwarden:80;
proxy_pass $upstream_vault;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# Homepage Dashboard
server {
listen 80;
server_name home.{{domain}};
location / {
set $upstream_homepage http://{{containerPrefix}}-homepage:3000;
proxy_pass $upstream_homepage;
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;
}
}
# Excalidraw
server {
listen 80;
server_name draw.{{domain}};
location / {
set $upstream_excalidraw http://{{containerPrefix}}-excalidraw:80;
proxy_pass $upstream_excalidraw;
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 Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
{{/if}}
# Root domain — MkDocs static site
server {
listen 80;
server_name {{domain}};
location / {
set $upstream_mkdocs_site http://{{containerPrefix}}-mkdocs-site:80;
proxy_pass $upstream_mkdocs_site;
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;
}
}
# ─── Default Server (localhost / direct port access) ──────
# Catches requests without a matching server_name (e.g., localhost, IP)
server {
listen 80 default_server;
server_name localhost _;
add_header X-Frame-Options "SAMEORIGIN" always;
# Bot detection for OG meta previews
set $is_bot 0;
if ($http_user_agent ~* "(Twitterbot|facebookexternalhit|LinkedInBot|Slackbot|TelegramBot|WhatsApp|Discordbot|Googlebot|bingbot|Pinterest)") {
set $is_bot 1;
}
# Campaign OG meta
location ~ ^/campaign/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/campaign/(.*)$ /api/og/campaign/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
# Landing page OG meta
location ~ ^/p/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/p/(.*)$ /api/og/page/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{#if enableMedia}}
# Gallery video OG meta
location ~ ^/gallery/watch/([^/]+)$ {
if ($is_bot = 1) {
rewrite ^/gallery/watch/(.*)$ /api/og/gallery/$1 break;
proxy_pass http://{{containerPrefix}}-api:4000;
}
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{/if}}
# Admin GUI + Public pages (default)
location / {
set $upstream_admin http://{{containerPrefix}}-admin:3000;
proxy_pass $upstream_admin;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
}
{{#if enableMedia}}
# Media API admin routes (must come BEFORE /api/ for longest prefix match)
# Rewrites /api/media/* to /api/* on media-api
location /api/media/ {
set $upstream_media http://{{containerPrefix}}-media-api:4100;
rewrite ^/api/media/(.*) /api/$1 break;
proxy_pass $upstream_media;
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;
# Large upload support
client_max_body_size 10G;
proxy_read_timeout 3600s;
proxy_connect_timeout 75s;
proxy_request_buffering off;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Media API routes rewrite (matches Vite dev proxy behavior)
# Rewrites /media/* to /api/* on media-api (port 4100)
location /media/ {
set $upstream_media_default http://{{containerPrefix}}-media-api:4100;
rewrite ^/media/(.*) /api/$1 break;
proxy_pass $upstream_media_default;
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;
# Large upload support
client_max_body_size 10G;
proxy_read_timeout 3600s;
proxy_connect_timeout 75s;
proxy_request_buffering off;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
{{/if}}
# Express API
location /api/ {
set $upstream_api http://{{containerPrefix}}-api:4000;
proxy_pass $upstream_api;
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 3600s;
}
}