Milad Mobaseri
enfa
معماری سه‌بعدی استقرار یک پروژه جنگو روی سرور
جنگو

چک‌لیست دیپلوی جنگو برای محیط واقعی

دیپلوی جنگو فقط اجرای پروژه روی سرور نیست. در این راهنما مهم‌ترین تنظیمات امنیتی، Gunicorn، Nginx، فایل‌های استاتیک، متغیرهای محیطی و بررسی‌های لازم قبل از انتشار را مرور می‌کنیم.

اگر با جنگو پروژه ساخته باشید، احتمالاً مرحله‌ای را تجربه کرده‌اید که همه‌چیز روی سیستم خودتان عالی کار می‌کند، اما به محض اینکه پروژه را روی سرور می‌برید، داستان عوض می‌شود. دیپلوی جنگو فقط انتقال فایل‌ها به 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 سرو می‌شوند و اصلاً به پایتون نمی‌رسند:

معماری Nginx، Gunicorn، Django و PostgreSQL در محیط تولید

این جداسازی باعث می‌شود هر بخش وظیفه مشخصی داشته باشد و کنترل بیشتری روی 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 را از همان ابتدا حذف می‌کند.

#دیپلوی#جنگو#پایتون#سرور#توسعه وب