Mengamankan transport HTTP: terminasi TLS dengan rustls dan axum-server, arsitektur reverse proxy (nginx/caddy) yang paling umum di produksi, serta pengelolaan sertifikat dan HSTS yang benar.

Sejauh ini server kita berjalan di HTTP polos — data mengalir terenkripsi seadanya. Episode ini menutup celah itu dengan HTTPS/TLS: enkripsi traffic antara klien dan server. Kalian akan belajar dua arsitektur: TLS langsung di Axum (rustls + axum-server) dan — yang lebih umum di produksi — terminasi TLS di reverse proxy di depan aplikasi.
Mengapa arsitektur proxy lebih dominan? Karena di produksi, Axum jarang berdiri sendiri: nginx/caddy di depan menangani TLS, static files, compression, dan load balancing. Memahami kedua cara — plus cara men-debug masalah HTTPS yang klasik — adalah bekal yang wajib sebelum deployment di episode 24.
| Aspek | TLS di Axum | TLS di Reverse Proxy |
|---|---|---|
| Sertifikat | Dikelola aplikasi | Dikelola proxy |
| Auto-renew (Let's Encrypt) | Manual / extra tooling | Otomatis (caddy) |
| Static files & compression | Aplikasi (episode 11) | Proxy (lebih cepat) |
| Kompleksitas | Lebih rendah | Lebih tinggi |
| Skalabilitas | Satu instance | Bisa multi instance di belakang |
Untuk produksi, hampir selalu gunakan reverse proxy. TLS di Axum berguna untuk kasus khusus: prototipe, edge deployment mandiri, atau kebutuhan TLS mutakhir per service.
Untuk TLS di aplikasi, axum-server mempermudah: ia menyediakan Server::bind_rustls di atas rustls (implementasi TLS murni Rust).
cargo add axum-server --features rustlsuse axum_server::tls_rustls::RustlsConfig;
use std::path::PathBuf;
#[tokio::main]
async fn main() {
let config = Config::from_env();
// Contoh sertifikat self-signed untuk development
// (produksi: dapatkan dari Let's Encrypt / certbot)
let cert_path = PathBuf::from("certs/server.crt");
let key_path = PathBuf::from("certs/server.key");
let tls = RustlsConfig::from_pem_file(cert_path, key_path)
.await
.expect("gagal memuat sertifikat TLS");
let app = build_app();
axum_server::bind_rustls(
config.bind_addr.parse().unwrap(),
tls,
)
.serve(app.into_make_service())
.await
.unwrap();
}Menghasilkan sertifikat self-signed untuk development:
mkdir -p certs
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout certs/server.key -out certs/server.crt \
-days 365 -subj "/CN=localhost"Uji koneksi TLS:
curl -k https://localhost:3000/api/health-k mem-bypass verifikasi sertifikat (karena self-signed). Untuk produksi, jangan pernah pakai self-signed — gunakan Let's Encrypt (sertifikat gratis, auto-renew dengan certbot).
Warning
Self-signed hanya untuk development. Di produksi: (1) dapatkan sertifikat dari CA tepercaya (Let's Encrypt via certbot, atau dari cloud provider), (2) auto-renew dengan cron/systemd timer — sertifikat kadaluarsa adalah penyebab downtime paling membosankan. Selalu pasang alert untuk expiry (episode 17 punya alatnya).
Pola yang akan dipakai di deployment (episode 24): nginx atau caddy di depan, Axum di belakang. Axum mendengarkan di 127.0.0.1 (tidak terekspos), proxy yang menangani dunia luar.
Caddy adalah pilihan paling malas (dan bagus) — TLS dan sertifikat otomatis:
api.kita.id {
reverse_proxy 127.0.0.1:3000
}Caddy mendapatkan sertifikat dari Let's Encrypt secara otomatis, memperbaruinya, dan mengatur HTTP→HTTPS redirect. Inilah alasan banyak tim memilih caddy untuk aplikasi Axum.
Nginx lebih klasik — kalian mengelola sertifikat sendiri:
server {
listen 443 ssl;
server_name api.kita.id;
ssl_certificate /etc/letsencrypt/live/api.kita.id/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.kita.id/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
location / {
proxy_pass http://127.0.0.1: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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}Tiga blok yang wajib dipahami:
ssl_certificate / ssl_certificate_key — sertifikat yang didapat dari Let's Encrypt (certbot).proxy_set_header X-Forwarded-For dll — meneruskan identitas asli klien; aplikasi memakainya untuk rate limit per-IP (episode 19) dan log.Upgrade / Connection: upgrade — wajib untuk WebSocket (episode 12) bekerja lewat proxy.Note
Tanpa header X-Forwarded-Proto, aplikasi tidak tahu request aslinya HTTPS — bisa memicu redirect loop atau menandai cookie tidak aman. Selalu setel header ini di proxy dan pastikan aplikasi membaca Forwarded/X-Forwarded-* dengan benar.
Dua protokol realtime dari episode 12 punya kebutuhan berbeda di belakang proxy:
Upgrade headers di nginx (sudah di atas). Caddy menangani otomatis.KeepAlive di aplikasi (sudah dipasang di episode 12) dan konfigurasi proxy yang menoleransi koneksi panjang:location /events {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_read_timeout 3600s;
proxy_buffering off;
}proxy_buffering off penting untuk SSE — tanpa ini, proxy menahan potongan event hingga buffer penuh, membuat notifikasi tampak tertunda.
Setelah HTTPS aktif, pastikan tidak ada yang memakai HTTP polos:
server {
listen 80;
server_name api.kita.id;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
# ... konfigurasi TLS sebelumnya ...
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}Strict-Transport-Security (HSTS) memerintahkan browser: selama setahun, jangan pernah hubungi domain ini via HTTP. Ini mencegah downgrade attack — dan merupakan header yang kita rekomendasikan di episode 18.
Warning
HSTS sekali terpasang sulit dibatalkan (browser menghafalnya). Jangan pasang HSTS pada domain yang masih kalian akses via HTTP secara sengaja (misal subdomain development yang belum HTTPS). Terapkan HSTS setelah yakin seluruh subdomain sudah punya TLS.
Sebelum dianggap selesai, verifikasi dari sudut pandang klien nyata:
# Header + chain sertifikat
curl -sI https://api.kita.id/api/health
# Apakah redirect HTTP -> HTTPS bekerja?
curl -sI http://api.kita.id/api/health
# Protokol & cipher yang didukung
openssl s_client -connect api.kita.id:443 -servername api.kita.id 2>/dev/null \
| grep -E "Protocol|Cipher"
# Apakah HSTS terkirim?
curl -sI https://api.kita.id/api/health | grep -i strict-transportTool tambahan yang berguna: sslabs.com (test laboratorium) dan curl --tlsv1.3 untuk memastikan TLS 1.3 berjalan. Jangan lupa nonaktifkan protokol lama (TLSv1.2 TLSv1.3 saja di nginx) — protokol usang adalah pintu masuk serangan downgrade.
Pada episode 20 ini transport kalian aman:
axum-server + rustls (self-signed untuk dev).127.0.0.1.Di episode 21 selanjutnya kita eksekusi rencana dari episode 5: custom extractors & advanced routing — membangun AuthUser extractor reusable dan route dinamis yang memanfaatkan sistem tipe Axum sepenuhnya. Sampai jumpa di episode 21!