server infra guide series — article 04

저장하면
끝이다

Traefik에 서비스를 연결하는 데 5단계면 충분하다. DNS 서브도메인을 추가하고, YAML 파일 하나를 저장하면 재시작 없이 즉시 반영된다. 실전 예시 3가지와 트러블슈팅까지.

Part I

서버 환경 파악

Traefik(192.168.0.230)은 systemd 서비스로 설치되어 있다. Docker 컨테이너가 아니라 바이너리가 직접 실행되는 구조다. 설정 파일을 이해하면 라우팅 추가는 어렵지 않다.

Traefik 설정 파일 구조 /etc/traefik/ ├── traefik.yml ← 메인 설정 (정적 설정) ├── acme/ ← SSL 인증서 저장 폴더 └── dynamic/ ← 라우팅 규칙 폴더 (동적 설정) └── routes.yml ← 현재 라우팅 설정 파일

핵심은 두 파일의 차이다. traefik.yml정적 설정이다. 엔트리포인트, 인증서 리졸버, 프로바이더 같은 인프라 수준의 설정이 들어간다. 수정하면 재시작이 필요하다. dynamic/ 폴더 안의 파일은 동적 설정이다. 라우팅 규칙, 서비스 연결 정보가 들어간다. 저장하면 재시작 없이 즉시 반영된다.

traefik.yml (정적 설정)
엔트리포인트 — 80(HTTP), 443(HTTPS)
인증서 리졸버 — Let's Encrypt 연동
프로바이더 — 파일/Consul/Docker 감지
수정 시 재시작 필요
dynamic/*.yml (동적 설정)
라우터 — 도메인/경로 매칭 규칙
서비스 — 백엔드 서버 URL
미들웨어 — 인증, 헤더, Rate Limit
저장 시 즉시 반영 (재시작 불필요)

개발자가 건드리는 것은 dynamic/ 폴더뿐이다. traefik.yml은 인프라 관리자의 영역이다.

Part II

리버스 프록시 추가 — 5단계

작업은 두 곳에서 진행한다. DNS 설정(도메인 관리 업체)과 Traefik 서버(192.168.0.230). 순서를 지키면 5분이면 끝난다.

Step 01

DNS 서브도메인 추가

도메인 관리 업체(가비아, Cloudflare 등)에서 서브도메인의 A 레코드를 Traefik 서버 IP(192.168.0.230)로 연결한다. 백엔드 서버 IP가 아니다.

DNS A 레코드 설정 # 개별 등록 방식 chris-app.yourdomain.com → A → 192.168.0.230 lucy-app.yourdomain.com → A → 192.168.0.230 # 와일드카드 방식 (권장) *.yourdomain.com → A → 192.168.0.230 # 와일드카드를 설정하면 이후 서브도메인 추가 시 # DNS 작업 없이 Traefik 설정만 추가하면 된다
Step 02

Traefik 서버 접속

SSH로 Traefik 서버에 접속한다.

SSH $ ssh traefik@192.168.0.230
Step 03

라우팅 파일 편집

/etc/traefik/dynamic/ 폴더 안의 .yml 파일은 모두 자동 감지된다. 기존 routes.yml에 추가하거나, 서비스별로 새 파일을 만들 수 있다.

파일 편집 # 방법 A: 기존 파일에 추가 $ sudo vim /etc/traefik/dynamic/routes.yml # 방법 B: 새 파일 생성 (서비스별 분리 관리 시 권장) $ sudo vim /etc/traefik/dynamic/chris-app.yml
Step 04

라우팅 규칙 작성

YAML 파일에 라우터(어떤 도메인으로 들어오면)와 서비스(어떤 서버로 보낼지)를 정의한다. 아래 템플릿에서 [서비스명], [서브도메인], [대상IP], [포트]를 변경한다.

라우팅 규칙 템플릿 http: routers: [서비스명]: rule: "Host(`[서브도메인].yourdomain.com`)" entryPoints: - websecure service: [서비스명] tls: certResolver: letsencrypt services: [서비스명]: loadBalancer: servers: - url: "http://[대상IP]:[포트]"
Step 05

파일 저장

vim에서 :wq로 저장하면 Traefik이 파일 변경을 자동 감지하여 즉시 적용한다. 서비스 재시작이 필요 없다. SSL 인증서도 Let's Encrypt에서 자동 발급된다.

dynamic/ 폴더의 YAML을 저장하면
재시작 없이 즉시 반영된다.

Part III

실전 예시 3가지

01

개발자 서버 1대 연결

Chris의 개발 서비스를 서브도메인으로 노출

/etc/traefik/dynamic/chris-app.yml http: routers: chris-app: rule: "Host(`chris-app.yourdomain.com`)" entryPoints: - websecure service: chris-app tls: certResolver: letsencrypt services: chris-app: loadBalancer: servers: - url: "http://192.168.0.202:8080"
02

개발자 3명 한 파일에 등록

하나의 YAML 파일에서 여러 서비스를 관리

/etc/traefik/dynamic/dev-servers.yml http: routers: chris-app: rule: "Host(`chris.yourdomain.com`)" entryPoints: - websecure service: chris-app tls: certResolver: letsencrypt lucy-app: rule: "Host(`lucy.yourdomain.com`)" entryPoints: - websecure service: lucy-app tls: certResolver: letsencrypt evan-app: rule: "Host(`evan.yourdomain.com`)" entryPoints: - websecure service: evan-app tls: certResolver: letsencrypt services: chris-app: loadBalancer: servers: - url: "http://192.168.0.202:8080" lucy-app: loadBalancer: servers: - url: "http://192.168.0.203:8080" evan-app: loadBalancer: servers: - url: "http://192.168.0.204:8080"
03

경로(Path) 기반 라우팅

하나의 도메인에서 경로로 서비스를 분기

도메인 하나에 여러 서비스를 연결하려면 PathPrefix 조건을 추가한다. app.yourdomain.com/api는 API 서버로, app.yourdomain.com은 프론트엔드로 보내는 식이다.

경로 기반 라우팅 http: routers: api-service: rule: "Host(`app.yourdomain.com`) && PathPrefix(`/api`)" entryPoints: - websecure service: api-service tls: certResolver: letsencrypt services: api-service: loadBalancer: servers: - url: "http://192.168.0.202:3000"
Part IV

트러블슈팅

설정을 저장했는데 서비스에 접근이 안 되는 경우. 대부분 아래 3가지 중 하나다.

502 Bad Gateway
Traefik이 요청을 받았지만, 백엔드 서버가 응답하지 않는다.
대상 서버에서 해당 포트가 열려있는지 확인한다. 서비스가 실행 중인지, 방화벽이 차단하고 있지 않은지 점검한다. sudo firewall-cmd --list-all로 방화벽 상태를 확인한다.
404 Not Found
Traefik이 해당 도메인에 대한 라우팅 규칙을 찾지 못했다.
Host 규칙의 도메인명에 오타가 없는지 확인한다. DNS가 Traefik(230)을 가리키는지도 확인한다. nslookup chris-app.yourdomain.com으로 DNS 해석 결과를 확인한다.
SSL 인증서 오류
Let's Encrypt 인증서 발급에 실패했다.
/etc/traefik/acme/ 폴더의 권한을 확인한다. Let's Encrypt는 Rate Limit이 있다. 같은 도메인에 반복 요청하면 차단될 수 있다. 1시간 대기 후 재시도한다.
디버깅 명령어
확인 및 디버깅 # Traefik 실시간 로그 확인 $ sudo journalctl -u traefik -f # Traefik 대시보드 확인 (설정되어 있는 경우) # 브라우저에서 접속 http://192.168.0.230:8080/dashboard/ # 라우팅 테스트 (Host 헤더로 직접 요청) $ curl -H "Host: chris-app.yourdomain.com" http://192.168.0.230 # 설정 문법 오류 확인 (DEBUG 모드) $ sudo traefik --configFile=/etc/traefik/traefik.yml --log.level=DEBUG
주의사항
  1. /etc/traefik/dynamic/ 폴더 안의 파일만 자동 감지된다 — 하위 폴더는 감지되지 않을 수 있으니 폴더 안에 직접 .yml 파일을 둔다
  2. traefik.yml(메인 설정)을 수정하면 sudo systemctl restart traefik으로 재시작이 필요하다
  3. dynamic/ 폴더의 파일은 저장 즉시 반영, 재시작 불필요
  4. 파일 편집 시 root 권한이 필요하다 — sudo vim을 사용한다
  5. 개발자 개인 서버에 별도 Traefik을 설치하지 않는다 — 중앙 Traefik(230)에서 통합 관리한다

YAML 한 줄이
서비스를 연결한다

DNS를 잡고, YAML을 저장하면 끝이다. 인프라를 두려워할 필요 없다. 규칙만 지키면 5분이면 된다.