Self-Signed & Internal CA #
Tidak semua deployment membutuhkan sertifikat dari Let’s Encrypt atau ZeroSSL. Server internal, environment development, intranet perusahaan, dan staging server yang tidak bisa diakses dari internet — semuanya membutuhkan HTTPS, tapi tidak bisa menggunakan ACME public CA karena tidak memiliki domain publik atau akses internet yang diperlukan.
Untuk skenario ini, Caddy menyediakan internal CA yang bisa membuat sertifikat TLS yang valid untuk jaringan lokal dan development, tanpa ketergantungan pada internet atau CA pihak ketiga.
Dua Pendekatan untuk HTTPS Tanpa ACME Publik #
Pendekatan 1: Internal CA (direkomendasikan)
Caddy bertindak sebagai CA sendiri
Membuat root CA → Menerbitkan sertifikat untuk domain lokal
Keunggulan: Sertifikat di-trust oleh browser setelah root CA di-install
Pendekatan 2: Sertifikat Manual
Kamu menyediakan sertifikat dan private key sendiri
Caddy hanya menggunakannya tanpa mengelola lifecycle
Keunggulan: Fleksibel, bisa untuk domain apapun termasuk IP
Internal CA — Solusi untuk Localhost #
Caddy memiliki kemampuan untuk menjalankan internal Certificate Authority yang bisa menerbitkan sertifikat untuk domain lokal. Ini terintegrasi langsung di Caddy tanpa plugin tambahan.
Cara Mengaktifkan Internal CA #
# Cara 1: Gunakan 'localhost' — Caddy otomatis pakai internal CA
localhost {
reverse_proxy localhost:3000
}
# Cara 2: Gunakan 'local_certs' di global options
# Semua site di instance ini menggunakan internal CA
{
local_certs
}
example.local {
file_server
}
app.internal {
reverse_proxy localhost:3000
}
# Cara 3: Konfigurasi TLS internal per-site
myapp.localhost {
tls internal
reverse_proxy localhost:3000
}
Install Root CA ke Browser #
Sertifikat yang dikeluarkan oleh internal CA Caddy tidak otomatis di-trust browser — kamu perlu install root CA-nya satu kali. Caddy menyediakan perintah untuk ini:
# Install root CA Caddy ke sistem dan browser
# Perintah ini membutuhkan privilege admin/sudo
caddy trust
# Output:
# 2024/01/01 00:00:00.000 INFO pki.ca.local installed root certificate
# {"path": "/home/user/.local/share/caddy/pki/authorities/local/root.crt"}
# Untuk menghapus root CA dari sistem
caddy untrust
Setelah caddy trust, browser (Chrome, Firefox, Edge) akan mempercayai semua sertifikat yang diterbitkan oleh internal CA Caddy. Ini berlaku untuk semua domain yang dilayani oleh instance Caddy tersebut.
Menemukan File Root CA #
# Lokasi root CA Caddy
# Linux / macOS:
ls ~/.local/share/caddy/pki/authorities/local/
# root.crt root.key intermediate.crt intermediate.key
# Windows:
# %APPDATA%\Caddy\pki\authorities\local\
# Jika menggunakan systemd service (root.crt ada di home user 'caddy')
sudo ls /var/lib/caddy/.local/share/caddy/pki/authorities/local/
Install Root CA Secara Manual (Tanpa caddy trust)
#
Jika kamu perlu install root CA ke mesin yang berbeda atau ke browser tertentu:
# Export root CA dari server Caddy ke file
sudo cp /var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt \
/tmp/caddy-root-ca.crt
# Install ke Ubuntu/Debian system trust store
sudo cp /tmp/caddy-root-ca.crt /usr/local/share/ca-certificates/caddy-root.crt
sudo update-ca-certificates
# Install ke RHEL/CentOS system trust store
sudo cp /tmp/caddy-root-ca.crt /etc/pki/ca-trust/source/anchors/caddy-root.crt
sudo update-ca-trust
# Install ke Firefox (via certificate manager)
# Buka Firefox → Settings → Privacy & Security → View Certificates
# → Import → Pilih caddy-root-ca.crt
# → Centang "Trust this CA to identify websites"
# Install ke Chrome/Edge
# Pada Linux, Chrome menggunakan system trust store
# Pada macOS: security add-trusted-cert -d -r trustRoot caddy-root-ca.crt
# Pada Windows: certutil -addstore -f "ROOT" caddy-root-ca.crt
Internal CA di Docker #
Saat menjalankan Caddy di Docker untuk development, root CA perlu di-export dan di-install di host:
# docker-compose.yml
services:
caddy:
image: caddy:2.8.4
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
# Mount direktori untuk mengakses root CA dari host
- ./caddy-pki:/data/caddy/pki
volumes:
caddy_data:
caddy_config:
# Setelah container pertama kali berjalan, root CA ada di ./caddy-pki/
ls ./caddy-pki/authorities/local/
# root.crt root.key intermediate.crt intermediate.key
# Install root CA ke sistem host
sudo cp ./caddy-pki/authorities/local/root.crt \
/usr/local/share/ca-certificates/caddy-local.crt
sudo update-ca-certificates
# Sekarang https://localhost bekerja tanpa warning di semua program
# yang menggunakan system trust store
Sertifikat Manual — Kamu Sediakan Sertifikat Sendiri #
Untuk kasus di mana kamu sudah memiliki sertifikat (dari CA internal perusahaan, wildcard cert dari CA komersial, atau cert yang di-generate sendiri dengan openssl), kamu bisa memberitahu Caddy untuk menggunakannya langsung:
Menggunakan Sertifikat yang Sudah Ada #
example.internal {
# Path ke cert dan key
tls /path/to/cert.pem /path/to/private-key.pem
reverse_proxy localhost:3000
}
# Atau di dalam blok tls yang lebih detail
example.internal {
tls {
# Load dari file
cert_file /etc/ssl/example.internal/fullchain.pem
key_file /etc/ssl/example.internal/privkey.pem
}
file_server
}
# Pastikan user 'caddy' bisa membaca file sertifikat
sudo chown caddy:caddy /path/to/cert.pem /path/to/private-key.pem
sudo chmod 640 /path/to/cert.pem /path/to/private-key.pem
# Atau set permission 644 untuk cert (bukan key!)
sudo chmod 644 /path/to/cert.pem
sudo chmod 600 /path/to/private-key.pem
Generate Sertifikat Self-Signed dengan OpenSSL #
# Generate self-signed certificate untuk server internal
# Berlaku 10 tahun, untuk domain example.internal
# Cara 1: Single command (cocok untuk testing cepat)
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 3650 -nodes \
-subj "/CN=example.internal/O=My Organization/C=ID"
# Cara 2: Dengan SAN (Subject Alternative Names) — lebih kompatibel dengan browser modern
# Browser modern membutuhkan SAN, bukan hanya CN
cat > san.cnf << EOF
[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req
[dn]
C = ID
O = My Organization
CN = example.internal
[v3_req]
subjectAltName = @alt_names
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = example.internal
DNS.2 = *.example.internal
IP.1 = 192.168.1.100
IP.2 = 127.0.0.1
EOF
openssl req -x509 -newkey rsa:4096 \
-keyout example.internal.key \
-out example.internal.crt \
-days 3650 -nodes \
-config san.cnf
# Install di Caddy
# tls /path/to/example.internal.crt /path/to/example.internal.key
On-Premise CA via ACME (Untuk Enterprise) #
Untuk organisasi yang sudah memiliki PKI internal (Active Directory Certificate Services, HashiCorp Vault, EJBCA, dll.), Caddy bisa dikonfigurasi untuk mendapatkan sertifikat dari CA internal tersebut via protokol ACME:
HashiCorp Vault PKI #
{
cert_issuer acme {
# Vault PKI Secrets Engine ACME endpoint
ca https://vault.internal:8200/v1/pki/acme/directory
# Jika Vault menggunakan TLS dengan internal CA
# trusted_roots /path/to/vault-ca.pem
email [email protected]
}
}
app.company.internal {
reverse_proxy localhost:3000
}
EJBCA (Enterprise Java Bean Certificate Authority) #
{
cert_issuer acme {
ca https://ejbca.company.internal/ejbca/acme/directory
eab {
key_id {env.EJBCA_KEY_ID}
mac_key {env.EJBCA_MAC_KEY}
}
}
}
Microsoft Active Directory Certificate Services (ADCS) #
{
cert_issuer acme {
# ADCS dengan ACME module (butuh setup tambahan di ADCS)
ca https://ca.company.internal/acme/directory
}
}
Konfigurasi TLS untuk Server dengan IP Address #
Server internal sering diakses via IP address, bukan nama domain. Sertifikat untuk IP address membutuhkan pendekatan khusus:
# Buat sertifikat dengan IP sebagai SAN
cat > ip-cert.cnf << EOF
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req
[dn]
CN = 192.168.1.100
[v3_req]
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.100
IP.2 = 10.0.0.50
EOF
openssl req -x509 -newkey rsa:2048 \
-keyout ip-server.key \
-out ip-server.crt \
-days 3650 -nodes \
-config ip-cert.cnf
192.168.1.100 {
tls /etc/ssl/certs/ip-server.crt /etc/ssl/private/ip-server.key
file_server {
root /var/www/html
}
}
Perbandingan: Kapan Menggunakan Apa #
Skenario Rekomendasi
────────────────────────────────────────────────────────────────────
Development localhost Internal CA (caddy trust)
Staging server, domain publik Let's Encrypt staging
Production, domain publik Let's Encrypt production
Production, wildcard Let's Encrypt + DNS challenge
Intranet, domain .internal/.local Internal CA atau sertifikat manual
Server yang akses ke internet dibatasi Internal CA atau sertifikat manual
Enterprise dengan PKI internal Custom ACME CA (Vault, ADCS, dll.)
Perlu sertifikat spesifik dari CA Sertifikat manual
komersial tertentu (DigiCert, etc.)
Troubleshooting Internal CA #
Browser Masih Menampilkan Warning #
# Gejala: Setelah caddy trust, browser masih warning
# Diagnosa: Pastikan root CA sudah terinstall di trust store
# Linux (Chrome/Chromium menggunakan NSS database)
certutil -d sql:$HOME/.pki/nssdb -L | grep caddy
# Jika tidak muncul, install manual:
certutil -d sql:$HOME/.pki/nssdb -A -t "C,," \
-n "Caddy Local Authority" \
-i ~/.local/share/caddy/pki/authorities/local/root.crt
# Restart browser setelah install
Sertifikat Internal Tidak Diterima oleh curl #
# Gejala: curl memberikan error SSL meski browser ok
# curl tidak menggunakan trust store browser, tapi sistem
curl https://example.local/api/health
# error: SSL certificate problem: unable to get local issuer certificate
# Solusi: Tambahkan root CA ke sistem
sudo cp ~/.local/share/caddy/pki/authorities/local/root.crt \
/usr/local/share/ca-certificates/caddy-local.crt
sudo update-ca-certificates
# Atau gunakan flag --cacert untuk satu kali request
curl --cacert ~/.local/share/caddy/pki/authorities/local/root.crt \
https://example.local/api/health
Ringkasan #
- Internal CA (
tls internalataulocal_certs) adalah solusi terbaik untuk development dan server intranet — Caddy bertindak sebagai CA sendiri.- Jalankan
caddy trustsatu kali untuk menginstall root CA ke sistem/browser — setelah itu, semua domain yang dilayani Caddy akan di-trust.- Untuk sertifikat manual, gunakan
tls /path/cert.pem /path/key.pem— pastikan usercaddypunya permission untuk membaca file.- Sertifikat self-signed dengan OpenSSL membutuhkan SAN (Subject Alternative Names) agar kompatibel dengan browser modern — CN saja tidak cukup.
- Untuk enterprise dengan PKI internal, Caddy bisa dikonfigurasi sebagai ACME client terhadap CA internal (Vault, ADCS, EJBCA) via
cert_issuer acme { ca https://... }.- IP address bisa digunakan sebagai site address dengan sertifikat manual — butuh SAN dengan type IP, bukan DNS.