모든 배포 가이드 배포

Traefik(v3)에 사용자 지정 SSL 인증서를 설치하는 방법

Traefik는 ACME를 통해 인증서를 자동으로 발급하는 것으로 유명합니다. 하지만 때로는 그 대신 직접 보유한 인증서를 사용해야 할 때가 있습니다. GetHTTPS에서 발급받은 인증서, 사내/내부 CA가 발급한 인증서, 또는 다른 곳에서 관리하는 와일드카드 인증서 같은 것 말이죠. 이 가이드는 Traefik v3에서 그 방법을 정확히 알려 줍니다.

먼저 이해해야 할 핵심은 이것입니다. Docker 라벨로는 인증서 파일을 연결할 수 없습니다. Traefik 라벨은 라우팅을 제어하고 TLS를 활성화하지만, 인증서 자체는 동적 설정으로서 파일 provider에서 와야 합니다. 거의 모든 사람이 처음에 여기서 걸려 넘어집니다. 이 가이드에서는 올바른 방법으로 진행하겠습니다.

아직 인증서가 없다면 5분 만에 무료로 발급받으세요.

언제 사용해야 하나 (Traefik 자동 ACME와 비교)

자동 ACME 사용 (Let’s Encrypt)직접 보유한 인증서 사용 (이 가이드)
공개 웹사이트, 인터넷에서 접근 가능내부/인트라넷 서비스 (공개 DNS 없음)
표준 DV 인증서로 충분함특정 CA, 와일드카드, 또는 OV/EV 인증서가 필요함
Traefik가 HTTP/DNS 챌린지를 완료할 수 있음망분리(에어갭) 또는 방화벽 뒤에 있는 호스트
인증서 관리를 전혀 하고 싶지 않음이미 GetHTTPS나 다른 곳에서 받은 인증서가 있음

자동 ACME가 상황에 맞는다면 Traefik의 certificatesResolvers가 더 간단합니다. 이 가이드는 “이미 fullchain.pem + privkey.pem이 있고, Traefik가 이를 제공하도록 하고 싶다”는 경우를 위한 것입니다.

사전 준비물

  • Traefik v3가 Docker 컨테이너로 실행 중 (아래 설정은 Docker를 사용하지만, 동적 설정 부분은 어떤 구성에도 적용됩니다)
  • 인증서 파일 — 두 개:
    • fullchain.pem — 인증서 + 중간 체인
    • privkey.pem — 개인 키
  • 호스트를 가리키는 도메인 (또는 내부용으로 로컬 hosts 파일 항목)

Traefik에는 어떤 파일이 필요할까요? Traefik는 certFile에 전체 체인을, keyFile에 키를 원합니다. 리프(leaf) 인증서만 들어 있는 cert.pem을 사용하면 클라이언트에서 “체인 불완전(incomplete chain)” 오류가 발생합니다. Traefik는 파일 provider 인증서에 중간 인증서를 자동으로 덧붙이지 않습니다. fullchain.pem을 사용하세요. 인증서 형식 설명 →

Traefik 설정은 어떻게 나뉘나

Traefik에는 두 가지 종류의 설정이 있으며, 인증서는 두 번째 종류에 들어 있습니다.

  • 정적 설정(Static configuration) — 시작 시 설정됩니다 (entrypoint, provider). 변경하려면 재시작이 필요합니다. 이는 traefik.yml 또는 컨테이너 명령 플래그에 들어갑니다.
  • 동적 설정(Dynamic configuration) — 재시작 없이 실시간으로 다시 로드됩니다 (router, 서비스, TLS 인증서). 파일 provider가 읽는 것이 바로 이것입니다.

여러분의 인증서는 동적 설정입니다. 그래서 라벨이 인증서를 담을 수 없는 것입니다. 라벨은 Docker provider에서 읽지만, tls.certificates는 파일 provider의 개념이기 때문입니다.

1단계: 인증서 파일 배치

컨테이너에 마운트할 디렉터리에 파일을 넣으세요.

mkdir -p ./traefik/certs
cp fullchain.pem ./traefik/certs/
cp privkey.pem   ./traefik/certs/

# 개인 키 권한을 제한
chmod 600 ./traefik/certs/privkey.pem
chmod 644 ./traefik/certs/fullchain.pem

2단계: 동적 설정 작성

./traefik/dynamic/certs.yml을 만드세요. 여기에서 인증서를 선언합니다.

# ./traefik/dynamic/certs.yml  (동적 설정 — 파일 provider)
tls:
  certificates:
    - certFile: /certs/fullchain.pem
      keyFile: /certs/privkey.pem

  # 선택 사항: 더 구체적인 인증서와 일치하지 않는 모든 호스트에 대해
  # 이 인증서를 기본값으로 지정 (예: 와일드카드 또는 내부 CA).
  stores:
    default:
      defaultCertificate:
        certFile: /certs/fullchain.pem
        keyFile: /certs/privkey.pem

경로(/certs/...)는 컨테이너 내부의 경로입니다. 다음 단계에서 이를 마운트합니다. Traefik는 SNI를 사용해 요청마다 올바른 인증서를 선택하며, 인증서의 SAN을 요청된 호스트명과 비교합니다. defaultCertificate는 다른 어떤 것도 일치하지 않을 때의 대체값입니다.

3단계: Traefik 설정 (정적 설정 + 마운트)

완전한 docker-compose.yml은 다음과 같습니다. entrypoint와 파일 provider는 정적 설정(명령 플래그로 전달)이고, 인증서는 방금 작성한 동적 파일에서 로드됩니다.

services:
  traefik:
    image: traefik:v3.3
    container_name: traefik
    restart: unless-stopped
    command:
      # ─── Entrypoints ───────────────────────────────
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
      # 모든 HTTP → HTTPS를 entrypoint 수준에서 리디렉션
      - "--entrypoints.web.http.redirections.entrypoint.to=websecure"
      - "--entrypoints.web.http.redirections.entrypoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      # ─── Providers ─────────────────────────────────
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      # 파일 provider가 동적 설정 디렉터리를 감시
      - "--providers.file.directory=/dynamic"
      - "--providers.file.watch=true"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
      - "./traefik/certs:/certs:ro"
      - "./traefik/dynamic:/dynamic:ro"

  # ─── 예시 백엔드 서비스 ──────────────────────
  whoami:
    image: traefik/whoami
    container_name: whoami
    labels:
      - "traefik.enable=true"
      # Router: 호스트와 일치시키고, HTTPS entrypoint에서 제공
      - "traefik.http.routers.whoami.rule=Host(`example.com`)"
      - "traefik.http.routers.whoami.entrypoints=websecure"
      # 이 router에서 TLS 활성화 — 인증서는 라벨이 아니라
      # 동적 설정에서 가져온다.
      - "traefik.http.routers.whoami.tls=true"

핵심 줄은 traefik.http.routers.whoami.tls=true입니다. 이는 Traefik에 “이 router를 TLS로 제공하라”고 알려 줍니다. 그러면 Traefik는 SNI를 통해 파일 provider 스토어에서 일치하는 인증서를 고릅니다. tls.certfile 같은 라벨은 없습니다. router에는 그런 것이 존재하지 않습니다.

4단계: 시작 및 확인

docker compose up -d
docker compose logs -f traefik

파일 provider가 인증서를 로드하는지 지켜보세요. TLS 오류가 보이지 않아야 합니다. 그런 다음 확인하세요.

브라우저 확인

https://example.com을 방문하세요. 자물쇠 아이콘을 클릭합니다.

  • 발급자(Issued by) — 여러분의 CA (GetHTTPS의 경우 Let’s Encrypt, 또는 여러분의 내부 CA)
  • 유효 기간(Valid) — 시작 및 종료 날짜
  • 도메인 — URL과 일치

명령줄 확인

# Traefik가 자체 서명된 기본 인증서가 아닌 여러분의 인증서를 제공하는지 확인
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -noout -subject -issuer -dates

CN=TRAEFIK DEFAULT CERT가 보인다면 Traefik가 내장 자리표시자(placeholder)로 대체된 것이며, 여러분의 인증서가 로드되지 않은 것입니다. 아래 Troubleshooting 절을 참고하세요.

5단계 (선택 사항): TLS 강화

