تطبيق Python: gunicorn وsystemd
تشغيل Django أو Flask أو FastAPI على VDS: البيئة الافتراضية، وgunicorn مع socket، وخدمة systemd، واختيار عدد العمال حسب مستواك.
آخر تحديث 23 أغسطس 2026
خادم التطوير المدمج (manage.py runserver، flask run) غير مصمم لأحمال الإنتاج. على VPS، تقوم بتثبيت gunicorn أو uvicorn، ويقوم خادم ويب بتقديمهما خارجيًا.
البيئة
لا تثبّت حزم المشروع في Python النظام أبدًا — فتحديث النظام سيعطّل التطبيق.
apt install -y python3 python3-venv python3-pip
useradd -r -m -d /srv/app -s /usr/sbin/nologin appuser
sudo -u appuser python3 -m venv /srv/app/venv
sudo -u appuser /srv/app/venv/bin/pip install -r /srv/app/requirements.txt
sudo -u appuser /srv/app/venv/bin/pip install gunicorn
بالنسبة إلى FastAPI، ثبّت بالإضافة إلى ذلك uvicorn[standard] — إذ يشغّله gunicorn كفئة عامل.
الخدمة
/etc/systemd/system/myapp.service:
[Unit]
Description=Python app
After=network-online.target postgresql.service
[Service]
User=appuser
WorkingDirectory=/srv/app
EnvironmentFile=/srv/app/.env
ExecStart=/srv/app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/myapp/gunicorn.sock \
--access-logfile - \
myproject.wsgi:application
RuntimeDirectory=myapp
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
بالنسبة إلى FastAPI، استبدل سطر التشغيل بـ --worker-class uvicorn.workers.UvicornWorker app.main:app.
systemctl daemon-reload
systemctl enable --now myapp
journalctl -u myapp -f
ينشئ RuntimeDirectory=myapp المسار /run/myapp بالصلاحيات المطلوبة عند كل تشغيل — وإلا فلا يوجد مكان لوضع المقبس فيه.
عدد العمال
الصيغة المعتادة هي 2 × cores + 1، لكنها تصطدم بحدود الذاكرة: إذ يستهلك كل عامل Django ما بين 80 و200 ميغابايت.
| المستوى | الأنوية | العمال |
|---|---|---|
| VDS-1 | 1 | 2 |
| VDS-2 | 2 | 3 |
| VDS-3 | 4 | 5 |
| VDS-4 | 6 | 9 |
إذا كان التطبيق يقضي وقتًا طويلًا في انتظار الشبكة وقاعدة البيانات، فأضف --threads 2 بدلًا من زيادة عدد العمليات.
خادم الويب
location / {
proxy_pass http://unix:/run/myapp/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ { alias /srv/app/static/; }
قدّم ملفات Django الثابتة مباشرة عبر Nginx بعد جمعها: collectstatic. فتمريرها عبر Python يضيف حملًا غير ضروري.
الأخطاء الشائعة
| العَرَض | السبب |
|---|---|
502 وconnect() to unix:... failed (13) | لا يملك Nginx صلاحيات على المقبس — اضبط --umask 007 ومجموعة مشتركة |
ModuleNotFoundError | التشغيل بـ Python النظام بدلًا من venv |
DisallowedHost في Django | لم يُضف النطاق إلى ALLOWED_HOSTS |
| يُقتل العمال بسبب المهلة | طلب طويل — زد --timeout، وانقل الأعمال الثقيلة إلى قائمة انتظار |
| توقف كل شيء بعد إصدار جديد | نسيت systemctl restart myapp — فالكود في الذاكرة لا يحدّث نفسه |
احفظ الأسرار في
EnvironmentFileبصلاحيات600، لا فيsettings.py. فملف الإعدادات سينتهي به المطاف في المستودع عاجلًا أو آجلًا.