Debug Konfigurasi #
Debugging konfigurasi Caddy yang bermasalah bisa terasa membingungkan jika kamu tidak tahu di mana harus mencari. Artikel ini memberikan panduan sistematis untuk men-debug berbagai jenis masalah — dari routing yang tidak bekerja, headers yang tidak muncul, hingga TLS yang gagal.
Prinsip Debugging #
Workflow debugging yang efektif:
1. REPRODUCE
→ Konfirmasi masalah secara konsisten
→ Catat kondisi persis saat error terjadi
2. ISOLATE
→ Cari di mana masalah terjadi (Caddy? Backend? DNS?)
→ Sederhanakan konfigurasi hingga minimal yang reproduce masalah
3. ANALYZE
→ Baca log dengan teliti
→ Cek konfigurasi aktif via Admin API
→ Test setiap komponen secara terpisah
4. FIX
→ Terapkan perbaikan
→ Validate sebelum deploy
→ Test setelah deploy
Debug Mode #
Debug mode adalah langkah pertama yang paling berguna:
{
# Aktifkan debug mode global
# PERHATIAN: sangat verbose, jangan tinggalkan di production!
debug
}
example.com {
reverse_proxy localhost:3000
}
# Atau aktifkan via Admin API tanpa restart
curl -X PUT http://localhost:2019/config/logging/logs/default/level \
-H "Content-Type: application/json" \
-d '"debug"'
# Lihat log debug real-time
sudo journalctl -u caddy -f | grep -i debug
# Kembalikan ke INFO setelah selesai debugging
curl -X PUT http://localhost:2019/config/logging/logs/default/level \
-H "Content-Type: application/json" \
-d '"info"'
Membaca Konfigurasi Aktif #
Salah satu fitur terbaik Caddy: kamu bisa melihat konfigurasi yang sedang aktif kapan saja:
# Lihat seluruh konfigurasi aktif
curl -s http://localhost:2019/config/ | jq .
# Lihat hanya server HTTP
curl -s http://localhost:2019/config/apps/http/servers/ | jq 'keys'
# Lihat routes yang aktif
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/ | \
jq '[.[] | {id: .["@id"], match: .match[0].host, handlers: [.handle[].handler]}]'
# Bandingkan dengan Caddyfile yang diharapkan
caddy adapt --config /etc/caddy/Caddyfile | jq . > /tmp/expected.json
curl -s http://localhost:2019/config/ | jq . > /tmp/actual.json
diff /tmp/expected.json /tmp/actual.json
Debugging Routing #
Masalah routing adalah salah satu yang paling sering: request tidak diarahkan ke handler yang benar.
# Teknik: tambahkan header debug untuk melihat matcher mana yang aktif
example.com {
@matcher1 path /api/*
@matcher2 path /static/*
@matcher3 host admin.example.com
# Tambah header debug sementara
handle @matcher1 {
header X-Debug-Route "api-route"
reverse_proxy api:8080
}
handle @matcher2 {
header X-Debug-Route "static-route"
file_server { root /var/www/html }
}
handle @matcher3 {
header X-Debug-Route "admin-route"
reverse_proxy admin:9000
}
handle {
header X-Debug-Route "default-route"
respond "No route matched" 404
}
}
# Test routing
curl -I https://example.com/api/users | grep X-Debug-Route
# X-Debug-Route: api-route ✓
curl -I https://example.com/unknown | grep X-Debug-Route
# X-Debug-Route: default-route
curl -I -H "Host: admin.example.com" https://example.com/ | grep X-Debug-Route
# X-Debug-Route: admin-route ✓
Debugging Placeholder #
Placeholder Caddy memungkinkan kamu menggunakan nilai dinamis. Debugging placeholder yang tidak bekerja:
example.com {
# Inject nilai placeholder sebagai header untuk debug
header X-Debug-Remote-IP "{remote_host}"
header X-Debug-Host "{host}"
header X-Debug-URI "{uri}"
header X-Debug-Method "{method}"
header X-Debug-Scheme "{scheme}"
header X-Debug-Request-UUID "{http.request.uuid}"
reverse_proxy localhost:3000
}
# Cek nilai placeholder
curl -I https://example.com/api/test?foo=bar | grep X-Debug
# X-Debug-Remote-IP: 203.0.113.1
# X-Debug-Host: example.com
# X-Debug-URI: /api/test?foo=bar
# X-Debug-Method: GET
# X-Debug-Scheme: https
# X-Debug-Request-UUID: abc123...
Debugging TLS #
# Cek detail sertifikat yang digunakan
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null | \
openssl x509 -noout -text | grep -E "Subject:|DNS:|Not After"
# Cek cipher suite yang digunakan
openssl s_client -connect example.com:443 -brief 2>/dev/null | head -5
# Cek apakah TLS 1.3 digunakan
curl -v --tlsv1.3 https://example.com 2>&1 | grep "SSL connection"
# Cek HSTS header
curl -I https://example.com | grep -i strict-transport
# Test dengan ssllabs (via curl)
# Atau buka https://www.ssllabs.com/ssltest/ di browser
# Cek info CA yang digunakan Caddy untuk sertifikat
curl -s http://localhost:2019/pki/ca/local | jq '{name: .name, root_expires: .root.not_after}'
# Debug TLS handshake failure
# Aktifkan debug mode dan filter TLS logs
sudo journalctl -u caddy -f 2>/dev/null | grep -i "tls\|handshake\|certificate"
Debugging Reverse Proxy #
# Cek status upstream via Admin API
curl -s http://localhost:2019/reverse_proxy/upstreams/ | \
jq -r '.[] | "\(.address): \(if .healthy then "HEALTHY" else "UNHEALTHY" end) (fails: \(.fails))"'
# Test koneksi ke upstream secara langsung
curl -v http://localhost:3000/health
curl -v http://backend-server:3000/health
# Cek latency ke backend
time curl -s http://localhost:3000/heavy-endpoint > /dev/null
# Bandingkan: latency via Caddy vs langsung ke backend
time curl -s https://example.com/heavy-endpoint > /dev/null
# Perbedaan besar = overhead Caddy (biasanya sangat kecil, < 1ms)
Debugging Header Issues #
# Cek SEMUA header yang diterima client dari Caddy
curl -sv https://example.com 2>&1 | grep "^<"
# Cek header yang dikirim Caddy ke backend
# Gunakan requestbin atau httpbin sebagai backend sementara
curl -X POST https://example.com/debug \
-H "X-Custom: test" \
-H "Authorization: Bearer token123"
# Dan cek di backend apa yang diterima:
# (di backend Node.js: console.log(req.headers))
Debugging dengan caddy adapt
#
# Konversi Caddyfile ke JSON untuk melihat konfigurasi yang dihasilkan
caddy adapt --config /etc/caddy/Caddyfile | jq .
# Cek apakah directive di-parse dengan benar
caddy adapt --config /etc/caddy/Caddyfile | \
jq '.apps.http.servers.srv0.routes[] | select(.match[0].host[]? == "example.com")'
# Debug matcher
caddy adapt --config /etc/caddy/Caddyfile | \
jq '.apps.http.servers.srv0.routes[].match'
Workflow Debug Sistematis #
#!/bin/bash
# caddy-debug.sh — Kumpulkan info debug dalam satu script
echo "=== Caddy Debug Report ==="
echo "Time: $(date)"
echo ""
echo "--- Caddy Version ---"
caddy version
echo ""
echo "--- Service Status ---"
systemctl is-active caddy
echo ""
echo "--- Ports Listening ---"
ss -tlnp | grep caddy
echo ""
echo "--- Admin API ---"
curl -s http://localhost:2019/config/apps/http/servers/ | jq 'keys' 2>/dev/null || echo "Admin API not reachable"
echo ""
echo "--- Upstream Health ---"
curl -s http://localhost:2019/reverse_proxy/upstreams/ | \
jq -r '.[] | "\(.address): \(if .healthy then "UP" else "DOWN" end)"' 2>/dev/null || echo "No upstreams configured"
echo ""
echo "--- Recent Errors (last 50 lines) ---"
journalctl -u caddy -n 50 --no-pager | grep -E "error|warn|fail" | tail -20
echo ""
echo "--- TLS Certificates ---"
curl -s http://localhost:2019/pki/ca/local | jq '{name: .name}' 2>/dev/null
echo ""
echo "=== End of Debug Report ==="
Ringkasan #
- Aktifkan
debugdi global options untuk melihat semua detail — tapi ingat untuk menonaktifkannya kembali setelah selesai.- Gunakan Admin API (
/config/) untuk melihat konfigurasi yang sedang aktif dan membandingkannya dengan yang diharapkan.- Tambahkan
header X-Debug-*sementara untuk memverifikasi routing, placeholder values, dan header yang masuk — sangat efektif untuk debugging konfigurasi matcher.caddy adaptmengkonversi Caddyfile ke JSON — berguna untuk memahami persis bagaimana Caddy menginterpretasikan konfigurasimu.- Buat script debug yang mengumpulkan semua informasi dalam satu langkah — menghemat waktu saat harus troubleshoot di production.
- Selalu test di staging sebelum deploy ke production — environment yang mirip production bisa menangkap masalah lebih awal.
← Sebelumnya: Error Umum Berikutnya: Caddy Validate →
Membuat Minimal Reproducible Config #
Saat melaporkan bug atau meminta bantuan di forum, buat konfigurasi minimal yang mereproduksi masalah:
# Mulai dengan konfigurasi sangat sederhana
cat > /tmp/test.Caddyfile << 'EOF'
localhost:8080 {
respond "Hello" 200
}
EOF
# Test apakah masalah ada di konfigurasi minimal
./caddy run --config /tmp/test.Caddyfile
# Tambahkan komponen satu per satu sampai masalah muncul
# Ini membantu isolasi akar masalah
Penggunaan respond untuk Debugging
#
Direktif respond sangat berguna untuk isolasi masalah routing:
example.com {
# Ganti reverse_proxy dengan respond untuk test routing
@match1 path /api/*
handle @match1 {
respond "Match: api route" 200
}
@match2 host admin.example.com
handle @match2 {
respond "Match: admin subdomain" 200
}
handle {
respond "Match: default" 200
}
}
# Test setiap route
curl https://example.com/api/users # "Match: api route"
curl https://example.com/other # "Match: default"
curl -H "Host: admin.example.com" https://example.com # "Match: admin subdomain"
Setelah routing terverifikasi benar, ganti respond dengan handler yang sebenarnya.