Web Server with Flask
Basic Flask Server to serve static html files
My use case is simple: Using my documention built with Sphinx as a content for my Web server.
Creating a basic Flask Application
This Application has one function that uses the User input to display some custom text.
from flask import Flask
app = Flask(__name__)
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, {}!</h1>'.format(name)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=80)
Note
To access it from any device on your local network, set host=’0.0.0.0’
Serving Static files
The method send_static_files is used to output the build of our sphinx project.
from flask import Flask
app = Flask(__name__, static_url_path='/', static_folder='_build/')
@app.route('/')
@app.route('/<path:path>')
def serve_sphinx_docs(path='index.html'):
return app.send_static_file(path)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=80)
Run a production server
When running publicly rather than in development, you should not use the built-in development server (flask run). The development server is provided by Werkzeug for convenience, but is not designed to be particularly efficient, stable, or secure.
Instead, use a production WSGI server. For example, to use Waitress, first install it in the virtual environment:
$ pip install waitress
Creat another script to import waitress and your Flask App and use the serve method:
from waitress import serve
import flask_app
serve(flask_app.app, host='0.0.0.0', port=8080, url_scheme='https')
Note
Specifying the proper host, port and url_scheme is crucial.
Tip
To check which services are running use: sudo service –status-all
Create a service with systemd to run the server at startup
In order to automatically run the Web server at each startup, we can create a service with systemd:
source: https://linuxconfig.org/how-to-autostart-python-script-on-raspberry-pi
Note
All service files are located in /etc/systemd/system
user@pi:/etc/systemd/system $ ls
bluetooth.target.wants graphical.target.wants
cloudflared.service halt.target.wants
cloudflared-update.service jenkins.service.d
cloudflared-update.timer multi-user.target.wants
dbus-fi.w1.wpa_supplicant1.service network-online.target.wants
dbus-org.bluez.service poweroff.target.wants
dbus-org.freedesktop.Avahi.service printer.target.wants
dbus-org.freedesktop.ModemManager1.service reboot.target.wants
dbus-org.freedesktop.nm-dispatcher.service remote-fs.target.wants
dbus-org.freedesktop.timesync1.service runwaitress.service
default.target sockets.target.wants
dev-serial1.device.wants sshd.service
display-manager.service sysinit.target.wants
getty.target.wants timers.target.wants
[email protected] wayvnc.service.wants
user@pi:/etc/systemd/system $ cat runwaitress.service
[Unit]
Description=Run production server with Waitress
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/home/user/virtEnv/Website/bin/python /home/user/myApp/waitress_server.py --serve-in-foreground
[Install]
WantedBy=multi-user.target
Apply the appropriate permissions to the file so that systemd can execute it. Afterwards, we will apply the proper permissions to the systemd timer file.
$ sudo chmod 744 myApp/waitress_server.py
$ sudo chmod 664 /etc/systemd/system/runwaitress.service
Next, enable the service unit:
$ sudo systemctl daemon-reload
$ sudo systemctl enable runwaitress.service
Common pitfalls
Issues encountered and how they have been fixed.
Python OSError: [Errno 98] Address already in use
The Python error “OSError: [Errno 98] Address already in use” occurs when you have another process running on the specified port.
You can resolve the error by using the SO_REUSEADDR attribute or by identifying and stopping the process before you start your server.
To get the process ID of the process that is running on the specified port, use the lsof command.
$ sudo lsof -i :8081
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python 1931 root 6u IPv4 9077 0t0 TCP *:tproxy (LISTEN)
The PID column contains the ID of the process that is running on the specified port.
You can stop the process by issuing the kill command.
$ sudo kill -9 <YOUR_PID>