Proxy Headers

Proxy Headers #

Header HTTP adalah mekanisme komunikasi metadata antara client, proxy, dan backend. Ketika Caddy berperan sebagai reverse proxy, ia bisa menambah, mengubah, atau menghapus header baik pada request yang diteruskan ke backend maupun pada response yang dikembalikan ke client. Konfigurasi header yang tepat sangat penting untuk beberapa hal: mendapatkan IP client yang benar di backend, CORS yang berfungsi dengan baik, dan security headers yang konsisten.

Dua Arah: header_up dan header_down #

Client ──request──► Caddy ──[header_up modifikasi]──► Backend
                                                          │
Client ◄──response── Caddy ◄──[header_down modifikasi]── Backend
example.com {
    reverse_proxy backend:3000 {
        # header_up: modifikasi header REQUEST yang diteruskan ke backend
        header_up X-Custom "value"
        
        # header_down: modifikasi header RESPONSE dari backend ke client
        header_down X-Backend-Version "v2"
    }
}

Header Forwarding Standar #

Ini adalah set header standar yang harus diteruskan ke backend agar aplikasi bisa mengetahui informasi tentang request asli:

example.com {
    reverse_proxy backend:3000 {
        # IP client asli
        # Tanpa ini, backend hanya melihat IP Caddy (127.0.0.1)
        header_up X-Real-IP         {remote_host}
        
        # Daftar IP yang telah melewati proxy (bisa multiple proxy)
        # Format: "client-ip, proxy1-ip, proxy2-ip"
        header_up X-Forwarded-For   {remote_host}
        
        # Protokol asli yang digunakan client (http atau https)
        # Backend bisa cek ini untuk redirect logic
        header_up X-Forwarded-Proto {scheme}
        
        # Host header yang diminta client
        # Berguna jika backend perlu tahu domain yang diminta
        header_up X-Forwarded-Host  {host}
        
        # Port yang digunakan (80, 443, atau custom)
        header_up X-Forwarded-Port  {server_port}
        
        # Host untuk upstream (termasuk port jika non-standar)
        # Ini yang backend lihat sebagai "Host" header
        header_up Host              {upstream_hostport}
    }
}
Perlu dicatat: Caddy secara default sudah menambahkan X-Forwarded-For, X-Forwarded-Proto, dan X-Forwarded-Host secara otomatis. Kamu hanya perlu menambahkan secara eksplisit jika ingin mengubah nilai atau menambahkan header tambahan seperti X-Real-IP.

Placeholder yang Tersedia untuk Header Values #

Placeholder                    Nilai
─────────────────────────────────────────────────────────────────────
{remote_host}                  IP address client (tanpa port)
{remote_port}                  Port client
{remote_ip}                    IP address client (sama dengan remote_host)
{scheme}                       http atau https
{host}                         Hostname dari request (tanpa port)
{hostport}                     Hostname + port jika non-standar
{upstream_hostport}            Hostname + port upstream target
{server_port}                  Port server yang menerima request
{method}                       HTTP method (GET, POST, dll.)
{uri}                          URI lengkap termasuk query string
{path}                         Path tanpa query string
{query}                        Query string (tanpa ?)
{header.NAMA_HEADER}           Nilai header request tertentu
{http.request.uuid}            UUID unik untuk setiap request
{time.now.unix}                Unix timestamp saat ini
{env.NAMA_ENV}                 Nilai environment variable

Trusted Proxies dan X-Forwarded-For yang Benar #

Ini adalah salah satu konfigurasi yang paling sering disalahpahami. X-Forwarded-For adalah header yang bisa di-spoof oleh client — client bisa mengirim header ini dengan nilai IP palsu.

Tanpa trusted_proxies:
  Attacker (203.0.113.1) mengirim:
  X-Forwarded-For: 1.2.3.4    ← IP palsu yang attacker kirim
  
  Backend menerima:
  X-Forwarded-For: 1.2.3.4, 203.0.113.1  ← Caddy menambahkan IP attacker
  
  Tapi jika backend hanya baca X-Forwarded-For[0] = 1.2.3.4
  → IP palsu berhasil!

Dengan trusted_proxies:
  Caddy hanya percaya X-Forwarded-For dari IP yang ada di trusted list
  IP dari client langsung selalu ditambahkan ke akhir
{
    servers {
        # IP yang dipercaya untuk header forwarding
        # Sesuaikan dengan IP load balancer / proxy di depan Caddy
        trusted_proxies static 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16
        
        # Cloudflare (contoh, cek dokumentasi Cloudflare untuk IP terbaru)
        # trusted_proxies static 103.21.244.0/22 103.22.200.0/22 ...
    }
}

example.com {
    reverse_proxy backend:3000 {
        header_up X-Real-IP         {remote_host}
        header_up X-Forwarded-For   {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
}

Menghapus Header #

example.com {
    reverse_proxy backend:3000 {
        # Hapus header dengan prefix '-'
        
        # Hapus header sensitif dari request sebelum ke backend
        header_up -X-Internal-Secret
        header_up -Authorization    # Jika auth ditangani di Caddy, tidak perlu ke backend
        
        # Hapus header dari response sebelum ke client
        header_down -X-Powered-By   # Sembunyikan teknologi stack
        header_down -Server
        header_down -X-Runtime
        header_down -X-Debug-Info
    }
}

Menambahkan Header ke Response (header_down) #

example.com {
    reverse_proxy backend:3000 {
        # Security headers — tambahkan di proxy level
        # agar konsisten untuk semua response termasuk error dari backend
        header_down Strict-Transport-Security "max-age=31536000; includeSubDomains"
        header_down X-Frame-Options           "SAMEORIGIN"
        header_down X-Content-Type-Options    "nosniff"
        header_down Referrer-Policy           "strict-origin-when-cross-origin"
        
        # Versi API yang digunakan
        header_down X-API-Version "v2.1.0"
        
        # Hapus header informatif
        header_down -Server
        header_down -X-Powered-By
    }
}

CORS via Proxy Header #

Untuk mengaktifkan CORS dari sisi proxy (tanpa perlu mengubah kode backend):

api.example.com {
    @preflight method OPTIONS
    
    # Handle CORS preflight request
    handle @preflight {
        header Access-Control-Allow-Origin      "https://app.example.com"
        header Access-Control-Allow-Methods     "GET, POST, PUT, DELETE, PATCH, OPTIONS"
        header Access-Control-Allow-Headers     "Content-Type, Authorization, X-Requested-With"
        header Access-Control-Allow-Credentials "true"
        header Access-Control-Max-Age           "86400"
        respond "" 204
    }
    
    # Tambahkan CORS header ke semua response
    reverse_proxy backend:8080 {
        header_down Access-Control-Allow-Origin      "https://app.example.com"
        header_down Access-Control-Allow-Credentials "true"
        header_down Access-Control-Expose-Headers    "X-Total-Count, X-Page"
    }
}

Request ID Tracking #

Untuk distributed tracing dan korelasi log:

example.com {
    # Tambahkan request ID unik ke setiap request
    # Backend bisa log ID ini, memudahkan tracing masalah
    header X-Request-ID {http.request.uuid}
    
    reverse_proxy backend:3000 {
        # Teruskan ke backend
        header_up X-Request-ID {http.request.uuid}
        
        # Return ke client juga (untuk debugging dari sisi client)
        header_down X-Request-ID {http.request.uuid}
    }
    
    log {
        format json
        # Log otomatis menyertakan request UUID
    }
}

Rate Limit Headers #

Memberi informasi rate limit ke client via header response:

api.example.com {
    # Jika menggunakan plugin rate_limit, tambahkan info ke header
    reverse_proxy backend:8080 {
        # Pass-through rate limit headers dari backend
        # (jika backend mengelola rate limit sendiri)
        header_down X-RateLimit-Limit     ""
        header_down X-RateLimit-Remaining ""
        header_down X-RateLimit-Reset     ""
    }
}

Header untuk Autentikasi ke Backend #

internal-api.example.com {
    # Verifikasi JWT di level Caddy (dengan plugin)
    # Kemudian teruskan user info ke backend via header
    
    reverse_proxy backend:8080 {
        # Teruskan user ID yang sudah di-extract dari 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}
        
        # Hapus Authorization header agar backend tidak perlu validasi ulang
        # (karena Caddy sudah validasi di atas)
        header_up -Authorization
    }
}

Debugging Header #

# Lihat header yang dikirim Caddy ke backend
# Aktifkan debug log sementara di Caddyfile:
# {
#     debug
# }

# Atau tangkap request di backend
# Untuk Node.js/Express sementara, tambahkan:
# app.use((req, res, next) => { console.log(req.headers); next(); });

# Atau gunakan httpbin untuk melihat header
# reverse_proxy httpbin.org {
#     header_up Host "httpbin.org"
# }
# Akses /get atau /headers untuk melihat apa yang diterima

# Lihat header response dari Caddy
curl -I https://example.com/
# Atau lebih detail:
curl -sv https://example.com/ 2>&1 | grep "^[<>]"

Anti-Pattern yang Harus Dihindari #

# ANTI-PATTERN 1: Meneruskan header Authorization tanpa pemikiran
example.com {
    reverse_proxy backend:3000 {
        # Ini OK jika backend perlu validasi auth sendiri
        # Tapi jika Caddy sudah handle auth, hapus header ini
        # agar backend tidak di-bypass
        header_up Authorization {header.Authorization}
    }
}

# ANTI-PATTERN 2: Mempercaya X-Forwarded-For dari client tanpa trusted_proxies
# → Attacker bisa spoof IP address

# BENAR: Set trusted_proxies di global options untuk menentukan
# proxy mana yang boleh di-trust untuk X-Forwarded-For

Ringkasan #

  • header_up untuk modifikasi header request ke backend, header_down untuk modifikasi header response ke client.
  • Selalu teruskan X-Real-IP, X-Forwarded-For, dan X-Forwarded-Proto agar backend bisa mengetahui informasi client asli.
  • Konfigurasi trusted_proxies di global options untuk mencegah IP spoofing via X-Forwarded-For — hanya percaya header dari proxy yang kamu kontrol.
  • Hapus header informatif dari response (-Server, -X-Powered-By) untuk menyembunyikan teknologi stack dari publik.
  • Tambahkan X-Request-ID {http.request.uuid} untuk distributed tracing dan korelasi log antara Caddy dan backend.
  • Gunakan header_down di reverse_proxy untuk menambahkan security headers secara konsisten ke semua response, termasuk error dari backend.

← Sebelumnya: Konfigurasi Reverse Proxy   Berikutnya: Transport →

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