Admin Endpoint

Admin Endpoint #

Caddy memiliki built-in REST API yang berjalan di localhost:2019 secara default. Melalui API ini kamu bisa membaca konfigurasi aktif, mengubahnya secara real-time, memeriksa status sertifikat TLS, memantau upstream reverse proxy, dan bahkan melakukan reload konfigurasi — semua tanpa restart Caddy sama sekali.

Ini adalah salah satu fitur yang membedakan Caddy dari web server tradisional seperti Nginx. Di Nginx, kamu harus edit file konfigurasi dan jalankan nginx -s reload. Di Caddy, kamu bisa langsung POST JSON ke API dan konfigurasi langsung berubah secara atomic.

Default Behavior Admin API #

Saat Caddy pertama kali dijalankan:

  Admin API mendengarkan di: localhost:2019
  Hanya bisa diakses dari: 127.0.0.1 (loopback saja)
  Autentikasi: Tidak ada (tapi hanya localhost yang bisa akses)
  Protocol: HTTP (bukan HTTPS, karena lokal)
  
  Endpoint utama:
  GET    /config/             → Baca seluruh konfigurasi aktif
  POST   /config/             → Replace seluruh konfigurasi
  PATCH  /config/             → Merge perubahan ke konfigurasi
  DELETE /config/             → Hapus konfigurasi (Caddy berhenti serve)
  GET    /id/{id}             → Baca bagian konfigurasi berdasarkan @id
  PUT    /id/{id}             → Ganti elemen berdasarkan @id
  DELETE /id/{id}             → Hapus elemen berdasarkan @id
  GET    /pki/ca/             → Info PKI dan CA lokal
  GET    /reverse_proxy/upstreams/ → Status upstream reverse proxy
  POST   /load                → Load config dari body (format apapun)
  POST   /stop                → Hentikan Caddy secara graceful

Mengakses Admin API #

# Cek apakah Caddy berjalan dan admin API aktif
curl http://localhost:2019/config/

# Output: konfigurasi JSON lengkap yang sedang aktif
# Jika Caddy belum dikonfigurasi: {} atau null

# Pretty print dengan jq
curl -s http://localhost:2019/config/ | jq .

# Cek versi Caddy
curl -s http://localhost:2019/ | jq .

# Output contoh:
# {
#   "status": "ok"
# }

Mengamankan Admin API #

Default konfigurasi (hanya localhost) sudah cukup aman untuk deployment biasa. Tapi ada beberapa skenario di mana kamu perlu konfigurasi lebih lanjut.

Mengubah Listen Address #

{
    # Ubah port admin API
    admin localhost:2020
    
    # Atau bind ke semua interface (BERBAHAYA tanpa firewall!)
    # admin 0.0.0.0:2019
    
    # Atau matikan admin API sepenuhnya
    # admin off
}

example.com {
    reverse_proxy localhost:3000
}

Menonaktifkan Admin API #

Untuk production yang sudah stabil dan tidak perlu dynamic reconfiguration:

{
    # Matikan admin API
    # Caddy tidak bisa diubah konfigurasinya via API setelah ini
    # Perlu restart untuk perubahan konfigurasi
    admin off
}

example.com {
    file_server {
        root /var/www/html
    }
}

Remote Admin dengan TLS #

Untuk mengakses admin API dari server lain secara aman:

{
    admin {
        # Listen di semua interface (bukan hanya localhost)
        listen 0.0.0.0:2019
        
        # Lindungi dengan TLS + client certificate
        enforce_origin
        origins "admin.example.com"
        
        tls {
            # Sertifikat untuk admin endpoint
            cert_file /etc/caddy/admin-cert.pem
            key_file  /etc/caddy/admin-key.pem
            
            # Require client certificate
            client_auth {
                mode require_and_verify
                trusted_ca_certs_pem_files /etc/caddy/admin-ca.pem
            }
        }
    }
}
Jangan pernah expose admin API ke internet tanpa proteksi yang memadai. Admin API tidak memiliki autentikasi bawaan — siapa saja yang bisa mengakses endpoint ini bisa mengubah konfigurasi Caddy sepenuhnya, termasuk menambahkan reverse proxy ke server internal atau mengubah sertifikat TLS.

Semua Endpoint Admin API #

/config/ — Konfigurasi #

# READ: Baca konfigurasi lengkap
curl -s http://localhost:2019/config/ | jq .

# READ: Baca bagian tertentu dari konfigurasi
# Path mengikuti struktur JSON konfigurasi
curl -s http://localhost:2019/config/apps/http/servers/ | jq .
curl -s http://localhost:2019/config/apps/tls/ | jq .
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/ | jq .

# CREATE/REPLACE: Ganti konfigurasi lengkap
curl -X POST http://localhost:2019/config/ \
  -H "Content-Type: application/json" \
  -d '{ "apps": { "http": { "servers": { ... } } } }'

# PATCH: Tambahkan atau update bagian tertentu
curl -X PATCH http://localhost:2019/config/apps/http/servers/srv0/routes/ \
  -H "Content-Type: application/json" \
  -d '[{ ... route baru ... }]'

# DELETE: Hapus bagian konfigurasi
curl -X DELETE http://localhost:2019/config/apps/http/servers/srv0/routes/0

# Tambahkan elemen ke array
curl -X POST "http://localhost:2019/config/apps/http/servers/srv0/routes/" \
  -H "Content-Type: application/json" \
  -d '{ ... route baru ... }'

/reverse_proxy/upstreams/ — Status Upstream #

# Lihat semua upstream dan statusnya
curl -s http://localhost:2019/reverse_proxy/upstreams/ | jq .

# Output contoh:
# [
#   {
#     "address": "backend-1:3000",
#     "healthy": true,
#     "num_requests": 12345,
#     "fails": 0
#   },
#   {
#     "address": "backend-2:3000",
#     "healthy": false,
#     "num_requests": 11982,
#     "fails": 3
#   }
# ]

/pki/ca/ — PKI dan Sertifikat #

# Info CA lokal Caddy
curl -s http://localhost:2019/pki/ca/local | jq .

# Output contoh:
# {
#   "id": "local",
#   "name": "Caddy Local Authority",
#   "root_common_name": "Caddy Local Authority - ...",
#   "intermediate_common_name": "Caddy Local Authority - ...",
#   "root": {
#     "public_key_algorithm": "ECDSA",
#     "subject": { ... },
#     "not_before": "...",
#     "not_after": "...",
#     "pem": "-----BEGIN CERTIFICATE-----\n..."
#   }
# }

# Export root certificate
curl -s http://localhost:2019/pki/ca/local | jq -r '.root.pem' \
    > caddy-root-ca.pem

/load — Load Konfigurasi dari File #

# Load konfigurasi dari Caddyfile (format otomatis terdeteksi)
curl -X POST http://localhost:2019/load \
  -H "Content-Type: text/caddyfile" \
  --data-binary @/etc/caddy/Caddyfile

# Load dari JSON
curl -X POST http://localhost:2019/load \
  -H "Content-Type: application/json" \
  --data-binary @/etc/caddy/config.json

/stop — Hentikan Caddy #

# Hentikan Caddy secara graceful (tunggu request yang sedang diproses selesai)
curl -X POST http://localhost:2019/stop

# Setelah ini Caddy berhenti dan proses exit
# (Caddy akan di-restart oleh systemd jika dikonfigurasi dengan Restart=on-failure)

API menggunakan path yang mencerminkan struktur JSON konfigurasi. Ini sangat powerful tapi butuh pemahaman struktur:

/config/                                     → Root konfigurasi
/config/apps/                                → Semua aplikasi
/config/apps/http/                           → Aplikasi HTTP
/config/apps/http/servers/                   → Semua server HTTP
/config/apps/http/servers/srv0/              → Server pertama
/config/apps/http/servers/srv0/routes/       → Routes server pertama
/config/apps/http/servers/srv0/routes/0/     → Route index 0
/config/apps/tls/                            → Aplikasi TLS
/config/apps/tls/automation/                 → Automasi sertifikat
/config/apps/tls/automation/policies/        → Policy sertifikat
/config/logging/                             → Konfigurasi logging
# Contoh: Lihat semua routes
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/ | jq .

# Lihat route pertama
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/0 | jq .

# Lihat handler dalam route pertama
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/0/handle/ | jq .

Menggunakan @id untuk Referensi yang Lebih Mudah #

Navigasi via index (routes/0, routes/1) mudah berubah jika konfigurasi dimodifikasi. Caddy mendukung custom @id untuk referensi yang lebih stabil:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "routes": [
            {
              "@id": "main-app-route",
              "match": [{"host": ["example.com"]}],
              "handle": [...]
            },
            {
              "@id": "api-route",
              "match": [{"host": ["api.example.com"]}],
              "handle": [...]
            }
          ]
        }
      }
    }
  }
}
# Akses via @id — tidak terpengaruh perubahan posisi
curl -s http://localhost:2019/id/main-app-route | jq .
curl -s http://localhost:2019/id/api-route | jq .

# Update route berdasarkan @id
curl -X PUT http://localhost:2019/id/main-app-route \
  -H "Content-Type: application/json" \
  -d '{ "@id": "main-app-route", "match": [...], "handle": [...] }'

Monitoring via Admin API #

#!/bin/bash
# Script monitoring sederhana menggunakan admin API

echo "=== Caddy Status ==="
echo ""

echo "--- Upstream Health ---"
curl -s http://localhost:2019/reverse_proxy/upstreams/ | jq -r \
  '.[] | "\(.address): \(if .healthy then "✓ healthy" else "✗ UNHEALTHY" end) | requests: \(.num_requests) | fails: \(.fails)"'

echo ""
echo "--- TLS Certificates ---"
curl -s http://localhost:2019/config/apps/tls/ 2>/dev/null | jq -r \
  '.automation.policies[]?.subjects[]? // "no policies"' 2>/dev/null || echo "TLS info not available"

echo ""
echo "--- Active Routes ---"
curl -s http://localhost:2019/config/apps/http/servers/srv0/routes/ 2>/dev/null | \
  jq -r '.[] | "Route: \(.match[0].host // ["*"] | join(", "))"' 2>/dev/null || echo "No routes"

Ringkasan #

  • Admin API default berjalan di localhost:2019 — hanya bisa diakses dari mesin itu sendiri, tidak perlu autentikasi untuk akses lokal.
  • Gunakan admin off di global options jika kamu tidak butuh dynamic reconfiguration di production untuk meminimalkan attack surface.
  • Jangan expose admin API ke internet tanpa TLS + client certificate — tidak ada autentikasi bawaan.
  • Navigasi API menggunakan path JSON: /config/apps/http/servers/srv0/routes/ untuk melihat atau memodifikasi routes.
  • Gunakan @id di JSON konfigurasi untuk referensi yang stabil — lebih reliable dari index numerik yang bisa berubah.
  • Endpoint /reverse_proxy/upstreams/ sangat berguna untuk monitoring health status upstream secara real-time.

← Sebelumnya: Passive Health Check   Berikutnya: Config API →

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