Web server adalah daemon yang pekerjaannya menjawab percakapan HTTP: klien mengirim permintaan, server membalas dengan berkas, pengalihan, atau kode error. Di balik kesederhanaan itu tersimpan keputusan-keputusan penting yang menentukan arsitektur server kita — bagaimana satu IP melayani banyak domain, dari mana konten dihasilkan, dan mengapa memilih Nginx atau Apache. Sebelum memasang keduanya di chapter berikutnya, chapter ini membedah bahasa yang mereka bicarakan. Karena paket web server tidak terpasang di lingkungan latihan, kita memakai server mini python3 -m http.server — web server sungguhan yang kebetulan sederhana — untuk menyaksikan protokolnya bekerja langsung.

Anatomi Percakapan HTTP #

Sebuah permintaan HTTP berisi tiga hal: method (aksi yang diminta, paling sering GET), path (lokasi sumber daya seperti /halaman.html), dan sekumpulan header (metadata, salah satunya Host). Server membalas dengan baris status, header miliknya, lalu isi dokumen. Kode status adalah ringkasan nasib permintaan itu, dan empat angka berikut akan muncul terus-menerus di pekerjaan admin:

KodeNamaArti
200OKpermintaan berhasil, isi dokumen dikirim
301Moved Permanentlyalamat berpindah permanen, klien dialihkan
404Not Foundsumber daya tidak ada di path yang diminta
500Internal Server Errorsisi server gagal memproses permintaan

Kita saksikan dua di antaranya langsung: satu permintaan ke berkas yang ada, satu ke berkas yang tidak ada. Opsi -I milik curl meminta hanya header balasan (metode HEAD), sedangkan -w '%{http_code}' mencetak kode status saja — format yang ramah untuk skrip:

bash
mkdir -p situs
printf '<h1>Situs Latihan</h1>\n' > situs/index.html
python3 -m http.server 8765 --bind 127.0.0.1 >/dev/null 2>&1 &
server=$!
for i in 1 2 3 4 5; do curl -s -o /dev/null 127.0.0.1:8765/ && break; sleep 0.2; done
curl -sI 127.0.0.1:8765/ | head -1
curl -sI 127.0.0.1:8765/hilang.html | head -1
curl -s -o /dev/null -w '%{http_code}\n' 127.0.0.1:8765/
curl -s -o /dev/null -w '%{http_code}\n' 127.0.0.1:8765/hilang.html
kill "$server"

Output yang Dihasilkan:

text
HTTP/1.0 200 OK
HTTP/1.0 404 File not found
200
404

Mari kita bedah baris demi baris:

  1. Baris 1–2 (mkdir dan printf): menyiapkan akar dokumen berisi satu index.html — inilah konten statis yang akan dilayani.
  2. Baris 3–4: server mini dijalankan di background pada 127.0.0.1:8765 — pola binding loopback dari Chapter Server Basics — dengan PID disimpan agar bisa dimatikan.
  3. Baris 5 (for i in ... curl ...): menunggu hingga server siap menerima permintaan, karena http.server butuh sekejap untuk mulai mendengarkan.
  4. Baris 6–7 (curl -sI ... | head -1): mengambil baris status dari balasan HEAD — baris pertama balasan selalu berisi versi protokol, kode status, dan frasa alasannya.
  5. Baris 8–9 (-w '%{http_code}'): format khusus curl yang mencetak kode status saja — pemeriksaan satu angka yang pas untuk skrip monitoring.

Perhatikan pola pentingnya: kode 404 bukan kegagalan koneksi. Koneksi berhasil, server hidup, dan server sengaja menjawab “tidak ada” — tiga keadaan yang berbeda dari server yang mati (di mana curl malah gagal terhubung sama sekali).

Header Host: Banyak Situs di Satu IP #

Alamat IPv4 itu mahal dan terbatas, sedangkan domain murah — hampir semua web server modern menampung puluhan situs dalam satu IP. Kuncinya ada di header Host yang wajib dikirim klien HTTP/1.1: server membaca nama domain di situ, lalu mencocokkannya dengan konfigurasi situs yang tepat. Mekanisme ini disebut name-based virtual host. Kita intip wujud mentah permintaan HTTP yang dikirim curl lewat opsi -v, lalu saring hanya baris permintaannya:

bash
printf '<h1>Situs Latihan</h1>\n' > index.html
python3 -m http.server 8765 --bind 127.0.0.1 >/dev/null 2>&1 &
server=$!
for i in 1 2 3 4 5; do curl -s -o /dev/null 127.0.0.1:8765/ && break; sleep 0.2; done
curl -sv -H 'Host: latihan.example.com' -o /dev/null 127.0.0.1:8765/ 2>&1 | grep '^> [A-Za-z]'
kill "$server"

Output yang Dihasilkan:

text
> GET / HTTP/1.1
> Host: latihan.example.com
> User-Agent: curl/8.14.1
> Accept: */*

Baris Host: latihan.example.com itulah seluruh “sihir” virtual host: nama situs dikirim sebagai data biasa di dalam permintaan, bukan sebagai bagian dari alamat IP. Pola grep '^> [A-Za-z]' menyaring hanya baris permintaan yang berawalan huruf — baris > kosong yang menutup blok header ikut tersaring, begitu pula baris * dan < yang berasal dari sisi balasan. Server mini kita mengabaikan header Host dan melayani satu situs saja, tetapi Nginx mencocokkan nilai itu dengan directive server_name dan Apache dengan ServerName — keduanya akan kita praktikkan di chapter masing-masing. Bila tidak ada situs yang cocok, permintaan jatuh ke default server — situs pertama yang didefinisikan.

Konten Statis, Dinamis, dan Reverse Proxy #

Berdasarkan dari mana isinya berasal, pekerjaan web server terbagi tiga model. Konten statis adalah berkas yang dibaca apa adanya dari disk — HTML, CSS, gambar — dengan web server hanya memeriksa izin akses dan mengirimkannya. Konten dinamis dihasilkan program pada saat diminta: kode PHP berjalan di PHP-FPM, aplikasi Python di server-nya sendiri, lalu hasilnya diserahkan ke web server untuk dikirim. Model ketiga, reverse proxy, membuat web server sebagai pintu depan yang menerima semua permintaan lalu meneruskannya ke backend di belakangnya — pola yang dibedah tuntas di Chapter Reverse Proxy .

Ketiganya tidak saling menggantikan; satu server produksi biasanya memakai ketiganya sekaligus: Nginx melayani berkas statis, meneruskan /api ke backend aplikasi, sementara halaman utama ditulis PHP yang dijalankan PHP-FPM.

Nginx atau Apache #

Dua nama ini menguasai mayoritas instalasi di dunia, dan keduanya sama-sama mampu mengerjakan semua model di atas. Bedanya ada di arsitektur inti:

AspekNginxApache HTTP Server
Model koneksibeberapa worker dengan event loop per workerproses/thread per koneksi lewat MPM (prefork, worker, event)
Konfigurasi per situsserver block di berkas tunggalVirtualHost, ditambah .htaccess per direktori
Konten dinamisterpisah — proxy ke PHP-FPM dsb.mod_php di dalam proses, atau PHP-FPM
Khas dipakai untukreverse proxy, konten statis bervolume besarfleksibilitas per-direktori, ekosistem module tua

Kesimpulannya bukan “yang mana yang lebih baik”, melainkan “yang mana cocok dengan pekerjaan” — dan keduanya akan kita pasang dan konfigurasikan satu per satu di dua chapter berikutnya.

HTTPS dan Sertifikat TLS #

Dalam produksi, percakapan HTTP dibungkus TLS menjadi HTTPS: isi permintaan dan balasan terenkripsi, dan server membuktikan identitasnya lewat sertifikat — berkas bertanda tangan yang memuat nama domain. Kita bisa membuat sertifikat latihan sendiri; openssl menangani seluruh prosesnya, dan x509 membaca kembali hasilnya:

bash
openssl req -x509 -newkey rsa:2048 -nodes \
  -subj "/CN=latihan.example.com" -days 365 \
  -keyout kunci-privat.pem -out sertifikat.pem 2>/dev/null
openssl x509 -in sertifikat.pem -noout -subject
ls -1 kunci-privat.pem sertifikat.pem

Output yang Dihasilkan:

text
subject=CN=latihan.example.com
kunci-privat.pem
sertifikat.pem

Mari kita bedah baris demi baris:

  1. openssl req -x509 -newkey rsa:2048 -nodes: membuat sertifikat sekaligus kunci RSA 2048-bit barunya; -nodes berarti kunci privat disimpan tanpa passphrase (tepat untuk server, agar layanan bisa start tanpa interaksi).
  2. -subj "/CN=latihan.example.com": subjek sertifikat — CN (Common Name) adalah nama domain yang diklaim; inilah nama yang dicocokkan browser dengan alamat yang dikunjungi.
  3. -days 365 ... -keyout ... -out ...: masa berlaku setahun, kunci privat ke kunci-privat.pem, sertifikat ke sertifikat.pem.
  4. openssl x509 -noout -subject: membaca kembali subjek sertifikat tanpa mencetak seluruh isi berkasnya — verifikasi cepat bahwa nama domain memang tertanam di dalamnya.

Sertifikat ini self-signed — ditandatangani kunci kita sendiri, bukan Certificate Authority — sehingga browser akan memperingatkan pengunjung. Untuk situs publik, sertifikat berbayar maupun gratis dari Let’s Encrypt adalah jalannya, dan seluruh prosesnya dibedah di Chapter TLS dan SSL Certificates .

Fondasi konsepnya sudah lengkap: permintaan dan status, virtual host, model konten, dan sertifikat. Saatnya menyentuh web server sungguhan — yang paling dulu kita pasang adalah yang paling sering jadi pintu depan: Nginx, di Chapter nginx .

Referensi lanjut: panduan awal Nginx untuk peta direktive-nya, serta dokumentasi Apache HTTP Server untuk sisi sejawatnya.