Skip to main content

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:

  1. It's single-threaded by default
  2. It's not designed for high traffic loads
  3. 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:

bash
# 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:

bash
# 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:

python
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:

bash
uwsgi --http 127.0.0.1:5000 --module app:app

This tells uWSGI to:

  • Serve HTTP on port 5000
  • Load the app object from the app.py module

Creating a uWSGI Configuration File

For production, it's better to use a configuration file. Create a file named uwsgi.ini:

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:

bash
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:

ini
[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:

ini
[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:

ini
[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:

python
from app import create_app

app = create_app()

if __name__ == "__main__":
app.run()

And the uwsgi.ini would reference this:

ini
[uwsgi]
module = wsgi:app
# other configuration options...

Monitoring and Logging

For proper production deployment, you should set up logging:

ini
[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:

ini
[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:

bash
sudo systemctl enable myapp
sudo systemctl start myapp

Check its status:

bash
sudo systemctl status myapp

Common Issues and Troubleshooting

1. Import Errors

If you get import errors, make sure your Python path is correctly set:

ini
[uwsgi]
module = wsgi:app
pythonpath = /path/to/your/app

2. Permission Issues

Socket file permission issues are common:

ini
[uwsgi]
socket = /tmp/myapp.sock
chmod-socket = 666 # More permissive for troubleshooting

3. Memory Leaks

If your app consumes too much memory over time:

ini
[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:

  1. Installing uWSGI and its dependencies
  2. Creating basic uWSGI configurations
  3. Understanding key configuration options
  4. Working with socket files for Nginx integration
  5. Managing environment variables
  6. Setting up proper logging and monitoring
  7. Running your application as a system service
  8. 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

Exercises

  1. Set up a basic Flask application with uWSGI and test it locally.
  2. Configure your uWSGI setup to use socket files instead of HTTP.
  3. Create a systemd service file for your application and test that it starts on boot.
  4. Experiment with different numbers of processes and threads to find the optimal configuration for your hardware.
  5. 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! :)