Pembatasan IP #

Dalam strategi pertahanan berlapis (defense in depth), membatasi akses berdasarkan alamat IP (IP Address) klien adalah salah satu metode keamanan yang paling langsung, tangguh, dan efisien. Dengan menyaring lalu lintas pada tingkat gerbang masuk, kita dapat mengisolasi endpoint sensitif (seperti panel admin atau metrik pemantauan internal) agar hanya dapat diakses oleh tim tepercaya, sekaligus memblokir alamat IP aktor jahat secara instan. Caddy menyediakan pencocok bawaan remote_ip yang mendukung notasi CIDR untuk memfasilitasi penyaringan alamat IP tunggal maupun rentang subnet secara dinamis. Kita akan membahas secara mendalam konfigurasi pola Allowlist dan Blocklist, pentingnya konfigurasi Trusted Proxies untuk mencegah pemalsuan IP (IP Spoofing), taktik pemblokiran geografis (Geo-blocking), penulisan log khusus untuk audit, serta mitigasi serangan Server-Side Request Forgery (SSRF) pada arsitektur cloud.


Matcher remote_ip dan Notasi CIDR #

Pencocok remote_ip pada Caddy mendeteksi alamat IP asal yang mengirimkan request dan mencocokkannya dengan daftar aturan yang kita tetapkan. Matcher ini berjalan sangat cepat di tingkat pemrosesan request karena hanya melakukan pencocokan biner pada struktur data IP.

Kita dapat mendefinisikan pencocokan alamat IP menggunakan notasi alamat tunggal maupun rentang blok CIDR (Classless Inter-Domain Routing):

# Contoh dasar pemblokiran IP
example.com {
    # Menyaring IP tunggal dan rentang subnet kustom
    @klien_jahat remote_ip 203.0.113.5 198.51.100.0/24
    respond @klien_jahat "Akses Ditolak!" 403
    
    file_server {
        root /var/www/html
    }
}

Format penulisan alamat IP dan subnet yang didukung oleh Caddy meliputi:

  • Alamat Tunggal (IPv4 / IPv6): Menargetkan satu perangkat secara spesifik (misalnya 192.168.1.10 atau 2001:db8::1).
  • Notasi CIDR (Subnetting): Menargetkan seluruh klaster alamat jaringan. Format /24 pada IPv4 mewakili 256 alamat IP (misalnya 192.168.1.0/24 mencakup 192.168.1.0 hingga 192.168.1.255), sedangkan /16 mewakili 65.536 alamat IP.
  • Jaringan Privat Standar (RFC 1918):
    • 10.0.0.0/8 (Rentang IP privat besar, umum digunakan di cloud VPC).
    • 172.16.0.0/12 (Rentang IP privat sedang).
    • 192.168.0.0/16 (Rentang IP privat lokal LAN kantor/rumah).
  • Alamat Loopback: 127.0.0.1/32 (IPv4) dan ::1 (IPv6) yang merujuk pada mesin lokal itu sendiri.

Pola Allowlist vs Blocklist #

Dalam merancang kebijakan keamanan jaringan, kita dapat memilih antara dua strategi utama: Allowlist (mengizinkan hanya yang dikenal, memblokir sisanya) atau Blocklist (mengizinkan semua, memblokir yang dicurigai).

+--------------------------------------------------------------------------+
|                       Perbandingan Pola Penyaringan IP                   |
+--------------------------------------------------------------------------+
|  Pola Allowlist (Tingkat Keamanan Tinggi):                               |
|  [Semua Request] ---> {Apakah IP Terdaftar?} -- Ya --> [Izinkan Masuk]    |
|                                              -- Tidak -> [Blokir (403)]  |
|                                                                          |
|  Pola Blocklist (Tingkat Aksesibilitas Tinggi):                          |
|  [Semua Request] ---> {Apakah IP Terblokir?} -- Ya --> [Blokir (403)]    |
|                                              -- Tidak -> [Izinkan Masuk] |
+--------------------------------------------------------------------------+

1. Pola Allowlist (Daftar Izin) #

Pola ini sangat direkomendasikan untuk mengamankan situs internal perusahaan, dashboard audit, atau endpoint administratif. Secara filosofis, kita menganggap semua koneksi dari internet adalah ancaman, kecuali jika alamat IP klien terdaftar di daftar izin kita:

# BENAR: Menggunakan handle untuk mengunci seluruh situs dengan allowlist
admin-panel.example.com {
    # Matcher untuk menyaring siapa saja yang BUKAN bagian dari kantor kita
    @bukan_kantor {
        not remote_ip 203.0.113.100/32 203.0.113.101/32 192.168.0.0/16
    }
    
    # Tolak langsung request di luar kantor dengan pesan error kustom
    respond @bukan_kantor "Akses Ditolak: Hanya jaringan internal kantor yang diizinkan." 403
    
    reverse_proxy localhost:9000
}

2. Pola Blocklist (Daftar Blokir) #

Pola ini umum digunakan untuk website publik (seperti e-commerce atau blog). Kita ingin semua orang dapat mengakses halaman web, namun kita ingin memblokir IP tertentu yang terdeteksi melakukan serangan pemindaian eksploitasi (vulnerability scanning) atau spamming:

# Penerapan Blocklist dinamis
example.com {
    # Matcher berisi IP aktor jahat yang terdeteksi sistem monitoring
    @klien_terblokir {
        remote_ip 198.51.100.50
        remote_ip 203.0.113.0/24
    }
    
    respond @klien_terblokir 403
    
    file_server {
        root /var/www/html
    }
}

Pembatasan IP pada Tingkat Jalur (Path-Level IP Restriction) #

Sering kali kita tidak ingin mengunci seluruh website, melainkan hanya ingin mengamankan sub-direktori tertentu saja (seperti /admin/ atau /metrics) tanpa mengganggu akses pengunjung publik pada halaman utama.

Kita dapat menggabungkan pencocok path dan IP di dalam named matcher Caddyfile:

# Mengamankan endpoint sensitif secara spesifik
example.com {
    # 1. Kunci rute panel admin hanya untuk IP kantor
    @admin_area {
        path /admin/*
        not remote_ip 203.0.113.100/32 10.0.0.0/8
    }
    respond @admin_area "Forbidden" 403

    # 2. Kunci endpoint Prometheus Metrics hanya untuk server monitoring kita
    @monitoring_area {
        path /metrics /status
        not remote_ip 10.10.1.50/32
    }
    respond @monitoring_area "Access Denied" 403

    # Lalu lintas publik normal
    root * /var/www/public
    file_server
}

Pertahanan Berlapis (IP Restriction + Basic Auth) #

Mengandalkan penyaringan IP saja memiliki risiko jika alamat IP kantor kita berubah atau jika karyawan sedang bekerja dari luar kantor (remote working). Untuk itu, kita wajib menerapkan Pertahanan Berlapis (Defense in Depth) dengan menggabungkan pembatasan IP dengan autentikasi Basic Auth:

# Kombinasi IP restriction dan Basic Auth untuk proteksi admin panel
admin.example.com {
    # Lapisan 1: Hanya izinkan IP kantor dan IP VPN kantor
    @tidak_sah {
        not remote_ip 203.0.113.100/32 10.8.0.0/24
    }
    respond @tidak_sah "Jaringan tidak dikenal" 403

    # Lapisan 2: Wajibkan Basic Auth untuk semua yang lolos pengecekan IP
    basicauth {
        sysadmin $2a$14$sysadminBcryptHashHere
    }

    # Lapisan 3: Penulisan log audit khusus
    log {
        output file /var/log/caddy/admin_security.log
        format json
    }

    reverse_proxy localhost:8080
}

IP Restriction di belakang CDN / Load Balancer (Trusted Proxies) #

Di lingkungan produksi modern, server Caddy kita hampir selalu diletakkan di belakang Load Balancer (seperti AWS ALB) atau jaringan Content Delivery Network (seperti Cloudflare).

Jika hal ini terjadi, koneksi TCP yang diterima oleh sistem operasi server Caddy bukan lagi berasal dari IP pengunjung asli, melainkan berasal dari IP internal Load Balancer atau IP publik Cloudflare. Akibatnya, matcher remote_ip bawaan Caddy akan membaca IP Load Balancer tersebut, menyebabkan aturan penyaringan kita menjadi tidak efektif (semua pengunjung dianggap memiliki IP yang sama).

Untuk mengatasinya, perantara proxy biasanya menyisipkan header HTTP X-Forwarded-For yang berisi alamat IP asli pengunjung. Namun, Caddy tidak akan membaca header ini secara otomatis karena header tersebut dapat dimanipulasi dengan mudah oleh penyerang (IP Spoofing) jika tidak divalidasi.

Kita wajib mengonfigurasi opsi trusted_proxies pada blok opsi global Caddy untuk mendaftarkan alamat IP Load Balancer/CDN kita. Begitu dikonfigurasi, Caddy akan memvalidasi koneksi dan secara aman mengekstrak IP asli pengunjung dari header X-Forwarded-For untuk digunakan pada matcher remote_ip:

# Konfigurasi opsi global Trusted Proxies
{
    servers {
        # Definisikan alamat IP proxy/load balancer yang kita percayai
        # Contoh: Seluruh subnet internal AWS VPC kita
        trusted_proxies static 10.0.0.0/8
        
        # Contoh: Jika menggunakan Cloudflare, daftarkan seluruh rentang IP publik Cloudflare
        # trusted_proxies static 103.21.244.0/22 103.22.200.0/22 104.16.0.0/13
    }
}

example.com {
    # Setelah trusted_proxies aktif, remote_ip akan membaca IP pengunjung asli
    # dari header X-Forwarded-For secara aman.
    @klien_jahat remote_ip 198.51.100.50
    respond @klien_jahat 403

    reverse_proxy backend:8080
}

[!WARNING] Jangan pernah memasukkan trusted_proxies static 0.0.0.0/0 (mempercayai semua IP di internet). Tindakan ini akan mengekspos server kita terhadap serangan IP Spoofing tingkat tinggi, di mana penyerang dapat mengirimkan request dengan memanipulasi header X-Forwarded-For kustom untuk berpura-pura sebagai IP internal perusahaan kita dan memotong seluruh aturan keamanan.


Mekanisme Pemblokiran Geografis (Geo-blocking) #

Membatasi akses berdasarkan letak geografis (negara) sangat berguna untuk melindungi website dari serangan spam masif atau menyelaraskan distribusi konten dengan aturan hukum hak cipta negara tertentu.

Ada dua pendekatan utama untuk mengonfigurasi Geo-blocking pada Caddy:

1. Memanfaatkan Header CDN (Cloudflare CF-IPCountry) #

Jika website kita menggunakan Cloudflare sebagai CDN, Cloudflare secara otomatis menyisipkan header respons CF-IPCountry yang berisi kode negara dua huruf ISO (misal ID, SG, US). Kita dapat menyaring request berdasarkan header ini secara langsung:

# Memblokir lalu lintas dari negara tertentu menggunakan header CDN
example.com {
    @negara_terblokir {
        # Blokir akses dari negara RU (Rusia) dan CN (Tiongkok)
        header CF-IPCountry RU
        header CF-IPCountry CN
    }
    
    respond @negara_terblokir "Akses dari wilayah Anda dibatasi." 403
    
    file_server
}

2. Menggunakan Database Geolocation Lokal (MaxMind GeoIP) #

Jika kita tidak menggunakan Cloudflare dan ingin melakukan pemetaan IP secara lokal mandiri (self-hosted), kita harus mengompilasi Caddy dengan plugin caddy-maxmind-geolocation dan mengunduh database GeoIP (.mmdb) dari MaxMind:

# Kompilasi Caddy dengan plugin MaxMind Geolocation
xcaddy build --with github.com/porech/caddy-maxmind-geolocation

Setelah terpasang, susun konfigurasi database pada Caddyfile:

# Filter menggunakan database MaxMind GeoIP lokal
example.com {
    @bukan_indonesia {
        # Evaluasi IP menggunakan modul MaxMind
        maxmind_geolocation {
            db_path /var/lib/GeoIP/GeoLite2-Country.mmdb
            # Balikkan logika: blokir jika negara BUKAN ID (Indonesia) atau SG (Singapura)
            not allow_countries ID SG
        }
    }
    
    respond @bukan_indonesia "Layanan ini hanya tersedia untuk wilayah Indonesia dan Singapura." 403
    
    reverse_proxy localhost:3000
}

Penulisan Log Khusus untuk Audit IP Terblokir #

Untuk mendeteksi pola serangan pemindaian bot dan memantau efektivitas aturan penyaringan kita, kita harus mencatat setiap request yang diblokir ke dalam berkas log keamanan khusus:

# Konfigurasi pencatatan log audit audit terpusat
example.com {
    # Daftar blokir IP
    @blocked_ip remote_ip 198.51.100.0/24

    # Buat sub-rute khusus untuk mencatat log sebelum membuang koneksi
    handle @blocked_ip {
        log {
            output file /var/log/caddy/security_blocks.log
            format json
        }
        respond "Forbidden" 403
    }

    # Lalu lintas normal
    root * /var/www/html
    file_server
}

Kita dapat menganalisis data log tersebut menggunakan perintah terminal standard:

# Memantau log pemblokiran IP secara real-time
tail -f /var/log/caddy/security_blocks.log | jq -r '"[\(.ts)] BLOCKED: \(.request.remote_addr) -> Jalur: \(.request.uri)"'

Pemblokiran IP Dinamis Berbasis Log (Scripted Auto-Blocking) #

Di lingkungan produksi yang mendapat serangan spam bertubi-tubi, kita dapat membuat skrip Bash otomatis yang berjalan di server sebagai cron job untuk memindai log akses utama Caddy, menyaring IP mencurigakan (misalnya IP yang memicu HTTP 4xx > 100 kali dalam 5 menit), lalu menulisnya ke dalam berkas blocklist Caddy secara dinamis:

#!/bin/bash
# caddy-auto-blocker.sh
# Menganalisis log akses Caddy dan memperbarui daftar blokir IP secara otomatis

LOG_FILE="/var/log/caddy/access.log"
BLOCK_LIST="/etc/caddy/blocklist.txt"
THRESHOLD=100
WINDOW_SECONDS=300

# 1. Deteksi IP mencurigakan yang menghasilkan status 4xx/5xx dalam 5 menit terakhir
SUSPICIOUS_IPS=$(cat "$LOG_FILE" | \
    jq -r 'select(.ts > (now - '"$WINDOW_SECONDS"') and .status >= 400) | .request.remote_addr' | \
    cut -d: -f1 | sort | uniq -c | \
    awk -v t="$THRESHOLD" '$1 > t {print $2}')

if [ -z "$SUSPICIOUS_IPS" ]; then
    echo "Tidak ada aktivitas mencurigakan terdeteksi."
    exit 0
fi

echo "Mendeteksi alamat IP mencurigakan: $SUSPICIOUS_IPS"

# 2. Perbarui berkas blocklist
for ip in $SUSPICIOUS_IPS; do
    # Masukkan IP ke file jika belum terdaftar
    if ! grep -q "$ip" "$BLOCK_LIST" 2>/dev/null; then
        echo "Memasukkan $ip ke daftar blokir..."
        echo "remote_ip $ip" >> "$BLOCK_LIST"
    fi
done

# 3. Pemicu reload konfigurasi Caddy agar perubahan aktif
echo "Melakukan reload konfigurasi Caddy..."
sudo systemctl reload caddy

Di sisi Caddyfile, kita cukup mengimpor berkas blocklist.txt tersebut ke dalam named matcher:

# Mengimpor daftar blokir dari berkas eksternal
example.com {
    @klien_blacklist {
        # Import file yang di-update oleh script otomatis
        import /etc/caddy/blocklist.txt
    }
    respond @klien_blacklist "Akses Anda dibatasi karena aktivitas mencurigakan." 403

    file_server { root /var/www/html }
}

Mengamankan Webhook CI/CD Menggunakan Allowlist IP #

Jika website kita memiliki endpoint webhook (misalnya /webhooks/deploy) yang memicu proses deployment otomatis dari layanan Git eksternal seperti GitHub, kita harus membatasi akses endpoint tersebut agar hanya dapat dipanggil oleh alamat IP resmi GitHub.

Ini mencegah aktor luar mengirimkan request palsu untuk memicu looping proses build server kita:

# Proteksi endpoint webhook deployment
example.com {
    # Hanya izinkan akses webhook dari IP resmi GitHub Actions
    # (IP didapat dari endpoint metadata GitHub)
    @bukan_github {
        path /webhooks/deploy
        not remote_ip 192.30.252.0/22 185.199.108.0/22 140.82.112.0/20
    }
    respond @bukan_github "Unauthorized Webhook Source" 403

    # Rute normal
    reverse_proxy localhost:3000
}

Mencegah SSRF dengan Memblokir Akses Metadata Cloud #

Ketika kita menjalankan server Caddy di lingkungan cloud provider (seperti AWS EC2, Google Cloud, atau DigitalOcean), cloud provider menyediakan endpoint metadata internal yang dapat diakses oleh VM di alamat IP khusus 169.254.169.254 tanpa otentikasi. Endpoint ini berisi informasi sensitif mengenai kredensial IAM, token akses, dan konfigurasi VM.

Jika aplikasi backend kita memiliki celah keamanan Server-Side Request Forgery (SSRF) di mana pengguna dapat menginstruksikan server untuk melakukan request ke URL kustom, penyerang dapat mengeksploitasinya untuk membaca data metadata tersebut.

Kita dapat mengonfigurasi Caddy untuk bertindak sebagai perisai depan dengan memblokir request yang mencoba mengakses rentang IP metadata cloud tersebut:

# Mitigasi serangan SSRF Metadata Cloud
example.com {
    # Deteksi request yang mencoba mengarah ke IP Link-Local / Metadata
    @metadata_attack {
        path /proxy/* /fetch/*
        remote_ip 169.254.0.0/16
    }
    respond @metadata_attack "Akses ke jaringan lokal dilarang!" 403

    reverse_proxy localhost:8080
}

Ringkasan #

  • Matcher remote_ip: Gunakan pencocok remote_ip untuk membatasi akses berdasarkan alamat IP tunggal maupun subnet menggunakan notasi CIDR.
  • Strategi Allowlist: Untuk data sensitif (admin panel/metrics), selalu terapkan pola Allowlist (tolak semua, izinkan hanya IP tepercaya) menggunakan not remote_ip.
  • Konfigurasi Trusted Proxies: Jika Caddy berjalan di belakang CDN/Load Balancer, wajib konfigurasikan trusted_proxies pada opsi global agar Caddy dapat membaca IP pengunjung asli secara aman.
  • Geo-blocking Efisien: Lakukan pemblokiran geografis menggunakan header CF-IPCountry jika menggunakan Cloudflare, atau plugin MaxMind GeoIP untuk solusi mandiri.
  • Pencegahan SSRF: Lindungi infrastruktur cloud kita dengan memblokir request yang mengarah ke rentang IP metadata internal 169.254.0.0/16.
  • Audit Trail Log: Catat setiap request yang terblokir ke dalam file log terpisah (security_blocks.log) untuk dianalisis oleh skrip pencegahan serangan otomatis.

← Sebelumnya: Rate Limiting   Berikutnya: Security Headers →

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