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

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


Введение

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

Предпосылки

Для выполнения этого урока вам понадобятся:

  • Сервер с установленной Ubuntu 18.04 и пользователем без полномочий root с привилегиями sudo и включенным брандмауэром. Следуйте нашему руководству по первоначальной настройке сервера.
  • Nginx установлен, следуя шагам 1 и 2 инструкции по установке Nginx в Ubuntu 18.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

    Затем настройте виртуальную среду, чтобы изолировать приложение Flask от других файлов Python в системе.

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

    1. sudo apt install python3-venv

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

    1. mkdir ~/myproject

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

    1. cd ~/myproject

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

    1. python3.6 -m venv myprojectenv

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

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

    1. source myprojectenv/bin/activate

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

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

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

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

    1. pip install wheel

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

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

    1. pip install uwsgi flask

    После завершения установки вы можете начать использовать Flask.

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

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

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

    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 и ENTER.

    Если вы следовали руководству по первоначальной настройке сервера, у вас должен быть включен брандмауэр 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

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

    Сначала создайте и назовите файл wsgi.py:

    1. nano ~/myproject/wsgi.py

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

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

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

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

    Теперь ваше приложение написано с установленной точкой входа. Теперь вы можете перейти к настройке 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:

    [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.

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

    Шаг 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. Не забудьте заменить имя пользователя здесь своим именем пользователя:

    [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 и включить ее, чтобы она запускалась при загрузке:

    1. sudo systemctl start myproject
    2. 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 Active: active (running) since Mon 2021-10-25 22:34:52 UTC; 14s ago Main PID: 9391 (uwsgi) Tasks: 6 (limit: 1151) CGroup: /system.slice/myproject.service ├─9391 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9410 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9411 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9412 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i ├─9413 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i └─9414 /home/sammy/myproject/myprojectenv/bin/uwsgi --ini myproject.i

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

    Шаг 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

    С файлом в этом каталоге вы можете проверить наличие синтаксических ошибок, выполнив следующее:

    1. sudo nginx -t

    Если это возвращается без каких-либо проблем, перезапустите процесс Nginx, чтобы прочитать новую конфигурацию:

    1. sudo systemctl restart nginx

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

    1. sudo ufw delete allow 5000

    После этого вы разрешите доступ к серверу Nginx:

    1. 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-сертификат для своего домена. Есть несколько способов сделать это, в том числе получить бесплатный сертификат от Как защитить Nginx с помощью Let’s Encrypt в Ubuntu 18.04.

    Сначала добавьте репозиторий Certbot Ubuntu:

    1. sudo add-apt-repository ppa:certbot/certbot

    Вам нужно будет нажать ENTER, чтобы принять.

    Затем установите пакет Certbot Nginx с помощью apt:

    1. sudo apt install python-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 2022-01-24. 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 мог с ней взаимодействовать, а затем настроили сервер приложений uWSGI для предоставления этой функции. После этого вы создали служебный файл systemd для автоматического запуска сервера приложений при загрузке. Вы также создали серверный блок Nginx, который передает трафик веб-клиента на сервер приложений, ретранслируя внешние запросы и защищенный трафик на ваш сервер с помощью Let’s Encrypt.

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