ما الذي يتغيّر بين جهازك والإنتاج؟
| التطوير | الإنتاج | |
|---|---|---|
| الخادم | runserver | Gunicorn أو Uvicorn خلف Nginx |
| قاعدة البيانات | SQLite | PostgreSQL |
DEBUG | True | False |
| الملفات الثابتة | يخدمها Django | collectstatic + Nginx أو WhiteNoise |
| الأسرار | ملف .env محلّي | متغيّرات بيئة على الخادم |
| HTTPS | لا | إلزامي |
runserver خادم تطوير لعميل واحد هو أنت: لا يتحمّل الضغط، ولم يُراجَع أمنيًا. وثائق Django نفسها تقول بوضوح: لا تستخدمه في الإنتاج.
1. إعدادات الإنتاج
import os
DEBUG = os.environ.get("DJANGO_DEBUG", "") == "1"
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
ALLOWED_HOSTS = os.environ["DJANGO_ALLOWED_HOSTS"].split(",")
CSRF_TRUSTED_ORIGINS = ["https://example.com"]
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") # خلف Nginx/منصّة
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
التفاصيل الكاملة لكل إعداد أمني في درس الأمان.
2. قاعدة بيانات حقيقية
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.environ["DB_NAME"],
"USER": os.environ["DB_USER"],
"PASSWORD": os.environ["DB_PASSWORD"],
"HOST": os.environ.get("DB_HOST", "localhost"),
"PORT": os.environ.get("DB_PORT", "5432"),
"CONN_MAX_AGE": 60, # أعد استخدام الاتصال بدل فتح واحد لكل طلب
}
}
تحتاج المشغّل psycopg (pip install "psycopg[binary]"). لماذا لا SQLite؟ تعمل بملف واحد، فتُقفل عند الكتابات المتزامنة الكثيرة، ولا تتوزّع على عدّة خوادم. وتحتاج نسخًا احتياطيًا منتظمًا لقاعدة الإنتاج من اليوم الأول.
3. خادم التطبيق: Gunicorn
python -m pip install gunicorn
gunicorn mysite.wsgi:application --bind 127.0.0.1:8000 --workers 3
Gunicorn يشغّل عدّة عمّال (workers): كل واحد عملية Python تخدم طلبًا في وقت واحد. نقطة بداية شائعة: (2 × عدد الأنوية) + 1. ولتطبيق يستخدم ميزات async بكثافة، استخدم Uvicorn مع mysite.asgi:application.
وشغّله كخدمة systemd لا بـ nohup، حتى يعود تلقائيًا بعد انهيار أو إعادة إقلاع (درس الخدمات في Linux).
4. Nginx أمامه
server {
server_name example.com;
location /static/ {
alias /srv/mysite/staticfiles/; # STATIC_ROOT
}
location /media/ {
alias /srv/mysite/media/;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Nginx يخدم الملفات الثابتة مباشرة (أسرع بكثير من Python)، ويتولّى HTTPS (بشهادة مجانية من Let's Encrypt عبر certbot)، ويحمي Gunicorn من العملاء البطيئين، ويمرّر الباقي له.
5. خطوات كل نشر
git pull
python -m pip install -r requirements.txt
python manage.py migrate --noinput
python manage.py collectstatic --noinput
python manage.py check --deploy
sudo systemctl restart mysite # خدمة Gunicorn
الترتيب مهمّ: migrate قبل إعادة تشغيل الكود الجديد، لأن الكود الجديد قد يقرأ أعمدة لم تُنشأ بعد. وفي تغييرات كبيرة (حذف عمود يستخدمه الكود القديم) انشر على مرحلتين.
الطريق الأسهل: المنصّات
Render وRailway وFly.io وغيرها تتولّى الخادم وNginx وHTTPS وقاعدة PostgreSQL: تربط المستودع، وتضبط متغيّرات البيئة، وتحدّد أمر البدء (gunicorn mysite.wsgi) وأمر البناء (collectstatic وmigrate). أسرع للبداية، والمبادئ أعلاه نفسها ما زالت تنطبق. وبديل شائع آخر: حاوية Docker تشغّلها أي منصّة (مسار Docker).
قائمة التحقّق
DEBUG = FalseوALLOWED_HOSTSمحدّدة.SECRET_KEYوكلمات السر من متغيّرات البيئة.- PostgreSQL مع نسخ احتياطي.
- Gunicorn خلف Nginx كخدمة systemd.
collectstaticوmigrateفي كل نشر.- HTTPS مع إعدادات الكوكيز الآمنة.
check --deployبلا تحذيرات.- السجلّات والأخطاء مراقبة (Sentry أو ما يشبهها).
أخطاء شائعة
runserverفي الإنتاج: بطء وثغرات.- الملفات الثابتة تختفي:
collectstaticلم يُشغَّل، أو Nginx لا يشير إلىSTATIC_ROOT. - خطأ 400 بعد النشر:
ALLOWED_HOSTSلا تحتوي النطاق. - خطأ CSRF عند الدخول عبر HTTPS: أضف النطاق إلى
CSRF_TRUSTED_ORIGINS، واضبطSECURE_PROXY_SSL_HEADERخلف البروكسي. - نسيان
migrate: الكود الجديد يطلب أعمدة غير موجودة، فتظهر أخطاء 500.
🎯 التالي: نموذج المستخدم المخصّص — لماذا يجب استبداله من أول يوم.