Поиск по сайту:

Как обслуживать приложения Flask с помощью uWSGI и Nginx в Ubuntu 22.04


Введение

В этом руководстве вы создадите приложение Python, используя Nginx в качестве внешнего обратного прокси-сервера.

Предпосылки

Прежде чем приступить к этому руководству, у вас должно быть:

  • Сервер с установленной Ubuntu 22.04 и пользователем без полномочий root с привилегиями sudo. Следуйте нашему руководству по первоначальной настройке сервера.
  • Nginx установлен, выполнив шаги с 1 по 3 инструкции Как установить Nginx в Ubuntu 22.04.
  • Доменное имя, настроенное так, чтобы оно указывало на ваш сервер. Вы можете приобрести его в документации по доменам и DNS. В этом руководстве предполагается, что вы создали следующие записи DNS:
    • Запись A с your_domain, указывающая на общедоступный IP-адрес вашего сервера.
    • Запись A с www.your_domain, указывающая на общедоступный IP-адрес вашего сервера.

    Кроме того, может быть полезно ознакомиться с uWSGI, сервером приложений, который вы настроите в этом руководстве, и спецификацией WSGI. В этом обсуждении определений и понятий подробно рассматривается и то, и другое.

    Шаг 1 — Установка компонентов из репозиториев Ubuntu

    Первым шагом будет установка всех необходимых компонентов из репозиториев Ubuntu. Пакеты, которые вам необходимо установить, включают pip, менеджер пакетов Python, для управления вашими компонентами Python. Вы также получите файлы разработки Python, необходимые для сборки uWSGI.

    Сначала обновите локальный индекс пакета:

    1. sudo apt update

    Затем установите пакеты, которые позволят вам создать среду Python. Они будут включать python3-pip, а также еще несколько пакетов и инструментов разработки, необходимых для надежной среды программирования:

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

    Имея эти пакеты, вы готовы перейти к созданию виртуальной среды для своего проекта.

    Шаг 2 — Создание виртуальной среды Python

    Виртуальная среда Python — это автономный каталог проекта, который содержит определенные версии Python и модули Python, необходимые для данного проекта. Это полезно для изоляции одного приложения от других в той же системе путем отдельного управления зависимостями каждого из них. На этом шаге вы настроите виртуальную среду Python, из которой вы будете запускать приложение Flask.

    Начните с установки пакета python3-venv, который установит модуль venv:

    1. sudo apt install python3-venv

    Затем создайте родительский каталог для вашего проекта Flask:

    1. mkdir ~/myproject

    Перейдите в каталог после его создания:

    1. cd ~/myproject

    Создайте виртуальную среду для хранения требований Python вашего проекта Flask, набрав:

    1. python3.10 -m venv myprojectenv

    Это установит локальную копию Python и pip в каталог с именем myprojectenv в каталоге вашего проекта.

    Перед установкой приложений в виртуальной среде ее необходимо активировать. Сделайте это, набрав:

    1. source myprojectenv/bin/activate

    Ваше приглашение изменится, чтобы показать, что вы сейчас работаете в виртуальной среде. Это будет выглядеть примерно так: (myprojectenv)user@хост:~/myproject$.

    Шаг 3 — Настройка приложения Flask

    Теперь, когда вы находитесь в виртуальной среде, вы можете установить Flask и uWSGI, а затем приступить к разработке своего приложения.

    Сначала установите wheel с локальным экземпляром pip, чтобы убедиться, что ваши пакеты будут установлены, даже если в них отсутствуют архивы колес:

    1. pip install wheel

    Примечание. Независимо от используемой версии Python при активации виртуальной среды следует использовать команду pip (не pip3).

    Затем установите Flask и uWSGI:

    1. pip install uwsgi flask

    Создание примера приложения

    Теперь, когда у вас есть Flask, вы можете создать образец приложения. Flask — это микрофреймворк. Он не включает многие из инструментов, которые могут быть в более полнофункциональных фреймворках, и существует в основном как модуль, который вы можете импортировать в свои проекты, чтобы помочь вам в инициализации веб-приложения.

    Хотя ваше приложение может быть более сложным, в этом примере вы создадите приложение Flask в одном файле с именем myproject.py. Откройте myproject.py с помощью nano или вашего любимого текстового редактора:

    1. nano ~/myproject/myproject.py

    Код приложения будет жить в этом файле. Он импортирует Flask и создаст экземпляр объекта Flask. Вы можете использовать это для определения функций, которые вы хотите запускать при запросе определенного маршрута:

    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')
    

    По сути, это определяет, какой контент должен быть представлен всем, кто обращается к корневому домену. Сохраните и закройте файл, когда закончите. Если вы использовали nano для редактирования файла, как в предыдущем примере, сделайте это, нажав CTRL + X, Y, а затем ВВОД.

    Если вы следовали руководству по первоначальной настройке сервера, у вас должен быть включен брандмауэр UFW. Для тестирования приложения необходимо разрешить доступ к порту 5000:

    1. sudo ufw allow 5000

    Теперь вы можете протестировать свое приложение Flask, набрав:

    1. python myproject.py

    Вы увидите вывод, подобный следующему, включая полезное предупреждение, напоминающее вам не использовать эту настройку сервера в рабочей среде:

    Output
    WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Serving Flask app 'myproject' * Debug mode: off * Running on all addresses (0.0.0.0) WARNING: This is a development server. Do not use it in a production deployment. * Running on http://127.0.0.1:5000 * Running on http://your_server:5000 (Press CTRL+C to quit)

    Посетите IP-адрес вашего сервера, а затем :5000 в веб-браузере:

    http://your_server_ip:5000
    

    Вы увидите что-то вроде этого:

    Когда вы закончите, нажмите CTRL + C в окне терминала, чтобы остановить сервер разработки Flask.

    Создание точки входа WSGI

    Затем создайте файл, который будет служить точкой входа для вашего приложения. Это сообщит вашему серверу uWSGI, как с ним взаимодействовать.

    Вызовите файл wsgi.py:

    1. nano ~/myproject/wsgi.py

    В этом файле импортируйте экземпляр Flask из вашего приложения, а затем запустите его:

    from myproject import app
    
    if __name__ == "__main__":
        app.run()
    

    Сохраните и закройте файл, когда закончите.

    Шаг 4 — Настройка uWSGI

    Теперь ваше приложение написано с установленной точкой входа. Вы можете перейти к настройке uWSGI.

    Проверка того, может ли uWSGI обслуживать приложение

    В качестве первого шага проверьте, может ли uWSGI правильно обслуживать ваше приложение, передав ему имя вашей точки входа. Он состоит из имени модуля (минус расширение .py) и имени вызываемого объекта в приложении. В контексте этого руководства точка входа называется wsgi:app.

    Также укажите сокет, чтобы он запускался на общедоступном интерфейсе, а также протокол, чтобы он использовал HTTP вместо бинарного протокола uwsgi. Используйте тот же номер порта, 5000, который вы открыли ранее:

    1. uwsgi --socket 0.0.0.0:5000 --protocol=http -w wsgi:app

    Посетите IP-адрес вашего сервера с :5000, добавленным в конце, в веб-браузере еще раз:

    http://your_server_ip:5000
    

    Вы снова увидите вывод вашего приложения:

    Убедившись, что он работает правильно, нажмите CTRL + C в окне терминала.

    Теперь вы закончили работу с виртуальной средой, поэтому можете ее деактивировать:

    1. deactivate

    Любые команды Python теперь снова будут использовать системную среду Python.

    Создание файла конфигурации uWSGI

    Вы проверили, что uWSGI может обслуживать ваше приложение, но вам нужно что-то более надежное для длительного использования. Вы можете создать файл конфигурации uWSGI с соответствующими параметрами для этого.

    Поместите этот файл в каталог вашего проекта и назовите его myproject.ini:

    1. nano ~/myproject/myproject.ini

    Внутри запустите файл с заголовком [uwsgi], чтобы uWSGI знал, что нужно применить настройки. Ниже укажите сам модуль — ссылаясь на файл wsgi.py без расширения — и вызываемый объект в файле, app:

    [uwsgi]
    module = wsgi:app
    

    Затем скажите uWSGI запуститься в режиме мастера и создать пять рабочих процессов для обслуживания фактических запросов:

    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 5
    

    Во время тестирования вы выставили uWSGI на сетевой порт. Однако вы будете использовать Nginx для обработки реальных клиентских подключений, которые затем будут передавать запросы в uWSGI. Поскольку эти компоненты работают на одном компьютере, сокет Unix предпочтительнее, поскольку он быстрее и безопаснее. Вызовите сокет myproject.sock и поместите его в этот каталог.

    Затем измените разрешения на сокете. Позже вы передадите группе Nginx право собственности на процесс uWSGI, поэтому вам нужно убедиться, что владелец группы сокета может читать информацию из него и записывать в него. Также добавьте параметр vacuum и установите для него значение true; это очистит сокет, когда процесс остановится:

    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 5
    
    socket = myproject.sock
    chmod-socket = 660
    vacuum = true
    

    Последнее, что нужно сделать, это установить параметр умереть на срок. Это может помочь гарантировать, что система инициализации и uWSGI имеют одинаковые предположения о том, что означает каждый сигнал процесса. Установка этого параметра выравнивает два системных компонента, реализуя ожидаемое поведение:

    [uwsgi]
    module = wsgi:app
    
    master = true
    processes = 5
    
    socket = myproject.sock
    chmod-socket = 660
    vacuum = true
    
    die-on-term = true
    

    Вы могли заметить, что в этих строках не указан протокол, как в командной строке. Это связано с тем, что по умолчанию uWSGI использует протокол uwsgi, быстрый двоичный протокол, предназначенный для связи с другими серверами. Nginx может говорить по этому протоколу нативно, поэтому лучше использовать его, чем навязывать связь по HTTP.

    Когда вы закончите, сохраните и закройте файл.

    При этом uWSGI настроен в вашей системе. Чтобы дать вам больше гибкости в том, как вы управляете своим приложением Flask, теперь вы можете настроить его для работы в качестве службы systemd.

    Шаг 5 — Создание файла модуля systemd

    Systemd — это набор инструментов, который обеспечивает быструю и гибкую модель инициализации для управления системными службами. Создание файла модуля systemd позволит системе инициализации Ubuntu автоматически запускать uWSGI и обслуживать приложение Flask при каждой загрузке сервера.

    Создайте юнит-файл, оканчивающийся на .service, в каталоге /etc/systemd/system, чтобы начать:

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

    Внутри начните с раздела [Unit], который используется для указания метаданных и зависимостей. Затем поместите здесь описание службы и скажите системе инициализации, чтобы она запускалась только после достижения цели сети:

    [Unit]
    Description=uWSGI instance to serve myproject
    After=network.target
    

    Затем создайте раздел [Service]. Это укажет пользователя и группу, под которой вы хотите запустить процесс. Дайте вашей обычной учетной записи пользователя право собственности на процесс, поскольку она владеет всеми соответствующими файлами. Затем передайте групповое владение группе www-data, чтобы Nginx мог взаимодействовать с процессами uWSGI (это группа, с которой Nginx работает по умолчанию в Ubuntu). Не забудьте заменить имя пользователя здесь своим именем пользователя:

    [Unit]
    Description=uWSGI instance to serve myproject
    After=network.target
    
    [Service]
    User=sammy
    Group=www-data
    

    Затем наметьте рабочий каталог и установите переменную окружения PATH, чтобы система инициализации знала, что исполняемые файлы процесса находятся в вашей виртуальной среде. Также укажите команду для запуска службы. Systemd требует, чтобы вы указали полный путь к исполняемому файлу uWSGI, который установлен в вашей виртуальной среде. Здесь мы передаем имя файла конфигурации .ini, который вы создали в каталоге вашего проекта.

    Не забудьте заменить имя пользователя и пути проекта своей информацией:

    [Unit]
    Description=uWSGI 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/uwsgi --ini myproject.ini
    

    Наконец, добавьте раздел [Install]. Это сообщит systemd, с чем связать эту службу, если вы включите ее запуск при загрузке. В этом случае настройте запуск службы, когда обычная многопользовательская система запущена и работает:

    [Unit]
    Description=uWSGI 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/uwsgi --ini myproject.ini
    
    [Install]
    WantedBy=multi-user.target
    

    На этом ваш служебный файл systemd готов. Сохраните и закройте его сейчас.

    Перед запуском службы uWSGI вам необходимо изменить права доступа, поскольку пользователь Nginx www-data не сможет по умолчанию читать файлы в вашем домашнем каталоге в Ubuntu 22.04 и новее. Это может помешать вам обслуживать веб-приложения из вашего домашнего каталога. Быстрое решение — изменить группу, связанную с вашим домашним каталогом, с помощью chgrp:

    1. sudo chgrp www-data /home/sammy

    Это позволит Nginx увидеть содержимое вашего домашнего каталога, которое ему необходимо для доступа к файлу сокета. Ни один из файлов в вашем домашнем каталоге не будет доступен в Интернете.

    Теперь вы можете запустить созданную вами службу uWSGI:

    1. sudo systemctl start myproject

    Затем включите его, чтобы он запускался при загрузке:

    1. sudo systemctl enable myproject

    Проверьте статус:

    1. sudo systemctl status myproject

    Вы увидите такой вывод:

    Output
    ● myproject.service - uWSGI instance to serve myproject Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: ena> Active: active (running) since Fri 2022-08-05 17:22:05 UTC; 6s ago Main PID: 4953 (uwsgi) Tasks: 6 (limit: 2327) Memory: 20.9M CPU: 241ms CGroup: /system.slice/myproject.service ├─4953 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4954 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4955 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4956 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini ├─4957 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini └─4958 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.ini

    Если вы видите какие-либо ошибки, обязательно устраните их, прежде чем продолжить обучение. В противном случае вы можете перейти к настройке установки Nginx для передачи запросов в сокет myproject.sock.

    Шаг 6 — Настройка Nginx для прокси-запросов

    Теперь ваш сервер приложений uWSGI запущен и работает, ожидая запросов к файлу сокета в каталоге проекта. На этом шаге вы настроите Nginx для передачи веб-запросов в этот сокет с использованием протокола uwsgi.

    Начните с создания нового файла конфигурации блока сервера в каталоге Nginx sites-available. Чтобы соответствовать остальной части руководства, в следующем примере это называется myproject:

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

    Откройте блок сервера и скажите Nginx прослушивать порт по умолчанию 80. Кроме того, скажите ему использовать этот блок для запросов доменного имени вашего сервера:

    server {
        listen 80;
        server_name your_domain www.your_domain;
    }
    

    Затем добавьте блок местоположения, соответствующий каждому запросу. В этот блок включите файл uwsgi_params, в котором указаны некоторые общие параметры uWSGI, которые необходимо установить. Затем передайте запросы в сокет, который вы определили с помощью директивы uwsgi_pass:

    server {
        listen 80;
        server_name your_domain www.your_domain;
    
        location / {
            include uwsgi_params;
            uwsgi_pass unix:/home/sammy/myproject/myproject.sock;
        }
    }
    

    Сохраните и закройте файл, когда закончите.

    Чтобы включить конфигурацию блока сервера Nginx, которую вы только что создали, свяжите файл с каталогом sites-enabled:

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

    Когда вы устанавливаете Nginx, процесс автоматически настраивает файл конфигурации блока сервера с именем default в каталоге sites-available, а затем создает символическую ссылку между этим файлом и sites-enabled каталог. Если вы оставите эту символическую ссылку на месте, конфигурация по умолчанию заблокирует загрузку вашего сайта. Вы можете удалить ссылку с помощью следующей команды:

    1. sudo unlink /etc/nginx/sites-enabled/default

    После этого вы можете проверить наличие синтаксических ошибок, набрав:

    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
    

    Вы увидите вывод вашего приложения:

    Если вы столкнулись с какими-либо ошибками, попробуйте проверить следующее:

    • 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: проверяет журналы uWSGI вашего приложения Flask.

    Шаг 7 — Защита приложения

    Чтобы обеспечить безопасность трафика на ваш сервер, получите SSL-сертификат для своего домена. Это можно сделать несколькими способами, в том числе получить бесплатный сертификат от Let’s Encrypt, создать самозаверяющий сертификат или купить его у коммерческого поставщика. Для удобства в этом руководстве объясняется, как получить бесплатный сертификат от Let’s Encrypt.

    Сначала установите Certbot и его подключаемый модуль Nginx с помощью apt:

    1. sudo apt install certbot 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, а затем запустит вызов, чтобы убедиться, что вы контролируете домен, для которого запрашиваете сертификат.

    Конфигурация будет обновлена, и Nginx перезагрузится, чтобы принять новые настройки. certbot завершится сообщением о том, что процесс прошел успешно и где хранятся ваши сертификаты:

    Output
    Successfully received certificate. Certificate is saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Key is saved at: /etc/letsencrypt/live/your_domain/privkey.pem This certificate expires on 2022-11-03. These files will be updated when the certificate renews. Certbot has set up a scheduled task to automatically renew this certificate in the background. Deploying certificate Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject Congratulations! You have successfully enabled HTTPS on https://your_domain and https://www.your_domain - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 мог взаимодействовать с ней, а затем настроили сервер приложений uWSGI для предоставления этой функции. После этого вы создали служебный файл systemd для автоматического запуска сервера приложений при загрузке. Вы также создали серверный блок Nginx, который передает трафик веб-клиента на сервер приложений, тем самым ретранслируя внешние запросы и защищая трафик на ваш сервер с помощью Let’s Encrypt.

    Flask — это гибкий фреймворк, предназначенный для предоставления вашим приложениям функциональности без чрезмерных ограничений в отношении структуры или дизайна. Вы можете использовать общий стек, описанный в этом руководстве, для обслуживания приложений flask, которые вы разрабатываете.