Caddy JSON

Caddy JSON #

Caddy JSON adalah format konfigurasi native Caddy — semua konfigurasi, termasuk Caddyfile, pada akhirnya dikonversi ke JSON sebelum digunakan oleh Caddy. Caddyfile adalah lapisan abstraksi yang ramah manusia, tapi di balik layar Caddy selalu bekerja dengan JSON.

Memahami Caddy JSON membuka kemungkinan yang tidak bisa dilakukan dengan Caddyfile: konfigurasi yang sangat granular, integrasi dengan Config API, penggunaan fitur-fitur yang belum ada shortcut-nya di Caddyfile, dan pembuatan tooling yang menghasilkan konfigurasi Caddy secara programatik.

Mengapa Memahami Caddy JSON #

Caddyfile:          Caddy JSON:
──────────────────────────────────────────────────
Ramah manusia       Native format Caddy
Mudah ditulis       Lebih verbose tapi lebih lengkap
Kurang ekspresif    Akses semua opsi modul
Tidak cocok untuk   Cocok untuk Config API
programmatic use    dan tooling
Cocok untuk         Bisa di-generate programatik
manusia             (misalnya dari database)

Struktur Top-Level Caddy JSON #

{
  "admin": { ... },        // Konfigurasi admin API
  "logging": { ... },      // Konfigurasi logging global
  "storage": { ... },      // Storage untuk sertifikat TLS
  "apps": {
    "http": { ... },       // Aplikasi HTTP server
    "tls": { ... },        // Aplikasi TLS / cert management
    "layer4": { ... },     // TCP/UDP proxy (opsional)
    "dns": { ... }         // DNS server (opsional)
  }
}

Mengkonversi Caddyfile ke JSON #

Cara termudah memahami struktur JSON adalah mengkonversi Caddyfile yang sudah kamu buat:

# Konversi Caddyfile ke JSON
caddy adapt --config /etc/caddy/Caddyfile --adapter caddyfile

# Pretty print dengan jq
caddy adapt --config /etc/caddy/Caddyfile --adapter caddyfile | jq .

# Simpan ke file
caddy adapt --config /etc/caddy/Caddyfile --adapter caddyfile \
  | jq . > /etc/caddy/config.json

Contoh Konversi #

Caddyfile:

example.com {
    reverse_proxy localhost:3000
    encode gzip
    log {
        output file /var/log/caddy/access.log
        format json
    }
}

Hasil JSON (caddy adapt output, disederhanakan):

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [":443", ":80"],
          "routes": [
            {
              "match": [{"host": ["example.com"]}],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "encode",
                          "encodings": {"gzip": {}}
                        }
                      ]
                    },
                    {
                      "handle": [
                        {
                          "handler": "reverse_proxy",
                          "upstreams": [{"dial": "localhost:3000"}]
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            }
          ],
          "logs": {
            "logger_names": {
              "example.com": "log0"
            }
          }
        }
      }
    },
    "tls": {
      "automation": {
        "policies": [
          {
            "subjects": ["example.com"],
            "issuers": [
              {
                "module": "acme",
                "ca": "https://acme-v02.api.letsencrypt.org/directory"
              }
            ]
          }
        ]
      }
    }
  },
  "logging": {
    "logs": {
      "log0": {
        "writer": {
          "output": "file",
          "filename": "/var/log/caddy/access.log"
        },
        "encoder": {"format": "json"}
      }
    }
  }
}

Anatomi Routes #

Routes adalah jantung dari konfigurasi HTTP Caddy:

{
  "routes": [
    {
      "@id": "optional-stable-id",
      
      "match": [
        {
          "host": ["example.com", "www.example.com"],
          "path": ["/api/*"],
          "method": ["GET", "POST"],
          "header": {
            "Content-Type": ["application/json"]
          },
          "remote_ip": {
            "ranges": ["192.168.0.0/16"]
          }
        }
      ],
      
      "handle": [
        {
          "handler": "headers",
          "response": {
            "set": {
              "X-Custom-Header": ["value"]
            }
          }
        },
        {
          "handler": "reverse_proxy",
          "upstreams": [
            {"dial": "backend:3000"}
          ]
        }
      ],
      
      "terminal": true
    }
  ]
}

Handler Types #

// Static file server
{
  "handler": "file_server",
  "root": "/var/www/html",
  "index_names": ["index.html"],
  "browse": {}
}

// Reverse proxy
{
  "handler": "reverse_proxy",
  "upstreams": [
    {"dial": "backend-1:3000"},
    {"dial": "backend-2:3000"}
  ],
  "load_balancing": {
    "selection_policy": {
      "policy": "least_conn"
    }
  },
  "health_checks": {
    "active": {
      "uri": "/health",
      "interval": "10s",
      "timeout": "5s",
      "expect_status": 200
    },
    "passive": {
      "fail_duration": "30s",
      "max_fails": 3
    }
  }
}

// Static response
{
  "handler": "static_response",
  "status_code": 301,
  "headers": {
    "Location": ["https://example.com{http.request.uri}"]
  }
}

// Encode (compression)
{
  "handler": "encode",
  "encodings": {
    "gzip": {},
    "zstd": {}
  },
  "minimum_length": 1024
}

Konfigurasi TLS dalam JSON #

{
  "apps": {
    "tls": {
      "automation": {
        "policies": [
          {
            "subjects": ["example.com", "*.example.com"],
            "issuers": [
              {
                "module": "acme",
                "ca": "https://acme-v02.api.letsencrypt.org/directory",
                "email": "[email protected]",
                "challenges": {
                  "dns": {
                    "provider": {
                      "name": "cloudflare",
                      "api_token": "{env.CF_API_TOKEN}"
                    }
                  }
                }
              },
              {
                "module": "acme",
                "ca": "https://acme.zerossl.com/v2/DV90",
                "external_account": {
                  "key_id": "{env.ZEROSSL_KEY_ID}",
                  "mac_key": "{env.ZEROSSL_MAC_KEY}"
                }
              }
            ]
          },
          {
            "subjects": ["internal.company.com"],
            "issuers": [
              {
                "module": "internal"
              }
            ]
          }
        ]
      }
    }
  }
}

Admin dan Logging dalam JSON #

{
  "admin": {
    "listen": "localhost:2019",
    "enforce_origin": false,
    "origins": ["localhost:2019"]
  },
  
  "logging": {
    "logs": {
      "default": {
        "writer": {
          "output": "stderr"
        },
        "encoder": {
          "format": "console"
        },
        "level": "INFO"
      },
      "access": {
        "writer": {
          "output": "file",
          "filename": "/var/log/caddy/access.log",
          "roll_size_mb": 50,
          "roll_keep": 5,
          "roll_keep_days": 30
        },
        "encoder": {
          "format": "json"
        },
        "include": ["http.log.access"]
      }
    }
  }
}

Menggunakan JSON Langsung #

# Jalankan Caddy dengan JSON config
caddy run --config /etc/caddy/config.json --adapter json

# Atau jika JSON adalah format native (tidak perlu --adapter):
caddy run --config /etc/caddy/config.json

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

Kapan Menggunakan JSON vs Caddyfile #

Gunakan CADDYFILE ketika:
  ✓ Konfigurasi ditulis dan dipelihara oleh manusia
  ✓ Tim tidak familiar dengan format JSON verbose
  ✓ Use case standar (reverse proxy, file server, dll.)
  ✓ Tidak butuh integrasi programatik
  ✓ Untuk sebagian besar deployment production sehari-hari

Gunakan JSON ketika:
  ✓ Konfigurasi di-generate secara programatik
  ✓ Integrasi dengan Config API (platform multi-tenant)
  ✓ Butuh fitur yang belum ada shortcut-nya di Caddyfile
  ✓ Tooling atau infrastruktur yang menghasilkan config
  ✓ Testing dan debugging konfigurasi detail
  ✓ Kubernetes CRD atau Terraform provider yang generate JSON

Ringkasan #

  • Caddy JSON adalah format native — semua Caddyfile dikonversi ke JSON sebelum digunakan. Gunakan caddy adapt untuk melihat JSON yang dihasilkan dari Caddyfile.
  • Struktur top-level: apps (berisi http, tls), admin, logging, dan storage.
  • Routes terdiri dari match (kondisi), handle (handlers), dan terminal (apakah stop matching setelah route ini cocok).
  • Gunakan @id di routes untuk referensi stabil yang bisa digunakan dengan Config API endpoint /id/{id}.
  • JSON lebih verbose dari Caddyfile tapi memberikan akses ke semua opsi modul yang mungkin tidak ada shortcut-nya di Caddyfile.
  • Untuk sebagian besar kebutuhan, Caddyfile sudah lebih dari cukup — gunakan JSON hanya ketika memang diperlukan (programmatic generation, tooling, advanced config).

← Sebelumnya: Reload Config   Berikutnya: Basic Auth →

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