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

Caddyfile 지원

원문 보기 위키 갱신

Caddyfile 지원 (Caddyfile Support)

출처: Caddy 공식 문서

본문

Caddy 모듈은 등록될 때 그 네임스페이스 덕분에 네이티브 JSON 설정에 자동으로 추가돼서, 사용 가능하고 문서화됩니다. 그래서 Caddyfile 지원은 순전히 선택 사항이지만, Caddyfile을 선호하는 사용자들이 자주 요청해요.

Unmarshaler

모듈에 Caddyfile 지원을 추가하려면 caddyfile.Unmarshaler 인터페이스를 구현하면 돼요. 토큰을 어떻게 파싱하느냐에 따라 모듈이 가질 Caddyfile 문법을 선택하게 돼요.

unmarshaler의 역할은 전달된 caddyfile.Dispenser를 사용해 필드를 채우는 등으로 모듈의 타입을 설정하는 거예요. 예를 들어 Gizmo라는 모듈 타입에는 이 메서드가 있을 수 있어요:

// UnmarshalCaddyfile implements caddyfile.Unmarshaler. Syntax:
//
// gizmo <name> [<option>]
//
func (g *Gizmo) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
	d.Next() // consume directive name

	if !d.Args(&g.Name) {
		// not enough args
		return d.ArgErr()
	}
	if d.NextArg() {
		// optional arg
		g.Option = d.Val()
	}
	if d.NextArg() {
		// too many args
		return d.ArgErr()
	}

	return nil
}

메서드의 godoc 주석에 문법을 문서화하는 것이 좋아요. Caddyfile 파싱에 대한 더 많은 정보는 caddyfile패키지 godoc을 참조하세요.

지시문 이름 토큰은 간단한 d.Next() 호출로 소비/건너뛸 수 있어요.

d.NextArg() 또는 d.RemainingArgs()로 누락되거나 과도한 인자를 확인하세요. 간단한 "잘못된 경우" 메시지에는 d.ArgErr()를, 문제 설명(이상적으로는 제안된 해결책)을 담은 유용한 오류 메시지를 만들려면 d.Errf("some message")를 사용해요.

인터페이스가 제대로 충족되는지 확인하기 위해 인터페이스 가드도 추가해야 해요:

var _ caddyfile.Unmarshaler = (*Gizmo)(nil)

블록

한 줄에 담기 어려운 더 많은 설정을 받으려면 서브지시문이 있는 블록을 허용하고 싶을 수 있어요. 이는 d.NextBlock()과 원래 중첩 수준으로 돌아올 때까지의 반복으로 할 수 있어요:

for nesting := d.Nesting(); d.NextBlock(nesting); {
	switch d.Val() {
		case "sub_directive_1":
		// ...
		case "sub_directive_2":
		// ...
	}
}

루프의 각 반복이 전체 세그먼트(줄 또는 블록)를 소비하기만 하면, 블록을 처리하는 우아한 방법이에요.

HTTP 지시문

HTTP Caddyfile은 Caddy의 기본 Caddyfile 어댑터 문법(또는 "서버 타입")이에요. 확장 가능하며, 여러분의 모듈을 위한 자신만의 "최상위" 지시문을 등록할 수 있어요:

func init() {
	httpcaddyfile.RegisterDirective("gizmo", parseCaddyfile)
}

지시문이 단일 HTTP 핸들러만 반환한다면(흔한 경우) RegisterHandlerDirective가 더 쉬울 수 있어요:

func init() {
	httpcaddyfile.RegisterHandlerDirective("gizmo", parseCaddyfileHandler)
}

기본 아이디어는 지시문과 연결한 파싱 함수가 하나 이상의 ConfigValue 값을 반환한다는 거예요. (RegisterHandlerDirective를 사용하면 채워진 caddyhttp.MiddlewareHandler 값을 직접 반환합니다.) 각 설정 값은 "클래스"와 연결되는데, 이 클래스는 HTTP Caddyfile 어댑터가 최종 JSON 설정의 어느 부분에 사용할 수 있는지 알게 해줘요. 모든 설정 값은 더미에 쌓이고, 어댑터가 최종 JSON 설정을 구성할 때 그 더미에서 가져와요.

이 설계 덕분에 지시문은 인식된 어떤 클래스에 대해서든 어떤 설정 값이든 반환할 수 있어요. 즉 HTTP Caddyfile 어댑터가 지정한 클래스가 있는 설정의 어떤 부분이든 영향을 줄 수 있어요.

이미 UnmarshalCaddyfile() 메서드를 구현했다면 파싱 함수는 이렇게 간단할 수 있어요:

// parseCaddyfileHandler unmarshals tokens from h into a new middleware handler value.
func parseCaddyfileHandler(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error) {
	var g Gizmo
	err := g.UnmarshalCaddyfile(h.Dispenser)
	return g, err
}

httpcaddyfile.Helper 타입을 사용하는 방법에 대한 자세한 내용은 httpcaddyfile패키지 godoc을 참조하세요.

핸들러 순서

HTTP 미들웨어/핸들러 값을 반환하는 모든 지시문은 올바른 순서로 평가되어야 해요. 예를 들어 사이트의 루트 디렉터리를 설정하는 핸들러는 루트 디렉터리에 접근하는 핸들러보다 앞에 와야, 디렉터리 경로가 무엇인지 알 수 있기 때문이에요.

HTTP Caddyfile은 표준 지시문에 대해 하드코딩된 순서가 있어요. 이는 사용자가 웹 서버의 가장 흔한 함수들의 구현 세부 사항을 알 필요가 없게 하고, 올바른 설정을 쓰기 더 쉽게 만들어요. 단일 하드코딩된 목록은 Caddyfile의 확장 가능한 특성을 고려할 때 비결정성을 방지하기도 해요.

새 핸들러 지시문을 등록하면(route 블록 밖에서) 사용되기 전에 그 목록에 추가되어야 해요. 이는 세 가지 방법 중 하나로 이루어져요:

  • (권장) 플러그인 작성자가 지시문을 등록한 후 init()에서 httpcaddyfile.RegisterDirectiveOrder를 호출해서, 다른 표준 지시문을 기준으로 순서에 삽입할 수 있어요. 이렇게 하면 사용자는 추가 설정 없이 사이트에서 지시문을 직접 사용할 수 있어요. 예를 들어 gizmo 지시문을 header 핸들러 다음에 평가되도록 삽입하려면:
httpcaddyfile.RegisterDirectiveOrder("gizmo", httpcaddyfile.After, "header")
  • 사용자는 order전역 옵션을 추가해 자신의 Caddyfile에 대해 표준 순서를 수정할 수 있어요. 예: order gizmo before respond는 respond 핸들러보다 먼저 평가될 새 gizmo 지시문을 삽입해요. 그러면 지시문을 정상적으로 사용할 수 있어요.

  • 사용자는 지시문을 route블록에 둘 수 있어요. route 블록의 지시문은 재정렬되지 않으므로, route 블록에서 사용되는 지시문은 목록에 나타날 필요가 없어요.

후자 두 가지 옵션 중 하나를 선택한다면, 사용자가 제대로 사용할 수 있도록 지시문이 정렬되기 적절한 위치에 대한 권장 사항을 문서화해 주세요.

클래스

이 표는 HTTP Caddyfile 어댑터가 인식하는, 내보낸 타입이 있는 각 클래스를 설명해요:

클래스 이름 기대되는 타입 설명
bind []string 서버 리스너 바인드 주소
route caddyhttp.Route HTTP 핸들러 라우트
error_route *caddyhttp.Subroute HTTP 오류 처리 라우트
tls.connection_policy *caddytls.ConnectionPolicy TLS 연결 정책
tls.cert_issuer certmagic.Issuer TLS 인증서 발급자
tls.cert_loader caddytls.CertificateLoader TLS 인증서 로더

서버 타입

구조적으로 Caddyfile은 간단한 형식이라, 다양한 요구에 맞는 서로 다른 유형의 Caddyfile 형식(때로 "서버 타입"이라고 함)이 있을 수 있어요.

기본 Caddyfile 형식은 HTTP Caddyfile이며, 아마 잘 아실 거예요. 이 형식은 주로 http앱을 구성하고, 다른 부분(예: 인증서를 로드·자동화하는 tls 앱)에는 약간의 설정만 뿌릴 뿐이에요.

HTTP 외의 앱을 구성하려면 자신만의 서버 타입을 사용하는 자신만의 설정 어댑터를 구현하고 싶을 수 있어요. Caddyfile 어댑터는 실제로 여러분을 위해 입력을 파싱하고 서버 블록과 옵션 목록을 주며, 그 구조를 이해하고 JSON 설정으로 바꾸는 것은 여러분의 어댑터 몫이에요.

더 알아보기 (Learn more)