Belajar FrankenPHP - TLS/HTTPS Otomatis & Localhost
Episode 10 of 25

Belajar FrankenPHP - TLS/HTTPS Otomatis & Localhost

Memanfaatkan automatic HTTPS FrankenPHP: sertifikat Let's Encrypt untuk domain produksi tanpa intervensi manual, sertifikat internal untuk localhost, directive tls, variabel SERVER_NAME, dan cara menangani kasus khusus https://127.0.0.1 di Docker.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah episode 9 membahas reverse proxy, episode ini menyentuh fitur yang membuat FrankenPHP (dan Caddy) begitu berbeda dari tumpukan web server tradisional: HTTPS yang bekerja sendiri. Tidak ada lagi certbot, tidak ada lagi cron renewal, tidak ada lagi lupa memperbarui sertifikat yang berakhir tengah malam. FrankenPHP mengambil, memperbarui, dan memperpanjang sertifikat secara otomatis.

Mengapa penting? HTTPS adalah syarat mutlak di 2026 — browser menandai situs HTTP sebagai tidak aman, dan HTTP/2/3 tidak berjalan tanpa TLS. Kemampuan ini menghapus salah satu bagian paling menyakitkan dari operasional web server, dan memahaminya akan mencegah kalian dari kebingungan "kenapa sertifikat lokal tidak dipercaya".

Bagaimana Automatic HTTPS Bekerja

Caddy punya modul ACME bawaan (Automatic Certificate Management Environment). Alurnya:

  1. Kalian menulis hostname domain di site block, misal api.kaliansite.com.
  2. Saat frankenphp run pertama kali, Caddy meminta sertifikat dari Let's Encrypt untuk domain itu.
  3. Let's Encrypt memverifikasi kepemilikan domain (HTTP-01 atau DNS-01).
  4. Sertifikat disimpan dan digunakan; Caddy memperbaruinya otomatis ~30 hari sebelum kedaluwarsa.

Karena port 80 dan 443 harus bisa diakses dari internet untuk verifikasi, pastikan firewall membukanya dan DNS mengarah ke IP server.

Contoh: dengan Caddyfile berikut dan DNS yang sudah benar, HTTPS produksi jalan tanpa satu pun perintah manual:

Caddyfile - HTTPS otomatis produksi
api.kaliansite.com {
    reverse_proxy 127.0.0.1:8081
}

Cukup itu. Buka https://api.kaliansite.com — sertifikat valid, renewal otomatis, dan HTTP/2/3 aktif.

Sertifikat Internal untuk Localhost

Tanpa domain, FrankenPHP menerbitkan sertifikat internal untuk localhost secara otomatis. Ini berlaku untuk development: https://localhost langsung bekerja tanpa konfigurasi TLS apa pun. Browser akan menampilkan peringatan karena CA-nya tidak dipercaya — klik "Advance" dan lanjutkan, atau tambahkan CA lokal FrankenPHP ke trust store sistem.

Caddyfile - localhost dengan HTTPS
localhost {
    root * public/
    php_server
}

Jalankan frankenphp run lalu buka https://localhost. Caddyfile di atas menghasilkan sertifikat untuk localhost tanpa kalian menulis directive tls sama sekali.

Warning

Gunakan https://localhost, bukan https://127.0.0.1. FrankenPHP menerbitkan sertifikat untuk hostname localhost secara default — mengakses lewat 127.0.0.1 akan memicu error TLS "certificate is valid for localhost, not 127.0.0.1". Untuk memakai IP, kalian harus menambahkannya ke server name.

Directive tls

Directive tls memberi kontrol manual ketika default otomatis tidak cukup:

Caddyfile - tls internal (tanpa Let's Encrypt)
localhost {
    tls internal
 
    root * public/
    php_server
}

tls internal memaksa sertifikat lokal alih-alih mencoba Let's Encrypt — berguna di development tanpa internet. Pilihan lainnya:

Caddyfile - tls dengan file sertifikat
example.com {
    tls /etc/ssl/example.crt /etc/ssl/example.key
 
    root * public/
    php_server
}

Mode manual ini untuk sertifikat dari CA eksternal (misal company CA internal atau sertifikat wildcard).

Mengendalikan Hostname via SERVER_NAME

Untuk image Docker, hostname diambil dari env var SERVER_NAME — ini cara paling umum mengganti domain di image yang sama:

Set domain via env var
docker run \
  -e SERVER_NAME="api.kaliansite.com" \
  -p 80:80 -p 443:443 -p 443:443/udp \
  dunglas/frankenphp

Untuk development tanpa HTTPS, matikan automatic HTTPS dengan SERVER_NAME=:80:

Nonaktifkan HTTPS di dev
docker run \
  -e SERVER_NAME=":80" \
  -p 80:80 \
  dunglas/frankenphp

Nilai SERVER_NAME juga bisa berupa daftar hostname yang dipisahkan koma — semua akan mendapatkan sertifikat.

Kasus Khusus: https://127.0.0.1 dengan Docker

Kadang kalian membutuhkan akses via 127.0.0.1 (misal untuk menguji API di localhost dari host). Dua solusi dari dokumentasi resmi:

Solusi 1 — Host networking (Linux):

Docker dengan host networking
docker run \
  -e SERVER_NAME="127.0.0.1" \
  -v $PWD:/app/public \
  --network host \
  dunglas/frankenphp

Solusi 2 — Masukkan IP container ke server name:

Docker - perkirakan IP container
docker run \
  -e SERVER_NAME="127.0.0.1, 172.17.0.3" \
  -v $PWD:/app/public \
  -p 80:80 -p 443:443 -p 443:443/udp \
  dunglas/frankenphp

Kedua pendekatan menambahkan 127.0.0.1 sebagai subject sertifikat sehingga TLS tidak lagi ditolak. Host networking tidak didukung di macOS/Windows — di platform itu gunakan Solusi 2 (cek docker network inspect bridge untuk menemukan IP container).

HTTP ke HTTPS Redirect

Caddy melakukan redirect HTTP ke HTTPS secara otomatis selama automatic HTTPS aktif. Ini termasuk default:

  • Browser membuka http://domain → dijawab 308 → diarahkan ke https://domain.

Untuk memastikan redirect tetap berjalan saat HTTPS dimatikan di development, jangan aktifkan SERVER_NAME=:80 di produksi.

Common Pitfalls

  • Domain tanpa DNS: Let's Encrypt gagal verifikasi karena tidak ada record A/AAAA ke server. Perbaiki DNS dulu.
  • Port 80 diblokir: verifikasi ACME HTTP-01 membutuhkan port 80 terbuka ke internet.
  • Sertifikat expired di container: volume caddy_data harus persisten (Docker named volume) — jika hilang, sertifikat diperoleh ulang, dan renewal tidak mungkin terjadi.
  • Server name tanpa domain: hostname tak dikenal akan dianggap localhost dan memakai sertifikat internal — periksa kembali SERVER_NAME.

Penutup

Pada episode 10 ini, kalian telah menguasai TLS/HTTPS otomatis FrankenPHP.

Inti yang harus dibawa pulang:

  • Let's Encrypt otomatis untuk domain produksi — tanpa certbot, tanpa renewal manual.
  • Sertifikat internal untuk localhost — HTTPS development gratis.
  • Directive tls internal / tls <crt> <key> untuk kontrol manual.
  • SERVER_NAME mengendalikan hostname (terutama di Docker).
  • Selalu https://localhost, dan simpan volume caddy_data agar sertifikat awet.

Di episode 11 selanjutnya kita membahas manajemen konfigurasi lintas environment: environment variables, Caddy env substitution, dan format config Caddyfile vs JSON — agar satu aplikasi bisa berjalan di development, staging, dan produksi. Sampai jumpa di episode 11!

Belajar FrankenPHP - TLS/HTTPS Otomatis & Localhost | Belajar FrankenPHP