compose.yml
tinyauth:
image: ghcr.io/steveiliop56/tinyauth:latest
container_name: tinyauth
hostname: tinyauth
networks:
- traefik-network
....
environment:
- ...
labels:
- "traefik.enable=true"
- "traefik.http.services.tinyauth.loadBalancer.server.port=3000"
도커로 배포하고 싶은 컨테이너를 설정 하기 위해서는 label 설정이 필요합니다.
"traefik.enable=true" 이 옵션은 traefik이 컨테이너가 활성화 되면 인식해라
라는 옵션입니다. traefik은 이 옵션이 켜져있으면 자동적으로 기본 경로를 만들어 줍니다.
"traefik.http.services.tinyauth.loadBalancer.server.port=3000" 이 옵션을 사용 하지 않으면,
서비스 이름이 위와 같이 자동으로 생성이 됩니다.
저같은 경우에는 compose에서 쓴 tinyauth가 접두사로 붙고,
스택 이름인 traefik-service 가 붙어서 저런 이름이 되었습니다.
사용자 환경이 다 다르기 때문에
traefik.http.services.[원하는 서비스명].loadBalancer.server.port 을 선언을 하면,
[원하는 서비스명]@docker 라는 서비스로 보기 쉽게 만들어 집니다.
사용될 포트를 명시적으로 선언도 가능하구요
즉, 서비스를 만들고 싶으실때, docker-compose에서는
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.services.[원하는 서비스명].loadBalancer.server.port=[컨테이너 서비스 포트]"
를 사용 하시면 됩니다. 꼭 서비스하실 도커 컨테이너는 traefik과 같은 네트워크에 있어야 합니다
nginx:
image: nginx:stable-alpine
hostname: nginx-rtn
container_name: nginx-rtn
restart: unless-stopped
networks:
- traefik-network
volumes:
- ./traefik/err:/usr/share/nginx/html:ro
nginx 모듈이 있는 이유
traefik은 에러 메세지를 html으로 반환 할 수 있는 기능이 없고, 에러가 생겼을 때
미들웨어를 호출(이경우에는 nginx)해서 특수한 동작을 할 수 있습니다.
여기서는 에러 페이지를 보여주기위한 기능을 하면 된다라고 보시면 됩니다.
그를 위해 경량 이미지를 사용합니다.
traefik.yml 설명
api:
dashboard: true
insecure: true # Set to false in production to require authentication for dashboard access
debug: true
dashboard: true 는 웹 대시보드를 활성화하는 옵션 입니다.
insecure: true 는 비밀번호 없이 웹 대시보드를 접근 할 수 있게 합니다.
debug: true 는 로그가 더 자세하게 나오는 기능 입니다.
log:
level: "DEBUG" # Recommended to change to INFO or ERROR after setup is complete
로그 레벨을 정할 수 있는 섹션 입니다. 설정을 다하시면 DEBUG에서 INFO나 ERROR로 바꾸시는것을 추천 드립니다.
기타 다른 옵션들은 이번 가이드에서는 설명하지 않습니다.
dynamic.yml
제일 중요한 파일인데요, 작성은 router -> service -> middlewares 로 작성되어 있지만,
역순으로 설명하도록 하겠습니다.
#Start Middlewares
middlewares:
auth:
forwardAuth:
address: "http://tinyauth:3000/api/auth/traefik"
먼저 인증에 사용되는 middlewares인 auth입니다.
middleware의 구조는
auth: #middleware 이름
forwardAuth: #해당 middleware의 기능. middleware의 기능은 정해져 있는데, docs를 참고하시는게 좋습니다.
address: "http://tinyauth:3000/api/auth/traefik" #이 아래는 해당 기능에 대한 속성 설정
https://doc.traefik.io/traefik/middlewares/http/forwardauth/
에 그림을 봐주시면 해당 기능이 어떻게 작동하시는지 볼 수 있습니다.
###### Chain Middlewares ######
secure-stack:
chain:
middlewares: [compress, ratelimit, secure-headers, custom-headers]
다음은 Chain Middlewares 에 대한 설명 입니다.
우선, dynamic.yml 의 내용을 보시면
compress: { compress: {} }
...
ratelimit:
...
secure-headers:
...
custom-headers:
...
이런 기본 보안관련 옵션들이 있습니다.
하지만 이걸 라우터에 적용시키려면 원래는
middlewares: [compress, ratelimit, secure-headers, custom-headers]
이런식으로 사용 해야 하는데요,
secure-stack: #chain middleware 이름
chain: # middleware chain 기능을 사용하겠다
middlewares: [compress, ratelimit, secure-headers, custom-headers] #나는 여기에 써져 있는 middleware를 전부 같이 쓰겠다 선언
이런식으로 사용하게 되면,
middlewares: [error-pages, secure-stack]
이렇게 secure-stack만 선언해도, 적혀있는 모든 보안 관련 미들웨어들을 한번에 적용할수가 있는 유용한 옵션입니다.
다음 에러페이지에 대한 middleware 인데요
error-pages: #middleware 이름
errors: #error 기능 사용
status: ["400-599"] #400-599 사이의 값이 반환이 되면
service: error #error라는 이름의 서비스를 호출하고
query: "/err.html" #/err.html를 호출하라
라는 기능 입니다. 여기서 서비스란을 한번 보면
services: #service들을 작성하는 섹션 선언
error: #service 이름을 error로 선언
loadBalancer: # 로드밸런서 안에 서버 주소를 설정할 수 있는 기능이 있습니다. servers 항목이 두개 이상이면 실제로 분산처리 됩니다.
servers: [{ url: "http://nginx-rtn:80" }] #error라는 service는 nginx-rtn(nginx의 host명입니다. compose.yml에 선언되어있습니다)를 가르킨다
입니다 즉, error-pages라는 middleware를 router에 적용하면,
traefik에서 에러를 반환하면, error 서비스에 err.html 파일을 보여달라고 호출하고
error 서비스에 연결된 컨테이너인 nginx가 처리 해서 보여주는 구조 입니다.
다음은 서비스에 대한 내용입니다.
보통 services에서는 도커로 서비스 하지 않으시는것들을 추가로 기입하시게 될텐데요(nas server등)
services:
truenas: #service 이름
loadBalancer:
servers: [{ url: "http://192.168.0.100:8080" }] #해당 서비스의 ip:port
이런식으로 작성 하시면 됩니다.
서비스를 선언 한다는 것은 내용이 안적혀져 있고 방향만 가르켜주는 표지판을 세웠다 라고 이해하시면 될것 같습니다.
원래는 도커 서비스들도 일일히 기입을 해야하는게 맞습니다.
하지만 저희는
labels:
- "traefik.enable=true"
- "traefik.http.services.[원하는 서비스명].loadBalancer.server.port=[컨테이너 서비스 포트]"
이렇게 docker 컨테이너를 생성할때 서비스명을 미리 선언해 두기로 했기 때문에, 여기서는 도커 서비스가 아니거나
traefik 서버가 아닌 바깥의 서버에 대해서 선언이 필요할때만 작성하시면 되겠습니다.
다음으로 라우터 설정입니다. 맨처음 라우터는 이런 설정 입니다.
global-catch-all: #모든 서브도메인에 대한 처리 라우터
entryPoints: [websecure] # 엔트리 포인트는 traefik의 입구라고 보시면 됩니다.
service: error #아래에서 설명
middlewares: [error-pages, secure-stack] # 이 router를 통할때 해당 middleware 호출
rule: "PathPrefix(`/`)" #모든 도메인을 다 처리하겠다는 뜻 입니다.
tls: {} #TLS 연결로 처리
priority: 0 #이 router를 최우선적으로 처리
우선 이상한점이 있을수가 있습니다
service에 error가 설정되어 있는데요.
그럼 무조건 error-page가 표시되는것이 아니냐? 라고 할 수 있는데 원래는 "그렇지 않습니다"
router 선언시에는 service 항목이 필수로 들어가야 해서 더미로 들어간 서비스 입니다.
실제로 traefik은 해당 router가 있으면 이렇게 작동 합니다.
dashboard.domain.com으로 접속
traefik이 dashboard는 api@internal 서비스가 연결되있는걸 확인하고 거기로 접속시킴 - 정상
non-exist.domain.com으로 접속 (와일드카드로 연결되어 있으므로 어떤 서브도메인이든 접속이 들어오는건 맞습니다)
traefik이 non-exist.domain.com 에 맞는 룰을 가진 router가 없으므로 에러를 반환 합니다
이를 error-pages 미들웨어가 감지하고 에러 페이지를 호출하여 보여줌
이런 구조로 설정되어 있습니다.
딱히 설명을 안해도 되지만, 의문점을 가지실수도 있을것 같아 설명드렸습니다.
다음은 정상 라우터 설정 예시들을 보겠습니다.
dashboard: #router 이름
entryPoints: [websecure]
service: api@internal #api@internal은 traefik의 웹 대시보드를 가르키는 고유적인 이름입니다.
middlewares: [error-pages, secure-stack, auth] # 이 router로 진입할때는 해당 미들웨어를 적용 시켜라 라는 뜻입니다.
rule: 'Host(`dashboard.{{ env "DOMAIN" }}`)'
tls: {}
auth:
entryPoints: [websecure]
service: tinyauth@docker
middlewares: [error-pages, secure-stack]
rule: 'Host(`auth.{{ env "DOMAIN" }}`)'
tls: {}
우선 rule: 'Host(`dashboard.{{ env "DOMAIN" }}`)' 를 보도록 할까요
{{ env "DOMAIN" }} 이 선언되어 있습니다.
이는 앞서 docker-compose.yml 에 환경변수로 선언된 내용인데요,
컴포즈 환경변수 파일에서 DOMAIN=domain.com 같이 설정 하셨을 겁니다
dynamic.yml이 해당 환경변수를 인식해서 해당 도메인으로 치환해주는데요,
그럼 dashboard 라우터는 실제로 규칙이 'Host(`dashboard.domain.com`)'
으로 설정 되게 됩니다.
그럼 이 라우터는 dashboard.domain.com 로 오는 트래픽을 처리하게 됩니다.
앞서 서비스는 해당 서비스의 방향을 가르키고 있는 내용없는 표지판을 세우는 거라고 말씀드렸는데요,
router의 rule은 해당 표지판의 내용을 쓰는거라고 생각하시면 됩니다.
tls: {}는 https로 통신하라는 내용 입니다.
middleware는 router를 보시면 대부분 error-pages, secure-stack을 기본으로 사용하고, auth만 있거나 없거나 한데요
auth도 같이 쓰게 되면 google 로그인을 요구하고 앞서 설정하신 내용대로
계정이 일치하면 접속 허가, 아니면 비허가 되게 됩니다.
결론적으로, 구현한 환경에서 새로운 서비스를 추가 하기 위해서는 어떻게 해야할까요?
도커 서비스가 아닌 서비스를 연결하고 싶다 >
routers:
....
nas:
entryPoints: [websecure]
service: truenas
middlewares: [error-pages, secure-stack, auth] #auth는 서비스마다 선택 자유
rule: 'Host(`nas.{{ env "DOMAIN" }}`)'
tls: {}
....
services:
....
truenas:
loadBalancer:
servers: [{ url: "http://nas 서버 주소" }]
....
도커 서비스를 연결하고 싶다 >
우선 docker-compose.yml에서
portainer:
image: ..
hostname: portainer
networks: [traefik-network]
environment:
...
labels:
- "traefik.enable=true"
- "traefik.http.services.portainer.loadBalancer.server.port=9000"
그 후 dynamic.yml에서
routers:
....
portainer:
entryPoints: [websecure]
service: portainer@docker
middlewares: [error-pages, secure-stack, auth] #auth는 서비스마다 선택 자유
rule: 'Host(`portainer.{{ env "DOMAIN" }}`)'
tls: {}
....
'서버 > Home Server 구축' 카테고리의 다른 글
02. Google OAuth + TinyAuth 세팅하기 (0) | 2025.03.28 |
---|---|
01. CloudFlare Tunnel 환경 만들기 (0) | 2025.03.26 |