feat: add recommended Caddyfile and update usage guide for production configuration

This commit is contained in:
S
2026-03-02 22:06:27 -06:00
parent 3c86890983
commit 96214654d0
5 changed files with 168 additions and 12 deletions

View File

@@ -3,6 +3,7 @@
## Pre-cutover ## Pre-cutover
- [ ] `nginx -T` snapshot captured (`output/nginx-full.conf`) - [ ] `nginx -T` snapshot captured (`output/nginx-full.conf`)
- [ ] Generated Caddyfile reviewed - [ ] Generated Caddyfile reviewed
- [ ] `Caddyfile.recommended` reviewed/adapted for your domains
- [ ] `conversion-warnings.txt` reviewed and resolved for canary site - [ ] `conversion-warnings.txt` reviewed and resolved for canary site
- [ ] `validate_caddy.sh` passes - [ ] `validate_caddy.sh` passes
- [ ] DNS TTL lowered for canary domain - [ ] DNS TTL lowered for canary domain

View File

@@ -0,0 +1,130 @@
# Recommended Caddy baseline for the current homelab reverse-proxy estate.
# Source upstreams were derived from setup/nginx-to-caddy/oldconfig/*.conf.
#
# If your public suffix changes (for example sintheus.com -> privacyindesign.com),
# update the hostnames below before deployment.
{
# DNS-01 certificates through Cloudflare.
# Requires CF_API_TOKEN in Caddy runtime environment.
acme_dns cloudflare {env.CF_API_TOKEN}
# Trust private-range proxy hops in LAN environments.
servers {
trusted_proxies static private_ranges
protocols h1 h2 h3
}
}
(common_security) {
encode zstd gzip
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
}
(proxy_headers) {
# Keep Nginx parity for backends that consume Host and X-Real-IP.
header_up Host {host}
header_up X-Real-IP {remote_host}
}
(proxy_streaming) {
import proxy_headers
# Flush immediately for streaming/log-tail/websocket-heavy UIs.
flush_interval -1
}
ai.sintheus.com {
import common_security
request_body {
max_size 50MB
}
reverse_proxy http://192.168.1.82:8181 {
import proxy_streaming
}
}
photos.sintheus.com {
import common_security
request_body {
max_size 50GB
}
reverse_proxy http://192.168.1.222:2283 {
import proxy_headers
}
}
fin.sintheus.com {
import common_security
reverse_proxy http://192.168.1.233:8096 {
import proxy_streaming
}
}
disk.sintheus.com {
import common_security
request_body {
max_size 20GB
}
reverse_proxy http://192.168.1.52:80 {
import proxy_headers
}
}
pi.sintheus.com {
import common_security
reverse_proxy http://192.168.1.4:80 {
import proxy_headers
}
}
plex.sintheus.com {
import common_security
reverse_proxy http://192.168.1.111:32400 {
import proxy_streaming
}
}
sync.sintheus.com {
import common_security
reverse_proxy http://192.168.1.119:8384 {
import proxy_headers
}
}
syno.sintheus.com {
import common_security
reverse_proxy https://100.108.182.16:5001 {
import proxy_headers
transport http {
tls_insecure_skip_verify
}
}
}
tower.sintheus.com {
import common_security
reverse_proxy https://192.168.1.82:443 {
import proxy_headers
transport http {
tls_insecure_skip_verify
}
}
}

View File

@@ -13,6 +13,8 @@ This module is intentionally conservative:
- SSH into a host and collect `nginx -T`, `/etc/nginx` tarball, and a quick inventory summary. - SSH into a host and collect `nginx -T`, `/etc/nginx` tarball, and a quick inventory summary.
- `nginx_to_caddy.sh` - `nginx_to_caddy.sh`
- Convert basic Nginx server blocks into a generated Caddyfile. - Convert basic Nginx server blocks into a generated Caddyfile.
- `Caddyfile.recommended`
- Hardened baseline config (security headers, sensible body limits, streaming behavior).
- `validate_caddy.sh` - `validate_caddy.sh`
- Run `caddy fmt`, `caddy adapt`, and `caddy validate` on the generated Caddyfile. - Run `caddy fmt`, `caddy adapt`, and `caddy validate` on the generated Caddyfile.
@@ -24,6 +26,7 @@ cd setup/nginx-to-caddy
./extract_nginx_inventory.sh --host=<host> --user=<user> --port=22 --yes ./extract_nginx_inventory.sh --host=<host> --user=<user> --port=22 --yes
./nginx_to_caddy.sh --input=./output/nginx-full.conf --output=./output/Caddyfile.generated --tls-mode=cloudflare --yes ./nginx_to_caddy.sh --input=./output/nginx-full.conf --output=./output/Caddyfile.generated --tls-mode=cloudflare --yes
./validate_caddy.sh --config=./output/Caddyfile.generated --docker ./validate_caddy.sh --config=./output/Caddyfile.generated --docker
./validate_caddy.sh --config=./Caddyfile.recommended --docker
``` ```
## Conversion Scope ## Conversion Scope

View File

@@ -51,7 +51,23 @@ If local `caddy` is installed:
./validate_caddy.sh --config=./output/Caddyfile.generated ./validate_caddy.sh --config=./output/Caddyfile.generated
``` ```
## 4) Canary migration (recommended) ## 4) Use the recommended baseline
This toolkit now includes a hardened baseline at:
- `setup/nginx-to-caddy/Caddyfile.recommended`
Use it when you want a production-style config instead of a raw 1:1 conversion.
You can either:
1. use it directly (if hostnames/upstreams already match your environment), or
2. copy its common snippets and service patterns into your live Caddyfile.
Validate it before deployment:
```bash
./validate_caddy.sh --config=./Caddyfile.recommended --docker
```
## 5) Canary migration (recommended)
Migrate one low-risk subdomain first: Migrate one low-risk subdomain first:
1. Copy only one site block from generated Caddyfile to your live Caddy config. 1. Copy only one site block from generated Caddyfile to your live Caddy config.
@@ -62,7 +78,7 @@ Migrate one low-risk subdomain first:
- API/websocket calls work - API/websocket calls work
4. Keep Nginx serving all other subdomains. 4. Keep Nginx serving all other subdomains.
## 5) Full migration after canary success ## 6) Full migration after canary success
When the canary is stable: When the canary is stable:
1. Add remaining site blocks. 1. Add remaining site blocks.
@@ -70,14 +86,14 @@ When the canary is stable:
3. Keep Nginx config snapshots for rollback. 3. Keep Nginx config snapshots for rollback.
4. Decommission Nginx only after monitoring period. 4. Decommission Nginx only after monitoring period.
## 6) Rollback plan ## 7) Rollback plan
If a site fails after cutover: If a site fails after cutover:
1. Repoint affected DNS entry back to Nginx endpoint. 1. Repoint affected DNS entry back to Nginx endpoint.
2. Restore previous Nginx server block. 2. Restore previous Nginx server block.
3. Investigate conversion warnings for that block. 3. Investigate conversion warnings for that block.
## 7) Domain/TLS note for your current setup ## 8) Domain/TLS note for your current setup
You confirmed the domain is `privacyindesign.com`. You confirmed the domain is `privacyindesign.com`.
@@ -86,7 +102,7 @@ If you use `TLS_MODE=cloudflare` with Caddy, ensure:
- Cloudflare token has DNS edit on the same zone. - Cloudflare token has DNS edit on the same zone.
- DNS records point to the Caddy ingress path you intend (direct or via edge proxy). - DNS records point to the Caddy ingress path you intend (direct or via edge proxy).
## 8) Suggested next step for Phase 8 ## 9) Suggested next step for Phase 8
Given your current repo config: Given your current repo config:
- keep Phase 8 Caddy focused on `source.privacyindesign.com` - keep Phase 8 Caddy focused on `source.privacyindesign.com`

View File

@@ -49,35 +49,41 @@ fi
CONFIG_FILE="$(cd "$(dirname "$CONFIG_FILE")" && pwd)/$(basename "$CONFIG_FILE")" CONFIG_FILE="$(cd "$(dirname "$CONFIG_FILE")" && pwd)/$(basename "$CONFIG_FILE")"
docker_env_args=()
if [[ "$USE_DOCKER" == "true" ]]; then if [[ "$USE_DOCKER" == "true" ]]; then
require_cmd docker require_cmd docker
docker_env_args=()
if [[ -n "${CF_API_TOKEN:-}" ]]; then if [[ -n "${CF_API_TOKEN:-}" ]]; then
docker_env_args+=( -e "CF_API_TOKEN=${CF_API_TOKEN}" ) docker_env_args+=( -e "CF_API_TOKEN=${CF_API_TOKEN}" )
elif [[ -n "${CLOUDFLARE_API_TOKEN:-}" ]]; then elif [[ -n "${CLOUDFLARE_API_TOKEN:-}" ]]; then
docker_env_args+=( -e "CF_API_TOKEN=${CLOUDFLARE_API_TOKEN}" ) docker_env_args+=( -e "CF_API_TOKEN=${CLOUDFLARE_API_TOKEN}" )
fi fi
run_docker_caddy() {
if [[ "${#docker_env_args[@]}" -gt 0 ]]; then
docker run --rm "${docker_env_args[@]}" "$@"
else
docker run --rm "$@"
fi
}
if [[ "$FORMAT_FILE" == "true" ]]; then if [[ "$FORMAT_FILE" == "true" ]]; then
log_info "Formatting Caddyfile with Docker..." log_info "Formatting Caddyfile with Docker..."
docker run --rm \ run_docker_caddy \
"${docker_env_args[@]}" \
-v "$CONFIG_FILE:/etc/caddy/Caddyfile" \ -v "$CONFIG_FILE:/etc/caddy/Caddyfile" \
"$CADDY_IMAGE" caddy fmt --overwrite /etc/caddy/Caddyfile "$CADDY_IMAGE" caddy fmt --overwrite /etc/caddy/Caddyfile
fi fi
if [[ "$DO_ADAPT" == "true" ]]; then if [[ "$DO_ADAPT" == "true" ]]; then
log_info "Adapting Caddyfile (Docker)..." log_info "Adapting Caddyfile (Docker)..."
docker run --rm \ run_docker_caddy \
"${docker_env_args[@]}" \
-v "$CONFIG_FILE:/etc/caddy/Caddyfile:ro" \ -v "$CONFIG_FILE:/etc/caddy/Caddyfile:ro" \
"$CADDY_IMAGE" caddy adapt --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null "$CADDY_IMAGE" caddy adapt --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null
fi fi
if [[ "$DO_VALIDATE" == "true" ]]; then if [[ "$DO_VALIDATE" == "true" ]]; then
log_info "Validating Caddyfile (Docker)..." log_info "Validating Caddyfile (Docker)..."
docker run --rm \ run_docker_caddy \
"${docker_env_args[@]}" \
-v "$CONFIG_FILE:/etc/caddy/Caddyfile:ro" \ -v "$CONFIG_FILE:/etc/caddy/Caddyfile:ro" \
"$CADDY_IMAGE" caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile "$CADDY_IMAGE" caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile
fi fi