Предположим, у вас есть Ubuntu, в котором нужно развернуть Nginx с Flask-приложением. Вам необходимо использовать WSGI сервер, например, Gunicorn. Gunicorn (Green Unicorn) — WSGI HTTP сервер на Python для UNIX систем. Представляю вольный перевод статьи Onur Guzel «How to Run Flask Applications with Nginx Using Gunicorn», где шаг за шагом показано процесс развертывания.


Шаг 0: Требования


Мы будет использовать virtualenv для работы с виртуальным окружением Python и pip для работы с Python-пакетами. Установим их введя в терминал следующую команду:

sudo apt-get install python-virtualenv python-pip

Создадим виртуальное окружение и активируем его:

virtualenv hello
source hello/bin/activate

Замечаем, что у нас prompt теперь начинается с названия виртуальной среды.


Шаг 1: Приложение


Установим Flask:

pip install Flask

После установки Flask, используя pip, вы можете написать следующий код в hello.py и запустить его:

from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
    return "Hello world!"
 
if __name__ == '__main__':
    app.run()

Flask имеет встроенный веб-сервер, который позволяет запускать приложения. Тем не менее, он не является масштабируемым и не подходит для production. С другой стороны, есть Gunicorn, который является готовым к использованию для production и обеспечивает масштабируемость.


Шаг 2: Gunicorn


Установим Gunicorn:

pip install gunicorn

Для того чтобы наше Flask-приложение работало с Gunicorn, нужно добавить 2 и 9 строки из кода в hello.py:

from flask import Flask
from werkzeug.contrib.fixers import ProxyFix
app = Flask(__name__)
 
@app.route('/')
def hello():
    return "Hello world!"

app.wsgi_app = ProxyFix(app.wsgi_app)
if __name__ == '__main__':
    app.run()

Теперь мы можем запустить приложение с Gunicorn:

gunicorn hello:app

Где hello это имя python-файла(без расширения). И app это имя Flask-объекта.


Шаг 3: Nginx


Создадим новую конфигурацию сервера и сохраним файл в:
/etc/nginx/sites-available/hello.conf
Содержимое hello.conf:

server {
    listen 80;
    server_name hello.itu24.com;
 
    root /path/to/hello;
 
    access_log /path/to/hello/logs/access.log;
    error_log /path/to/hello/logs/error.log;
 
    location / {
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://127.0.0.1:8000;
            break;
        }
    }
}

Создадим символическую ссылку для директории sites-enabled:

sudo ln -s /etc/nginx/sites-available/hello.conf /etc/nginx/sites-enabled/

Проверим конфигурацию на ошибки:

nginx -t

Если с конфигурацией все нормально, вы можете перезапустить Nginx и получить развернутое приложение.

Комментарии (7)


  1. Ungla
    17.09.2015 17:51

    А после перезагрузки сервера приложение так же будет отвечать?


    1. Core2Duo
      17.09.2015 18:01
      +2

      Нет, не будет. Автор описал очень малую часть, совсем малую. Gunicorn без конфигурации, nginx с минимумом. Для контроля и автоматического перезапуска обычно ставят еще и supervisor.


      1. Deepwalker
        17.09.2015 19:06
        +1

        Supervisor очень дельное замечание. Ну или если особые любители то runit хотя бы. И еще я вот требую нынче чтобы у каждого проекта в комплекте шел ansible плейбук.


  1. Core2Duo
    17.09.2015 18:11
    +2

    По опыту использования связки Cloudflare — nginx — gunicorn — django подскажу еще пару моментов.
    Если оба веб-сервера находятся на одной машине, то совсем необязательно выделять gunicorn'у отдельный порт, можно забиндить его на unix-сокет.
    С такой длинной цепочкой становится сложно получить реальный IP-адрес пользователя, поэтому не стоит забывать про пробросы заголовка X-Real-IP
    nginx:

    location / {
        proxy_pass         $scheme://your_proxy;
        proxy_redirect     off;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
    }
    

    В конфиг gunicorn'а стоит добавить строчку
    access_log_format = '%({x-real-ip}i)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'

    а то будете видеть в логах все запросы от локалхоста.


    1. intelligence
      18.09.2015 15:48
      +1

      Тогда уже добавить для полноты, как самому nginx узнавать реальный ip юзера
      support.cloudflare.com/hc/en-us/articles/200170706-How-do-I-restore-original-visitor-IP-with-Nginx-


  1. baldr
    17.09.2015 22:12
    +3

    На мой взгляд статья для перевода выбрана неудачно. Как мануал этот пост совершенно не поможет никому.
    gunicorn в терминале запускать — то же самое что dev-сервер, от которого, как сам автор замечает, никакого толку в продакшене. Значит надо запускать демона, описать минимальный конфиг gunicorn'а, упомянуть про выделенного юзера, рассказать про ключ "-D" и сколько воркеров нужно ставить. Хотя бы. Как минимум.
    Про supervisor тут уже упомянули. Это только один из способов, но в любом случае необходимо как-то обеспечить автозапуск же?

    В оригинальной статье уже в третьем комментарии упоминают, что «использовать if в location считается плохим подходом, лучше используйте try_files, что рекомендуется сообществом nginx». Это замечание было проигнорировано.

    VladimirPesterev, скажите, а в чем был смысл публиковать этот пост?

    Даже вот эта статья (первая ссылка из поиска google), на мой взгляд, недостаточно полна, но в ней хотя бы больше деталей.


  1. novoxudonoser
    17.09.2015 23:12
    +2

    Про супервизор уже сказали, а где потоки? где треды? Где треды, Карл ?! Где другие опции коих там чуть более чем много?