Hoe Flask-applicaties te serveren met Gunicorn en Nginx op Ubuntu 22.04

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

Introductie

In deze handleiding ga je een Python-toepassing bouwen met behulp van het Flask-microframework op Ubuntu 22.04. Het grootste deel van deze tutorial zal gaan over hoe je de Gunicorn-toepassingsserver kunt instellen en hoe je de toepassing kunt starten en Nginx kunt configureren om als een front-end omgekeerde proxy te fungeren.

Vereisten

Voordat je aan deze handleiding begint, moet je het volgende hebben:

  • Een server met Ubuntu 22.04 geïnstalleerd en een niet-root gebruiker met sudo-rechten. Volg onze handleiding voor de initiële serverconfiguratie voor begeleiding.

  • Nginx geïnstalleerd, volgens Stappen 1 en 2 van Hoe Nginx te installeren op Ubuntu 22.04.

  • Een domeinnaam geconfigureerd om naar uw server te wijzen. U kunt er een kopen op Namecheap of er een gratis krijgen op Freenom. U kunt leren hoe u domeinen naar DigitalOcean kunt verwijzen door de relevante documentatie over domeinen en DNS te volgen. Zorg ervoor dat u de volgende DNS-records aanmaakt:

    • Een A-record met uw_domein dat wijst naar het publieke IP-adres van uw server.
    • Een A-record met www.uw_domein dat wijst naar het publieke IP-adres van uw server.
  • Bekendheid met de WSGI-specificatie, die de Gunicorn-server zal gebruiken om te communiceren met uw Flask-toepassing. Dit gesprek behandelt WSGI meer in detail.

Stap 1 — Het installeren van de componenten uit de Ubuntu Repositories

De eerste stap is het installeren van alle vereiste onderdelen uit de Ubuntu-repositories. Dit omvat pip, de Python-pakketbeheerder, die de Python-componenten zal beheren. Je zult ook de Python-ontwikkelingsbestanden krijgen die nodig zijn om sommige van de Gunicorn-componenten te bouwen.

Eerst, update de lokale pakketindex en installeer de pakketten die je in staat stellen om je Python-omgeving op te bouwen. Deze zullen python3-pip omvatten, samen met nog een paar meer pakketten en ontwikkelingstools die nodig zijn voor een robuuste programmeeromgeving:

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

Met deze pakketten op hun plaats is de volgende stap het creëren van een virtuele omgeving voor je project.

Stap 2 — Het creëren van een Python Virtuele Omgeving

Vervolgens zul je een virtuele omgeving opzetten om de Flask-toepassing te isoleren van de andere Python-bestanden op je systeem.

Begin met het installeren van het python3-venv-pakket, dat de venv-module zal installeren:

  1. sudo apt install python3-venv

Maak vervolgens een hoofdmap voor je Flask-project. Ga naar de map met het cd commando nadat je deze hebt aangemaakt:

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

Maak een virtuele omgeving aan om de Python-vereisten van je Flask-project op te slaan door het volgende in te typen:

  1. python3 -m venv myprojectenv

Dit zal een lokale kopie van Python en pip installeren in een map genaamd myprojectenv binnen je projectmap.

Voordat je toepassingen binnen de virtuele omgeving installeert, moet je deze activeren. Doe dit door het volgende in te typen:

  1. source myprojectenv/bin/activate

Je prompt zal veranderen om aan te geven dat je nu binnen de virtuele omgeving werkt. Het zal er ongeveer zo uitzien: (myprojectenv)gebruiker@host:~/myproject$.

Stap 3 — Het opzetten van een Flask-toepassing

Nu je in je virtuele omgeving bent, kun je Flask en Gunicorn installeren en beginnen met het ontwerpen van je toepassing.

Installeer eerst wheel met de lokale instantie van pip om ervoor te zorgen dat je pakketten worden geïnstalleerd, zelfs als de wheel-archieven ontbreken:

  1. pip install wheel

Let op

Ongeacht welke versie van Python je gebruikt, wanneer de virtuele omgeving is geactiveerd, moet je het pip-commando gebruiken (niet pip3).

Vervolgens installeer je Flask en Gunicorn:

  1. pip install gunicorn flask

Het maken van een voorbeeld-app

Nu je Flask beschikbaar hebt, kun je een eenvoudige applicatie maken. Flask is een microframework. Het bevat niet veel van de tools die meer uitgebreide frameworks zouden kunnen bevatten, en bestaat voornamelijk als een module die je kunt importeren in je projecten om je te helpen bij het initialiseren van een webapplicatie.

Hoewel je applicatie misschien complexer is, zullen we onze Flask-applicatie in één bestand maken, genaamd myproject.py:

  1. nano ~/myproject/myproject.py

De applicatiecode zal in dit bestand leven. Het zal Flask importeren en een Flask-object instantiëren. Hiermee kun je de functies definiëren die moeten worden uitgevoerd wanneer een specifieke route wordt aangevraagd:

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

Dit definieert in feite welke inhoud moet worden weergegeven wanneer het hoofddomein wordt benaderd. Sla het bestand op en sluit het af wanneer je klaar bent.

Als je de initiële serverconfiguratiegids hebt gevolgd, zou je een UFW-firewall ingeschakeld moeten hebben. Om de applicatie te testen, moet je toegang toestaan tot poort 5000:

  1. sudo ufw allow 5000

Nu kun je je Flask-app testen door het volgende te typen:

  1. python myproject.py

Je zult output zien zoals het volgende, inclusief een nuttige waarschuwing die je eraan herinnert deze serverconfiguratie niet in productie te gebruiken:

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)

Bezoek het IP-adres van je server gevolgd door :5000 in je webbrowser:

http://your_server_ip:5000

Je zou iets als dit moeten zien:

Wanneer je klaar bent, druk je op CTRL-C in je terminalvenster om de Flask-ontwikkelingsserver te stoppen.

Het creëren van het WSGI-toegangspunt

Vervolgens maak je een bestand aan dat zal dienen als het toegangspunt voor je applicatie. Dit vertelt de Gunicorn-server hoe te communiceren met de applicatie.

Geef het bestand de naam wsgi.py:

  1. nano ~/myproject/wsgi.py

In dit bestand importeer je de Flask-instantie vanuit onze applicatie en voer je deze vervolgens uit:

~/myproject/wsgi.py
from myproject import app

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

Sla het bestand op en sluit het af wanneer je klaar bent.

Stap 4 — Configuratie van Gunicorn

Je applicatie is nu geschreven met een ingesteld toegangspunt. Je kunt nu doorgaan met het configureren van Gunicorn.

Voordat je verder gaat, controleer of Gunicorn de applicatie correct kan bedienen.

Dit kun je doen door het de naam van het toegangspunt van de applicatie mee te geven. Dit wordt geconstrueerd als de naam van de module (zonder de .py-extensie), plus de naam van de aanroepbare functie binnen de applicatie. In dit geval is dat wsgi:app.

Specificeer ook de interface en poort om aan te binden met behulp van het argument 0.0.0.0:5000 zodat de applicatie zal worden gestart op een publiek beschikbare interface:

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

Je zou uitvoer moeten zien zoals het volgende:

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

Bezoek opnieuw het IP-adres van uw server met :5000 toegevoegd aan het einde in uw webbrowser:

http://your_server_ip:5000

Je zou de uitvoer van je applicatie moeten zien:

Wanneer je hebt bevestigd dat het goed functioneert, druk je op CTRL-C in je terminalvenster.

Als je klaar bent met het gebruik van de virtuele omgeving, kun je deze deactiveren:

  1. deactivate

Alle Python-opdrachten zullen nu weer de Python-omgeving van het systeem gebruiken.

Vervolgens maak je het systemd-servicelicentiebestand aan. Het maken van een systemd-servicelicentiebestand zal het init-systeem van Ubuntu automatisch Gunicorn starten en de Flask-applicatie bedienen wanneer de server opstart.

Maak een eenheid-bestand aan met de extensie .service binnen de map /etc/systemd/system om te beginnen:

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

Daarin begin je met de sectie [Unit], die wordt gebruikt om metagegevens en afhankelijkheden te specificeren. Voeg hier een beschrijving van uw service toe en vertel het init-systeem om dit pas te starten nadat het netwerkdoel is bereikt:

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

Vervolgens voeg je een [Service]-sectie toe. Hiermee specificieer je de gebruiker en groep waaronder je wilt dat het proces wordt uitgevoerd. Geef je reguliere gebruikersaccount eigenaarschap van het proces aangezien het alle relevante bestanden bezit. Geef ook groepseigenaarschap aan de groep www-data zodat Nginx gemakkelijk kan communiceren met de Gunicorn-processen. Vergeet niet om hier de gebruikersnaam te vervangen met jouw gebruikersnaam:

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

[Service]
User=sammy
Group=www-data

Volgende, breng de werkmappen in kaart en stel de omgevingsvariabele PATH in zodat het init-systeem weet dat de uitvoerbare bestanden voor het proces zich bevinden binnen onze virtuele omgeving. Specificeer ook het commando om de service te starten. Dit commando zal het volgende doen:

  • Start 3 werkprocessen (hoewel je dit indien nodig moet aanpassen)
  • Maak een Unix-socketsbestand aan, myproject.sock, binnen onze projectmap en bind het eraan. We stellen een umask-waarde van 007 in zodat het socketsbestand wordt gemaakt met toegang voor de eigenaar en de groep, terwijl andere toegang wordt beperkt
  • Specificeer de naam van het WSGI-ingangspuntbestand, samen met de Python-functie binnen dat bestand (wsgi:app)

Systemd vereist dat je het volledige pad naar het Gunicorn-uitvoerbare bestand opgeeft, dat is geïnstalleerd binnen je virtuele omgeving.

Vergeet niet om de gebruikersnaam en projectpaden te vervangen door je eigen informatie:

/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

Tenslotte, voeg een [Install]-sectie toe. Dit vertelt systemd waaraan deze service moet worden gekoppeld als je hem inschakelt om bij het opstarten te starten. Je wilt dat deze service start wanneer het reguliere multi-user systeem actief en operationeel is:

/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

Met dit is je systemd-servicebestand compleet. Sla het nu op en sluit het af.

Je kunt nu de Gunicorn-service die je hebt gemaakt starten en deze inschakelen zodat deze bij het opstarten start:

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

Laten we de status controleren:

  1. sudo systemctl status myproject

Je zou output als deze moeten zien:

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

Als je fouten ziet, zorg er dan voor dat je ze oplost voordat je verdergaat met de tutorial.

Stap 5 — Configuratie van Nginx voor het doorsturen van verzoeken

Je Gunicorn-toepassingsserver zou nu actief moeten zijn en wachten op verzoeken op het socketbestand in de projectdirectory. Nu kun je Nginx configureren om webverzoeken naar dat socket door te sturen door enkele kleine wijzigingen aan te brengen in het configuratiebestand.

Begin met het maken van een nieuw serverblok configuratiebestand in de sites-available directory van Nginx. Noem dit myproject om in lijn te blijven met de rest van de handleiding:

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

Open een serverblok en vertel Nginx om te luisteren op de standaard poort 80. Vertel het ook om dit blok te gebruiken voor verzoeken voor de domeinnaam van onze server:

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

Voeg vervolgens een locatieblok toe dat overeenkomt met elk verzoek. Binnen dit blok voeg je het proxy_params bestand toe dat enkele algemene proxyparameters specificeert die moeten worden ingesteld. Je zult dan de verzoeken doorsturen naar het socket dat je hebt gedefinieerd met behulp van de proxy_pass richtlijn:

/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;
    }
}

Sla het bestand op en sluit het af wanneer je klaar bent.

Om de Nginx-serverblokconfiguratie die je zojuist hebt gemaakt te activeren, link je het bestand naar de sites-enabled directory:

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

Met het bestand in die directory kun je testen op syntaxisfouten:

  1. sudo nginx -t

Als dit terugkomt zonder enige problemen aan te geven, herstart dan het Nginx-proces om de nieuwe configuratie in te lezen:

  1. sudo systemctl restart nginx

Tenslotte, pas de firewall opnieuw aan. Je hebt geen toegang meer nodig via poort 5000, dus je kunt die regel verwijderen. Je kunt dan volledige toegang toestaan tot de Nginx-server:

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

Je zou nu naar de domeinnaam van je server moeten kunnen navigeren in je webbrowser:

http://your_domain

Je zou de uitvoer van je applicatie moeten zien:

Opmerking: Je krijgt een HTTP 502 gatewayfout als Nginx geen toegang heeft tot het socketbestand van gunicorn. Meestal komt dit doordat de thuismap van de gebruiker andere gebruikers niet toestaat om bestanden erin te openen.

Als je socketbestand /home/sammy/myproject/myproject.sock heet, zorg er dan voor dat /home/sammy minimaal 0755 rechten heeft. Je kunt een tool zoals chmod gebruiken om de rechten als volgt te wijzigen:

  1. sudo chmod 755 /home/sammy

Vernieuw dan de pagina om te zien of de HTTP 502-fout verdwijnt.

Als je fouten tegenkomt, probeer dan het volgende te controleren:

  • sudo less /var/log/nginx/error.log: controleert de Nginx-foutenlogboeken.
  • sudo less /var/log/nginx/access.log: controleert de Nginx-toegangslogboeken.
  • sudo journalctl -u nginx: controleert de Nginx-proceslogboeken.
  • sudo journalctl -u myproject: controleert de Gunicorn-logboeken van je Flask-applicatie.

Stap 6 — Het beveiligen van de applicatie

Om ervoor te zorgen dat het verkeer naar uw server veilig blijft, laten we een SSL-certificaat voor uw domein verkrijgen. Er zijn meerdere manieren om dit te doen, waaronder het verkrijgen van een gratis certificaat van Let’s Encrypt, het genereren van een zelfondertekend certificaat, of het kopen van een van een andere aanbieder en het configureren van Nginx om het te gebruiken door Stappen 2 tot en met 6 te volgen van Hoe maak je een zelfondertekend SSL-certificaat voor Nginx in Ubuntu 22.04. We zullen optie één (Let’s Encrypt) gebruiken omwille van de snelheid.

Installeer de Nginx-pakket van Certbot met apt:

  1. sudo apt install python3-certbot-nginx

Certbot biedt verschillende manieren om SSL-certificaten te verkrijgen via plugins. De Nginx-plugin zal zorgen voor het herconfigureren van Nginx en het opnieuw laden van de configuratie wanneer nodig. Om deze plugin te gebruiken, typ het volgende:

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

Dit voert certbot uit met de --nginx plugin, waarbij -d wordt gebruikt om de namen op te geven waarvoor het certificaat geldig moet zijn.

Als dit de eerste keer is dat je certbot uitvoert, wordt je gevraagd om een e-mailadres in te voeren en akkoord te gaan met de servicevoorwaarden. Nadat je dat hebt gedaan, zal certbot communiceren met de Let’s Encrypt-server, vervolgens een uitdaging uitvoeren om te verifiëren dat je het domein waarvoor je een certificaat aanvraagt, beheert.

Als dat succesvol is, zal certbot vragen hoe je je HTTPS-instellingen wilt configureren:

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

Kies je optie en druk op ENTER. De configuratie wordt bijgewerkt en Nginx zal worden herladen om de nieuwe instellingen op te pikken. certbot zal afsluiten met een bericht waarin staat dat het proces succesvol was en waar je certificaten zijn opgeslagen:

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

Als je de Nginx-installatie-instructies in de prerequisites hebt gevolgd, heb je de overbodige HTTP-profieltoewijzing niet langer nodig:

  1. sudo ufw delete allow 'Nginx HTTP'

Om de configuratie te controleren, navigeer opnieuw naar je domein, met behulp van https://:

https://your_domain

Je zou opnieuw de uitvoer van je applicatie moeten zien, samen met de beveiligingsindicator van je browser, die moet aangeven dat de site beveiligd is.

Conclusie

In deze handleiding hebt u een eenvoudige Flask-toepassing gemaakt en beveiligd binnen een Python virtuele omgeving. U hebt een WSGI-ingangspunt gemaakt zodat elke WSGI-compatibele toepassingsserver ermee kan communiceren, en vervolgens de Gunicorn-app-server geconfigureerd om deze functie te bieden. Daarna hebt u een systemd-servicebestand gemaakt om de toepassingsserver automatisch op te starten bij het opstarten. U hebt ook een Nginx-serverblok gemaakt dat webclientverkeer doorstuurt naar de toepassingsserver, externe verzoeken doorgeeft en het verkeer naar uw server beveiligt met Let’s Encrypt.

Flask is een zeer eenvoudig maar uiterst flexibel framework dat bedoeld is om uw toepassingen functionaliteit te bieden zonder te strikt te zijn over structuur en ontwerp. U kunt de algemene stack gebruiken die in deze handleiding wordt beschreven om de door u ontworpen Flask-toepassingen te serveren.

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