바이브 빌드 (Vibe Build)

혼자서 서버구축, 바이브 코딩, WebUI 제작, 배포, 운영, 응용과정을 기록하는 기술 블로그 입니다.

Docker Nginx 컨테이너

Docker Nginx 컨테이너

Article Guide

목  차

이 문서는 Docker Engine이 설치된 Linux 서버에서 Nginx 컨테이너를 실행하고, Windows 관리 PC의 웹 브라우저에서 접속을 확인하며, 컨테이너를 관리하는 과정을 설명합니다.

1. 이 문서에서 완성할 환경

이 문서를 마치면 다음 작업을 할 수 있습니다.

  • VS Code의 Remote – SSH 확장으로 project-dev-server에 연결하고 Linux 서버의 원격 터미널과 프로젝트 폴더에서 작업할 수 있습니다.
  • Nginx 공식 이미지 nginx:alpinenginx-web 컨테이너를 백그라운드에서 실행하고 unless-stopped 재시작 정책을 적용할 수 있습니다.
  • Linux 서버 내부 IP 주소의 8080번 포트를 Nginx 컨테이너의 80번 포트에 게시하고, Linux 서버와 Windows 관리 PC에서 Nginx 응답을 확인할 수 있습니다.
  • docker ps, docker logs, docker stop, docker start, docker restartdocker rm으로 컨테이너 상태와 로그를 확인하고 실행 주기를 관리할 수 있습니다.
  • Docker의 포트 공개 범위와 UFW의 관계를 이해하고, 서버의 내부 IP 주소에만 포트를 게시하는 방법을 적용할 수 있습니다.
  • Linux 서버의 nginx-web/html 폴더를 Nginx 웹 문서 폴더에 읽기 전용 바인드 마운트하여 사용자 웹페이지를 표시할 수 있습니다.
  • 컨테이너 이름 중복, 포트 충돌과 접속 거부 문제가 발생했을 때 상태, 로그, 포트와 네트워크를 순서대로 점검할 수 있습니다.

2. 시작하기 전에

다음 항목이 준비되어 있어야 합니다.

  • project-dev-server에 Docker Engine이 설치되어 있고 Docker 서비스가 실행 중이어야 합니다.
  • 현재 Linux 사용자가 docker 그룹에 포함되어 있거나 Docker 명령을 sudo로 실행할 수 있어야 합니다.
  • Windows 관리 PC에서 VS Code와 Remote – SSH 확장을 사용해 project-dev-server에 접속할 수 있어야 합니다.
  • Windows 관리 PC와 Linux 서버가 같은 네트워크에 연결되어 있고, Windows 관리 PC에서 사용할 서버의 내부 IP 주소를 알고 있어야 합니다.
  • Linux 서버의 내부 IP 주소가 실제 네트워크 인터페이스에 설정되어 있어야 합니다. 이 문서에서는 예시 주소로 192.168.1.231을 사용합니다.
  • Linux 서버가 Docker Hub에서 nginx:alpine 이미지를 내려받을 수 있도록 인터넷에 연결되어 있어야 합니다.
  • 호스트의 8080번 포트를 다른 프로그램이나 컨테이너가 사용하고 있지 않아야 합니다.
  • Linux 서버에서 접속 확인에 사용할 curl 명령을 실행할 수 있어야 합니다.
  • Linux 사용자에게 프로젝트 폴더를 만들고 HTML 파일을 저장할 수 있는 권한이 있어야 합니다.
  • 실제 암호, 개인 키와 인증정보를 명령, 문서 또는 화면 캡처에 기록하지 않아야 합니다.

Docker Engine 설치와 사용자 권한 설정은 Docker Engine 설치에서, VS Code의 Remote – SSH 연결은 VS Code 환경에서 확인할 수 있습니다.

3. VS Code에서 project-dev-server 접속

3.1 Remote – SSH 연결

Command Palette 또는 Remote Explorer에서 원격 서버에 연결할 수 있습니다.

여기서는 VS Code 환경에서 설명한 Remote Explorer를 사용합니다.

왼쪽 Activity Bar에서 Remote Explorer를 선택한 뒤 SSH 호스트 목록에서 project-dev-server를 찾습니다.

등록된 호스트 목록에서 project-dev-server를 선택합니다.

VS Code의 Remote Explorer SSH 호스트 목록에서 project-dev-server와 Connect in Current Window 버튼을 확인하는 화면

연결되면 VS Code 왼쪽 아래의 원격 연결 표시와 새로 열린 창을 확인합니다. 이때부터 VS Code의 터미널과 파일 탐색기는 Windows가 아니라 Linux 서버를 대상으로 동작합니다.

VS Code 왼쪽 아래 상태 표시줄에 SSH project-dev-server가 표시되어 Linux 서버 원격 연결이 완료된 화면

왼쪽 Activity Bar에서 Explorer를 선택한 뒤 Open Folder를 엽니다. /home/apple2ne1/ 폴더를 확인하고 OK 버튼을 선택합니다.

VS Code의 Open Folder 창에서 Linux 서버의 /home/apple2ne1/ 홈 폴더 경로와 OK 버튼을 확인하는 화면

3.2 터미널에서 자신의 위치 다시 확인

VS Code에서 새 터미널을 열고 다음 명령을 실행합니다.

whoami
hostname
pwd

예상 확인 항목은 다음과 같습니다.

  • whoami: 서버 작업에 사용할 Linux 사용자
  • hostname: project-dev-server 또는 실제로 설정한 호스트 이름
  • pwd: 현재 Linux 작업 경로
VS Code의 SSH 원격 터미널에서 whoami, hostname과 pwd 명령으로 사용자 apple2ne1, 서버 이름 project-dev-server 및 홈 폴더 경로를 확인한 결과

4. 프로젝트 루트 준비

Docker를 알아보기 위한 준비로 다음과 같이 실습용 프로젝트 폴더를 만듭니다.

mkdir -p /home/apple2ne1/projects/docker-test
cd /home/apple2ne1/projects/docker-test

현재 위치를 다시 확인합니다.

pwd
ls -la

pwd 결과가 다음과 같은 프로젝트 루트여야 합니다.

/home/apple2ne1/projects/docker-test
VS Code의 Linux 서버 터미널에서 docker-test 프로젝트 폴더를 만들고 이동한 뒤 pwd와 ls 명령으로 경로와 폴더 내용을 확인한 결과

4.1 VS Code 작업 폴더로 열기

Remote – SSH로 연결된 VS Code에서 다음 중 한 가지 방법을 사용합니다.

첫 번째 방법:

Remote Explorer의 SSH 목록에서 project-dev-server 오른쪽에 있는 Connect in Current Window 버튼을 선택합니다.

VS Code의 Remote Explorer에서 project-dev-server 오른쪽의 Connect in Current Window 버튼을 선택하는 화면

Explorer를 선택한 후 Open Folder를 선택합니다.

Open Folder에서 docker-test 폴더를 찾아 OK 버튼을 선택합니다.

VS Code의 Open Folder 창에 Linux 서버의 docker-test 프로젝트 폴더 경로를 입력하고 OK 버튼을 선택하는 화면

DOCKER-TEST [SSH: PROJECT-DEV-SERVER] 원격 작업 폴더가 표시됩니다.

VS Code Explorer에 DOCKER-TEST SSH PROJECT-DEV-SERVER 원격 작업 폴더가 열린 화면

다시 Remote Explorer를 선택하면 SSH 목록에 docker-test 작업 폴더가 표시됩니다. 이후 이 항목을 사용해 원격 작업 폴더를 바로 열 수 있습니다.

VS Code의 Remote Explorer에서 project-dev-server 아래에 docker-test 원격 작업 폴더 바로가기가 표시된 화면

두 번째 방법:

  • File → Open Folder...에서 프로젝트 폴더 선택
  • 서버 터미널에서 프로젝트 루트로 이동한 뒤 code . 실행
cd /home/apple2ne1/projects/docker-test
code .

새 VS Code 창이 열리면 Explorer의 최상위 폴더가 docker-test인지 확인합니다.

5. Nginx 컨테이너 실행

Nginx(엔진엑스)는 사용자에게 웹페이지를 전달하는 웹 서버 프로그램입니다.

이 문서의 기본 구성에서 사용자가 웹 브라우저로 다음 주소에 접속하면:

http://192.168.1.231:8080

Nginx가 요청을 받아 HTML, CSS, JavaScript, 이미지 등을 브라우저로 전달합니다.

웹 브라우저 → Nginx → 웹페이지 전달

Nginx의 주요 역할은 다음과 같습니다.

  • 웹페이지 제공
  • React 빌드 결과물 제공
  • 사용자 요청을 백엔드로 전달
  • HTTPS 인증서 처리
  • 여러 서버로 요청 분산
  • 외부에서 내부 서비스로 들어오는 입구 역할
웹 브라우저의 요청을 받은 Nginx가 웹페이지와 React 빌드 파일을 정적 응답으로 돌려주고 API 요청과 응답을 백엔드에 중계하는 흐름

예를 들어 /api 요청을 Node.js로 전달할 수 있습니다.

사용자 → Nginx
            ├─ /      → React 화면
            └─ /api   → Node.js 백엔드

이 가운데 Nginx가 /api 요청을 백엔드로 전달하고 응답을 다시 사용자에게 돌려주는 기능을 리버스 프록시라고 합니다. 정적 파일 제공, TLS 종료와 부하 분산은 Nginx가 수행할 수 있는 서로 다른 역할입니다.

이제 Docker에서 Nginx를 실행합니다.

먼저 IP 주소를 생략한 포트 게시 동작을 확인하기 위해 다음 명령을 실행합니다. 이 명령은 학습을 위한 첫 실행이며, 8절에서 Linux 서버의 내부 IP 주소에만 포트를 게시하는 기본 실습 구성으로 변경합니다.

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:alpine

sudo가 필요한 환경이라면 다음과 같이 실행합니다.

sudo docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 8080:80 \
  nginx:alpine

Nginx 공식 Docker 이미지는 컨테이너의 80번 포트를 호스트 포트에 연결하여 외부에서 접속하는 방법을 제공합니다.

명령 분석

docker run

로컬에 이미지가 없으면 저장소에서 이미지를 내려받은 뒤 새 컨테이너를 생성하고 실행합니다.

