Python programming code on laptop

Deploy Python Flask/Django บน VPS ด้วย uWSGI และ Nginx

มิถุนายน 2026 · อ่าน 8 นาที

การ deploy Python web application บน VPS นั้นมีหลายทางเลือก แต่ combination ที่ได้รับความนิยมและมีประสิทธิภาพสูงที่สุดคือการใช้ uWSGI เป็น WSGI server คู่กับ Nginx เป็น reverse proxy บทความนี้จะพาคุณผ่านทุกขั้นตอนตั้งแต่เริ่มต้นจนถึง production-ready สำหรับทั้ง Flask และ Django

ทำไมต้องใช้ uWSGI + Nginx?

Python web framework อย่าง Flask และ Django มี built-in development server แต่ ไม่ควรใช้ใน production เด็ดขาด เพราะไม่ปลอดภัยและรองรับ concurrent request ได้น้อย การใช้งานจริงจึงต้องมี stack ที่เหมาะสม ดังนี้

ขั้นตอนที่ 1: เตรียม VPS และ Python Environment

เริ่มต้นด้วยการอัพเดทระบบและติดตั้ง package ที่จำเป็น (สมมติว่าใช้ Ubuntu 22.04 LTS)

# อัพเดทระบบก่อน
sudo apt update && sudo apt upgrade -y

# ติดตั้ง Python, pip, virtualenv และ build tools
sudo apt install -y python3 python3-pip python3-venv python3-dev \
    build-essential libssl-dev libffi-dev nginx

# ตรวจสอบ version
python3 --version
nginx -v

จากนั้นสร้าง user แยกต่างหากสำหรับรัน application (best practice ด้านความปลอดภัย)

sudo useradd -m -s /bin/bash appuser
sudo su - appuser

ขั้นตอนที่ 2: สร้างและ Deploy Python App

สำหรับ Flask

# สร้าง project directory
mkdir -p /home/appuser/myapp
cd /home/appuser/myapp

# สร้าง virtual environment
python3 -m venv venv
source venv/bin/activate

# ติดตั้ง Flask และ uWSGI
pip install flask uwsgi

# สร้างไฟล์ application หลัก
cat > app.py << 'EOF'
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '

Hello from Flask on VPS!

' @app.route('/health') def health(): return {'status': 'ok'} if __name__ == '__main__': app.run() EOF

สำหรับ Django

# ติดตั้ง Django และ uWSGI
pip install django uwsgi

# สร้าง Django project ใหม่
django-admin startproject myproject .

# ปรับค่า ALLOWED_HOSTS ใน settings.py
# ALLOWED_HOSTS = ['your-domain.com', 'your-server-ip']

# Run migrations
python manage.py migrate
หมายเหตุ: สำหรับ Django ให้แทนที่ app:app ด้วย myproject.wsgi:application ในขั้นตอน uWSGI configuration ด้านล่าง

ขั้นตอนที่ 3: ตั้งค่า uWSGI

สร้างไฟล์ configuration สำหรับ uWSGI

cat > /home/appuser/myapp/uwsgi.ini << 'EOF'
[uwsgi]
# สำหรับ Flask
module = app:app

# สำหรับ Django ใช้บรรทัดนี้แทน:
# module = myproject.wsgi:application

master = true
processes = 4
threads = 2

# Socket file สำหรับ communicate กับ Nginx
socket = /tmp/myapp.sock
chmod-socket = 660
vacuum = true

# Log
logto = /var/log/uwsgi/myapp.log

# เพิ่ม stability
die-on-term = true
EOF

สร้าง log directory และทดสอบ uWSGI

sudo mkdir -p /var/log/uwsgi
sudo chown appuser:www-data /var/log/uwsgi

# ทดสอบว่า uWSGI ทำงานได้
cd /home/appuser/myapp
source venv/bin/activate
uwsgi --ini uwsgi.ini
คำเตือน: ถ้า uWSGI ขึ้น error unable to load configuration ให้ตรวจสอบว่า path ใน uwsgi.ini ถูกต้องและ virtual environment ถูก activate แล้ว

ขั้นตอนที่ 4: ตั้งค่า systemd Service

สร้าง systemd service เพื่อให้ uWSGI รันอัตโนมัติเมื่อ server restart

sudo nano /etc/systemd/system/myapp.service

วางเนื้อหาต่อไปนี้ในไฟล์

[Unit]
Description=uWSGI instance for myapp
After=network.target

[Service]
User=appuser
Group=www-data
WorkingDirectory=/home/appuser/myapp
Environment="PATH=/home/appuser/myapp/venv/bin"
ExecStart=/home/appuser/myapp/venv/bin/uwsgi --ini uwsgi.ini

Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
# เปิดใช้งานและเริ่ม service
sudo systemctl daemon-reload
sudo systemctl enable myapp
sudo systemctl start myapp

# ตรวจสอบสถานะ
sudo systemctl status myapp

ขั้นตอนที่ 5: ตั้งค่า Nginx

สร้าง Nginx virtual host configuration

sudo nano /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name your-domain.com www.your-domain.com;

    # Logging
    access_log /var/log/nginx/myapp_access.log;
    error_log  /var/log/nginx/myapp_error.log;

    # Static files (สำหรับ Django)
    location /static/ {
        alias /home/appuser/myapp/staticfiles/;
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # Media files (สำหรับ Django)
    location /media/ {
        alias /home/appuser/myapp/media/;
        expires 7d;
    }

    # Proxy ทุก request ไปหา uWSGI
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/myapp.sock;
        uwsgi_read_timeout 60;
        uwsgi_connect_timeout 60;
    }

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}
# เปิดใช้งาน site
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/

# ตรวจสอบ syntax
sudo nginx -t

# Reload Nginx
sudo systemctl reload nginx

ขั้นตอนที่ 6: เพิ่ม SSL ด้วย Let's Encrypt

การใช้ HTTPS เป็นสิ่งจำเป็นใน production ใช้ Certbot เพื่อขอ SSL certificate ฟรีจาก Let's Encrypt

# ติดตั้ง Certbot
sudo apt install -y certbot python3-certbot-nginx

# ขอ certificate (แทนที่ด้วย domain จริง)
sudo certbot --nginx -d your-domain.com -d www.your-domain.com

# ทดสอบ auto-renewal
sudo certbot renew --dry-run
หมายเหตุ: Certbot จะแก้ไข Nginx config ให้อัตโนมัติ เพิ่ม HTTPS redirect และใส่ SSL certificate path ให้เรียบร้อย

ขั้นตอนที่ 7: ตั้งค่า Static Files (Django)

สำหรับ Django จำเป็นต้อง collectstatic ก่อน deploy ทุกครั้ง

cd /home/appuser/myapp
source venv/bin/activate

# ตั้งค่าใน settings.py
# STATIC_ROOT = '/home/appuser/myapp/staticfiles/'

# รวม static files
python manage.py collectstatic --noinput

# Restart service
sudo systemctl restart myapp

การ Monitor และ Debug

คำสั่งที่ใช้บ่อยในการตรวจสอบและแก้ไขปัญหา

# ดู log ของ uWSGI แบบ real-time
sudo journalctl -u myapp -f

# ดู log ของ Nginx
sudo tail -f /var/log/nginx/myapp_error.log
sudo tail -f /var/log/nginx/myapp_access.log

# ตรวจสอบ socket file
ls -la /tmp/myapp.sock

# Restart service หลังแก้โค้ด
sudo systemctl restart myapp

# ดูสถานะ service ทั้งหมด
sudo systemctl status myapp nginx

การ Deploy Code ใหม่ (Workflow)

  1. อัพโหลดหรือ pull code ใหม่มายัง server
  2. เข้า virtual environment: source venv/bin/activate
  3. ติดตั้ง dependencies ใหม่: pip install -r requirements.txt
  4. สำหรับ Django รัน migration: python manage.py migrate
  5. สำหรับ Django รวม static files: python manage.py collectstatic --noinput
  6. Restart uWSGI service: sudo systemctl restart myapp
คำเตือน: การ restart service จะทำให้ website หยุดให้บริการชั่วขณะ ถ้าต้องการ zero-downtime deployment ให้ใช้คำสั่ง sudo systemctl reload myapp หรือพิจารณาใช้ blue-green deployment

Checklist ความปลอดภัยก่อน Production


สรุป

การ deploy Python Flask หรือ Django บน VPS ด้วย uWSGI และ Nginx เป็น stack ที่เสถียร ปลอดภัย และ scale ได้ดีสำหรับ production environment ขั้นตอนหลักที่ต้องจำคือ

  1. เตรียม environment — Python venv, ติดตั้ง dependencies
  2. ตั้งค่า uWSGI — สร้าง uwsgi.ini และ systemd service
  3. ตั้งค่า Nginx — virtual host ที่ proxy ไปยัง uWSGI socket
  4. เพิ่ม SSL — ใช้ Let's Encrypt ผ่าน Certbot
  5. ทดสอบและ monitor — ตรวจสอบ log และ service status

เมื่อทำครบทุกขั้นตอนแล้ว Python app ของคุณจะพร้อมรับ traffic จริงได้อย่างมั่นคง หากต้องการ scale เพิ่มเติมในอนาคต สามารถเพิ่มจำนวน processes ใน uWSGI config หรือใช้ Nginx เป็น load balancer ระหว่างหลาย server ได้ทันที

ตรวจสอบว่า Python App ทำงานถูกต้อง

# ตรวจสอบสถานะ uWSGI service
sudo systemctl status myapp

# ตรวจสอบว่า socket file สร้างแล้ว
ls -la /tmp/myapp.sock

# ทดสอบ app ตอบสนองผ่าน Nginx
curl -I http://localhost/
# ควรได้ HTTP/1.1 200 OK

# ดู log real-time เพื่อตรวจ error
sudo journalctl -u myapp -f --no-pager | head -20

# ดู Nginx error log
sudo tail -20 /var/log/nginx/myapp_error.log
Tip: ถ้า systemctl status myapp แสดง active (running) และ socket file มีอยู่ แต่ยังได้ 502 ให้ตรวจ group permission ของ socket — Nginx ต้องมีสิทธิ์อ่าน socket

แก้ปัญหาที่พบบ่อย

Error: 502 Bad Gateway จาก Nginx

Nginx ส่ง request ไปยัง uWSGI socket ไม่ได้ มักเกิดจาก socket permission หรือ path ไม่ตรง

# ตรวจสอบ socket มีอยู่และ Nginx อ่านได้
ls -la /tmp/myapp.sock
# ควรเห็น srwxrwx--- หรือ permission ที่ www-data อ่านได้

# แก้ permission ใน uwsgi.ini
# chmod-socket = 664
# chown-socket = appuser:www-data

# ตรวจ Nginx error log เพื่อดู error จริง
sudo tail -20 /var/log/nginx/myapp_error.log

Error: "ModuleNotFoundError" หรือ "ImportError" ตอน uWSGI start

uWSGI ไม่ได้ใช้ Python จาก virtual environment — PATH ผิดใน systemd service

# ตรวจสอบว่า virtualenv path ถูกต้องใน myapp.service
cat /etc/systemd/system/myapp.service | grep "Environment\|ExecStart"

# ต้องมี:
# Environment="PATH=/home/appuser/myapp/venv/bin"
# ExecStart=/home/appuser/myapp/venv/bin/uwsgi --ini uwsgi.ini

# ถ้าแก้ไข service file ต้อง reload daemon ก่อน
sudo systemctl daemon-reload
sudo systemctl restart myapp

Django: "DisallowedHost" error

ALLOWED_HOSTS ใน settings.py ไม่ได้ระบุ domain หรือ IP ของ server

# แก้ settings.py
ALLOWED_HOSTS = ['your-domain.com', 'www.your-domain.com', 'YOUR_SERVER_IP']

# หรือใช้ environment variable
import os
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split(',')

# Restart uWSGI หลังแก้ settings
sudo systemctl restart myapp

Django: "collectstatic" error — STATIC_ROOT ไม่ถูกตั้ง

ต้องกำหนด STATIC_ROOT ใน settings.py ก่อนรัน collectstatic

# เพิ่มใน settings.py
STATIC_ROOT = '/home/appuser/myapp/staticfiles/'
STATICFILES_DIRS = [BASE_DIR / 'static']

# รัน collectstatic
cd /home/appuser/myapp
source venv/bin/activate
python manage.py collectstatic --noinput

# ตรวจสอบว่า Nginx location /static/ ชี้ถูก path
grep -A2 "location /static" /etc/nginx/sites-available/myapp

uWSGI Crash loop — "unable to load configuration" หรือ respawn too fast

ตรวจสอบ error ใน log ก่อน บ่อยครั้งเกิดจาก syntax error ใน Python code หรือ uwsgi.ini

# รัน uWSGI manual เพื่อดู error โดยตรง
cd /home/appuser/myapp
source venv/bin/activate
uwsgi --ini uwsgi.ini

# ตรวจสอบว่า Python app import ได้
python -c "from app import app; print('OK')"  # Flask
python -c "import myproject.wsgi; print('OK')"  # Django

คำถามที่พบบ่อย

ควรใช้ uWSGI หรือ Gunicorn?

ทั้งคู่ใช้ได้ดี Gunicorn ง่ายกว่า ตั้งค่าน้อยกว่า เหมาะกับโปรเจกต์เริ่มต้น uWSGI มีฟีเจอร์มากกว่า เช่น async workers, Emperor mode จัดการหลาย app พร้อมกัน และ performance สูงกว่าในบางกรณี สำหรับ Flask/Django ทั่วไป Gunicorn ก็เพียงพอแล้ว ใช้คำสั่ง gunicorn app:app -w 4 --bind unix:/tmp/myapp.sock แทน uwsgi ได้เลย

ทำไมต้องใช้ virtual environment?

Virtual environment แยก Python packages ของแต่ละโปรเจกต์ออกจากกัน ป้องกัน version conflict เช่น App A ต้องการ Django 4.2 ส่วน App B ต้องการ Django 5.0 ถ้าไม่มี venv ทั้งสองจะใช้ Django version เดียวกัน ซึ่งทำให้หนึ่งในนั้นพัง นอกจากนี้ยังป้องกันการ install package ใน system Python ที่ Ubuntu/Debian ใช้สำหรับ system tools ด้วย

zero-downtime deploy ทำอย่างไร?

uWSGI รองรับ graceful reload ด้วย signal SIGHUP — workers ใหม่จะขึ้นมาก่อนที่ workers เก่าจะหยุดรับ request

# Graceful reload — ไม่มี downtime
sudo systemctl reload myapp
# หรือส่ง signal ตรงๆ
sudo kill -HUP $(cat /tmp/myapp.pid)