avatarYash Prakash

Summary

The provided content outlines a comprehensive guide on deploying a FastAPI application using Nginx, Gunicorn, and Supervisor on an Ubuntu VPS, ensuring security and scalability for production environments.

Abstract

The article details a step-by-step process for deploying a FastAPI web application on a virtual private server (VPS) running Ubuntu 20.04. It emphasizes the importance of securing the server by enabling automatic updates, creating a non-root user, and setting up a firewall. The deployment stack includes Nginx as a web server and reverse proxy, Gunicorn as a WSGI HTTP server, and Supervisor for process control. The guide covers setting up Python with Pyenv, configuring Gunicorn and Supervisor, and integrating Nginx with a custom domain. It concludes with instructions for obtaining a free SSL certificate using Certbot to secure the application with HTTPS. The tutorial aims to enhance the reader's deployment skills and ensure their FastAPI application is robust and ready for production traffic.

Opinions

  • The author advocates for the use of FastAPI due to its ease of setup and performance benefits over other frameworks, including Node.js.
  • The author suggests using Pyenv for Python version management, indicating a preference for control and flexibility in development environments.
  • The author highlights the significance of automating security updates to maintain system integrity without manual intervention.
  • The recommendation to change the default SSH port and disable root login implies a strong emphasis on server security best practices.
  • The use of Supervisor to manage Gunicorn processes reflects the author's experience in ensuring that the FastAPI application runs reliably as a managed service.
  • The inclusion of troubleshooting tips for common issues, such as permission errors with NGINX, suggests the author's awareness of practical deployment challenges.
  • The author encourages readers to subscribe to a newsletter for ongoing educational content, indicating a commitment to community engagement and continuous learning.

Deploying a FastAPI App with Nginx, Supervisor, and Gunicorn

Take your Python API deployment skills to the next level in under 6 minutes

Photo by Jaredd Craig on Unsplash

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, 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 intervene
  • APT::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.

Hope you learned something new from this tutorial!

If you want a regular supply of these informative articles, get my newsletter: https://codecast.substack.com

Level Up Coding

Thanks for being a part of our community! Before you go:

🔔 Follow us: Twitter | LinkedIn | Newsletter

🚀👉 Join the Level Up talent collective and find an amazing job

Python
Technology
Programming
Coding
Development
Recommended from ReadMedium