-d

컨테이너를 백그라운드에서 실행합니다.

--name nginx-web

컨테이너 이름을 nginx-web으로 지정합니다.

--restart unless-stopped

서버 재부팅이나 Docker 데몬 재시작 후 컨테이너를 다시 실행합니다. 단, 사용자가 직접 중지한 컨테이너는 사용자가 다시 시작하기 전까지 자동으로 실행되지 않습니다.

-p 8080:80

포트를 연결합니다.

Linux 서버 포트 : 컨테이너 포트
8080             : 80

Nginx는 격리된 컨테이너 환경에서 실행되며 컨테이너 내부의 80번 포트를 사용합니다. -p 8080:80은 Linux 서버의 8080번 포트로 들어온 요청을 Nginx 컨테이너의 80번 포트로 전달한다는 의미입니다.

즉 다음과 같은 흐름입니다.

Windows 관리 PC의 웹 브라우저 (192.168.1.231:8080) → 서버 8080번 포트 → Nginx 컨테이너 80번 포트
Windows 관리 PC의 웹 브라우저 요청이 Linux 서버의 8080번 포트를 거쳐 Nginx 컨테이너의 80번 포트로 전달되는 과정
nginx:alpine

Nginx의 Alpine Linux 기반 이미지가 서버에 없으면 자동으로 내려받아 컨테이너를 실행합니다. 사용자가 Nginx 설치 파일을 직접 찾아 내려받고 설치하는 과정을 거칠 필요가 없습니다. 같은 이미지를 다른 서버에서 실행하면 동일한 구성의 컨테이너 환경을 만들 수 있다는 것이 Docker의 장점입니다.

Docker 컨테이너를 실행할 때 포트를 공개하면, Ubuntu의 UFW에서 해당 포트를 차단했더라도 외부 PC가 컨테이너에 접속할 수 있는 경우가 있다는 의미입니다.

예를 들어 다음과 같이 Nginx를 실행했다고 가정하겠습니다.

docker run -d --name nginx-web -p 8080:80 nginx:alpine

의미는 다음과 같습니다.

서버의 8080번 포트 → 컨테이너의 80번 포트

Docker는 이 포트 연결을 위해 Linux의 방화벽 규칙을 직접 추가합니다. 이 규칙은 일반적인 UFW 처리보다 먼저 적용될 수 있습니다. 따라서 UFW에서 다음처럼 표시되더라도,

sudo ufw status
8080 포트 허용 규칙 없음

다른 컴퓨터가 다음 주소로 접속할 가능성이 있습니다.

http://서버-IP:8080

포트를 게시할 호스트 IP 주소

docker run -p에서 호스트 IP 주소를 어떻게 지정하는지에 따라 Docker가 요청을 받을 네트워크 인터페이스가 달라집니다.

모든 네트워크 인터페이스에 게시:

-p 8080:80

이는 기본적으로 다음 설정과 같습니다.

-p 0.0.0.0:8080:80

Linux 서버의 특정 내부 IP 주소에 게시:

-p 192.168.1.231:8080:80

Linux 서버 자체에서만 접속할 수 있도록 루프백 주소에 게시:

-p 127.0.0.1:8080:80

이 설정들은 포트를 게시할 호스트 주소를 선택합니다. 192.168.1.0/24와 같은 출발지 네트워크의 접속만 허용하려면 별도의 방화벽 정책이 필요합니다. —

6. Nginx 컨테이너 상태 확인

이미지로 생성한 컨테이너의 실행 상태를 확인합니다. 컨테이너를 중지해도 삭제하기 전까지는 남아 있습니다.

docker ps

정상 예시:

CONTAINER ID   IMAGE          COMMAND                  STATUS         PORTS
a123456789ab   nginx:alpine   "/docker-entrypoint…"   Up 41 minute    0.0.0.0:8080->80/tcp
VS Code의 Linux 서버 터미널에서 docker ps 명령으로 nginx-web 컨테이너가 실행 중이며 호스트의 8080번 포트가 컨테이너의 80번 포트에 게시된 것을 확인한 결과

중요한 부분은 다음입니다.

Up 41 minute

컨테이너가 실행된 지 약 41분이 되었다는 의미입니다.

0.0.0.0:8080->80/tcp

Linux 서버의 모든 네트워크 인터페이스에서 8080번 포트를 받고, 이를 컨테이너의 80번 포트로 전달한다는 의미입니다.

예를 들어 서버에는 다음과 같은 인터페이스가 있을 수 있습니다.

lo       → 서버 자기 자신용
eno1     → 유선 LAN
wlan0    → Wi-Fi
tailscale0 → Tailscale 연결

여기서 0.0.0.0서버의 특정 IP 하나만이 아니라, 서버가 가진 모든 IPv4 인터페이스에서 8080번 포트를 받겠다는 뜻입니다.

따라서 조건이 맞으면 다음 주소들로 접근할 수 있습니다.

http://127.0.0.1:8080
http://192.168.1.231:8080
http://Tailscale-IP:8080

다만 실제 접속 가능 여부는 방화벽, 라우터, 네트워크 설정에도 영향을 받습니다.

특정 인터페이스에서만 요청을 받으려면 호스트 IP 주소를 직접 지정할 수 있습니다. 다음은 실행 명령이 아니라 포트 게시 문법을 보여 주는 예시입니다.

docker run -d --name nginx-web -p 192.168.1.231:8080:80 nginx:alpine

이 경우에는 192.168.1.231 인터페이스를 통해 들어오는 요청만 받습니다. 이미 다른 컨테이너가 8080번 포트를 사용하고 있다면 이 명령을 그대로 실행할 수 없습니다.

컨테이너가 docker ps의 실행 중인 컨테이너 목록에 나타나지 않으면 중지되었을 수 있습니다. 중지된 컨테이너를 포함한 전체 목록은 다음 명령으로 확인합니다.

docker ps -a
VS Code의 Linux 서버 터미널에서 docker ps -a 명령으로 실행 중인 nginx-web 컨테이너와 종료된 hello-world 컨테이너를 함께 확인한 결과

7. Linux 서버 내부에서 Nginx 접속 확인

먼저 서버 자체에서 Nginx가 정상적으로 응답하는지 확인합니다.

curl http://localhost:8080

정상이라면 HTML 내용이 출력됩니다.

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
VS Code로 연결한 Linux 서버 터미널에서 curl 명령을 실행하여 localhost의 Nginx HTML 응답을 확인한 결과

간단하게 HTTP 상태만 확인하려면 다음 명령을 사용할 수 있습니다.

curl -I http://localhost:8080

정상 예시:

HTTP/1.1 200 OK
Server: nginx
Content-Type: text/html
VS Code로 연결한 Linux 서버 터미널에서 curl -I 명령으로 localhost의 Nginx HTTP 200 응답 헤더를 확인한 결과

200 OK는 Nginx가 정상적으로 웹페이지를 반환하고 있다는 의미입니다.

8. 포트 공개 범위와 방화벽 확인

Ubuntu에서는 일반적으로 UFW를 사용합니다. UFW는 Ubuntu에서 사용하는 간단한 방화벽 관리 도구이며 기본적으로 비활성 상태일 수 있습니다.

현재 상태를 확인합니다.

sudo ufw status

UFW가 비활성 상태인 경우

Status: inactive

UFW 자체에서 서버의 8080번 포트를 차단하고 있지는 않습니다.

UFW가 활성 상태인 경우

Status: active

Docker는 게시된 컨테이너 포트에 자체 방화벽 규칙을 추가합니다. IP 주소를 생략한 -p 8080:80은 기본적으로 모든 호스트 인터페이스에 포트를 게시하며, UFW에서 해당 포트를 차단했더라도 외부에서 접근할 수 있습니다.

따라서 Docker 게시 포트의 접근 범위를 UFW 규칙만으로 제한해서는 안 됩니다. 이 문서에서는 모든 인터페이스에 게시하지 않도록 다음과 같이 Linux 서버의 내부 IP 주소에 포트를 바인딩합니다.

먼저 예시에 사용할 내부 IP 주소가 Linux 서버에 실제로 설정되어 있는지 확인합니다.

ip -br addr

이 문서에서는 192.168.1.231을 예시로 사용합니다. 출력에서 확인한 실제 내부 IP 주소가 다르면 이후 명령과 접속 주소를 해당 값으로 바꿉니다.

단, 기존 nginx-web 컨테이너가 이미 8080번 포트를 사용 중이라면 먼저 해당 컨테이너를 중지하고 삭제한 뒤 다시 생성해야 합니다.

먼저 8080번 포트로 실행 중인 nginx-web 컨테이너를 중지하고 삭제합니다. 관련 관리 명령은 13절에서도 정리합니다.

docker rm -f nginx-web

Linux 서버의 192.168.1.231:8080으로 들어온 요청만 Nginx 컨테이너의 80번 포트로 전달하도록 다시 실행합니다.

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 192.168.1.231:8080:80 \
  nginx:alpine
VS Code로 연결한 Linux 서버 터미널에서 기존 Nginx 컨테이너를 삭제하고 서버의 내부 IP 주소 192.168.1.231과 8080번 포트에 다시 바인딩한 결과

위 화면에서 호스트 IP 주소가 포함된 포트 게시 결과를 확인할 수 있습니다.

9. Windows 관리 PC의 웹 브라우저에서 접속

Windows 관리 PC에서 Chrome, Edge 또는 Firefox를 엽니다.

주소창에 다음 주소를 입력합니다.

http://192.168.1.231:8080

여기서:

http://

HTTP 방식으로 연결한다는 의미입니다.

192.168.1.231

Linux 서버의 IP 주소입니다.

:8080

Nginx 컨테이너를 공개한 Linux 서버의 포트입니다.

정상적으로 접속되면 다음 제목의 기본 화면이 나타납니다.

Welcome to nginx!
Windows 관리 PC의 웹 브라우저에서 Linux 서버의 192.168.1.231 주소와 8080번 포트로 접속하여 Nginx 기본 페이지를 확인한 화면

이 화면이 나타나면 전체 연결이 성공한 것입니다.

Windows 관리 PC의 웹 브라우저
→ Linux 서버 IP
→ 서버의 8080번 포트
→ Docker 포트 게시
→ Nginx 컨테이너 80번 포트
→ Nginx 기본 웹페이지

10. Windows 관리 PC에서 서버 주소로 localhost를 사용할 수 없는 이유

Windows 관리 PC의 웹 브라우저에서 다음 주소를 입력하면 안 됩니다.

http://localhost:8080

또는:

http://127.0.0.1:8080

Windows 관리 PC의 웹 브라우저에서 localhostLinux 서버가 아니라 현재 사용 중인 Windows 관리 PC 자신을 의미합니다.

따라서 Windows에서 Linux 서버의 Nginx에 접속하려면 반드시 Linux 서버의 IP를 사용해야 합니다.

http://192.168.1.231:8080

정리하면 다음과 같습니다.

주소를 입력하는 위치 localhost가 가리키는 컴퓨터
Linux 서버 터미널 Linux 서버
Windows 관리 PC의 웹 브라우저 Windows 관리 PC
Nginx 컨테이너 내부 Nginx 컨테이너 자신

11. 선택 사항: 8080 없이 서버 IP만으로 접속하기

웹 브라우저에서 다음과 같이 포트 번호 없이 접속하고 싶을 수 있습니다.

http://192.168.1.231

HTTP의 기본 포트는 80입니다.

80번 포트를 사용하려면 먼저 기존 컨테이너를 중지하고 삭제합니다.

docker stop nginx-web
docker rm nginx-web

중지와 삭제를 한 번에 처리하려면 다음 명령을 대신 사용할 수 있습니다.

docker rm -f nginx-web

그다음 Linux 서버 내부 IP 주소의 80번 포트를 컨테이너의 80번 포트에 게시합니다.

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 192.168.1.231:80:80 \
  nginx:alpine
VS Code로 연결한 Linux 서버 터미널에서 Nginx 컨테이너를 호스트의 80번 포트와 컨테이너의 80번 포트에 연결하고 실행 상태를 확인한 결과

이제 Windows 관리 PC의 웹 브라우저에서 다음 주소로 접속합니다.

http://192.168.1.231
Windows 관리 PC의 웹 브라우저에서 포트 번호 없이 Linux 서버의 192.168.1.231 주소로 접속하여 Nginx 기본 페이지를 확인한 화면

11.1 정적 Nginx 환경과 Vite 개발 환경의 포트

이 문서의 정적 Nginx 환경에서는 Nginx 컨테이너가 웹 문서 폴더의 정적 파일을 직접 제공합니다. 02-vibe-coding-login-admin-dashboard-ui-ko에서 다룰 Vite 개발 환경은 별도의 구조입니다. 웹 브라우저 요청은 먼저 외부 포트를 게시한 Nginx 컨테이너로 들어오고, Nginx는 Docker 네트워크에서 proxy_pass http://vite:5173과 같은 설정을 사용해 Vite 컨테이너의 개발 서버로 전달할 수 있습니다.

따라서 이 구조에서 5173은 웹 브라우저가 직접 연결하는 포트가 아니라 Nginx가 Docker 네트워크를 통해 접근하는 Vite 컨테이너의 내부 포트입니다. 현재 문서에서는 Vite 컨테이너나 리버스 프록시를 구성하지 않습니다.

개발 환경에서는 웹 브라우저 요청이 Linux 호스트와 Nginx 컨테이너를 거쳐 Vite 컨테이너의 5173번 포트로 전달되고 정적 Nginx 환경에서는 호스트 포트가 Nginx 컨테이너의 80번 포트로 연결되는 비교
Docker 설정 웹 브라우저 접속 주소
-p 192.168.1.231:8080:80 http://192.168.1.231:8080
-p 192.168.1.231:80:80 http://192.168.1.231

처음 테스트할 때는 호스트의 8080번 포트를 사용하는 것이 편리합니다. 서버의 80번 포트를 다른 웹 서버가 이미 사용하고 있을 가능성을 줄일 수 있기 때문입니다.

11.2 기본 실습 구성으로 복구

12절부터 계속 진행하려면 nginx-web 컨테이너를 다시 생성해 기본 실습 구성으로 복구합니다.

docker rm -f nginx-web

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 192.168.1.231:8080:80 \
  nginx:alpine

12. Nginx 로그 확인

현재 실행 중인 nginx-web 컨테이너의 웹 브라우저 접속 기록과 오류를 확인합니다.

VS Code의 SSH 원격 터미널에서 docker ps 명령으로 nginx-web 컨테이너의 실행 상태와 호스트 8080번 포트에서 컨테이너 80번 포트로 게시된 구성을 확인한 결과
docker logs nginx-web

실시간으로 로그를 보려면 다음 명령을 사용합니다.

docker logs -f nginx-web
VS Code의 SSH 원격 터미널에서 docker logs -f nginx-web 명령으로 Nginx 시작 로그와 Windows 관리 PC의 GET 요청 및 favicon 파일 오류를 실시간으로 확인한 결과

이 상태에서 Windows 관리 PC의 웹 브라우저를 Ctrl+F5로 새로 고치면 다음과 비슷한 접속 기록이 나타납니다.

192.168.1.240 - - [23/Jul/2026:...] "GET / HTTP/1.1" 200

여기서:

  • 192.168.1.240: 접속한 Windows 관리 PC의 IP 주소
  • GET /: 기본 페이지 요청
  • 200: 정상 응답

실시간 로그 화면에서 빠져나오려면 다음을 누릅니다.

Ctrl + C

이 명령은 로그 보기만 종료하며 컨테이너는 계속 실행됩니다.

13. Nginx 컨테이너 관리 명령

실행 중인 컨테이너 확인

docker ps

모든 컨테이너 확인

docker ps -a

컨테이너 중지

실행 중인 nginx-web 컨테이너를 중지합니다. 중지된 컨테이너는 삭제하기 전까지 남아 있습니다.

docker stop nginx-web

컨테이너 다시 시작

중지된 nginx-web 컨테이너를 같은 구성으로 다시 시작합니다.

docker start nginx-web

컨테이너 재시작

실행 중인 nginx-web 컨테이너의 프로세스를 중지한 뒤 같은 구성으로 다시 시작합니다.

docker restart nginx-web

컨테이너 삭제

Docker 컨테이너를 삭제하는 기본 명령은 다음과 같습니다.

docker rm nginx-web

실행 중인 nginx-web 컨테이너는 먼저 중지한 뒤 삭제합니다.

docker stop nginx-web
docker rm nginx-web
VS Code의 SSH 원격 터미널에서 nginx-web 컨테이너를 중지한 뒤 삭제하고 docker ps -a 명령으로 컨테이너가 남아 있지 않은지 확인한 결과

중지와 삭제를 한 번에 강제로 처리하려면 다음 명령을 사용합니다.

docker rm -f nginx-web
VS Code의 SSH 원격 터미널에서 docker rm -f nginx-web 명령으로 실행 중인 Nginx 컨테이너를 강제로 중지하고 삭제한 뒤 docker ps -a 명령으로 확인한 결과

docker ps 또는 docker ps -a에서 확인한 컨테이너 ID로도 삭제할 수 있습니다.

docker rm a1b2c3d4e5f6

호스트의 중지된 컨테이너를 모두 삭제하려면 다음 명령을 사용합니다.

docker container prune

다음 확인 메시지가 나타납니다.

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N]
VS Code의 SSH 원격 터미널에서 중지된 Nginx 컨테이너 목록을 확인하고 docker container prune 명령의 삭제 경고에 y를 입력하는 화면

삭제를 진행하려면 y를 입력합니다.

VS Code의 SSH 원격 터미널에서 docker container prune 명령으로 중지된 컨테이너를 삭제하고 회수된 공간과 비어 있는 docker ps -a 결과를 확인한 화면

컨테이너 프로세스가 정상적으로 종료되지 않아 즉시 중지해야 할 때는 다음 명령을 사용합니다.

docker kill nginx-web

일반적으로는 프로그램이 안전하게 종료될 시간을 주는 docker stop을 사용하고, 정상적으로 멈추지 않을 때만 docker kill을 사용합니다.

따라서 나중에 같은 이미지로 컨테이너를 다시 만들 수 있습니다.

내려받은 이미지 확인

docker run은 로컬에 지정한 이미지가 없으면 저장소에서 이미지를 내려받고 그 이미지로 컨테이너를 생성합니다. 내려받은 이미지는 다음 명령으로 확인합니다.

docker images
VS Code의 SSH 원격 터미널에서 docker images 명령으로 hello-world와 nginx:alpine 이미지의 ID, 디스크 사용량과 콘텐츠 크기를 확인한 결과

Docker Compose로 만든 컨테이너는 compose.yaml 파일이 있는 폴더에서 다음 명령으로 해당 Compose 프로젝트를 정리할 수 있습니다. 현재 문서의 nginx-web 컨테이너는 docker run으로 생성했으므로 이 명령의 대상이 아닙니다.

docker compose down

명령의 차이는 다음과 같습니다.

명령 기능
docker rm nginx-web 중지된 nginx-web 컨테이너 삭제
docker rm -f nginx-web 실행 중인 nginx-web 컨테이너를 강제로 중지하고 삭제
docker container prune 호스트의 중지된 모든 컨테이너 삭제
docker compose down 현재 Compose 프로젝트의 컨테이너와 기본 네트워크 삭제

14. 사용자 웹페이지 표시하기

Nginx 기본 화면 대신 직접 만든 HTML 페이지를 표시할 수 있습니다.

14.1 프로젝트 폴더 생성

4절의 docker-test는 Docker 명령을 연습하기 위한 작업 폴더입니다. 사용자 웹페이지 파일은 역할을 구분하기 위해 별도의 nginx-web 프로젝트 폴더에서 관리합니다.

mkdir -p /home/apple2ne1/projects/nginx-web

프로젝트 폴더로 이동합니다.

cd /home/apple2ne1/projects/nginx-web
pwd
ls -la

pwd 결과는 다음과 같아야 합니다.

/home/apple2ne1/projects/nginx-web
VS Code의 SSH 원격 터미널에서 nginx-web 프로젝트 폴더를 만들고 이동한 뒤 pwd와 ls 명령으로 경로와 폴더 내용을 확인한 결과

웹 문서를 저장할 html 폴더를 만듭니다.

