From 2b8d1ac703034668e74c1277d2ac69862bf489e1 Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Tue, 2 Jun 2026 08:36:34 +0700 Subject: [PATCH] feat(infra): replace traefik path routing with nginx reverse proxy - Add nginx service with /api, /ws, and / location routing - Move traefik labels to proxy service only (port 80) - Remove traefik labels from backend and frontend services - Backend routes to :3001 via nginx upstream - WebSocket upgrade enabled for /ws path Co-Authored-By: Claude Opus 4.8 --- infra/docker/Dockerfile.nginx | 7 +++++ infra/docker/docker-compose.yml | 46 +++++++++++++++++------------ infra/docker/nginx/nginx.conf | 52 +++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 19 deletions(-) create mode 100644 infra/docker/Dockerfile.nginx create mode 100644 infra/docker/nginx/nginx.conf diff --git a/infra/docker/Dockerfile.nginx b/infra/docker/Dockerfile.nginx new file mode 100644 index 0000000..d7e7c22 --- /dev/null +++ b/infra/docker/Dockerfile.nginx @@ -0,0 +1,7 @@ +FROM nginx:alpine + +COPY nginx.conf /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"] diff --git a/infra/docker/docker-compose.yml b/infra/docker/docker-compose.yml index fa70e8d..413a107 100644 --- a/infra/docker/docker-compose.yml +++ b/infra/docker/docker-compose.yml @@ -1,7 +1,26 @@ version: '3.8' services: - # Backend Service (REST API + WebSocket via Traefik) + # Nginx Reverse Proxy — handles /api and /ws routing behind Traefik + proxy: + build: + context: . + dockerfile: Dockerfile.nginx + container_name: bete-proxy + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.bete.rule=Host(`imphnen.asepharyana.my.id`)" + - "traefik.http.routers.bete.entrypoints=websecure" + - "traefik.http.routers.bete.tls=true" + - "traefik.http.services.bete.loadbalancer.server.port=80" + depends_on: + - backend + - frontend + networks: + - app-shared-net + + # Backend Service (REST API + WebSocket) backend: build: context: .. @@ -12,13 +31,8 @@ services: - ../../.env environment: NODE_ENV: production - WEBSERVER_PORT: 3000 - labels: - - "traefik.enable=true" - - "traefik.http.routers.bete-backend.rule=Host(`imphnen.asepharyana.my.id`) && PathPrefix(`/api`, `/ws`)" - - "traefik.http.routers.bete-backend.entrypoints=websecure" - - "traefik.http.routers.bete-backend.tls=true" - - "traefik.http.services.bete-backend.loadbalancer.server.port=3000" + WEBSERVER_PORT: 3001 + # No Traefik labels — nginx handles routing depends_on: - discord-gateway networks: @@ -40,7 +54,7 @@ services: networks: - app-shared-net - # Frontend Service (React Dashboard via Traefik) + # Frontend Service (React Dashboard) frontend: build: context: .. @@ -48,16 +62,10 @@ services: container_name: bete-frontend restart: unless-stopped environment: - VITE_API_URL: https://imphnen.asepharyana.my.id - VITE_WS_URL: wss://imphnen.asepharyana.my.id - labels: - - "traefik.enable=true" - - "traefik.http.routers.bete-frontend.rule=Host(`imphnen.asepharyana.my.id`)" - - "traefik.http.routers.bete-frontend.entrypoints=websecure" - - "traefik.http.routers.bete-frontend.tls=true" - - "traefik.http.services.bete-frontend.loadbalancer.server.port=3000" - depends_on: - - backend + # Point to the same domain — nginx routes /api and /ws to backend + VITE_BE_API_URL: https://imphnen.asepharyana.my.id + VITE_BE_WS_URL: wss://imphnen.asepharyana.my.id + # No Traefik labels — nginx handles routing networks: - app-shared-net diff --git a/infra/docker/nginx/nginx.conf b/infra/docker/nginx/nginx.conf new file mode 100644 index 0000000..564625b --- /dev/null +++ b/infra/docker/nginx/nginx.conf @@ -0,0 +1,52 @@ +upstream backend { + server backend:3001; +} + +upstream frontend { + server frontend:3000; +} + +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +server { + listen 80; + server_name imphnen.asepharyana.my.id; + + # API proxy + location /api/ { + proxy_pass http://backend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + # WebSocket proxy + location /ws { + proxy_pass http://backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # WebSocket-specific: no buffering, longer timeouts + proxy_buffering off; + proxy_read_timeout 86400s; + proxy_send_timeout 86400s; + } + + # Frontend SPA fallback + location / { + proxy_pass http://frontend; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +}