Python/Flask: Difference between revisions
| (4 intermediate revisions by the same user not shown) | |||
| Line 79: | Line 79: | ||
== WSGI == | == WSGI == | ||
=== Apache | === Apache mod_wsgi-express === | ||
<pre> | <pre> | ||
| Line 89: | Line 89: | ||
</pre> | </pre> | ||
wsgi.py : | wsgi.py : (or yourapp.wsgi) | ||
<pre> | <pre> | ||
## IIMPORT PATTERN | ## IIMPORT PATTERN | ||
| Line 109: | Line 109: | ||
--user hello --group hello --port 80 --processes 4 | --user hello --group hello --port 80 --processes 4 | ||
Reference: https://flask.palletsprojects.com/en/stable/deploying/mod_wsgi/ | |||
=== Apache mod_wsgi and WSGIScriptAlias === | |||
Another WSGI option using mod_wsgi and WSGIScriptAlias | |||
Install: | |||
sudo apt install apache2 libapache2-mod-wsgi-py3 | |||
TIP: You can also use the touch command on your .wsgi file to gracefully restart the application processes without restarting the entire Apache server when you make code changes. | |||
/path/to/your/yourapp.wsgi : ( the "bridge" between apache and Flask ) | |||
<pre> | |||
import sys | |||
import os | |||
# Add your project directory to Python's path | |||
project_home = os.path.dirname(os.path.abspath(__file__)) | |||
if project_home not in sys.path: | |||
sys.path.insert(0, project_home) | |||
# Import the 'app' object from your Flask application file (e.g., app.py) | |||
from app import app as application | |||
</pre> | |||
Virtual Host : | |||
<pre> | |||
<VirtualHost *:80> | |||
ServerName yourdomain.com | |||
# Points to your WSGI script | |||
WSGIScriptAlias / /path/to/your/yourapp.wsgi | |||
# Configure daemon processes | |||
WSGIDaemonProcess yourapp_daemon user=www-data group=www-data threads=5 | |||
WSGIProcessGroup yourapp_daemon | |||
# Grant access to the application directory | |||
<Directory /path/to/your/project/folder> | |||
WSGIProcessGroup yourapp_daemon | |||
WSGIApplicationGroup %{GLOBAL} | |||
Order deny,allow | |||
Allow from all | |||
Require all granted | |||
</Directory> | |||
ErrorLog /var/log/apache2/yourdomain.com_error.log | |||
CustomLog /var/log/apache2/yourdomain.com_access.log combined | |||
</VirtualHost> | |||
</pre> | |||
Enable the virtual host: | |||
<pre> | |||
# On Ubuntu/Debian | |||
sudo a2ensite yourdomain.com.conf | |||
sudo systemctl restart apache2 | |||
# On Fedora/RHEL | |||
sudo systemctl restart httpd | |||
</pre> | |||
Prerequisites | |||
* Python Virtual Environment: Your Flask application should be installed in a dedicated Python virtual environment for dependency isolation. | |||
* Apache Web Server: Apache must be installed and running. | |||
* mod_wsgi: The mod_wsgi package must be installed and enabled for the correct Python version (e.g., libapache2-mod-wsgi-py3 on Ubuntu systems). | |||
* No app.run(): Ensure that any app.run() calls are removed or placed inside an if __name__ == '__main__': block in your Flask app's main file, as Apache will manage the server lifecycle. | |||
=== Reverse Proxy === | |||
Tell Flask it is being reverse Proxied: | |||
<pre> | |||
from werkzeug.middleware.proxy_fix import ProxyFix | |||
app.wsgi_app = ProxyFix( | |||
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1 | |||
) | |||
</pre> | |||
reference: https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/ | |||
Apapache Configuration: | |||
<pre> | |||
LoadModule proxy_module modules/mod_proxy.so | |||
LoadModule proxy_http_module modules/mod_proxy_http.so | |||
ProxyPass / http://127.0.0.1:8000/ | |||
RequestHeader set X-Forwarded-Proto http | |||
RequestHeader set X-Forwarded-Prefix / | |||
</pre> | |||
reference: https://flask.palletsprojects.com/en/stable/deploying/apache-httpd/ | |||
=== Systemd Flask Service === | |||
/etc/systemd/system/myproject.service | |||
<pre> | |||
[Unit] | |||
Description=Gunicorn instance to serve myproject | |||
After=network.target | |||
[Service] | |||
User=youruser | |||
WorkingDirectory=/path/to/your/project | |||
Environment="FLASK_ENV=production" | |||
ExecStart=/path/to/your/project/venv/bin/gunicorn -w 4 'app:app' -b 0.0.0.0:8000 | |||
Restart=always | |||
[Install] | |||
WantedBy=multi-user.target | |||
</pre> | |||
sudo systemctl daemon-reload | |||
sudo systemctl start myproject | |||
sudo systemctl enable myproject | |||
Check logs with: | |||
sudo systemctl status myproject | |||
journalctl -u myproject | |||
== keywords == | == keywords == | ||
Latest revision as of 22:42, 13 December 2025
Flask
Installation
## Linux / macOS mkdir myproject cd myproject # python3 -m venv .flask python3 -m venv .venv . .venv/bin/activate
## Windows mkdir myproject cd myproject py -3 -m venv .venv .venv\Scripts\activate
## Next Common Step # pip install Flask pip3 install Flask
# End deactivate
References:
Quick Start
Flask Hello World
helloworld.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>\n"
Run the server:
flask --app helloworld run
NOTE: As a shortcut, if the file is named app.py or wsgi.py, you don’t have to use --app. See Command Line Interface for more details.
- Meaning, just simply rename helloworld.py to app.py (or wsgi.py) and you can simply run run:
flask run
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
Note:
* Running on http://127.0.0.1:5000
Test the server:
curl http://127.0.0.1:5000 <p>Hello, World!</p>
References:
Hello World Headers
$ curl -i http://127.0.0.1:5000 HTTP/1.1 200 OK Server: Werkzeug/3.1.4 Python/3.12.3 Date: Sat, 13 Dec 2025 22:05:42 GMT Content-Type: text/html; charset=utf-8 Content-Length: 20 Connection: close <p>Hello, World!</p>
WSGI
Apache mod_wsgi-express
$ cd hello-app $ python -m venv .venv $ . .venv/bin/activate $ pip install . # install your application $ pip install mod_wsgi
wsgi.py : (or yourapp.wsgi)
## IIMPORT PATTERN from hello import app application = app ## OR ## FACTORY PATTERN from hello import create_app application = create_app()
Configure mod_wsgi-express and specify the number of worker processes:
mod_wsgi-express start-server wsgi.py --processes 4
Example running mod_wsgi-express as root, to bind to port 80/443, but then drop permissions and binding app as different user:
sudo /home/hello/.venv/bin/mod_wsgi-express start-server /home/hello/wsgi.py \ --user hello --group hello --port 80 --processes 4
Reference: https://flask.palletsprojects.com/en/stable/deploying/mod_wsgi/
Apache mod_wsgi and WSGIScriptAlias
Another WSGI option using mod_wsgi and WSGIScriptAlias
Install:
sudo apt install apache2 libapache2-mod-wsgi-py3
TIP: You can also use the touch command on your .wsgi file to gracefully restart the application processes without restarting the entire Apache server when you make code changes.
/path/to/your/yourapp.wsgi : ( the "bridge" between apache and Flask )
import sys
import os
# Add your project directory to Python's path
project_home = os.path.dirname(os.path.abspath(__file__))
if project_home not in sys.path:
sys.path.insert(0, project_home)
# Import the 'app' object from your Flask application file (e.g., app.py)
from app import app as application
Virtual Host :
<VirtualHost *:80>
ServerName yourdomain.com
# Points to your WSGI script
WSGIScriptAlias / /path/to/your/yourapp.wsgi
# Configure daemon processes
WSGIDaemonProcess yourapp_daemon user=www-data group=www-data threads=5
WSGIProcessGroup yourapp_daemon
# Grant access to the application directory
<Directory /path/to/your/project/folder>
WSGIProcessGroup yourapp_daemon
WSGIApplicationGroup %{GLOBAL}
Order deny,allow
Allow from all
Require all granted
</Directory>
ErrorLog /var/log/apache2/yourdomain.com_error.log
CustomLog /var/log/apache2/yourdomain.com_access.log combined
</VirtualHost>
Enable the virtual host:
# On Ubuntu/Debian sudo a2ensite yourdomain.com.conf sudo systemctl restart apache2 # On Fedora/RHEL sudo systemctl restart httpd
Prerequisites
- Python Virtual Environment: Your Flask application should be installed in a dedicated Python virtual environment for dependency isolation.
- Apache Web Server: Apache must be installed and running.
- mod_wsgi: The mod_wsgi package must be installed and enabled for the correct Python version (e.g., libapache2-mod-wsgi-py3 on Ubuntu systems).
- No app.run(): Ensure that any app.run() calls are removed or placed inside an if __name__ == '__main__': block in your Flask app's main file, as Apache will manage the server lifecycle.
Reverse Proxy
Tell Flask it is being reverse Proxied:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)
reference: https://flask.palletsprojects.com/en/stable/deploying/proxy_fix/
Apapache Configuration:
LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so ProxyPass / http://127.0.0.1:8000/ RequestHeader set X-Forwarded-Proto http RequestHeader set X-Forwarded-Prefix /
reference: https://flask.palletsprojects.com/en/stable/deploying/apache-httpd/
Systemd Flask Service
/etc/systemd/system/myproject.service
[Unit] Description=Gunicorn instance to serve myproject After=network.target [Service] User=youruser WorkingDirectory=/path/to/your/project Environment="FLASK_ENV=production" ExecStart=/path/to/your/project/venv/bin/gunicorn -w 4 'app:app' -b 0.0.0.0:8000 Restart=always [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl start myproject sudo systemctl enable myproject
Check logs with:
sudo systemctl status myproject journalctl -u myproject