Docker와 함께 VPS에 Django 배포: 단계별 가이드
Source: Dev.to
이 가이드는 누구를 위한 것인가?
- 셀프‑호스팅에 호기심이 있고 기본을 배우고 싶다면.
- 비싼 관리형 서비스를 사용하지 않고 작은 프로젝트나 사이드 프로젝트를 실행하고 싶다면.
- 호스팅 비용을 절감하고 싶다면.
이 가이드를 건너뛰어야 하는 사람은?
- 시작하기 위한 절대적으로 가장 빠른 방법(예: 관리형 PaaS)이 필요합니다.
- 지속적인 유지보수를 피하고 싶습니다.
- 핵심 업무 워크로드를 실행해야 하며 서버 관리에 익숙하지 않습니다.
시작하기 위한 간단하고 관리형 방법을 찾고 계신가요? 저희 제품을 확인해 보세요: sliplane.io.
사전 요구 사항
| 요구 사항 | 세부 사항 |
|---|---|
| Django 애플리케이션 | 컨테이너화 준비 완료 |
| VPS 계정 | Hetzner (또는 다른 선호하는 제공업체) |
| 도메인 이름 | SSL 종료 및 리버스 프록시용 |
| Docker 지식 | 기본적인 이해 (선택 사항이지만 도움이 됨) |
우리는 Docker를 사용하여 Django 앱을 컨테이너화하고 데이터베이스로 PostgreSQL을 사용할 것입니다. 배포는 Docker Compose와 자동 SSL을 위한 리버스 프록시인 Caddy를 사용하여 수행됩니다.
왜 Docker인가?
Docker를 사용하면 Django 앱에 필요한 모든 것을 Dockerfile에 정의할 수 있습니다. 그런 다음 모든 종속성이 설치된 격리된 컨테이너를 실행하여 “내 컴퓨터에서는 동작한다”는 문제를 피할 수 있습니다.
- 일관된 환경 – 동일한 Python 버전, 동일한 시스템 라이브러리.
- 분리된 서비스 – Django와 PostgreSQL을 서로 다른 컨테이너에서 실행하여 종속성 충돌을 방지.
- 방대한 생태계 – 데이터베이스, 캐시, 웹 서버 등을 위한 사전 구축 이미지 제공.
더 자세히 알고 싶다면 **[Django in Docker tutorial]**을 참고하세요.
TL;DR – 최소 Docker 설정
Django 프로젝트 루트에 두 개의 파일을 생성합니다:
Dockerfile
# ---------- Stage 1: Builder ----------
FROM python:3.13-slim AS builder
# Create and set the app directory
RUN mkdir /app
WORKDIR /app
# Optimize Python
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Upgrade pip
RUN pip install --upgrade pip
# Cache dependencies
COPY requirements.txt /app/
RUN pip install --no-cache-dir -r requirements.txt
# ---------- Stage 2: Production ----------
FROM python:3.13-slim
# Create a non‑root user and app directory
RUN useradd -m -r appuser && \
mkdir /app && \
chown -R appuser /app
# Copy Python packages from builder
COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/
COPY --from=builder /usr/local/bin/ /usr/local/bin/
WORKDIR /app
# Copy application code (preserve ownership)
COPY --chown=appuser:appuser . .
# Optimize Python (again, for the final image)
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
# Switch to non‑root user
USER appuser
# Expose the port Django will run on
EXPOSE 8000
# Start the app with Gunicorn
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "myproject.wsgi:application"]
docker-compose.yml
services:
web:
build: .
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
volumes:
postgres_data:
로컬 테스트
- Docker 설치 (아직 설치하지 않았다면).
- 실행:
docker compose up
Django 앱은 http://localhost:8000에서 접근할 수 있습니다.
프로덕션으로 이동하기 전에 로컬에서 모든 것이 정상적으로 작동하는지 확인하세요.
Source: …
프로덕션‑준비 이미지 워크플로우
위의 compose 파일은 개발에는 좋지만, 서버가 매 배포 시마다 이미지를 다시 빌드하기 때문에 프로덕션에는 적합하지 않습니다. 프로덕션에서는 다음과 같이 해야 합니다:
-
이미지를 로컬(또는 CI)에서 빌드합니다.
docker build -t my-django-app . -
컨테이너 레지스트리에 푸시합니다 (예: GitHub Container Registry, GHCR).
# 인증 echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_GITHUB_USERNAME --password-stdin # 태그 지정 및 푸시 docker tag my-django-app ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest docker push ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latestlatest태그는 튜토리얼에서는 괜찮지만, 실제 프로젝트에서는 의미 있는 버전 관리(예: 시맨틱 버전 또는 커밋 해시)를 고려하세요. -
CI/CD 파이프라인(예: GitHub Actions)으로 이 단계를 자동화합니다. 이 주제에 대해서는 별도의 포스트가 있습니다.
VPS 설정하기
1️⃣ VPS 제공업체 선택
우리는 별도의 글에서 여러 저렴한 제공업체를 비교했습니다. Hetzner는 가격, 안정성, 성능 면에서 돋보이며, 제휴 링크를 사용하면 €20 크레딧을 받을 수 있습니다.
2️⃣ VPS 사양 결정
가장 작은 플랜(예: 1 vCPU, 2 GB RAM)부터 시작하세요. 트래픽이 늘어나면 언제든지 확장할 수 있습니다.
3️⃣ 서버 준비
-
새 서버 생성 (Ubuntu 22.04 LTS 권장).
-
시스템 업데이트
sudo apt update && sudo apt upgrade -y -
Docker & Docker Compose 설치
# Install Docker curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh # Enable Docker to start on boot sudo systemctl enable docker # Install Docker Compose (v2 plugin) sudo apt install -y docker-compose-plugin -
비루트 사용자 생성 (선택 사항이지만 권장)
sudo adduser deployer sudo usermod -aG docker deployer -
방화벽 설정 (UFW)
sudo ufw allow OpenSSH sudo ufw allow 80/tcp # HTTP sudo ufw allow 443/tcp # HTTPS sudo ufw enable
4️⃣ 애플리케이션 배포
-
서버에 로그인하고 저장소를 클론하거나 이미지를 직접 가져옵니다.
git clone https://github.com/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME.git cd YOUR_REPO_NAME -
.env파일을 만들어 Django와 PostgreSQL 설정(DJANGO_SECRET_KEY,POSTGRES_PASSWORD등)을 입력합니다. -
**
docker-compose.prod.yml**을 생성하여 로컬에서 빌드하지 않고 미리 빌드된 이미지를 사용하도록 합니다:version: "3.9" services: web: image: ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest env_file: - .env depends_on: - db restart: unless-stopped db: image: postgres:17 volumes: - postgres_data:/var/lib/postgresql/data env_file: - .env restart: unless-stopped volumes: postgres_data: -
스택 실행
docker compose -f docker-compose.prod.yml up -d -
Caddy를 리버스 프록시로 설정 (HTTPS 자동 처리).
Caddyfile을 생성합니다:yourdomain.com { reverse_proxy web:8000 }그런 다음 compose 파일에 Caddy 서비스를 추가합니다:
services: caddy: image: caddy:2 ports: - "80:80" - "443:443" volumes: - ./Caddyfile:/etc/caddy/Caddyfile - caddy_data:/data restart: unless-stopped volumes: caddy_data:다시 배포합니다:
docker compose -f docker-compose.prod.yml up -dCaddy는 Let’s Encrypt에서 TLS 인증서를 자동으로 발급 및 갱신합니다.
Recap Checklist
- Dockerize Django app (
Dockerfile,docker-compose.yml). - Build and push image to a container registry (GHCR).
- Choose and provision a VPS (Hetzner recommended).
- Install Docker & Docker Compose on the server.
- Create production‑ready
docker-compose.prod.yml. - Set up environment variables (
.env). - Deploy stack with
docker compose up -d. - Add Caddy reverse proxy for HTTPS.
You now have a fully self‑hosted Django application running on a cheap VPS, with automated SSL and a clean, reproducible deployment pipeline. 🎉
Happy self‑hosting!
작은 Django + Postgres VPS를 위한 빠른 시작 체크리스트
기본 VPS만으로도 얼마나 멀리 갈 수 있는지 놀라실 겁니다 – PostgreSQL 데이터베이스와 작은 Django 앱을 단 1 GB RAM으로도 실행할 수 있습니다. 나중에 언제든지 크기를 조정할 수 있습니다. 간단히 시작하세요: 데이터베이스와 Django 앱을 같은 서버에 실행합니다(단일 VPS에서 여러 앱을 실행하는 방법에 대한 가이드를 참고). 실제로 확장이 필요할 때만 더 복잡한 설정을 고민하면 됩니다.
1. VPS를 어디에 두고 싶나요?
2. 어떤 프로세서 아키텍처 – x86 또는 ARM?
- ARM은 비용이 저렴해 점점 인기를 얻고 있지만, 가용성 문제와 가끔 발생하는 소프트웨어 호환성 문제에 직면한 적이 있습니다.
- 우리는 보통 x86을 고수합니다. 개발은 x86에서 하고 배포는 ARM에서 하면 예상치 못한 문제가 발생할 수 있습니다.
- VPS의 장점: 서버가 실행되는 시간만큼만 비용을 지불하므로, ARM 서버를 몇 센트 정도로 테스트해 보고 필요하면 다시 x86으로 전환할 수 있습니다.
3. 공유형인가 전용형인가?
- 공유형부터 시작하고 필요에 따라 업그레이드합니다.
- 공유 서버는 일반적으로 속도가 느리고 예측이 어려울 수 있으므로, 제공업체 선택이 중요합니다.
- Hetzner를 이용하면 좋은 경험을 할 수 있습니다 – 공유 서버 성능이 일관되고 안정적이었습니다.
4. 어떤 OS를 선택해야 할까요?
- Ubuntu(최신 LTS)가 안전한 기본 선택입니다 – 우리가 가장 많이 사용해 왔고 커뮤니티 지원이 가장 큽니다.
- 배포판 간 차이는 대부분 선호도의 문제입니다. 확신이 서지 않으면 Ubuntu를 선택하세요.
- 일반적으로 인기 있는 것을 고수하면 필요할 때 온라인에서 도움을 찾기 쉽습니다.
Source: …
서버가 올라간 후 – 첫 단계
-
SSH로 연결하기
ssh root@your-server-ipyour-server-ip를 제공업체 대시보드나 환영 이메일에 표시된 IP 주소로 바꾸세요. -
서버 강화
- 루트 로그인 비활성화 (
sudo권한이 있는 일반 사용자 사용). - 비밀번호 대신 SSH 키 사용.
- 방화벽 설정 (UFW 또는 iptables).
- 시스템을 최신 상태로 유지 (
apt update && apt upgrade -y). - fail2ban을 설치해 무차별 로그인 시도를 차단.
- 검증된 하드닝 스크립트를 실행할 경우, 스크립트가 하는 일을 충분히 이해하고 사용하세요.
- 루트 로그인 비활성화 (
-
네트워크 수준 방화벽 (Hetzner)
- 22 (SSH), 80 (HTTP), 443 (HTTPS) 포트만 허용.
- Hetzner 방화벽을 로컬 방화벽과 함께 사용하면 리소스를 절약하고, 로컬 규칙을 Docker가 우회하기 전에 트래픽을 차단할 수 있습니다.
Docker 설치
# Remove old versions
sudo apt-get remove docker docker-engine docker.io containerd runc
# Set up the repository
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
설치 확인:
docker --version
docker compose version
Source: …
Docker Compose 로 Django 앱 배포
1. 환경 변수 준비
서버의 프로젝트 디렉터리에 .env 파일을 생성합니다 (이 파일을 Git에 커밋하지 마세요):
POSTGRES_DB=mydb
POSTGRES_USER=myuser
POSTGRES_PASSWORD=mypassword
DATABASE_URL=postgres://myuser:mypassword@db:5432/mydb
DJANGO_SECRET_KEY=your-secret-key
Tip: 프로덕션 수준의 보안을 위해 일반
.env파일 대신 Docker secrets 사용을 고려하세요.
2. 프로덕션용 docker‑compose.yml
services:
web:
image: ghcr.io/YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:latest
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:17
volumes:
- postgres_data:/var/lib/postgresql/data
env_file:
- .env
caddy:
image: caddy:2.10.2
restart: unless-stopped
cap_add:
- NET_ADMIN
ports:
- "80:80"
- "443:443"
volumes:
- $PWD/conf:/etc/caddy
- caddy_data:/data
- caddy_config:/config
volumes:
postgres_data:
caddy_data:
caddy_config:
3. Caddy 설정
docker‑compose.yml 옆에 conf 디렉터리를 만들고 Caddyfile 을 추가합니다:
yourdomain.com {
reverse_proxy web:8000
}
yourdomain.com을 실제 도메인 이름으로 바꾸세요.
Caddy는 해당 도메인에 대해 자동으로 Let’s Encrypt 인증서를 발급합니다.
4. DNS를 VPS에 연결
도메인에 A (또는 AAAA) 레코드를 추가하여 VPS IP 주소를 가리키게 합니다. 전파는 보통 몇 분 정도 걸립니다.
5. 스택 올리기
docker compose up -d
이제 https://yourdomain.com 에서 Django 앱에 접근할 수 있습니다.
6. 새 버전 배포
docker compose pull web # 최신 이미지 가져오기
docker compose up -d web # 웹 서비스만 재시작
CI/CD 파이프라인(GitHub Actions, GitLab CI 등)으로 자동화할 수 있습니다.
Recap – What We Used in This Guide
| Component | Purpose |
|---|---|
| Docker | Django 앱을 컨테이너화 |
| Docker Compose | Django, Postgres, Caddy를 오케스트레이션 |
| Postgres | 관계형 데이터베이스 |
| Caddy | 리버스 프록시 + 자동 TLS |
| Hetzner firewall | 네트워크‑레벨 트래픽 필터링 |
| UFW / iptables | 호스트‑레벨 방화벽 |
| fail2ban | SSH 및 기타 서비스에 대한 무차별 공격 방지 |
| .env file (or Docker secrets) | 민감한 설정 저장 |
최종 생각
소규모 VPS에 Django를 배포하는 것은 저렴하고 빠르며 인프라에 대해 배우기에 훌륭한 방법입니다. 간단하게 시작하고, 초기에 보안을 강화하며, Docker와 Caddy가 대부분의 무거운 작업을 처리하도록 하세요. 트래픽이 증가하면 서비스를 별도의 머신으로 분리하거나, 로드 밸런서를 추가하거나, 관리형 플랫폼으로 이동할 수 있습니다—하지만 많은 소규모에서 중간 규모 프로젝트에 대해 위 설정만으로도 충분합니다. 즐거운 코딩 되세요!