Tag archieven: Apache

Flask API via Apache

In de vorige post Mod_wsgi in Apache hebben we de module in Apache 2.4 op Centos7 beschikbaar gemaakt. Het gebruik daarentegen is de volgende stap.

Laten we eerst beginnen met een simpele API in de default document root ‘/var/www/html/’ waar we een directory maken api_test. Daarin maken we een virtuele omgeving via python3.8 en zetten wat structuur klaar:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mkdir /var/www/html/api_test
mkdir /var/www/html/api_test/api
cd /var/www/html/api_test
python3.8 -m venv venv
touch api.wsgi
touch api/__init__.py
mkdir /var/www/html/api_test mkdir /var/www/html/api_test/api cd /var/www/html/api_test python3.8 -m venv venv touch api.wsgi touch api/__init__.py
mkdir /var/www/html/api_test
mkdir /var/www/html/api_test/api
cd /var/www/html/api_test
python3.8 -m venv venv
touch api.wsgi
touch api/__init__.py

We activeren de virtual environment en zorgen dat pip geüpdatet is in deze ‘venv’ en installeren we de juiste package, namelijk Flask:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
source venv/bin/activate
python -m pip install --upgrade pip
pip install flask
source venv/bin/activate python -m pip install --upgrade pip pip install flask
source venv/bin/activate
python -m pip install --upgrade pip
pip install flask

De uiteindelijke directory structuur en bestanden word dan:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
api_test/
├── api/
│ ├── __init__.py
├── venv/
└── api.wsgi
api_test/ ├── api/ │ ├── __init__.py ├── venv/ └── api.wsgi
api_test/
├── api/
│   ├── __init__.py
├── venv/
└── api.wsgi

De API, voor nu een simpele JSON output van zichzelf en de Flask App zijn weggezet in het __init__.py bestand. Dit is een redelijk plat geval:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from flask import request, jsonify, Flask
import socket
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
@app.route('/', defaults={'path': ''})
@app.route('/', methods=['GET'])
def info():
return jsonify({
"name": "Test program",
"version": "0.1a",
"hostname": socket.gethostname(),
"ip": request.remote_addr,
}), 200
from flask import request, jsonify, Flask import socket app = Flask(__name__) app.config['JSON_SORT_KEYS'] = False @app.route('/', defaults={'path': ''}) @app.route('/', methods=['GET']) def info(): return jsonify({ "name": "Test program", "version": "0.1a", "hostname": socket.gethostname(), "ip": request.remote_addr, }), 200
from flask import request, jsonify, Flask
import socket

app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False

@app.route('/', defaults={'path': ''})
@app.route('/', methods=['GET'])
def info():
    return jsonify({
        "name": "Test program",
        "version": "0.1a",
        "hostname": socket.gethostname(),
        "ip": request.remote_addr,
    }), 200

In het ‘wsgi’ bestand wat Apache gaat lezen instrueren we wat er gestart moet en een aantal path variabelen. De verwijzing naar de juiste package directory is vanwege de ‘virtual environment’. De andere is om de import van de API te laten werken. Uiteindelijk importeren wij dus uit de api de app als application

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import sys
sys.path.insert(0, '/var/www/html/api_test/venv/lib/python3.8/site-packages')
sys.path.insert(1, '/var/www/html/api_test')
from api import app as application
import sys sys.path.insert(0, '/var/www/html/api_test/venv/lib/python3.8/site-packages') sys.path.insert(1, '/var/www/html/api_test') from api import app as application
import sys
sys.path.insert(0, '/var/www/html/api_test/venv/lib/python3.8/site-packages')
sys.path.insert(1, '/var/www/html/api_test')

from api import app as application

Binnen Apache, ‘virtual hosts’ of niet, kan je een aantal parameters opnemen die de mod_wsgi aansturen en het bovengenoemde bestand uitvoeren. Dit moet ingevoerd worden binnen de VirtualHost tags of daar buiten:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
WSGIDaemonProcess api user=apache group=apache threads=5 home=/var/www/html/api_test
WSGIScriptAlias /api/v1 /var/www/html/api_test/api.wsgi
<Directory /var/www/html/api_test>
WSGIProcessGroup api
<IfModule mod_authz_core.c>
Require all granted
</IfModule>
</Directory>
WSGIDaemonProcess api user=apache group=apache threads=5 home=/var/www/html/api_test WSGIScriptAlias /api/v1 /var/www/html/api_test/api.wsgi <Directory /var/www/html/api_test> WSGIProcessGroup api <IfModule mod_authz_core.c> Require all granted </IfModule> </Directory>
    WSGIDaemonProcess api user=apache group=apache threads=5 home=/var/www/html/api_test
    WSGIScriptAlias /api/v1 /var/www/html/api_test/api.wsgi

    <Directory /var/www/html/api_test>
        WSGIProcessGroup api
        <IfModule mod_authz_core.c>
            Require all granted
        </IfModule>
    </Directory>

Na het herstarten van de ‘httpd’ daemon zou de api beschikbaar moeten zijn. Laten we het testen van een externe server:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[bartjanh@godlyserver ~]$ curl https://www.pc-mania.nl/api/v1/
{"name":"Test program","version":"0.1a","hostname":"mightyserver.pc-mania.nl","ip":"2001:9a0:2005:85::24"}
[bartjanh@godlyserver ~]$ curl https://www.pc-mania.nl/api/v1/ {"name":"Test program","version":"0.1a","hostname":"mightyserver.pc-mania.nl","ip":"2001:9a0:2005:85::24"}
[bartjanh@godlyserver ~]$ curl https://www.pc-mania.nl/api/v1/
{"name":"Test program","version":"0.1a","hostname":"mightyserver.pc-mania.nl","ip":"2001:9a0:2005:85::24"}

De API werkt! Er is nog veel meer maar de minimale basis zoals het er staat, werkt zoals het hoort.

Mod_wsgi in Apache

Om via een webserver Python scripts te kunnen gebruiken en specifiek Django of Flask voor bijvoorbeeld API deployments zal je de server iets bij moeten werken.

Onderstaand voorbeeld is hoe je dus Mod_wsgi activeert in een Centos7 server voorzien van Apache 2.4. De keuze op Python versie is sowieso 3.x en in dit voorbeeld 3.8.7.

Belangrijk is om root rechten te hebben. We beginnen met 2 environment variabelen te definiëren:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
export PATH=$PATH:/usr/local/bin/
export LD_RUN_PATH=/usr/local/lib/
export PATH=$PATH:/usr/local/bin/ export LD_RUN_PATH=/usr/local/lib/
export PATH=$PATH:/usr/local/bin/
export LD_RUN_PATH=/usr/local/lib/

Hierna zorgen we dat de package apxs beschikbaar is, die via httpd-devel te vinden is:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
yum install -y httpd-devel
yum install -y httpd-devel
yum install -y httpd-devel

Dan is het zaak Python te installeren. Vanwege redenen is Centos7 nog steeds standaard uitgerust met versie 2.7 en dat willen we verder niet gebruiken. Het is dus belangrijk dat de installatie naast de bestaande komt te draaien. Het hele Centos ecosysteem is afhankelijk van de huidige versie. Dat word met ‘make altinstall‘ bepaald.

Nog veel belangrijker is de ‘–enable-shared‘ optie waarme Python op de juiste manier compiled word. Vergeet deze niet!

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
cd /tmp
wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tgz
tar -xf Python-3.8.7.tgz -C /usr/local/src
cd /usr/local/src/Python-3.8.7
./configure --enable-shared --enable-optimizations
make altinstall
cd /tmp wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tgz tar -xf Python-3.8.7.tgz -C /usr/local/src cd /usr/local/src/Python-3.8.7 ./configure --enable-shared --enable-optimizations make altinstall
cd /tmp
wget https://www.python.org/ftp/python/3.8.7/Python-3.8.7.tgz
tar -xf Python-3.8.7.tgz -C /usr/local/src
cd /usr/local/src/Python-3.8.7
./configure --enable-shared --enable-optimizations
make altinstall

Als het goed is kan je daarna Python3.8 starten:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[root@mightyserver ~]# python3.8
Python 3.8.7 (default, Jan 2 2021, 14:19:51)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
[root@mightyserver ~]# python3.8 Python 3.8.7 (default, Jan 2 2021, 14:19:51) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux Type "help", "copyright", "credits" or "license" for more information. >>>
[root@mightyserver ~]# python3.8
Python 3.8.7 (default, Jan  2 2021, 14:19:51)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>

Voor we de module mod_wsgi introduceren in Apache moet er nog een kleine update gedaan worden:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/usr/local/bin/python3.8 -m pip install --upgrade pip
/usr/local/bin/python3.8 -m pip install --upgrade pip
/usr/local/bin/python3.8 -m pip install --upgrade pip

Nu kunnen we via ‘Pip’ de installatie van de module uitvoeren en deze configureren:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
pip3.8 install mod_wsgi
mod_wsgi-express install-module > /etc/httpd/conf.modules.d/02-wsgi.conf
systemctl restart httpd
pip3.8 install mod_wsgi mod_wsgi-express install-module > /etc/httpd/conf.modules.d/02-wsgi.conf systemctl restart httpd
pip3.8 install mod_wsgi
mod_wsgi-express install-module > /etc/httpd/conf.modules.d/02-wsgi.conf

systemctl restart httpd

Een controle kan gedaan worden of de module beschikbaar is:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
[root@mightyserver ~]# httpd -t -D DUMP_MODULES | grep wsgi
wsgi_module (shared)
[root@mightyserver ~]# httpd -t -D DUMP_MODULES | grep wsgi wsgi_module (shared)
[root@mightyserver ~]# httpd -t -D DUMP_MODULES | grep wsgi
 wsgi_module (shared)

In de volgende post meer over hoe nu Apache te ‘sturen’ is naar jouw Python project.