Proxy Headers #
Header HTTP bertindak sebagai pembawa metadata penting yang memfasilitasi komunikasi antara browser klien, reverse proxy, dan server backend aplikasi kita. Konfigurasi manipulasi header yang tepat di level proxy adalah aspek fundamental dalam mengamankan alur data, meneruskan identitas asli pengguna, mengelola izin lintas asal (CORS), serta menyembunyikan jejak teknologi internal server. Caddy menyediakan mekanisme modifikasi header dua arah yang sangat fleksibel dan aman untuk memastikan backend kita menerima informasi tepercaya yang mereka butuhkan.
Mekanisme Pipa Header: header_up vs header_down
#
Ketika Caddy bertindak sebagai reverse proxy, ia mengelola pipa data (pipeline) dua arah. Modifikasi header dapat dilakukan pada kedua fase perjalanan data ini:
flowchart TD
subgraph RequestFlow ["Request (Klien ke Backend)"]
direction LR
Klien1["Klien"] -->|"Request"| Caddy1["Caddy Proxy"]
Caddy1 -->|"header_up"| Backend1["Backend"]
end
subgraph ResponseFlow ["Response (Backend ke Klien)"]
direction LR
Backend2["Backend"] -->|"header_down"| Caddy2["Caddy Proxy"]
Caddy2 -->|"Response"| Klien2["Klien"]
endheader_up: Digunakan untuk memodifikasi header pada objek request yang dikirimkan oleh klien sebelum Caddy meneruskannya ke server backend. Biasanya digunakan untuk menyuntikkan IP klien asli, menyetel ulang headerHostagar dikenali oleh backend, atau menghapus kredensial sensitif.header_down: Digunakan untuk memodifikasi header pada objek response yang dikembalikan oleh server backend sebelum Caddy mengirimkannya kembali ke browser klien. Biasanya digunakan untuk menghapus penanda teknologi backend, menyuntikkan kebijakan keamanan browser, atau menyisipkan tajuk caching.
Berikut adalah contoh implementasi sintaksis dasarnya di dalam Caddyfile:
# Contoh modifikasi dua arah
example.com {
reverse_proxy localhost:3000 {
# Modifikasi request ke backend
header_up X-Custom-Request-Header "Data-Upstream"
# Modifikasi response ke klien
header_down X-Custom-Response-Header "Data-Downstream"
}
}
Meneruskan Identitas Klien (Standard Headers) #
Secara default, saat server backend menerima request dari reverse proxy, ia akan melihat alamat IP sumber koneksi datang dari IP Caddy (biasanya 127.0.0.1 atau IP jaringan lokal), bukan dari IP internet asli milik pengguna. Kondisi ini membuat backend tidak bisa melakukan logging IP pengguna dengan benar, menyulitkan pelacakan geolokasi, dan merusak logika blokir keamanan internal backend.
Untuk mengatasi ini, Caddy secara otomatis menyuntikkan beberapa header standar industri ke arah backend saat kita mengaktifkan direktif reverse_proxy:
X-Forwarded-For: Menyimpan daftar IP klien asli beserta seluruh proxy lain yang telah dilewati oleh request tersebut. Caddy mengisi nilai ini dengan alamat IP klien asli secara otomatis.X-Forwarded-Proto: Mengidentifikasi skema protokol (HTTP atau HTTPS) yang digunakan oleh browser klien saat berkomunikasi dengan Caddy. Ini krusial bagi backend untuk mendeteksi apakah request aman atau perlu dialihkan (redirect) ke HTTPS.X-Forwarded-Host: Berisi nama domain asli (Hostheader) yang diminta oleh browser klien di internet.
Jika kita ingin melengkapi dengan header non-standar namun populer seperti X-Real-IP, kita dapat menambahkannya secara eksplisit menggunakan header_up:
# Konfigurasi manual penerusan identitas lengkap
example.com {
reverse_proxy localhost:3000 {
# Mengisi IP klien asli tanpa port ke header X-Real-IP
header_up X-Real-IP {remote_host}
# Mengisi host tujuan backend
header_up Host {upstream_hostport}
}
}
IP Spoofing dan Konfigurasi trusted_proxies
#
Header X-Forwarded-For sangat rentan terhadap serangan manipulasi IP (IP spoofing) jika reverse proxy kita tidak dikonfigurasi dengan ketat. Karena header ini adalah header teks HTTP biasa, seorang peretas (attacker) dapat secara manual menyisipkan header X-Forwarded-For: 8.8.8.8 yang berisi IP palsu saat mengirimkan permintaan ke server Caddy kita.
Skenario Bahaya IP Spoofing #
Jika Caddy mempercayai mentah-mentah header kiriman dari luar tersebut, Caddy akan menggabungkan IP palsu tersebut ke dalam daftar IP yang diteruskan ke backend. Jika backend kita mendasarkan keamanan aksesnya (seperti admin panel whitelist) pada indeks pertama X-Forwarded-For, peretas dapat dengan mudah melewati sistem keamanan kita.
Untuk mencegah celah keamanan ini, Caddy menyediakan opsi konfigurasi global trusted_proxies:
flowchart TD
Request["Klien Kirim Request\n(IP: 203.0.113.1)\nX-Forwarded-For: 1.2.3.4 (Palsu)"] --> Caddy{"Caddy Proxy"}
Caddy -->|Evaluasi IP Sumber| TrustedCheck{"Apakah IP 203.0.113.1\nada di trusted_proxies?"}
TrustedCheck -- Tidak (User Biasa) --> StripIP["Abaikan header input palsu\nX-Forwarded-For diteruskan ke backend sebagai:\n203.0.113.1"]
TrustedCheck -- Ya (Cloudflare/CDN) --> TrustIP["Terima header input\nX-Forwarded-For diteruskan ke backend sebagai:\n1.2.3.4, 203.0.113.1"]
StripIP --> Backend["Backend Server"]
TrustIP --> BackendKita harus mendefinisikan alamat IP proxy tepercaya (seperti IP Cloudflare atau IP Load Balancer internal awan kita) di blok opsi global Caddyfile agar Caddy mengetahui IP mana yang boleh dipercaya untuk meneruskan header kiriman klien:
# Blok opsi global Caddyfile
{
servers {
# Daftarkan subnet IP Cloudflare atau load balancer internal kita
# Contoh: VPC privat subnet 10.0.0.0/16
trusted_proxies static 10.0.0.0/16
}
}
# Blok situs
example.com {
reverse_proxy localhost:3000
}
Dengan konfigurasi ini, jika ada koneksi langsung dari internet luar (yang IP-nya berada di luar subnet 10.0.0.0/16), Caddy akan secara otomatis mengabaikan dan menghapus data header X-Forwarded-For palsu yang dikirim oleh klien tersebut, lalu menggantinya dengan IP asli yang sebenarnya terdeteksi di tingkat soket koneksi TCP.
Nilai Header Dinamis (Placeholders) #
Caddy dilengkapi dengan sistem placeholder yang sangat kaya untuk menyisipkan nilai-nilai dinamis dari request ke dalam header yang kita manipulasi. Nilai-nilai ini diisi secara otomatis oleh Caddy di runtime untuk setiap request.
Berikut adalah tabel placeholder yang paling sering digunakan beserta contoh nilai keluarannya:
| Nama Placeholder | Penjelasan Nilai | Contoh Output |
|---|---|---|
{remote_host} | Alamat IP klien asli (tanpa nomor port) | 192.168.1.50 |
{remote_port} | Nomor port koneksi keluar klien | 53210 |
{remote_ip} | Sinonim untuk alamat IP klien asli | 192.168.1.50 |
{scheme} | Protokol yang digunakan klien | https atau http |
{host} | Nama domain yang diminta klien (tanpa port) | api.example.com |
{hostport} | Nama domain beserta port (jika non-standar) | api.example.com:8443 |
{upstream_hostport} | Alamat backend tujuan yang dipilih Caddy | 10.0.0.22:3000 |
{method} | Metode HTTP yang digunakan request | GET, POST, DELETE |
{uri} | URI path lengkap beserta query string | /users/search?q=caddy |
{path} | URI path bersih tanpa query string | /users/search |
{query} | Parameter kueri pencarian (tanpa tanda tanya) | q=caddy&limit=10 |
{http.request.uuid} | ID pelacak unik UUID v4 untuk request ini | 9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d |
{header.NAMA_HEADER} | Membaca nilai dari header request klien tertentu | {header.User-Agent} |
Pengamanan Response: Menyembunyikan Jejak Teknologi #
Sebuah server backend yang baik tidak boleh membocorkan detail spesifik mengenai teknologi, bahasa pemrograman, atau framework yang digunakannya. Informasi seperti X-Powered-By: PHP/8.3.2 atau Server: Microsoft-IIS/10.0 memudahkan penyerang di internet untuk mencari daftar kerentanan (CVE) yang berkaitan dengan teknologi tersebut guna melakukan serangan terarah.
Dengan Caddy, kita dapat menghapus seluruh header penanda ini secara terpusat pada tingkat proxy menggunakan simbol - sebelum nama header:
# Proteksi kebocoran metadata backend
example.com {
reverse_proxy localhost:3000 {
# Hapus header sensitif dari response backend sebelum dikirim ke klien
header_down -X-Powered-By
header_down -X-AspNet-Version
header_down -Server
}
}
Menyuntikkan Security Headers Terpusat #
Selain menghapus, kita juga bisa memaksa penambahan tajuk keamanan (security headers) standar industri pada semua response yang keluar dari proxy Caddy kita agar browser klien memperketat keamanannya:
# Menyuntikkan security headers
example.com {
reverse_proxy localhost:3000 {
# Lindungi dari pembajakan klik (Clickjacking)
header_down X-Frame-Options "SAMEORIGIN"
# Proteksi tipe MIME (MIME sniffing prevention)
header_down X-Content-Type-Options "nosniff"
# HSTS - Paksa browser menggunakan HTTPS selama 1 tahun
header_down Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Kebijakan perujuk (Referrer Policy)
header_down Referrer-Policy "strict-origin-when-cross-origin"
# Hapus info server
header_down -Server
}
}
Implementasi Kebijakan Keamanan Konten (Content Security Policy - CSP) #
Untuk memitigasi serangan Cross-Site Scripting (XSS) dan injeksi data, kita dapat menyuntikkan header CSP tingkat lanjut secara terpusat melalui Caddy. Header ini memberitahu browser klien dari mana saja berkas JavaScript, gaya CSS, dan gambar boleh dimuat:
# Contoh penambahan CSP terpusat
example.com {
reverse_proxy localhost:3000 {
# Menolak semua asset kecuali dari origin yang sama dan subdomain terpercaya
header_down Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://apis.google.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com;"
}
}
Mengelola CORS (Cross-Origin Resource Sharing) Terpusat #
Ketika kita membangun aplikasi arsitektur terpisah (misalnya Frontend React berjalan di app.example.com dan Backend API berjalan di api.example.com), browser klien akan memblokir request API karena aturan kebijakan asal yang sama (Same-Origin Policy).
Kita harus mengizinkan akses tersebut dengan mengonfigurasi header CORS. Menuliskan logika CORS di dalam kode backend sering kali merepotkan dan tidak konsisten. Kita dapat menyerahkan tugas ini ke tingkat reverse proxy Caddy:
sequenceDiagram
autonumber
participant Browser as Browser Klien
participant Caddy as Caddy Proxy
participant Backend as App Backend
Note over Browser: Preflight Request (OPTIONS)
Browser->>Caddy: OPTIONS /api/data (Origin: app.example.com)
Note over Caddy: Caddy mencocokkan matcher @preflight<br/>dan langsung menjawab tanpa backend
Caddy-->>Browser: 204 No Content (Access-Control-Allow-Origin: app.example.com)
Note over Browser: Request Riil (GET/POST)
Browser->>Caddy: GET /api/data (Origin: app.example.com)
Caddy->>Backend: Forward GET /api/data
Backend-->>Caddy: 200 OK (Data JSON)
Note over Caddy: Caddy menyuntikkan CORS header_down
Caddy-->>Browser: 200 OK (Access-Control-Allow-Origin: app.example.com)Berikut adalah konfigurasi Caddyfile untuk menangani jabat tangan CORS secara terpusat:
# Mengamankan dan mengonfigurasi CORS di Caddy
api.example.com {
# Tentukan matcher untuk HTTP method OPTIONS (Preflight)
@cors_preflight method OPTIONS
# Tangani request Preflight langsung di Caddy tanpa membebani backend
handle @cors_preflight {
header Access-Control-Allow-Origin "https://app.example.com"
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
header Access-Control-Allow-Headers "Authorization, Content-Type, Accept"
header Access-Control-Allow-Credentials "true"
header Access-Control-Max-Age "86400"
respond "" 204
}
# Teruskan request normal (GET/POST) ke backend dan selipkan CORS header
reverse_proxy localhost:8080 {
header_down Access-Control-Allow-Origin "https://app.example.com"
header_down Access-Control-Allow-Credentials "true"
}
}
Pelacakan Permintaan (Request Tracking & Distributed Tracing) #
Pada arsitektur sistem terdistribusi, satu permintaan klien ke gerbang utama dapat memicu rantai pemanggilan ke berbagai microservice di backend. Jika terjadi kegagalan atau kelambatan respon di tengah jalan, akan sangat sulit mencari tahu request mana di log backend yang berkaitan dengan keluhan pengguna tersebut.
Kita dapat mengimplementasikan Distributed Tracing menggunakan ID pelacak unik (Correlation ID) di Caddy. Caddy memiliki placeholder {http.request.uuid} yang menghasilkan UUID unik untuk setiap request masuk. Kita menyuntikkan UUID ini ke arah backend dan mengembalikannya ke klien:
# Distribusi penjejak log
example.com {
reverse_proxy localhost:3000 {
# Suntikkan Request ID unik ke request backend
header_up X-Request-ID {http.request.uuid}
# Sisipkan Request ID yang sama ke response klien
# Berguna bagi pengguna saat melaporkan error ke customer service
header_down X-Request-ID {http.request.uuid}
}
log {
format json
# UUID request akan otomatis tercatat di log Caddy
}
}
Di tingkat aplikasi backend kita (misalnya menggunakan middleware logger Winston di Node.js atau Logback di Java), kita hanya perlu membaca nilai header X-Request-ID dari request masuk dan menyertakannya di setiap baris log aplikasi. Jika klien melaporkan error dengan menyertakan header X-Request-ID yang diterimanya, tim pengembang kita cukup melakukan pencarian (grep) ID tersebut di seluruh klaster log untuk menganalisis seluruh riwayat jalannya request tersebut dari awal hingga akhir.
Autentikasi dan Penerusan Metadata Pengguna #
Untuk menyederhanakan kode backend, kita dapat memindahkan proses validasi autentikasi pengguna (seperti otentikasi dasar HTTP, validasi token API, atau otentikasi JWT) ke lapisan Caddy menggunakan modul plugin autentikasi Caddy (seperti plugin JWT).
Setelah Caddy berhasil memverifikasi token pengguna, Caddy dapat meneruskan detail informasi identitas pengguna tersebut ke backend melalui header kustom, dan menghapus kredensial mentah agar backend tidak perlu melakukan validasi ulang:
# Penerusan metadata otentikasi
secure-api.example.com {
# (Asumsikan di sini kita menggunakan plugin JWT Caddy)
# jwt_auth {
# secret "jwt-secret-key"
# }
reverse_proxy localhost:8080 {
# Teruskan metadata pengguna yang diekstrak dari klaim JWT
header_up X-User-ID {http.auth.user.id}
header_up X-User-Email {http.auth.user.email}
header_up X-User-Role {http.auth.user.role}
# JANGAN teruskan token Authorization mentah ke backend demi keamanan
header_up -Authorization
}
}
Skenario ini memastikan backend kita tetap bersih, aman, dan hanya menerima request yang sudah tervalidasi secara sah dari gerbang utama Caddy.
Penanganan Header Berukuran Besar dan Cookies #
Dalam beberapa aplikasi web skala korporasi yang menggunakan sistem manajemen identitas terpusat (seperti Active Directory, Keycloak, atau Okta), ukuran cookie sesi pengguna bisa membengkak sangat besar.
Apabila header cookie melebihi batas ukuran buffer default pada proxy, koneksi akan diputus dengan pesan error 400 Bad Request atau 431 Request Header Fields Too Large. Caddy memungkinkan kita untuk menyesuaikan batasan ukuran pembacaan header di tingkat server sebelum diteruskan ke backend:
# Menyesuaikan batas ukuran buffer header
{
# Konfigurasi global server
servers {
# Naikkan batas ukuran header pembacaan request klien menjadi 16KB (Default: 1MB untuk Caddy modern, namun bisa dikustomisasi)
max_header_bytes 16384
}
}
example.com {
reverse_proxy localhost:3000 {
# Set buffer baca transport http ke 8KB untuk menampung respon backend yang besar
transport http {
read_buffer_size 8kb
}
}
}
Ringkasan #
- Modifikasi Dua Arah: Gunakan
header_upuntuk memodifikasi request metadata ke backend danheader_downuntuk memodifikasi response data ke browser klien.- Mencegah IP Spoofing: Daftarkan IP proxy eksternal tepercaya pada opsi global
trusted_proxiesagar penyerang tidak dapat memalsukan alamat IP mereka via headerX-Forwarded-For.- Keamanan Tambahan: Hapus header informatif dari backend (
-Server,-X-Powered-By) dan suntikkan HSTS, CSP, serta CORS secara terpusat di Caddy proxy.- Tracing Sistem: Suntikkan
X-Request-IDmenggunakan placeholder dinamis{http.request.uuid}ke backend dan klien untuk memfasilitasi penelusuran log terdistribusi.- Otentikasi Bersih: Caddy dapat memproses otentikasi di gerbang masuk lalu menyalurkan data pengguna tepercaya via header kustom ke backend tanpa mengirim token sensitif mentah.
← Sebelumnya: Konfigurasi Reverse Proxy Berikutnya: Transport →