كيفية خدمة تطبيقات Flask باستخدام Gunicorn و Nginx على Ubuntu 22.04

A previous version of this tutorial was written by Kathleen Juell.

مقدمة

في هذا الدليل، ستقوم ببناء تطبيق Python باستخدام إطار العمل Flask على Ubuntu 22.04. ستكون معظم هذا البرنامج التعليمي حول كيفية إعداد خادم التطبيقات Gunicorn وكيفية تشغيل التطبيق وتكوين Nginx ليعمل كوكيل عكسي أمامي.

المتطلبات المسبقة

قبل بدء هذا الدليل، يجب أن تكون لديك:

الخطوة 1 — تثبيت المكونات من مستودعات أوبونتو

الخطوة الأولى ستكون تثبيت جميع القطع المطلوبة من مستودعات أوبونتو. يشمل ذلك pip، مدير حزم Python، الذي سيدير المكونات باللغة Python. ستحصل أيضًا على ملفات تطوير Python اللازمة لبناء بعض مكونات Gunicorn.

أولاً، قم بتحديث فهرس الحزم المحلي وتثبيت الحزم التي ستسمح لك ببناء بيئتك البرمجية باللغة Python. ستتضمن هذه python3-pip، بالإضافة إلى عدد قليل من الحزم الأخرى وأدوات التطوير اللازمة لبيئة برمجية قوية:

  1. sudo apt update
  2. sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools

بعد تثبيت هذه الحزم، الخطوة التالية هي إنشاء بيئة افتراضية لمشروعك.

الخطوة 2 — إنشاء بيئة افتراضية للPython

بعد ذلك، ستقوم بإعداد بيئة افتراضية لعزل تطبيق Flask عن الملفات الأخرى باللغة Python على نظامك.

ابدأ بتثبيت الحزمة python3-venv، التي ستقوم بتثبيت وحدة venv:

  1. sudo apt install python3-venv

ثم قم بإنشاء دليل رئيسي لمشروع Flask الخاص بك. انتقل إلى الدليل باستخدام الأمر cd بعد إنشائه:

  1. mkdir ~/myproject
  2. cd ~/myproject

قم بإنشاء بيئة افتراضية لتخزين متطلبات Python لمشروع Flask الخاص بك عن طريق كتابة:

  1. python3 -m venv myprojectenv

سيتم تثبيت نسخة محلية من Python و pip في دليل يسمى myprojectenv داخل دليل مشروعك.

قبل تثبيت التطبيقات داخل البيئة الافتراضية، تحتاج إلى تفعيلها. قم بذلك بكتابة:

  1. source myprojectenv/bin/activate

سيتغير موجه الأوامر ليشير إلى أنك تعمل الآن داخل البيئة الافتراضية. سيبدو مثل هذا: (myprojectenv)user@host:~/myproject$.

الخطوة 3 — إعداد تطبيق Flask

الآن بعد أن تكون داخل البيئة الافتراضية، يمكنك تثبيت Flask و Gunicorn والبدء في تصميم تطبيقك.

أولاً، قم بتثبيت wheel باستخدام النسخة المحلية من pip للتأكد من أن حزمك ستتم تثبيتها حتى إذا كانت الأرشيفات الخاصة بـ wheel مفقودة:

  1. pip install wheel

ملاحظة

بغض النظر عن الإصدار من Python الذي تستخدمه، عندما يتم تنشيط البيئة الافتراضية، يجب عليك استخدام أمر pip (وليس pip3).

بعد ذلك، قم بتثبيت Flask و Gunicorn:

  1. pip install gunicorn flask

إنشاء تطبيق تجريبي

الآن بعد أن لديك Flask متاح، يمكنك إنشاء تطبيق بسيط. Flask هو إطار عمل مصغر. لا يتضمن العديد من الأدوات التي قد يتضمنها إطار العمل الكامل المزيد من الميزات، ويوجد أساسًا كوحدة يمكنك استيرادها إلى مشاريعك لمساعدتك في تهيئة تطبيق ويب.

على الرغم من أن تطبيقك قد يكون أكثر تعقيدًا، سنقوم بإنشاء تطبيق Flask الخاص بنا في ملف واحد، يسمى myproject.py:

  1. nano ~/myproject/myproject.py

سيعيش كود التطبيق في هذا الملف. سيقوم بالاستيراد Flask وإنشاء كائن Flask. يمكنك استخدام ذلك لتحديد الوظائف التي يجب تشغيلها عند طلب مسار محدد:

~/myproject/myproject.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "<h1 style='color:blue'>Hello There!</h1>"

if __name__ == "__main__":
    app.run(host='0.0.0.0')

هذا ببساطة يحدد ما الذي يجب عرضه عند الوصول إلى النطاق الرئيسي. احفظ وأغلق الملف عند الانتهاء.

إذا قمت بمتابعة دليل إعداد الخادم الأولي، يجب أن تكون لديك جدار ناري UFW مفعل. لاختبار التطبيق، تحتاج إلى السماح بالوصول إلى المنفذ 5000:

  1. sudo ufw allow 5000

الآن يمكنك اختبار تطبيق Flask الخاص بك عن طريق كتابة:

  1. python myproject.py

سوف ترى إخراجًا مثل الآتي، بما في ذلك تحذير مفيد يذكرك بعدم استخدام إعداد الخادم هذا في الإنتاج:

Output
* Serving Flask app "myproject" (lazy loading) * Environment: production WARNING: Do not use the development server in a production environment. Use a production WSGI server instead. * Debug mode: off * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

قم بزيارة عنوان IP الخادم الخاص بك تليه :5000 في متصفح الويب الخاص بك:

http://your_server_ip:5000

يجب أن ترى شيئًا مشابهًا لهذا:

عند الانتهاء، اضغط CTRL-C في نافذة الطرفية الخاصة بك لإيقاف خادم التطوير Flask.

إنشاء نقطة الوصول WSGI

الخطوة التالية، قم بإنشاء ملف سيعمل كنقطة الوصول لتطبيقك. سيخبر هذا خادم Gunicorn كيفية التفاعل مع التطبيق.

سمِّ الملف wsgi.py:

  1. nano ~/myproject/wsgi.py

في هذا الملف، قم بإستيراد الـ Flask instance من تطبيقنا ومن ثم قم بتشغيله:

~/myproject/wsgi.py
from myproject import app

if __name__ == "__main__":
    app.run()

احفظ الملف وأغلقه عند الانتهاء.

الخطوة 4 — تكوين Gunicorn

تم كتابة تطبيقك الآن مع تأسيس نقطة الوصول. يمكنك الآن المضي قدماً في تكوين Gunicorn.

قبل المضي قدماً، تحقق من أن Gunicorn يمكنه خدمة التطبيق بشكل صحيح.

يمكنك فعل ذلك عن طريق تمرير اسم نقطة الوصول للتطبيق. يتم بناؤها على أنها اسم الوحدة (باستثناء الامتداد .py)، ثم اسم الدالة داخل التطبيق. في هذه الحالة، هو wsgi:app.

حدد أيضًا واجهة الشبكة والمنفذ للربط عليها باستخدام الوسيطة 0.0.0.0:5000 لكي يتم بدء التطبيق على واجهة متاحة على الإنترنت:

  1. cd ~/myproject
  2. gunicorn --bind 0.0.0.0:5000 wsgi:app

يجب أن ترى إخراجًا مثل التالي:

Output
[2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4 [2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419) [2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync [2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421

زر عنوان IP الخاص بالخادم الخاص بك بالإضافة إلى :5000 في متصفح الويب مرة أخرى:

http://your_server_ip:5000

يجب أن ترى إخراج تطبيقك:

عندما تؤكد أنه يعمل بشكل صحيح، اضغط على CTRL-C في نافذة الطرفية.

عند الانتهاء من استخدام البيئة الافتراضية، يمكنك إلغاء تنشيطها:

  1. deactivate

أي أوامر Python ستستخدم الآن بيئة Python النظام مرة أخرى.

المرحلة التالية، قم بإنشاء ملف وحدة خدمة systemd. إنشاء ملف وحدة systemd سيسمح لنظام التشغيل init في أوبونتو بتشغيل Gunicorn تلقائيًا وخدمة تطبيق Flask في كل مرة يتم فيها تشغيل الخادم.

أنشئ ملف وحدة ينتهي بالامتداد .service داخل الدليل /etc/systemd/system للبدء:

  1. sudo nano /etc/systemd/system/myproject.service

داخله، ستبدأ بالقسم [Unit]، الذي يُستخدم لتحديد البيانات الوصفية والاعتمادات. أضف وصفًا لخدمتك هنا وأخبر نظام التشغيل بالبدء فقط بعد الوصول إلى الهدف الشبكي:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

المرحلة التالية، أضف قسم [Service]. سيحدد هذا المستخدم والمجموعة التي تريد أن يعمل العملية تحت. قم بإعطاء حساب المستخدم العادي ملكية العملية لأنه يمتلك جميع الملفات ذات الصلة. كما قم بإعطاء ملكية المجموعة لمجموعة www-data حتى يتمكن Nginx من التواصل بسهولة مع عمليات Gunicorn. تذكر أن تستبدل اسم المستخدم هنا بالاسم الخاص بك:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data

بعد ذلك، قم بتعيين دليل العمل وضبط المتغير البيئي PATH حتى يعلم نظام التهيئ أن ملفات التنفيذ للعملية موجودة داخل بيئتنا الافتراضية. كما حدد الأمر لبدء الخدمة. سيقوم هذا الأمر بما يلي:

  • بدء 3 عمليات عمل (على الرغم من أنك يجب أن تعدل هذا حسب الضرورة)
  • إنشاء وربط ملف مأخذ Unix، myproject.sock، داخل دليل مشروعنا. سنقوم بتعيين قيمة لـ umask تكون 007 حتى يتم إنشاء ملف المأخذ ممنحًا الوصول إلى المالك والمجموعة، مع تقييد الوصول للآخرين
  • حدد اسم ملف نقطة الدخول WSGI، مع الدالة القابلة للتنفيذ بلغة Python داخل ذلك الملف (wsgi:app)

يتطلب systemd أن تعطي المسار الكامل إلى الملف التنفيذي Gunicorn، الذي يتم تثبيته داخل البيئة الافتراضية الخاصة بك.

تذكر أن تستبدل اسم المستخدم ومسار المشروع بمعلوماتك الخاصة:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

وأخيرًا، أضف قسم [Install]. سيخبر هذا systemd بما يتعين ربط هذه الخدمة به إذا قمت بتمكينها للبدء عند التمهيد. سترغب في بدء هذه الخدمة عندما يكون النظام متعدد المستخدمين العادي جاهزًا ويعمل:

/etc/systemd/system/myproject.service
[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data
WorkingDirectory=/home/sammy/myproject
Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

بهذا، يكتمل ملف خدمة systemd الخاص بك. احفظه وأغلقه الآن.

يمكنك الآن بدء خدمة Gunicorn التي أنشأتها وتمكينها لكي تبدأ عند التمهيد:

  1. sudo systemctl start myproject
  2. sudo systemctl enable myproject

لنتحقق من الحالة:

  1. sudo systemctl status myproject

يجب أن ترى نتائج مشابهة لهذه:

Output
● myproject.service - Gunicorn instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled) Active: active (running) since Tue 2022-05-10 19:40:41 UTC; 9s ago Main PID: 17300 (gunicorn) Tasks: 4 (limit: 2327) Memory: 56.0M CPU: 514ms CGroup: /system.slice/myproject.service ├─17300 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17301 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app ├─17302 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app └─17303 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app May 10 19:40:41 r systemd[1]: Started Gunicorn instance to serve myproject. . . .

إذا رأيت أي أخطاء، تأكد من حلها قبل المتابعة مع البرنامج التعليمي.

الخطوة 5 — تكوين Nginx لتوجيه الطلبات

يجب أن يكون خادم التطبيق Gunicorn الخاص بك الآن مشغلاً وجاهزًا لاستقبال الطلبات على ملف الجرسونيك في دليل المشروع. يمكنك الآن تكوين Nginx لتمرير طلبات الويب إلى هذا الجرسونيك من خلال إجراء بعض الإضافات الصغيرة إلى ملف تكوينه.

ابدأ بإنشاء ملف تكوين كتلة خادم جديد في دليل sites-available في Nginx. اسمها myproject لتكون متوافقة مع بقية الدليل:

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

افتح كتلة الخادم وأخبر Nginx بالاستماع على المنفذ الافتراضي 80. وأخبره أيضًا باستخدام هذه الكتلة لطلبات اسم النطاق لخادمنا:

/etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name your_domain www.your_domain;
}

بعد ذلك، أضف كتلة موقع تطابق كل طلب. داخل هذه الكتلة، ستضمن تضمين ملف proxy_params الذي يحدد بعض المعلمات العامة للوكيل التي يجب تعيينها. ثم ستمرر الطلبات إلى الجرسونيك الذي قمت بتعريفه باستخدام توجيه proxy_pass:

/etc/nginx/sites-available/myproject
server {
    listen 80;
    server_name your_domain www.your_domain;

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
    }
}

احفظ وأغلق الملف عند الانتهاء.

لتمكين تكوين كتلة خادم Nginx التي أنشأتها للتو، قم بربط الملف بدليل sites-enabled:

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

بعد وضع الملف في هذا الدليل، يمكنك الاختبار للتأكد من عدم وجود أخطاء في الصياغة:

  1. sudo nginx -t

إذا لم يظهر أي تحذير، قم بإعادة تشغيل عملية Nginx لقراءة التكوين الجديد:

  1. sudo systemctl restart nginx

أخيرًا، قم بضبط جدار الحماية مرة أخرى. لم يعد لديك الحاجة إلى الوصول من خلال المنفذ 5000، لذا يمكنك إزالة تلك القاعدة. يمكنك بعد ذلك السماح بالوصول الكامل إلى خادم Nginx:

  1. sudo ufw delete allow 5000
  2. sudo ufw allow 'Nginx Full'

يجب أن تكون قادرًا الآن على التنقل إلى اسم النطاق الخاص بخادمك في متصفح الويب الخاص بك:

http://your_domain

يجب أن ترى إخراج تطبيقك:

ملاحظة: ستتلقى خطأ بوابة HTTP 502 إذا لم يتمكن Nginx من الوصول إلى ملف socket لـ gunicorn. عادةً ما يكون ذلك بسبب عدم السماح لمجلد المستخدم بالوصول إلى الملفات داخله.

إذا كان اسم ملف السوكت الخاص بك هو /home/sammy/myproject/myproject.sock، فتأكد من أن /home/sammy لديه على الأقل أذونات 0755 كحد أدنى. يمكنك استخدام أداة مثل chmod لتغيير الأذونات بهذه الطريقة:

  1. sudo chmod 755 /home/sammy

ثم أعد تحميل الصفحة لمعرفة ما إذا كان خطأ HTTP 502 قد اختفى.

إذا واجهت أي أخطاء، جرب التحقق من الآتي:

  • sudo less /var/log/nginx/error.log: يتحقق من سجلات أخطاء Nginx.
  • sudo less /var/log/nginx/access.log: يتحقق من سجلات الوصول إلى Nginx.
  • sudo journalctl -u nginx: يتحقق من سجلات عملية Nginx.
  • sudo journalctl -u myproject: يتحقق من سجلات Gunicorn لتطبيق Flask الخاص بك.

الخطوة 6 — تأمين التطبيق

لضمان بقاء حركة المرور إلى خادمك آمنة، دعنا نحصل على شهادة SSL لنطاقك. هناك عدة طرق للقيام بذلك، بما في ذلك الحصول على شهادة مجانية من Let’s Encrypt، إنشاء شهادة ذاتية التوقيع، أو شراء واحدة من مزود آخر وتكوين Nginx لاستخدامها باتباع الخطوات من 2 إلى 6 في كيفية إنشاء شهادة SSL ذاتية التوقيع لـ Nginx في Ubuntu 22.04. سنستخدم الخيار الأول (Let’s Encrypt) من أجل السرعة.

قم بتثبيت حزمة Nginx لـ Certbot باستخدام apt:

  1. sudo apt install python3-certbot-nginx

يوفر Certbot مجموعة متنوعة من الطرق للحصول على شهادات SSL من خلال الإضافات. ستقوم الإضافة الخاصة بـ Nginx بإعادة تكوين Nginx وإعادة تحميل التكوين عند الضرورة. لاستخدام هذه الإضافة، اكتب ما يلي:

  1. sudo certbot --nginx -d your_domain -d www.your_domain

يقوم هذا بتشغيل certbot مع إضافة --nginx، باستخدام -d لتحديد الأسماء التي نرغب في أن تكون الشهادة صالحة لها.

إذا كانت هذه المرة الأولى التي تقوم فيها بتشغيل certbot، سيُطلب منك إدخال عنوان بريد إلكتروني والموافقة على شروط الخدمة. بعد ذلك، سيقوم certbot بالتواصل مع خادم Let’s Encrypt، ثم يقوم بتشغيل تحدي للتحقق من أنك تتحكم في النطاق الذي تطلب شهادة له.

إذا كان ذلك ناجحًا، سيطلب certbot كيف ترغب في تكوين إعدادات HTTPS الخاصة بك:

Output
Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access. ------------------------------------------------------------------------------- 1: No redirect - Make no further changes to the webserver configuration. 2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for new sites, or if you're confident your site works on HTTPS. You can undo this change by editing your web server's configuration. ------------------------------------------------------------------------------- Select the appropriate number [1-2] then [enter] (press 'c' to cancel):

اختر خيارك ثم اضغط على ENTER. سيتم تحديث التكوين، وسيقوم Nginx بإعادة التحميل لالتقاط الإعدادات الجديدة. سيُنهي certbot برسالة تخبرك بأن العملية كانت ناجحة وأين يتم تخزين شهاداتك:

Output
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2020-08-18. To obtain a new or tweaked version of this certificate in the future, simply run certbot again with the "certonly" option. To non-interactively renew *all* of your certificates, run "certbot renew" - Your account credentials have been saved in your Certbot configuration directory at /etc/letsencrypt. You should make a secure backup of this folder now. This configuration directory will also contain certificates and private keys obtained by Certbot so making regular backups of this folder is ideal. - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le

إذا اتبعت تعليمات تثبيت Nginx في المتطلبات المسبقة، فلن تحتاج بعد الآن إلى تفعيل ملف تعريف HTTP المتكرر:

  1. sudo ufw delete allow 'Nginx HTTP'

للتحقق من التكوين، انتقل مرة أخرى إلى نطاقك، باستخدام https://:

https://your_domain

يجب أن ترى إخراج تطبيقك مرة أخرى، إلى جانب مؤشر الأمان في متصفحك، الذي يجب أن يشير إلى أن الموقع مؤمن.

الختام

في هذا الدليل، قمت بإنشاء وتأمين تطبيق Flask بسيط داخل بيئة Python افتراضية. لقد قمت بإنشاء نقطة دخول WSGI بحيث يمكن لأي خادم تطبيقات قابل للتنفيذ WSGI التواصل معه، ثم قمت بتكوين خادم التطبيقات Gunicorn لتوفير هذه الوظيفة. بعد ذلك، قمت بإنشاء ملف خدمة systemd لتشغيل خادم التطبيق تلقائيًا عند التمهيد. كما قمت بإنشاء كتلة خادم Nginx التي تمرر حركة المرور من عملاء الويب إلى خادم التطبيق، مُعَادلة الطلبات الخارجية، وتأمين حركة المرور إلى خادمك باستخدام Let’s Encrypt.

Flask هو إطار عمل بسيط جدًا، لكنه مرن للغاية يهدف إلى توفير وظائف لتطبيقاتك دون أن يكون مقيدًا جدًا فيما يتعلق بالهيكل والتصميم. يمكنك استخدام الستاك العام الموصوف في هذا الدليل لخدمة تطبيقات Flask التي تصممها.

Source:
https://www.digitalocean.com/community/tutorials/how-to-serve-flask-applications-with-gunicorn-and-nginx-on-ubuntu-22-04