Directive & Context

Directive & Context #

Ketika kita pertama kali membuka file konfigurasi Nginx, tampilannya mungkin terlihat familiar jika kita terbiasa dengan bahasa pemrograman terstruktur, tetapi terasa asing jika kita membandingkannya dengan format file konfigurasi key-value sederhana seperti INI atau YAML. Sintaksis Nginx bukanlah sekadar daftar variabel statis, melainkan sebuah Domain-Specific Language (DSL) deklaratif. DSL ini dibangun di atas dua pilar utama yang mendefinisikan perilakunya: Directive (instruksi tindakan) dan Context (ruang lingkup cakupan).

Memahami interaksi antara directive dan context, serta bagaimana nilai konfigurasi mengalir di antara mereka, adalah kunci untuk menulis konfigurasi Nginx yang aman, efisien, dan bebas bug. Artikel ini akan membedah anatomi directive, mengeksplorasi hierarki context global Nginx, serta mengupas tuntas aturan pewarisan (inheritance rules) yang sering kali menjadi jebakan bagi administrator sistem pemula.

Anatomi Directive: Instruksi Kerja Nginx #

Setiap baris instruksi konfigurasi di Nginx yang berada di luar kurung kurawal disebut sebagai Directive. Directive adalah perintah tunggal yang memberitahu Nginx apa yang harus dilakukan atau nilai apa yang harus dipasang untuk parameter tertentu.

Sintaksis Dasar Directive #

Sintaks penulisan directive sangat ketat dan wajib mengikuti aturan berikut:

# Format: nama_directive argumen1 [argumen2 ...];
worker_processes auto;
keepalive_timeout 65;

Ada tiga bagian utama dari setiap directive:

  1. Nama Directive: Kata kunci yang dikenali oleh modul Nginx (seperti root, listen, server_name).
  2. Argumen: Nilai yang diberikan kepada directive. Argumen dapat berupa nilai tunggal, beberapa nilai terpisah spasi, atau parameter konfigurasi kompleks.
  3. Titik Koma (Semicolon ;): Setiap directive wajib diakhiri dengan tanda titik koma. Jika kita lupa menuliskan titik koma di akhir baris, Nginx akan mendeteksi baris berikutnya sebagai argumen tambahan dari baris sebelumnya dan mengeluarkan error fatal saat kita menjalankan nginx -t.

Jenis-Jenis Format Argumen #

Argumen pada directive Nginx dapat berupa berbagai tipe data:

  • Nilai Waktu: Digunakan untuk timeout atau durasi cache. Nginx menggunakan satuan default (biasanya detik) jika kita hanya menuliskan angka, tetapi mendukung satuan waktu eksplisit:
    • ms: milidetik (e.g., client_body_timeout 500ms;)
    • s: detik (e.g., keepalive_timeout 65s;)
    • m: menit (e.g., proxy_read_timeout 5m;)
    • h: jam (e.g., expires 1h;)
    • d: hari (e.g., expires 30d;)
    • w: minggu, M: bulan, y: tahun.
  • Nilai Ukuran Data: Digunakan untuk pembatasan buffer memori atau ukuran berkas:
    • k atau K: kilobyte (e.g., client_body_buffer_size 16k;)
    • m atau M: megabyte (e.g., client_max_body_size 50m;)
    • g atau G: gigabyte (e.g., proxy_max_temp_file_size 1g;)
  • Multiple Arguments dengan Makna Berbeda:
    # Mengikat port 443, mengaktifkan enkripsi SSL, dan mengoptimalkan backlog socket
    listen 443 ssl backlog=2048;
    

Anatomi Context Block: Ruang Lingkup Eksekusi #

Context adalah blok konfigurasi yang dibatasi oleh sepasang kurung kurawal { ... }. Context bertindak sebagai ruang lingkup (scope) yang membungkus kumpulan directive. Karakteristik utama dari context adalah ia mendefinisikan di mana dan dalam kondisi apa directive yang dibungkusnya dapat diterapkan.

Sebagai contoh:

http {
    # Directive 'gzip' berada di dalam context 'http'
    gzip on;

    server {
        # Directive 'listen' berada di dalam context 'server'
        listen 80;
        
        location /images/ {
            # Directive 'root' berada di dalam context 'location'
            root /var/www;
        }
    }
}

Di dalam Nginx, tidak semua directive dapat diletakkan di sembarang tempat. Setiap directive memiliki batasan context (context constraint) yang didefinisikan oleh modul pembuatnya. Misalnya, directive proxy_pass hanya valid diletakkan di dalam context location atau blok limit_except. Jika kita mencoba menulis proxy_pass langsung di dalam context http atau server, Nginx akan menolak berjalan dengan pesan error: "[emerg] \"proxy_pass\" directive is not allowed here".


Hierarki Context Utama Nginx #

Nginx memiliki struktur hierarki context yang tetap dan sangat terorganisir. Context tingkat atas tidak boleh saling bersilangan secara acak. Berikut adalah diagram pohon hierarki context utama di Nginx:

flowchart TD
    Main["Main Context <br> (Global Scope / Lepas Blok)"]
    
    Main --> Events["events { } <br> (Network Connection Loop)"]
    Main --> HTTP["http { } <br> (Web Server Engine)"]
    Main --> Stream["stream { } <br> (TCP/UDP Proxy & Load Balancer)"]
    Main --> Mail["mail { } <br> (Email Proxy - IMAP/POP3/SMTP)"]
    
    HTTP --> UpstreamHTTP["upstream { } <br> (Backend Server Pool)"]
    HTTP --> ServerHTTP1["server { } <br> (Virtual Host A)"]
    HTTP --> ServerHTTP2["server { } <br> (Virtual Host B)"]
    
    ServerHTTP1 --> Loc1["location / { } <br> (Prefix Path /)"]
    ServerHTTP1 --> Loc2["location /api/ { } <br> (Prefix Path /api/)"]
    Loc2 --> NestedLoc["location /api/admin/ { } <br> (Nested Location)"]
    
    Stream --> UpstreamStream["upstream { } <br> (L4 Backend Pool)"]
    Stream --> ServerStream["server { } <br> (L4 Port Forwarder)"]
    
    style Main stroke:#0288d1,stroke-width:2.5px
    style HTTP stroke:#388e3c,stroke-width:2px
    style Stream stroke:#f57c00,stroke-width:2px

Mari kita ulas peran dan fungsi dari masing-masing context utama tersebut:

1. Main Context (Global Scope) #

Ini adalah context tingkat teratas. Context ini tidak ditandai oleh kurung kurawal apapun; ia mencakup seluruh baris konfigurasi yang kita tulis langsung di baris terluar berkas nginx.conf.

  • Fungsi: Mengonfigurasi parameter sistem operasi tingkat rendah seperti user OS yang menjalankan proses (user), batasan file descriptor sistem, CPU core binding (worker_cpu_affinity), dan inisialisasi PID log.

2. Events Context #

Blok events { ... } terletak di dalam main context dan hanya boleh ada satu blok per konfigurasi.

  • Fungsi: Mengatur bagaimana worker process Nginx berinteraksi dengan kernel untuk menangani koneksi baru (misal, menentukan modul event loop epoll atau kqueue, dan kapasitas koneksi per worker worker_connections).

3. HTTP Context #

Blok http { ... } adalah jantung dari Nginx sebagai web server dan HTTP reverse proxy.

  • Fungsi: Menentukan aturan pemrosesan protokol HTTP global (seperti MIME types, kompresi Gzip, format access log, server header security, SSL/TLS defaults, dan inisialisasi upstream cache paths).

4. Server Context (Virtual Host) #

Blok server { ... } didefinisikan di dalam http context. Kita dapat memiliki puluhan hingga ratusan server block untuk membedakan domain.

  • Fungsi: Mewakili satu virtual host (situs web atau API). Context ini bertanggung jawab memetakan IP address, port jaringan, dan nama domain (server_name) yang dilayani situs tersebut.

5. Location Context (Request Routing) #

Blok location { ... } didefinisikan di dalam server context atau di dalam location context lainnya (nested).

  • Fungsi: Mengarahkan request ke lokasi file fisik di disk (root/alias), memproses file melalui proxy backend (proxy_pass), atau menerapkan pembatasan akses khusus untuk URI path tertentu.

6. Upstream Context (Load Balancing) #

Blok upstream { ... } digunakan untuk mendefinisikan kumpulan server backend.

  • Fungsi: Mengelompokkan IP address atau domain server aplikasi backend (seperti kluster Node.js, PHP-FPM, atau Go), serta menentukan algoritma load balancing yang digunakan (seperti Round Robin, Least Connections, atau IP Hash).

7. Stream Context (Layer 4 Proxy) #

Blok stream { ... } adalah modul transport-level proxy (Layer 4 TCP/UDP) yang berjalan sejajar dengan HTTP context.

  • Fungsi: Digunakan untuk melakukan proxying dan load balancing trafik non-HTTP, seperti koneksi database MySQL/PostgreSQL, Redis cache, port LDAP, atau traffic DNS.

Aturan Pewarisan Nilai (Inheritance Rules) #

Bagaimana Nginx memutuskan nilai suatu parameter jika parameter tersebut didefinisikan di beberapa context yang berbeda? Proses ini diatur oleh Aturan Pewarisan Konfigurasi. Nginx mengalirkan konfigurasi dari atas ke bawah (dari parent context ke child context).

Namun, ada tiga perilaku pewarisan yang berbeda tergantung dari jenis directive-nya. Mengabaikan perbedaan perilaku ini sering kali menjadi penyebab utama hilangnya header keamanan atau kesalahan alur proxy pada server production.

flowchart TD
    Start["Request Masuk ke Location Context"] --> TypeCheck{"Evaluasi Tipe Directive"}
    
    TypeCheck -->|"1. Simple Directive"| SimpleInherit{"Apakah didefinisikan <br> di tingkat Child (location)?"}
    SimpleInherit -->|"Ya"| SimpleOverride["Abaikan nilai Parent. <br> Gunakan nilai di tingkat Child secara penuh."]
    SimpleInherit -->|"Tidak"| SimpleParent["Warisi nilai dari Parent <br> (HTTP / Server context)"]
    
    TypeCheck -->|"2. Array Directive"| ArrayInherit{"Apakah ada deklarasi baru <br> di tingkat Child?"}
    ArrayInherit -->|"Ya"| ArrayReplace["Abaikan SELURUH daftar parent! <br> Gunakan hanya daftar baru di tingkat Child."]
    ArrayInherit -->|"Tidak"| ArrayParent["Warisi seluruh daftar <br> array dari Parent"]
    
    TypeCheck -->|"3. Action/Handler Directive"| HandlerCheck["Directive dieksekusi langsung <br> (misal: return, proxy_pass). <br> Mengabaikan pewarisan handler di atasnya."]
    
    style TypeCheck stroke:#0288d1,stroke-width:2px
    style ArrayInherit stroke:#f57c00,stroke-width:2px
    style SimpleInherit stroke:#388e3c,stroke-width:2px

Mari kita bahas ketiga kategori directive ini secara mendalam:

1. Simple Directive (Pewarisan dengan Override) #

Simple directive adalah directive yang hanya menerima satu nilai per baris konfigurasi.

  • Aturan Pewarisan: Jika child context tidak mendefinisikan directive tersebut, ia akan mewarisi nilai dari parent context. Namun, jika child context mendefinisikan directive tersebut, nilai dari parent context akan ditimpa (overridden) sepenuhnya.
http {
    # 1. Didefinisikan secara global di level HTTP
    client_max_body_size 10m;

    server {
        listen 80;
        server_name example.com;
        # server block ini tidak menulis client_max_body_size,
        # maka ia mewarisi nilai 10m dari http context.

        location /api/upload/ {
            # 2. Override khusus untuk path upload berkas
            client_max_body_size 100m;
            # Nilai 10m dari parent (http) ditimpa menjadi 100m.
        }

        location /static/ {
            # path ini mewarisi nilai default server (10m)
        }
    }
}

2. Array Directive (Pewarisan “Bersihkan-dan-Ganti”) #

Array directive adalah jenis directive yang dapat didefinisikan beberapa kali dalam satu context untuk membangun sebuah daftar nilai (seperti add_header, error_log, access_log, index).

  • Aturan Pewarisan (Gotcha Terbesar!): Jika child context tidak mendefinisikan array directive tersebut sama sekali, ia akan mewarisi seluruh daftar dari parent context. Namun, jika child context mendefinisikan satu saja array directive sejenis, seluruh daftar array dari parent context akan dibersihkan (cleared) dan tidak diwariskan sama sekali. Nilai baru di child context akan menggantikan daftar parent secara utuh, bukan menambahkannya (replacement, not addition).

Mari kita lihat contoh kasus nyata yang sangat sering membocorkan keamanan situs:

http {
    # Kita memasang header keamanan global di tingkat HTTP
    add_header X-Frame-Options "DENY";
    add_header X-Content-Type-Options "nosniff";
    add_header Content-Security-Policy "default-src 'self'";

    server {
        listen 80;
        server_name example.com;

        # Server block ini mewarisi ke-3 header di atas secara otomatis

        location / {
            try_files $uri $uri/ =404;
        }

        location /api/ {
            # KEBOCORAN KEAMANAN: Kita ingin menambahkan header debugging khusus API
            add_header X-API-Debug "true";
            
            # Dampak Fatal:
            # Karena kita menulis 'add_header' di location ini, Nginx MENGHAPUS
            # seluruh header X-Frame-Options, X-Content-Type-Options, dan CSP
            # dari tingkat http! Request ke /api/ kini sama sekali tidak terlindungi.
            
            proxy_pass http://api_backend;
        }
    }
}

Solusi yang Benar untuk Array Directive: #

Untuk memastikan child context tetap aman tanpa kehilangan konfigurasi global, kita wajib mendeklarasikan ulang array tersebut secara lengkap di child context, atau memindahkan deklarasi ke berkas snippet dan meng-include-nya kembali:

        location /api/ {
            # Tulis kembali header keamanan global
            add_header X-Frame-Options "DENY";
            add_header X-Content-Type-Options "nosniff";
            add_header Content-Security-Policy "default-src 'self'";
            
            # Tambahkan header kustom baru
            add_header X-API-Debug "true";
            
            proxy_pass http://api_backend;
        }

3. Action / Handler Directive #

Action directive adalah instruksi yang memicu tindakan pemrosesan konten (seperti return, rewrite, proxy_pass, fastcgi_pass).

  • Aturan Pewarisan: Action directive tidak diwariskan. Nginx mengeksekusi request di dalam context yang paling spesifik (biasanya location block terdalam). Jika location block terdalam memiliki handler (misal proxy_pass), maka handler di parent context (seperti return 301 di server context) diabaikan atau dijalankan di fase rewrite sebelum location dicocokkan.

Studi Kasus Kesalahan Pewarisan & Solusinya #

Berikut adalah beberapa kesalahan konfigurasi nyata yang sering dijumpai akibat salah memahami alur context dan pewarisan:

Kasus 1: Pewarisan Directive index yang Menyebabkan File Tidak Ditemukan #

Banyak pembuat konfigurasi berpikir bahwa directive index bertindak secara aditif (menambahkan opsi file indeks ke daftar pencarian).

# ANTI-PATTERN
http {
    index index.html index.htm;

    server {
        listen 80;
        server_name example.com;
        
        # Kita ingin menambahkan index.php untuk virtual host ini
        index index.php;
        
        # Kesalahan: Nginx menghapus 'index.html' dan 'index.htm' dari daftar pencarian.
        # Nginx hanya mencari 'index.php'. Jika index.php tidak ada, Nginx langsung 
        # mengembalikan error 403 Forbidden (jika autoindex off).
    }
}

Solusi yang Benar: #

Deklarasikan daftar file pencarian secara urut dan lengkap dari kiri ke kanan:

# BENAR
server {
    listen 80;
    server_name example.com;
    index index.php index.html index.htm;
}

Kasus 2: Pewarisan access_log yang Membocorkan Log Sensitif #

Kita ingin menyetel logging global untuk semua site, tetapi mematikan logging untuk direktori gambar statis dan file sensitif agar tidak memenuhi kapasitas disk.

# BENAR
http {
    # Set log akses default global
    access_log /var/log/nginx/access.log main;

    server {
        listen 80;
        server_name example.com;

        # 1. Mewarisi log akses global
        location / {
            try_files $uri $uri/ =404;
        }

        # 2. Matikan log akses untuk static images demi performa I/O
        location ~* \.(jpg|jpeg|png|gif|ico)$ {
            access_log off;
            expires 30d;
        }

        # 3. Alihkan log untuk area admin ke file terpisah
        location /admin/ {
            access_log /var/log/nginx/admin_access.log main;
            # Ini secara otomatis menimpa (override) log default global,
            # sehingga request ke /admin/ tidak akan ditulis ke access.log utama.
        }
    }
}

Ringkasan #

  • Anatomi Directive: Wajib diakhiri dengan titik koma (;). Mendukung argumen kustom untuk waktu (s, m, h, d) dan kapasitas memori (k, m, g).
  • Hierarki Context: Terstruktur secara ketat dari Global Scope (main) → Event Loop (events) → Web Engine (http) → Virtual Host (server) → Request Path (location).
  • Simple Directive Inheritance: Nilai parent diwariskan ke bawah secara otomatis, tetapi dapat ditimpa (override) sepenuhnya di child context.
  • Array Directive Inheritance Trap: Menulis satu saja directive array (seperti add_header, index, error_log) di child context akan menghapus seluruh daftar array sejenis yang diwarisi dari parent context.
  • nginx -T adalah alat terbaik untuk memverifikasi seluruh konfigurasi gabungan aktif di memori RAM dan mendeteksi kesalahan pewarisan sebelum server direload.

← Sebelumnya: Struktur File Config   Berikutnya: Server Block →

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