FastAPI Deploying to a Cloud Server

Running your app on your local machine is fine for development. Deploying to a cloud server makes it accessible to anyone on the internet, keeps it running 24/7, and scales when traffic grows. This topic covers two paths: deploying a Docker container to a cloud VM, and deploying to a managed platform.

Deployment Options Overview

Option 1: Cloud VM (VPS)
  Full control. You manage the server.
  Providers: DigitalOcean, AWS EC2, Linode, Hetzner
  Best for: custom setups, cost control at scale

Option 2: Managed Platform (PaaS)
  Platform handles servers, scaling, SSL.
  Providers: Railway, Render, Fly.io, Heroku
  Best for: fast deployment, small teams, prototypes

Option 3: Kubernetes
  Orchestrates many containers across many machines.
  Best for: large-scale production systems

Deploying to a Cloud VM (Ubuntu + Docker)

Step 1: Provision the Server

Create an Ubuntu 22.04 VM on your chosen cloud provider. Get the server's IP address and SSH access.

Step 2: Install Docker on the Server

ssh user@your-server-ip

# Install Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Step 3: Transfer Your App

# Option A: copy files with scp
scp -r ./my-fastapi-app user@your-server-ip:/home/user/

# Option B: clone from Git (recommended)
git clone https://github.com/yourname/your-repo.git
cd your-repo

Step 4: Build and Run

docker build -t my-app .
docker run -d -p 8000:8000 --restart always my-app
-d           → run in background (detached)
--restart always → restart automatically if server reboots

Adding a Reverse Proxy with Nginx

Nginx sits in front of your app, handles HTTPS, and forwards traffic to your container. Port 80 (HTTP) and 443 (HTTPS) cannot be used directly by Docker containers without root — Nginx bridges this gap.

Internet → port 443 → [ Nginx ] → port 8000 → [ FastAPI container ]
# Install Nginx
sudo apt install nginx

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Free SSL with Certbot

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com

# Certbot automatically edits your nginx config
# and sets up auto-renewal

After this step, your API is accessible at https://yourdomain.com with a valid SSL certificate.

Deploying to Render (Managed Platform)

Step 1: Push your code to GitHub

Step 2: Sign up at render.com

Step 3: Create a new "Web Service"
  → Connect your GitHub repo
  → Set build command: pip install -r requirements.txt
  → Set start command: uvicorn main:app --host 0.0.0.0 --port $PORT
  → Add environment variables (DATABASE_URL, SECRET_KEY)

Step 4: Click Deploy
  → Render builds, deploys, and gives you an HTTPS URL

Deploying to Railway

Step 1: Sign up at railway.app
Step 2: New project → Deploy from GitHub repo
Step 3: Add a PostgreSQL plugin (one click)
Step 4: Set environment variables
Step 5: Railway auto-detects FastAPI and deploys

Result: live URL in ~2 minutes

Environment Variables for Production

Development (.env file, never committed):
  DATABASE_URL=sqlite:///./dev.db
  SECRET_KEY=dev-secret

Production (set in cloud dashboard, not in code):
  DATABASE_URL=postgresql://user:pass@prod-host/db
  SECRET_KEY=long-random-production-secret
  DEBUG=false

Health Check Endpoint

Add a simple health check route. Cloud platforms and load balancers ping this to verify your app is alive:

@app.get("/health")
def health():
    return {"status": "ok"}

Key Points

  • Cloud VMs give full control; managed platforms give speed and simplicity.
  • Run containers with --restart always on a VM so they survive reboots.
  • Use Nginx as a reverse proxy to handle ports 80/443 and forward to your app.
  • Use Certbot to get free, auto-renewing SSL certificates from Let's Encrypt.
  • Always set production secrets as environment variables in the cloud dashboard — never in code.

Leave a Comment

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