Project O - Flask deployen op Linux Fedora

01 - Doel en de onderdelen van hosting

Je gebruikt de werkende coins-app uit project N. Deployen betekent dat je die app op een server installeert en daar laat draaien. De browser gebruikt daarna het serveradres in plaats van je eigen computer.

Gunicorn is een serverprogramma dat een Flask-app via de WSGI-interface uitvoert. WSGI is de afspraak waarmee een webserver Python-apps aanroept. Apache ontvangt de openbare HTTP-aanvragen en stuurt ze door naar Gunicorn. Die rol heet reverse proxy. Gunicorn luistert alleen op de server zelf.

systemd beheert een programma als achtergrondservice: starten bij een herstart, stoppen en logs bewaren. firewalld bepaalt welke netwerkpoorten bereikbaar zijn. SELinux controleert daarnaast welke acties programma’s mogen uitvoeren. Hieronder leer je de benodigde opdrachten vóór je ze toepast.

02 - Servertoegang en terminalopdrachten begrijpen

Je hebt een Fedora-oefenserver en een bestaand gebruikersaccount met beheertoegang nodig. Het maken van een server of account valt buiten deze Python-opdracht; gebruik een door jou of je beheerder ingerichte oefenserver. Deze basisconfiguratie gebruikt één app op een server zonder bestaande websiteconfiguratie.

SSH opent een terminal op de server. Gebruik in onderstaande voorbeelden jouw loginnaam in plaats van leerling en jouw echte serveradres in plaats van 192.0.2.10. Dat IP-adres is alleen een documentatievoorbeeld. Voer op je eigen computer uit:

ssh leerling@192.0.2.10

Controleer bij de eerste verbinding de getoonde serversleutel met de informatie van je beheerder. Meld je aan met je bestaande toegang. Je ziet daarna de serverprompt. exit sluit die verbinding; zo onderscheid je lokale en serveropdrachten.

sudo voert één opdracht met beheerdersrechten uit. dnf installeert Fedora-pakketten, mkdir -p maakt mappen inclusief tussenliggende mappen, chown stelt de eigenaar in en ls -l toont bestanden en eigenaren. nano is een teksteditor in de terminal: opslaan met Ctrl+O, Enter en sluiten met Ctrl+X.

Installeer nu op de server de hulpmiddelen:

sudo dnf install python3 python3-pip httpd firewalld curl nano

httpd is de Fedora-pakketnaam voor Apache. curl vraagt vanuit een terminal een URL op. In de volgende stappen staat steeds aangegeven op welke computer je de opdracht uitvoert.

03 - Doelmap maken en bronbestanden kopiëren

Maak op de server de doelmap aan en geef je loginaccount het eigendom. Dezelfde gebruiker gaat straks de app uitvoeren en moet in data kunnen schrijven. Vervang leerling door je loginnaam:

sudo mkdir -p /srv/apps/coins
sudo chown leerling /srv/apps/coins

SCP kopieert bestanden via SSH. De schrijfwijze gebruiker@server:/pad/ geeft de bestemming aan. -r neemt een map met inhoud mee. Open een tweede, lokale terminal in je coins-projectmap en kopieer alleen de bronbestanden:

scp app.py database.py markt.py controle_db.py requirements.txt leerling@192.0.2.10:/srv/apps/coins/
scp -r templates static leerling@192.0.2.10:/srv/apps/coins/

Kopieer .venv niet: die maak je opnieuw op de server. Ook de database maak je in deze eerste deployment nieuw aan. Je lokale oefendatabase blijft op je eigen computer. Controleer in de serverterminal:

cd /srv/apps/coins
ls -l

Je ziet de vier Python-bestanden, requirements.txt en de mappen templates en static.

04 - Serveromgeving en database vóór het starten

Maak op de server de bekende projectomgeving aan en installeer de dependencies. Gunicorn is een extra pakket en wordt aan de lijst toegevoegd:

cd /srv/apps/coins
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m pip install gunicorn
python -m pip freeze > requirements.txt

In N, blok 12, heb je gezien dat een import het startblok van app.py overslaat. Gunicorn gaat de app importeren. Maak de database daarom nu expliciet aan met de bekende controle uit N:

python controle_db.py

Je ziet None bij een nieuwe database. data/coins.db en de tabel bestaan nu al voordat Gunicorn start. De gebruiker die deze opdracht uitvoert wordt ook de servicegebruiker in blok 06; daardoor kan SQLite in de datamap schrijven.

05 - Gunicorn los testen

De notatie app:app betekent: importeer module app.py en gebruik daaruit de variabele app. De interpreter en imports ken je uit hoofdstuk 8. --bind kiest adres en poort; 127.0.0.1:8000 is alleen vanaf de server bereikbaar. --workers 2 start twee werkprocessen.

Voer uit op de server, vanuit de actieve omgeving:

gunicorn --workers 2 --bind 127.0.0.1:8000 app:app

Open daarnaast een tweede SSH-terminal en controleer daar:

curl --fail http://127.0.0.1:8000/

--fail geeft een foutmelding bij een HTTP-foutstatus. Je ziet bij succes HTML met Bitcoin Dashboard. Als de API tijdelijk niet bereikbaar is, toont de app de lege toestand uit N. Stop Gunicorn in de eerste serverterminal met Ctrl+C voordat je de service start.

06 - Een systemd-service maken en testen

Een unitbestand beschrijft voor systemd hoe een service start. User kiest de bestaande login die eigenaar is van het project; WorkingDirectory kiest de projectmap en ExecStart de volledige startopdracht. De absolute locatie van Gunicorn gebruikt vanzelf de juiste virtual environment; handmatig activeren is voor systemd niet nodig.

Restart=on-failure herstart na een fout en RestartSec geeft de wachttijd. After=network.target bepaalt de startvolgorde, maar garandeert niet dat een externe API bereikbaar is. WantedBy=multi-user.target maakt starten bij de normale serverstart mogelijk.

Open op de server:

sudo nano /etc/systemd/system/coins.service

Plaats onderstaande inhoud en vervang bij User de voorbeeldnaam:

[Unit]
Description=Coins Flask dashboard
After=network.target

[Service]
User=leerling
WorkingDirectory=/srv/apps/coins
ExecStart=/srv/apps/coins/.venv/bin/gunicorn --workers 2 --bind 127.0.0.1:8000 app:app
Restart=on-failure
RestartSec=3

[Install]
WantedBy=multi-user.target

daemon-reload leest gewijzigde unitbestanden. enable --now schakelt automatisch starten in en start meteen. status toont de toestand:

sudo systemctl daemon-reload
sudo systemctl enable --now coins.service
systemctl status coins.service
curl --fail http://127.0.0.1:8000/

De toestand moet active (running) zijn en curl geeft de HTML terug. Ga pas daarna door naar Apache. Voor een latere codewijziging gebruik je sudo systemctl restart coins.service.

07 - Apache als reverse proxy configureren

Apache krijgt HTTP-verkeer op poort 80 en stuurt het naar Gunicorn op de lokale poort 8000. ProxyPass kiest het doel; ProxyPassReverse past door de achterliggende server gemaakte redirects aan. ProxyRequests Off schakelt een open forward proxy uit; onze app gebruikt alleen de reverse proxy.

Open op de server:

sudo nano /etc/httpd/conf.d/coins.conf

Zet hierin voor deze server met één oefenapp:

ProxyRequests Off
ProxyPass / http://127.0.0.1:8000/
ProxyPassReverse / http://127.0.0.1:8000/

apachectl configtest controleert de configuratie voordat de webserver start. De modules proxy_module en proxy_http_module verzorgen het doorsturen; controleer dat ze in de modulelijst staan:

sudo httpd -M
sudo apachectl configtest

Ga verder bij Syntax OK. De benodigde netwerktoestemming volgt in het volgende blok voordat we Apache starten.

08 - Netwerktoegang instellen en de openbare pagina testen

Er zijn twee controles: de firewall laat bezoekers op HTTP binnen, en SELinux moet Apache toestaan verbinding met Gunicorn te maken. setsebool wijzigt een SELinux-instelling; -P bewaart die wijziging. httpd_can_network_connect staat netwerkverbindingen vanuit Apache toe.

firewall-cmd beheert firewalld. --add-service=http opent de poort voor HTTP, --permanent bewaart de instelling en --reload activeert de opgeslagen regels. De SSH-toegang hoort bij de al ingerichte oefenserver; behoud die.

Voer op de server uit:

sudo setsebool -P httpd_can_network_connect on
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
sudo systemctl enable --now httpd
curl --fail http://127.0.0.1/

Open daarna op je eigen computer http://192.0.2.10/, met je echte serveradres. De cursusopdracht gebruikt de hoofdroute /; een ander pad vraagt extra proxyconfiguratie en wordt hier niet ingesteld. Klik op verversen en controleer of een meting wordt opgeslagen.

09 - Fouten per laag onderzoeken

Logs zijn de meldingen die programma’s tijdens het draaien schrijven. journalctl -u toont de logs van één service, -n 50 de laatste vijftig regels en --no-pager drukt ze direct af. tail -n 50 toont de laatste regels van een tekstbestand.

systemctl status coins.service
sudo journalctl -u coins.service -n 50 --no-pager
sudo journalctl -u httpd -n 50 --no-pager
sudo tail -n 50 /var/log/httpd/error_log
  • Werkt curl http://127.0.0.1:8000/ niet op de server? Begin bij Gunicorn, het pad in ExecStart en ontbrekende packages.
  • no such table betekent dat de initialisatie uit blok 04 niet is uitgevoerd voor deze database. attempt to write a readonly database vraagt om controle van eigenaar en schrijfrechten op de hele map data, niet alleen op het databasebestand.
  • Werkt 8000 wel, maar Apache geeft 502 of 503? Controleer proxyconfiguratie, de Apache-logs en de SELinux-netwerktoestemming.
  • Werkt de pagina via curl op de server, maar niet vanaf je eigen computer? Controleer IP-adres, firewalld en eventuele netwerkregels bij de hostingprovider.
  • Een API-fout hoort als melding in het dashboard te verschijnen. De laatst opgeslagen prijs blijft staan; controleer ook of de server externe HTTPS-aanvragen kan uitvoeren.

Schakel SELinux niet uit als oplossing. Bij een bestandscontextmelding leg je de concrete fout voor aan de serverbeheerder; de juiste context hangt af van het serverbeleid.

10 - Eindcontrole en vervolgstappen
  • Controleer dat coins.service en httpd actief zijn, de openbare pagina laadt en de knop een nieuwe meting opslaat.
  • Controleer met python controle_db.py vanuit de serveromgeving dat die meting in de serverdatabase staat. Je lokale database is een ander bestand.
  • Herstart alleen de app-service en controleer opnieuw: de opgeslagen meting blijft behouden en de app start zonder het Python-startblok uit te voeren.
  • Bewaar de werkende broncode, requirements en configuratie. Bij nieuwe code controleer je dependencies en herstart je de app-service.

Je hebt nu de keten browser → Apache → Gunicorn → Flask → API/SQLite opgebouwd en iedere laag afzonderlijk getest. Een eigen domeinnaam en HTTPS zijn afzonderlijke vervolgstappen; deze oefening configureert alleen HTTP. Gebruik voor die vervolgstappen de handleiding van je serverbeheerder of hostingprovider.

Naslag: Flask met Gunicorn, Apache mod_proxy en systemd-services.