Menggunakan FrankenPHP sebagai reverse proxy dan load balancer: meneruskan request ke beberapa backend API atau microservices dengan directive reverse_proxy, konfigurasi health check, policy load balancing round_robin / least_conn / random, retry policy, dan pengaturan trusted_proxies.

Sejauh ini FrankenPHP kita gunakan untuk melayani aplikasi PHP secara langsung. Tetapi di dunia nyata, sebuah domain biasanya juga harus melayani API lain, microservices, atau backend yang bukan PHP. Episode ini membahas kemampuan FrankenPHP (melalui Caddy) sebagai reverse proxy dan load balancer — salah satu alasan mengapa satu binary FrankenPHP bisa menggantikan tumpukan "Nginx + PHP-FPM + API gateway" sekaligus.
Mengapa penting? Arsitektur modern hampir selalu memecah aplikasi: frontend PHP, API service, service upload, dsb. Dengan reverse_proxy, satu entry point FrankenPHP bisa merutekan semua itu, mengeraskan TLS, dan menyeimbangkan beban — tanpa infrastruktur tambahan.
reverse_proxyDirective reverse_proxy meneruskan request ke upstream. Contoh paling sederhana — PHP dilayani FrankenPHP, API di backend terpisah:
localhost {
@api path /api/*
reverse_proxy @api 127.0.0.1:8081
root * public/
php_server
}Semua request /api/* diteruskan ke 127.0.0.1:8081; sisanya ditangani PHP. Response dari backend mengalir balik tanpa modifikasi signifikan.
Ketika satu backend tidak cukup, daftarkan beberapa upstream dalam blok:
localhost {
@api path /api/*
reverse_proxy @api {
to 10.0.0.11:8081
10.0.0.12:8081
10.0.0.13:8081
lb_policy round_robin
}
root * public/
php_server
}| Policy | Perilaku | Cocok untuk |
|---|---|---|
round_robin | Giliran merata ke tiap backend | Backend seragam (default) |
least_conn | Kirim ke backend dengan koneksi paling sedikit | Backend dengan request berat bervariasi |
random | Pilih acak, boleh dengan choose 2 (2 kandidat) | Kecepatan murni |
Contoh least_conn:
reverse_proxy @api {
to 10.0.0.11:8081 10.0.0.12:8081
lb_policy least_conn
}Backend yang mati tidak boleh menerima request. Caddy melakukan health check aktif (active probe) dan pasif (menandai backend bermasalah setelah gagal N request):
reverse_proxy @api {
to 10.0.0.11:8081 10.0.0.12:8081
health_uri /healthz
health_interval 10s
health_timeout 3s
max_fails 3
fail_duration 30s
}health_uri /healthz — Caddy mengecek GET /healthz tiap health_interval.health_interval/health_timeout — frekuensi dan batas waktu probe.max_fails 3 + fail_duration 30s — jika 3 request gagal dalam 30 detik, backend dianggap mati untuk sementara.Tip
Pastikan aplikasi kalian punya endpoint health (/healthz, /livez, /readyz) yang menjawab cepat. Health check yang lambat akan mengubah load balancer menjadi bottleneck.
Ketika upstream pertama gagal, Caddy bisa mencoba upstream berikutnya secara otomatis:
reverse_proxy @api {
to 10.0.0.11:8081 10.0.0.12:8081
lb_retries 2
lb_retry_duration 5s
}lb_retries = jumlah percobaan ke upstream lain; lb_retry_duration = batas waktu total retry. Default Caddy melakukan retry ke upstream berikutnya untuk request idempotent (GET/HEAD) — dengan kedua opsi ini kalian mengontrol kedalaman dan durasinya.
Warning
Jangan retry request yang tidak idempotent (POST yang menulis data) ke backend lain secara membabi buta — request mungkin sudah dieksekusi di backend pertama, lalu dieksekusi lagi di backend kedua (double submit). Pisahkan aturan proxy untuk mutasi dan baca, atau batasi retry.
Proxy sering perlu menambahkan atau menghapus header. Gunakan blok header_up (ke backend) dan header_down (ke klien):
reverse_proxy @api {
to 10.0.0.11:8081
header_up X-Real-IP {remote_host}
header_up Host api.internal.local
header_down Server "" # hapus header Server dari backend
header_down X-Powered-By ""
}Ini berguna untuk menyembunyikan identitas backend dan memberikan informasi yang benar ke log aplikasi.
trusted_proxies: Saat FrankenPHP di Belakang Proxy LainJika FrankenPHP sendiri berada di belakang load balancer cloud (AWS ELB, Google Cloud LB, Nginx), header X-Forwarded-* dari proxy tersebut harus dipercaya — jika tidak, IP klien yang terlihat salah dan deteksi HTTPS bisa gagal:
{
servers {
trusted_proxies static 10.0.0.0/8
}
}Sesuaikan CIDR dengan jangkauan IP proxy kalian. Dan jangan lupa sisi aplikasi: Symfony memakai env TRUSTED_PROXIES, Laravel memakai middleware TrustProxies — dua-duanya harus sinkron agar X-Forwarded-Proto/X-Forwarded-For benar.
trusted_proxies: IP klien selalu tercatat sebagai IP load balancer.Pada episode 9 ini, kalian telah menguasai reverse proxy dan load balancing di FrankenPHP.
Inti yang harus dibawa pulang:
reverse_proxy merutekan request ke upstream — API, microservices, backend lain.round_robin, least_conn, random sesuai karakter beban.health_uri, health_interval) + max_fails menjauhkan backend mati.lb_retries untuk failover; hati-hati dengan request non-idempotent.trusted_proxies wajib saat FrankenPHP berada di belakang proxy cloud.Di episode 10 selanjutnya kita membahas fitur paling ikonik Caddy: TLS/HTTPS otomatis — Let's Encrypt untuk domain produksi, sertifikat internal untuk localhost, directive tls, dan penyelesaian masalah 127.0.0.1 di Docker. Sampai jumpa di episode 10!