Directive #
Directive adalah instruksi yang kamu berikan kepada Caddy di dalam blok site — mereka adalah jantung dari konfigurasi Caddyfile. Setiap directive memberitahu Caddy untuk melakukan sesuatu: melayani file statis, meneruskan request ke backend, mengompresi response, menambahkan header, atau melakukan autentikasi. Memahami directive yang tersedia dan cara menggunakannya secara efektif adalah keterampilan inti untuk bekerja dengan Caddy.
Anatomi Directive #
Directive memiliki dua bentuk penulisan:
Bentuk Inline (Satu Baris) #
Untuk directive sederhana dengan sedikit argumen:
example.com {
# Format: nama_directive [argumen...]
root * /var/www/html
file_server
encode gzip
redir /old-path /new-path permanent
}
Bentuk Blok #
Untuk directive dengan banyak opsi atau konfigurasi yang kompleks:
example.com {
# Format:
# nama_directive [argumen...] {
# subdirective [argumen...]
# subdirective [argumen...]
# }
log {
output file /var/log/caddy/access.log
format json
level INFO
}
tls {
protocols tls1.2 tls1.3
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
}
}
Campuran #
Beberapa directive mendukung keduanya sekaligus:
example.com {
# Inline sederhana
encode gzip
# Atau dengan blok untuk opsi tambahan
encode {
gzip 6 # gzip dengan compression level 6
zstd # juga aktifkan zstd
minimum_length 1024 # hanya compress jika >= 1024 bytes
}
}
Directive Paling Sering Digunakan #
root — Direktori Root
#
Menetapkan direktori root untuk file_server dan php_fastcgi:
example.com {
# Syntax: root [matcher] path
# '*' berarti cocok dengan semua request
root * /var/www/html
# Bisa juga dengan matcher tertentu
root /static/* /var/www/static-assets
file_server
}
file_server — Menyajikan File Statis
#
example.com {
root * /var/www/html
# file_server sederhana
file_server
# Dengan opsi tambahan
file_server {
# Aktifkan directory listing
browse
# Sembunyikan file/direktori tertentu dari listing
hide .git .env *.secret
# Index file yang dicari (default: index.html)
index index.html index.htm
# Nonaktifkan canonical redirects (trailing slash)
disable_canonical_uris
}
}
reverse_proxy — Proxy ke Backend
#
Directive yang paling sering digunakan untuk melayani aplikasi:
example.com {
# Proxy ke satu upstream
reverse_proxy localhost:3000
# Proxy ke beberapa upstream (load balancing otomatis dengan round-robin)
reverse_proxy localhost:3001 localhost:3002 localhost:3003
# Dengan opsi lengkap
reverse_proxy localhost:3000 {
# Header yang diteruskan ke backend
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-For {remote_host}
header_up X-Forwarded-Proto {scheme}
# Health check
health_uri /health
health_interval 10s
health_timeout 5s
health_status 200
# Timeout
transport http {
dial_timeout 5s
response_header_timeout 30s
read_buffer_size 4kb
}
}
}
encode — Kompresi Response
#
example.com {
root * /var/www/html
# Aktifkan gzip dan zstd sekaligus
# Caddy otomatis memilih berdasarkan Accept-Encoding header
encode gzip zstd
# Atau dengan konfigurasi detail
encode {
gzip 6 # Level kompresi (1-9, default 4)
zstd # zstd compression (lebih efisien dari gzip)
minimum_length 512 # Minimum ukuran response untuk di-compress
# Hanya compress content-type tertentu
# match {
# header Content-Type text/*
# header Content-Type application/json
# }
}
file_server
}
header — Manipulasi Header
#
example.com {
# Set header response
header X-Frame-Options "SAMEORIGIN"
header X-Content-Type-Options "nosniff"
header X-XSS-Protection "1; mode=block"
# Dengan blok untuk banyak header sekaligus
header {
# Set header baru atau ganti yang sudah ada
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Frame-Options "DENY"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
Permissions-Policy "camera=(), microphone=(), geolocation=()"
# Hapus header tertentu
-Server
-X-Powered-By
# Tambahkan ke header yang sudah ada (append)
+Set-Cookie "secure; HttpOnly; SameSite=Strict"
}
file_server
}
redir — Redirect
#
example.com {
# Redirect permanen (301)
redir /old-page /new-page permanent
# Redirect sementara (302)
redir /promo /landing-2024 temporary
# Redirect dengan preserving path (wildcard)
redir /blog/* /posts/{path} permanent
# Redirect ke domain lain
redir * https://new-site.com{uri} permanent
# Redirect dengan status code tertentu
redir /gone / 308
}
# Redirect www ke non-www
www.example.com {
redir https://example.com{uri} permanent
}
rewrite — Modifikasi URI Internal
#
Berbeda dari redir, rewrite mengubah URI secara internal tanpa browser tahu:
example.com {
# Rewrite URI internal (browser tidak tahu)
# Request ke /app/... diteruskan ke backend seolah request ke /...
rewrite /app/* /{path}
# Rewrite dengan kondisi
@php path *.php
rewrite @php /index.php?{query}
# Rewrite untuk SPA (Single Page App)
@notFile {
not file
not path /api/*
}
rewrite @notFile /index.html
file_server
}
respond — Response Langsung
#
example.com {
# Kembalikan response sederhana
respond "Hello, World!"
# Dengan status code
respond "Not Found" 404
# Dengan header
@health path /health
respond @health `{"status":"ok"}` 200
# Tolak semua request lain
respond "Forbidden" 403
}
basicauth — HTTP Basic Authentication
#
example.com {
# Lindungi path tertentu dengan username/password
basicauth /admin/* {
# Format: username bcrypt_hash
# Buat hash dengan: caddy hash-password
admin $2a$14$example_hash_here
}
# Lindungi seluruh site
basicauth {
user1 $2a$14$hash1
user2 $2a$14$hash2
}
reverse_proxy localhost:3000
}
# Buat bcrypt hash untuk password
caddy hash-password --plaintext "password-kamu"
tls — Konfigurasi TLS
#
example.com {
# TLS default (otomatis menggunakan Let's Encrypt)
# Tidak perlu directive tls sama sekali untuk ini
# TLS dengan email untuk Let's Encrypt
tls [email protected]
# TLS dengan sertifikat manual
tls /path/to/cert.pem /path/to/key.pem
# TLS dengan opsi lengkap
tls {
# Protocol minimum
protocols tls1.2 tls1.3
# DNS challenge untuk wildcard
dns cloudflare {env.CF_API_TOKEN}
# Custom ACME CA
ca https://acme.custom-ca.com/directory
# Internal CA untuk localhost/development
# issuer internal
}
file_server
}
log — Access Log
#
example.com {
log {
# Output ke file
output file /var/log/caddy/access.log {
roll_size 100mb # Rotate setelah 100MB
roll_keep 5 # Simpan 5 file log lama
}
# Format log
format json # JSON format (direkomendasikan untuk parsing)
# format console # Human-readable format
# Level log
level INFO
# Sampling (untuk traffic sangat tinggi)
# sampling {
# interval 1s
# first 50
# thereafter 100
# }
}
file_server
}
php_fastcgi — PHP via FastCGI
#
example.com {
root * /var/www/html
# PHP-FPM via TCP
php_fastcgi localhost:9000
# PHP-FPM via Unix socket (lebih cepat)
php_fastcgi unix//run/php/php8.3-fpm.sock
# Dengan opsi tambahan
php_fastcgi unix//run/php/php8.3-fpm.sock {
# Environment variable untuk PHP
env PHP_ADMIN_VALUE "expose_php=off"
# Timeout
dial_timeout 5s
read_timeout 30s
}
file_server
}
Kombinasi Directive untuk Use Case Umum #
Static Website dengan Security Headers #
example.com {
root * /var/www/html
encode gzip zstd
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains"
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
Referrer-Policy "strict-origin-when-cross-origin"
-Server
}
file_server
log {
output file /var/log/caddy/access.log
format json
}
}
API Backend dengan CORS #
api.example.com {
header {
Access-Control-Allow-Origin "https://app.example.com"
Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
Access-Control-Allow-Headers "Content-Type, Authorization"
Access-Control-Max-Age "3600"
}
# Handle OPTIONS preflight request
@options method OPTIONS
respond @options "" 204
encode gzip
reverse_proxy localhost:8080 {
health_uri /health
health_interval 30s
}
log {
output file /var/log/caddy/api.log
format json
}
}
WordPress / PHP Application #
blog.example.com {
root * /var/www/wordpress
encode gzip
# Handle PHP
php_fastcgi unix//run/php/php8.3-fpm.sock
# WordPress permalink
@notFile {
not file
not path /wp-admin/* /wp-includes/*
}
rewrite @notFile /index.php
# Blokir akses ke file sensitif
@sensitive {
path /wp-config.php /.env /.git/*
}
respond @sensitive 403
file_server {
hide .htaccess
}
}
Reverse Proxy dengan Autentikasi #
admin.example.com {
# Batasi ke IP internal
@external {
not remote_ip 10.0.0.0/8 192.168.0.0/16
}
respond @external 403
# Basic auth sebagai layer kedua
basicauth {
admin $2a$14$example_bcrypt_hash
}
reverse_proxy localhost:9000
log {
output file /var/log/caddy/admin.log
format json
}
}
Directive yang Jarang Diketahui tapi Berguna #
try_files — Fallback ke File Lain
#
example.com {
root * /var/www/html
# Coba file yang diminta, jika tidak ada coba fallback
try_files {path} {path}.html /index.html
file_server
}
request_header — Modifikasi Header Request
#
example.com {
# Tambahkan header ke request sebelum diteruskan ke backend
request_header X-App-Version "1.2.3"
# Hapus header dari request (misalnya header internal yang tidak boleh diteruskan)
request_header -X-Internal-Token
reverse_proxy localhost:3000
}
uri — Manipulasi URI
#
example.com {
# Hapus prefix dari URI
uri strip_prefix /v1
# Tambahkan prefix ke URI
uri path_prefix /api
# Replace query string
uri query +debug true
reverse_proxy localhost:3000
}
push — HTTP/2 Server Push
#
example.com {
root * /var/www/html
# Push resource untuk halaman tertentu
push /index.html {
Link "</style.css>; rel=preload; as=style"
Link "</app.js>; rel=preload; as=script"
}
file_server
}
Ringkasan #
- Directive tersedia dalam dua bentuk: inline (satu baris) dan blok (dengan kurung kurawal) — pilih sesuai kompleksitas konfigurasi.
reverse_proxyadalah directive paling penting untuk aplikasi web — mendukung load balancing, health check, dan header forwarding.file_serveruntuk file statis,php_fastcgiuntuk PHP — keduanya membutuhkanrootyang di-set terlebih dahulu.headeruntuk security headers,encodeuntuk kompresi,loguntuk access log — tiga directive yang hampir selalu ada di production.rewritemengubah URI secara internal (browser tidak tahu),redirmengirim redirect ke browser.- Urutan penulisan directive tidak menentukan urutan eksekusi — Caddy menggunakan urutan internal yang sudah terdefinisi.
- Kombinasikan directive untuk membangun konfigurasi production yang lengkap — tidak ada yang memaksamu menggunakan satu directive saja.