# 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_PATH` or 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 ```caddy 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: ```bash 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): ```bash 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 1. Stop old containers: `docker compose down` 2. Tar volumes: `tar czf n8n-data.tar.gz -C /var/lib/docker/volumes n8n_postgres_data n8n_n8n_data` 3. SCP to new server 4. Extract, create volumes, restore data 5. Fix permissions on `n8n_data` volume 6. Update `.env` with new `N8N_HOST` and `N8N_PROTOCOL=http` 7. `docker compose up -d`