دپلوی وب اپ پایتون با nginx و uwsgi در دبیان

اشتراک‌گذاری

بعد از درخواست یکی از دوستان در مورد مستقر کردن(deploy) یک وب اپلیکیشن پایتونی که با جنگو نوشته شده بود، تصمیم گرفتم این مطلب رو بنویسم. اینجا چند چیز را فرض کردم:

  • از سکوی (framework) فلسک استفاده می‌کنید.در مورد جنگو هم البته داستان کمابیش همین هست. در مورد چری‌پای میتونید با همچین راهنمایی پیش برید یا از کارساز(سرور) وب خود چری‌پای به اسم چروت (cheroot) استفاده کنید.
  • از دبیان (یا توزیع‌هایی که بر پایه دبیان ساخته شدن مثل اوبونتو) و systemd استفاده می‌کنید.
  • میخواهید از انجین‌ایکس(nginx) به عنوان کارساز وب یا وب‌سرور استفاده کنید.
  • تنها از HTTP می‌خواهید استفاده کنید و برای سادگی کار فعلا HTTPS را کنار میگزاریم.
  • قرار هست وب اپلیکیشن شما در ریشه قرار بگیرد. یعنی از طریق آدرسی مثل https://example.com/ قابل دسترسی باشد نه مثلا https://example.com/somewhere

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

from flask import Flask
app = Flask(__name__)

@app.route("/")
def salam():
    return "Salam donya!"

فرض می‌کنم در فایلی به اسم mycoolapp.py ذخیره‌اش کردید. خب اول مواد و وسایل لازم برای پخت را بایست نصب کنیم:

sudo apt install -y python3-full python3-pip python3-setuptools

آپشن -y به این معنی می‌باشد که در مورد دانلود و نصب از شما سوال نکند که نصب کند یا نه.

سپس با pip بایست نرم‌افزار uwsgi نصب شده و البته سایر نیازمندی‌های پروژه‌ای که میخواهید دپلوی کنید. اینجا چون از فلسک استفاده می‌کنم و نه چیز دیگه‌ای پس فقط فلسک و uwsgi را نصب می‌کنم.

pip3 install uwsgi Flask --user

قبل از اینکه ادامه دهم باید این را توضیح بدم که چیزی که می‌سازید چطور کار می‌کند.تصویر زیر بسیار گویاست:

این در صورتیست که سرور مورد نظر کاملا در اختیار شما باشد،اما در بعضی ارائه دهنده‌ها دسترسی روت ندارید در نتیجه درخواست کلاینت‌ها مستقیما به وب‌سرور شما نمی‌رسد.در اینجور مواقع چارت زیر صادق هست

به این معنی که انجین‌ایکس شما باید به جای پورت ۸۰(یا هر پورت دیگری که مدنظرتان هست) به پورتی دیگر یا یک سوکت یونیکس(UDS) گوش دهد.این در هر ارائه دهنده متفاوت است و باید به مستندات یا پشتیبانی ارائه دهنده مورد نظر مراجعه کنید.برای مثال در یک شل‌سرور ممکن است از شما بخواهند وب‌سرورتان به سوکت‌های یونیکس مشخصی در دایرکتوری خانه خودتان گوش دهد یا یک پورت مشخص TCP/IP.

حال باید با استفاده از uwsgi وب‌اپلیکیشن خود را اجرا کنیم:

uwsgi -s SOCKET --manage-script-name --mount /=mycoolapp:app

باید SOCKET را با یک آی‌پی و پورت یا آدرس یک سوکت یونیکس جایگزین کنید.معمولا بنده به دلیل پرفرمنس بهتر سوکت‌های یونیکس را ترجیح می‌دهم که البته در مقیاس پایین معمولا محسوس نیست.توجه کنید که «مکانی که میخواهید تخصیص دهید نباید قبلا تخصیص شده باشد».یعنی اگر از یک پورت TCP/IP استفاده می‌کنید نباید قبلا توسط برنامه دیگری اشغال شده باشد یا اگر می‌خواهید از سوکت یونیکس استفاده کنید نباید قبلا فایل‌آن وجود داشته باشد.همچنین اگر در یک شل‌سرور یا سیستم چند کاربره برای هاست کردن استفاده می‌کنید بهتر است از سوکت یونیکس در دایرکتوری شخصی خود استفاده کنید تا مطمئن باشید که هیچ پروسه‌ای متعلق به دیگر کاربران آنرا اشغال نکرده است.

uwsgi -s 127.0.0.1:8090 --manage-script-name --mount /=mycoolapp:app uwsgi -s /home/farooqkz/.myapp.sock --manage-script-name --mount /=mycoolapp:app

توجه کنید که mycoolapp اسم فایل برنامه‌شما بدون پسوند و app اسم برنامه موجود در آن است که با توجه به کاربرد شما میتواند متفاوت باشد.

خب حالا نوبت نوشتن یک فایل یونیت systemd هست که بتوانیم به سادگی وب اپلیکیشن خود را اجرا یا restart کنیم.البته میتوانید دستی آنرا اجرا کنید اما چیز تمیز و شایسته‌ای از آب در نمی‌آید!

[Unit]
Description=adobe
StartLimitIntervalSec=0
[Service]
ExecStartPre=-/usr/bin/rm %h/.myapp.sock ExecStart=/bin/sh -c "cd /home/farooqkz/myapp/; /home/farooqkz/.local/bin/uwsgi -s /home/farooqkz/.myapp.sock --manage-script-name --mount /=mycoolapp:app" ExecStopPost=-/usr/bin/rm %h/.myapp.sock
[Install]
WantedBy=default.target

فکر کنم همه چیز مشخص باشد، نه؟ اگر از سوکت TCP استفاده می‌کنید نیازی به ExecStartPre و ExecStopPost نیست. درصد اچ(%h) نشان دهنده دایرکتوری شخصی یک کاربر است.فایلی با این محتویات را در آدرس زیر ذخیره کنید.علامت تیلده نشان دهند دایرکتوری شخصی کاربر مورد نظر است.اسم آنرا myapp.service بگذارید.

~/.config/systemd/user/

خب حالا می‌توانید دستورات زیر را به ترتیب برای اجرای سرویس ایجاد شده بعد از هر ریبوت یا لاگین و اجرای سرویس در همین لحظه اجرا کنید:

systemctl --user enable myapp.service systemctl --user start myapp.service

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

systemctl --user enable --now myapp.service

تبریک! تا به اینجا موفق شدید وب اپلیکیشن خود را آماده اجرا کنید تا انجین‌ایکس درخواست‌ها را به آن ارسال کند!

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

sudo apt install -y nginx

حال فایل پیکره‌بندی یا کانفیگ(config) آنرا به همچین فرمی در بیاورید:

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    sendfile on;
    server {
        listen SOCKET;
        server_name EXAMPLE.COM;
        location / {
            include /etc/nginx/uwsgi_params; uwsgi_pass USOCKET;
        }
    }
}

موارد زیر را در نظر داشته باشید:

  • SOCKET را باید با یک آدرس،یک سوکت TCP یا یک سوکت یونیکس، جایگزین کنید.
  • EXAMPLE.COM را باید با آدرسی که با آی‌پی سرور شما مرتبط شده جایگزین کنید.
  • USOCKET را باید با سوکت مربوط به اپلیکیشن پایتونی که قبلا اجرا کردید جایگزین کنید مثلا /home/farooqkz/.myapp.sock
اشتراک‌گذاری