From 097d102dd99f53d0f6f9affb350f39ea0a41f29f Mon Sep 17 00:00:00 2001 From: Johngreen Date: Sat, 7 Mar 2026 23:58:39 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20nginx=EB=A5=BC=20Traefik=20v3.2?= =?UTF-8?q?=EB=A1=9C=20=EA=B5=90=EC=B2=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Docker 라벨 기반 자동 라우팅으로 전환 - /admin/* → admin 서비스 (StripPrefix 미들웨어) - /* → web 서비스 (catch-all) - Let's Encrypt 설정 준비 (도메인 확보 시 활성화) - 다른 서비스 추가 시 라벨만 붙이면 자동 등록 Co-Authored-By: Claude Opus 4.6 --- deploy/traefik/traefik.yml | 21 +++++++++++++++++++ docker-compose.prod.yml | 41 ++++++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 deploy/traefik/traefik.yml diff --git a/deploy/traefik/traefik.yml b/deploy/traefik/traefik.yml new file mode 100644 index 0000000..8aee852 --- /dev/null +++ b/deploy/traefik/traefik.yml @@ -0,0 +1,21 @@ +api: + dashboard: false + +entryPoints: + web: + address: ":80" + websecure: + address: ":443" + +providers: + docker: + exposedByDefault: false + +# 도메인 준비되면 주석 해제 +# certificatesResolvers: +# letsencrypt: +# acme: +# email: your-email@example.com +# storage: /letsencrypt/acme.json +# httpChallenge: +# entryPoint: web diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 84b98b9..8fd8f6f 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -30,6 +30,20 @@ services: timeout: 5s retries: 5 + traefik: + image: traefik:v3.2 + restart: unless-stopped + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./deploy/traefik/traefik.yml:/etc/traefik/traefik.yml:ro + - traefik_letsencrypt:/letsencrypt + depends_on: + - web + - admin + web: build: context: . @@ -45,6 +59,12 @@ services: NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000} NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:?NEXTAUTH_SECRET is required} NODE_ENV: production + labels: + - "traefik.enable=true" + - "traefik.http.routers.web.rule=PathPrefix(`/`)" + - "traefik.http.routers.web.entrypoints=web" + - "traefik.http.routers.web.priority=1" + - "traefik.http.services.web.loadbalancer.server.port=3000" depends_on: postgres: condition: service_healthy @@ -64,25 +84,20 @@ services: DATABASE_URL: postgresql://${DB_USER:-relink}:${DB_PASSWORD}@postgres:5432/${DB_NAME:-relink_prod}?schema=public REDIS_URL: redis://:${REDIS_PASSWORD}@redis:6379 NODE_ENV: production + labels: + - "traefik.enable=true" + - "traefik.http.routers.admin.rule=PathPrefix(`/admin`)" + - "traefik.http.routers.admin.entrypoints=web" + - "traefik.http.routers.admin.middlewares=admin-strip" + - "traefik.http.middlewares.admin-strip.stripprefix.prefixes=/admin" + - "traefik.http.services.admin.loadbalancer.server.port=3000" depends_on: postgres: condition: service_healthy redis: condition: service_healthy - nginx: - image: nginx:alpine - restart: unless-stopped - ports: - - "80:80" - - "443:443" - volumes: - - ./deploy/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro - - ./deploy/nginx/ssl:/etc/nginx/ssl:ro - depends_on: - - web - - admin - volumes: postgres_data: redis_data: + traefik_letsencrypt: