API
API (관리 엔드포인트)
Caddy는 HTTP로 REST API를 통해 접근할 수 있는 관리 엔드포인트로 설정돼요. 이 엔드포인트는 Caddy config에서 설정할 수 있어요.
출처: Caddy 공식 문서
본문
Caddy는 HTTP로 REST API를 통해 접근할 수 있는 관리 엔드포인트로 설정돼요. Caddy config에서 이 엔드포인트를 설정할 수 있어요.
기본 주소: localhost:2019
기본 주소는 CADDY_ADMIN 환경 변수를 설정해 바꿀 수 있어요. 일부 설치 방법은 이를 다르게 설정할 수 있어요. Caddy config의 주소는 항상 기본값보다 우선해요.
서버에서 신뢰할 수 없는 코드를 실행한다면(😬) 프로세스를 격리하고, 취약한 프로그램을 패치하고, 엔드포인트를 권한이 있는 유닉스 소켓에 바인딩하도록 설정해서 관리 엔드포인트를 보호하세요.
최신 설정은 변경 후 디스크에 저장돼요(비활성화하지 않는 한). 재시작 후 마지막으로 동작한 config를 caddy run --resume으로 이어갈 수 있어요. 이는 정전이나 그와 유사한 상황에서도 config 내구성을 보장해요.
API를 시작하려면 API 튜토리얼을 시도하거나, 시간이 1분뿐이라면 API 빠른 시작 가이드를 참고해요.
-
POST /load — 활성 설정을 설정하거나 교체
-
POST /stop — 활성 설정을 중지하고 프로세스 종료
-
GET /config/[path] — 명명된 경로의 config 내보내기
-
POST /config/[path] — 객체 설정/교체; 배열에 추가
-
PUT /config/[path] — 새 객체 생성; 배열에 삽입
-
PATCH /config/[path] — 기존 객체 또는 배열 요소 교체
-
DELETE /config/[path] — 명명된 경로의 값 삭제
-
@idJSON에서 사용하기 — config 구조를 쉽게 탐색 -
동시 config 변경 — 동기화되지 않은 변경 시 충돌 방지
-
POST /adapt — 실행하지 않고 config를 JSON으로 어댑트
-
GET /pki/ca/ — 특정 PKI 앱 CA 정보 반환
-
GET /pki/ca//certificates — 특정 PKI 앱 CA의 인증서 체인 반환
-
GET /reverse_proxy/upstreams — 설정된 프록시 업스트림의 현재 상태 반환
POST /load
Caddy의 설정을 설정해 이전 설정을 덮어써요. reload가 완료되거나 실패할 때까지 차단돼요. 설정 변경은 가볍고 효율적이며 제로 다운타임을 일으켜요. 새 config가 어떤 이유로든 실패하면 이전 config가 다운타임 없이 제자리로 롤백돼요.
이 엔드포인트는 config 어댑터를 사용해 다른 config 형식을 지원해요. 요청의 Content-Type 헤더는 요청 본문에 사용된 config 형식을 나타내요. 보통 Caddy의 네이티브 config 형식인 application/json이어야 해요. 다른 config 형식에는 슬래시 / 뒤의 값이 사용할 config 어댑터 이름이 되도록 적절한 Content-Type을 지정해요. 예를 들어 Caddyfile을 제출할 때는 text/caddyfile 같은 값을 쓰고, JSON 5에는 application/json5 같은 값을 써요.
새 config가 현재 것과 같으면 reload가 일어나지 않아요. reload를 강제하려면 요청 헤더에 Cache-Control: must-revalidate를 설정해요.
config 어댑터가 경고를 emit했다면 성공 응답은 warnings 배열이 있는 JSON 본문을 갖고, 그 외에는 응답 본문이 비어 있어요. config를 어댑트하거나 로드할 수 없으면 응답은 상태 400과 error 메시지가 있는 JSON 본문, 그리고 어댑터의 warnings를 포함해요:
{
"error": "loading config: ...",
"warnings": [
{
"file": "Caddyfile",
"line": 2,
"message": "..."
}
]
}
예시
새 활성 설정을 설정해요:
curl "http://localhost:2019/load" \
-H "Content-Type: application/json" \
-d @caddy.json
참고: curl의 -d 플래그는 줄바꿈을 제거하므로, config 형식이 줄바꿈에 민감하면(예: Caddyfile) 대신 --data-binary를 사용해요:
curl "http://localhost:2019/load" \
-H "Content-Type: text/caddyfile" \
--data-binary @Caddyfile
POST /stop
서버를 우아하게 종료하고 프로세스를 종료해요. 프로세스를 종료하지 않고 실행 중인 설정만 중지하려면 DELETE /config/를 사용해요.
예시
프로세스를 중지해요:
curl -X POST "http://localhost:2019/stop"
GET /config/[path]
명명된 경로에서 Caddy의 현재 설정을 내보내요. JSON 본문을 반환해요.
예시
전체 config를 내보내고 예쁘게 출력해요:
curl "http://localhost:2019/config/" | jq
{
"apps": {
"http": {
"servers": {
"myserver": {
"listen": [
":443"
],
"routes": [
{
"match": [
{
"host": [
"example.com"
]
}
],
"handle": [
{
"handler": "file_server"
}
]
}
]
}
}
}
}
}
리스너 주소만 내보내요:
curl "http://localhost:2019/config/apps/http/servers/myserver/listen"
[":443"]
POST /config/[path]
명명된 경로에서 Caddy의 설정을 요청의 JSON 본문으로 변경해요. 대상 값이 배열이면 POST는 추가하고, 객체면 생성하거나 교체해요.
특수한 경우로, 다음 조건이면 배열에 여러 항목을 추가할 수 있어요:
-
경로가
/...로 끝나고 -
/...앞의 경로 요소가 배열을 가리키고 -
페이로드가 배열인 경우
이 경우 페이로드 배열의 요소가 확장되고 각각 대상 배열에 추가돼요. Go 용어로 이는 다음과 같은 효과예요:
baseSlice = append(baseSlice, newElems...)
예시
리스너 주소를 추가해요:
curl \
-H "Content-Type: application/json" \
-d '":8080"' \
"http://localhost:2019/config/apps/http/servers/myserver/listen"
여러 리스너 주소를 추가해요:
curl \
-H "Content-Type: application/json" \
-d '["127.0.0.1:8080", ":5133"]' \
"http://localhost:2019/config/apps/http/servers/myserver/listen/..."
PUT /config/[path]
명명된 경로에서 Caddy의 설정을 요청의 JSON 본문으로 변경해요. 대상 값이 배열의 위치(인덱스)이면 PUT은 삽입하고, 객체면 엄격히 새 값을 생성해요.
예시
첫 번째 슬롯에 리스너 주소를 추가해요:
curl -X PUT \
-H "Content-Type: application/json" \
-d '":8080"' \
"http://localhost:2019/config/apps/http/servers/myserver/listen/0"
PATCH /config/[path]
명명된 경로에서 Caddy의 설정을 요청의 JSON 본문으로 변경해요. PATCH는 엄격히 기존 값이나 배열 요소를 교체해요.
예시
리스너 주소를 교체해요:
curl -X PATCH \
-H "Content-Type: application/json" \
-d '["127.0.0.1:8081", ":8082"]' \
"http://localhost:2019/config/apps/http/servers/myserver/listen"
DELETE /config/[path]
명명된 경로에서 Caddy의 설정을 제거해요. DELETE는 대상 값을 삭제해요.
예시
전체 현재 설정을 언로드하되 프로세스는 계속 실행되게 해요:
curl -X DELETE "http://localhost:2019/config/"
HTTP 서버 하나만 중지하려면:
curl -X DELETE "http://localhost:2019/config/apps/http/servers/myserver"
JSON에서 @id 사용하기
JSON 문서에 ID를 임베드해 JSON의 해당 부분에 더 쉽게 직접 접근할 수 있어요.
객체에 "@id"라는 필드를 추가하고 고유한 이름을 주면 돼요. 예를 들어 자주 접근하고 싶은 reverse proxy 핸들러가 있다면:
{
"@id": "my_proxy",
"handler": "reverse_proxy"
}
사용하려면 /id/ API 엔드포인트에 해당 /config/ 엔드포인트처럼 요청하면 되고, 전체 경로는 필요 없어요. ID가 요청을 config의 해당 범위로 직접 데려가줘요.
예를 들어 ID 없이 reverse proxy의 업스트림에 접근하려면 경로가 대략 이렇게 될 거예요:
/config/apps/http/servers/myserver/routes/1/handle/0/upstreams
하지만 ID를 쓰면 경로는 이렇게 돼요:
/id/my_proxy/upstreams
기억하고 손으로 쓰기가 훨씬 쉬워요.
동시 config 변경 (Concurrent config changes)
이 섹션은 모든 /config/ 엔드포인트에 적용돼요. 실험적이며 변경될 수 있어요.
Caddy의 config API는 개별 요청에 ACID 보장을 제공하지만, 단일 요청을 넘는 변경은 제대로 동기화되지 않으면 충돌이나 데이터 손실이 발생할 수 있어요.
예를 들어 두 클라이언트가 동시에 GET /config/foo를 하고, 그 범위(config 경로) 안에서 편집한 다음, 동시에 POST|PUT|PATCH|DELETE /config/foo/...를 호출해 변경을 적용하면 충돌이 발생할 수 있어요. 하나가 다른 하나를 덮어쓰거나, 두 번째 변경이 준비했던 것과 다른 config 버전에 적용되어 config를 의도하지 않은 상태로 남길 수 있어요. 변경들이 서로를 인지하지 못하기 때문이에요.
Caddy의 API는 여러 요청에 걸친 트랜잭션을 지원하지 않고, HTTP는 무상태 프로토콜이에요. 하지만 Etag와 If-Match 헤더를 사용해 모든 변경에 대해 일종의 낙관적 동시성 제어로 충돌을 감지·방지할 수 있어요. 동기화 없이 Caddy의 /config/... 엔드포인트를 동시에 사용할 가능성이 있다면 유용해요. 모든 GET /config/... 응답은 그 범위의 경로와 내용 해시를 담은 Etag라는 HTTP 헤더를 갖고 있어요(예: Etag: "/config/apps/http/servers 65760b8e"). 변경 요청에 If-Match 헤더를 이전 GET 요청의 Etag 헤더 값으로 설정하면 돼요.
기본 알고리즘은 다음과 같아요:
-
config 내 임의의 범위
S에GET요청을 수행하고 응답의Etag헤더를 잡아둬요. -
반환된 config에 원하는 변경을 가해요.
-
범위
S내에서POST|PUT|PATCH|DELETE요청을 수행하고,If-Match요청 헤더를 저장된Etag값으로 설정해요. -
응답이 HTTP 412(Precondition Failed)면 1단계부터 반복하거나, 너무 많이 시도한 후 포기해요.
이 알고리즘은 명시적 동기화 없이 Caddy 설정에 대한 여러 겹치는 변경을 안전하게 허용해요. config의 다른 부분에 대한 동시 변경은 재시도가 필요 없도록 설계됐어요. config의 같은 범위와 겹치는 변경만 충돌을 일으킬 수 있고 따라서 재시도가 필요해요.
POST /adapt
설정을 로드하거나 실행하지 않고 Caddy JSON으로 어댑트해요. 성공하면 결과 JSON 문서가 응답 본문에 반환돼요.
Content-Type 헤더는 /load와 같은 방식으로 config 형식을 지정하는 데 사용돼요. 예를 들어 Caddyfile을 어댑트하려면 Content-Type: text/caddyfile을 설정해요.
이 엔드포인트는 관련 config 어댑터가 Caddy 빌드에 연결되어 있는 한 어떤 config 형식이든 어댑트해요.
예시
Caddyfile을 JSON으로 어댑트해요:
curl "http://localhost:2019/adapt" \
-H "Content-Type: text/caddyfile" \
--data-binary @Caddyfile
GET /pki/ca/
ID로 특정 PKI 앱 CA에 대한 정보를 반환해요. 요청한 CA ID가 기본값(local)이면 아직 프로비저닝되지 않았다면 CA가 프로비저닝돼요. 다른 CA ID는 이전에 프로비저닝되지 않았다면 에러를 반환해요.
curl "http://localhost:2019/pki/ca/local" | jq
{
"id": "local",
"name": "Caddy Local Authority",
"root_common_name": "Caddy Local Authority - 2022 ECC Root",
"intermediate_common_name": "Caddy Local Authority - ECC Intermediate",
"root_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... gRw==\n-----END CERTIFICATE-----\n",
"intermediate_certificate": "-----BEGIN CERTIFICATE-----\nMIIB ... FzQ==\n-----END CERTIFICATE-----\n"
}
GET /pki/ca//certificates
ID로 특정 PKI 앱 CA의 인증서 체인을 반환해요. 요청한 CA ID가 기본값(local)이면 아직 프로비저닝되지 않았다면 CA가 프로비저닝돼요. 다른 CA ID는 이전에 프로비저닝되지 않았다면 에러를 반환해요.
이 엔드포인트는 CA의 루트 인증서를 시스템의 신뢰 저장소에 설치할 수 있게 해주는 caddy trust 명령이 내부적으로 사용해요.
curl "http://localhost:2019/pki/ca/local/certificates"
-----BEGIN CERTIFICATE-----
MIIByDCCAW2gAwIBAgIQViS12trTXBS/nyxy7Zg9JDAKBggqhkjOPQQDAjAwMS4w
...
By75JkP6C14OfU733oElfDUMa5ctbMY53rWFzQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIBpDCCAUmgAwIBAgIQTS5a+3LUKNxC6qN3ZDR8bDAKBggqhkjOPQQDAjAwMS4w
...
9M9t0FwCIQCAlUr4ZlFzHE/3K6dARYKusR1ck4A3MtucSSyar6lgRw==
-----END CERTIFICATE-----
GET /reverse_proxy/upstreams
설정된 reverse proxy 업스트림(백엔드)의 현재 상태를 JSON 문서로 반환해요.
curl "http://localhost:2019/reverse_proxy/upstreams" | jq
[
{"address": "10.0.1.1:80", "num_requests": 4, "fails": 2},
{"address": "10.0.1.2:80", "num_requests": 5, "fails": 4},
{"address": "10.0.1.3:80", "num_requests": 3, "fails": 3}
]
JSON 배열의 각 항목은 전역 업스트림 풀에 저장된 설정된 업스트림이에요.
-
address는 업스트림의 다이얼 주소예요.
-
num_requests는 현재 업스트림이 처리 중인 활성 요청 수예요.
-
fails는 수동 상태 확인에 따라 기억된 현재 실패한 요청 수예요.
백엔드의 가용성을 결정하는 것이 목표라면, 사용 중인 핸들러 설정과 업스트림의 관련 속성을 교차 확인해야 해요. 예를 들어 프록시에 수동 상태 확인을 활성화했다면, 업스트림이 가용한지 결정하려면 fails와 num_requests 값도 고려해야 해요. fails가 프록시에 대해 설정한 최대 실패 수(즉 max_fails)보다 작고, num_requests가 프록시 전체에 대해 설정한 업스트림당 최대 요청 수(즉 unhealthy_request_count)나 개별 업스트림에 대한 max_requests보다 작거나 같은지 확인해요.