Getting Started with Flask Deployment: Gunicorn and Nginx Configuration Tutorial

1. Why Gunicorn and Nginx are Needed?

The built-in development server of Flask (flask run) is only suitable for local debugging. It does not support high concurrency and is insecure, making it unable to directly provide production-level services. In a production environment, two tools are typically required:

  • Gunicorn: As a WSGI server, it runs the Flask application, handles client requests, and returns results (similar to an “application server”).
  • Nginx: As a reverse proxy server, it manages static resources (e.g., images, CSS, JS), load balances, encrypts SSL, and forwards dynamic requests to Gunicorn (similar to a “gatekeeper + administrator”).

2. Preparation

Assume you have already installed Python and have a simple Flask application (e.g., app.py with the following content):

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello, Flask!"

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

3. Install Required Tools

  1. Install Gunicorn (WSGI server):
   pip install gunicorn
  1. Install Nginx (reverse proxy server):
    - For Ubuntu/Debian: sudo apt-get update && sudo apt-get install nginx
    - For CentOS/RHEL: sudo yum install nginx
    - Verify installation: nginx -v (version number displayed indicates success).

4. Start Gunicorn Service

Gunicorn requires specifying the Flask application’s entry point and port. The syntax is:

gunicorn [options] module_name:Flask_instance_name

Example: For an application in app.py with an entry point app (i.e., app = Flask(__name__)):

# Bind to 127.0.0.1:8000 with 4 workers (adjust based on CPU cores, typically CPU cores * 2 + 1)
gunicorn -w 4 -b 127.0.0.1:8000 app:app
  • Parameter Explanation:
  • -w 4: Specifies 4 worker processes (w = worker; process count: CPU cores * 2 + 1 to avoid excessive resource usage).
  • -b 127.0.0.1:8000: Binds to the address and port (local access only; adjust for public exposure in production).
  • app:app: app is the module name (app.py), and the second app is the Flask instance name (app = Flask(__name__)).

Verify Gunicorn:
Open a browser to http://127.0.0.1:8000, or test via command line:

curl http://127.0.0.1:8000  # Should return "Hello, Flask!"

5. Configure Nginx Reverse Proxy

Nginx forwards client requests to Gunicorn (127.0.0.1:8000) and handles static resources.

5.1 Create Nginx Configuration File

For Ubuntu/Debian, place configuration files in /etc/nginx/sites-available/. Create a new file (e.g., flask_app):

sudo nano /etc/nginx/sites-available/flask_app

5.2 Write Nginx Configuration

Paste the following content, replacing server_name with your domain or server IP (use localhost for local testing):

server {
    listen 80;                 # Listen on port 80 (HTTP)
    server_name localhost;     # Replace with your domain (e.g., example.com)

    # Forward dynamic requests to Gunicorn
    location / {
        proxy_pass http://127.0.0.1:8000;  # Gunicorn address
        proxy_set_header Host $host;        # Forward request headers
        proxy_set_header X-Real-IP $remote_addr;  # Forward real IP
    }

    # Serve static files (CSS, JS, images) directly via Nginx
    location /static {
        alias /path/to/your/flask/static;  # Replace with your Flask static directory
        expires 30d;  # Cache static files for 30 days
    }
}

Note: If the Flask app has no static files, delete the location /static block.

5.3 Enable Configuration and Restart Nginx

  • Create a symlink to sites-enabled (Nginx loads this directory by default):
  sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
  • Check configuration syntax:
  sudo nginx -t  # "syntax is ok" indicates no errors
  • Restart Nginx:
  sudo systemctl restart nginx  # or service nginx restart

6. Verify the Final Result

Access your server’s IP or domain (e.g., http://localhost). You should see the Flask app’s response: “Hello, Flask!”.

7. Advanced: Gunicorn Process Management (Auto-Start on Boot)

To avoid manually starting Gunicorn after server restarts, use systemd for auto-start:

  1. Create a systemd service file:
   sudo nano /etc/systemd/system/gunicorn.service
  1. Add the following content (replace paths and parameters):
   [Unit]
   Description=Gunicorn instance to serve Flask app
   After=network.target

   [Service]
   User=your_username  # Replace with your actual username (e.g., ubuntu)
   WorkingDirectory=/path/to/your/flask/app  # Replace with app directory
   ExecStart=/home/your_username/.local/bin/gunicorn -w 4 -b 127.0.0.1:8000 app:app  # Gunicorn command

   [Install]
   WantedBy=multi-user.target
  1. Start and enable auto-start:
   sudo systemctl start gunicorn
   sudo systemctl enable gunicorn  # Auto-start on boot

8. Common Troubleshooting

  1. Nginx Cannot Forward Requests:
    - Check Gunicorn status: ps aux | grep gunicorn
    - Check port usage: lsof -i:80 (modify Nginx listen if port 80 is occupied).
    - Verify firewall rules: sudo ufw allow 80/tcp (Ubuntu) or sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT.

  2. Static Files Not Loading:
    - Confirm location /static alias path is correct (e.g., /home/ubuntu/myapp/static).
    - Restart Nginx: sudo systemctl restart nginx.

Summary

By running Flask with Gunicorn (WSGI server) and using Nginx as a reverse proxy, you achieve production-grade deployment. The core steps are “start Gunicorn → configure Nginx to forward requests”. Further optimizations include HTTPS and load balancing.

Xiaoye