258 lines
6.5 KiB
Markdown
258 lines
6.5 KiB
Markdown
# NPM to Caddy Migration Plan
|
|
|
|
Step-by-step guide to migrate from Nginx Proxy Manager to Caddy on `10.10.0.16`.
|
|
|
|
## Prerequisites
|
|
|
|
- [ ] Cloudflare API token with `Zone:DNS:Edit` for manticorum.com
|
|
- [ ] SSH access to `pihole` (10.10.0.16) and `ubuntu-manticore` (10.10.0.226)
|
|
- [ ] Docker and docker compose installed on 10.10.0.16
|
|
- [ ] Familiarity with current NPM proxy hosts (see README.md)
|
|
|
|
## Phase 1: Prepare (no downtime, no changes to production)
|
|
|
|
### 1.1 Create Cloudflare API Token
|
|
|
|
1. Go to https://dash.cloudflare.com/profile/api-tokens
|
|
2. Create token with permissions:
|
|
- **Zone - DNS - Edit** (scoped to manticorum.com)
|
|
3. Save the token securely
|
|
|
|
### 1.2 Deploy Caddy Config to Host
|
|
|
|
```bash
|
|
# From workstation
|
|
scp -r server-configs/caddy-migration/ pihole:/home/cal/caddy/
|
|
ssh pihole "cp /home/cal/caddy/.env.example /home/cal/caddy/.env"
|
|
```
|
|
|
|
Edit `.env` on the host:
|
|
```bash
|
|
ssh pihole "nano /home/cal/caddy/.env"
|
|
# Set CF_API_TOKEN=<your token>
|
|
```
|
|
|
|
### 1.3 Build and Test Caddy (on alternate ports)
|
|
|
|
Temporarily modify `docker-compose.yml` to use non-conflicting ports:
|
|
```yaml
|
|
ports:
|
|
- "8080:80"
|
|
- "8443:443"
|
|
- "8443:443/udp"
|
|
```
|
|
|
|
```bash
|
|
ssh pihole "cd /home/cal/caddy && docker compose up -d --build"
|
|
```
|
|
|
|
Verify the container starts and the Cloudflare module is loaded:
|
|
```bash
|
|
ssh pihole "docker logs caddy 2>&1 | head -30"
|
|
ssh pihole "docker exec caddy caddy list-modules | grep cloudflare"
|
|
```
|
|
|
|
Verify config is valid:
|
|
```bash
|
|
ssh pihole "docker exec caddy caddy validate --config /etc/caddy/Caddyfile"
|
|
```
|
|
|
|
Test a proxy host directly (bypass DNS):
|
|
```bash
|
|
curl -k --resolve sbadev.manticorum.com:8443:10.10.0.16 https://sbadev.manticorum.com:8443/
|
|
```
|
|
|
|
### 1.4 Verify Cert Issuance
|
|
|
|
Check that Caddy successfully obtains a wildcard cert:
|
|
```bash
|
|
ssh pihole "docker logs caddy 2>&1 | grep -i 'certificate\|tls\|acme'"
|
|
```
|
|
|
|
You should see successful ACME DNS-01 challenge completion.
|
|
|
|
### 1.5 Stop Test Caddy
|
|
|
|
```bash
|
|
ssh pihole "cd /home/cal/caddy && docker compose down"
|
|
```
|
|
|
|
Revert `docker-compose.yml` ports back to 80/443.
|
|
|
|
## Phase 2: Cutover (brief downtime)
|
|
|
|
Expected downtime: **< 2 minutes** (stop NPM, start Caddy, sync DNS).
|
|
|
|
### 2.1 Backup NPM
|
|
|
|
```bash
|
|
ssh pihole "cd ~/nginx-proxy-manager && tar czf ~/npm-backup-$(date +%Y%m%d).tar.gz data/ letsencrypt/"
|
|
```
|
|
|
|
### 2.2 Take a Snapshot
|
|
|
|
If 10.10.0.16 is a VM/LXC on Proxmox, take a snapshot first:
|
|
```bash
|
|
# From proxmox host (adjust VMID)
|
|
pct snapshot <VMID> pre-caddy-migration
|
|
```
|
|
|
|
### 2.3 Stop NPM
|
|
|
|
```bash
|
|
ssh pihole "cd ~/nginx-proxy-manager && docker compose down"
|
|
```
|
|
|
|
Ports 80, 443, and 81 are now free.
|
|
|
|
### 2.4 Start Caddy
|
|
|
|
```bash
|
|
ssh pihole "cd /home/cal/caddy && docker compose up -d"
|
|
```
|
|
|
|
### 2.5 Verify Services
|
|
|
|
Quick smoke test of key services:
|
|
```bash
|
|
# Test from workstation (DNS should already point to 10.10.0.16 via Pi-hole)
|
|
curl -sI https://git.manticorum.com | head -5
|
|
curl -sI https://n8n.manticorum.com | head -5
|
|
curl -sI https://jellyfin.manticorum.com | head -5
|
|
curl -sI https://foundry.manticorum.com | head -5
|
|
curl -sI https://status.manticorum.com | head -5
|
|
|
|
# Test internal-only access
|
|
curl -sI https://radarr.manticorum.com | head -5 # should work from local
|
|
curl -sI https://sonarr.manticorum.com | head -5
|
|
```
|
|
|
|
### 2.6 Update Pi-hole Sync
|
|
|
|
Deploy the new sync script:
|
|
```bash
|
|
ssh pihole "cp /home/cal/caddy/scripts/caddy-pihole-sync.sh /home/cal/scripts/"
|
|
ssh pihole "chmod +x /home/cal/scripts/caddy-pihole-sync.sh"
|
|
```
|
|
|
|
Test dry run:
|
|
```bash
|
|
ssh pihole "/home/cal/scripts/caddy-pihole-sync.sh --dry-run"
|
|
```
|
|
|
|
Run sync:
|
|
```bash
|
|
ssh pihole "/home/cal/scripts/caddy-pihole-sync.sh"
|
|
```
|
|
|
|
Update cron to use the new script:
|
|
```bash
|
|
ssh pihole "crontab -l | sed 's|npm-pihole-sync.sh|caddy-pihole-sync.sh|g' | crontab -"
|
|
```
|
|
|
|
Also update the `CADDYFILE` path variable in the script if the deployment path differs from `/home/cal/caddy/Caddyfile`.
|
|
|
|
## Phase 3: Validate (next 24-48 hours)
|
|
|
|
### 3.1 Monitor Caddy Logs
|
|
|
|
```bash
|
|
ssh pihole "docker logs caddy -f"
|
|
```
|
|
|
|
Look for:
|
|
- Successful TLS handshakes
|
|
- No upstream connection errors
|
|
- Cert renewal events (if timing aligns)
|
|
|
|
### 3.2 Check Uptime Kuma
|
|
|
|
Verify all monitored services at https://status.manticorum.com show UP.
|
|
|
|
### 3.3 Test WebSocket Services
|
|
|
|
These services use WebSockets and should be tested interactively:
|
|
- **Foundry VTT** (foundry.manticorum.com) - open a game session
|
|
- **n8n** (n8n.manticorum.com) - open workflow editor
|
|
- **Memos** (memos.manticorum.com) - create/edit a memo
|
|
- **Termix** (termix.manticorum.com) - open a terminal session
|
|
|
|
### 3.4 Test External Access
|
|
|
|
If any services are accessed via Cloudflare from outside:
|
|
1. From a phone on cellular (not on home WiFi)
|
|
2. Access public services and verify they load
|
|
3. Access internal-only services and verify 403 response
|
|
|
|
### 3.5 Verify Access Restrictions
|
|
|
|
```bash
|
|
# From a machine NOT on 10.0.0.0/23 or 10.10.0.0/24:
|
|
curl -sI https://radarr.manticorum.com # Should return 403
|
|
curl -sI https://sonarr.manticorum.com # Should return 403
|
|
```
|
|
|
|
## Phase 4: Cleanup
|
|
|
|
### 4.1 Remove NPM (after validation period)
|
|
|
|
```bash
|
|
# Keep backup, remove containers and images
|
|
ssh pihole "cd ~/nginx-proxy-manager && docker compose rm -f"
|
|
ssh pihole "docker image rm jc21/nginx-proxy-manager:latest"
|
|
```
|
|
|
|
### 4.2 Update Documentation
|
|
|
|
- Update `server-configs/networking/nginx-proxy-manager-pihole.md` to reference Caddy
|
|
- Update any Uptime Kuma monitors that check port 81 (NPM admin)
|
|
- Update `CONTEXT.md` networking section
|
|
|
|
### 4.3 Free Port 81
|
|
|
|
Port 81 (NPM admin UI) is no longer needed. Caddy's admin API runs on localhost:2019 inside the container by default (not exposed).
|
|
|
|
## Rollback Plan
|
|
|
|
If something goes wrong, rollback takes < 1 minute:
|
|
|
|
```bash
|
|
# Stop Caddy
|
|
ssh pihole "cd /home/cal/caddy && docker compose down"
|
|
|
|
# Restart NPM
|
|
ssh pihole "cd ~/nginx-proxy-manager && docker compose up -d"
|
|
|
|
# Revert cron to old sync script
|
|
ssh pihole "crontab -l | sed 's|caddy-pihole-sync.sh|npm-pihole-sync.sh|g' | crontab -"
|
|
```
|
|
|
|
Or restore from Proxmox snapshot:
|
|
```bash
|
|
pct rollback <VMID> pre-caddy-migration
|
|
```
|
|
|
|
## Adding New Services After Migration
|
|
|
|
Edit the Caddyfile and reload - no web UI needed:
|
|
|
|
```bash
|
|
ssh pihole "nano /home/cal/caddy/Caddyfile"
|
|
|
|
# Add a new block:
|
|
# newservice.manticorum.com {
|
|
# reverse_proxy 10.10.0.xxx:port {
|
|
# import proxy_headers
|
|
# }
|
|
# }
|
|
|
|
# Validate
|
|
ssh pihole "docker exec caddy caddy validate --config /etc/caddy/Caddyfile"
|
|
|
|
# Apply (zero downtime)
|
|
ssh pihole "docker exec caddy caddy reload --config /etc/caddy/Caddyfile"
|
|
|
|
# Sync DNS to Pi-holes
|
|
ssh pihole "/home/cal/scripts/caddy-pihole-sync.sh"
|
|
```
|