فصل ۸: تست، استقرار و پروژه‌ی پایانی

استقرار روی اوبونتو (۱): PostgreSQL، gunicorn و systemd

از runserver تا سرور واقعی

runserver فقط برای توسعه است: تک‌پروسه، بدون امنیت و کارایی لازم. معماری استاندارد استقرار جنگو روی لینوکس این است: nginx جلوی همه (HTTPS، فایل‌های static و media، محدودیت حجم)، gunicorn با چند worker برای اجرای کد پایتون، PostgreSQL به‌عنوان پایگاه داده و systemd برای روشن نگه داشتن همه‌چیز. در این درس سه لایه‌ی اول پشتی را می‌سازیم؛ درس بعد nginx و HTTPS.

۱. آماده‌سازی سرور

sudo apt update
sudo apt install -y python3.12-venv python3-dev build-essential libpq-dev \
    postgresql nginx redis-server git
sudo adduser --system --group --home /srv/carpet carpet

برنامه با یک کاربر سیستمی بدون دسترسی root اجرا می‌شود؛ اگر روزی آسیب‌پذیری در کد باشد، مهاجم به کل سرور دسترسی ندارد.

۲. PostgreSQL

sudo -u postgres psql <<'SQL'
CREATE USER carpet WITH PASSWORD 'a-long-random-password';
CREATE DATABASE carpet OWNER carpet ENCODING 'UTF8';
ALTER ROLE carpet SET timezone TO 'UTC';
SQL
# settings.py
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": os.getenv("DB_NAME", "carpet"),
        "USER": os.getenv("DB_USER", "carpet"),
        "PASSWORD": os.getenv("DB_PASSWORD"),
        "HOST": os.getenv("DB_HOST", "127.0.0.1"),
        "PORT": "5432",
        "CONN_MAX_AGE": 60,                 # استفاده‌ی مجدد از اتصال
        "CONN_HEALTH_CHECKS": True,
    }
}

۳. کد، venv و مهاجرت

sudo -u carpet -H bash
cd /srv/carpet
git clone https://git.example.ir/team/carpet.git app
cd app
python3.12 -m venv .venv
.venv/bin/pip install -r requirements.txt gunicorn "psycopg[binary]"
nano .env                                  # DJANGO_DEBUG=0 و بقیه
.venv/bin/python manage.py migrate
.venv/bin/python manage.py collectstatic --noinput
.venv/bin/python manage.py check --deploy

۴. gunicorn با systemd

# /etc/systemd/system/carpet.socket
[Unit]
Description=carpet gunicorn socket

[Socket]
ListenStream=/run/carpet.sock
SocketUser=www-data

[Install]
WantedBy=sockets.target

# /etc/systemd/system/carpet.service
[Unit]
Description=carpet gunicorn
Requires=carpet.socket
After=network.target postgresql.service

[Service]
User=carpet
Group=carpet
WorkingDirectory=/srv/carpet/app
EnvironmentFile=/srv/carpet/app/.env
ExecStart=/srv/carpet/app/.venv/bin/gunicorn config.wsgi:application \
    --workers 3 --timeout 60 --max-requests 1000 --max-requests-jitter 100 \
    --access-logfile -
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now carpet.socket carpet.service
sudo systemctl status carpet
journalctl -u carpet -n 50 --no-pager

نکته‌هایی که کمتر کسی می‌داند

  • تعداد worker معمول 2 × هسته + 1 است، اما روی VPSهای کم‌حافظه‌ی ایرانی حافظه محدودکننده است نه CPU؛ هر worker جنگو ۸۰ تا ۱۵۰ مگابایت می‌گیرد.
  • --max-requests هر worker را پس از چند صد درخواست بازسازی می‌کند؛ درمان ساده و مؤثر نشت حافظه‌ی تدریجی کتابخانه‌ها.
  • systemctl reload carpet (سیگنال HUP) workerها را بدون قطع درخواست‌های در جریان عوض می‌کند؛ برای استقرار نسخه‌ی جدید به‌جای restart از آن استفاده کنید.
  • با socket activation، systemd سوکت را نگه می‌دارد و در لحظه‌ی restart درخواست‌ها در صف می‌مانند و 502 نمی‌گیرند.
  • در ایران برای pip روی سرور، میرور داخلی را در /etc/pip.conf تنظیم کنید و برای apt هم از مخزن‌های آینه‌ی داخلی استفاده کنید؛ نصب‌ها از ده دقیقه به چند ثانیه می‌رسند.

برای ذخیره‌ی پیشرفت و شرکت در آزمون، وارد شوید — رایگان است.