mkdir -p html
VS Code의 SSH 원격 터미널에서 nginx-web 프로젝트 안에 html 폴더를 만들고 ls 명령으로 생성 결과를 확인한 화면

14.2 VS Code에서 폴더 열기

VS Code에서 File → Open Folder…를 선택하고 다음 폴더를 엽니다.

/home/apple2ne1/projects/nginx-web

OK 버튼을 선택한 뒤 Explorer의 최상위 작업 폴더가 nginx-web인지 확인합니다.

nginx-web 폴더 안에 html 폴더만 있으면 ExplorerCompact Folders 기능에 따라 nginx-web/html이 한 줄로 표시될 수 있습니다.

VS Code Explorer에서 projects 아래의 nginx-web 폴더와 유일한 하위 html 폴더가 Compact Folders 기능으로 nginx-web/html 한 줄에 표시된 화면

14.3 HTML 파일 만들기

VS Code의 Explorer에서 nginx-web/html 왼쪽의 꺾쇠를 선택하여 아래쪽을 향하게 하고 html 폴더를 펼칩니다.

VS Code Explorer에서 nginx-web 아래의 html 폴더를 선택하고 프로젝트 경로가 ~/projects/nginx-web/html인지 확인한 화면

html 폴더를 마우스 오른쪽 버튼으로 선택한 뒤 New File을 선택합니다.

VS Code Explorer에서 nginx-web/html 폴더의 바로 가기 메뉴를 열고 New File 항목을 선택하는 화면

파일명 입력란이 나타나면 index.html을 입력합니다.

VS Code Explorer의 nginx-web/html 폴더 아래에 새 파일명을 입력할 수 있는 입력란이 열린 화면
index.html

생성된 index.html 파일을 선택하면 오른쪽 편집기에 파일 내용이 표시됩니다. 편집기에 다음 내용을 복사해 작성하고 Ctrl+S로 저장합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Docker Nginx Server</title>
</head>
<body>
    <h1>Docker Nginx 서버 연결 성공</h1>
    <p>Windows 관리 PC의 VS Code에서 Linux 서버의 파일을 수정하고 있습니다.</p>
    <p>This page is running inside an Nginx container.</p>
</body>
</html>
VS Code에서 nginx-web/html/index.html 파일을 열고 Docker Nginx 연결 확인용 HTML 코드를 작성한 화면

저장합니다.

Ctrl + S

15. HTML 폴더를 Nginx 컨테이너에 연결

기존 컨테이너가 있다면 삭제합니다.

docker rm -f nginx-web

현재 위치를 확인합니다.

pwd

결과 예시:

/home/apple2ne1/projects/nginx-web

다음 명령으로 Nginx 컨테이너를 다시 실행합니다.

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 192.168.1.231:8080:80 \
  -v "$(pwd)/html:/usr/share/nginx/html:ro" \
  nginx:alpine
VS Code로 연결한 Linux 서버 터미널에서 html 폴더를 읽기 전용으로 바인드 마운트하고 nginx-web 컨테이너를 실행한 결과

핵심 부분은 다음입니다.

-v "$(pwd)/html:/usr/share/nginx/html:ro"

의미:

Linux 서버의 폴더
/home/apple2ne1/projects/nginx-web/html

        ↓ 연결

Nginx 컨테이너의 웹 문서 폴더
/usr/share/nginx/html
Linux 서버의 HTML 폴더를 Nginx 컨테이너의 웹 문서 폴더에 읽기 전용 바인드 마운트로 연결한 구조

마지막의 :ro는 컨테이너에서 해당 폴더를 읽기 전용으로 사용한다는 의미입니다.

Windows 관리 PC의 웹 브라우저에서 다시 접속합니다.

http://192.168.1.231:8080

이제 Nginx 기본 화면 대신 다음 문장이 표시되어야 합니다.

Docker Nginx 서버 연결 성공
Windows 관리 PC의 웹 브라우저에서 nginx-web 컨테이너가 제공하는 사용자 작성 index.html 화면을 확인한 결과

HTML 파일을 VS Code에서 수정하고 저장한 뒤 웹 브라우저에서 Ctrl+F5로 새로 고치면 변경 내용이 반영됩니다.

15.1 최종 환경 확인

실행 중인 컨테이너와 포트 게시 상태를 확인합니다.

docker ps --filter 'name=^/nginx-web$'

PORTS 항목에는 다음과 같이 Linux 서버의 내부 IP 주소와 호스트 포트가 표시되어야 합니다.

192.168.1.231:8080->80/tcp

Linux 서버에서 사용자 웹페이지의 응답을 확인합니다.

curl -I http://192.168.1.231:8080
VS Code로 연결한 Linux 서버 터미널에서 nginx-web 컨테이너의 포트 매핑과 사용자 웹페이지의 HTTP 200 응답 헤더를 확인한 결과

사용자 HTML의 제목까지 확인하려면 다음 명령을 실행합니다.

curl -s http://192.168.1.231:8080 | grep -F 'Docker Nginx 서버 연결 성공'

재시작 정책과 바인드 마운트 구성을 확인합니다.

docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' nginx-web
docker inspect --format '{{range .Mounts}}{{.Source}} -> {{.Destination}} (RW={{.RW}}){{end}}' nginx-web

첫 번째 명령은 unless-stopped를 출력해야 합니다. 두 번째 명령은 호스트의 nginx-web/html 폴더가 /usr/share/nginx/html에 연결되어 있고 RW=false인 것을 보여야 합니다.

VS Code로 연결한 Linux 서버 터미널에서 nginx-web 컨테이너의 재시작 정책과 읽기 전용 바인드 마운트 구성을 확인한 결과

다음 항목이 모두 충족되면 이 문서의 기본 환경이 완성된 것입니다.

  • 컨테이너 이름이 nginx-web입니다.
  • 이미지가 nginx:alpine입니다.
  • 재시작 정책이 unless-stopped입니다.
  • Linux 서버의 192.168.1.231:8080이 컨테이너의 80번 포트에 게시되어 있습니다.
  • /home/apple2ne1/projects/nginx-web/html/usr/share/nginx/html에 읽기 전용 바인드 마운트되어 있습니다.
  • Linux 서버와 Windows 관리 PC의 웹 브라우저에서 사용자 HTML 페이지가 표시됩니다.

16. 자주 발생하는 오류

Docker 데몬 소켓 권한 오류는 Docker Engine 설치에서 설명합니다.

오류 1: 컨테이너 이름이 이미 사용 중

예시:

Conflict. The container name "/nginx-web" is already in use

기존 컨테이너 확인:

docker ps -a

기존 컨테이너 삭제:

docker rm -f nginx-web

그다음 다시 실행합니다.

오류 2: 포트가 이미 사용 중

예시:

Bind for 0.0.0.0:8080 failed: port is already allocated

8080번 포트를 사용하는 프로그램을 확인합니다.

sudo ss -lntp | grep :8080

다른 포트를 사용하려면 다음처럼 실행합니다.

docker rm -f nginx-web

cd /home/apple2ne1/projects/nginx-web

docker run -d \
  --name nginx-web \
  --restart unless-stopped \
  -p 192.168.1.231:8081:80 \
  -v "$(pwd)/html:/usr/share/nginx/html:ro" \
  nginx:alpine

웹 브라우저 주소도 바뀝니다.

http://192.168.1.231:8081

오류 3: 웹 브라우저에 Connection refused 표시

확인:

docker ps
curl -I http://192.168.1.231:8080
sudo ss -lntp | grep 8080

컨테이너가 중지되었다면:

docker start nginx-web

오류 4: Windows 관리 PC에서는 안 되지만 서버 내부에서는 접속됨

서버에서 다음 명령은 정상인데:

curl http://192.168.1.231:8080

Windows 관리 PC의 웹 브라우저에서는 접속되지 않는다면 다음 가능성이 큽니다.

  • UFW 또는 다른 방화벽 문제
  • 잘못된 서버 IP 사용
  • Windows 관리 PC와 Linux 서버가 서로 다른 네트워크에 연결
  • 공유기의 AP Isolation 또는 Client Isolation 기능
  • 게스트 Wi-Fi 사용
  • 컨테이너 포트를 127.0.0.1에만 연결한 경우

다음처럼 실행했다면 외부 컴퓨터에서 접속되지 않습니다.

-p 127.0.0.1:8080:80

같은 네트워크의 Windows 관리 PC에서 접속하려면 Linux 서버의 실제 내부 IP 주소를 지정합니다.

-p 192.168.1.231:8080:80

참고 자료 및 출처

  • docker container run
  • 컨테이너 실행, 포트 게시, 이미지 가져오기 정책과 바인드 마운트 동작을 확인했습니다.
  • 확인 날짜: 2026-08-09
  • Packet filtering and firewalls
  • Docker 게시 포트와 UFW를 포함한 호스트 방화벽의 관계를 확인했습니다.
  • 확인 날짜: 2026-08-09
  • Start containers automatically
  • unless-stopped 재시작 정책의 동작을 확인했습니다.
  • 확인 날짜: 2026-08-09
  • nginx Official Image
  • Nginx 공식 이미지의 Alpine 변형과 웹 문서 폴더 바인드 마운트 예시를 확인했습니다.
  • 확인 날짜: 2026-08-09

다음 글

Docker Nginx Compose

다음 글에서 다룰 내용:

  • docker run으로 만든 기존 nginx-web 컨테이너를 정리하고 Compose 프로젝트 폴더와 파일을 확인합니다.
  • nginx-compose.yaml에 Nginx 서비스, 이미지, 재시작 정책, 8080:80 포트 게시와 읽기 전용 바인드 마운트를 선언합니다.
  • docker compose config로 YAML 구문과 Compose가 해석한 최종 구성을 검증합니다.
  • docker compose up -d, pslogs를 사용해 Nginx 서비스를 실행하고 상태와 로그를 확인합니다.
  • stop, startdown 명령으로 Compose 서비스와 프로젝트 리소스를 관리합니다.
  • Linux 서버의 curl과 Windows 관리 PC의 웹 브라우저를 사용해 사용자 웹페이지가 정상적으로 표시되는지 확인합니다.
  • 접속되지 않을 때 서버 IP, Compose 구성, 포트 게시, Nginx 로그, 방화벽과 Windows의 포트 연결을 순서대로 점검합니다.

관련 문서


Previous article
Next article