본문 바로가기
WIKI 기술 지식 베이스

tls 지시문

원문 보기 위키 갱신

tls 지시문 (TLS 설정)

사이트의 TLS를 설정해요.

Caddy의 기본 TLS 설정은 안전해요. 이유가 확실하고 그 영향력을 이해하지 못한다면 이 설정을 바꾸지 않는 게 좋아요. 이 지시문의 가장 흔한 용도는 ACME 계정 이메일 주소 지정, ACME CA 엔드포인트 변경, 또는 직접 인증서를 제공하는 거예요.

호환성 참고: 보안 프로토콜이라는 민감한 특성 때문에 TLS 기본값에 대한 의도적인 조정이 새 minor 또는 patch 릴리스에서 이뤄질 수 있어요. 오래됐거나 깨진 TLS 버전, 암호, 기능 등은 언제든 제거될 수 있어요. 배포 환경이 변경에 극도로 민감하다면 반드시 유지해야 할 값을 명시적으로 지정하고 업그레이드에 주의를 기울이세요. 거의 모든 경우 기본 설정을 사용하는 걸 권장해요.

출처: Caddy 공식 문서

본문

사이트의 TLS를 설정해요.

Caddy의 기본 TLS 설정은 안전해요. 이유가 확실하고 그 영향력을 이해하지 못한다면 이 설정을 바꾸지 않는 게 좋아요. 이 지시문의 가장 흔한 용도는 ACME 계정 이메일 주소 지정, ACME CA 엔드포인트 변경, 또는 직접 인증서를 제공하는 거예요.

호환성 참고: 보안 프로토콜이라는 민감한 특성 때문에 TLS 기본값에 대한 의도적인 조정이 새 minor 또는 patch 릴리스에서 이뤄질 수 있어요. 오래됐거나 깨진 TLS 버전, 암호, 기능 등은 언제든 제거될 수 있어요. 배포 환경이 변경에 극도로 민감하다면 반드시 유지해야 할 값을 명시적으로 지정하고 업그레이드에 주의를 기울이세요. 거의 모든 경우 기본 설정을 사용하는 걸 권장해요.

문법 (Syntax)

tls [internal|force_automate|<email>] | [<cert_file> <key_file>] {

	protocols <min> [<max>]
	ciphers   <cipher_suites...>
	curves    <groups...>
	alpn      <values...>
	load      <paths...>
	ca        <ca_dir_url>
	ca_root   <pem_file>
	key_type  ed25519|p256|p384|rsa2048|rsa4096
	dns       <provider_name> [<params...>]
	propagation_timeout <duration>
	propagation_delay   <duration>
	dns_ttl             <duration>
	dns_challenge_override_domain <domain>
	resolvers <dns_servers...>
	eab       <key_id> <mac_key>
	on_demand
	reuse_private_keys
	client_auth {
		mode                   [request|require|verify_if_given|require_and_verify]
		trust_pool             <module>
		verifier 			   <module>
	}
	issuer          <issuer_name>  [<params...>]
	get_certificate <manager_name> [<params...>]
	insecure_secrets_log <log_file>
	renewal_window_ratio <ratio>
	force_automate
}
  • internal은 이 사이트의 인증서를 만들 때 Caddy의 내부적이고 로컬에서 신뢰되는 CA를 사용한다는 뜻이에요. internal 발급자를 더 구성하려면 issuer 하위 지시문을 사용해요.

  • force_automate는 다른 관리 인증서가 적용되더라도 사이트의 인증서 자동화를 강제해요.

  • ****은 사이트의 인증서를 관리하는 ACME 계정에 쓸 이메일 주소예요. 모든 사이트를 한 번에 구성하려면 email글로벌 옵션을 쓰는 게 나을 수도 있어요.

참고로 Let's Encrypt가 인증서 만료가 임박했다는 이메일을 보낼 수 있는데, Caddy가 갱신 시 다른 발급자(예: ZeroSSL)를 썼다면 이는 오해의 소지가 있을 수 있어요. 로그와/또는 인증서 자체(예: 브라우저에서)를 확인해서 어떤 발급자가 사용됐는지, 그리고 그 만료가 여전히 유효한지 확인해요. 그렇다면 Let's Encrypt의 이메일은 안전하게 무시해도 돼요.

  • **<cert_file>**과 **<key_file>**은 인증서와 개인 키 PEM 파일의 경로예요. 하나만 지정하면 유효하지 않아요.