프로토콜 버전과 암호화 알고리즘을 제어하려면 동적 설정에 TLS 옵션 블록을 추가하고 router에서 이를 참조하세요. certs.yml에 추가합니다.

tls:
  options:
    modern:
      minVersion: VersionTLS12
      sniStrict: true

그런 다음 router 라벨에 추가합니다.

- "traefik.http.routers.whoami.tls.options=modern@file"

@file 접미사는 이 옵션 세트가 파일 provider에서 온다는 것을 Traefik에 알려 줍니다. 이렇게 하면 TLS 1.2와 1.3으로 제한되고, 일치하는 SNI가 없는 연결은 거부됩니다.

HSTS: HTTPS가 모든 곳에서 작동한다고 확신이 들면 Traefik headers 미들웨어를 통해 Strict-Transport-Security 헤더를 추가하세요. HSTS 가이드 →

갱신하는 방법

Traefik는 여러분이 직접 제공한 인증서를 자동으로 갱신하지 않습니다. 이것이 직접 인증서를 가져올 때의 절충점입니다. 인증서 만료가 임박하면(Let’s Encrypt의 경우 90일 중 60일째):

  1. GetHTTPS(또는 여러분의 갱신 도구)에서 새 인증서를 받으세요.
  2. 파일을 제자리에 덮어쓰세요.
    cp new-fullchain.pem ./traefik/certs/fullchain.pem
    cp new-privkey.pem   ./traefik/certs/privkey.pem
  3. 그게 전부입니다. --providers.file.watch=true가 설정되어 있으므로, Traefik가 파일 변경을 감지해 인증서를 핫 리로드합니다. 재시작도, 다운타임도 없습니다. 이는 사용자 지정 인증서에 있어 Traefik의 가장 멋진 특성 중 하나입니다.

전체 갱신 가이드 →

Troubleshooting

Traefik가 내 인증서 대신 “TRAEFIK DEFAULT CERT”를 제공함

원인: Traefik가 인증서를 로드할 수 없어서 자체 서명된 자리표시자로 대체된 것입니다. 거의 항상 경로 또는 마운트 문제입니다.

해결:

# 1. 파일이 컨테이너 내부의 예상 경로에 존재하는지 확인
docker compose exec traefik ls -l /certs

# 2. 동적 파일이 마운트되어 읽을 수 있는지 확인
docker compose exec traefik cat /dynamic/certs.yml

# 3. 실제 원인을 로그에서 확인
docker compose logs traefik | grep -i "certificate\|tls\|error"

certs.ymlcertFile/keyFile 경로는 호스트 경로가 아니라 컨테이너 경로(/certs/...)와 일치해야 합니다.

”unable to find certificate for domain” / 잘못된 인증서가 제공됨

원인: 어떤 인증서의 SAN도 요청된 호스트명과 일치하지 않고, defaultCertificate도 설정되어 있지 않습니다.

해결: 호스트명을 인증서에 추가하거나, stores.default 블록(2단계)에 defaultCertificate를 설정해 Traefik가 대체값을 갖도록 하세요.

router가 404를 반환하고, 인증서는 확인조차 되지 않음

원인: router 규칙이 일치하지 않거나, 서비스가 노출되지 않았습니다. 라우팅이 일치하기 전까지 TLS는 무관합니다.

해결:

# router가 존재하고 활성화되어 있는지 확인
docker compose exec traefik wget -qO- http://localhost:8080/api/http/routers 2>/dev/null | grep whoami

백엔드 컨테이너에 traefik.enable=true가 설정되어 있고, Host() 규칙이 테스트 중인 도메인과 일치하는지 확인하세요.

certs.yml 변경 사항이 적용되지 않음

원인: 파일 provider가 감시하고 있지 않거나, 재시작이 필요한 정적 설정을 편집했습니다.

해결: --providers.file.watch=true가 정적 설정에 있는지 확인하세요. 기억하세요. entrypoint/provider는 정적(재시작 필요)이고, router와 tls.certificates동적(핫 리로드)입니다.

클라이언트에서 “x509: certificate signed by unknown authority” 발생

원인: 체인 불완전 — certFilefullchain.pem 대신 리프 인증서만 들어 있는 cert.pem을 사용했습니다.

해결: certFile이 전체 체인을 가리키도록 하세요. 파일이 따로 분리되어 있다면 연결하세요(리프 먼저, 그다음 중간 인증서).

cat cert.pem intermediate.pem > fullchain.pem

자주 묻는 질문

Docker 라벨로 인증서 파일을 지정할 수 있나요?

아니요. 이것이 가장 흔한 오해입니다. 라벨은 TLS를 활성화하기 위해 traefik.http.routers.<name>.tls=true를 설정하지만, 인증서 파일은 파일 provider(tls.certificates)를 통해 동적 설정에서 선언해야 합니다. .pem 파일을 가리키는 router 라벨은 없습니다.

인증서가 있으면 router에 tls=true가 필요한가요?

네. tls.certificates에 인증서를 선언하면 인증서가 사용 가능해지지만, 실제로 HTTPS로 제공하려면 각 router에 여전히 tls=true가 있어야 합니다(또는 TLS가 활성화된 entrypoint에서 수신 대기해야 합니다). 인증서만 정의한다고 해서 router가 TLS로 전환되지는 않습니다.

자동 ACME와 사용자 지정 인증서를 함께 사용할 수 있나요?

네. Traefik는 일부 router에는 certificatesResolver를, 다른 router에는 파일 provider 인증서를 사용할 수 있습니다. 요청별로, SNI에 의한 명시적 tls.certificates 일치가 해당 호스트명에 대해 ACME보다 우선합니다.

Kubernetes에서는 인증서를 어디에 두나요?

파일 provider가 아닙니다. Kubernetes에서는 인증서를 TLS Secrets로 제공하고 IngressRoute/Ingress에서 이를 참조합니다. 이 가이드의 파일 provider 방식은 Docker 및 독립 실행형(비 K8s) 구성을 위한 것입니다.

Traefik가 내 사용자 지정 인증서를 자동으로 갱신하나요?

아니요. 자동 갱신은 Traefik가 ACME를 통해 직접 발급한 인증서에만 적용됩니다. 직접 보유한 인증서의 경우 파일을 교체해야 하지만, --providers.file.watch=true 덕분에 Traefik가 다운타임 없이 핫 리로드합니다. 위의 갱신하는 방법 절에서 설명한 대로입니다.

ECDSA/ECC 인증서에서도 작동하나요?

네. Traefik는 ECDSA 인증서를 RSA와 정확히 똑같이 제공합니다. certFile/keyFile 설정도 동일합니다. GetHTTPS는 더 작고 빠른 핸드셰이크를 위해 기본적으로 ECDSA P-256을 발급합니다.

관련 기사

배포 2026-05-08
Docker와 리버스 프록시에서의 SSL 인증서
Nginx 리버스 프록시, 자동 Let's Encrypt가 포함된 Traefik, 수동 인증서 마운트를 사용하여 Docker 컨테이너의 HTTPS를 구성합니다.
시작하기 2026-05-08
무료 SSL 인증서 받는 방법 (단계별 가이드)
5분 만에 Let's Encrypt에서 무료 SSL 인증서를 발급받으세요 - 소프트웨어 설치 불필요, 계정 생성 불필요. 4가지 방법, 두 가지 챌린지 유형, 6개 플랫폼 설치, 문제 해결을 포함하는 완전 가이드입니다.
배포 2026-05-08
Nginx에 SSL 인증서를 설치하는 방법
Nginx에 SSL 인증서를 설치하는 단계별 가이드. 파일 업로드, 전체 서버 블록 설정, TLS 모범 사례, HTTP/2, HSTS, 리다이렉트 설정, 테스트, 6가지 일반 오류 문제 해결을 다룹니다.
SSL 및 인증서 2026-05-07
SSL 인증서 형식: PEM, PFX, DER 설명
PEM, PFX/PKCS#12, DER 인증서 형식을 이해하세요. 서버에 필요한 형식과 OpenSSL을 사용하여 형식 간 변환하는 방법을 알아보세요.
브라우저에서 무료 SSL 인증서 받기
설치 불필요, 계정 불필요. 개인키는 항상 기기에 남습니다.
인증서 발급