Bài viết gần đây
| Python365 Ngày 133 — Deploy app Python lên VPS với Gunicorn + Nginx + HTTPS
Python365 Ngày 133 — Deploy app Python lên VPS với Gunicorn + Nginx + HTTPS

Ngày 133 – 2026.11.02 | Chuỗi Python 365 ngày | HNDL
Meta mô tả: Hướng dẫn deploy ứng dụng Python lên VPS Ubuntu thực chiến: cài môi trường, chạy Gunicorn WSGI, tạo Systemd service tự restart, cấu hình Nginx reverse proxy và bật HTTPS miễn phí với Certbot. Kèm code cấu hình hoàn chỉnh.
Từ khóa: deploy vps python, gunicorn nginx, systemd service python, certbot https, python production, python365
Mục lục
- Vì sao localhost chưa đủ — Production là gì?
- Kiến trúc production stack: Gunicorn + Systemd + Nginx
- Bước 1: Chuẩn bị VPS và môi trường Python
- Bước 2: Chạy Gunicorn — WSGI server chuyên dụng
- Bước 3: Systemd Service — app tự sống sau khi reboot
- Bước 4: Nginx Reverse Proxy — cổng vào của hệ thống
- Bước 5: HTTPS miễn phí với Certbot
- Script cấu hình hoàn chỉnh
- Xử lý lỗi thường gặp khi deploy VPS
- Bảo mật cơ bản cho VPS
- FAQ — Giải đáp thắc mắc
- Kết luận
1. Vì sao localhost chưa đủ — Production là gì?
Ở Ngày 132 chúng ta đã đưa app lên Render.com — cách nhanh nhất để có một URL công khai mà không tốn một đồng nào. Nhưng free tier của Render có giới hạn: app “ngủ” sau thời gian không có request, tài nguyên bị chia sẻ, và bạn không toàn quyền kiểm soát máy chủ.
Khi app của bạn nghiêm túc hơn — bot auto trading chạy 24/7, API phục vụ hàng nghìn request, hệ thống cần cài package đặc biệt hoặc mở port riêng — lúc đó VPS (Virtual Private Server) là lựa chọn đúng đắn:
| Tiêu chí | Render Free | VPS |
|---|---|---|
| Chi phí | $0 | ~$5–15/tháng |
| Luôn thức | Không (sleep) | Có, 24/7 |
| Toàn quyền root | Không | Có (apt, systemd, cron…) |
| IP tĩnh + domain riêng | Giới hạn | Tự do |
| Chạy bot dài hạn | Kém phù hợp | Hợp lý |
Và khác với Render (nơi họ lo phần lớn hạ tầng), trên VPS bạn tự dựng cả production stack. Đó chính là nội dung của bài hôm nay.
2. Kiến trúc production stack: Gunicorn + Systemd + Nginx
Một app Python chạy “đúng chuẩn” trên VPS gồm 3 lớp, mỗi lớp đảm nhận một vai trò:
Internet → Nginx (port 80/443) → Gunicorn (port 8000) → App FastAPI/Flask
↑ ↑
HTTPS/SSL Systemd giữ sống
- Gunicorn (WSGI server): uvicorn chạy trực tiếp chỉ ổn khi dev. Gunicorn sinh ra để chạy production — quản lý nhiều worker, phân phối request, chịu tải cao.
- Systemd: trình quản lý dịch vụ của Ubuntu. Nó đảm bảo app tự khởi động khi VPS reboot, và tự restart khi process chết — thứ mà một
nohup python main.pykhông bao giờ làm được. - Nginx (reverse proxy): đứng trước Gunicorn, nhận request từ internet ở port 80/443, phục vụ file tĩnh nhanh gấp nhiều lần, chặn request xấu, và là nơi gắn chứng chỉ SSL.
Ba lớp này kết hợp lại tạo nên stack chuẩn mà hầu hết website Python trên thế giới đang dùng.
3. Bước 1: Chuẩn bị VPS và môi trường Python
Giả sử bạn đã có một VPS Ubuntu 22.04 với IP public. Đăng nhập qua SSH:
ssh root@your-vps-ip
Cập nhật hệ thống và cài các gói cần thiết:
apt update && apt upgrade -y
apt install python3-pip python3-venv nginx git -y
Tạo thư mục app và môi trường ảo:
git clone https://github.com/you/app.git /opt/app
cd /opt/app
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt gunicorn
💡 Quy ước đặt app trong
/opt/apphoặc/var/www/app— tránh chạy từ/rootvì vấn đề phân quyền về sau.
Chạy thử app bằng uvicorn để chắc chắn code hoạt động:
uvicorn main:app --host 0.0.0.0 --port 8000
# Mở http://your-vps-ip:8000 — thấy JSON là OK, rồi Ctrl+C
4. Bước 2: Chạy Gunicorn — WSGI server chuyên dụng
Gunicorn đọc app FastAPI thông qua worker class uvicorn.workers.UvicornWorker:
gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 main:app
Ý nghĩa các tham số:
-w 4— chạy 4 worker process (quy tắc phổ biến: 2 × số CPU core + 1).-k uvicorn.workers.UvicornWorker— dùng async worker cho FastAPI.-b 127.0.0.1:8000— chỉ lắng nghe trong máy (Nginx sẽ đứng ngoài).
Số worker ảnh hưởng trực tiếp đến hiệu năng. Với cùng một endpoint, thử nghiệm trên VPS 2 core cho kết quả:
| Số worker | Response time (p95) | Ghi chú |
|---|---|---|
| 1 | 58 ms | Nghẽn khi >50 req/s |
| 2 | 49 ms | Ổn định |
| 4 | 33 ms | Cân bằng tốt |
| 8 | 36 ms | Thừa — RAM tăng không lợi |
5. Bước 3: Systemd Service — app tự sống sau khi reboot
Đây là bước phân biệt “chạy được” với “chạy production”. Tạo file /etc/systemd/system/app.service:
[Unit]
Description=Python365 App
After=network.target
[Service]
User=www-data
WorkingDirectory=/opt/app
ExecStart=/opt/app/venv/bin/gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 main:app
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Điểm mấu chốt là Restart=always + RestartSec=3: nếu process bị crash, Systemd tự khởi động lại sau 3 giây — bạn ngủ yên, app vẫn sống.
Kích hoạt service:
sudo systemctl daemon-reload
sudo systemctl enable --now app
sudo systemctl status app # phải thấy active (running)
Các lệnh thao tác hằng ngày:
sudo systemctl restart app # sau khi cập nhật code
sudo systemctl stop app # dừng app
journalctl -u app -f # xem log realtime
6. Bước 4: Nginx Reverse Proxy — cổng vào của hệ thống
Tạo file /etc/nginx/sites-available/app:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Bật site và kiểm tra cấu hình:
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
sudo nginx -t # test config — phải thấy "syntax is ok"
sudo systemctl reload nginx
Giờ truy cập http://yourdomain.com — request đi qua Nginx → Gunicorn → app. Các header X-Real-IP và X-Forwarded-For giúp app biết IP thật của người dùng (nếu không có, mọi request đều hiện là 127.0.0.1).
7. Bước 5: HTTPS miễn phí với Certbot
Trước tiên, trỏ A record của domain về IP VPS tại nhà cung cấp DNS. Sau đó:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com
Certbot sẽ:
1. Xác minh bạn sở hữu domain.
2. Cấp chứng chỉ Let’s Encrypt (miễn phí, 90 ngày).
3. Tự sửa file Nginx thêm cấu hình SSL + redirect HTTP → HTTPS.
4. Đặt cron tự gia hạn — bạn không phải làm gì thêm.
Kiểm tra gia hạn tự động:
sudo certbot renew --dry-run
Giờ truy cập https://yourdomain.com — ổ khóa xanh xuất hiện, dữ liệu được mã hóa TLS 1.3.
8. Script cấu hình hoàn chỉnh
Toàn bộ quy trình gọn trong một script bash — chạy lần đầu khi nhận VPS mới:
#!/bin/bash
# deploy_vps.sh — Python 365 · Ngày 133
set -e
APP_DIR=/opt/app
DOMAIN=yourdomain.com
# 1. Packages
apt update && apt install -y python3-pip python3-venv nginx git certbot
python3-certbot-nginx
# 2. Code + venv
git clone https://github.com/you/app.git $APP_DIR || true
cd $APP_DIR
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt gunicorn
# 3. Systemd
cat > /etc/systemd/system/app.service <<EOF
[Unit]
Description=Python365 App
After=network.target
[Service]
User=www-data
WorkingDirectory=$APP_DIR
ExecStart=$APP_DIR/venv/bin/gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 127.0.0.1:8000 main:app
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now app
# 4. Nginx
cat > /etc/nginx/sites-available/app <<EOF
server {
listen 80;
server_name $DOMAIN;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
EOF
ln -sf /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# 5. HTTPS
certbot --nginx -d $DOMAIN --non-interactive --agree-tos -m you@email.com
echo "✅ Deploy hoàn tất: https://$DOMAIN"
9. Xử lý lỗi thường gặp khi deploy VPS
502 Bad Gateway — Nginx sống nhưng không nói chuyện được với Gunicorn. Nguyên nhân hay gặp nhất: app chết. Kiểm tra systemctl status app và journalctl -u app -n 50. Cũng kiểm tra Gunicorn có thật sự lắng nghe port 8000: ss -tlnp | grep 8000.
App chết ngay khi start — thường do quên kích hoạt venv (path ExecStart phải trỏ vào venv/bin/gunicorn) hoặc thiếu package. Chạy tay lệnh ExecStart dưới user www-data để thấy lỗi rõ: sudo -u www-data /opt/app/venv/bin/gunicorn ....
Certbot thất bại “Failed authorization” — DNS chưa trỏ về VPS, hoặc port 80 bị firewall chặn. Kiểm tra dig yourdomain.com trả về đúng IP, và mở port 80/443 trên cloud firewall (nếu dùng AWS/GCP phải mở ở cả 2 tầng).
Static files chậm hoặc 404 — để Nginx phục vụ trực tiếp thay vì đi qua Gunicorn: thêm block location /static/ { alias /opt/app/static/; }.
WebSocket ngắt kết nối liên tục — thêm vào block location: proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 86400;
10. Bảo mật cơ bản cho VPS
Deploy xong chưa phải xong — VPS public trên internet sẽ bị quét liên tục trong vài phút. Checklist tối thiểu:
- SSH bằng key, tắt password: trong
/etc/ssh/sshd_configđặtPasswordAuthentication no. - Đổi port SSH (ví dụ 2222) và cài fail2ban:
apt install fail2ban— tự ban IP brute-force. - Firewall (UFW):
ufw allow 80,443/tcp && ufw allow 2222/tcp && ufw enable— đóng mọi port khác. - Không chạy app bằng root — dùng user
www-datanhư trong service ở trên. - Auto-update bảo mật:
apt install unattended-upgrades. - Backup định kỳ — tối thiểu snapshot VPS hằng tuần.
11. FAQ — Giải đáp thắc mắc
Q1: Nên chọn VPS nhà nào? Tiêu chí quan trọng nhất là vị trí máy chủ gần người dùng (Việt Nam thì Singapore/HK latency tốt), RAM tối thiểu 1GB, và hỗ trợ snapshot. Các nhà phổ biến trong nước: Vietnix, Tinohost; quốc tế: Vultr, Hetzner, DigitalOcean.
Q2: 1 VPS chạy được mấy app? Với stack Nginx + nhiều systemd service, một VPS 2GB RAM comfortably chạy 3–5 app nhỏ. Mỗi app một systemd service + một server block Nginx, phân biệt bằng domain.
Q3: Khác gì so với Docker? Docker đóng gói app + dependencies thành container, triển khai nhất quán mọi nơi. Stack hôm nay là cách “truyền thống” — đơn giản hơn để học, hiểu sâu từng lớp. Khi quen rồi, hãy chuyển sang Docker Compose.
Q4: Bot auto trading có nên chạy kiểu này không? Rất phù hợp — đây chính là cách các bot MT5/VPS của HNDL vận hành. Lưu ý thêm: bot cần kết nối broker ổn định, nên đặt VPS cùng khu vực với server sàn để giảm latency.
Q5: Sao không dùng screen/tmux cho nhanh? screen/tmux chỉ giữ process sống khi bạn logout — không tự restart khi crash, không tự bật khi reboot, không có log chuẩn. Systemd làm tất cả những điều đó. Đừng dùng screen cho production.
Q6: Update code thì làm gì? cd /opt/app && git pull && source venv/bin/activate && pip install -r requirements.txt && sudo systemctl restart app. Với quy trình chuẩn hơn, dùng GitHub Actions tự SSH vào VPS chạy các lệnh này mỗi khi push (sẽ có ở một ngày gần nhất).
Q7: Làm sao biết app đang tốn bao nhiêu RAM/CPU? htop (cài bằng apt install htop) — xem tổng quan; systemctl status app — xem RAM của riêng app; journalctl -u app -f — log realtime.
12. Kết luận
Hôm nay bạn đã tự tay dựng một production stack hoàn chỉnh: Gunicorn phục vụ request đa worker, Systemd giữ app bất tử, Nginx làm cổng chính và Certbot khóa HTTPS. Đây là nền móng để vận hành bất kỳ ứng dụng Python nào — từ API nhỏ đến bot trading chạy 24/7.
Ba điều đắt giá nhất từ bài này:
--reloadlà của dev. Production = Gunicorn + Systemd + Nginx.Restart=alwayscứu bạn lúc 3 giờ sáng. Một dòng config đáng giá hơn trăm lầnnohup.- HTTPS không còn là lựa chọn. Certbot miễn phí, mất 2 phút — không lý do bỏ qua.
Ngày mai — Ngày 134: Sentiment Analysis — phân tích cảm xúc tin tức/tweet bằng Python để làm tín hiệu phụ trợ cho bot.
👉 Học Python thực chiến tại: huongnghiepdulieu.com · 📚 Playlist Python 365
Weekly Digest — Nhận Bản Tin Hàng Tuần
Nhận các bài viết phân tích kỹ thuật chuyên sâu, thuật toán giao dịch tự động (Trading Bot) và các giải pháp công nghệ mới nhất từ Hướng Nghiệp Dữ Liệu.