Skip to content

Appendix A. 사내 실무 환경설정 및 Docker/Nginx 배포 가이드 ​

"로컬에서만 잘 돌아가는 코드는 아무런 가치가 없다. 개발, 검증, 운영 환경을 안전하게 분기하고, Docker와 Nginx로 프로덕션에 배포하는 엔터프라이즈 실무 표준을 정립한다."


A.1 환경변수 분기 전략 (.env) ​

사내 시스템은 보통 로컬(Local), 개발/검증(Dev/Stage), 운영(Prod) 환경으로 나뉩니다.
API 서버의 도메인이 환경마다 달라지는데, 코드 안에 http://localhost:8080을 하드코딩해서는 안 됩니다.

Vite는 접두사 **VITE_**로 시작하는 환경변수를 빌드 시점에 코드 내부로 주입해 줍니다.

[설정 A-1] 로컬 개발 환경 (.env.development) ​

ini
# 로컬 개발 환경: Vite의 리버스 프록시(/api)를 타도록 상대 경로 지정
VITE_API_BASE_URL=
VITE_ENV_NAME=local

[설정 A-2] 사내 운영 환경 (.env.production) ​

ini
# 운영 배포 환경: 실제 사내 API 게이트웨이 또는 도메인 주소 지정
VITE_API_BASE_URL=https://board-api.company.com
VITE_ENV_NAME=production

코드 내부에서는 TypeScript의 타입 가호를 받으며 다음과 같이 참조합니다:

typescript
// src/api/httpClient.ts
export const httpClient = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL || '',
  timeout: 10000
});

A.2 프로덕션 배포를 위한 멀티 스테이지 Dockerfile ​

Vue 3 SPA는 빌드하고 나면 순수한 HTML, CSS, JavaScript 정적 파일(dist/ 폴더)만 남습니다.
Node.js 런타임을 운영 서버에 통째로 띄울 필요 없이, 초경량 Nginx 컨테이너로 서빙하는 것이 엔터프라이즈의 표준입니다.

[코드 A-1] 멀티 스테이지 빌드 (frontend/Dockerfile) ​

dockerfile
# ==========================================
# 1단계: 빌드 스테이지 (Node.js 환경)
# ==========================================
FROM node:20-alpine AS builder
WORKDIR /app

# 캐시 효율을 위해 package.json 먼저 복사
COPY package*.json ./
RUN npm ci

# 소스 복사 및 프로덕션 빌드 실행
COPY . .
RUN npm run build

# ==========================================
# 2단계: 서빙 스테이지 (경량 Nginx 알파인 환경)
# ==========================================
FROM nginx:alpine
# 빌드된 dist 폴더만 Nginx 루트로 복사 (이미지 용량: 30MB 이하로 극단적 경량화)
COPY --from=builder /app/dist /usr/share/nginx/html

# SPA 라우팅을 위한 커스텀 Nginx 설정 파일 주입
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

A.3 SPA 히스토리 모드를 위한 Nginx 라우팅 설정 (nginx.conf) ​

Vue Router의 createWebHistory()를 사용할 때 가장 흔히 터지는 운영 장애가 있습니다:
메인(/)에서는 잘 동작하는데, 사용자가 특정 상세 URL(예: /post/10)에서 **브라우저 새로고침(F5)**을 누르면 Nginx가 실제 물리 파일인 /post/10을 찾다가 404 Not Found 에러를 뿜어내는 현상입니다.

이를 방지하기 위해 모든 URL 요청을 Vue의 index.html로 폴백(Fallback)시켜 주어야 합니다.

[코드 A-2] frontend/nginx.conf ​

nginx
server {
    listen 80;
    server_name localhost;

    root /usr/share/nginx/html;
    index index.html;

    # Gzip 압축 전송 설정 (초기 로딩 속도 극대화)
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

    location / {
        # 🌟 핵심: 요청한 파일($uri)이나 디렉토리($uri/)가 없으면 index.html로 토스!
        try_files $uri $uri/ /index.html;
    }

    # 정적 에셋(JS, CSS, 이미지)의 브라우저 캐시 정책 (1년 캐싱)
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, no-transform";
    }

    # 500 등 서버 장애 시 에러 페이지
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
}

A.4 사내 원클릭 빌드 및 배포 명령어 ​

bash
# 1. Docker 이미지 빌드
docker build -t company-board-fe:latest .

# 2. 컨테이너 기동 (포트 80 매핑)
docker run -d -p 80:80 --name board-frontend company-board-fe:latest

이 설정이 갖춰지면, 사내 GitLab CI나 Jenkins 파이프라인에서 커밋 푸시 한 번으로 운영 서버에 무중단으로 컨테이너가 배포되는 완벽한 DevOps 파이프라인이 완성됩니다.

Moon HomeLab Engineering Knowledge Hub