컴퓨터 활용/노년에 즐기는 코딩
같은 VPC의 3개 인스턴스(예: Bastion, Web, DB) 를 활용
easyfly
2025. 10. 18. 07:22
반응형
Django + Gunicorn + Nginx + MariaDB 운용 환경을 구축
1. 아키텍처 개요
- VPC: 10.0.0.0/16 (예시)
- 서브넷
- Public Subnet: Bastion, Web(Nginx) 배치, IGW 경유 인터넷 통신
- Private Subnet: DB(MariaDB) 배치, 공개 IP 없음
- 보안그룹
- SG-Bastion: Inbound 22/tcp(관리자 IP), Outbound All
- SG-Web: Inbound 80,443/tcp(Anywhere 또는 ALB), 22/tcp(Bastion만), Outbound All
- SG-DB: Inbound 3306/tcp(SG-Web만 참조), Outbound All
(주의: 3306을 CIDR로 열지 말고 보안그룹 참조로 한정)
- 접속 흐름
- 운영자 → Bastion(SSH) → Web(SSH)
- 외부 사용자 → Web(HTTP/HTTPS, Nginx → Gunicorn → Django)
- Web → DB : 10.x 프라이빗 통신(3306)
2. 데이터베이스 서버(Private, 10.0.x.y) 준비
2.1 MariaDB 설치 및 기동
sudo dnf update -y
sudo dnf install -y mariadb105-server
sudo systemctl enable --now mariadb
sudo mysql_secure_installation
2.2 데이터베이스/계정 생성
sudo mysql -u root -p
CREATE DATABASE simadang CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER 'simadang'@'10.0.%' IDENTIFIED BY '강한비밀번호!'; -- Web 인스턴스 대역 허용
GRANT ALL PRIVILEGES ON simadang.* TO 'simadang'@'10.0.%';
FLUSH PRIVILEGES;
EXIT;
필요시필요시 CloudShell/S3/Scp로 받은 백업을 복원:
sudo mysql -u root -p simadang < /home/ec2-user/madang_YYYYMMDD.sql
3. 웹 서버(퍼블릭, Nginx + Gunicorn + Django)
3.1 시스템 패키지 및 파이썬 가상환경
sudo dnf update -y
sudo dnf install -y nginx python3.11 python3.11-pip python3.11-venv git
python3.11 -m venv ~/venv
source ~/venv/bin/activate
pip install --upgrade pip wheel
3.2 Django 프로젝트 배포(예시)
# (A) 새 프로젝트
pip install django gunicorn mysqlclient
django-admin startproject config ~/app
# 또는 (B) Git에서 가져오기
# git clone <repo> ~/app && cd ~/app && pip install -r requirements.txt
3.2.1 Django DB 설정 (~/app/config/settings.py)
ALLOWED_HOSTS = ["example.com", "웹서버공인IP", "내부도메인"]
STATIC_URL = "/static/"
STATIC_ROOT = "/var/www/static"
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "simadang",
"USER": "simadang",
"PASSWORD": "강한비밀번호!",
"HOST": "10.0.2.95", # DB의 프라이빗 IP
"PORT": "3306",
"OPTIONS": {"charset": "utf8mb4"},
}
}
3.2.2 마이그레이션/정적파일
cd ~/app
python manage.py migrate
python manage.py collectstatic --noinput
sudo mkdir -p /var/www/static && sudo chown -R ec2-user:ec2-user /var/www/static
3.3 Gunicorn 서비스(시스템디)
sudo tee /etc/systemd/system/gunicorn.service > /dev/null <<'EOF'
[Unit]
Description=gunicorn daemon
After=network.target
[Service]
User=ec2-user
Group=nginx
WorkingDirectory=/home/ec2-user/app
Environment="PATH=/home/ec2-user/venv/bin"
ExecStart=/home/ec2-user/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn.sock config.wsgi:application
RuntimeDirectory=gunicorn
RuntimeDirectoryMode=0755
Restart=always
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now gunicorn
sudo systemctl status gunicorn --no-pager
3.4 Nginx 리버스 프록시
sudo tee /etc/nginx/conf.d/django.conf > /dev/null <<'EOF'
server {
listen 80;
server_name _;
# 정적 파일
location /static/ {
alias /var/www/static/;
access_log off;
expires max;
}
# 애플리케이션
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
EOF
sudo nginx -t && sudo systemctl enable --now nginx
HTTPS(권장): 퍼블릭 도메인이 있다면 ACM+ALB(또는 Nginx certbot)로 TLS 적용
- 간단: sudo dnf install -y certbot python3-certbot-nginx && sudo certbot --nginx
4. 배스천 호스트(퍼블릭) 역할
- 운영자 SSH 진입점.
- 보안그룹에서 22/tcp를 관리자 고정 IP로만 허용.
- Bastion → Web/DB로의 SSH는 프라이빗 IP 사용.
- 파일 반입/반출: scp -i <pem> file ec2-user@10.0.x.x:/path/
5. 네트워킹과 보안 체크리스트
- 라우팅
- 퍼블릭 서브넷: 0.0.0.0/0 → IGW
- 프라이빗 서브넷: IGW 경로 없음, 내부 통신만
- 필요시 Private의 외부 업데이트는 NAT GW 경유
- 보안그룹
- Web → DB: SG-Web이 SG-DB의 3306에 접근 가능해야 함(보안그룹 참조 방식)
- 외부 → Web: 80/443만 개방, 22는 관리자만
- 서브넷/ENI
- Web 인스턴스는 퍼블릭 IP/탄력적 IP(EIP) 부여
- DB 인스턴스는 퍼블릭 IP 없음
- 시계/로캘
sudo timedatectl set-timezone Asia/Seoul
- 로그/모니터링
- journalctl -u gunicorn -f, sudo tail -f /var/log/nginx/access.log
- CloudWatch Agent로 기본 메트릭/로그 적재 권장
6. 운영 편의(권장 사항)
- 환경변수 분리: .env(SECRET_KEY/DB PW) → django-environ 사용
- 정적/미디어 외부화: 이미지/첨부물은 S3 + CloudFront(캐시/HTTPS)
- 마이그레이션 자동화: 배포 스크립트에 migrate/collectstatic 포함
- 백업: DB 스냅샷 + 주기적 mysqldump(S3 버킷에 버전닝)
- 무중단 배포: Nginx proxy_next_upstream, Gunicorn --graceful-timeout 조정
- 방화벽 추가계층: NACL은 기본 허용/허용 규칙, 차단 정책 시 주의
7. 점검용 퀵 테스트
- Web ↔ DB 포트 점검
# Web 인스턴스에서
nc -zv 10.0.2.95 3306
- Django DB 연결 테스트
python - <<'PY'
import MySQLdb
conn = MySQLdb.connect(host="10.0.2.95", user="simadang", passwd="강한비밀번호!", db="simadang", charset="utf8mb4")
cur = conn.cursor(); cur.execute("SELECT 1"); print(cur.fetchone()); conn.close()
PY
- HTTP 확인
- curl -I http://웹서버공인IP/
- 정적: http://웹서버공인IP/static/ 에서 200 응답
8. 장애 시 빠른 체크 순서
- systemctl status gunicorn → 비정상 시 journalctl -u gunicorn -e
- sudo nginx -t → 설정오류 여부, systemctl restart nginx
- mysql -h 10.0.2.95 -u simadang -p → 응답/권한/방화벽 확인
- SG 규칙: Web→DB 3306 허용(보안그룹 참조 여부)
- 서브넷/라우팅: DB는 퍼블릭 라우트 없어야 함(외부 노출 방지)
마무리
위 절차대로 진행하시면 Bastion(관리), Web(Nginx+Gunicorn), DB(MariaDB) 가 같은 VPC 내에서 안전하게 동작하는 프로덕션 기본 구조를 완성할 수 있습니다.
반응형