∟ Framework/∟ DRF

AWS EC2(Ubuntu)에서 Django 앱 배포하기 (Gunicorn + Nginx)

최 수빈 2025. 4. 6. 04:14

 

AWS(Amazon Web Services)의 EC2(Elastic Compute Cloud)

 

AWS에서 제공하는 가상 컴퓨터(인스턴스), 가상 서버

 

 

서버

네트워크를 통해 클라이언트의 요청을 받아 처리하고, 그에 대한 응답을 보내주는 컴퓨터(또는 소프트웨어 시스템)

 

클라우드

물리적인 서버를 인터넷을 통해 빌려 쓸 수 있는 서비스

 

  • Iaas(Infrastructure as a Service)
    물리적인 컴퓨팅 자원을 가상화해서 제공하는 서비스
    AWS EC2(자유도 높음, 셋업은 직접해야 함), Microsoft Azure, Google Compute Engine
  • PaaS(Platform as a Service)
    플랫폼을 가상화해서 제공하는 서비스
    인프라에 대한 관리 없이 개발에 집중하여 빠른 속도로 개발할 수 있음
    Heroku, AWS Elastic Beanstalk, PythonAnyWhere 등 (간편하지만 제약 있음)
  • SaaS(Software as a Service)
    서비스형 소프트웨어
    컴퓨터에 설치하고 사용하던 이전의 소프트웨어와 달리 인터넷 접속을 통해 바로 서비스 사용 가능
    모든 서비스를 맡기고 비지니스에 집중할 수 있음
    Notion, Dropbox처럼 서비스 자체를 제공

 

 

AWS EC2 인스턴스 생성 및 접속

 

AWS 계정 생성 (카드 필요, 소액 테스트 결제 발생)

https://aws.amazon.com/ko/

 

클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web Services

Amazon Bedrock은 주요 AI 기업의 고성능 FM 옵션을 평가하고 선택하는 데 도움을 주는 완전관리형 서비스입니다. 기반 인프라를 관리하지 않고도 생성형 AI 애플리케이션을 구축할 수 있습니다. Amazon

aws.amazon.com

 

 

Management Console - 리전 설정 - EC2 인스턴스 생성

 

  • AWS는 리전별로 자원을 따로 관리
    EC2, S3, RDS 등 대부분의 AWS 리소스는 특정 리전에 물리적으로 위치함
    콘솔에서 리전을 바꾸지 않으면 원하는 리소스를 찾지 못할 수 있음 (예: 서울(ap-northeast-2) 리전에 EC2 인스턴스를 만들었는데, 콘솔 리전이 오리곤(us-west-2)으로 되어있으면 "EC2 없음" 이라고 나옴)
    리전별로 요금/ 속도/ 법적 조건이 다름

  • OS: Ubuntu 22.04

    Ubuntu = 리눅스 기반 운영체제
    오픈소스 + 무료
    커뮤니티 크고 정보 많음
    패키지 관리 쉬움(apt)
    서버 환경에 최적화된 버전 존재 (Ubuntu Server는 GUI 없이 가볍고 빠르게 작동 → 리소스를 아껴서 EC2와 같은 클라우드 환경에 적합)
    다양한 클라우드 서비스에서 기본 제공(AWS, GCP, Azure 모두 Ubuntu 이미지 기본 제공, 관리 쉬움)

    → 가볍고, 빠르고, 배우기 쉬우면서도 강력

  • Amazon Machine Image(AMI): Cnonical이 제공하는 이미지 사용(프리 티어)

    AMI
    운영체제 + 기본 설정이 들어있는 '서버 템플릿'
    무엇을 설치할지, 어떤 성능의 컴퓨터를 쓸지 결정
    무료로 AWS 공식 이미지와 Canonical(Ubuntu 만든 공식 회사)이 제공하는 이미지 사용 가능 → "Published by" 항목에서 확인
    Canonical이 만든 공식 이미지는 Ubuntu 순정 그대로라 불필요한 AWS 도구가 없고,
    AWS 공식 이미지는 AWS 환경에 최적화 돼있음(CloudWatch, SSM, AWS CLI 기본 설치 등)
    기타 서드파티 제공자가 제공하는 이미지들도 존재함

  • 인스턴스 타입: t2.micro(프리 티어)

 

  • 키페어 생성 및 다운로드
    내 EC2 인스턴스에 접근할 수 있는 암호키
    공유 X, 잃어버리지 않도록 주의해야 함

 

