Reverse proxy di chapter sebelumnya menjadi satu pintu untuk seluruh trafik; gembok hijau di address bar adalah janji bahwa percakapan di balik pintu itu tidak bisa disadap. Janji itu ditepati TLS, protokol yang membungkus HTTP polos menjadi HTTPS. Bahan bakunya adalah sertifikat — berkas bertanda tangan yang memuat nama domain dan kunci publik pemiliknya. Chapter ini membedah cara kerja TLS dan rantai kepercayaannya, lalu mempraktikkan pembuatan sertifikat dengan openssl, dari sertifikat latihan dan CSR hingga pemeriksaan kecocokan kunci. Alat certbot tidak terpasang di lingkungan latihan, sehingga urusan Let’s Encrypt kita lihat lewat konsep dan contoh tampilan.
Cara Kerja TLS: Bertukar Kunci, Lalu Bicara Cepat #
Enkripsi kunci publik aman tetapi ribuan kali lebih lambat daripada enkripsi simetris, jadi TLS memakai keduanya dalam dua fase. Fase handshake bersifat asimetris: klien menyapa, server memperkenalkan diri lewat sertifikatnya, klien memverifikasi tanda tangannya, lalu kedua pihak menyepakati satu session key simetris. Fase kedua adalah datanya sendiri: seluruh permintaan dan balasan HTTP dienkripsi dengan session key itu memakai cipher cepat seperti AES-GCM. Muatan sertifikat pun sederhana: nama domain, kunci publik, masa berlaku, dan tanda tangan penerbitnya.
Rantai Kepercayaan: Root, Intermediate, dan Leaf #
Kepercayaan browser pada sertifikat orang asing diwariskan berlapis. Di puncak berdiri root CA — lembaga seperti ISRG dan DigiCert yang kunci privatnya disimpan erat; bentuk publiknya justru tersebar di setiap komputer sebagai trust store bawaan paket ca-certificates. Root menandatangani intermediate CA, dan intermediate inilah yang menandatangani sertifikat domain (leaf) di server kita. Verifikasi berjalan dari leaf ke atas sampai root yang dikenal — karena itu server wajib mengirim leaf beserta intermediate-nya, digabung dalam fullchain.pem.
Membuat Sertifikat Latihan dengan openssl #
Paket nginx dan certbot tidak ada di mesin latihan, tetapi openssl — mesin kriptografi di balik keduanya — tersedia. Kita kerjakan bahan bakunya langsung:
openssl req -x509 -newkey rsa:2048 -nodes -days 365 \
-subj "/CN=app.latihan.example.com" \
-keyout kunci-privat.pem -out sertifikat.pem 2>/dev/null
openssl x509 -in sertifikat.pem -noout -subject -issuer
ls -1 sertifikat.pem kunci-privat.pemOutput yang Dihasilkan:
subject=CN=app.latihan.example.com
issuer=CN=app.latihan.example.com
kunci-privat.pem
sertifikat.pemMari kita bedah baris demi baris:
- Baris 1 (
openssl req -x509 ...): membuat sertifikat sekaligus kunci RSA 2048-bit baru —-x509menghasilkan sertifikat jadi (bukan permintaan),-nodesmenyimpan kunci tanpa passphrase agar layanan bisa start otomatis,-days 365menetapkan masa berlaku setahun. -subj "/CN=...": subjek sertifikat;CN(Common Name) adalah nama domain yang diklaim — di produksi nama domain juga harus muncul di Subject Alternative Names (SAN).-keyout ... -out ...: kunci privat kekunci-privat.pem, sertifikat kesertifikat.pem;2>/dev/nullmenyembunyikan progres di stderr.- Baris 4 (
openssl x509 -noout -subject -issuer): membaca kembali identitas tanpa mencetak seluruh isi berkas. Subjek dan penerbit di output sama persis — sertifikat ditandatangani kuncinya sendiri, itulah artinya self-signed.
CSR: Menitipkan Kunci Publik untuk Ditandatangani #
Untuk sertifikat yang dipercaya publik, kita meminta CA menandatanganinya lewat CSR (Certificate Signing Request): berkas berisi subjek dan kunci publik kita, dijahit dengan tanda tangan kunci privat sendiri agar tak dirusak di perjalanan. Kunci privat tidak pernah meninggalkan server — CA hanya menerima kunci publiknya:
openssl req -new -newkey rsa:2048 -nodes \
-subj "/CN=toko.example.com" \
-keyout kunci-toko.pem -out permintaan-toko.csr 2>/dev/null
openssl req -in permintaan-toko.csr -noout -verify -subjectOutput yang Dihasilkan:
Certificate request self-signature verify OK
subject=CN=toko.example.comMari kita bedah baris demi baris:
- Baris 1 (
openssl req -new ...): flag-newtanpa-x509menghasilkan permintaan tanda tangan, bukan sertifikat jadi. -keyout ... -out ...: kunci privat disimpan terpisah, sementara CSR yang memuat kunci publiknya dikirim ke CA.- Baris 4 (
openssl req -verify): memeriksa tanda tangan CSR terhadap kunci publik di dalamnya — bukti CSR utuh dan kunci privatnya di tangan pembuatnya;-subjectmencetak ulang subjek sebagai pemeriksaan terakhir.
Menjodohkan Kunci Privat dengan Sertifikatnya #
Satu kecelakaan klasik setelah pembaruan sertifikat: admin memasang sertifikat baru tetapi lupa menukar kuncinya — nginx menolak start dengan pesan key values mismatch. Sertifikat dan kunci privat harus memuat kunci yang sama, dan buktinya ada pada modulus — bilangan besar RSA yang tertanam di keduanya:
openssl req -x509 -newkey rsa:2048 -nodes -subj "/CN=uji.example.com" \
-keyout kunci-uji.pem -out sert-uji.pem 2>/dev/null
openssl req -x509 -newkey rsa:2048 -nodes -subj "/CN=lain.example.com" \
-keyout kunci-lain.pem -out sert-lain.pem 2>/dev/null
a=$(openssl x509 -in sert-uji.pem -noout -modulus | openssl md5)
b=$(openssl rsa -in kunci-uji.pem -noout -modulus 2>/dev/null | openssl md5)
c=$(openssl rsa -in kunci-lain.pem -noout -modulus 2>/dev/null | openssl md5)
if [ "$a" = "$b" ]; then echo "kunci-uji.pem cocok dengan sert-uji.pem"; else echo "kunci-uji.pem TIDAK cocok dengan sert-uji.pem"; fi
if [ "$a" = "$c" ]; then echo "kunci-lain.pem cocok dengan sert-uji.pem"; else echo "kunci-lain.pem TIDAK cocok dengan sert-uji.pem"; fiOutput yang Dihasilkan:
kunci-uji.pem cocok dengan sert-uji.pem
kunci-lain.pem TIDAK cocok dengan sert-uji.pemMari kita bedah baris demi baris:
- Baris 1–4: dua pasang sertifikat-kunci sebagai bahan uji — pasangan sah dan satu pasangan lain yang tak berhubungan.
- Baris 5–7 (
-modulus | openssl md5): modulus ratusan digit dicukupi sidik jarinya; subperintahx509membacanya dari sertifikat,rsadari kunci privat. - Baris 8–9 (
if [ "$a" = "$b" ] ...): perbandingan string biasa — pasangan yang lahir bersama mencetak cocok, kunci milik pasangan lain mencetak TIDAK cocok.
Self-Signed atau Ditandatangani CA Publik #
Kedua jenis sertifikat sah secara teknis; pilihan bergantung pada siapa yang harus mempercayainya:
| Aspek | Self-signed | CA publik (mis. Let’s Encrypt) |
|---|---|---|
| Dipercaya klien | harus diimpor manual ke tiap klien | otomatis, via rantai ke root yang dikenal |
| Cocok untuk | lab, alat internal, koneksi antar server milik sendiri | situs dan API yang diakses publik |
| Masa berlaku | bebas kita tetapkan | 90 hari, dipaksa disegar otomatis |
| Biaya | gratis | gratis |
Let’s Encrypt dan certbot #
Let’s Encrypt adalah CA publik gratis yang prosesnya diotomatisasi penuh lewat protokol ACME. Klien yang paling umum adalah certbot; plugin --webroot bekerja di atas server yang sudah berjalan — certbot meletakkan berkas tantangan di jalur /.well-known/acme-challenge/ di bawah document root, server Let’s Encrypt mengunduhnya sebagai bukti kita menguasai domain itu, lalu sertifikat diterbitkan:
sudo certbot certonly --webroot -w /var/www/toko -d toko.example.comBerikut contoh tampilan proses penerbitannya:
Requesting a certificate for toko.example.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/toko.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/toko.example.com/privkey.pem
This certificate expires on 2026-04-15.
These files will be updated when the certificate renews.Dua path itulah yang dirujuk directive ssl_certificate dan ssl_certificate_key di server block nginx. Masa hidup 90 hari disengaja pendek agar pembaruan selalu otomatis: paket certbot memasang systemd timer yang menjalankan certbot renew dua kali sehari, dan pembaruan hanya terjadi bila tersisa kurang dari 30 hari. Berikut contoh tampilan pemeriksaan timer-nya:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Sat 2026-01-17 00:38:21 11h Fri 2026-01-16 00:38:21 12h ago certbot.timer certbot.serviceAgar nginx memuat sertifikat baru tanpa putus, berikan deploy hook seperti --deploy-hook "systemctl reload nginx".
TLS 1.2, TLS 1.3, SNI, dan HSTS #
TLS 1.3 memangkas handshake menjadi satu bolak-balik dan membuang cipher tua; TLS 1.2 masih dipertahankan untuk klien lama — keduanya diaktifkan lewat ssl_protocols. SNI (Server Name Indication) adalah perpanjangan virtual host dari Chapter Web Server
ke ranah TLS: sejak TLS 1.2, klien mengirim nama domain di awal handshake, sehingga satu IP dapat melayani banyak situs HTTPS dengan sertifikat masing-masing. Pengunci terakhir adalah HSTS — header yang memerintahkan browser menolak HTTP polos selama max-age berlaku:
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000" always;Dengan sertifikat terpasang dan penyegarannya otomatis, pintu depan server kita resmi berkunci. Pertanyaan berikutnya: apa saja yang lewat di balik pintu itu — jawabannya tercatat rapi di log, bahan utama Chapter Web Server Logs .
Referensi lanjut: dokumentasi modul SSL Nginx
untuk seluruh directive ssl_*, serta panduan server HTTPS Nginx
untuk topik operasionalnya.