이렇게 로드된 인증서는 모든 사이트가 공유하는 Caddy의 인증서 캐시에 추가돼요. 따라서 로드된 인증서는 tls 지시문이 없는 다른 사이트라도 그 이름을 커버하는 사이트에서도 사용되며, auto_https ignore_loaded_certs 글로벌 옵션이 설정되지 않는 한 Caddy는 그 이름의 인증서를 자동 관리하지 않아요.

  • protocols은 최소 및 최대 프로토콜 버전을 지정해요. 뭘 하고 있는지 모른다면 바꾸지 마세요. Caddy는 항상 현대적인 기본값을 사용하기 때문에 이걸 구성할 일은 거의 없어요.

기본 최소: tls1.2, 기본 최대: tls1.3

  • ciphers은 선호도 내림차순으로 암호 스위트 이름 목록을 지정해요. 뭘 하고 있는지 모른다면 바꾸지 마세요. TLS 1.3에서는 암호 스위트를 커스터마이즈할 수 없고, 모든 TLS 1.2 암호가 기본으로 활성화돼 있지 않다는 점을 유의해요. 지원되는 이름은 (Go stdlib가 선호하는 순서대로):

  • TLS_AES_128_GCM_SHA256

  • TLS_CHACHA20_POLY1305_SHA256

  • TLS_AES_256_GCM_SHA384

  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

  • TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256

  • TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA

  • TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA

  • TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA

  • TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA

  • TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

  • curves은 지원할 EC 그룹 목록을 지정해요. 기본값은 바꾸지 않는 걸 권장해요. 지원되는 값은:

  • x25519mlkem768 (PQC)

  • x25519

  • secp256r1

  • secp384r1

  • secp521r1

  • alpn은 TLS 핸드셰이크의 ALPN 확장에서 광고할 값 목록이에요.

  • load는 인증서+키 번들인 PEM 파일을 로드할 폴더 목록을 지정해요.

  • ca는 ACME CA 엔드포인트를 변경해요. 테스트할 때 Let's Encrypt의 스테이징 엔드포인트를 설정하거나 내부 ACME 서버를 쓸 때 가장 자주 사용해요. (Caddyfile 전체에 이 값을 바꾸려면 acme_ca 글로벌 옵션을 대신 사용해요.)

  • ca_root는 시스템 신뢰 저장소에 없을 때 ACME CA 엔드포인트용 신뢰할 수 있는 루트 인증서를 담은 PEM 파일을 지정해요.

  • key_type은 CSR 생성 시 사용할 키 유형이에요. 특정 요구 사항이 있을 때만 설정해요.

  • dns는 지정된 제공자 플러그인을 사용해 DNS 챌린지를 활성화해요. 플러그인은 caddy-dns 저장소 중 하나에서 플러그인으로 추가돼야 해요. 각 제공자 플러그인은 이름 뒤에 자체 문법이 있을 수 있어요. 자세한 내용은 해당 문서를 참고해요. 각 DNS 제공자에 대한 지원은 커뮤니티 노력으로 유지돼요. 위키에서 내 제공자에 대한 DNS 챌린지를 활성화하는 법을 배워요.

  • propagation_timeout은 DNS 챌린지를 사용할 때 DNS TXT 레코드가 나타날 때까지 기다릴 최대 시간을 설정하는 기간 값이에요. 전파 확인을 비활성화하려면 -1로 설정해요. 기본 2분이에요.

  • propagation_delay는 DNS 챌린지를 사용할 때 DNS TXT 레코드 전파 확인을 시작하기 전에 기다릴 시간을 설정하는 기간 값이에요. 기본 0(대기 없음)이에요.

  • dns_ttl은 DNS 챌린지에 쓰는 TXT 레코드의 TTL을 설정하는 기간 값이에요. 거의 필요 없어요.

  • dns_challenge_override_domain은 DNS 챌린지에 사용할 도메인을 덮어써요. 챌린지를 다른 도메인에 위임하기 위한 거예요.

기본 도메인의 DNS 제공자에 DNS 플러그인이 없다면 이걸 쓰고 싶을 수 있어요. 대신 기본 도메인에 서브도메인 _acme-challenge로 CNAME 레코드를 추가해서, 플러그인이 있는 보조 도메인을 가리키게 할 수 있어요. 이 옵션은 플러그인의 특별한 지원을 요구하지 않아요.

