Portainer에 백엔드, 프론트엔드 배포 방식

홍성웅·2025년 3월 18일
0

Nginx 로고

Nginx란?

Nginx는 클라이언트로부터 요청을 받아 정적 파일을 제공하는 HTTP 웹 서버로 활용되거나, 리버스 프록시 서버로 동작하여 WAS(Web Application Server)의 부하를 분산시키는 로드밸런서 역할을 수행한다.

Nginx 사용 이유

현재 Docker를 통해 로컬에서 개발한 프로젝트를 동일한 환경에서 실행하기 위해 Docker를 활용하고 있다. AWS Lightsail에서는 보안을 위해 Port 80(HTTP)과 443(HTTPS)만 개방되어 있어, 다른 포트로는 외부 접근이 제한되어여한다.

환경 구성

  • 백엔드(BE): NestJS (Docker port: 3000)
  • 프론트엔드(FE): React + Vite (Docker port: 80)

구현 목표

도메인을 https://domain.example.com으로 가정할 때, 다음과 같이 구성하고자 합니다:

  1. 해당 도메인 접근 시 Nginx가 80번 포트로 연결되어 프론트엔드의 정적 파일을 제공
  2. https://domain.example.com/api 경로로 접근 시 백엔드 서버(3000 포트)로 요청을 전달하는 리버스 프록시 설정

Nginx 설정

다음은 Nginx 설정 예시입니다.

reverse proxy 에는 portainer에 올린 백엔드의 container 이름을 추가해야함

server {
    listen 80;
    server_name domain.example.com;
    
    # HTTPS 프록시를 위한 설정 (Cloudflare, AWS ALB 등)
    set_real_ip_from 0.0.0.0/0;  # 모든 프록시 IP 허용 (Cloudflare라면 해당 IP만 지정)
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    
    # React Vite 정적 파일 서빙
    root /usr/share/nginx/html;
    index index.html;
    
    location / {
        try_files $uri /index.html;
    }
    
    # NestJS 백엔드 리버스 프록시 설정
    location /api/ {
        proxy_pass http://containerName:3000;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
    }
    
    # WebSocket 프록시 설정 (ws:// 또는 wss:// 지원)
    location /socket.io/ {
        proxy_pass http://containerName:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header 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;
    }
    
    error_page 404 /index.html;
}

Docker 설정

Vite 프로젝트의 경우 환경 변수가 빌드 시점에 결정되므로, 빌드 전에 동적으로 설정해야 합니다.

docker-compose.yml

services:
  app:
    container_name: w-place-frontend
    build:
      context: .
      args:
        VITE_API_URL: ${VITE_API_URL}
        VITE_SOCKET_URL: ${VITE_SOCKET_URL}
    ports:
      - "80:80"
    environment:
      VITE_API_URL: ${VITE_API_URL}
      VITE_SOCKET_URL: ${VITE_SOCKET_URL}

Dockerfile

# 빌드 단계
FROM node:18 as build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .

# .env 파일을 빌드 시점에 동적으로 생성
ARG VITE_API_URL
ARG VITE_SOCKET_URL
RUN touch .env && \
    echo "VITE_API_URL=${VITE_API_URL}" >> .env && \
    echo "VITE_SOCKET_URL=${VITE_SOCKET_URL}" >> .env

RUN npm run build

# 프로덕션 단계
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

정리

이 구성을 통해 단일 도메인에서 프론트엔드와 백엔드 서비스를 모두 제공할 수 있었다. Nginx가 프록시 역할을 수행하여 클라이언트 요청을 적절한 서비스로 라우팅하며, Docker를 통해 일관된 환경에서 애플리케이션을 배포할 수 있다.

80번 포트에 nginx 가 깔리게 되고 domain으로 접속시 80번포트에 있는 nginx가 fe의 정적파일을 보내준다.

fe 에서는 be쪽에 https://domain.example.com/api url을 통해 api 호출을 진행하면 된다.

profile
Backend Developer

0개의 댓글