Konsep ACME #
ACME (Automated Certificate Management Environment) adalah protokol standar terbuka yang mendefinisikan bagaimana server web bisa membuktikan kepemilikan domain ke Certificate Authority (CA) dan mendapatkan sertifikat TLS secara otomatis. Protokol ini distandardisasi dalam RFC 8555 dan menjadi fondasi dari seluruh ekosistem sertifikat gratis modern — Let’s Encrypt, ZeroSSL, dan beberapa CA lainnya semuanya menggunakan ACME.
Memahami cara kerja ACME bukan hanya pengetahuan teoritis. Ketika sertifikat Caddy gagal diperpanjang, ketika kamu mendapat error saat pertama kali setup, atau ketika kamu perlu memilih antara HTTP-01 dan DNS-01 challenge — pemahaman tentang mekanisme di balik layar adalah yang memungkinkan kamu mendiagnosis masalah dengan benar.
Sejarah Singkat: Sebelum ACME #
Sebelum ACME dan Let’s Encrypt, mendapatkan sertifikat TLS untuk website melibatkan proses yang panjang dan mahal:
Proses mendapat sertifikat TLS sebelum ACME:
1. Buat private key dan CSR (Certificate Signing Request)
2. Kirim CSR ke CA (Comodo, DigiCert, dll.) beserta:
- Pembayaran $50-200/tahun
- Dokumen verifikasi identitas
- Menunggu proses review (bisa beberapa hari)
3. Terima sertifikat via email
4. Install secara manual di server
5. Atur reminder untuk renewal 30 hari sebelum expire
6. Ulangi seluruh proses setiap tahun
Hasil: Proses manual, mahal, rawan lupa, dan membosankan.
Let’s Encrypt diluncurkan pada 2015 dengan satu misi: membuat HTTPS gratis dan mudah untuk semua orang. Untuk mewujudkan ini, mereka perlu protokol standar yang memungkinkan otomatisasi penuh — lahirlah ACME.
Konsep Inti: Domain Validation #
Sebelum CA menerbitkan sertifikat untuk example.com, ia perlu memastikan bahwa kamu benar-benar mengontrol domain tersebut. Ini disebut Domain Validation (DV). ACME mendefinisikan tiga metode untuk membuktikan kepemilikan domain.
Challenge HTTP-01 #
Metode paling umum. CA meminta kamu untuk menyajikan token tertentu di URL yang sudah ditentukan:
Alur HTTP-01 Challenge:
1. Caddy menghubungi CA: "Saya ingin sertifikat untuk example.com"
│
▼
2. CA merespons: "Oke, saya akan cek. Taruh string ini:
'abc123xyz456' di URL ini:
http://example.com/.well-known/acme-challenge/TOKEN_ID"
│
▼
3. Caddy secara otomatis menyiapkan endpoint tersebut
(Caddy memulai HTTP server sementara di port 80 jika perlu)
│
▼
4. CA melakukan HTTP GET ke:
http://example.com/.well-known/acme-challenge/TOKEN_ID
│
▼
5. CA menerima response yang berisi 'abc123xyz456'
"Token cocok! example.com memang dikontrol pemohon"
│
▼
6. CA menerbitkan sertifikat untuk example.com
Persyaratan HTTP-01:
- Port 80 harus bisa diakses dari internet
- Domain harus resolve ke IP server yang menjalankan Caddy
- Tidak bisa digunakan untuk wildcard certificate (
*.example.com)
Caddy menangani HTTP-01 secara otomatis — tidak ada konfigurasi yang diperlukan. Caddy menjalankan HTTP server di port 80 yang siap menjawab challenge kapan saja.
Challenge TLS-ALPN-01 #
Metode alternatif yang bekerja di port 443 menggunakan TLS extension ALPN:
Alur TLS-ALPN-01 Challenge:
1. Caddy menghubungi CA, meminta sertifikat untuk example.com
│
▼
2. CA merespons: "Lakukan handshake TLS khusus di port 443
dengan ALPN protocol 'acme-tls/1'. Sertakan key authorization
di sertifikat challenge."
│
▼
3. Caddy membuat sertifikat self-signed khusus dengan
key authorization di extension SAN
│
▼
4. CA melakukan TLS handshake ke example.com:443
dengan ALPN 'acme-tls/1'
│
▼
5. Caddy merespons dengan sertifikat challenge tersebut
│
▼
6. CA memverifikasi key authorization dan menerbitkan sertifikat
Persyaratan TLS-ALPN-01:
- Port 443 harus bisa diakses dari internet
- Tidak bisa digunakan untuk wildcard certificate
- Berguna ketika port 80 diblokir atau tidak tersedia
Challenge DNS-01 #
Metode yang paling fleksibel — domain validation dilakukan melalui DNS record:
Alur DNS-01 Challenge:
1. Caddy menghubungi CA, meminta sertifikat untuk *.example.com
│
▼
2. CA merespons: "Buat TXT record di DNS:
_acme-challenge.example.com → 'digest-of-key-authorization'"
│
▼
3. Caddy menghubungi Cloudflare API (atau DNS provider lain):
"Buat TXT record ini di DNS example.com"
│
▼
4. DNS provider membuat TXT record yang diminta
│
▼
5. CA melakukan DNS lookup untuk _acme-challenge.example.com
│
▼
6. CA menemukan TXT record dengan nilai yang tepat
"Domain terbukti dikontrol pemohon!"
│
▼
7. CA menerbitkan sertifikat (termasuk wildcard *.example.com)
│
▼
8. Caddy menghapus TXT record yang sudah tidak diperlukan
Persyaratan DNS-01:
- Akses ke DNS API provider kamu (Cloudflare, Route53, dll.)
- Satu-satunya metode yang mendukung wildcard certificate
- Server tidak perlu bisa diakses dari internet (cocok untuk server internal)
- Caddy butuh plugin DNS provider yang sesuai
Alur Lengkap Perolehan Sertifikat di Caddy #
Inilah yang sebenarnya terjadi setiap kali Caddy mendapatkan sertifikat baru dari awal:
Caddy startup / domain baru ditambahkan ke konfigurasi
│
▼
Caddy cek storage lokal (filesystem atau external storage)
│
┌───────────┴────────────────┐
│ │
Sertifikat valid ada Tidak ada / expire < 30 hari
(> 30 hari sebelum expire) │
│ ▼
│ Caddy buat ACME account baru
│ (jika belum pernah)
│ │
│ ▼
│ Caddy pilih CA (prioritas):
│ 1. Let's Encrypt (default)
│ 2. ZeroSSL (fallback otomatis)
│ │
│ ▼
│ Caddy minta sertifikat ke CA
│ │
│ ▼
│ CA kirim challenge
│ │
│ ┌──────────────┼──────────────┐
│ │ │ │
│ HTTP-01 TLS-ALPN-01 DNS-01
│ (default) (port 443) (via API)
│ │ │ │
│ └──────────────┴───────────────┘
│ │
│ Caddy fulfill challenge
│ │
│ CA verifikasi
│ │
│ Sertifikat diterbitkan (DER format)
│ │
│ Caddy simpan ke storage
│ │
└────────────────────────────┘
│
▼
HTTPS aktif untuk domain tersebut
│
▼
Background renewal checker berjalan setiap ~10 menit
Renewal dimulai ~30 hari sebelum expire
Jika renewal gagal, retry dengan exponential backoff
Rate Limit Let’s Encrypt #
Rate limit adalah salah satu hal yang paling sering membuat developer frustasi dengan Let’s Encrypt — dan paling mudah dihindari jika kamu tahu aturannya.
Rate Limit Let's Encrypt (Production):
─────────────────────────────────────────────────────────────
Limit Nilai Reset
─────────────────────────────────────────────────────────────
Certificates per Registered Domain 50/minggu Rolling 7 hari
Duplicate Certificate 5/minggu Rolling 7 hari
Failed Validations per hostname 5/jam Rolling 1 jam
New Orders per account 300/3 jam Rolling 3 jam
Pending Authorizations per account 300 Sampai expire
Accounts per IP 10/3 jam Rolling 3 jam
─────────────────────────────────────────────────────────────
"Registered Domain" = domain + TLD, misal:
- example.com → RD = example.com
- sub.example.com → RD = example.com (sama!)
- app.sub.example.com → RD = example.com (sama!)
Ini berarti: semua subdomain dari example.com berbagi
50 sertifikat per minggu yang sama
Situasi yang Menguras Rate Limit #
# ANTI-PATTERN: Script deployment yang membuat ulang container
# Setiap iterasi meminta sertifikat baru!
for i in {1..10}; do
docker rm -f caddy
docker run -d caddy # Sertifikat baru diminta setiap kali!
done
# Setelah 5 iterasi: "duplicate certificate" rate limit tercapai
# BENAR: Persist volume sertifikat
docker run -d -v caddy_data:/data caddy # Gunakan ulang sertifikat yang ada
Menggunakan Staging Environment #
Let’s Encrypt menyediakan staging environment dengan rate limit yang jauh lebih longgar untuk testing:
{
# STAGING — untuk testing. Sertifikat tidak di-trust browser.
acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
email [email protected]
}
example.com {
file_server
}
Rate Limit Staging Let's Encrypt:
─────────────────────────────────────────────────────────────
Certificates per Registered Domain 30.000/minggu
Duplicate Certificate 30.000/minggu
Failed Validations 60/jam
─────────────────────────────────────────────────────────────
Hampir tidak mungkin mencapai rate limit staging
Sertifikat dari staging tidak di-trust browser — browser akan menampilkan security warning. Gunakan staging hanya untuk memastikan konfigurasi bekerja sebelum switch ke production. Setelah yakin berhasil, hapus acme_ca staging dari konfigurasi dan jalankan ulang.Algoritma Pemilihan Challenge #
Caddy memilih challenge type berdasarkan ketersediaan dan konfigurasi:
Caddy perlu challenge untuk example.com
│
▼
Apakah DNS provider dikonfigurasi di konfigurasi TLS?
│
├─ Ya → Gunakan DNS-01 (paling fleksibel)
│
└─ Tidak
│
▼
Apakah port 443 tersedia dan bisa diakses?
│
├─ Ya → Coba TLS-ALPN-01
│
└─ Tidak (atau port 80 lebih reliable)
│
▼
Gunakan HTTP-01 via port 80
(default untuk sebagian besar kasus)
Renewal Otomatis #
Sertifikat Let’s Encrypt berlaku selama 90 hari. Caddy secara otomatis melakukan renewal jauh sebelum sertifikat expire:
Timeline renewal:
Hari 0 │ Sertifikat baru diperoleh (valid 90 hari)
│
Hari 60 │ Caddy mulai mencoba renewal
(30 hari │ (~66% masa hidup sertifikat sudah lewat)
sebelum │
expire) │
│ Jika renewal berhasil: sertifikat baru valid 90 hari
│ Jika gagal: Caddy retry dengan exponential backoff
│ - Retry pertama: 1 menit
│ - Retry kedua: 2 menit
│ - Retry ketiga: 4 menit
│ - Dan seterusnya, maksimal beberapa jam
│
Hari 90 │ Sertifikat expire (idealnya renewal sudah berhasil
│ jauh sebelum ini)
Caddy sangat jarang gagal melakukan renewal karena:
- Proses dimulai 30 hari sebelum expire
- Ada mekanisme retry otomatis
- Caddy berjalan sebagai daemon yang terus-menerus memantau
Debugging Masalah ACME #
# Lihat log ACME Caddy
sudo journalctl -u caddy | grep -i "acme\|certificate\|tls\|solving"
# Atau dari Docker
docker logs caddy 2>&1 | grep -i "acme\|cert"
# Cek apakah domain bisa di-resolve
dig +short example.com # Harus return IP server
nslookup example.com # Cross-check
# Cek apakah port 80 accessible dari internet
# (dari server yang berbeda atau pakai online tool)
curl -I http://example.com/.well-known/acme-challenge/test
# Cek rate limit status via Let's Encrypt API
# https://crt.sh/?q=example.com (lihat sertifikat yang diterbitkan)
# Verifikasi sertifikat yang aktif
echo | openssl s_client -connect example.com:443 2>/dev/null \
| openssl x509 -noout -dates -subject -issuer
Ringkasan #
- ACME adalah protokol standar (RFC 8555) yang mendefinisikan cara server membuktikan kepemilikan domain ke CA secara otomatis.
- HTTP-01 adalah challenge default — token di-serve via port 80. Tidak bisa untuk wildcard.
- TLS-ALPN-01 bekerja di port 443 via ALPN extension. Alternatif ketika port 80 tidak tersedia. Tidak bisa untuk wildcard.
- DNS-01 menggunakan TXT record di DNS. Satu-satunya cara untuk wildcard certificate. Membutuhkan API key DNS provider.
- Caddy mengelola seluruh lifecycle sertifikat secara otomatis: perolehan, penyimpanan, dan renewal ~30 hari sebelum expire.
- Rate limit production: 50 sertifikat per registered domain per minggu, 5 duplicate per minggu. Gunakan staging CA untuk testing.
- Semua subdomain berbagi kuota yang sama —
sub1.example.com,sub2.example.com, dll. semuanya termasuk dalam 50/minggu untukexample.com.