Django

Všichni určitě máme rádi Python a kdo ne, ten Python nejspíš pořádně nikdy nevyzkoušel. Tento snadno naučitený jazyk, není nutně jen shell jazykem pro skriptovaní, ale může nalézt uplatnění i jinde, například pro vývoj jednoduchých a rychlých webů. Nebo často také pro tvorbu specializovaných webů ve Flask frameworku. Tento návod de týká toho, jak nastavit Nginx a uWSGI prostředí pro běh Flask aplikací.

Co že je vlastně uWSGI? Uwsgi je něco podobného jako php-fpm wrapper pro PHP. Funkcí je to wrapper pro spouštění aplikací napsaných v Python, umožňující mít Python stránky dostupné na http. Jde celkem snadno připůsobit, aby pracoval v kooperaci s Nginx.

Začneme instalací. Asi nepřekvapí, že nejnovější uWSGI se instaluje pomocí pip:

pip install uwsgi

Napíšeme si jednoduchý python skript v Flasku, abychom si mohli vyzkoušet spouštění aplikací s uWSGI:

from flask import Flask, render_template
from flask_wtf import FlaskForm

app = Flask(__name__)
app.config['SECRET_KEY'] = "secret-key"

@app.route('/')
def root():
        return "It's working..."

if __name__ == "__main__":
    #app.run(host='0.0.0.0', port=8000, debug=True)
    #app.run(host='::', port=8000, debug=True)
    app.run(port=8000, debug=True)

Skript spustíme pomocí uWSGI. Měli bychom vidět It's working... message na localhost:8000. Pokud bychom uWSGI potřebovali spustit na veřejné ip adrese, naspecifikujeme příkazu ještě ip adresu:

uwsgi --http :8000 --wsgi-file test.py
uwsgi --http [2001:aaaa:bb:c::ffff]:80 --wsgi-file test.py

V produkčním prostředí je lepší, aby se o uwsgi protokol a http requesty staral přímo Nginx. Nginx podporuje uwsgi protokol out-of-the-box. Jediné co je potřeba, je includnout /etc/nginx/uwsgi_params v konfiguráku Nginxu. Nginx bude naslouchat requestům na http a bude je posílat na unixový socket /tmp/uwsi.sock:

server {
    listen 80;
    server_name uwsgi.example.com;
    charset utf-8;
    location /static  {
        alias /path/to/project/project/static;
    }
    location / {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass unix:/tmp/uwsgi.sock;
    }
}

V adresáři /path/to/project/project/static se budou nacházet statické soubory. Například test.css, ty by pak mělo být dostupné na uwsgi.example.com/static/test.css, jestliže všechno funguje jak má.

Abychom pustili Nginx s uWSGI použijeme přímo socket, který napojíme na Nginx, pokud bychom v error.logu viděli permission denied, tak je potřeba použít volbu --chmod-socket:

uwsgi --socket /tmp/uwsgi.sock --chdir=/path/to/projectname --wsgi-file projectname/app.py
uwsgi --socket /tmp/uwsgi.sock --chdir=/path/to/projectname --wsgi-file projectname/app.py --chmod-socket=666

Pokud koukneme na uWSGI, zjistíme že uWSGI má asi milion konfiguračních parametrů. Psát je všechny do command line, by bylo náročné, a tak někdo chytrý vymyslel .ini file, kam jdou všechny konfigurační volby zapisovat najednou.

[uwsgi]
callable = app
virtualenv = /var/www/uwsgi-apps/
uid = www-data
gid = www-data
chdir = /var/www/uwsgi-apps/projects/test
wsgi-file = /var/www/uwsgi-apps/projects/test/app.py
processes = 2
max-requests = 5000
chmod-socket = 666
master = True
vacuum = True
socket = /var/www/uwsgi-apps/projects/test/uwsgi.sock
die-on-term = true
logto = /var/log/uwsgi/uwsgi.yono.cz.log

Soubor uložíme jako /etc/uwsgi/mysite.ini a spustíme:

uwsgi --ini /path/mysite.ini

V Emperror módu, můžeme pomocí uwsgi spouštět aplikace - neboli ini soubory, v terminologii uwsgi "vasaly" - tak, že uwsgi zadáme cestu k adresáři s ini soubory, a on si je všechny naloaduje.

uwsgi --emperor /var/www/uwsgi-apps/vassals --uid www-data --gid www-data

Určitě bychom rádi, aby jsme nemuseli uWSGI pokaždé pouštět ručně. To je možné vyřešit systemd servisou, kterou vytvoříme v /etc/systemd/system/uwsgi.service:

# /etc/systemd/system/uwsgi-flask.service
[Unit]
Description=uWSGI instance to serve project
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/uwsgi-apps/tmp/
Environment="PATH=/var/www/uwsgi-apps/bin/"
ExecStart=/var/www/uwsgi-apps/bin/uwsgi --emperor /var/www/uwsgi-apps/vassals --uid www-data --gid www-data

[Install]
WantedBy=multi-user.target

Nakonec ještě servisu dáme jako enable, aby se nám automaticky startovala po každém bootu.

Start uWSGI: systemctl start uwsgi
Restart: systemctl restart uwsgi
Stop: systemctl stop uwsgi
Check status: systemctl status uwsgi.service
Enable: systemctl enable uwsgi.service