Deploying a FastAPI App with Nginx, Supervisor, and Gunicorn
Take your Python API deployment skills to the next level in under 6 minutes

FastAPI is one of the most important web frameworks in Python and for good reason. It’s wonderfully easy to setup and is faster than even Node.js. What’s not to like?
I recently performed a full scale deployment of a side project that I recently launched: Quirkability (a dedicated article coming on this soon 😃 ), and it required a thorough deployment routine for the FastAPI server that I had to setup for the website to be live.
There are a few quirks that you need to be aware of in these processes, and of course, some tools that you need to learn.
No need to fear though as in this article, we’ll learn about it all.
Let’s dive in 👇
Some Prerequisites
Before we start, make sure you have the following set up:
A virtual private server (VPS) running Ubuntu 20.04 (or slightly older), or a similar Linux distribution
Access to the server via SSH (it doesn’t matter what OS you’re on locally, just make sure to be able to SSH into your remote server)
What tools we’ll be using
In this tutorial, we will deploy a FastAPI application using the following technology stack:
FastAPI: A modern, fast (high-performance) web framework for building APIs with Python based on standard Python type hints
Nginx: A high-performance HTTP server and reverse proxy server
Gunicorn: A Python WSGI HTTP server for UNIX
Supervisor: A process control system that allows you to manage and monitor processes on UNIX-like operating systems
Step 0: Secure Your Server
Enable Automatic Updates for more security. It’s optional though, so: your choice!
Install the `unattended-upgrades` package on your Ubuntu system:
sudo apt-get update
sudo apt-get install unattended-upgrades
Next, enable automatic updates by editing the configuration file:
sudo nano /etc/apt/apt.conf.d/20unattended-upgrades
Ensure that the following lines are uncommented:
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
Save and close the file.
This will make sure to:
APT::Periodic::Unattended-Upgrade "1"
: the system will be updated to the latest version of the packages without you having to interveneAPT::Periodic::Update-Package-Lists "1"
: the list of packages will be automatically updated every day
Create a Non-root User
Create a new user with sudo privileges so that your server isn’t always being accessed via the root user:
sudo adduser yourusername
sudo usermod -aG sudo yourusername
Log in as the new user:
su — yourusername
Other Security Measures
You may also want to secure your server by changing the default SSH port, disabling root login, and most importantly, setting up a firewall.
These steps are beyond the scope of this tutorial, but you can find many resources online to help you complete these tasks.
One great way to enable firewall for everything except Nginx and SSH processes is by the following commands:
sudo ufw allow ssh
sudo ufw allow "Nginx Full"
sudo ufw enable
sudo ufw status
Step 2: Install Some Dependencies
Install the necessary libraries and tools to get your deployment down the road:
sudo apt-get update
sudo apt-get install nginx gunicorn supervisor
And…Install Python
I prefer to use Pyenv to manage the Python versions on my system(s):
sudo curl https://pyenv.run | bash
You’ll need sudo as it needs to export with system Path variables.
Follow the instructions on the screen to add some snippets of code to your .bash_profile and .profile. Then, test it with:
pyenv versions
This will give you a list of Python versions that can be installed. Select something around 3.10 or higher if you’re like myself, using all the benefits of the newer versions.
pyenv install 3.11.1 # I used this version in my deployment
For specific requirements, select as per your needs.
Step 3: Set Up Your FastAPI API
Create a new directory for your FastAPI application and navigate to it:
mkdir ~/fastapi_server
cd ~/fastapi_server
Now clone your GitHub repo:
git clone https://your-fastapi-github-repo-URL .
Then create a virtual environment and activate it:
python3 -m venv venv
source venv/bin/activate
Install your requirements.txt
(you should have one already):
pip install -r requirements.txt
Test your FastAPI app locally by running:
uvicorn main:app — reload
Your app should now be running on localhost
.
Step 4: Set up Gunicorn
Install Gunicorn in your virtual environment:
pip install gunicorn
Now, in your project directory, go ahead and create a config file for Gunicorn called gunicorn_run:
#!/bin/bash
NAME=fastapi-server
DIR=/home/yourusername/fastapi_server
USER=yourusername
GROUP=yourusername
WORKERS=2
WORKER_CLASS=uvicorn.workers.UvicornWorker
VENV=$DIR/.venv/bin/activate
BIND=unix:$DIR/run/gunicorn.sock
LOG_LEVEL=info
cd $DIR
source $VENV
exec gunicorn main:app \
--name $NAME \
--workers $WORKERS \
--worker-class $WORKER_CLASS \
--user=$USER \
--group=$GROUP \
--bind=$BIND \
--log-level=$LOG_LEVEL \
--log-file=-
Make this file executable by running:
chmod u+x gunicorn_run
Finally, make the new BIND parameter path directory we specified above for defining our socket:
mkdir run
This will help run Gunicorn with 2 worker processes and the Uvicorn worker class.
Now, it’s time to setup to Supervisor to actually run Gunicorn with the above defined configurations!
Step 5: Set up Supervisor
Create a new Supervisor configuration file for your FastAPI app:
sudo nano /etc/supervisor/conf.d/fastapi_server.conf
Add the following configuration snippet:
[program:fastapi_server]
command=/home/yourusername/fastapi_server/gunicorn_run
user=yourusername
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stdout_logfile=/home/yourusername/fastapi_server/logs/gunicorn-errors.log
Close and save the file. Next, quickly make a new directory called “logs” in your project directory:
mkdir logs
This will store our Gunicorn errors.
Make sure to replace `yourusername
` with your actual username everywhere above.
Now, tell Supervisor to read the new configuration and check the status of the FastAPI server:
sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl status fastapi-server
Your FastAPI app should now show up as running as a managed process.
Test it by running a curl
command from the terminal:
curl --unix-socket /home/yourusername/fastapi-server/run/gunicorn.sock localhost://someendpoint-you-have-configured
It should return your desired response.
Step 6: Setting up NGINX on a custom domain
Create a new Nginx configuration file for your FastAPI server:
sudo nano /etc/nginx/sites-available/fastapi
Add the following configuration snippet inside:
upstream myfastapiserver {
server unix:/home/yourusername/fastapi-server/run/gunicorn.sock fail_timeout=0;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000; # replace your server IP here
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
if (!-f $request_filename) {
proxy_pass http://myfastapiserver;
break;
}
}
}
Replace `yourdomain.com` with your actual domain name.
Save and close the file. Then create a symbolic link to the `sites-enabled` directory:
sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/
Test your Nginx configuration and restart Nginx:
sudo nginx -t
sudo systemctl restart nginx
Your FastAPI app should now be accessible at `
http://yourdomain.com`.
Step 6: Obtain an SSL Certificate For FREE Using Certbot
Install snapd
first:
sudo apt install snapd
sudo snap install core; sudo snap refresh core
To obtain an SSL certificate for your domain, first install Certbot:
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Run Certbot to interactively obtain and install the SSL certificate on specific domains you’ve defined inside the Nginx config file:
sudo certbot --nginx
After following through the process, Certbot will automatically update your Nginx configuration to enable HTTPS.
Certbot will also automatically handle the renewal of your certificate when it’s time to actually do it. To test that it works, type and enter:
sudo certbot renew --dry-run
Troubleshooting common issues
If you get a permission error telling you that NGINX cannot access the unix socket, just add the www-data
user (which typically is the user running the NGINX processes) to the yourusername
group like so:
sudo usermod -aG yourusername www-data
Restart Supervisor process when your code changes (eg, on a Git Pull):
sudo supervisorctl restart fastapi-server
Conclusion
Hurray! 🎊
You’ve successfully deployed a FastAPI Python application using Nginx, Gunicorn, and Supervisor. Your app is now running as a managed process, and you’ve also secured it with an SSL certificate. Well done!
This setup is now suitable for production environments and can be easily scaled to handle more traffic by adjusting the number of Gunicorn worker processes.
If you learned something new today, share it with a friend maybe: