changemaker.lite/docs/NGINX_DOMAIN_TEMPLATING.md

5.8 KiB

Nginx Domain Templating

Overview

The nginx configuration now uses environment variable templating to support dynamic domain configuration. This allows you to change the domain for all services by simply updating the DOMAIN environment variable in .env.

How It Works

  1. Template Files: Nginx configuration files are stored as templates with .template extension

    • nginx/conf.d/api.conf.template
    • nginx/conf.d/default.conf.template
    • nginx/conf.d/services.conf.template
  2. Environment Variable: The DOMAIN variable in .env controls all subdomains

    DOMAIN=betteredmonton.org
    
  3. Startup Process: When the nginx container starts:

    • The entrypoint script (nginx/entrypoint.sh) runs first
    • It uses envsubst to replace ${DOMAIN} in templates with the actual value
    • Generated .conf files are created in /etc/nginx/conf.d/
    • Nginx starts with the generated configuration
  4. Docker Configuration: The DOMAIN env var is passed to nginx via docker-compose.yml:

    environment:
      - DOMAIN=${DOMAIN:-cmlite.org}
    

Configured Subdomains

All subdomains automatically use the DOMAIN value from .env:

Subdomain Service Port
${DOMAIN} Admin GUI (root domain) -
app.${DOMAIN} Admin GUI -
api.${DOMAIN} API Server -
db.${DOMAIN} NocoDB -
docs.${DOMAIN} MkDocs -
code.${DOMAIN} Code Server -
listmonk.${DOMAIN} Listmonk -
grafana.${DOMAIN} Grafana -
git.${DOMAIN} Gitea -
n8n.${DOMAIN} n8n -
mail.${DOMAIN} MailHog -
qr.${DOMAIN} Mini QR -
draw.${DOMAIN} Excalidraw -
home.${DOMAIN} Homepage -

Changing the Domain

To change to a new domain:

  1. Update .env:

    DOMAIN=newdomain.com
    
  2. Rebuild nginx and restart admin:

    docker compose build nginx
    docker compose up -d nginx admin
    

    Note: Admin needs to restart to pick up the new DOMAIN for Vite's allowed hosts configuration.

  3. Update Pangolin resources (if using Pangolin tunnel):

    • The Pangolin admin page will automatically show the new domain in the resource list
    • Create Public resources in Pangolin dashboard for each subdomain you need
    • Point each resource to nginx:80 as the target
  4. Check nginx logs:

    docker compose logs nginx --tail 20
    

    You should see: Configuring nginx for domain: newdomain.com

Pangolin Resource Creation

For each subdomain you want accessible through Pangolin:

  1. Go to Pangolin dashboard → Resources → Create Resource
  2. Resource Type: Public Site
  3. URL: https://subdomain.yourdomain.org
  4. Target: nginx (or the Newt connection ID)
  5. Protocol: http
  6. Backend: nginx:80

Repeat for all required subdomains (app, api, db, etc.)

Troubleshooting

Duplicate server name warning:

  • Check nginx logs for conflicting server_name directives
  • This usually means a subdomain is defined twice in the templates

502 Bad Gateway:

  • Verify the backend service is running: docker compose ps
  • Check nginx can reach the backend: docker compose exec nginx wget -qO- http://backend:port
  • Review nginx error logs: docker compose logs nginx

Domain not updating:

  • Ensure you rebuilt nginx: docker compose build nginx
  • Verify the DOMAIN env var is set: docker compose config | grep DOMAIN
  • Check generated configs: docker compose exec nginx cat /etc/nginx/conf.d/services.conf | grep server_name

Technical Details

Template Syntax:

server_name app.${DOMAIN};

Generated Output (with DOMAIN=betteredmonton.org):

server_name app.betteredmonton.org;

Entrypoint Script (nginx/entrypoint.sh):

#!/bin/sh
export DOMAIN=${DOMAIN:-cmlite.org}
envsubst '${DOMAIN}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf
envsubst '${DOMAIN}' < /etc/nginx/conf.d/api.conf.template > /etc/nginx/conf.d/api.conf
envsubst '${DOMAIN}' < /etc/nginx/conf.d/services.conf.template > /etc/nginx/conf.d/services.conf
nginx -t
exec /docker-entrypoint.sh "$@"

Files Modified

  • nginx/Dockerfile — Added gettext package, entrypoint script
  • nginx/entrypoint.sh — New file: templates configs with envsubst
  • nginx/conf.d/*.template — Template versions of all nginx configs
  • docker-compose.yml — Added DOMAIN environment variable to nginx and admin services
  • docker-compose.yml — Removed read-only conf.d volume mount (configs generated at runtime)
  • docker-compose.yml — Updated healthcheck (removed crond check)
  • admin/vite.config.ts — Dynamic allowed hosts based on DOMAIN env var

Benefits

  1. Single Source of Truth: Change domain in one place (.env)
  2. No Manual Edits: No need to edit nginx configs or Vite config files
  3. Environment-Specific: Use different domains for dev/staging/production
  4. Pangolin Integration: Resource list automatically uses current domain
  5. Version Control Friendly: Templates are committed, generated configs are not
  6. Vite Host Check: Automatically allows the configured domain in Vite's dev server

Vite Configuration

The admin Vite dev server now dynamically configures allowed hosts based on the DOMAIN environment variable:

// admin/vite.config.ts
const domain = process.env.DOMAIN || 'cmlite.org';

export default defineConfig({
  server: {
    allowedHosts: [
      `.${domain}`, // Allow all subdomains
      'changemaker-v2-admin', // Container hostname
      'localhost',
      '127.0.0.1',
    ],
  },
});

This prevents Vite's host check from blocking requests when accessing the app through:

  • Pangolin tunnel with custom domain
  • Cloudflare tunnel
  • Any reverse proxy with custom domain
  • Docker container networking