Skip to content
OVEX TECH
Education & E-Learning

Deploy Your FastAPI App to a VPS: Security, Nginx, SSL

Deploy Your FastAPI App to a VPS: Security, Nginx, SSL

How to Deploy Your FastAPI App to a Live Server

This guide will show you how to take your FastAPI application, built with features like authentication, a PostgreSQL database, and S3 file storage, and make it accessible to the public internet. We will deploy it to a Virtual Private Server (VPS), configure essential security measures, set up a custom domain name, and secure it with an SSL certificate using Nginx. This process provides a fundamental understanding of web application deployment that applies to various VPS providers.

Prerequisites

  • A completed FastAPI application (as built in previous tutorials).
  • A GitHub account to host your code.
  • A registered domain name.
  • Basic familiarity with the command line and Git.

Step 1: Add a Health Check Endpoint

Before deploying, it’s crucial to add a health check to your FastAPI application. This endpoint lets monitoring systems and load balancers know if your application is running correctly. For our blog app, we’ll check if the database is reachable.

  1. Open your main application file (e.g., main.py).
  2. Add the necessary import: from sqlalchemy import text.
  3. Locate where you include your routers. Right after that, add the health check endpoint.
  4. Paste the following code snippet to create the health check route:
@app.get("/health", tags=["Health"])
async def health_check(db: Session = Depends(get_db)):
 try:
 # Execute a lightweight query to check database connectivity
 await db.execute(text("SELECT 1"))
 return {"status": "healthy"}
 except Exception:
 raise HTTPException(status_code=503, detail="Database unavailable")

This code attempts a simple database query. If it succeeds, it returns a “healthy” status. If it fails (meaning the database is down), it returns a 503 Service Unavailable error.

Step 2: Upload Your Code to GitHub

To easily transfer your project to the server, we’ll use GitHub. You can use a public or private repository; public is fine for this tutorial.

  1. Create a new repository on GitHub (e.g., fastapi-tutorial-18-deployment-vps).
  2. In your local project’s terminal, add the GitHub repository as a remote origin and push your code:
git remote add origin https://github.com/YOUR_USERNAME/YOUR_REPO_NAME.git
git push -u origin main

Expert Note: Ensure your .env file is in your .gitignore file. Never push sensitive credentials to your code repository.

  1. Commit your latest changes (including the health check) if you haven’t already:
git add . Git commit -m "Add health check endpoint"
git push

Step 3: Set Up Your Virtual Private Server (VPS)

We’ll use a VPS provider like Linode. The concepts apply to DigitalOcean, AWS EC2, etc.

  1. Sign up for a VPS provider account (e.g., Linode).
  2. Create a new server instance (a “Linode” on Linode).
  3. Choose an Image: Select Ubuntu 24.04 LTS for long-term support.
  4. Choose a Region: Pick a data center geographically close to your expected users.
  5. Choose a Plan: Start with a basic, affordable plan (e.g., 1GB RAM shared CPU) for small applications. You can upgrade later.
  6. Add a Label: Give your server a descriptive name (e.g., fastapi-blog).
  7. Set a Strong Root Password: Create a secure password and save it.
  8. Finalize Creation: Review add-ons (like backups) and create the server.

Once the server is provisioned, you will get a public IP address. Note this IP address down.

Step 4: Connect to Your Server via SSH

You’ll connect to your server using SSH (Secure Shell). We’ll initially log in as the root user.

  1. Open your local terminal.
  2. Connect using the SSH command, replacing YOUR_SERVER_IP with your server’s IP address:
ssh root@YOUR_SERVER_IP

You’ll be asked to confirm the server’s fingerprint; type yes. Then, enter the root password you set during server creation.

Step 5: Initial Server Setup and User Creation

It’s best practice to create a non-root user for daily operations to limit potential damage from mistakes or security breaches.

  1. Update System Packages: Ensure your server has the latest software and security patches.
sudo apt update && sudo apt upgrade -y

When prompted about configuration files, choose the package maintainer’s version for a clean install.

  1. Create a New User: Replace your_username with your desired username.
adduser your_username

Set a strong password for this new user when prompted. You can skip the additional user details by pressing Enter.

  1. Grant Sudo Privileges: Allow your new user to run administrative commands.
usermod -aG sudo your_username

Verify the user is in the sudo group by running groups your_username.

Step 6: Set Up SSH Key-Based Authentication

SSH keys are more secure than passwords. We’ll generate a key pair on your local machine and copy the public key to the server.

  1. Generate SSH Key Pair (Local Machine):
ssh-keygen -t ed25519 -C "[email protected]"

Accept the default file location (~/.ssh/id_ed25519) or specify a descriptive name. Enter a strong passphrase when prompted. This passphrase protects your private key.

  1. Copy Public Key to Server: Use the ssh-copy-id command. Replace your_username and YOUR_SERVER_IP.
ssh-copy-id -i ~/.ssh/id_ed25519.pub your_username@YOUR_SERVER_IP

Enter the password for your new user on the server when prompted.

  1. Add Key to SSH Agent (Local Machine): This allows you to use the key without re-entering the passphrase every time.
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

Enter your SSH key passphrase when asked.

  1. Test SSH Key Login: Try connecting to your server again. You should not be asked for a password.
ssh your_username@YOUR_SERVER_IP

If this works, your SSH key setup is successful.

Step 7: Harden SSH Configuration

To significantly improve security, we’ll disable root login and password authentication entirely, forcing all logins to use SSH keys.

  1. Edit SSH Daemon Configuration:
sudo nano /etc/ssh/sshd_config

Find and modify the following lines:

  • PermitRootLogin no
  • PubkeyAuthentication yes
  • PasswordAuthentication no
  • ChallengeResponseAuthentication no

Save the file (Ctrl+X, then Y, then Enter).

  1. Restart SSH Service:
sudo systemctl restart ssh

Critical Warning: Before closing your current SSH session, open a *new* terminal window on your local machine and try to SSH into the server using your SSH key. If you cannot connect, revert the changes in sshd_config using your root login before proceeding. Once you confirm you can still log in, you can close the root session.

Step 8: Configure Firewall (UFW)

A firewall controls network traffic to and from your server. We’ll use UFW (Uncomplicated Firewall).

  1. Install UFW (if not already installed):
sudo apt install ufw -y
  1. Set Default Policies: Deny all incoming traffic and allow all outgoing traffic by default.
sudo ufw default deny incoming
sudo ufw default allow outgoing
  1. Allow Necessary Ports: Crucially, allow SSH, HTTP (port 80), and HTTPS (port 443) traffic.
sudo ufw allow OpenSSH
sudo ufw allow http
sudo ufw allow https

Important: Always allow SSH *before* enabling the firewall to avoid locking yourself out.

  1. Enable the Firewall:
sudo ufw enable

Confirm with y. Check the status with sudo ufw status verbose.

Step 9: Install and Configure Nginx and SSL

Nginx will act as a reverse proxy, handling incoming web requests and directing them to your FastAPI application. We’ll also set up SSL for HTTPS.

  1. Install Nginx:
sudo apt install nginx -y
  1. Configure Nginx for Your App: Create a new Nginx configuration file for your domain. Replace your_domain.com with your actual domain name.
sudo nano /etc/nginx/sites-available/your_domain.com

Paste the following configuration, adjusting your_domain.com and the server’s IP address (if needed). Make sure the proxy_pass points to where your FastAPI app will run (e.g., http://127.0.0.1:8000).

server {
 listen 80;
 server_name your_domain.com www.your_domain.com;

 location / {
 proxy_pass http://127.0.0.1:8000; # Assuming your app runs on port 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;
 }
}
  1. Enable the Nginx Site: Create a symbolic link to enable the configuration.
sudo ln -s /etc/nginx/sites-available/your_domain.com /etc/nginx/sites-enabled/
  1. Test Nginx Configuration:
sudo nginx -t

If syntax is okay, proceed. If not, fix errors in the configuration file.

  1. Install Certbot for SSL: Certbot automates obtaining and renewing Let’s Encrypt SSL certificates.
sudo apt install certbot python3-certbot-nginx -y
  1. Obtain SSL Certificate: Run Certbot to get a certificate for your domain.
sudo certbot --nginx -d your_domain.com -d www.your_domain.com

Follow the prompts. Certbot will automatically update your Nginx configuration to use HTTPS and set up automatic renewal.

Step 10: Deploy Your FastAPI Application

Now we need to get your FastAPI app running on the server and make sure it starts automatically.

  1. Install Dependencies: On your server, clone your repository (if you haven’t already) and install project dependencies.
git clone https://github.com/YOUR_USERNAME/YOUR_REPO_NAME.git
cd YOUR_REPO_NAME
sudo apt install python3-venv python3-dev build-essential libpq-dev -y
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

Make sure your requirements.txt includes fastapi, uvicorn[standard], sqlalchemy, and your database driver (e.g., psycopg2-binary).

  1. Configure Environment Variables: Set up your production database URL and other secrets in a .env file on the server.

Security Tip: Use a tool like python-dotenv to load these variables into your application.

  1. Run FastAPI with Uvicorn: Start your FastAPI application. Replace main:app with your application’s entry point.
uvicorn main:app --host 0.0.0.0 --port 8000 --reload

Test if your application is accessible via your domain name (e.g., http://your_domain.com/health). If not, check Nginx logs (`/var/log/nginx/error.log`) and your application’s output.

  1. Set Up a Process Manager (Systemd): To ensure your application runs continuously and restarts if it crashes, use a process manager like Systemd. Create a service file.
sudo nano /etc/systemd/system/fastapi_blog.service

Paste the following configuration, adjusting paths and usernames:

[Unit]
Description=FastAPI Blog Service
After=network.target

[Service]
User=your_username
Group=your_username
WorkingDirectory=/home/your_username/YOUR_REPO_NAME
ExecStart=/home/your_username/YOUR_REPO_NAME/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
  1. Enable and Start the Service:
sudo systemctl daemon-reload
sudo systemctl enable fastapi_blog.service
sudo systemctl start fastapi_blog.service
sudo systemctl status fastapi_blog.service

Check the status to ensure it’s running. You can view logs using sudo journalctl -u fastapi_blog.service.

Conclusion

Your FastAPI application is now deployed to a VPS, accessible via your custom domain with HTTPS, and secured with a firewall and SSH hardening. This foundation allows real users to interact with your application. For more advanced deployments, consider containerization with Docker in the next tutorial.


Source: Python FastAPI Tutorial (Part 18): Deploy to a VPS – Security, Nginx, SSL, and Custom Domain (YouTube)

Leave a Reply

Your email address will not be published. Required fields are marked *

Written by

John Digweed

3,025 articles

Life-long learner.