Caddy DNS

Caddy DNS #

Plugin caddy-dns memungkinkan Caddy mendapatkan sertifikat TLS wildcard melalui DNS-01 ACME challenge. Berbeda dari HTTP-01 challenge (yang memerlukan akses publik ke port 80), DNS-01 challenge dilakukan sepenuhnya melalui DNS record — sehingga cocok untuk server internal, server di belakang firewall, atau kebutuhan wildcard certificate.

Mengapa DNS Challenge? #

HTTP-01 Challenge (default Caddy):
  + Simple, tidak perlu konfigurasi tambahan
  + Works out of the box
  - Butuh port 80 bisa diakses dari internet
  - Tidak bisa digunakan untuk internal servers
  - Tidak support wildcard certificate (*.example.com)

DNS-01 Challenge (via caddy-dns):
  + Support wildcard certificate (*.example.com)
  + Bekerja untuk server internal / di belakang firewall
  + Tidak butuh port 80 terbuka ke internet
  - Butuh API access ke DNS provider
  - Propagasi DNS butuh waktu (30 detik - beberapa menit)
  - Perlu mengelola API credentials dengan aman

Provider yang Didukung #

Provider                    Module
──────────────────────────────────────────────────────────────────
Cloudflare                  github.com/caddy-dns/cloudflare
AWS Route53                 github.com/caddy-dns/route53
Google Cloud DNS            github.com/caddy-dns/googleclouddns
Azure DNS                   github.com/caddy-dns/azure
DigitalOcean                github.com/caddy-dns/digitalocean
Namecheap                   github.com/caddy-dns/namecheap
Gandi                       github.com/caddy-dns/gandi
Hetzner                     github.com/caddy-dns/hetzner
Porkbun                     github.com/caddy-dns/porkbun
Vultr                       github.com/caddy-dns/vultr
DNSimple                    github.com/caddy-dns/dnsimple
GoDaddy                     github.com/caddy-dns/godaddy
dan puluhan lainnya...      https://github.com/caddy-dns

Instalasi: Cloudflare (Paling Umum) #

xcaddy build \
    --with github.com/caddy-dns/cloudflare
# Buat Cloudflare API Token (bukan API Key global!)
# Di Cloudflare Dashboard:
# My Profile → API Tokens → Create Token
# Template: "Edit zone DNS"
# Zone Resources: Include - Specific zone - example.com
# (Beri akses hanya ke zone yang diperlukan, bukan semua)

# Simpan token sebagai environment variable
export CF_API_TOKEN="your-cloudflare-api-token-here"

Konfigurasi Wildcard Certificate — Cloudflare #

{
    # Konfigurasi global TLS untuk menggunakan DNS challenge
    email [email protected]
}

# Wildcard certificate untuk semua subdomain
*.example.com example.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
    
    # Routing berdasarkan subdomain
    @app    host app.example.com
    @api    host api.example.com
    @admin  host admin.example.com
    
    handle @app {
        reverse_proxy app-backend:3000
    }
    
    handle @api {
        reverse_proxy api-backend:8080
    }
    
    handle @admin {
        basicauth { ... }
        reverse_proxy admin-backend:9000
    }
    
    # Default handler
    handle {
        root * /var/www/html
        file_server
    }
}

Konfigurasi Route53 — AWS #

xcaddy build \
    --with github.com/caddy-dns/route53
{
    email [email protected]
}

*.example.com example.com {
    tls {
        dns route53 {
            # Opsi 1: Gunakan IAM role (direkomendasikan di AWS)
            # Tidak perlu konfigurasi credentials eksplisit
            # Caddy akan menggunakan instance role otomatis
            
            # Opsi 2: Access key eksplisit
            access_key_id     {env.AWS_ACCESS_KEY_ID}
            secret_access_key {env.AWS_SECRET_ACCESS_KEY}
            region            {env.AWS_REGION}
            
            # Opsi 3: Profile dari ~/.aws/credentials
            # profile my-profile
        }
    }
    
    reverse_proxy backend:3000
}
// IAM Policy minimum untuk Route53 DNS challenge
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:GetChange",
                "route53:ChangeResourceRecordSets",
                "route53:ListResourceRecordSets"
            ],
            "Resource": [
                "arn:aws:route53:::hostedzone/YOUR_HOSTED_ZONE_ID",
                "arn:aws:route53:::change/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": "route53:ListHostedZonesByName",
            "Resource": "*"
        }
    ]
}

Internal Server dengan DNS Challenge #

Skenario paling umum penggunaan DNS challenge: server yang tidak bisa diakses dari internet:

{
    email [email protected]
    
    # Gunakan CA internal untuk sertifikat internal
    # (Atau Let's Encrypt jika domain public tapi server internal)
}

# Server internal — tidak perlu port 80 terbuka ke internet
internal.company.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
    
    # Hanya izinkan akses dari jaringan internal
    @external not remote_ip 10.0.0.0/8 192.168.0.0/16
    respond @external 403
    
    reverse_proxy internal-app:8080
}

DNS Challenge untuk Multi-Domain #

{
    email [email protected]
}

# Wildcard untuk domain utama
*.example.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
    
    reverse_proxy backend:3000
}

# Wildcard untuk domain lain (multi-tenant)
*.client-a.com *.client-b.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }
    
    # Map ke backend berdasarkan domain
    reverse_proxy backend:3000
}

Keamanan API Key #

# JANGAN simpan API key langsung di Caddyfile!
# Gunakan environment variables

# /etc/caddy/caddy.env (mode 600, owned by caddy user)
cat > /etc/caddy/caddy.env << 'EOF'
CF_API_TOKEN=your-cloudflare-token
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
EOF

chmod 600 /etc/caddy/caddy.env
chown caddy:caddy /etc/caddy/caddy.env

# Tambahkan ke systemd service
sudo systemctl edit caddy
# /etc/systemd/system/caddy.service.d/override.conf
[Service]
EnvironmentFile=/etc/caddy/caddy.env
sudo systemctl daemon-reload
sudo systemctl restart caddy

# Verifikasi environment tersedia
sudo systemctl show caddy --property=Environment

Troubleshooting DNS Challenge #

# 1. Cek apakah Caddy berhasil membuat TXT record
# Setelah inisiasi, Caddy harusnya buat record:
# _acme-challenge.example.com TXT "..."
dig TXT _acme-challenge.example.com

# 2. Cek log Caddy untuk error DNS challenge
sudo journalctl -u caddy -n 50 | grep -i "dns\|acme\|tls"

# 3. Debug mode untuk TLS
# Di global options:
# { debug }
# Lalu perhatikan log untuk "dns-01" challenge

# 4. Error umum:
# "permission denied" → API token tidak punya permission yang cukup
# "zone not found" → Domain tidak di account Cloudflare tersebut
# "propagation timeout" → DNS lambat propagasi, tambah delay:
{
    email [email protected]
}

*.example.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
        
        # Tunggu lebih lama untuk propagasi DNS
        # (default biasanya cukup, tapi beberapa DNS provider lambat)
        resolvers 1.1.1.1 8.8.8.8
    }
}

Ringkasan #

  • Plugin caddy-dns tersedia untuk hampir semua DNS provider populer — install hanya provider yang kamu gunakan.
  • DNS-01 challenge adalah satu-satunya cara mendapatkan wildcard certificate (*.example.com) — tidak bisa dilakukan dengan HTTP-01.
  • Simpan API credentials di environment variables atau file terpisah (mode 600) — jangan pernah hardcode di Caddyfile yang masuk ke version control.
  • Gunakan API token dengan permission minimal — hanya izinkan akses ke zone yang diperlukan, bukan seluruh akun DNS.
  • Untuk server internal yang tidak bisa diakses internet, DNS-01 adalah satu-satunya pilihan untuk mendapatkan sertifikat dari public CA seperti Let’s Encrypt.
  • Jika DNS challenge gagal, cek propagasi TXT record dengan dig TXT _acme-challenge.example.com — record harus muncul sebelum Let’s Encrypt memverifikasi.

← Sebelumnya: Plugin Populer   Berikutnya: Buat Plugin →


DNS Challenge dengan ZeroSSL #

ZeroSSL adalah alternatif Let’s Encrypt yang juga mendukung wildcard certificate via DNS challenge:

{
    email [email protected]
    
    # ZeroSSL perlu EAB credentials
    # Dapatkan dari: https://app.zerossl.com/developer
}

*.example.com example.com {
    tls {
        ca https://acme.zerossl.com/v2/DV90
        
        # External Account Binding credentials
        eab_key_id     {env.ZEROSSL_KEY_ID}
        eab_mac_key    {env.ZEROSSL_MAC_KEY}
        
        # DNS challenge
        dns cloudflare {env.CF_API_TOKEN}
    }
    
    reverse_proxy backend:3000
}

Menggunakan Dua Provider Sekaligus (Fallback) #

{
    email [email protected]
}

*.example.com example.com {
    tls {
        # Caddy otomatis fallback ke issuer kedua jika pertama gagal
        issuer acme {
            ca https://acme-v02.api.letsencrypt.org/directory
            dns cloudflare {env.CF_API_TOKEN}
        }
        issuer acme {
            ca https://acme.zerossl.com/v2/DV90
            eab_key_id  {env.ZEROSSL_KEY_ID}
            eab_mac_key {env.ZEROSSL_MAC_KEY}
            dns cloudflare {env.CF_API_TOKEN}
        }
    }
    
    reverse_proxy backend:3000
}

Konfigurasi ini memberikan redundansi — jika Let’s Encrypt tidak tersedia, Caddy otomatis mencoba ZeroSSL. Kedua provider menawarkan sertifikat gratis untuk domain publik.

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