2.7 KiB
Caddy Subdomain Routing Pattern
When to Use Subdomains vs Path-Based Routing
Subdomains (n8n.itpropartner.com) are preferred when:
- The backend app uses absolute asset paths (
/assets/foo.js,/static/bar.css) - The app has its own SPA router that doesn't support base-path rewriting
- You need WebSocket support for real-time features
- The app redirects internally (signin flows, OAuth callbacks)
Path-based (app1.itpropartner.com/n8n/) only works when:
- The app supports
BASE_PATHor equivalent configuration - All internal asset references are relative or use the base path
- You've verified the SPA router handles the sub-path correctly
Subdomain Caddyfile Pattern
n8n.itpropartner.com {
reverse_proxy 127.0.0.1:5678 {
flush_interval -1
}
}
flush_interval -1 enables WebSocket support — required for n8n's real-time editor.
Let's Encrypt Pitfalls
Rate Limit: Too Many Failed Authorizations
If DNS isn't pointing to the server when cert issuance is attempted, failed validations count against a 5-per-hour-per-domain rate limit. After 5 failures, Let's Encrypt blocks further attempts for 1 hour.
Fix: Ensure DNS A record resolves to the correct IP BEFORE adding the domain to Caddyfile. Caddy auto-requests certs on config load.
Staging vs Production Certs
Caddy tries staging first, then production. A staging cert issuance success does NOT mean the production cert will work — they have separate rate limits.
Retry After Rate Limit
Caddy auto-retries when the limit resets. Check with:
journalctl -u caddy --no-pager -n 20 | grep -E "cert|rateLimit|will retry"
n8n-Specific Configuration
Docker Volume Permissions
When migrating n8n Docker volumes between servers, the n8n_data volume must be owned by UID 1000 (the node user inside the container):
chown -R 1000:1000 /var/lib/docker/volumes/n8n_n8n_data/_data
Failure to do this causes EACCES: permission denied, open '/home/node/.n8n/crash.journal'.
N8N_PROTOCOL Behind Reverse Proxy
Set N8N_PROTOCOL=http when behind Caddy — Caddy handles SSL termination. Setting it to https inside forces n8n to do its own SSL redirects, creating redirect loops.
N8N_HOST
Must match the public domain — n8n.itpropartner.com. n8n uses this for OAuth callbacks and webhook URLs.
Migration Steps
- Stop old containers:
docker compose down - Tar volumes:
tar czf n8n-data.tar.gz -C /var/lib/docker/volumes n8n_postgres_data n8n_n8n_data - SCP to new server
- Extract, create volumes, restore data
- Fix permissions on
n8n_datavolume - Update
.envwith newN8N_HOSTandN8N_PROTOCOL=http docker compose up -d