177 lines
5.8 KiB
Markdown
177 lines
5.8 KiB
Markdown
# 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
|
|
```bash
|
|
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`:
|
|
```yaml
|
|
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`**:
|
|
```bash
|
|
DOMAIN=newdomain.com
|
|
```
|
|
|
|
2. **Rebuild nginx and restart admin**:
|
|
```bash
|
|
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**:
|
|
```bash
|
|
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**:
|
|
```nginx
|
|
server_name app.${DOMAIN};
|
|
```
|
|
|
|
**Generated Output** (with `DOMAIN=betteredmonton.org`):
|
|
```nginx
|
|
server_name app.betteredmonton.org;
|
|
```
|
|
|
|
**Entrypoint Script** (`nginx/entrypoint.sh`):
|
|
```bash
|
|
#!/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:
|
|
|
|
```typescript
|
|
// 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
|