Python Web Deployment | Heroku, AWS, and Docker in Practice
이 글의 핵심
Deploy Python web apps: requirements.txt,.env, Gunicorn, Docker and Compose, Heroku, AWS EC2 with Nginx, systemd, and a production-minded checklist.
Introduction
“Development is done—time to deploy”
Deployment is the process of shipping your application to real users.
1. Deployment prep
requirements.txt
# Generate pinned dependencies
pip freeze > requirements.txt
Flask==2.3.0
gunicorn==20.1.0
python-dotenv==1.0.0
Environment variables (.env)
# .env
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://user:pass@localhost/db
DEBUG=False
# app.py
from dotenv import load_dotenv
import os
load_dotenv()
app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['DEBUG'] = os.getenv('DEBUG', 'False') == 'True'
2. Gunicorn
Running with Gunicorn
# Install
pip install gunicorn
# Run
gunicorn app:app
# Workers and bind address
gunicorn -w 4 -b 0.0.0.0:8000 app:app
gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "sync"
timeout = 30
keepalive = 2
3. Docker deployment
Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]
docker-compose.yml
version: '3.8'
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
# Start stack
docker-compose up -d
4. Heroku deployment
Procfile
web: gunicorn app:app
runtime.txt
python-3.11.0
Deploy commands
# After installing Heroku CLI
heroku login
heroku create myapp
# Set config
heroku config:set SECRET_KEY=your-secret-key
# Deploy
git push heroku main
# Logs
heroku logs --tail
5. AWS deployment (EC2)
EC2 setup
# SSH into server
ssh -i key.pem ubuntu@ec2-instance
# Install Python tooling
sudo apt update
sudo apt install python3-pip python3-venv
# Clone project
git clone https://github.com/user/myapp.git
cd myapp
# Virtual environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# Run Gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 app:app
Nginx configuration
# /etc/nginx/sites-available/myapp
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
# Enable site
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
6. Practical tips
Deployment checklist
# Environment variables
# SECRET_KEY, DATABASE_URL, etc.
# DEBUG = False
app.config['DEBUG'] = False
# ALLOWED_HOSTS (Django)
ALLOWED_HOSTS = ['yourdomain.com']
# Static files
python manage.py collectstatic
# Database migrations
python manage.py migrate
# HTTPS
# Let's Encrypt, Cloudflare, etc.
Going deeper
Example: Gunicorn + systemd (minimal production pattern)
Assume the app is exposed as myapp.wsgi:app. This example binds to 127.0.0.1:8000 (not socket activation).
/etc/systemd/system/myapp.service:
[Unit]
Description=My Gunicorn App
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
EnvironmentFile=/etc/myapp.env
ExecStart=/var/www/myapp/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 myapp.wsgi:app
Restart=always
[Install]
WantedBy=multi-user.target
After deployment: sudo systemctl daemon-reload && sudo systemctl enable --now myapp.
Common mistakes
- Running with DEBUG=True in production and leaking secrets or tracebacks.
- Hard-coding virtualenv paths so deploy scripts break on the server.
- Relying on load balancers without health checks, so dead processes go unnoticed.
Safety notes
- Keep secrets in environment variables or a secret manager—never commit them to Git.
- Re-validate ALLOWED_HOSTS, CORS, and CSRF under your production profile.
How teams usually operate
- Put Nginx or Caddy in front for TLS termination.
- Ship logs to journald and onward to CloudWatch, ELK, or similar.
- For containers, prefer read-only root filesystems and non-root users.
Options at a glance
| Approach | Strengths |
|---|---|
| PaaS (Heroku, etc.) | Simple operations |
| VM + systemd | Control vs. cost tradeoff |
| Kubernetes | Large scale, many services |
Further reading
Summary
Key takeaways
- Gunicorn: production WSGI server
- Docker: reproducible environments
- Heroku: fast path to hosted apps
- AWS: flexible, often cost-effective at scale
- Nginx: reverse proxy in front of app workers
Next steps
- Pandas for data analysis
- Web scraping (future topics in the series)
Related posts
- [Python environment setup | Install on Windows & Mac](/en/blog/python-series-01-environment-setup/
- [Python basics: variables, operators, control flow](/en/blog/python-series-02-basic-syntax/
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Deploy Python web apps: requirements.txt, .env, Gunicorn, Docker and Compose, Heroku, AWS EC2 with Nginx, systemd, and a… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. Python 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- [Flask Basics | Get Started with the Python Web Framework](/en/blog/python-series-11-flask-basics/
- [Django Basics](/en/blog/python-series-12-django-basics/
- [Docker Compose Tutorial for Beginners](/en/blog/docker-compose-tutorial/
- [C++ DevContainer & Docker Guide — Standardize Builds,](/en/blog/cpp-series-40-3-docker-cpp/
- [Kubernetes Deployment with minikube | Node.js API](/en/blog/kubernetes-deployment-strategies/
이 글에서 다루는 키워드 (관련 검색어)
Python, Deployment, Heroku, AWS, Docker, Gunicorn 등으로 검색하시면 이 글이 도움이 됩니다.