EC2 접속 (SSH) - masOS ver.

 

chmod 400 키페어파일경로.pem
ssh -i 키페어파일경로.pem ubuntu@퍼블릭 IPv4 DNS

 

SSH(Secure Shell)

원격 컴퓨터에 안전하게 접속할 수 있게 해주는 암호화된 통신 프로토콜

모든 데이터가 암호화되어 전송됨 (패킷도 보호됨)

기본 포트 22번

패드워드 / 공개키 인증 (대부분 키페어.pem 사용)

 

chmod

파일 권한(permission)을 바꾸는 유닉스(Unix) 계열 OS 명령어

400은 파일을 오직 소유자만 읽을 수 있게 만드는 권한 설정(소유자도 쓰기(w), 실행(x) 불가)

 

 

서버 환경 준비

sudo apt update                               # 패키지 정보 업데이트
sudo apt install python3-pip                  # python과 pip 설치
sudo apt install build-essential libpq-dev -y # requirements 설치 시 필요할 수 있는 시스템 패키지 사전 설치
apt apt-get
Ubuntu 16.04 이후 오래된 명령어 (legacy)
사용자 친화적 UI (진행률 표시, 컬러 등) 스크립트 친화적 (출력 단순함)
직접 터미널에서 입력할 때 스크립트에서 사용할 때

 

 

 

Github 코드 배포 및 세팅

 

settings.py의 ALLOWED_HOSTS에 EC2 IP 추가 및 STATIC_URL, STATIC_ROOT 설정

# settings.py

...

DEBUG = False

ALLOSED_HOSTS = [
    "퍼블릭 IPv4 주소",
    "127.0.0.1",
    "localhost",
]

STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "static"

...

 

  1. 로컬에서 프로젝트 .gitignore, requirementx.txt 정리 후 push
  2. EC2에서 clone
  3. 프로젝트 폴더로 이동
  4. 가상환경 생성 및 활성화
  5. 패키지 설치
git clone 레포지토리
cd 클론한폴더
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

 

 

.env

  1. 프로젝트 루트 폴더에 .env 파일 생성
  2. nano .env로 내용 작성
cd ~/프로젝트 루트 폴더 # 프로젝트 루트 폴더로 이동
touch .env   # .env 파일 생성
nano .env # .env 파일 열고 내용 작성
# .env
DJANGO_SECRET_KEY=settings.py에 적혀있는 SECRET_KEY
OPENAI_API_KEY=openai-api-key
OTHER_KEY=value

개발 코드(.env를 불러오는 쪽 코드)에서 dotenv, load_dotenv, os.environ.get(...) 등등 적절히 처리돼있어야 함

 

Ctrl + O (저장) → Enter (파일이름 설정) → Ctrl + X (nano 편집기 종료)

 

 

Django 마이그레이션 및 서버 실행

python3 manage.py migrate
python3 manage.py createsuperuser
python3 manage.py runserver 0:8000 # 0:8000 EC2 외부 IP로 8000번 포트에 들어오는 것 허용

 

EC2 > 인스턴스 >  보안 그룹에서 인바운드 규칙 편집 클릭 후 8000 포트 인바운드 규칙 추가

SSH (22번 포트) 원격 접속용 (보통 EC2에 로그인) 리눅스 EC2 접속할 때 필수
HTTP (80번 포트) 웹사이트 트래픽 (비암호화) 일반 웹 서비스
HTTPS (443번 보트) 웹사이트 트래픽 (암호화) 보안 웹 서비스
Custom TCP Rule 임의의 TCP 포트 허용 예: Django 서버 8000포트, MySQL 3306 등
All Traffic 모든 트래픽 허용(비추..) 테스트용/급한 경우
ICMP 핑(Ping) 등 네트워크 테스트용 ping 명령어 허용 시
SMTP (25, 465, 587 포트) 메일 전송용 이메일 서버 운영 시

settings.py의 ALLOWED_HOSTS에 EC2 IP 추가돼있어야 함 !!

 


개발 서버 벗어나기

 

Nginx

웹 서버 + 리버스 프록시 + 정적 파일 처리

 

브라우저에서 요청이 오면 가장 먼저 응답

이미지, CSS, JS 같은 정적 파일은 속도가 빠른 Nginx가 직접 처리함

동적 요청은 뒤에 있는 애플리케이션 서버(Gunicorn)로 전달함

클라이언트 ↔ Nginx ↔ Gunicorn ↔ Django

 

 

WSGI (Web Server Gateway Interface)

 

웹 서버와 Python 웹 애플리케이션(Django)을 이어주는 인터페이스

 

WSGI는 '규약'이라고 할 수 있음

Django가 WSGI 규칙에 맞춰 애플리케이션 작성, Gunicorn 같은 서버가 WSGI 앱 실행

# Django의 WSGI 진입점 제공
application = get_wsgi_application()

 

 

Gunicorn

Python WSGI 애플리케이션을 실행하는 애플리케이션 서버

gunicorn [wsgi.py파일이 있는 폴더의 디렉토리(디렉토리.으로 구분)].wsgi:application

→ 배포용 서버에서 Django가 실행, nginx 통해 외부 요청 처리 가능

 

여러 요청을 멀티 프로세스로 처리할 수 있어 성능 향상

브라우저 요청을 직접 받지 않고, Nginx를 통해 전달받음

 

[사용자 브라우저]
       ↓
     [Nginx] ───▶ 정적 파일 처리
       ↓
  (동적 요청이면)
       ↓
    [Gunicorn]  ───▶ WSGI 인터페이스
       ↓
     [Django]
       ↓
     [DB or 응답]

 

 

 

Gunicorn 설치 및 실행

sudo apt install gunicorn
gunicorn --bind 0:8000 your_project.wsgi:application

 

 

 

Nginx 설치 및 설정

 

정적 파일 수집

python3 manage.py collectstatic

 

/etc/nginx/
├── nginx.conf               ← 메인 설정 파일
├── sites-available/         ← 사용 가능한 사이트 설정들
└── sites-enabled/           ← 실제로 적용되는 사이트 설정들 (심볼릭 링크)
sudo apt install nginx -y
cd /etc/nginx/sites-available
sudo vi django # 내 설정 파일 생성
server {
    listen 80;                                    # EC2의 80번 포트로 들어오는 요청 받음 (HTTP 기본 포트)
    server_name 퍼블릭 IP;                          # 이 서버 블록은 이 도메인에 해당하는 요청을 처리
    client_max_body_size 128M;                    # 클라이언트가 업로드할 수 있는 최대 파일 크기 128MB

    location /static {
        alias /home/ubuntu/your-repo/static;      # /static 경로로 요청이 오면, 실제 파일은 이 경로에서 찾아서 보여줌
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/tmp/gunicorn.sock; # 그 외 모든 요청은 Gunicorn으로 보냄 (유닉스 소켓으로 연결)
    }
}

esc → :wq Enter

 

 

설정 파일 적용

cd /etc/nginx/sites-enabled
sudo rm default # 기본 설정 삭제
sudo ln -s /etc/nginx/sites-available/django # 링크 방식으로 설정 활성화

포트 80도 보안 그룹에서 열어줘야 함

 

 

nginx 유저 정보 변경

 

기본적으로 nginx는 www-data라는 사용자로 실행됨

ps aux | grep nginx # 프로세스 확인 명령어

www-data 유저는 프로젝트의 파일을 읽을 권한이 없을 수도 있음(ubuntu사용자로 만든 파일 등)

sudo vi /etc/nginx/nginx.conf

i 입력하여 INSERT 모드로 변경

 

제일 윗 줄에

user ubuntu;
...

추가 하여 유저 정보 변경 후 esc :wq

 

sudo nginx -t # 문법 체크
sudo systemctl start nginx # Nginx 실행
sudo systemctl stop nginx # Nginx 중지
sudo systemctl restart nginx # Nginx 재시작

restart: 서버 완전 재시작 - 설정을 크게 바꾸거나 오류가 났을 때

reload: 설정만 다시 적용 - 설정 파일만 수정했을 때 (끊김 없이 반영)

 

 

 

Gunicorn 서비스로 등록

 

직접 gunicorn --bind 0:8000 ... 명령어를 입력하여 실행하는 방식은 터미널 종료, 서버 리부팅하면 꺼짐

자동 시작 X (테스트나 개발용)

TCP 포트로 통신

 

systemd + 소켓 방식 실행

gunicorn.service라는 systemd유닛 파일을 만들어서 systemctl로 실행

백그라운드에서 계속 실행됨 (시스템 서비스)

systemd가 관리 → 자동시작 enable하면 EC2 재부팅 되어도 자동 실행 됨

운영(배포)환경에 적합

유닉스 소켓 파일(/tmp/gunicorn.sock)로 통신 

cd /etc/systemd/system
sudo vi gunicorn.service
[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=ubuntu
Group=ubuntu
WorkingDirectory=manage.py가 위치한 디렉토리 pwd
ExecStart=gunicorn이 설치된 가상환경 위치 # which gunicorn 명령어로 경로 확인 가능
  --workers 2 \
  --bind unix:/tmp/gunicorn.sock \
  wsgi.py가 있는 디렉토리 이름.wsgi:application

[Install]
WantedBy=multi-user.target

 

sudo systemctl daemon-reexec    # systemd 자체를 재실행 (시스템 핵심 프로세스 자체 재시작이라 거의 안씀)
sudo systemctl start gunicorn   # gunicorn 서비스 시작
sudo systemctl enable gunicorn  # gunicorn 서비스 자동 실행 설정
sudo systemctl restart gunicorn # gunicorn 서비스 재시작 (기존 프로세스 종료 + 새로 시작)
sudo systemctl status gunicorn  # gunicorn 서비스 상태 확인
systemctl list-units --type=service # 현재 실행 중인 서비스 리스트

 

 

테스트 및 Postman으로 API 확인

Postman 환경변수에 배포환경 등록
배포환경에서 로그인 완료

 


  1. 로컬에서 .env 포함 설정 마무리 확인
    • DEBUG=False
    • ALLOWED_HOSTS → EC2 외부 IP
    • SECRET_KEY, API 키 등 환경 변수 .env로 관리
  2. .gitignore .env 포함돼 있으면 EC2에 직접 만들어줘야 함
  3. EC2에서 git clone or git pull
  4. .env 직접 만들고 SECRET_KEY, 키값들 입력
  5. 가상환경 만들고, pip install -r requirements.txt
  6. python manage.py collectstatic, migrate 등 실행
  7. Gunicorn, Nginx 설정해서 서비스 시작

'∟ Framework > ∟ DRF' 카테고리의 다른 글

Django + 외부 API  (1) 2025.04.01
API 문서화(Documentation)  (0) 2025.03.31
Redis를 Django 캐시 백엔드로 설정하기  (1) 2025.03.31
ORM 최적화  (0) 2025.03.31
Django ORM(Object Relational Mapping) 활용  (0) 2025.03.31