Flask uWSGI Setup
Introduction
When you're ready to move your Flask application from development to production, you'll need a more robust way to serve it than Flask's built-in development server. This is where uWSGI comes in. uWSGI is a fast, self-healing and developer/sysadmin-friendly application container that can be used to deploy Python web applications.
In this guide, we'll learn how to:
- Install and configure uWSGI
- Connect uWSGI to your Flask application
- Set up proper production configurations
- Optimize performance for your application
Why Use uWSGI?
Flask's built-in server is great for development but has several limitations for production use:
- It's single-threaded by default
- It's not designed for high traffic loads
- It lacks many production-ready features
uWSGI solves these problems by providing:
- Multi-process and multi-threaded capabilities
- Better memory management
- Native integration with web servers like Nginx
- Advanced features like load balancing and auto-reloading
Installing uWSGI
Let's start by installing uWSGI and its dependencies. It's recommended to do this in a virtual environment:
# Create and activate virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Flask and uWSGI
pip install flask uwsgi
If you encounter problems with the installation, you may need to install development packages first:
# On Ubuntu/Debian
sudo apt-get install python3-dev build-essential
# On CentOS/RHEL
sudo yum install python3-devel gcc
Creating a Basic Flask Application
Let's create a simple Flask application to deploy with uWSGI. Save this as app.py
:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello, World! This is served via uWSGI.'
if __name__ == '__main__':
app.run(debug=True)
Configuring uWSGI
uWSGI can be configured either through command-line arguments or configuration files. While command-line arguments are good for testing, configuration files are recommended for production.
Basic Command-Line Usage
You can run your Flask app with uWSGI using this command:
uwsgi --http 127.0.0.1:5000 --module app:app
This tells uWSGI to:
- Serve HTTP on port 5000
- Load the
app
object from theapp.py
module
Creating a uWSGI Configuration File
For production, it's better to use a configuration file. Create a file named uwsgi.ini
:
[uwsgi]
; Server basics
http = 127.0.0.1:5000
module = app:app
; Process management
master = true
processes = 4
threads = 2
; Better process management
vacuum = true
die-on-term = true
; File monitoring
py-autoreload = 1
To run using this configuration:
uwsgi --ini uwsgi.ini
Explanation of Key Configuration Options
- http: Address and port to bind the server to
- module: Python module and application object to use (format: module_name:app_variable)
- master: Enable master process mode
- processes: Number of worker processes to spawn
- threads: Number of threads per process
- vacuum: Clean up socket files on server exit
- die-on-term: Shutdown gracefully upon receiving SIGTERM
- py-autoreload: Auto-reload when Python files change (development only)
Using Socket Files for Nginx Integration
In production, it's common to use uWSGI with Nginx. Instead of HTTP, we use socket files:
[uwsgi]
; Use socket instead of HTTP
socket = /tmp/myapp.sock
chmod-socket = 660
vacuum = true
module = app:app
master = true
processes = 4
threads = 2
die-on-term = true
Managing Environment Variables
When deploying, you'll need to handle environment variables for things like database credentials or API keys. One way is to use an environment file:
[uwsgi]
; Basic configuration
module = app:app
master = true
processes = 4
; Load environment variables from file
env = DATABASE_URL=postgresql://user:pass@localhost/dbname
env = SECRET_KEY=your-secret-key
A better approach is to load from a .env file:
[uwsgi]
; Basic configuration
module = app:app
master = true
processes = 4
; Load environment variables from file
for-readline = .env
env = %(_)
endfor =
And your .env
file would contain:
DATABASE_URL=postgresql://user:pass@localhost/dbname
SECRET_KEY=your-secret-key
Production Application Structure
For real-world applications, your structure might look like this:
project/
├── app/
│ ├── __init__.py # Creates the Flask app
│ ├── models.py
│ ├── routes.py
│ └── templates/
├── venv/
├── wsgi.py # Entry point for uWSGI
└── uwsgi.ini # uWSGI config
Your wsgi.py
file would be:
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run()
And the uwsgi.ini would reference this:
[uwsgi]
module = wsgi:app
# other configuration options...
Monitoring and Logging
For proper production deployment, you should set up logging:
[uwsgi]
module = wsgi:app
master = true
processes = 4
# Logging
logto = /var/log/uwsgi/%n.log
log-date = true
Example: Complete Production uWSGI Configuration
Here's a more complete example of a production uWSGI configuration:
[uwsgi]
# Python module
module = wsgi:app
# Process management
master = true
processes = 8
threads = 2
enable-threads = true
# Socket configuration (for Nginx)
socket = /tmp/myapp.sock
chmod-socket = 660
vacuum = true
# Process management optimizations
harakiri = 30 # Kill requests that take more than 30 seconds
max-requests = 5000 # Restart workers after handling 5000 requests
reload-on-rss = 200 # Reload worker if it uses more than 200MB RAM
# Logging
logto = /var/log/uwsgi/%n.log
log-date = true
# Stats
stats = /tmp/stats.socket
# Security
uid = www-data
gid = www-data
Running as a Service with Systemd
To ensure your Flask app stays running after server reboots, you should create a systemd service file. Create /etc/systemd/system/myapp.service
:
[Unit]
Description=uWSGI instance to serve myapp
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/your/app/venv/bin"
ExecStart=/path/to/your/app/venv/bin/uwsgi --ini uwsgi.ini
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl enable myapp
sudo systemctl start myapp
Check its status:
sudo systemctl status myapp
Common Issues and Troubleshooting
1. Import Errors
If you get import errors, make sure your Python path is correctly set:
[uwsgi]
module = wsgi:app
pythonpath = /path/to/your/app
2. Permission Issues
Socket file permission issues are common:
[uwsgi]
socket = /tmp/myapp.sock
chmod-socket = 666 # More permissive for troubleshooting
3. Memory Leaks
If your app consumes too much memory over time:
[uwsgi]
max-requests = 1000 # Restart workers after handling 1000 requests
reload-on-rss = 200 # Reload worker if it uses more than 200MB RAM
Summary
In this guide, we've covered the essentials of deploying a Flask application with uWSGI:
- Installing uWSGI and its dependencies
- Creating basic uWSGI configurations
- Understanding key configuration options
- Working with socket files for Nginx integration
- Managing environment variables
- Setting up proper logging and monitoring
- Running your application as a system service
- Troubleshooting common issues
uWSGI provides a robust way to deploy your Flask applications in production environments. When combined with a web server like Nginx, it creates a powerful and efficient stack for serving your web applications.
Additional Resources
- Official uWSGI Documentation
- Flask Documentation on Deployment
- Digital Ocean's Guide on Deploying Flask with uWSGI and Nginx
Exercises
- Set up a basic Flask application with uWSGI and test it locally.
- Configure your uWSGI setup to use socket files instead of HTTP.
- Create a systemd service file for your application and test that it starts on boot.
- Experiment with different numbers of processes and threads to find the optimal configuration for your hardware.
- Set up proper logging and monitoring for your application.
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)