Directive

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_proxy adalah directive paling penting untuk aplikasi web — mendukung load balancing, health check, dan header forwarding.
  • file_server untuk file statis, php_fastcgi untuk PHP — keduanya membutuhkan root yang di-set terlebih dahulu.
  • header untuk security headers, encode untuk kompresi, log untuk access log — tiga directive yang hampir selalu ada di production.
  • rewrite mengubah URI secara internal (browser tidak tahu), redir mengirim 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.

← Sebelumnya: Site Address   Berikutnya: Matcher →

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