Web Server dengan Nginx

Web Server dengan Nginx

Bitnesia • Aug 26, 2026 102 •EN

Zone file example.local yang kita buat di Bab 9 sudah menyimpan record www IN A 192.168.1.20, jadi nama domain itu sudah mengarah ke alamat yang benar. Masalahnya, DNS yang benar saja tidak otomatis berarti ada layanan yang berjalan di alamat tersebut. Buktikan sendiri dengan menjalankan perintah berikut dari komputer lain di jaringan yang sama.

curl http://192.168.1.20

Hasilnya bukan halaman web, melainkan pesan:

curl: (7) Failed to connect to 192.168.1.20 port 80: Connection refused

DNS memang sudah benar, tapi belum ada satu pun proses yang mendengarkan di port 80 pada IP tersebut. Tugas kita selanjutnya adalah menyalakan software yang benar-benar menjawab permintaan HTTP di alamat itu, dan Nginx adalah jawabannya. Bab ini membuka Bagian IV series, bagian yang membahas layanan web secara khusus.

Kita akan mulai dari instalasi dan struktur direktori konfigurasi Nginx, lalu membuat virtual host (server block) untuk domain example.local yang sudah terdaftar di DNS. Setelah itu, kita mempraktikkan cara menyajikan static content dan dasar reverse proxy ke aplikasi backend, sebelum menutup bab dengan cara membaca access log dan error log untuk kebutuhan verifikasi maupun troubleshooting sehari-hari.

12.1 Instalasi dan Struktur Konfigurasi Nginx

Nginx (dibaca "engine-x") adalah web server sekaligus reverse proxy yang awalnya ditulis oleh Igor Sysoev untuk mengatasi C10K problem, yaitu tantangan melayani puluhan ribu koneksi bersamaan tanpa membebani resource server secara berlebihan. Berbeda dari Apache yang secara tradisional membuat satu proses atau thread untuk setiap koneksi, Nginx memakai arsitektur event-driven yang jauh lebih hemat memori saat menangani banyak koneksi sekaligus. Karakteristik inilah yang membuat Nginx jadi pilihan populer, baik sebagai web server murni maupun sebagai reverse proxy di depan aplikasi backend, topik yang akan kita perdalam lagi di Bab 16.

12.1.1 Instalasi Nginx dari Repository Ubuntu

Ubuntu Server menyediakan Nginx langsung di repository resmi, sehingga instalasinya tidak berbeda dari paket lain yang sudah kita pasang di bab-bab sebelumnya.

Langkah Praktik

  1. Perbarui daftar paket, lalu pasang Nginx.
    sudo apt update
    sudo apt install nginx
    Perintah ini sebenarnya memasang nginx sebagai metapackage yang menarik salah satu varian, umumnya nginx-core yang ringan dan cukup untuk kebutuhan web server standar. Varian lain seperti nginx-full atau nginx-extras baru relevan jika kita butuh module tambahan yang tidak ikut dalam build inti.
  2. Berbeda dari chrony di Bab 11 yang sudah terpasang sejak awal, paket Debian/Ubuntu untuk Nginx otomatis mengaktifkan dan menjalankan service-nya begitu instalasi selesai. Konfirmasi statusnya.
    systemctl status nginx.service
  3. Buka akses port HTTP di UFW agar Visitor dari luar server bisa menjangkau Nginx.
    sudo ufw allow 80/tcp
  4. Uji dari komputer lain di jaringan yang sama, sekarang mengarah ke IP server tempat Nginx berjalan.
    curl http://192.168.1.20
    Jika berhasil, responsnya berupa halaman HTML sederhana berjudul "Welcome to nginx!", tanda Nginx sudah melayani request dengan konfigurasi bawaannya.

Verifikasi dan Troubleshooting

  • Periksa versi Nginx yang benar-benar terpasang, karena versi persis bisa berbeda tergantung kapan repository Ubuntu terakhir disinkronkan.
    nginx -v
  • Jika systemctl status menunjukkan service gagal start, penyebab paling umum adalah port 80 sudah dipakai proses lain. Periksa dengan:
    sudo ss -tlnp | grep :80
    Kasus ini sering terjadi kalau Apache (Bab 13) pernah dipasang lebih dulu di server yang sama. Kedua web server itu tidak bisa berjalan bersamaan di port yang sama tanpa konfigurasi khusus.
  • Jika curl dari komputer lain tetap gagal padahal service sudah active (running), cek ulang rule UFW.
    sudo ufw status

12.1.2 Anatomi Direktori Konfigurasi Nginx

Sebelum membuat konfigurasi sendiri, penting memahami dulu bagaimana file-file konfigurasi Nginx saling terhubung. Salah paham soal struktur ini adalah salah satu sumber troubleshooting paling sering di lapangan, terutama saat perubahan yang sudah disimpan ternyata tidak pernah benar-benar dibaca oleh Nginx.

Langkah Praktik

  1. Lihat isi file konfigurasi utama.
    cat /etc/nginx/nginx.conf
    Isinya kurang lebih seperti berikut, meski detail seperti worker_connections bisa sedikit berbeda tergantung versi paket yang terpasang.
    user www-data;
    worker_processes auto;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    
    events {
        worker_connections 768;
    }
    
    http {
        include /etc/nginx/mime.types;
        default_type application/octet-stream;
    
        access_log /var/log/nginx/access.log;
        error_log /var/log/nginx/error.log;
    
        gzip on;
    
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
    }
    Dua baris include terakhir pada blok http adalah kunci untuk memahami struktur ini. Baris tersebut memberi tahu Nginx untuk membaca setiap file di /etc/nginx/conf.d/ dan setiap file di /etc/nginx/sites-enabled/ sebagai bagian dari konfigurasi aktif.
  2. Lihat isi kedua direktori tersebut.
    ls -la /etc/nginx/sites-available/
    ls -la /etc/nginx/sites-enabled/

/etc/nginx/sites-available/ berisi semua file konfigurasi virtual host yang pernah kita buat, aktif maupun tidak, sedangkan /etc/nginx/sites-enabled/ hanya berisi symbolic link yang menunjuk balik ke file-file tertentu di sites-available. Konvensi dua direktori ini sebenarnya bukan fitur bawaan Nginx, melainkan konvensi packaging khas Debian dan Ubuntu untuk memudahkan kita mengaktifkan atau menonaktifkan sebuah site cukup dengan menambah atau menghapus symlink, tanpa perlu menghapus file konfigurasinya sama sekali. Server block bawaan bernama default sudah aktif sejak awal, itulah yang tadi menjawab curl kita dengan halaman "Welcome to nginx!", dan isinya disajikan dari /var/www/html.

Verifikasi dan Troubleshooting

  • Setiap kali mengubah konfigurasi Nginx, biasakan menguji sintaksnya lebih dulu sebelum diterapkan. Kebiasaan ini akan terus kita pakai di seluruh bagian bab ini.
    sudo nginx -t
    Output yang sehat menunjukkan syntax is ok dan test is successful. Jika ada baris yang salah, pesan errornya biasanya sudah menyebutkan nama file dan nomor baris yang bermasalah, jadi tidak perlu menebak-nebak.
  • Di lapangan, kesalahan paling umum pemula adalah mengedit file di sites-available tapi lupa membuat symlink-nya di sites-enabled, sehingga perubahan tidak pernah terbaca meski nginx -t tetap melaporkan sintaks valid.

12.2 Virtual Host (Server Block)

Di Nginx, satu blok konfigurasi yang mendefinisikan bagaimana sebuah domain dilayani disebut server block, istilah yang setara dengan virtual host di Apache (Bab 13). Server block memungkinkan satu server fisik atau satu IP address yang sama melayani banyak domain sekaligus, masing-masing dengan document root, konfigurasi, bahkan aplikasi backend yang berbeda. Mekanismenya mengandalkan header Host yang dikirim browser di setiap request HTTP, itulah cara Nginx tahu domain mana yang sedang diminta Visitor meski semuanya mengarah ke IP yang sama.

12.2.1 Membuat Server Block untuk example.local

Sekarang kita akan mengganti server block default bawaan dengan server block milik sendiri, yang benar-benar menyajikan halaman untuk domain example.local dan www.example.local sesuai record DNS yang sudah kita daftarkan di Bab 9.

Langkah Praktik

  1. Buat direktori document root khusus untuk domain ini, terpisah dari /var/www/html milik server block default.
    sudo mkdir -p /var/www/example.local/html
  2. Buat halaman index sederhana untuk pengujian.
    echo "<h1>Halaman example.local berjalan di Nginx</h1>" | sudo tee /var/www/example.local/html/index.html
  3. Samakan kepemilikan direktori dengan user yang dipakai worker process Nginx, yaitu www-data, sesuai baris user www-data; yang sudah kita lihat di nginx.conf.
    sudo chown -R www-data:www-data /var/www/example.local
  4. Buat file server block baru di sites-available.
    sudo nano /etc/nginx/sites-available/example.local
  5. Isi dengan konfigurasi berikut.
    server {
        listen 80;
        listen [::]:80;
    
        server_name example.local www.example.local;
        root /var/www/example.local/html;
        index index.html;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    Directive server_name menentukan domain mana yang ditangani server block ini, root menunjuk document root-nya, dan try_files pada blok location / memerintahkan Nginx mencari file sesuai $uri yang diminta, mencoba sebagai direktori jika file tidak ditemukan, lalu mengembalikan 404 apabila keduanya tetap tidak ada.
  6. Aktifkan server block ini dengan membuat symlink ke sites-enabled.
    sudo ln -s /etc/nginx/sites-available/example.local /etc/nginx/sites-enabled/
  7. Nonaktifkan server block default agar tidak lagi menjadi fallback yang membingungkan saat kita menambah domain lain nanti.
    sudo rm /etc/nginx/sites-enabled/default
    File aslinya di sites-available/default tetap dibiarkan ada sebagai referensi, hanya symlink aktifnya yang dihapus.
  8. Uji sintaks, lalu terapkan perubahan.
    sudo nginx -t
    sudo systemctl reload nginx
    Gunakan reload, bukan restart, untuk perubahan konfigurasi rutin seperti ini. reload membuat Nginx membaca ulang konfigurasi tanpa memutus koneksi yang sedang berlangsung, sedangkan restart mematikan dulu seluruh proses sebelum menyalakannya kembali, yang berisiko menyebabkan jeda singkat pada layanan production.
  9. Uji dari komputer lain di jaringan yang sama, kali ini lewat nama domain karena DNS internal dari Bab 9 sudah mengenalinya.
    curl http://www.example.local

Verifikasi dan Troubleshooting

  • Jika muncul error [emerg] "server" directive is not allowed here saat nginx -t, penyebab paling umum adalah kurung kurawal yang tidak seimbang di file konfigurasi.
  • Jika curl masih mengembalikan halaman "Welcome to nginx!" alih-alih halaman example.local, kemungkinan besar symlink ke sites-enabled/default belum benar-benar terhapus, atau reload belum dijalankan setelah perubahan.
  • Untuk client yang belum sempat menyinkronkan cache DNS-nya, uji langsung ke IP dengan header Host manual agar tidak perlu menunggu propagasi.
    curl -H "Host: www.example.local" http://192.168.1.20

12.2.2 Multiple Virtual Host Berbasis Nama Domain

Kekuatan sebenarnya dari server block terlihat saat satu server melayani lebih dari satu domain. Skema ini disebut name-based virtual hosting, karena Nginx membedakan setiap domain murni berdasarkan header Host, bukan berdasarkan IP address atau nomor port yang berbeda-beda.

Langkah Praktik

  1. Siapkan document root untuk domain kedua, misalnya blog.example.local.
    sudo mkdir -p /var/www/blog.example.local/html
    echo "<h1>Blog example.local</h1>" | sudo tee /var/www/blog.example.local/html/index.html
    sudo chown -R www-data:www-data /var/www/blog.example.local
  2. Buat server block baru untuk domain ini.
    sudo nano /etc/nginx/sites-available/blog.example.local
    server {
        listen 80;
        listen [::]:80;
    
        server_name blog.example.local;
        root /var/www/blog.example.local/html;
        index index.html;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
  3. Aktifkan, uji, dan terapkan seperti sebelumnya.
    sudo ln -s /etc/nginx/sites-available/blog.example.local /etc/nginx/sites-enabled/
    sudo nginx -t
    sudo systemctl reload nginx
  4. Domain blog.example.local belum punya record di zone file Bab 9, jadi tambahkan dulu record A baru mengikuti pola yang sama dengan record www yang sudah ada, lalu naikkan nomor Serial di SOA dan reload BIND9.
    blog	IN	A	192.168.1.20
    Untuk pengujian cepat tanpa menyentuh DNS server sama sekali, curl juga mendukung resolusi nama secara manual lewat flag --resolve, cocok dipakai saat kita hanya ingin memverifikasi server block tanpa mengubah zone file lebih dulu.
    curl --resolve blog.example.local:80:192.168.1.20 http://blog.example.local/

Verifikasi dan Troubleshooting

  • Bandingkan hasil curl http://www.example.local dan curl http://blog.example.local dari IP server yang sama persis. Konten yang berbeda pada kedua domain itu membuktikan Nginx benar-benar memilih server block berdasarkan header Host, bukan sekadar menyajikan satu konfigurasi yang sama untuk semua request.
  • Jika dua server block punya server_name yang sama secara tidak sengaja, Nginx tetap berjalan tanpa error saat nginx -t, tetapi hanya server block yang didefinisikan lebih dulu (berdasarkan urutan baca file) yang benar-benar dipakai. Hal ini adalah jebakan klasik yang sering luput dari perhatian karena tidak memunculkan pesan error apa pun.

12.3 Serving Static Content dan Reverse Proxy Dasar

Server block yang sudah kita buat sejauh ini menyajikan file statis apa adanya. Bagian ini memperdalam sedikit cara Nginx menyajikan static content, lalu masuk ke kemampuan yang membuat Nginx begitu populer di arsitektur modern: berperan sebagai reverse proxy di depan aplikasi backend.

12.3.1 Serving Static Content: root, alias, dan Halaman Error Kustom

Dua directive yang sering tertukar pemula adalah root dan alias. Directive root menempelkan path location di belakang path filesystem, sedangkan alias menggantikannya sepenuhnya. Salah pilih di antara keduanya adalah penyebab umum error 404 yang membingungkan meski file-nya sebenarnya ada di disk.

Langkah Praktik

  1. Buat halaman error kustom sederhana untuk status 404.
    echo "<h1>Halaman tidak ditemukan di example.local</h1>" | sudo tee /var/www/example.local/html/404.html
  2. Tambahkan directive error_page ke dalam server block example.local.
    sudo nano /etc/nginx/sites-available/example.local
    error_page 404 /404.html;
    location = /404.html {
        internal;
    }
    Directive internal memastikan halaman ini hanya bisa dicapai lewat mekanisme internal redirect milik Nginx sendiri, bukan diakses langsung oleh Visitor lewat URL /404.html.
  3. Terapkan dan uji.
    sudo nginx -t
    sudo systemctl reload nginx
    curl -i http://www.example.local/halaman-yang-tidak-ada

Verifikasi dan Troubleshooting

  • Pada output curl -i, perhatikan baris status pertama. Baris tersebut seharusnya tetap menunjukkan HTTP/1.1 404 Not Found meski isi halamannya sudah berupa halaman error kustom, bukan halaman 404 bawaan Nginx yang polos.
  • Di lapangan, kesalahan yang cukup sering muncul adalah menaruh directive root yang berbeda di dalam blok location tertentu, padahal maksudnya memakai alias. Kombinasi root /var/www/example.local/html; location /assets { root /var/www/shared; } tetap menempelkan /assets di belakang path root-nya, sehingga file yang benar-benar dicari adalah /var/www/shared/assets/..., bukan /var/www/shared/... seperti yang sering diasumsikan.

12.3.2 Reverse Proxy ke Aplikasi Backend

Sebagai reverse proxy, Nginx menerima request dari Visitor lalu meneruskannya ke aplikasi backend yang berjalan di port lain, kemudian meneruskan kembali responsnya ke Visitor seolah-olah Nginx sendiri yang menjawab. Pola ini sangat umum dipakai Developer untuk aplikasi Node.js, Python, atau Java yang punya application server sendiri, tapi tidak dirancang untuk menghadapi traffic publik secara langsung. Bab 16 nanti akan memperluas topik ini sampai ke load balancing beberapa backend sekaligus, sedangkan di sini kita fokus dulu pada mekanisme dasarnya dengan satu backend saja.

Langkah Praktik

  1. Untuk menguji mekanisme reverse proxy tanpa perlu men-deploy aplikasi sungguhan, jalankan HTTP server sederhana bawaan Python sebagai backend tiruan yang hanya mendengarkan di localhost.
    mkdir -p ~/demo-backend && cd ~/demo-backend
    echo "Halo dari backend port 8080" > index.html
    python3 -m http.server 8080 --bind 127.0.0.1
    Biarkan perintah ini berjalan di satu sesi terminal atau tmux (Bab 3) tersendiri, karena prosesnya berjalan di foreground.
  2. Di terminal lain, tambahkan blok location baru pada server block example.local yang meneruskan request ke backend tersebut.
    sudo nano /etc/nginx/sites-available/example.local
    location /app/ {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
  3. Terapkan dan uji.
    sudo nginx -t
    sudo systemctl reload nginx
    curl http://www.example.local/app/
    Responsnya seharusnya menampilkan isi index.html dari backend Python tadi, padahal Visitor hanya berkomunikasi dengan Nginx di port 80.

Tiga directive proxy_set_header di atas bukan sekadar formalitas. Tanpa Host, backend menerima Host: 127.0.0.1 alih-alih nama domain asli yang diminta Visitor, yang bisa merusak aplikasi yang membangun URL absolut berdasarkan header ini. Tanpa X-Real-IP dan X-Forwarded-For, log aplikasi backend hanya akan mencatat IP Nginx itu sendiri (127.0.0.1) sebagai sumber semua request, bukan IP Visitor yang sebenarnya, yaitu masalah yang baru terasa saat Sysadmin butuh menelusuri sumber traffic mencurigakan atau serangan brute-force di backend.

Verifikasi dan Troubleshooting

  • Error 502 Bad Gateway hampir selalu berarti Nginx tidak bisa menghubungi backend di proxy_pass. Pastikan proses backend-nya masih berjalan.
    ss -tlnp | grep 8080
  • Perhatikan tanda garis miring (/) di akhir path pada location /app/ dan proxy_pass http://127.0.0.1:8080/. Kombinasi garis miring di kedua sisi ini membuat Nginx menghapus prefix /app/ sebelum meneruskan request ke backend. Jika salah satu garis miring dihilangkan, prefix tersebut justru ikut terbawa ke backend, dan hasilnya sering berupa 404 yang membingungkan karena terlihat benar di konfigurasi tapi salah pada praktiknya.

12.4 Log Access dan Error

Dua file log adalah sumber informasi utama saat kita perlu memverifikasi traffic atau menelusuri masalah pada Nginx, jauh lebih cepat dibanding menebak-nebak dari gejala di sisi client.

12.4.1 Membaca Access Log dan Error Log

Access log mencatat setiap request yang berhasil diterima Nginx, sedangkan error log mencatat kejadian di luar kondisi normal, mulai dari warning ringan sampai kegagalan proxy ke backend. Secara default, keduanya tersimpan di /var/log/nginx/access.log dan /var/log/nginx/error.log, sesuai directive access_log dan error_log yang sudah kita lihat di nginx.conf pada Bagian 12.1.2.

Langkah Praktik

  1. Pantau access log secara real-time di satu sesi terminal.
    sudo tail -f /var/log/nginx/access.log
  2. Dari terminal lain, kirim beberapa request ke server, lalu perhatikan baris baru yang muncul di access log.
    curl http://www.example.local
    curl http://www.example.local/halaman-yang-tidak-ada
    Setiap baris log kurang lebih berformat seperti berikut, mengikuti log format combined yang jadi standar de facto banyak web server.
    192.168.1.5 - - [26/Aug/2026:10:15:03 +0700] "GET / HTTP/1.1" 200 512 "-" "curl/8.5.0"
    Urutan field-nya adalah IP client, identitas remote user (biasanya - karena jarang dipakai), timestamp, baris request lengkap, HTTP status code, ukuran response dalam byte, referer, dan terakhir user agent.
  3. Tekan Ctrl+C untuk menghentikan tail -f, lalu lihat error log untuk membandingkan.
    sudo tail -n 20 /var/log/nginx/error.log

Verifikasi dan Troubleshooting

  • Kolom status code di access log adalah titik awal paling cepat untuk menilai kesehatan traffic secara kasar. Rentetan 5xx yang tiba-tiba muncul biasanya menandakan masalah di sisi server atau backend, sedangkan lonjakan 4xx, terutama 404, sering menandakan link rusak atau Attacker yang sedang melakukan scanning path-path umum secara serampangan.
  • Jika ingin memisahkan log per domain agar lebih mudah dianalisis, tambahkan directive access_log dan error_log sendiri di dalam server block tertentu, menimpa pengaturan global di nginx.conf.
    access_log /var/log/nginx/example.local.access.log;
    error_log /var/log/nginx/example.local.error.log;

12.4.2 Level Error Log dan Rotasi Log

Directive error_log menerima parameter level opsional yang mengatur seberapa detail pesan yang dicatat, berurutan dari yang paling ringan ke paling kritis: debug, info, notice, warn, error, crit, alert, dan emerg. Level bawaan adalah error, cukup untuk operasional harian, tapi terlalu minim saat kita sedang menelusuri bug yang sulit direproduksi.

Langkah Praktik

  1. Naikkan sementara level error log ke debug saat butuh detail maksimal untuk troubleshooting, misalnya pada server block example.local yang sedang bermasalah.
    error_log /var/log/nginx/example.local.error.log debug;
    Level debug hanya berfungsi jika binary Nginx dikompilasi dengan opsi --with-debug. Cek dulu dengan nginx -V sebelum mengandalkan level ini, dan jangan lupa mengembalikannya ke warn atau error setelah selesai, karena level debug menghasilkan volume log yang sangat besar dan cepat memenuhi disk pada server production.
  2. Pastikan rotasi log sudah berjalan otomatis, karena tanpa rotasi, access.log dan error.log akan terus membesar tanpa batas.
    cat /etc/logrotate.d/nginx

Verifikasi dan Troubleshooting

  • Paket nginx dari repository Ubuntu sudah menyertakan konfigurasi logrotate ini secara default, umumnya berjalan harian dan menyimpan beberapa hari riwayat sebelum file lama dihapus atau dikompresi. Pembahasan lebih dalam soal strategi retensi log lintas server akan kita bahas di Bab 39.
  • Jika disk server tiba-tiba penuh dan dugaan mengarah ke log Nginx, periksa dulu ukurannya sebelum menyalahkan volume traffic.
    sudo du -sh /var/log/nginx/*

Sampai di sini, Nginx sudah berjalan sebagai web server yang benar-benar menjawab domain example.local dan blog.example.local, lengkap dengan static content, reverse proxy dasar ke backend, serta access log dan error log yang siap kita baca kapan pun dibutuhkan. Bab 13 akan membahas Apache sebagai alternatif web server yang masih banyak dipakai di berbagai infrastruktur, sekaligus membandingkannya dengan Nginx supaya kita punya dasar yang jelas untuk memilih salah satunya sesuai kebutuhan.