اگر با جنگو پروژه ساخته باشید، احتمالاً مرحلهای را تجربه کردهاید که همهچیز روی سیستم خودتان عالی کار میکند، اما به محض اینکه پروژه را روی سرور میبرید، داستان عوض میشود. دیپلوی جنگو فقط انتقال فایلها به VPS و اجرای python manage.py runserver نیست؛ یک پروژه واقعی باید از نظر امنیت، اجرای برنامه، فایلهای استاتیک، پایگاه داده، لاگها و مدیریت خطا برای محیط تولید آماده شود.
من در پروژههای جنگو معمولاً قبل از اینکه سراغ انتشار نهایی بروم، چند لایه مختلف را بررسی میکنم. بعضی از این موارد ساده به نظر میرسند، اما نادیده گرفتنشان میتواند باعث خطای عجیب، افت عملکرد یا حتی یک مشکل امنیتی جدی شود.
در این مقاله یک چکلیست عملی برای دیپلوی جنگو میسازیم که بتوانید هنگام انتقال پروژه از محیط توسعه به سرور واقعی از آن استفاده کنید.

تفاوت محیط توسعه و محیط واقعی چیست؟
در محیط توسعه، هدف اصلی این است که سریع کد بنویسیم، تغییرات را ببینیم و خطاها را پیدا کنیم. به همین دلیل معمولاً DEBUG=True است، سرور توسعه Django را اجرا میکنیم و بسیاری از تنظیمات برای راحتی توسعه انتخاب میشوند.
اما محیط واقعی شرایط متفاوتی دارد.
وقتی یک سایت روی اینترنت قرار میگیرد، کاربران واقعی، رباتهای موتورهای جستجو، درخواستهای غیرمنتظره و حتی افراد مخرب میتوانند به آن دسترسی داشته باشند. بنابراین چیزی که روی لپتاپ شما کاملاً مناسب است، لزوماً انتخاب درستی برای production نیست.
یکی از اولین اشتباهات رایج همینجاست: پروژه بدون تغییر جدی از development به production منتقل میشود.
محیط تولید باید یک محیط متفاوت با تنظیمات، دسترسیها و رفتارهای مناسب خودش باشد؛ نه فقط همان پروژهای که روی کامپیوتر شخصی اجرا میشود.
۱. اول از همه DEBUG را خاموش کنید
مهمترین تنظیمی که باید قبل از انتشار بررسی کنید:
DEBUG = False
وقتی DEBUG=True باشد، Django در بسیاری از خطاها اطلاعات بسیار بیشتری از پروژه نمایش میدهد؛ اطلاعاتی که در محیط توسعه مفید هستند اما در اینترنت نباید در اختیار کاربر قرار بگیرند.
برای مثال، نمایش traceback میتواند اطلاعاتی درباره مسیر فایلها، کد برنامه، متغیرها و محیط اجرای پروژه فاش کند.
بنابراین تنظیم production باید چیزی شبیه این باشد:
DEBUG = False
ALLOWED_HOSTS = [
"example.com",
"www.example.com",
]
اگر دامنه پروژه را هنوز مشخص نکردهاید، بهتر است بهجای استفاده عجولانه از *، ساختار تنظیمات را طوری طراحی کنید که مقدار صحیح در زمان اجرا وارد شود.
۲. SECRET_KEY را داخل کد قرار ندهید
یکی دیگر از اشتباهات رایج این است که کلید محرمانه Django داخل settings.py قرار بگیرد و همان فایل نیز وارد Git شود.
بهتر است اطلاعات محرمانه از محیط اجرا دریافت شوند.
برای مثال:
import os
SECRET_KEY = os.environ["SECRET_KEY"]
سپس مقدار آن را در محیط سرور تنظیم میکنید:
export SECRET_KEY="your-production-secret-key"
در پروژههای واقعی ممکن است از فایل .env یا سیستم مدیریت secrets استفاده شود، اما نکته اصلی این است:
اطلاعات محرمانه نباید بخشی از کد منبع عمومی پروژه باشند.
همین موضوع برای رمز پایگاه داده، کلید API سرویسها و سایر اطلاعات حساس نیز صدق میکند.
۳. ALLOWED_HOSTS را درست تنظیم کنید
وقتی DEBUG=False باشد، Django به تنظیم ALLOWED_HOSTS اهمیت میدهد.
مثلاً:
ALLOWED_HOSTS = [
"example.com",
"www.example.com",
]
اگر دامنه دیگری قرار است به همان پروژه متصل شود، باید آن را نیز آگاهانه اضافه کنید.
من توصیه نمیکنم صرفاً برای اینکه خطای DisallowedHost نگیرید، این تنظیم را با ["*"] پر کنید. هر تنظیم امنیتی باید بر اساس نیاز واقعی پروژه باشد.
۴. از runserver برای سایت واقعی استفاده نکنید
این یکی از مهمترین تفاوتهای development و production است.
دستور زیر برای توسعه مناسب است:
python manage.py runserver
اما نباید آن را به عنوان سرور اصلی یک وبسایت واقعی در نظر بگیرید.
برای اجرای Django در محیط واقعی معمولاً از یک WSGI یا ASGI server استفاده میشود. یکی از انتخابهای رایج برای WSGI، Gunicorn است.
مثلاً:
gunicorn config.wsgi:application
در اینجا config نام پروژه Django شماست و ممکن است در پروژه شما نام دیگری داشته باشد.
در یک معماری رایج، درخواست کاربر ابتدا به Nginx میرسد و سپس Nginx درخواستهای مربوط به Django را به Gunicorn منتقل میکند. فایلهای استاتیک هم مستقیم از دیسک توسط Nginx سرو میشوند و اصلاً به پایتون نمیرسند:

این جداسازی باعث میشود هر بخش وظیفه مشخصی داشته باشد و کنترل بیشتری روی SSL، فایلهای استاتیک، درخواستها و اجرای برنامه داشته باشیم.
۵. فایلهای استاتیک را فراموش نکنید
یکی از مشکلات کلاسیک بعد از دیپلوی جنگو این است که سایت بالا میآید، اما CSS و JavaScript یا تصاویر نمایش داده نمیشوند.
در production باید فایلهای استاتیک را مدیریت کنید.
در تنظیمات Django معمولاً چیزی شبیه این دارید:
STATIC_URL = "/static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
بعد:
python manage.py collectstatic
Django فایلهای استاتیک را در STATIC_ROOT جمع میکند تا وبسرور بتواند آنها را ارائه کند.
نکته مهم این است که Django development server در زمان توسعه بسیاری از این کارها را برای شما ساده میکند؛ اما در production باید مسیر ارائه فایلها را آگاهانه تنظیم کنید.
مثلاً Nginx میتواند درخواستهای /static/ را مستقیماً پاسخ دهد و لازم نباشد هر فایل استاتیک از داخل Django عبور کند.
۶. HTTPS را جدی بگیرید
اگر سایت شما ورود کاربران، پنل مدیریت، session یا هر نوع اطلاعات حساس دارد، استفاده از HTTPS عملاً یک ضرورت است.
گواهی SSL فقط برای نمایش یک قفل کنار آدرس سایت نیست. HTTPS ارتباط بین مرورگر کاربر و سرور را رمزنگاری میکند و از افشای اطلاعات حساس در مسیر جلوگیری میکند.
بعد از راهاندازی HTTPS، تنظیمات امنیتی Django نیز باید متناسب با معماری پروژه بررسی شوند.
برای مثال:
SECURE_SSL_REDIRECT = True
البته اگر HTTPS در لایه دیگری مدیریت میشود، باید تنظیمات proxy و headerها نیز درست باشند. نباید یک تنظیم امنیتی را بدون توجه به معماری سرور کپی کرد.
۷. پایگاه داده را بخشی از دیپلوی بدانید
دیپلوی موفق فقط بالا آمدن صفحه اصلی نیست.
باید مطمئن شوید migrationها اجرا شدهاند:
python manage.py migrate
همچنین اطلاعات اتصال به پایگاه داده نباید داخل کد hard-code شوند.
برای مثال:
import os
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["DB_HOST"],
"PORT": os.environ.get("DB_PORT", "5432"),
}
}
و مهمتر از همه، برای پایگاه داده واقعی backup داشته باشید.
ممکن است برنامه کاملاً سالم باشد، اما یک اشتباه انسانی، خرابی دیسک یا مشکل سرور باعث از دست رفتن دادهها شود. داشتن backup بخشی از deployment است، نه کاری که باید بعداً به آن فکر کنیم.
۸. قبل از انتشار، check --deploy را اجرا کنید
خود Django ابزاری برای بررسی بخشی از تنظیمات deployment دارد:
python manage.py check --deploy
این دستور جای بررسی انسانی را نمیگیرد، اما میتواند برخی مشکلات متداول را پیدا کند.
من پیشنهاد میکنم این دستور را به بخشی از فرآیند انتشار پروژه تبدیل کنید، نه اینکه فقط یک بار قبل از اولین دیپلوی اجرا شود.
اگر پروژه چند محیط دارد، مهم است که این بررسی با تنظیمات واقعی production انجام شود.
۹. لاگ و خطاها را قابل مشاهده کنید
یکی از بدترین وضعیتها این است که سایت خراب شود و شما فقط بدانید:
500 Internal Server Error
اما ندانید چرا.
در production باید برای خطاها و اتفاقات مهم logging داشته باشید.
یک نمونه ساده:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {
"class": "logging.StreamHandler",
},
},
"root": {
"handlers": ["console"],
"level": "INFO",
},
}
در پروژههای جدیتر میتوان از ابزارهای monitoring و error tracking نیز استفاده کرد تا خطاها، tracebackها و رخدادهای مهم بهتر قابل پیگیری باشند.
این موضوع وقتی اهمیت بیشتری پیدا میکند که پروژه دیگر یک سایت شخصی کوچک نباشد و کاربران واقعی دائماً از آن استفاده کنند.
۱۰. امنیت را فقط به Django محدود نکنید
Django بسیاری از قابلیتهای امنیتی را در اختیار شما قرار میدهد، اما امنیت کل سیستم فقط به framework وابسته نیست.
اگر پروژه روی VPS اجرا میشود، باید خود سرور، Nginx، SSH، پایگاه داده، firewall، دسترسی فایلها و سرویسهای در حال اجرا نیز بررسی شوند.
برای مثال، اگر PostgreSQL یا MySQL فقط باید توسط خود برنامه قابل دسترسی باشد، منطقی نیست پورت پایگاه داده را بدون نیاز برای کل اینترنت باز بگذارید.
همین تفکر برای Redis، پنلهای مدیریتی و سایر سرویسها نیز کاربرد دارد:
هر سرویسی که از اینترنت قابل دسترسی نیست، بهتر است اصلاً از اینترنت قابل دسترسی نباشد.
در پروژههایی که کارهای پسزمینه دارند، ممکن است Celery و Redis نیز به همین معماری اضافه شوند؛ قاعده همان است: فقط Nginx رو به اینترنت، بقیه پشت آن.
سه اشتباهی که روی سرور خودم پیدا کردم
چکلیستها وقتی ارزش پیدا میکنند که یک بار جای خالیشان را حس کرده باشید. این سه مورد را همین اواخر روی سرور همین سایت پیدا کردم؛ سایتی که «کار میکرد» و هیچ خطایی نشان نمیداد.
ارسال فرم ۸.۸ ثانیه طول میکشید
فرم تماس سایت کار میکرد، اما کاربر بعد از زدن دکمهی ارسال تقریباً ۹ ثانیه منتظر میماند. دلیلش این بود که ایمیل اطلاعرسانی داخل خود درخواست از طریق SMTP جیمیل فرستاده میشد؛ یعنی پاسخ به کاربر تا وقتی جیمیل جواب نمیداد برنمیگشت.
راهحل: اول اطلاعات فرم در پایگاه داده ذخیره میشود، پاسخ فوراً به کاربر برمیگردد و ایمیل در پسزمینه ارسال میشود. اگر ایمیل هم شکست بخورد، پیام کاربر از دست نمیرود.
هر کاری که به یک سرویس بیرونی وابسته است (ایمیل، پیامک، API) نباید کاربر را منتظر نگه دارد.
لاگها فقط یک هفته میماندند
یکی از دوستانم گزارش داد که فرم شروع پروژه برایش ثبت نشده. وقتی رفتم علت را پیدا کنم، لاگ آن روز دیگر وجود نداشت؛ لاگهای سرور فقط حدود یک هفته نگه داشته میشدند.
راهحل: هشدارها و خطاهای Django حالا علاوه بر لاگ سیستم، در یک فایل جداگانه با چرخش خودکار ذخیره میشوند که چند ماه سابقه دارد، و هر فرمی که رد شود، دلیل دقیقش ثبت میشود.
آپدیتهای امنیتی خاموش بودند
روی سرور، آپدیت خودکار نصب بود اما در تنظیماتش غیرفعال شده بود. نتیجه: ۸۹ بستهی امنیتی، از جمله OpenSSH و Nginx، بیصدا منتظر نصب مانده بودند.
راهحل: آپدیت خودکار فقط برای وصلههای امنیتی فعال شد و یک بررسی دورهای به کارهای نگهداری اضافه شد.
هیچکدام از این سه مورد سایت را از کار نینداخته بود. همین خطرناکشان میکند: تا روزی که لازمشان داشته باشید، دیده نمیشوند.
چکلیست نهایی دیپلوی جنگو قبل از انتشار
قبل از اینکه بگویم «پروژه آماده است»، معمولاً این موارد را بررسی میکنم:
| مورد | وضعیت مورد انتظار |
|---|---|
DEBUG |
False |
SECRET_KEY |
خارج از کد و امن |
ALLOWED_HOSTS |
محدود به دامنههای موردنیاز |
| HTTPS | فعال |
| Web Server | Nginx یا معادل آن |
| Application Server | Gunicorn / ASGI server |
| Database | تنظیم و migration شده |
| Static files | collectstatic اجرا شده |
| Media files | مسیر و دسترسی صحیح |
| Backup | فعال و قابل بازیابی |
| Logging | قابل بررسی و ماندگار |
| ارسال ایمیل و API | خارج از مسیر درخواست |
| آپدیت امنیتی سرور | خودکار |
| Deployment check | check --deploy اجرا شده |
اگر پروژه شما قرار است جدیتر از یک نمونه آموزشی باشد، همین چکلیست ساده میتواند جلوی تعداد زیادی از مشکلات معمول را بگیرد.
اگر توسعه وب و ساخت پروژههای Django بخش اصلی کار شماست، میتوانید نمونه خدمات توسعه وب من را نیز در صفحه توسعه وب ببینید.
سؤالات متداول
آیا میتوان Django را با runserver روی سرور اجرا کرد؟
برای محیط توسعه بله، اما برای یک سایت واقعی انتخاب مناسبی نیست. در production بهتر است Django پشت یک application server مانند Gunicorn یا یک سرور ASGI مناسب و معمولاً پشت Nginx اجرا شود.
آیا DEBUG=False به تنهایی پروژه Django را امن میکند؟
خیر. خاموش کردن DEBUG ضروری است، اما امنیت پروژه به موارد بسیار بیشتری مانند مدیریت secrets، HTTPS، تنظیمات host، پایگاه داده، سرور، دسترسیها و وابستگیهای نرمافزاری بستگی دارد.
قبل از دیپلوی Django چه دستوری باید اجرا کنم؟
یکی از بررسیهای رسمی Django این دستور است:
python manage.py check --deploy
این دستور بخشی از تنظیمات deployment را بررسی میکند، اما جایگزین یک بررسی کامل امنیتی و عملیاتی پروژه نیست.
جمعبندی
دیپلوی جنگو را نباید به «کپی کردن پروژه روی VPS و اجرای آن» محدود کرد. یک deployment خوب یعنی برنامه، سرور، پایگاه داده، فایلهای استاتیک، امنیت، HTTPS، logging و backup همگی در کنار یکدیگر درست کار کنند.
من اگر بخواهم فقط یک توصیه از این مقاله بدهم، این است: قبل از اینکه پروژه را در اختیار کاربران واقعی قرار دهید، production را مثل یک محیط کاملاً متفاوت از سیستم توسعه در نظر بگیرید. همین تغییر نگرش بسیاری از خطاهای رایج deployment را از همان ابتدا حذف میکند.