ACME 발급자가 기본 도메인의 DNS 챌린지를 해결하려 하면, CNAME을 따라 보조 도메인에서 TXT 레코드를 찾아요.

참고: 여기 값에는 CNAME 레코드의 전체 정식 이름을 사용해요 — _acme-challenge 서브도메인은 자동으로 앞에 붙지 않아요.

  • resolvers는 DNS 챌린지를 수행할 때 사용하는 DNS 리졸버를 커스터마이즈해요. 이들은 시스템 리졸버나 기본값보다 우선해요. 여기 설정하면 리졸버가 구성된 모든 인증서 발급자에게 전파돼요.

이것은 보통 IP 주소 목록이에요. 예를 들어 Google Public DNS를 쓰려면:

resolvers 8.8.8.8 8.8.4.4
  • eab는 CA가 제공하는 키 ID와 MAC 키를 사용해 이 사이트의 ACME 외부 계정 바인딩(EAB)을 구성해요.

  • on_demand는 사이트 블록 주소에 주어진 호스트 이름에 대해 온디맨드 TLS를 활성화해요. 보안 경고: 남용을 완화하기 위해 on_demand_tls글로벌 옵션도 함께 구성하지 않으면 프로덕션에서 이렇게 하는 건 안전하지 않아요.

  • reuse_private_keys는 인증서 갱신 시 개인 키 재사용을 활성화해요. 기본적으로는 핀닝(pinning)을 완화하고 키 손상 범위를 줄이기 위해 새 인증서마다 새 키가 만들어져요. 키 핀닝은 업계 모범 사례에 어긋나요. 특별한 이유가 없다면 이 옵션을 쓰지 않는 걸 권장해요. 이 기능은 향후 버전에서 제거될 수 있어요.

  • client_auth는 TLS 클라이언트 인증을 활성화하고 구성해요:

  • mode는 클라이언트를 인증하는 모드예요. 허용되는 값:

Mode 설명
request 클라이언트에게 인증서를 요청하지만, 없어도 허용하고 검증하지 않아요
require 클라이언트가 인증서를 제시하도록 요구하지만 검증하지 않아요
verify_if_given 클라이언트에게 인증서를 요청하고, 없으면 허용하지만 있으면 검증해요
require_and_verify 클라이언트가 검증된 유효한 인증서를 제시하도록 요구해요

기본: trust_pool 모듈이 제공되면 require_and_verify, 그렇지 않으면 require.

  • trust_pool은 클라이언트 인증서를 검증할 때 기준이 되는 CA(인증 기관)에서 제공하는 인증서 공급원을 구성해요.

신뢰할 수 있는 인증서 풀을 제공하는 인증 기관과 세그먼트 내 구성은 구성된 trust pool 모듈의 공급원에 따라 달라져요. Caddy에서 제공하는 표준 모듈은 아래에 나열돼 있어요. 서드파티를 포함한 전체 모듈 목록은 trust_poolJSON 문서에 있어요.

여러 trusted_* 지시문을 사용해 여러 CA 또는 리프 인증서를 지정할 수 있어요. 리프 인증서 중 하나로 나열되지 않았거나 지정된 CA 중 하나가 서명하지 않은 클라이언트 인증서는 mode에 따라 거부돼요.

  • verifier는 커스텀 클라이언트 인증서 검증 모듈 사용을 활성화해요. 이 모듈은 인증서가 취소되지 않았는지 확인하는 것 같은 커스텀 클라이언트 인증 검사를 수행할 수 있어요.

  • issuer는 커스텀 인증서 발급자 또는 인증서를 얻는 공급원을 구성해요.

어떤 발급자가 사용되고 이 세그먼트에서 이어지는 옵션은 사용 가능한 발급자 모듈에 따라 달라져요. ca와 dns 같은 다른 하위 지시문 중 일부는 사실 acme 발급자를 구성하는 단축키(이 하위 지시문은 나중에 추가됨)여서, 이 지시문과 다른 것들을 함께 지정하면 혼란스러워 금지돼요.

이 하위 지시문은 여러 번 지정해서 여러 중복 발급자를 구성할 수 있어요. 발급자가 인증서 발급에 실패하면 다음이 시도돼요.

  • get_certificate는 핸드셰이크 시점에 관리자 모듈에서 인증서를 가져오도록 활성화해요.

  • insecure_secrets_log는 TLS 비밀을 파일로 기록하도록 활성화해요. 이것은 SSLKEYLOGFILE이라고도 알려져 있어요. NSS 키 로그 형식을 사용하며 Wireshark나 다른 도구가 파싱할 수 있어요. ⚠️ 보안 경고: 다른 프로그램이나 도구가 TLS 연결을 복호화할 수 있게 하므로 보안을 완전히 손상시키는 불안전한 방식이에요. 하지만 디버깅과 트러블슈팅에 유용할 수 있어요.

  • renewal_window_ratio는 Caddy가 인증서를 갱신하려 시도하기 전에 남아 있어야 하는 인증서 수명을 결정하는 0과 1 사이의 비율이에요. 예를 들어 인증서 수명이 90일이고 이 비율이 0.3333(기본값)이면, Caddy는 만료 30일 이하가 남았을 때 인증서를 계속해서 갱신하려 시도해요. renewal_window_ratio글로벌 옵션으로 전역 설정도 가능해요.

CA의 발급 시간이 매우 길다면 인증서 수명 후반에 갱신하는 게 유용할 수 있지만, 이걸 바꿀 일은 드물어요.

이것은 ACME 발급자가 ARI 확장을 구현할 수 있으므로 제안이란 점을 기억해요. ARI는 ACME 클라이언트(여기서는 Caddy)가 갱신을 시도해야 하는 창을 규정하며, 그 창은 이 비율과 정렬되지 않을 수 있어요.

  • force_automate는 인라인으로 지정하는 것과 같아요(위 참조).

트러스트 풀 제공자 (Trust Pool Providers)

trust_pool 하위 지시문에 쓸 수 있는 표준 트러스트 풀 제공자:

inline

inline 모듈은 신뢰할 수 있는 루트 인증서를 Caddyfile에 base64 DER 인코딩 형식으로 직접 나열해서 파싱해요. trust_der 지시문은 여러 번 반복할 수 있어요.

trust_pool inline {
	trust_der      <base64_der>
}
  • trust_der는 클라이언트 인증서를 검증할 기준이 되는 base64 DER 인코딩 CA 인증서예요.

file

file 모듈은 디스크의 PEM 파일에서 신뢰할 수 있는 루트 인증서를 읽어요. pem_file 지시문은 같은 줄에 여러 파일 경로를 받을 수 있고 여러 번 반복할 수 있어요.

... file [<pem_file>...] {
	pem_file <pem_file>...
}
  • pem_file은 클라이언트 인증서를 검증할 기준이 되는 PEM CA 인증서 파일 경로예요.

pki_root

pki_root 모듈은 PKI 앱에 정의된 인증 기관에서 루트를 얻고 인증서를 신뢰해요. authority 지시문은 동시에 여러 기관을 받을 수 있고 여러 번 반복할 수 있어요.

... pki_root [<ca_name>...] {
	authority <ca_name>...
}
  • authority는 PKI 앱에 구성된 인증 기관의 이름이에요.

pki_intermediate

pki_intermediate 모듈은 PKI 앱에 정의된 인증 기관에서 중간을 얻고 인증서를 신뢰해요. authority 지시문은 동시에 여러 기관을 받을 수 있고 여러 번 반복할 수 있어요.

... pki_intermediate [<ca_name>...] {
	authority <ca_name>...
}
  • authority는 PKI 앱에 구성된 인증 기관의 이름이에요.

storage

storage 모듈은 Caddy 저장소에서 신뢰할 수 있는 인증서 루트를 추출해요. authority 지시문은 동시에 여러 기관을 받을 수 있고 여러 번 반복할 수 있어요.

... storage [<storage_keys>...] {
	storage <storage_module>
	keys    <storage_keys>...
}
  • storage는 사용할 선택적 저장소 모듈이에요. 지정하지 않으면 기본 저장소 모듈이 사용돼요. 지정하면 한 번만 지정할 수 있어요.

  • keys는 인증서의 PEM 파일이 저장된 저장소 키 목록이에요. 이 지시문은 같은 줄에 여러 값을 받을 수 있고 여러 번 지정할 수 있어요.

http

http 모듈은 HTTP 엔드포인트에서 신뢰할 수 있는 인증서를 가져와요. endpoints 지시문은 동시에 여러 엔드포인트를 받을 수 있고 여러 번 반복할 수 있어요.

... http [<endpoints...>] {
	endpoints   <endpoints...>
	tls         <tls_config>
}
  • endpoints는 인증서를 얻을 HTTP 엔드포인트 목록이에요. 이 지시문은 같은 줄에 여러 값을 받을 수 있고 여러 번 지정할 수 있어요.

  • tls는 HTTP 엔드포인트에 연결할 때 사용할 선택적 TLS 구성이에요. 세그먼트 파싱은 다음 섹션에 정의돼 있어요.

TLS
... {
	ca                    <ca_module>
	insecure_skip_verify
	handshake_timeout     <duration>
	server_name           <name>
	renegotiation         <never|once|freely>
}
  • ca는 트러스트 풀의 제공자를 정의하는 선택적 지시문이에요. 구성은 trust_pool과 같은 동작을 따라요. 지정하면 한 번만 지정할 수 있어요.

  • insecure_skip_verify는 TLS 핸드셰이크 검증을 꺼서 연결을 안전하지 않게 만들고 중간자 공격에 취약하게 해요. 프로덕션에서 사용하지 마세요. 검증은 시스템이 신뢰하는 인증 기관 또는 ca 지시문이 결정한 인증 기관에 대해 수행돼요.

  • handshake_timeout은 TLS 핸드셰이크가 완료될 때까지 기다릴 최대 기간이에요. 기본: 타임아웃 없음.

  • server_name은 TLS 핸드셰이크에서 받은 인증서를 검증할 때 사용할 서버 이름을 설정해요. 기본적으로 업스트림 주소의 호스트 부분을 사용해요.

  • renegotiation은 TLS 재협상 수준을 설정해요. TLS 재협상은 첫 핸드셰이크 이후 후속 핸드셰이크를 수행하는 행위예요. 수준:

  • never(기본값)는 재협상을 비활성화해요.

  • once는 원격 서버가 연결당 한 번 재협상을 요청하도록 허용해요.

  • freely는 원격 서버가 반복적으로 재협상을 요청하도록 허용해요.

검증자 (Verifiers)

클라이언트 인증서 검증 모듈은 trust_pool이 구성된 경우 신뢰할 수 있는 인증 기관에서 발급됐는지 검증한 뒤 실행돼요. 현재 표준 Caddy에 포함된 검증자는 leaf예요.

Leaf

leaf 검증자는 클라이언트 인증서가 정의된 허용 인증서 집합 중 하나인지 확인해요. 인증서 집합은 로더 모듈을 사용해 로드돼요.

로더 (Loaders)

표준 Caddy 배포판에는 4개의 로더가 번들되어 있으며, 그중 3개는 Caddyfile에서 사용할 수 있어요.

File

file 로더는 지정된 PEM 파일에서 인증서 집합을 로드해요.

... file <pem_files...>
Folder

folder 로더는 이름이 지정된 디렉터리를 재귀적으로 탐색해 허용된 클라이언트 인증서로 로드할 PEM 파일을 찾아요.

... folder <folders...>
PEM

pem 로더는 Caddyfile에 PEM 형식으로 인라인된 인증서를 받아들여요.

... pem <pem_strings...>

발급자 (Issuers)

다음 발급자는 tls 지시문에 기본으로 포함돼 있어요:

acme

