# 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:8443; 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; } }