From Code to Production - Deploying FastAPI to a VPS with GitHub Actions CI/CD
Learn how to deploy a FastAPI app to a VPS and set up GitHub Actions for automatic deployment every time you push code — a full CI/CD workflow from scratch.
Prerequisites
- A VPS (e.g., Ubuntu 22.04 on DigitalOcean, Linode, etc.)
- Domain name (optional)
- Basic knowledge of Python, Git, and Linux
- SSH access to the server
- GitHub account with FastAPI project repository
- Update your system
1
sudo apt update && sudo apt upgrade -y
- Install dependencies for building Python
1 2 3 4 5 6 7
sudo apt install -y software-properties-common \ build-essential libssl-dev zlib1g-dev \ libncurses5-dev libncursesw5-dev \ libreadline-dev libsqlite3-dev \ libgdbm-dev libdb5.3-dev libbz2-dev \ libexpat1-dev liblzma-dev tk-dev \ curl wget git
- Install Python (recommended: 3.10 or newer)
1
sudo apt install python3 python3-pip -y
Check version
1
python3 --version
- Install FastAPI and Uvicorn
1
2
3
4
5
6
python3 -m venv venv
source venv/bin/activate
# Install FastAPI and Uvicorn:
pip install fastapi uvicorn
- Create a simple FastAPI app
Create a file named main.py
1
nano main.py
Paste this example:
1
2
3
4
5
6
7
8
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def read_root():
return {"message": "Hello from your VPS!"}
Run it:
1
uvicorn main:app --host 0.0.0.0 --port 8000
0.0.0.0 means “listen on all interfaces” so it’s accessible from outside.
Visit in browser:
1
http://your-vps-ip:8000
Summary
- Install Python -> sudo apt install python3 python3-pip -y
- Create venv -> python3 -m venv venv
- Activate venv source -> venv/bin/activate
- Install FastAPI + Uvicorn -> pip install fastapi uvicorn
- Create app -> nano main.py
- Run app -> uvicorn main:app –host 0.0.0.0 –port 8000
To create project directory:
1 2 mkdir ~/fastapi-app cd ~/fastapi-app
To delete project directory:
1 2 cd ~ rm -rf fastapi-app
- rm: remove command
- -r: recursive (removes all subdirectories/files)
- -f: force (no confirmation prompts)
Setup Deployment to VPS On Push With GitHub Actions
Set up SSH Key Access from GitHub to VPS
- Generate SSH key on your local machine (in my case on Win11 CMD)
1
ssh-keygen -t ed25519 -C "github-actions-deploy"
- Add public key to VPS - manually add the contents of github_fastapi_key.pub to:
1
~/.ssh/authorized_keys
- Add private key to GitHub
Go to GitHub repo → Settings → Secrets and variables → Actions → New repository secret:
Name: SSH_PRIVATE_KEY
Value: contents of github_fastapi_key NOT FROM PUB file but one without extension
VPS_HOST: your VPS IP or domain
VPS_USER: your VPS username
Set Up Your VPS to Accept Deploys
On the VPS:
- Clone your repo manually the first time
This command will clone repo to the /home/ubuntu/fastapi-app folder
1
git clone git@github.com:yourusername/yourrepo.git /home/ubuntu/fastapi-app
If VPS can’t clone the repo then we need to generate SSH key directly on VPS and add it to the GitHub repot Public Key section.
- Make sure your FastAPI app can run on the server
1 2 3
cd fastapi-app source venv/bin/activate uvicorn main:app --host 0.0.0.0 --port 8000
To deactivate virtual environment, run the command “deactivate”.
Run the command to keep uvicorn running after closing SSH session:
1 nohup uvicorn main:app --host 0.0.0.0 --port 8000 &> log.txt &
Create GitHub Actions Workflow
Create file: .github/workflows/deploy.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
name: Deploy to VPS
on:
push:
branches:
- main # or master, or whatever your deploy branch is
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: ⏳ Checkout code
uses: actions/checkout@v3
- name: 🔐 Set up SSH
uses: webfactory/ssh-agent@v0.7.0
with:
ssh-private-key: $
- name: 🚀 Deploy to VPS via SSH
run: |
ssh -o StrictHostKeyChecking=no $@$ << 'EOF'
cd $
git pull
source venv/bin/activate
pip install -r requirements.txt
# enter correct cloned/application folder name
sudo systemctl restart fastapi-app.service
EOF
Run FastAPI with systemd (recommended)
This keeps your app running and restarts it on reboot or deploy.
Create a systemd service on VPS:
1
sudo nano /etc/systemd/system/fastapi-app.service
Paste this (customize paths):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Unit]
Description=FastAPI App
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/fastapi-app
ExecStart=/home/ubuntu/fastapi-app/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000
Restart=always
[Install]
WantedBy=multi-user.target
Then enable and start it:
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable fastapi-app
sudo systemctl start fastapi-app
Now, whenever we push to main (or the branch you chose), GitHub Actions will:
- SSH into your VPS
- Pull the latest code
- Install dependencies
- Restart your FastAPI app via systemd
If you’re getting “Access denied” when trying to manually add an SSH public key to your VPS as root, even though you’re logged in as root, run these commands on VPS as root:
1
2
3
4
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
Then, manually add your public key to the file:
1
nano ~/.ssh/authorized_keys
Paste your public key (e.g., from github_fastapi_key.pub), then save and exit.
Generate requirements.txt automatically from your environment:
1pip freeze > requirements.txt