Debug Konfigurasi

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 debug di 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 adapt mengkonversi 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.

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact