[Docker 시리즈 5편] 정적 사이트를 Docker+nginx로 배포하는 전체 흐름

English version

4편에서 만든 정적 산출물을 이제 실제로 웹에서 보여 주어야 합니다. 이번 글은 가장 흔한 조합인 "정적 파일 + nginx"를 Docker로 묶는 기본기를 다룹니다. 모든 예시는 고등학생도 따라 할 수 있는 단일 Dockerfile과 짧은 nginx.conf를 기준으로 설명합니다.

이 글의 흐름

  1. 정적 사이트를 컨테이너에 담는 머릿속 그림
  2. nginx
    이용해 이미지를 만드는 기본 Dockerfile
  3. 꼭 알아야 할 nginx.conf 최소 설정
  4. 터미널에서 따라 하는 10분 실습
  5. 정적 사이트 배포에서 자주 만나는 확장 포인트

읽기 카드

  • 예상 소요 시간: 15분
  • 사전 준비: docker build, docker run 명령을 한 번이라도 실행해 본 경험
  • 읽고 나면: "정적 폴더 → nginx 이미지 → 실행" 과정을 스스로 설명할 수 있습니다.

머릿속 그림: 파일 상자 + 배달 트럭

정적 웹사이트를 컨테이너에 올리는 과정을 아래처럼 상상해 보세요.

1. build/ 폴더: 완성된 HTML/CSS/JS 상자
2. nginx 이미지: 상자를 싣고 배달하는 트럭
3. Docker 컨테이너: 트럭이 실제로 달리는 공간

트럭(nginx)은 상자 안에 어떤 프레임워크가 있었는지 관심이 없습니다. 단지 /usr/share/nginx/html 안의 파일을 그대로 내보낼 뿐입니다. 우리는 정적 파일을 그 위치로 복사하고, 트럭이 도착할 주소(포트 80)를 외부로 연결해 주면 됩니다.

기본 Dockerfile 살펴보기

가장 단순한 Dockerfile은 아래와 같습니다. 빌드 결과물이 build/ 폴더에 있다고 가정합니다.

FROM nginx:alpine
WORKDIR /usr/share/nginx/html
RUN rm -rf /usr/share/nginx/html/*
COPY build/ .
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
HEALTHCHECK CMD wget -qO- http://127.0.0.1/ >/dev/null || exit 1
  • RUN rm -rf ...는 기본으로 들어 있는 Welcome to nginx! 페이지를 비움으로써 실수로 노출되는 일을 막습니다.
  • COPY build/ .는 빌드 산출물을 문서 루트에 그대로 옮깁니다.
  • COPY nginx.conf ...는 우리가 준비한 설정을 덮어씌웁니다.
  • HEALTHCHECK는 30초마다 "응답이 오는지"를 확인하는 체온계 역할을 합니다. 정확한 간격을 추가하려면 --interval, --timeout 옵션을 붙이면 됩니다.

nginx.conf는 최소 네 줄만 이해해도 된다

처음부터 거대한 설정을 외울 필요는 없습니다. 아래 네 줄 정도면 정적 사이트를 안전하게 서빙할 수 있습니다.

server {
  listen 80;
  server_name _;
  root /usr/share/nginx/html;
  location / { try_files $uri $uri/ /index.html; }
}
  • listen 80;server_name _;은 "80번 포트를 열고, 어떤 도메인이 와도 응답한다"는 뜻입니다.
  • root는 방금 복사한 정적 파일의 위치를 가리킵니다.
  • try_files 규칙은 "정확한 파일 → 폴더 인덱스 → index.html" 순서로 찾습니다. SPA를 배포한다면 마지막 /index.html 덕분에 클라이언트 라우팅이 깨지지 않습니다.

여기에 캐시 정책, gzip, 보안 헤더 등을 하나씩 추가해 나가면 됩니다. 중요한 것은 "root와 location만 이해해도 나머지는 확장"된다는 사실입니다.

작은 실습: 이미지를 만들고 컨테이너 확인하기

  1. npm run build 같은 명령으로 정적 사이트를 만들어 build/ 폴더를 확인합니다.
  2. 위 예시와 같은 Dockerfile, nginx.conf를 같은 폴더에 둡니다.
  3. 터미널에서 아래 명령을 실행합니다.
docker build -t my-static-site .
docker run -d --name my-static -p 8080:80 my-static-site
  1. 브라우저에서 http://localhost:8080을 열고 화면이 뜨는지 확인합니다.
  2. 상태를 점검하려면 docker ps, docker logs my-static, curl -I localhost:8080 정도만 실행해도 충분합니다.

Tip: 컨테이너가 마음에 들지 않으면 docker rm -f my-static으로 지우고 Dockerfile을 수정한 뒤 다시 빌드하면 됩니다. 실습에서는 "빠르게 고치고 재시도"하는 습관이 가장 중요합니다.

흔한 실수와 해결법

  • 빌드 폴더 경로를 잘못 복사: COPY build/ . 앞에 빌드 명령을 넣거나, COPY --from=builder 구문으로 멀티 스테이지 빌드에서 직접 가져오면 해결됩니다.
  • 포트 충돌: -p 8080:80에서 앞쪽 숫자만 바꿔도 됩니다. 8787, 3000 등 빈 포트를 찾아 사용하세요.
  • 헬스체크 실패: wget이 없다면 apk add --no-cache wgetDockerfile에 추가하거나 curl 버전을 사용하세요.

정적 사이트 배포에서 자주 만나는 확장 포인트

기본 배포가 끝나면 보통 아래 기능을 하나씩 추가하게 됩니다.

  • gzip과 캐시 헤더로 정적 파일 전송을 최적화하기
  • /ko, /en 같은 경로 리다이렉트 붙이기
  • /api 요청만 별도 백엔드로 프록시하기
  • docker compose로 데이터베이스나 API와 함께 관리하기

하지만 핵심은 같습니다. 정적 파일을 /usr/share/nginx/html로 옮기고, 80번 포트를 외부에 연결한다. 이 기본 흐름을 확실히 이해했다면 어떤 정적 사이트라도 쉽게 도커라이즈할 수 있습니다.

다음 글 예고: Docker Compose로 실행 환경 묶기

이미지 하나만으로는 서비스 전체를 설명할 수 없습니다. 6편에서는 여러 컨테이너를 한 번에 정의하는 Docker Compose 기본기를 다루고, 웹+DB 같은 가장 흔한 조합부터 실습해 보겠습니다.

💬 댓글

이 글에 대한 의견을 남겨주세요