ACME 프로토콜을 사용해 인증서를 얻어요. acme는 기본 발급자(Let's Encrypt 사용)이므로 명시적으로 구성하는 건 보통 불필요해요.

... acme [<directory_url>] {
	dir      <directory_url>
	test_dir <test_directory_url>
	email    <email>
	timeout  <duration>
	disable_http_challenge
	disable_tlsalpn_challenge
	alt_http_port    <port>
	alt_tlsalpn_port <port>
	eab <key_id> <mac_key>
	trusted_roots <pem_files...>
	dns [<provider_name> [<options>]]
	propagation_timeout <duration>
	propagation_delay   <duration>
	dns_ttl             <duration>
	dns_challenge_override_domain <domain>
	resolvers <dns_servers...>
	preferred_chains [smallest] {
		root_common_name <common_names...>
		any_common_name  <common_names...>
	}
	profile <name>
}
  • dir은 ACME CA 디렉터리의 URL이에요.

기본: https://acme-v02.api.letsencrypt.org/directory

  • test_dir은 챌린지를 재시도할 때 사용할 선택적 대체 디렉터리예요. 모든 챌린지가 실패하면 재시도 중에 이 엔드포인트가 사용돼요. CA에 프로덕션 엔드포인트의 요율 제한을 피하고 싶은 스테이징 엔드포인트가 있을 때 유용해요.

기본: https://acme-staging-v02.api.letsencrypt.org/directory

  • email은 ACME 계정 연락처 이메일 주소예요.

  • timeout은 ACME 작업을 시간 초과하기 전에 기다릴 시간을 설정하는 기간 값이에요.

  • disable_http_challenge는 HTTP 챌린지를 비활성화해요.

  • disable_tlsalpn_challenge는 TLS-ALPN 챌린지를 비활성화해요.

  • alt_http_port는 HTTP 챌린지를 제공할 대체 포트예요. 이것은 포트 80에서 이뤄져야 하므로 패킷을 이 대체 포트로 전달해야 해요.

  • alt_tlsalpn_port는 TLS-ALPN 챌린지를 제공할 대체 포트예요. 이것은 포트 443에서 이뤄져야 하므로 패킷을 이 대체 포트로 전달해야 해요.

  • eab는 일부 ACME CA에서 요구할 수 있는 외부 계정 바인딩을 지정해요.

  • trusted_roots는 ACME CA 서버에 연결할 때 신뢰할 하나 이상의 루트 인증서(PEM 파일 이름)예요.

  • dns는 DNS 챌린지를 구성해요. dns글로벌 옵션이 전역적으로 적용 가능한 DNS 제공자 모듈을 지정하지 않는 한 여기에 제공자를 구성해야 해요.

  • propagation_timeout은 DNS 챌린지를 사용할 때 DNS TXT 레코드가 나타날 때까지 기다릴 최대 시간을 설정하는 기간 값이에요. 전파 확인을 비활성화하려면 -1로 설정해요. 기본 2분이에요.

  • propagation_delay는 DNS 챌린지를 사용할 때 DNS TXT 레코드 전파 확인을 시작하기 전에 기다릴 시간을 설정하는 기간 값이에요. 기본 0(대기 없음)이에요.

  • dns_ttl은 DNS 챌린지에 쓰는 TXT 레코드의 TTL을 설정하는 기간 값이에요. 거의 필요 없어요.

  • dns_challenge_override_domain은 DNS 챌린지에 사용할 도메인을 덮어써요. 챌린지를 다른 도메인에 위임하기 위한 거예요.

기본 도메인의 DNS 제공자에 DNS 플러그인이 없다면 이걸 쓰고 싶을 수 있어요. 대신 기본 도메인에 서브도메인 _acme-challenge로 CNAME 레코드를 추가해서, 플러그인이 있는 보조 도메인을 가리키게 할 수 있어요. 이 옵션은 플러그인의 특별한 지원을 요구하지 않아요.

ACME 발급자가 기본 도메인의 DNS 챌린지를 해결하려 하면, CNAME을 따라 보조 도메인에서 TXT 레코드를 찾아요.

참고: 여기 값에는 CNAME 레코드의 전체 정식 이름을 사용해요 — _acme-challenge 서브도메인은 자동으로 앞에 붙지 않아요.

  • resolvers는 DNS 챌린지를 수행할 때 사용하는 DNS 리졸버를 커스터마이즈해요. 이들은 시스템 리졸버나 기본값보다 우선해요. 여기 설정하면 리졸버가 구성된 모든 인증서 발급자에게 전파돼요.

이것은 보통 IP 주소 목록이에요. 예를 들어 Google Public DNS를 쓰려면:

resolvers 8.8.8.8 8.8.4.4
  • preferred_chains는 Caddy가 선호해야 하는 인증서 체인을 지정해요. CA가 여러 체인을 제공할 때 유용해요. 다음 옵션 중 하나를 사용해요:

  • smallest는 Caddy가 바이트 수가 가장 적은 체인을 선호하도록 해요.

  • root_common_name은 하나 이상의 공통 이름 목록이에요. Caddy는 지정된 공통 이름 중 하나 이상과 일치하는 루트가 있는 첫 번째 체인을 선택해요.

  • any_common_name은 하나 이상의 공통 이름 목록이에요. Caddy는 지정된 공통 이름 중 하나 이상과 일치하는 발급자가 있는 첫 번째 체인을 선택해요.

  • profile은 인증서를 주문할 때 적용할 ACME 프로필의 이름이에요. 하나를 지정하면 구성된 모든(암시적이든 아니든) CA가 이 프로필을 지원해야 해요. 사용 가능한 프로필은 CA 문서를 참고해요. 일부 CA는 프로필을 지원하지 않을 수 있어요. 실험적: ACME 프로필 사양은 아직 초안 상태이므로 이 기능은 변경되거나 제거될 수 있어요.

zerossl

ZeroSSL의 독점 인증서 발급 API를 사용해 인증서를 얻어요. API 키가 필요하며 요금제에 따라 결제가 필요할 수도 있어요. 이 발급자는 ZeroSSL의 ACME 엔드포인트와는 다르다는 점을 유의해요. ZeroSSL의 ACME 엔드포인트를 쓰려면 위에 설명된 acme 발급자를 ZeroSSL의 ACME 디렉터리 엔드포인트로 구성해서 사용해요.

... zerossl <api_key> {
	validity_days <days>
	alt_http_port <port>
	dns <provider_name> ...
	propagation_delay <duration>
	propagation_timeout <duration>
	resolvers <list...>
	dns_ttl <duration>
}
  • validity_days는 인증서 수명을 정의해요. 특정 값만 허용돼요. 자세한 내용은 ZeroSSL 문서를 참고해요.

  • alt_http_port는 포트 80이 아닐 때 ZeroSSL의 HTTP 검증을 완료하는 데 사용할 포트예요.

  • dns는 자동 레코드 프로비저닝을 위해 지정된 DNS 제공자를 사용해 CNAME 검증 방법을 활성화해요. DNS 제공자 플러그인은 caddy-dns 저장소에서 설치돼야 해요. 각 제공자 플러그인은 이름 뒤에 자체 문법이 있을 수 있어요. 자세한 내용은 해당 문서를 참고해요. 각 DNS 제공자에 대한 지원은 커뮤니티 노력으로 유지돼요.

  • propagation_delay는 CNAME 레코드 전파를 확인하기 전에 기다리는 시간이에요.

  • propagation_timeout은 포기하기 전에 CNAME 레코드 전파를 기다리는 시간이에요.

  • resolvers는 CNAME 레코드 전파를 확인할 때 사용할 커스텀 DNS 리졸버를 정의해요.

  • dns_ttl은 검증 프로세스의 일부로 만들어진 CNAME 레코드의 TTL을 구성해요.

internal

내부 인증 기관에서 인증서를 얻어요.

... internal {
	ca       <name>
	lifetime <duration>
	sign_with_root
}
  • ca는 사용할 내부 CA의 이름이에요. 기본: local. local CA를 구성하거나 대체 CA를 만들려면 PKI 앱 글로벌 옵션을 참고해요.

기본적으로 루트 CA 인증서는 3600d 수명(10년)이고 중간 인증서는 7d 수명(7일)이에요.

Caddy는 루트 CA 인증서를 시스템 신뢰 저장소에 설치하려 시도하지만(skip_install_trust글로벌 옵션이 설정되지 않은 경우), Caddy가 권한 없는 사용자로 실행 중이거나 Docker 컨테이너에서 실행 중이면 실패할 수 있어요. 그 경우 caddy trust 명령을 사용하거나 컨테이너 밖으로 복사해서 루트 CA 인증서를 수동으로 설치해야 해요.

  • lifetime은 내부 발급 리프 인증서의 유효 기간을 설정하는 기간 값이에요. 기본: 12h. 꼭 필요하지 않다면 바꾸지 않는 걸 권장해요. 중간 인증서 수명보다 짧아야 해요.

  • sign_with_root는 중간 인증서 대신 루트가 발급자 역할을 하도록 강제해요. 권장되지는 않으며, 기기/클라이언트가 인증서 체인을 제대로 검증하지 못할 때(매우 드묾)만 사용해야 해요.

인증서 관리자 (Certificate Managers)

인증서 관리자 모듈은 발급자 모듈과 구별되며, 관리자 모듈을 사용한다는 것은 외부 도구나 서비스가 인증서를 갱신 상태로 유지한다는 뜻이에요. 반면 발급자 모듈은 Caddy 자체가 인증서를 관리한다는 뜻이에요. (발급자 모듈은 인증서 서명 요청(CSR)을 입력으로 받지만, 인증서 관리자 모듈은 TLS ClientHello를 입력으로 받아요.)

다음 관리자 모듈은 tls 지시문에 기본으로 포함돼 있어요:

tailscale

로컬에서 실행되는 Tailscale 인스턴스에서 인증서를 가져와요. Tailscale 계정에서 HTTPS를 활성화해야 하며(또는 오픈소스 Headscale 서버에서), Caddy 프로세스는 루트로 실행 중이거나 tailscaled에서 인증서를 가져올 권한을 Caddy 사용자에게 부여하도록 구성해야 해요.

참고: 이것은 보통 불필요해요! Caddy는 별도 구성 없이 모든 *.ts.net 도메인에 Tailscale을 자동으로 사용해요.

get_certificate tailscale  # often unnecessary!

http

HTTP(S) 요청을 만들어 인증서를 가져와요. 응답은 200 상태 코드여야 하며 본문에는 전체 인증서(중간 포함)와 개인 키를 포함한 PEM 체인이 있어야 해요.

get_certificate http <url>
  • url은 요청할 정규화된 URL이에요. 성능상 로컬 엔드포인트일 것을 강력히 권장해요. URL에는 다음 쿼리 문자열 매개변수가 추가돼요:

  • server_name: SNI 값

  • signature_schemes: 서명 알고리즘의 hex ID를 쉼표로 구분한 목록

  • cipher_suites: 암호 스위트의 hex ID를 쉼표로 구분한 목록

  • local_ip: 클라이언트가 요청한 IP 주소

예제 (Examples)

커스텀 인증서와 키를 사용해요. 인증서는 사이트 주소와 일치하는 SAN이 있어야 해요:

example.com {
	tls cert.pem key.pem
}

현재 사이트 블록의 모든 호스트에 공개 인증서(ACME / Let's Encrypt) 대신 로컬 신뢰 인증서를 사용해요(개발 환경에서 유용):

example.com {
	tls internal
}

로컬 신뢰 인증서를 사용하되 백그라운드가 아닌 관리되는 온디맨드 방식을 써요. 이렇게 하면 아무 도메인이나 Caddy 인스턴스로 가리키고 자동으로 인증서를 프로비저닝할 수 있어요. Caddy 인스턴스가 공개적으로 접근 가능하다면 공격자가 서버 리소스를 고갈시키는 데 쓸 수 있으므로 사용해서는 안 돼요:

https:// {
	tls internal {
		on_demand
	}
}

내부 CA에 커스텀 옵션을 사용해요(tls internal 단축키는 사용 불가):

example.com {
	tls {
		issuer internal {
			ca foo
		}
	}
}

ACME 계정의 이메일 주소를 지정해요(하지만 모든 사이트에 하나의 이메일만 쓴다면 email 글로벌 옵션을 권장):

example.com {
	tls [email protected]
}

Cloudflare에서 관리하는 도메인에 계정 자격 증명을 환경 변수로 사용해 DNS 챌린지를 활성화해요. 이것은 DNS 검증을 요구하는 와일드카드 인증서 지원을 가능하게 해요:

*.example.com {
	tls {
		dns cloudflare {env.CLOUDFLARE_API_TOKEN}
	}
}

Caddy가 관리하는 대신 HTTP로 인증서 체인을 가져와요. get_certificate는 on_demand가 활성화돼 있음을 의미하며, ACME 발급을 트리거하는 대신 모듈을 사용해 인증서를 가져와요:

https:// {
	tls {
		get_certificate http http://localhost:9007/certs
	}
}

trust_pool file 제공자를 통해 제공된 모든 CA에 대해 검증된 유효한 인증서를 클라이언트가 제시하도록 TLS 클라이언트 인증을 활성화하고 요구해요:

example.com {
	tls {
		client_auth {
			trust_pool file ../caddy.ca.cer ../root.ca.cer
		}
	}
}

더 알아보기 (Learn more)