Lewati ke konten
LinkedIn GitHub X

Deploying a Simple Flask API Using Gunicorn, Supervisor & Nginx

Konten ini belum tersedia dalam bahasa Anda.

Post Cover

Intro

Hi there! Flask is great for building APIs quickly. But turning your local project into a publicly accessible web service involves a few extra steps that aren’t always obvious.

In this guide, I’ll show you how to deploy a Flask API using Gunicorn as the WSGI server, Supervisor to manage the process, and Nginx as a reverse proxy.

Overview

- Flask: The Python microframework we’ll use to build the API.

- Gunicorn: A Python WSGI HTTP server for running Flask in production.

- Supervisor: A process control system to ensure the Gunicorn server stays alive.

- Nginx: A reverse proxy to handle client requests and route them to Gunicorn.

Flask API Deployment Flow

The diagram below illustrates the flow of a request and response when using Flask, Gunicorn, Supervisor, and Nginx.

When a user sends an HTTP request, it first reaches the Nginx reverse proxy. Nginx forwards the request to Gunicorn, which serves the Flask application via the WSGI protocol. Supervisor ensures that Gunicorn keeps running and automatically restarts it if needed. The response follows the same path back to the user.

Deployment Flow

Requirements

Before starting, make sure you have the following installed on your system:

- Python 3 and Virtualenv

Check if Python is installed:

Terminal window
$ python3 --version
Python 3.10.14

If not installed, install it:

Ubuntu/Debian:

Terminal window
$ sudo apt update
$ sudo apt install python3 python3-venv -y

CentOS/RHEL:

Terminal window
$ sudo yum install python3 python3-venv -y

Homebrew (macOS):

Terminal window
$ brew install python

- Nginx

Ubuntu/Debian:

Terminal window
$ sudo apt install nginx -y

CentOS/RHEL:

Terminal window
$ sudo yum install nginx -y

Homebrew (macOS):

Terminal window
$ brew install nginx

After installation, check if Nginx is running:

Terminal window
$ sudo systemctl status nginx

If it’s not running, start and enable it:

Terminal window
$ sudo systemctl start nginx
$ sudo systemctl enable nginx
  • Supervisor

Ubuntu/Debian:

Terminal window
$ sudo apt update
$ sudo apt install supervisor -y

CentOS/RHEL:

Terminal window
$ sudo yum install supervisor -y

Homebrew (macOS):

Terminal window
$ brew install supervisor

After installation, check if Supervisor is running:

Terminal window
$ sudo systemctl status supervisor

If it’s not running, start and enable it:

Terminal window
$ sudo systemctl start supervisor
$ sudo systemctl enable supervisor

Setting Up the Flask Project

First, create a project directory and set up a virtual environment:

Terminal window
$ mkdir flask-api && cd flask-api
Terminal window
$ python3 -m venv venv
$ source venv/bin/activate

With the virtual environment activated, install Flask and Gunicorn:

Terminal window
$ pip install flask gunicorn

You can verify the installation:

Terminal window
$ flask --version
$ gunicorn --version

Next, you need to create a file called app.py inside your project directory. You can use any text editor you prefer, such as nano, vim, or others:

Terminal window
$ vim app.py
from flask import Flask
app = Flask(__name__)
@app.route("/api/hello")
def hello():
return {"message": "Hello from Flask API!"}

Then, try to run your Flask app using Gunicorn command:

Terminal window
$ gunicorn app:app
[2025-04-30 20:37:49 +0700] [1085004] [INFO] Starting gunicorn 23.0.0
[2025-04-30 20:37:49 +0700] [1085004] [INFO] Listening at: http://127.0.0.1:8000 (1085004)
[2025-04-30 20:37:49 +0700] [1085004] [INFO] Using worker: sync
[2025-04-30 20:37:49 +0700] [1085005] [INFO] Booting worker with pid: 1085005
[2025-04-30 20:38:58 +0700] [1085004] [INFO] Handling signal: winch

To try your app, just open another terminal session or window. You can use a tool like curl:

Terminal window
$ curl http://127.0.0.1:8000/api/hello
{"message":"Hello from Flask API!"}

Running with Multiple Workers

You can run Gunicorn with multiple worker processes using the -w option. For example, to run your app with 3 workers:

Terminal window
$ gunicorn -w 3 app:app
[2025-04-30 20:49:13 +0700] [1085759] [INFO] Starting gunicorn 23.0.0
[2025-04-30 20:49:13 +0700] [1085759] [INFO] Listening at: http://127.0.0.1:8000 (1085759)
[2025-04-30 20:49:13 +0700] [1085759] [INFO] Using worker: sync
[2025-04-30 20:49:13 +0700] [1085760] [INFO] Booting worker with pid: 1085759
[2025-04-30 20:49:13 +0700] [1085761] [INFO] Booting worker with pid: 1085760
[2025-04-30 20:49:13 +0700] [1085762] [INFO] Booting worker with pid: 1085761

