Site Address #

Di dalam Caddyfile, setiap blok situs (site block) wajib diawali dengan satu atau beberapa alamat situs yang dikenal sebagai Site Address. Elemen pertama ini bertindak sebagai penjaga gerbang (gatekeeper) — ia mendefinisikan untuk lalu lintas request mana saja blok konfigurasi tersebut akan diterapkan.

Menuliskan site address dengan benar bukan sekadar masalah estetika atau kemudahan penulisan. Di Caddy, format penulisan site address secara langsung memengaruhi perilaku inti server, terutama dalam menentukan apakah Caddy akan mengaktifkan HTTPS otomatis (Automatic HTTPS), menggunakan otoritas sertifikat (CA) publik atau internal, mendengarkan (listen) di port tertentu, atau bahkan mengonfigurasi pengalihan lalu lintas (traffic redirection) secara otomatis. Kesalahan kecil dalam format penulisan di sini dapat menyebabkan server gagal mendapatkan sertifikat SSL, atau request dari pengguna salah diarahkan ke situs lain.


Matriks Keputusan HTTPS Otomatis #

Caddy terkenal dengan fitur Automatic HTTPS yang diaktifkan secara bawaan. Namun, tidak semua alamat situs yang kita tulis di Caddyfile akan memicu fitur ini.

Untuk membantu kita memahami bagaimana Caddy menentukan status TLS untuk setiap alamat, mari kita perhatikan diagram pohon keputusan (decision tree) di bawah ini:

flowchart TD
    Address{"Mulai: Evaluasi Site Address"} --> IsIP{"Apakah berupa IP Address?"}
    IsIP -- "Ya" --> NoAutoHTTPS["HTTPS Otomatis: TIDAK\n(Hanya HTTP / Perlu TLS Manual)"]
    IsIP -- "Tidak" --> IsLocalhost{"Apakah domain 'localhost' atau *.localhost?"}
    IsLocalhost -- "Ya" --> InternalCA["HTTPS Otomatis: YA\n(Menggunakan CA Internal Caddy)"]
    IsLocalhost -- "Tidak" --> HasPort{"Apakah menentukan port secara eksplisit?"}
    HasPort -- "Ya" --> WhichPort{"Port yang ditentukan?"}
    WhichPort -- "80" --> NoAutoHTTPS
    WhichPort -- "Lainnya (443, 8443, dll)" --> AutoHTTPS["HTTPS Otomatis: YA\n(Let's Encrypt / ZeroSSL)"]
    HasPort -- "Tidak" --> HasScheme{"Apakah menggunakan http:// secara eksplisit?"}
    HasScheme -- "Ya" --> NoAutoHTTPS
    HasScheme -- "Tidak" --> IsWildcard{"Apakah berupa Wildcard (*.domain.com)?"}
    IsWildcard -- "Ya" --> AutoHTTPSWildcard["HTTPS Otomatis: YA\n(Let's Encrypt / ZeroSSL)\n*Wajib DNS-01 Challenge"]
    IsWildcard -- "Tidak" --> AutoHTTPS

Untuk melengkapi diagram di atas, berikut adalah tabel referensi cepat format alamat situs beserta status HTTPS otomatisnya:

Format Site AddressHTTPS Otomatis?Jenis CAKeterangan
example.comYAPublikDomain standar. Mendengarkan di port 80 (redirect) & 443 (TLS).
example.com:443YAPublikPort 443 eksplisit. Berperilaku sama seperti tanpa port.
example.com:8443YAPublikPort HTTPS non-standar. Sertifikat otomatis aktif di port tersebut.
http://example.comTIDAK-Skema http:// menonaktifkan TLS secara paksa. Hanya listen di port 80.
example.com:80TIDAK-Menentukan port 80 mematikan HTTPS otomatis. Hanya HTTP.
localhostYAInternalMenggunakan CA lokal Caddy. Browser membutuhkan instalasi root CA Caddy.
app.localhostYAInternalSubdomain localhost juga menggunakan CA internal secara otomatis.
192.168.1.100TIDAK-IP Address lokal/publik. Tidak dapat divalidasi oleh ACME publik tanpa nama domain.
127.0.0.1YAInternalIP loopback khusus. Caddy akan membuat sertifikat self-signed via CA internal.
*.example.comYAPublikDomain wildcard. Memerlukan otentikasi DNS-01 Challenge untuk validasi.
:80TIDAK-Hanya mendengarkan di port 80 untuk semua host (catch-all HTTP).
:443YAInternal/PublikMendengarkan di port 443 untuk semua host. Perlu on-demand TLS atau default certs.

Format Dasar Site Address #

Mari kita ulas secara detail masing-masing format alamat situs di atas beserta implikasinya terhadap server:

1. Nama Domain Saja (Format Paling Umum) #

# Caddy otomatis mengaktifkan HTTPS untuk domain ini
# Caddy akan listen di port 80 (untuk redirect ke HTTPS) dan 443 (HTTPS sesungguhnya)
example.com {
    file_server
}

Ini adalah format standar emas di Caddy. Caddy akan menangani semua urusan SSL/TLS di latar belakang tanpa instruksi tambahan dari kita.

2. Domain dengan Port Eksplisit #

# Mengaktifkan HTTPS pada port kustom 8443
example.com:8443 {
    file_server
}

Skenario ini berguna jika server kita berada di belakang firewall yang membatasi port 443 standar, atau jika kita menjalankan beberapa layanan web server di mesin yang sama dengan port TLS berbeda.

3. IP Address (Alamat IP) #

# Caddy tidak akan mengaktifkan HTTPS otomatis
# Server hanya dapat diakses via HTTP di port 80 (default untuk site block non-TLS)
192.168.1.50 {
    file_server
}

Secara default, otoritas sertifikat publik seperti Let’s Encrypt tidak mengeluarkan sertifikat SSL untuk alamat IP privat (RFC 1918) seperti 192.168.x.x atau 10.x.x.x. Oleh karena itu, Caddy menonaktifkan HTTPS otomatis pada alamat IP untuk mencegah error kegagalan validasi domain yang akan terus-menerus terjadi.

4. Alamat Khusus Localhost #

# Caddy mengaktifkan HTTPS menggunakan CA internal (Local CA)
# Sangat cocok untuk pengembangan lokal (development) yang aman
localhost {
    reverse_proxy localhost:3000
}

Saat kita menggunakan localhost atau domain berakhiran .localhost (misalnya myproject.localhost), Caddy akan bertindak sebagai Otoritas Sertifikat lokalnya sendiri. Caddy akan membuat sertifikat root, menambahkannya ke dalam trust store sistem operasi lokal kita (membutuhkan otorisasi password admin saat pertama kali dijalankan), dan menerbitkan sertifikat SSL yang valid untuk development lokal.


Domain Wildcard #

Domain wildcard digunakan jika kita ingin melayani semua kemungkinan subdomain menggunakan satu blok situs tunggal (misalnya user1.example.com, user2.example.com, dst. diarahkan ke blok yang sama). Format penulisannya menggunakan karakter bintang (*) di posisi subdomain tingkat ketiga:

# Menangani semua subdomain satu tingkat di bawah example.com
*.example.com {
    # PENTING: Wildcard domain membutuhkan DNS-01 Challenge
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    reverse_proxy localhost:8000
}

Mengapa Harus DNS Challenge? #

Secara default, Caddy menggunakan tantangan HTTP-01 untuk memvalidasi kepemilikan domain. Dalam tantangan HTTP-01, Let’s Encrypt akan mengirimkan request ke file verifikasi khusus di port 80 domain tersebut. Namun, Let’s Encrypt tidak dapat memvalidasi domain wildcard (*.example.com) menggunakan metode HTTP-01 karena tidak mungkin membuat file verifikasi di semua subdomain dinamis secara real-time.

Oleh karena itu, jika kita mendefinisikan site address wildcard, kita wajib mengonfigurasi modul TLS DNS Challenge. Caddy akan membuat entri TXT sementara di penyedia DNS kita (seperti Cloudflare, Route 53, atau DigitalOcean) untuk membuktikan kepemilikan domain.

Perlu dicatat juga bahwa wildcard *.example.com hanya cocok dengan subdomain satu tingkat. Alamat tersebut tidak akan cocok dengan domain apex (example.com) atau subdomain bertingkat seperti app.staging.example.com. Jika kita ingin menangani domain apex dan wildcard sekaligus, kita harus menulis keduanya di alamat situs:

# Menangani domain apex dan subdomain sekaligus
example.com
*.example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    reverse_proxy localhost:8000
}

On-Demand TLS (Multi-Tenant) #

Jika kita sedang membangun platform SaaS di mana pelanggan kita dapat mengarahkan domain kustom mereka sendiri (misalnya app.customer1.com, www.customer2.net) ke server kita, kita tidak mungkin menuliskan semua domain tersebut secara manual di Caddyfile.

Caddy menyediakan fitur luar biasa bernama On-Demand TLS. Dengan fitur ini, Caddy akan meminta sertifikat SSL ke Let’s Encrypt secara dinamis pada saat jabat tangan SSL (SSL handshake) pertama kali terjadi untuk domain baru yang belum terdaftar.

# 1. Konfigurasi Global Options untuk On-Demand TLS
{
    on_demand_tls {
        # Endpoint API internal kita untuk memeriksa apakah domain diizinkan menggunakan platform kita
        # Caddy akan mengirimkan request GET dengan parameter query '?domain=customer-domain.com'
        # API kita harus merespons dengan HTTP 200 (diizinkan) atau HTTP 400/403 (ditolak)
        ask http://localhost:5000/api/v1/validate-domain
        
        # Batasi pembuatan sertifikat baru untuk mencegah serangan DDoS
        interval 2m
        burst 5
    }
}

# 2. Blok situs catch-all HTTPS
:443 {
    tls {
        # Aktifkan on-demand untuk blok ini
        on_demand
    }
    
    # Teruskan traffic ke server aplikasi SaaS kita
    reverse_proxy localhost:3000
}

[!CAUTION] Jangan pernah mengaktifkan on_demand tanpa mengonfigurasi endpoint ask! Tanpa endpoint ask, siapa saja dapat mengarahkan domain acak mereka ke IP server Anda, memaksa server Anda meminta sertifikat ke Let’s Encrypt. Hal ini dapat menghabiskan kuota rate limit Let’s Encrypt Anda dalam hitungan menit, memenuhi penyimpanan disk dengan sertifikat sampah, atau bahkan mematikan server Anda karena serangan kehabisan memori.


Path Prefix pada Site Address #

Caddyfile mengizinkan kita menyertakan jalur awal (path prefix) langsung di dalam deklarasi alamat situs untuk membuat pemisahan perutean (routing) tingkat tinggi:

# Blok ini hanya menangani request yang dimulai dengan /api/
example.com/api/* {
    reverse_proxy localhost:8080
}

# Blok ini menangani semua request lainnya ke domain example.com
example.com {
    root * /var/www/html
    file_server
}

Mengapa Path Prefix di Site Address Jarang Digunakan? #

Meskipun fitur ini tersedia, dalam praktik arsitektur web modern, penulisan path prefix di site address sangat tidak direkomendasikan kecuali untuk kebutuhan sederhana. Alasannya adalah:

  1. Kurang Fleksibel: Perutean ini dievaluasi di awal saat inisialisasi server. Kita tidak dapat menggunakan logika bersyarat yang kompleks atau mengubah jalurnya dengan dinamis seperti menggunakan request matcher.
  2. Potensi Kebingungan: Sulit melihat seluruh alur perutean situs jika konfigurasi terbagi menjadi beberapa blok situs yang berbeda untuk domain yang sama.
  3. Alternatif yang Lebih Baik: Penggunaan blok handle atau directive route di dalam satu blok situs tunggal jauh lebih modular dan mudah dikelola.

Binding ke Interface Jaringan Tertentu #

Secara bawaan, jika kita menulis example.com, Caddy akan mendengarkan di semua antarmuka jaringan (network interfaces) yang tersedia di sistem operasi (setara dengan IP 0.0.0.0 untuk IPv4 dan :: untuk IPv6).

Jika server kita memiliki beberapa kartu jaringan (misalnya antarmuka publik dan antarmuka privat/VPN) dan kita ingin situs hanya dapat diakses dari jaringan privat, kita dapat mengikat (bind) alamat situs ke IP privat tersebut:

# Hanya dengarkan request example.com yang masuk melalui interface IP VPN internal 10.8.0.1
10.8.0.1:443, example.com {
    # Konfigurasi internal/admin
    reverse_proxy localhost:9000
}

Untuk skenario HTTP biasa tanpa domain, kita juga dapat mengikat port ke IP lokal:

# Hanya dapat diakses dari mesin localhost itu sendiri
127.0.0.1:8080 {
    respond "Halo dari localhost!"
}

Prioritas Pencocokan Domain (Routing Priority) #

Jika kita memiliki banyak blok situs di Caddyfile, Caddy harus memutuskan blok mana yang paling berhak memproses request HTTP yang masuk. Caddy menggunakan aturan prioritas yang sangat ketat untuk menentukan pemenang kecocokan host (host matching).

Aturan prioritas ini diurutkan dari yang paling spesifik (prioritas tertinggi) hingga yang paling umum (prioritas terendah):

  1. Exact Domain dengan Path Prefix Terpanjang
    • Contoh: api.example.com/v1/users
  2. Exact Domain Tanpa Path Prefix
    • Contoh: api.example.com
  3. Wildcard Domain dengan Subdomain Terpanjang
    • Contoh: *.sub.example.com
  4. Wildcard Domain Standar
    • Contoh: *.example.com
  5. Port Catch-All (Semua Host)
    • Contoh: :443 atau :80

Mari kita lihat contoh implementasinya di Caddyfile:

# Blok A
*.example.com {
    respond "Halo dari Subdomain Wildcard!"
}

# Blok B
api.example.com {
    respond "Halo dari API Spesifik!"
}

# Blok C
api.example.com/v1/auth/* {
    respond "Halo dari Endpoint Auth API!"
}

Jika client mengirimkan request ke:

  • api.example.com/v1/auth/login -> Dicocokkan dengan Blok C (karena memiliki domain dan path prefix yang paling spesifik).
  • api.example.com/users -> Dicocokkan dengan Blok B (karena domain cocok secara tepat dan Blok C tidak memenuhi kriteria path /v1/auth).
  • blog.example.com -> Dicocokkan dengan Blok A (karena domain cocok dengan pola wildcard).

Pola Umum dan Kasus Penggunaan (Common Patterns) #

1. Pengalihan Non-WWW ke WWW (dan sebaliknya) secara Aman #

Di production, kita biasanya ingin menetapkan satu domain kanonikal agar performa SEO web kita optimal. Jika user mengakses domain non-kanonikal, server akan mengalihkan mereka secara otomatis.

# Domain non-kanonikal (non-www)
example.com {
    # Alihkan permanen (301) ke domain kanonikal dengan mempertahankan skema HTTPS dan URI request asli
    redir https://www.example.com{uri} permanent
}

# Domain kanonikal (www)
www.example.com {
    root * /var/www/html
    file_server
}

2. Konfigurasi Multi-Environment (Dev, Staging, Prod) #

Kita dapat menggunakan variabel lingkungan agar berkas Caddyfile yang sama dapat berjalan di laptop development lokal kita tanpa HTTPS publik, serta berjalan di server staging dan produksi dengan HTTPS Let’s Encrypt yang aktif.

# Nilai default domain dan port backend akan diambil dari OS environment
{env.APP_URL} {
    reverse_proxy localhost:{env.BACKEND_PORT}
    
    # Jika di lokal kita tidak butuh TLS Let's Encrypt, kita dapat mengatur
    # environment variable APP_URL ke 'http://localhost' atau 'localhost'
}

Untuk menjalankan di mesin development lokal:

export APP_URL="localhost"
export BACKEND_PORT="3000"
caddy run

Untuk menjalankan di server produksi:

export APP_URL="myproduction.com"
export BACKEND_PORT="8080"
caddy run

Troubleshooting Site Address #

Berikut adalah beberapa masalah yang paling sering terjadi terkait konfigurasi alamat situs beserta langkah penyelesaiannya:

1. Caddy Gagal Mendapatkan Sertifikat SSL (TLS Handshake Fail) #

Jika domain Anda tidak dapat diakses via HTTPS dan log menampilkan pesan error ACME:

  • Penyebab 1: Rekaman DNS belum diarahkan ke server.
    • Solusi: Jalankan perintah dig +short domain-anda.com di terminal Anda. IP yang dikembalikan wajib mengarah ke IP publik server Anda. Jika domain belum terarah, Let’s Encrypt tidak akan bisa memverifikasi tantangan HTTP-01.
  • Penyebab 2: Port 80 atau 443 diblokir oleh Firewall.
    • Solusi: Let’s Encrypt wajib menghubungi server Anda di port 80 untuk memvalidasi kepemilikan domain. Pastikan firewall (seperti UFW di Ubuntu, iptables, AWS Security Groups, atau Cloudflare Proxy) mengizinkan lalu lintas masuk di port 80 dan 443.
  • Penyebab 3: Menggunakan Wildcard tanpa DNS API Token.
    • Solusi: Periksa apakah Anda menulis domain wildcard (*.domain.com) tetapi lupa mengonfigurasi plugin DNS challenge di blok tls.

2. Error: “bind: address already in use” #

Saat Caddy dijalankan, ia menampilkan pesan kegagalan pengikatan port:

run: loading initial config: loading new config: http app: start: listening on :80: listen tcp :80: bind: address already in use
  • Penyebab: Ada web server atau proses lain (seperti Nginx, Apache, atau instansi Caddy lain yang berjalan sebagai service) yang saat ini sedang menggunakan port 80 atau 443 di mesin Anda.
  • Solusi: Temukan proses yang menggunakan port tersebut dan matikan prosesnya:
    # Temukan PID proses yang memonopoli port 80/443
    sudo lsof -i :80
    sudo ss -tlnp | grep ':80'
    
    # Matikan layanan tersebut (misalnya jika Nginx aktif)
    sudo systemctl stop nginx
    

Ringkasan #

  • HTTPS Otomatis hanya diaktifkan oleh Caddy jika alamat situs menggunakan nama domain publik dan tidak menentukan port HTTP (80) atau skema http://.
  • Domain Wildcard (*.example.com) wajib menggunakan modul DNS-01 Challenge di blok konfigurasi TLS agar Caddy dapat membuktikan kepemilikan domain ke otoritas sertifikat.
  • On-Demand TLS memungkinkan penerbitan sertifikat SSL secara dinamis saat jabat tangan TLS pertama terjadi. Wajib gunakan endpoint ask untuk memvalidasi domain pelanggan dan menghindari penyalahgunaan.
  • Domain khusus localhost akan memicu CA internal Caddy untuk membuat sertifikat lokal yang tepercaya di komputer development kita.
  • Gunakan pemisah koma (,) atau baris baru untuk mengarahkan banyak domain ke dalam satu konfigurasi blok situs yang sama.
  • Caddy mengevaluasi kecocokan request berdasarkan tingkat spesifisitas domain. Domain exact dengan path prefix terpanjang selalu menang dari domain wildcard atau port catch-all.

← Sebelumnya: Struktur Caddyfile   Berikutnya: Directive →

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