4 min read

Pangolin + Traefik으로 홈서버 리버스 프록시 구축하기

홈서버에 도메인 연결, HTTPS, 인증까지 — Pangolin + Traefik + CrowdSec 조합으로 리버스 프록시를 구축한 경험을 공유합니다.

셀프호스팅의 첫 번째 관문

홈서버에 서비스를 하나둘 올리다 보면 금방 마주치는 문제가 있습니다.

  • Ghost 블로그는 3060 포트, Komga는 25600 포트, Authentik은 7080 포트...
  • 외부에서 접근하려면 IP:포트로 들어가야 하는데, 이걸 도메인으로 연결하고 싶습니다.
  • HTTPS도 붙이고 싶고, 인증도 걸고 싶습니다.

이걸 해결하는 게 리버스 프록시입니다. Nginx Proxy Manager, Caddy 등 선택지가 많지만, 저는 Pangolin + Traefik 조합을 선택했습니다.


왜 Pangolin 을 쓰려고 했을까 보면

방식 장점 단점
Nginx Proxy Manager GUI 쉬움 설정 자유도 낮음, 자동화 어려움
Caddy 설정 간결 복잡한 미들웨어 체인 한계
Traefik 단독 강력한 자동화 설정 파일이 복잡
Pangolin + Traefik 웹 UI + Traefik 파워 초기 세팅 복잡

Pangolin은 Traefik 위에 올라가는 관리 레이어입니다. 도메인 추가, SSL 인증서, 미들웨어 설정을 웹 UI에서 할 수 있으면서도 Traefik의 유연함을 그대로 쓸 수 있죠.

거기에 Gerbil(WireGuard 터널)이 붙어서, 외부에서 홈서버로 들어오는 트래픽을 안전하게 터널링합니다. 공유기 포트포워딩 없이도 외부 접근이 가능해집니다.


흐름을 살펴볼까요

인터넷 → Gerbil(:80/:443) → Traefik → 각 서비스
                                         │
               ┌─────────────────────────┼──────────────────┐
               │                         │                  │
         authentik-server          ghost(:3060)        rxresume(:3020)
         headscale-server          livecap(:3030)      sftpgo(:8080)

핵심 구성 요소:

  • Pangolin: 도메인·라우팅 관리 API
  • Gerbil: WireGuard 터널 + 포트 80/443 수신
  • Traefik: 실제 리버스 프록시 (Gerbil 네트워크 공유)
  • CrowdSec: 분산 위협 탐지 (IP 차단)
  • Autoheal: unhealthy 컨테이너 자동 재시작

Docker Compose 구성

services:
  pangolin:
    image: fosrl/pangolin:1.18.1
    container_name: pangolin-server
    restart: unless-stopped
    volumes:
      - ./config:/app/config
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
      interval: "10s"
      timeout: "10s"
      retries: 15

  gerbil:
    image: fosrl/gerbil:1.4.0
    container_name: pangolin-gerbil
    depends_on:
      pangolin:
        condition: service_healthy
    command:
      - --reachableAt=http://gerbil:3004
      - --generateAndSaveKeyTo=/var/config/key
      - --remoteConfig=http://pangolin:3001/api/v1/
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    ports:
      - 80:80
      - 443:443
      - 51820:51820/udp

  traefik:
    image: traefik:v3.6.14
    container_name: pangolin-traefik
    network_mode: service:gerbil  # Gerbil과 네트워크 공유
    depends_on:
      pangolin:
        condition: service_healthy
      gerbil:
        condition: service_healthy
    command:
      - --configFile=/etc/traefik/traefik_config.yml
    volumes:
      - ./config/traefik:/etc/traefik:ro
      - ./config/letsencrypt:/letsencrypt
    env_file:
      - .env
    labels:
      - "autoheal=true"

핵심 포인트:

  • 시작 순서: Pangolin(healthy) → Gerbil(healthy) → Traefik. depends_on으로 강제합니다.
  • network_mode: service:gerbil: Traefik이 Gerbil의 네트워크를 공유합니다. 포트는 Gerbil에서만 열면 됩니다.
  • autoheal 라벨: Traefik이 unhealthy 상태가 되면 자동으로 재시작됩니다.

SSL 인증서: DNS Challenge

Let's Encrypt 인증서를 자동 발급받습니다. HTTP Challenge 대신 DNS Challenge를 쓰면 와일드카드 인증서도 가능합니다.

# traefik_config.yml
certificatesResolvers:
  letsencrypt:
    acme:
      dnsChallenge:
        provider: route53  # AWS Route53 사용
      email: your@email.com
      storage: "/letsencrypt/acme.json"

Route53, Cloudflare, 등 DNS 프로바이더에 맞는 환경변수를 .env에 넣으면 됩니다.


보안: CrowdSec + Autoheal

  crowdsec:
    image: crowdsecurity/crowdsec:v1.7.7
    environment:
      - COLLECTIONS=crowdsecurity/linux
      - BOUNCER_KEY_firewall=${CROWDSEC_BOUNCER_KEY}
    volumes:
      - ./config/traefik/logs:/var/log/traefik:ro

  autoheal:
    image: willfarrell/autoheal:latest
    environment:
      - AUTOHEAL_CONTAINER_LABEL=autoheal
      - AUTOHEAL_INTERVAL=15
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    network_mode: none
  • CrowdSec: Traefik 로그를 읽어서 악성 IP를 자동 차단합니다. Traefik bouncer 플러그인과 연동하면 요청 단계에서 바로 블록됩니다.
  • Autoheal: autoheal=true 라벨이 붙은 컨테이너가 unhealthy 상태가 되면 15초 간격으로 체크 후 재시작합니다.

서비스 연결하기

새 서비스를 추가할 때는:

  1. 해당 서비스의 Docker 네트워크에 pangolin을 external로 추가
  2. Pangolin 웹 UI에서 도메인 → 서비스 매핑 설정
# 예: Ghost 블로그
services:
  ghost:
    image: ghost:5
    ports:
      - "3060:2368"
    networks:
      - ghost
      - pangolin  # 이것만 추가하면 됨

networks:
  pangolin:
    external: true

Pangolin UI에서 blog.example.comhttp://ghost:2368 매핑하면 끝입니다.


초기에 운영하면서 겪은 문제도...

Traefik이 간헐적으로 죽는 현상

Gerbil이 재시작되면 Traefik도 네트워크가 끊기면서 unhealthy 상태가 됩니다. autoheal 컨테이너를 추가해서 자동 복구되도록 했습니다.

서비스 추가 시 네트워크 연결 누락

pangolin 네트워크를 빼먹으면 Traefik에서 서비스에 접근을 못합니다. 502 에러가 나면 가장 먼저 네트워크 연결을 확인하는게 좋습니다.


마무리

Pangolin + Traefik 조합은 초기 세팅이 좀 복잡하지만, 한 번 잡아놓으면 서비스 추가가 매우 편합니다. 도메인 하나 추가하는 데 1분이면 충분하죠.

홈서버에 서비스가 5개 이상이라면 리버스 프록시는 필수입니다. 그 중에서도 자동화와 확장성을 원한다면 이 조합을 추천합니다.


참고 자료