To confirm that Gunicorn is running with multiple workers, you can use tools like top or htop.

Install htop (optional but nicer to read):

Terminal window
$ sudo apt install htop -y

Then run:

Terminal window
$ htop

Gunicorn Process

To bind it to a different port (e.g., 8081) and listen on all interfaces:

Terminal window
$ gunicorn -b 0.0.0.0:8081 app:app
[2025-04-30 21:14:29 +0700] [1085847] [INFO] Starting gunicorn 23.0.0
[2025-04-30 21:14:29 +0700] [1085847] [INFO] Listening at: http://0.0.0.0:8081 (1085847)
[2025-04-30 21:14:29 +0700] [1085847] [INFO] Using worker: sync
[2025-04-30 21:14:29 +0700] [1085848] [INFO] Booting worker with pid: 1085848

Adding Supervisor and Nginx Configuration

Supervisor Setup

To make sure Gunicorn runs in the background and restarts automatically if it crashes, you’ll want to use Supervisor. Here’s how to set it up:

Create a configuration file for your app:

Terminal window
$ sudo vim /etc/supervisor/conf.d/flask-api.conf

Insert this configuration (adjust paths as needed):

Terminal window
[program:flask-api]
directory=/home/youruser/flask-api
command=/home/youruser/flask-api/venv/bin/gunicorn -w 3 -b 127.0.0.1:8000 app:app
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/log/flask-api.out.log
stderr_logfile=/var/log/flask-api.err.log
environment=PATH="/home/youruser/flask-api/venv/bin"

directory=/home/youruser/flask-api → The working directory where your Flask project is located.

command=/home/youruser/flask-api/venv/bin/gunicorn -w 3 -b 127.0.0.1:8000 app

→ Runs the Gunicorn server with 3 workers, binding to localhost on port 8000.

autostart=true → Automatically starts the app when Supervisor starts (e.g., on boot).

autorestart=true → Restarts the app automatically if it crashes.

user=www-data → Runs the process as the www-data user (you can change this to your own user if needed).

stdout_logfile=/var/log/api/flask-api.out.log → File where standard output (including errors) is logged.

stderr_logfile=/var/log/api/flask-api.err.log → (Optional if using redirect_stderr) File for capturing standard error output.

environment=PATH=”…” → Ensures Supervisor uses the correct Python virtual environment for Gunicorn.

Then reload Supervisor to pick up the new config:

Terminal window
$ sudo supervisorctl reread
$ sudo supervisorctl update
$ sudo supervisorctl status

If the API is not running, check the logs:

Terminal window
$ cat /var/log/flask-api.out.log
$ cat /var/log/flask-api.err.log

Or use Supervisor’s built-in log viewer:

Terminal window
$ tail -f flask-api
==> Press Ctrl-C to exit <==

Nginx Configuration

Now that Gunicorn is running your Flask app on port 8000, you’ll want Nginx to act as a reverse proxy.

Create a new Nginx config file:

Terminal window
$ sudo vim /etc/nginx/sites-available/flask-api
Terminal window
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

Enable the site and test:

Terminal window
$ sudo ln -s /etc/nginx/sites-available/flask-api /etc/nginx/sites-enabled
$ sudo nginx -t
$ sudo systemctl restart nginx

Finally, ff everything is set up correctly, you should now be able to access your Flask API at http://YOUR_SERVER_IP/api/hello if you’re using a public server or VPS.

Optional: Project Structure & Requirements

To easily reinstall dependencies later:

Terminal window
$ pip freeze > requirements.txt

However, it’s better to specify only the packages you need manually:

Terminal window
$ sudo vim requirements.txt
Terminal window
flask
gunicorn

To install all requirements, just run pip install:

Terminal window
$ pip install -r requirements.txt

Your project structure should look like this:

Terminal window
flask-api/
├── app.py
├── venv/
└── requirements.txt

Common Issues

Here are a few quick troubleshooting tips:

502 Bad Gateway: Usually means Gunicorn isn’t running or the Nginx config has the wrong port.

Supervisor status shows STOPPED: Check your config file paths and the logs: sudo tail -f /var/log/flask-api.err.log

Permission errors: Ensure all paths used by Supervisor and Gunicorn are accessible by the appropriate user.

Conclusion

In this guide, we deployed a Flask API using Gunicorn as the WSGI server, Supervisor to keep the app running reliably, and Nginx as a reverse proxy to handle incoming requests. With this setup, your Flask app is ready to serve real traffic efficiently and automatically recover from crashes. Thanks for reading — and good luck with your deployment! 🚀

Project Reference: