چگونه یک برنامهٔ Django مبتنی بر ASGI را همراه با Postgres، Nginx و Uvicorn در Ubuntu 20.04 راه‌اندازی کنیم؟

Django یک فریم‌ورک قدرتمند وب است که می‌تواند به شما کمک کند تا برنامه یا وب‌سایت پایتون خود را به سرعت راه‌اندازی کنید. Django شامل یک سرور توسعه ساده برای تست کدهای شما به صورت محلی است، اما برای محیط‌های production نیاز به یک وب‌سرور امن‌تر و قدرتمندتر دارید.

روش سنتی برای استقرار یک برنامه Django استفاده از Web Server Gateway Interface (WSGI) است. اما با ظهور Python 3 و پشتیبانی از اجرای asynchronous، اکنون می‌توانید برنامه‌های پایتون خود را از طریق asynchronous callables با یک Asynchronous Server Gateway Interface (ASGI) اجرا کنید. ASGI که جانشین WSGI است، یک سوپرست از WSGI محسوب می‌شود و می‌تواند جایگزین مستقیم آن باشد.

Django اجازه می‌دهد حالت “async outside, sync inside”، به این معنا که کد شما به صورت همزمان (synchronous) درون برنامه اجرا شود، اما سرور ASGI درخواست‌ها را به صورت غیرهمزمان (asynchronously) مدیریت کند. این روش به وب‌سرور اجازه می‌دهد تا بتواند چندین رویداد ورودی و خروجی را برای هر برنامه به صورت همزمان پردازش کند. از آنجا که برنامه Django به صورت داخلی همزمان است، سازگاری با کدهای قدیمی حفظ می‌شود و از پیچیدگی‌های پردازش موازی جلوگیری می‌شود. بنابراین برای تغییر از WSGI به ASGI نیاز به تغییر در کدهای Django خود ندارید.

در این راهنما، شما برخی کامپوننت‌ها را روی Ubuntu 20.04 نصب و کانفیگ خواهید کرد تا بتوانید برنامه‌های Django را اجرا کنید. شما به جای استفاده از دیتابیس پیش‌فرض SQLite، یک دیتابیس PostgreSQL راه‌اندازی خواهید کرد. سرور برنامه Gunicorn به همراه Uvicorn به عنوان پیاده‌سازی ASGI برای اجرای برنامه‌های شما به صورت غیرهمزمان تنظیم خواهد شد. سپس Nginx را برای reverse proxy به سمت Gunicorn کانفیگ می‌کنید تا بتوانید از امکانات امنیتی و بهینه‌سازی آن استفاده نمایید.

برای تکمیل این آموزش به موارد زیر نیاز دارید:

ابتدا باید موارد موردنیاز را از مخازن اوبونتو دانلود و نصب کنید. برخی کامپوننت‌ها بعداً توسط pip نصب می‌شوند.

ابتدا با دستور زیر شاخص بسته‌های apt را بروزرسانی کنید و سپس بسته‌های موردنیاز را نصب نمایید. بسته‌های مورد نیاز بستگی به نسخه Python پروژه شما دارد.

برای نصب بسته‌های سیستم از دستور زیر استفاده کنید (دقت کنید تغییر ندهید):

sudo apt update
sudo apt install python3-venv python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx

این دستور کتابخانه‌های Python برای ایجاد virtual environment، سیستم دیتابیس Postgres و کتابخانه‌های مورد نیاز برای اتصال به آن و سرور وب Nginx را نصب می‌کند.

بعد از آن، یک دیتابیس و یوزر برای پروژه Django ایجاد خواهید کرد.

به صورت پیش‌فرض، Postgres برای ارتباط‌های لوکال از روش authentication به نام “peer authentication” استفاده می‌کند. یعنی اگر نام کاربری سیستم عامل شما با یک نام کاربری معتبر در Postgres مطابقت داشته باشد، بدون نیاز به ورودی مجدد به دیتابیس متصل می‌شوید.

در طول نصب Postgres، یک کاربر سیستم به نام postgres ساخته شده که معادل کاربر مدیریتی دیتابیس Postgres است. برای انجام کارهای مدیریتی باید از این کاربر استفاده کنید. می‌توانید با sudo و گزینه -u آن را اجرا کنید.

برای ورود به محیط تعاملی Postgres تایپ کنید:

sudo -u postgres psql

در پرامپت PostgreSQL می‌توانید دستورات زیر را اجرا کنید.

ابتدا یک دیتابیس جدید برای پروژه خود بسازید:

CREATE DATABASE myproject;

توجه: هر دستور Postgres باید با ; پایان یابد. اگر به مشکل خوردید، حتماً این موضوع را چک کنید.

سپس یک کاربر دیتابیس جدید بسازید و برای آن پسورد ایمن تعیین کنید:

CREATE USER myprojectuser WITH PASSWORD 'password';

حالا پارامترهای اتصال را برای این کاربر تنظیم می‌کنید تا عملیات دیتابیس سریع‌تر انجام شود و نیازی به تنظیم مجدد در هر ارتباط نباشد.

رمزگذاری پیش‌فرض را روی UTF-8 قرار دهید که Django انتظار دارد. سطح ایزولاسیون تراکنش را به “read committed” تنظیم می‌کنید که از خواندن اطلاعات مربوط به تراکنش‌های تایید نشده جلوگیری می‌کند. همچنین منطقه زمانی را UTC قرار دهید که به عنوان پیش‌فرض برای پروژه Django مناسب است. این تنظیمات براساس توصیه‌های رسمی پروژه Django است:

ALTER ROLE myprojectuser SET client_encoding TO 'utf8';
ALTER ROLE myprojectuser SET default_transaction_isolation TO 'read committed';
ALTER ROLE myprojectuser SET timezone TO 'UTC';

حالا به کاربر ساخته شده دسترسی مدیریت دیتابیس را بدهید:

GRANT ALL PRIVILEGES ON DATABASE myproject TO myprojectuser;

کار شما پایان یافته است، با دستور زیر از پرامپت PostgreSQL خارج شوید:

\q

حال Postgres برای اتصال و مدیریت دیتابیس توسط Django آماده است.

پس از آماده شدن دیتابیس، به نصب فایل‌های موردنیاز پروژه می‌پردازید. برای مدیریت آسان‌تر وابستگی‌های Python، تمامی نیازمندی‌ها را در یک virtual environment نصب می‌کنیم.

ابتدا یک پوشه برای نگهداری فایل‌های پروژه ایجاد کنید و وارد آن شوید:

mkdir ~/myprojectdir
cd ~/myprojectdir

سپس با ابزار ساخته شده در Python یک virtual environment ایجاد کنید:

python3 -m venv myprojectenv

این دستور پوشه‌ای به نام myprojectenv داخل myprojectdir می‌سازد و نسخه محلی Python و pip را نصب می‌کند. با این محیط، می‌توانید پروژه خود را به طور ایزوله مدیریت کنید.

برای نصب بسته‌های موردنیاز پروژه باید virtual environment را فعال کنید:

source myprojectenv/bin/activate

پیش‌نمایش ترمینال شما به شکل زیر تغییر می‌کند و نشان‌دهنده فعال بودن virtual environment است:

(myprojectenv) user@host:~/myprojectdir$

در این محیط، Django را نصب می‌کنید. نصب Django درون virtual environment باعث می‌شود پروژه‌ها و وابستگی‌های آن‌ها به صورت جداگانه مدیریت شوند. ضمن فعال بودن محیط، دستورات زیر را اجرا کنید:

pip install django gunicorn uvicorn psycopg2-binary

نکته: هنگام فعال بودن محیط مجازی (وقتی پرامپت، (myprojectenv) را نشان دهد) همیشه از pip به جای pip3 استفاده کنید. نام pip در محیط مجازی مستقل از نسخه Python است و فرقی ندارد.

حالا تمام نرم‌افزارهای موردنیاز برای ایجاد پروژه Django آماده هستند.

پس از نصب کامپوننت‌های Python، می‌توانید پروژه دجانگو را بسازید.

چون یک دایرکتوری پروژه دارید، دستور می‌دهید فایل‌ها در آنجا نصب شود. Django در داخل آن یک دایرکتوری درجه دوم برای کدها می‌سازد و یک اسکریپت مدیریت در سطح بالا ایجاد می‌کند که طبیعی است:

django-admin startproject myproject .

اکنون دایرکتوری پروژه شما (~/myprojectdir) شامل فایل‌های زیر خواهد بود:

  • manage.py
  • دایرکتوری myproject/ که کد اصلی در آن است

حالا باید تنظیمات پروژه را اصلاح کنید. فایل تنظیمات را در ویرایشگر متن باز کنید:

nano myproject/settings.py

ابتدا به دنبال متغیر ALLOWED_HOSTS بگردید. این متغیر شامل لیستی از آدرس‌ها یا دامنه‌های سروری است که می‌توانند به برنامه متصل شوند. هر درخواستی که Host آن در این لیست نباشد باعث بروز Exception در برنامه Django خواهد شد. این تنظیم برای افزایش امنیت ضروری است.

درون کروشه‌ها، آدرس‌های IP یا دامنه‌های سرور خود را وارد کنید. هر آیتم را درون کوتیشن و با کاما از هم جدا نمایید. برای مجاز کردن کل دامنه و زیر دامنه‌ها، یک نقطه قبل از نام دامنه قرار دهید. مثال‌ها در فایل به صورت کامنت هستند.

نکته: حتماً localhost را در این لیست وارد کنید چون اتصال‌ها از طریق Nginx به لوکال هدایت می‌شوند.

بعد به دنبال بخش دیتابیس‌ها بگردید که با DATABASES مشخص شده است. مقدار پیش‌فرض برای SQLite است. چون دیتابیس PostgreSQL ساخته‌اید، تنظیمات این بخش را تغییر دهید.

مقادیر زیر را با مشخصات دیتابیس PostgreSQL خود جایگزین کنید. در اینجا از psycopg2 که نصب کردید برای اتصال استفاده می‌شود و موقعیت سرور را لوکال (localhost) قرار می‌دهیم:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'myproject',
        'USER': 'myprojectuser',
        'PASSWORD': 'password',
        'HOST': 'localhost',
        'PORT': '',
    }
}

سپس به انتهای فایل بروید و مسیر پوشه‌ای برای فایل‌های static اضافه کنید تا Nginx بتواند آن‌ها را سرو کند. مسیر پیشنهادی، پوشه‌ای به نام static در دایرکتوری پروژه است:

STATIC_ROOT = BASE_DIR / "static"

فایل را ذخیره و ببندید.

اکنون می‌توانید اسکیما اولیه دیتابیس را روی PostgreSQL اعمال کنید:

python manage.py migrate

یک کاربر مدیریتی ایجاد کنید:

python manage.py createsuperuser

نام کاربری، ایمیل و رمز عبور را وارد کنید.

تمام فایل‌های static را جمع‌آوری کنید تا در مسیر مشخص شده قرار بگیرند (برای Nginx):

python manage.py collectstatic

برای استفاده از سرور توسعه باید پورت 8000 را در فایروال باز کنید:

sudo ufw allow 8000

حالا برای تست پروژه، سرور توسعه Django را اجرا کنید:

python manage.py runserver 0.0.0.0:8000

مرورگر خود را باز کنید و به دامنه یا IP سرور به همراه پورت 8000 بروید. صفحه پیش‌فرض Django را مشاهده خواهید کرد.

افزودن /admin به انتهای آدرس، شما را به صفحه ورود مدیریت هدایت می‌کند. با نام کاربری و رمز ایجاد شده وارد شوید و به پنل ادمین دسترسی خواهید داشت.

برای توقف سرور توسعه، در ترمینال Ctrl+C را فشار دهید.

در این آموزش از Gunicorn و Uvicorn برای اجرای برنامه استفاده می‌کنید. اگرچه Gunicorn معمولاً برای WSGI استفاده می‌شود، اما رابطی برای استفاده با ASGI با workerهای uvicorn دارد. از آنجایی که Gunicorn محصول کاملی است و امکانات بیشتری نسبت به Uvicorn دارد، توصیه می‌شود برای مدیریت فرآیندها از ترکیب gunicorn با worker uvicorn استفاده کنید.

قبل از خارج شدن از محیط مجازی، Gunicorn را برای اطمینان از عملکرد تست کنید:

gunicorn myproject.asgi:application -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000

این دستور Gunicorn را روی همان آدرس اجرای سرور توسعه اجرا می‌کند و می‌توانید دوباره تست کنید.

نکته: اگر بخواهید فقط از uvicorn استفاده کنید، دستور زیر را اجرا کنید:

uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000

توجه کنید که در این حالت، پنل ادمین استایل خود را نمایش نمی‌دهد زیرا Gunicorn نمی‌داند فایل‌های static در کجا قرار دارند.

اگر صفحات Django ظاهر شدند، یعنی Gunicorn به درستی کار می‌کند. با فرمان gunicorn، ماژول asgi.py پروژه Django که نقطه ورود برنامه است بارگذاری می‌شود. در این ماژول یک تابع application تعریف شده که برای ارتباط با برنامه استفاده می‌شود.

پس از اتمام تست، با Ctrl+C پروسه Gunicorn را متوقف کنید و سپس محیط مجازی را با دستور زیر ترک کنید:

deactivate

شاخص (نماد) محیط مجازی از پرامپت حذف خواهد شد.

در بخش بعد، برای کنترل بهتر اجرای Gunicorn باید فایل‌های systemd برای سرویس و سوکت ایجاد کنید. سوکت Gunicorn در بوت ساخته می‌شود و منتظر اتصال می‌ماند. وقتی اتصال ایجاد شود، systemd به‌صورت خودکار فرآیند Gunicorn را برای هندل کردن درخواست شروع می‌کند.

ابتدا با دسترسی sudo فایل سوکت systemd را بسازید و باز کنید:

sudo nano /etc/systemd/system/gunicorn.socket

داخل فایل، بخش‌های [Unit] برای توصیف سوکت، [Socket] برای تعیین آدرس سوکت و [Install] برای فعال کردن سوکت در زمان بوت را بنویسید.

فایل را ذخیره و ببندید.

سپس فایل سرویس systemd برای Gunicorn را با نام مشابه (به‌جز پسوند) بسازید و باز کنید:

sudo nano /etc/systemd/system/gunicorn.service

در بخش [Unit] اطلاعات متادیتا و وابستگی‌ها را وارد می‌کنید. توضیحی برای سرویس داده و می‌گویید فقط باید بعد از بالا آمدن شبکه اجرا شود. چون سرویس از سوکت استفاده می‌کند، باید Requires سوکت را مشخص کنید.

در بخش [Service] کاربر و گروهی که سرویس اجرا می‌شود را تعیین کنید. کاربر عادی خودتان به دلیل مالکیت فایل‌ها و گروه www-data برای دسترسی Nginx مناسب است.

دایرکتوری کاری و دستور شروع سرویس را وارد کنید. باید مسیر کامل Gunicorn در virtual environment را بنویسید. همچنین Gunicorn را به سوکت یونیکس اختصاصی متصل می‌کنید که در /run ساخته می‌شود تا با Nginx ارتباط برقرار شود. لاگ‌ها را به خروجی استاندارد هدایت کنید تا systemd آن‌ها را جمع‌آوری کند. می‌توانید تعداد workerها را هم تعریف کنید:

بخش [Install] هم برای فعال شدن سرویس در راه‌اندازی سیستم است.

فایل را ذخیره و ببندید.

حال سوکت Gunicorn را فعال و شروع کنید. این کار سوکت را در /run/gunicorn.sock ایجاد می‌کند و در بوت نیز فعال می‌ماند. با دریافت اتصال، سرویس gunicorn.service فعال می‌شود:

sudo systemctl start gunicorn.socket
sudo systemctl enable gunicorn.socket

برای اطمینان از صحت، می‌توانید وضعیت پردازش را بررسی کنید:

sudo systemctl status gunicorn.socket

وجود فایل /run/gunicorn.sock را هم بررسی کنید:

ls -l /run/gunicorn.sock

اگر خطایی وجود دارد یا فایل سوکت ساخته نشده، با Logs سیستم مشکل را بررسی کنید:

journalctl -u gunicorn.socket

سوکت از طریق systemctl فعال است اما ممکن است سرویس هنوز به علت نداشتن اتصال غیرفعال باشد. وضعیت آن را چک کنید:

sudo systemctl status gunicorn.service

اتصال سوکت را می‌توانید با دستور curl شبیه‌سازی کنید:

curl --unix-socket /run/gunicorn.sock http://localhost

اگر خروجی HTML برنامه را دریافت کردید یعنی سرویس به درستی کار می‌کند. وضعیت سرویس را بررسی کنید:

sudo systemctl status gunicorn.service

اگر مشکلی دارید، لاگ‌ها را بررسی کنید و فایل‌های سوکت و سرویس systemd را دوباره مرور نمایید. پس از اعمال تغییرات باید systemd را مجدداً بارگذاری و سرویس را ری‌استارت کنید:

sudo systemctl daemon-reload
sudo systemctl restart gunicorn.service

حال باید Nginx را برای پروکسی کردن ترافیک به سمت Gunicorn تنظیم کنید تا از امکانات امنیتی و بهینه آن استفاده شود.

یک فایل کانفیگ در sites-available نگیرید و باز کنید:

sudo nano /etc/nginx/sites-available/myproject

داخل آن بخش سرور را تعریف کنید تا روی پورت 80 گوش دهد و به دامنه یا IP شما پاسخ دهد:

نحوه مدیریت favicon و فایل‌های static که در ~/myprojectdir/static قرار دارند را مشخص کنید. این فایل‌ها با پیشوند URI /static فراخوانی می‌شوند:

location /static/ {
    alias /home/username/myprojectdir/static/;
}

بلاک location / را برای سایر درخواست‌ها ایجاد کرده و ترافیک را به سوکت Gunicorn ارسال کنید:

location / {
    include proxy_params;
    proxy_pass http://unix:/run/gunicorn.sock;
}

فایل را ذخیره و ببندید.

اکنون فایل را با ایجاد لینک در sites-enabled فعال کنید:

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled/

پیکربندی Nginx را برای خطا سنجی تست کنید:

sudo nginx -t

اگر خطایی گزارش نشد، Nginx را ری‌استارت کنید:

sudo systemctl restart nginx

همچنین فایروال را برای پورت 80 مجاز کنید و پورت 8000 را که قبلاً برای تست باز کردید ببندید:

sudo ufw allow 80
sudo ufw delete allow 8000

اکنون با رفتن به دامنه یا IP سرور، باید صفحه خوش آمدگویی Django با تصویر را مشاهده نمایید.

نکته: برای امنیت بهتر، توصیه می‌شود ترافیک خود را با استفاده از SSL/TLS ایمن کنید. بهترین روش استفاده از Let’s Encrypt است. راهنمای نصب Let’s Encrypt با Nginx روی Ubuntu 20.04 را دنبال کنید.

اگر در این مرحله برنامه نشان داده نشد، باید نصب و تنظیمات را بررسی کنید. نمایش صفحه پیش‌فرض Nginx معمولاً به علت تنظیم نادرست server_name در فایل /etc/nginx/sites-available/myproject است. server_name باید دامنه یا IP شما باشد. چون Nginx بر اساس server_name تعیین می‌کند کدام بلاک کانفیگ پاسخ دهد. اگر این مقدار مناسب نباشد، به صفحه پیش‌فرض fallback می‌شود.

خطای 502 به معنی ناتوانی Nginx برای پروکسی کردن درست درخواست است که دلایل متنوعی دارد. برای تشخیص مشکل باید لاگ خطاهای Nginx را ببینید:

sudo tail -f /var/log/nginx/error.log

یکی از ارورهای رایج، نبود فایل gunicorn.sock در مسیر معین است. بررسی کنید proxy_pass در فایل Nginx با محل واقعی این فایل در /run مطابقت داشته باشد.

عدم وجود فایل نشان می‌دهد سوکت systemd برای Gunicorn ساخته نشده. بخش سوکت Gunicorn را مجدداً بررسی و رفع اشکال کنید.

ممکن است خطای دسترسی به سوکت هم داشته باشید که معمولاً به دلیل مجوزهای فایل و مالکیت آن توسط root به جای یک کاربر sudo اتفاق می‌افتد. مجوزها و مالکیت سوکت و دایرکتوری‌های والد را بررسی کنید:

namei -l /run/gunicorn.sock

این دستور جزئیات مجوزها و مالک هر سطح دایرکتوری را نشان می‌دهد. اگر مجوزهای خواندن و اجرای مناسب روی مسیر نباشد، Nginx نمی‌تواند به سوکت دسترسی داشته باشد. می‌توانید حقوق خواندن و اجرای عمومی (r-x) یا گروهی که Nginx در آن باشد نصب کنید.

اگر هنگام دسترسی به بخش‌هایی از برنامه پیام خطایی دریافت کردید که نشان می‌دهد Django به دیتابیس وصل نمی‌شود، باید از اجرای Postgres مطمئن شوید:

sudo systemctl status postgresql

اگر اجرا نمی‌شود، استارت و فعال کنید تا در بوت اجرا شود:

sudo systemctl start postgresql
sudo systemctl enable postgresql

اگر هنوز مشکل دارید، تنظیمات دیتابیس در myproject/settings.py را دوباره چک کنید.

برای عیب‌یابی بهتر، این لاگ‌ها می‌توانند کمک کنند:

  • لاگ‌های Gunicorn و Uvicorn
  • لاگ‌های Nginx
  • لاگ‌های Django

هرگاه تغییراتی در پروژه یا سرویس‌ها دادید، با دستورات زیر آن‌ها را ری‌استارت یا reload کنید:

sudo systemctl restart gunicorn.service
sudo systemctl daemon-reload
sudo systemctl restart gunicorn.service
sudo nginx -t
sudo systemctl restart nginx

این دستورات به شما کمک می‌کنند تنظیمات جدید را بارگذاری کنید.

در این آموزش، پروژه Django ASGI خود را در یک محیط مجازی راه‌اندازی و تنظیم کردید. Gunicorn و Uvicorn طوری تنظیم شده‌اند که درخواست‌ها را به صورت غیرهمزمان انجام دهند و Django درخواست‌ها را پاسخ دهد. سپس Nginx به عنوان reverse proxy نصب و کانفیگ شد تا درخواست‌ها را مدیریت کند و پروژه مناسب را بر اساس درخواست ارائه دهد.

Django فرآیند ساخت پروژه و اپلیکیشن‌ها را ساده کرده و بخش‌های معمول را می‌سازد تا شما بتوانید روی موارد خاص تمرکز کنید. با استفاده از این ابزارها می‌توانید برنامه‌های خود را به سادگی از روی یک سرور سرو کنید.

با تشکر از همراهی شما با ParminCloud.

Click to rate this post!
[Total: 0 Average: 0]

نظرات کاربران

دیدگاهی بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *