Konsep ACME

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 untuk example.com.

← Sebelumnya: Global Options   Berikutnya: Let’s Encrypt →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact