Een Wagtail-site implementeren met Gunicorn, Nginx en Supervisor

Deze tutorial legt uit hoe je Gunicorn, Nginx en Supervisor op een Linux-server kunt installeren om een Django Wagtail-site te runnen.

16 juli 2020 09:10
Thema's: Deployment

In een eerdere tutorial hebben we ons project lokaal op een DigitalOcean-server geïmplementeerd. We gaan nu Gunicorn en Nginx installeren om onze site live te zetten op internet, zoals ook wordt beschreven in een DigitalOcean-tutorial. Onze opzet zal echter iets anders zijn: we zullen een Gunicorn-configuratiebestand gebruiken en Supervisor gebruiken om zowel Gunicorn als Nginx te beheren. Er zijn meer tutorials, zoals deze uitgebreide gids. Linux-tutorials zijn hier en hier te vinden.

Gunicorn zal dienen als applicatieserver, Nginx als webserver en reverse proxy en Supervisor als managementtool. Gunicorn zal onze site runnen en dynamische inhoud (uit de database) aanbieden en zal worden geïnstalleerd in dezelfde virtuele omgeving als onze site. Nginx zal statische inhoud (media en afbeeldingen) leveren en verzoeken voor andere inhoud delegeren aan Gunicorn. Nginx wordt op de server geïnstalleerd, buiten de virtuele omgeving. Supervisor zal ook op de server worden geïnstalleerd en zal worden gebruikt om zowel Nginx als Gunicorn te starten, stoppen en configureren. De stappen zijn:

  • productie-instellingen bijwerken
  • Gunicorn installeren en configureren
  • Nginx installeren en configureren
  • Supervisor installeren en configureren
  • de site runnen
1. Productie-instellingen bijwerken

Tot nu toe hebben we alleen de ontwikkel-instellingen van ons project gebruikt. Met Gunicorn en Nginx gebruiken we de productie-instellingen, waarbij debug = False. We moeten nu de parameter ALLOWED_HOSTS instellen, anders genereert Django een Bad Request error. We veranderen de instellingen op onze ontwikkelcomputer, pushen ze naar de repository en halen ze vanaf onze server daar vandaan. Voeg in je productie.py-instellingenbestand de regel toe:

ALLOWED_HOSTS = ['pythoneatstail.com', 'www.pythoneatstail.com',]

Push de wijziging naar de repository:

git add .
git commit -m "added allowed hosts"
git push

Ga naar de server, activeer de virtuele omgeving, ga de projectmap in en typ:

git pull origin master

Kijk in het bestand production.py of de wijziging is aangebracht. Verzamel ook alle statische bestanden in de directory /static/, zodat ze later door de webserver kunnen worden opgehaald:

python3 manage.py collectstatic
2. Gunicorn installeren en configureren

Log in op de server als de gebruiker die we hebben gecreëerd (gebruik je eigen IP-adres):

ssh usr_pet@165.22.199.4

Ga de virtuele omgeving in en installeer Gunicorn:

source env/bin/activate 
pip3 install gunicorn

Om te testen of Gunicorn de site kan bedienen, ga naar de map van je project en typ:

gunicorn --bind 0.0.0.0:8000 pet.wsgi

Een bezoek aan de site met de browser op http://165.22.199.4:8000 (vervang het IP-adres) zou hetzelfde resultaat moeten opleveren als in de vorige tutorial met de opdracht runserver. Sluit Gunicorn af met ctrl-C.

Er zijn verschillende manieren om de configuratie voor Gunicorn te definiëren. We kunnen een servicebestand maken voor de opdracht systemd, of een bash-script maken. Hier maken we een Gunicorn-configuratiebestand, zoals beschreven in de Gunicorn-documentatie. We kunnen het bestand overal plaatsen; om dicht bij de bestandsorganisatie van Linux te blijven, zullen we een directory /etc maken voor configuratiebestanden met een submap /gunicorn:

mkdir -p ~/env/etc/gunicorn
cd ~/env/etc/gunicorn
touch conf.py

De Gunicorn-repository bevat een voorbeeldconfiguratiebestand. We zullen enkele van de instellingen kopiëren die we nodig hebben. Laten we beginnen met een paar eenvoudige, die in het voorbeeldbestand worden uitgelegd. Open conf.py met vi of een andere editor en voeg toe:

workers = 3
keepalive = 5
user = 'usr_pet'
proc_name = 'pet'

We voegen ook informatie toe over hoe we willen loggen:

loglevel = 'error'
errorlog = '/home/usr_pet/env/var/log/gunicorn-error.log'
accesslog = '/home/usr_pet/env/var/log/gunicorn-access.log'

De opgegeven bestanden bestaan nog niet. We hoeven de bestanden niet te maken, maar we moeten er wel voor zorgen dat de directory bestaat, dus sluit de editor tijdelijk af en maak een directory ~/env/var/log aan. Maak ook een map ~/env/run voor het socketbestand (zie hieronder).

mkdir -p ~/env/var/log
mkdir ~/env/run

Keer terug naar het bewerken van het configuratiebestand conf.py. Essentieel is de bind-parameter, die Gunicorn vertelt wat de interface is om met de buitenwereld te communiceren. Hierboven gebruikten we een IP-adres, nu gebruiken we een bestand (een unix-socketbestand) waarmee Gunicorn zal communiceren met Nginx (dat op zijn beurt verbinding zal maken met een IP-adres). Gunicorn zal dat bestand zelf aanmaken, maar de directory moet bestaan. De syntaxis is:

bind = 'unix:/home/usr_pet/env/run/gunicorn.sock'

We hebben een manier nodig om Gunicorn te vertellen de productie-instellingen van ons project te gebruiken. De Django-parameter hiervoor is DJANGO_SETTINGS_MODULE en we kunnen deze instellen met de Gunicorn-parameter raw_env (zie ook voorbeeldbestand):

raw_env = ['DJANGO_SETTINGS_MODULE=pet.settings.production',]

Om ervoor te zorgen dat Gunicorn het Django-instellingenbestand kan vinden, moeten we het Python-pad specificeren:

pythonpath = '/home/usr_pet/pet'

Hiermee is het configuratiebestand van Gunicorn klaar.

3. Nginx installeren en configureren

Verlaat indien nodig de virtuele omgeving en installeer Nginx:

sudo apt-get update
sudo apt-get install nginx

Nginx maakt een generiek configuratiebestand aan op /etc/nginx/nginx.conf, en twee directories /sites-available en /sites-enabled. We zullen een configuratiebestand voor een serverblok maken in de map /sites-available. Maak het bestand (we noemen het pet) en open het met je editor (in ons geval vi; gebruik sudo voor schrijfrechten):

sudo vi /etc/nginx/sites-available/pet

In dit bestand plaatsen we een serverblok met een aantal instellingen (zie "Configure Nginx to Proxy Pass to Gunicorn"):

  • domeinnaam/namen van de server
  • pad naar logbestanden
  • location-blokken die ons vertellen hoe we met verschillende uri's moeten omgaan

Voeg de volgende inhoud toe en sla het bestand op; zie hieronder voor de uitleg.

server {
    server_name pythoneatstail.com www.pythoneatstail.com;

    access_log /home/usr_pet/env/var/log/nginx-access.log;
    error_log /home/usr_pet/env/var/log/nginx-error.log;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/usr_pet/pet;
    }
    location /media/ {
        root /home/usr_pet/pet;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/usr_pet/env/run/gunicorn.sock;
    }
}

De eerste regel specificeert de domeinnamen van onze site, de tweede en derde de logbestanden. Het eerste location-statement vertelt Nginx om mogelijke problemen met het vinden van een favicon te negeren. Het tweede en derde location-statement specificeren de locatie van de statische en mediabestanden in ons project, zodat Nginx deze direct kan bedienen als daarom wordt gevraagd. Het laatste statement behandelt alle andere verzoeken en verwijst naar het socketbestand dat we eerder hebben gemaakt, waardoor het verzoek via proxy wordt overgedragen aan Gunicorn. Het bevat een parameterbestand proxy_params gemaakt tijdens installatie in de directory /etc/nginx.

De daadwerkelijke Nginx-instellingen worden opgehaald uit de directory /sites-enabled, dus we maken daar een symbolische link van /sites-available:

sudo ln -s /etc/nginx/sites-available/pet /etc/nginx/sites-enabled

Test de Nginx-configuratie op fouten met:

sudo nginx -t

Gebruik de systemctl opdracht om te controleren of Nginx actief is; het zou moeten laten zien dat Nginx "active (running)" is.

sudo systemctl status nginx

We kunnen nu controleren of Gunicorn en Nginx gegevens kunnen uitwisselen via het socketbestand, door Gunicorn uit te voeren met zijn configuratiebestand:

sudo /home/usr_pet/env/bin/gunicorn pet.wsgi:application --config /home/usr_pet/env/etc/gunicorn/conf.py

Hier leidt het eerste pad naar het Gunicorn-uitvoeringsbestand, het argument pet.wsgi:application is de variabele application binnen het bestand pet.wsgi in het project, en het tweede pad leidt naar het configuratiebestand dat we hierboven hebben gemaakt. Deze opdracht start Gunicorn op de voorgrond en bezet tijdelijk het terminalvenster. Bezoek in je browser je domein (www.pythoneatstail.com); als alles in orde is, heb je toegang tot je site. Je kunt controleren of Gunicorn het socketbestand heeft gemaakt door een tweede terminal te openen en de inhoud van de directory /home/usr_pet/env/run te bekijken. Stop het Gunicorn-proces in de eerste terminal met ctrl-C. Het socketbestand is verdwenen.

4. Supervisor installeren en configureren

We zullen Supervisor gebruiken om zowel het Gunicorn- als het Nginx-proces te bewaken en te controleren. Het is iets eenvoudiger en gebruiksvriendelijker dan het ingebouwde Systemd en kan delegeren aan niet-rootgebruikers. Supervisor kan in de virtuele omgeving worden geïnstalleerd, maar aangezien we het willen gebruiken om Nginx te beheren, dat op de server is geïnstalleerd, is dit niet erg logisch en vereist meer configuratie. Installeren kan via pip, maar we zullen apt-get gebruiken zoals aanbevolen door DigitalOcean, ondanks het feit dat het ons een oudere versie geeft:

sudo apt-get install supervisor

Supervisor heeft een configuratiebestand gemaakt in /etc/supervisor. Als je het bekijkt, kun je zien dat het alle toepassingsspecifieke configuratiebestanden in de submap /conf.d laadt. Ga naar die submap, maak een bestand guni-pet.conf en plak de volgende inhoud:

[program:guni-pet]
command=/home/usr_pet/env/bin/gunicorn pet.wsgi:application --config /home/usr_pet/env/etc/gunicorn/conf.py
user=usr_pet
autostart=true
autorestart=true

Alle configuratieparameters staan in de documentatie. De eerste regel specificeert het uitvoeringscommando dat we eerder gebruikten, de tweede regel specificeert de gebruiker en de derde en vierde regel vertellen Supervisor om het proces automatisch te starten en herstarten na een exit. Maak voor Nginx een bestand nginx-pet.conf en plak:

[program:nginx-pet]
command=/usr/sbin/nginx -g "daemon off;"
autostart=true
autorestart=true
stderr_logfile=/home/usr_pet/env/var/log/nginx-error.log
stdout_logfile=/home/usr_pet/env/var/log/nginx-access.log

In de opdracht zetten we "daemon off" met de -g optie omdat Supervisor eist dat subprocessen op de voorgrond draaien. Deze keer specificeren we geen gebruiker, omdat Nginx door root is geïnstalleerd en daarom door root moet worden uitgevoerd. Om dezelfde reden herhalen we de logfile locaties, om er zeker van te zijn dat de logs daar terecht komen.

Dat voltooit de configuratie van Supervisor. De client van Supervisor voor de opdrachtregel is supervisorctl. Voeg de nieuwe configuraties toe aan Supervisor met:

sudo supervisorctl reread
sudo supervisorctl update
5. De site runnen

Dit zou nu zo simpel moeten zijn als:

sudo supervisorctl start all

waarmee Gunicorn en Nginx gestart worden. Ga naar je domeinadres in je browser (in ons geval www.pythoneatstail.com) en kijk of het werkt. Stop een van de processen, start ze opnieuw, controleer de status met behulp van de verschillende Supervisor-opdrachten (met <procesnaam> guni-pet of nginx-pet):

sudo supervisorctl status [optional: <process-name>]
sudo supervisorctl start <process-name>
sudo supervisorctl stop <process-name>
sudo supervisorctl restart <process-name>

Als we geen inhoud hebben gemaakt, is onze site nog steeds leeg. We kunnen hem handmatig vullen of een back-up gebruiken; lees een volgende tutorial hierover. We zullen ook een firewall opzetten, https inschakelen en ssh-toegangssleutels instellen.

Reageer op dit artikel (log eerst in of bevestig hieronder met naam en email)