Certbot memberi Anda sertifikat TLS yang valid dalam 5 menit — tetapi sertifikat yang valid tidak sama dengan konfigurasi TLS yang aman. Saya menggunakan Certbot untuk semua deployment produksi saya, dan saya segera mengikutinya dengan langkah pengerasan yang dilewati sebagian besar tutorial. Perbedaannya penting: pemindaian SSL Labs pada setup Certbot+nginx default mungkin mendapat nilai B atau bahkan C karena dukungan cipher warisan, HSTS yang hilang, atau versi TLS yang sudah usang masih diaktifkan.
SSL Labs (ssllabs.com/ssltest) menilai konfigurasi TLS dari A+ hingga F berdasarkan: versi protokol yang didukung, cipher suite yang ditawarkan, validitas sertifikat dan kelengkapan rantai, keberadaan HSTS dan durasinya, OCSP stapling, dan dukungan forward secrecy. Sebagian besar konfigurasi nginx+Certbot default mendapat nilai B karena masih mendukung TLS 1.0 dan 1.1 (yang sudah usang, rentan terhadap serangan BEAST dan POODLE).
Konfigurasi TLS minimum yang aman di tahun 2025: nonaktifkan TLS 1.0 dan 1.1 (gunakan `ssl_protocols TLSv1.2 TLSv1.3`), preferensikan TLS 1.3 di mana klien dan server mendukungnya, untuk TLS 1.2 gunakan daftar cipher yang dibatasi dengan ECDHE untuk forward secrecy, nonaktifkan RC4 dan 3DES secara eksplisit. Mozilla's SSL Configuration Generator (ssl-config.mozilla.org) menghasilkan konfigurasi nginx/Apache/HAProxy yang benar untuk tingkat kompatibilitas target Anda.
# Complete nginx TLS hardening config (scores A+ on SSL Labs)
# Generated from Mozilla SSL Configuration Generator (Intermediate profile)
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name yourdomain.com www.yourdomain.com;
# Certbot-managed certificates
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/yourdomain.com/chain.pem;
# TLS protocols: disable 1.0 and 1.1
ssl_protocols TLSv1.2 TLSv1.3;
# Cipher suites for TLS 1.2 (TLS 1.3 handles its own ciphers)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# DH parameters (generate once: openssl dhparam -out /etc/ssl/dhparam.pem 2048)
ssl_dhparam /etc/ssl/dhparam.pem;
# Session configuration
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# HSTS — max 1 year, include subdomains, preload
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
# Security headers
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
location / {
proxy_pass http://localhost:3000;
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;
}
}
# HTTP → HTTPS redirect
server {
listen 80;
listen [::]:80;
server_name yourdomain.com www.yourdomain.com;
return 301 https://$host$request_uri;
}Dari pengalaman saya menjalankan HTTPS produksi di beberapa deployment klien: hasilkan konfigurasi nginx TLS Anda dari Mozilla's SSL Configuration Generator daripada menyalin dari posting blog (termasuk milik saya). Pilih 'Modern' untuk API yang hanya perlu mendukung browser/klien saat ini, 'Intermediate' untuk aplikasi web umum, dan 'Old' hanya jika Anda harus mendukung IE11 atau Android yang lebih lama. Regenerasi setiap tahun saat rekomendasinya diperbarui.
HSTS (Strict-Transport-Security) memberi tahu browser untuk hanya terhubung ke domain Anda melalui HTTPS, bahkan jika pengguna mengetik http://. Header dasar: `Strict-Transport-Security: max-age=31536000` (1 tahun). Ditingkatkan: tambahkan `includeSubDomains` untuk mencakup semua subdomain dan `preload` untuk mengirimkan domain Anda ke daftar preload browser. Daftar preload dibangun ke dalam Chrome, Firefox, dan Edge — domain di dalamnya hanya HTTPS sebelum browser membuat permintaan apa pun.
Ketika browser memvalidasi sertifikat TLS, ia memeriksa status revokasi sertifikat dengan mengquery server OCSP CA. Ini menambahkan latensi (100-300ms). OCSP stapling memiliki server yang secara berkala mengambil respons OCSP dari CA dan menyertakannya dalam handshake TLS. Di nginx: `ssl_stapling on; ssl_stapling_verify on; resolver 8.8.8.8 8.8.4.4 valid=300s;`.
Sebelum mengaktifkan HSTS dengan preload dan includeSubDomains, verifikasi bahwa SEMUA subdomain Anda menyajikan HTTPS dengan benar — termasuk subdomain staging, dev, admin, atau internal mana pun. Setelah Anda masuk daftar preload, menghapus diri Anda memerlukan berbulan-bulan. Saya telah melihat klien memecahkan alat internal yang berada di subdomain HTTP-only dengan menambahkan includeSubDomains tanpa mengaudit semua subdomain mereka terlebih dahulu.
Log Certificate Transparency (CT) adalah catatan publik append-only dari semua sertifikat TLS yang dikeluarkan oleh CA tepercaya. Sertifikat apa pun untuk domain Anda akan muncul di log CT dalam hitungan menit setelah dikeluarkan. Pantau log CT untuk mendeteksi sertifikat yang tidak sah. Pemantauan gratis: crt.sh (cari domain Anda), pemantauan transparansi sertifikat Facebook, atau Cert Spotter.
# Verify OCSP stapling is working
openssl s_client -connect yourdomain.com:443 -status 2>/dev/null | grep -A 3 "OCSP Response Status"
# Expected: OCSP Response Status: successful (0x0)
# Verify TLS version and cipher
openssl s_client -connect yourdomain.com:443 -tls1_2 2>/dev/null | grep "Protocol|Cipher"
openssl s_client -connect yourdomain.com:443 2>/dev/null | grep "Protocol|Cipher"
# Check certificate expiry
echo | openssl s_client -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -dates
# Monitor cert expiry with Prometheus Blackbox Exporter
# blackbox.yml config:
# modules:
# https_2xx:
# prober: http
# http:
# valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
# tls_config:
# insecure_skip_verify: false
#
# prometheus.yml scrape:
# - job_name: 'tls-expiry'
# metrics_path: /probe
# params:
# module: [https_2xx]
# static_configs:
# - targets: ['https://yourdomain.com']
# relabel_configs:
# - source_labels: [__address__]
# target_label: __param_target
# - target_label: __address__
# replacement: blackbox-exporter:9115
#
# Alert rule:
# - alert: SSLCertificateExpiringSoon
# expr: probe_ssl_earliest_cert_expiry - time() < 7 * 24 * 3600
# labels:
# severity: criticalKonfigurasi nginx TLS lengkap yang saya gunakan untuk API produksi — menggabungkan sertifikat Let's Encrypt dengan preferensi TLS 1.3, cipher suite yang aman, OCSP stapling, HSTS, dan security header. Konfigurasi ini mendapat nilai A+ di SSL Labs dan lulus pemeriksaan security header di securityheaders.com.
Bahkan dengan pembaruan otomatis yang dikonfigurasi, pantau kedaluwarsa sertifikat sebagai pemeriksaan independen. Pembaruan Certbot gagal karena alasan: kegagalan validasi DNS, batas rate Let's Encrypt, error reload nginx setelah pembaruan. Siapkan pemantauan kedaluwarsa sertifikat eksternal (Uptime Robot memiliki monitor SSL gratis, Grafana dengan Blackbox Exporter berfungsi untuk self-hosted). Alert pada 30 hari dan 7 hari tersisa.