Deploying a FastAPI Backend on DigitalOcean with Dokploy and Docker

A practical production deployment setup for FastAPI using Docker and Dokploy on a DigitalOcean VPS, with PostgreSQL, HTTPS, and operational hardening.

fastapi
docker
dokploy
digitalocean
postgresql
deployment
devops
backend
Kazi Efazul Karim
4 min read
Deploying a FastAPI Backend on DigitalOcean with Dokploy and Docker

Deploying a FastAPI Backend on DigitalOcean with Dokploy and Docker

I recently moved my backend deployment from “works on my machine” to a production setup on a DigitalOcean VPS using Docker and Dokploy.

The goal was simple:

  • clean, repeatable deployments
  • low operational cost
  • room to scale later

The result is a practical stack that runs the API, PostgreSQL, HTTPS, and backups in a way that is easy to operate and maintain.

FastAPI + Dokploy + Docker deployment architecture

Why I chose Dokploy

I wanted something lighter than Kubernetes, but more structured than manually SSH’ing into a server and running everything by hand. Dokploy fit that middle ground.

It gives:

  • GitHub-based deployments
  • service management
  • domain + SSL handling
  • backups
  • a clean dashboard

Since I already had Dockerized services, Dokploy felt like the natural orchestration layer.

The architecture ended up being:

  • a single DigitalOcean VPS
  • Dokploy as the deployment platform
  • Docker containers for the API and PostgreSQL
  • HTTPS handled through Dokploy’s reverse proxy (Traefik)
  • GitHub as the source of truth

Step 1: Prepare the application for production

Before deploying anything, I hardened the backend for production.

Main changes:

  • slim Docker image
  • non-root runtime user
  • HEALTHCHECK
  • startup script that runs migrations and then starts Gunicorn with Uvicorn workers
  • logging to stdout
  • TrustedHostMiddleware
  • secure cookies in production
  • ALLOWED_HOSTS
  • reusable outbound HTTP client
  • documented .env.example

These matter because deployment failures are often app-readiness issues, not VPS issues.

Step 2: Push the latest code to GitHub

Dokploy deploys what is pushed, not what exists only locally.

So I made sure all production hardening changes were committed and pushed before server setup.

Step 3: Provision the VPS

I used a 4 GB Ubuntu VPS in Singapore. That gave enough headroom for:

  • app container
  • PostgreSQL container
  • Dokploy
  • reverse proxy overhead

After running Dokploy’s installer, I got:

  • Docker
  • Docker Swarm support
  • Traefik for routing/TLS
  • Dokploy dashboard (initially on port 3000)

Step 4: Configure DNS

I pointed a subdomain to the VPS with an A record.

This is critical because Let’s Encrypt issuance depends on correct DNS resolution and HTTP reachability.

Step 5: Add PostgreSQL inside Dokploy

Instead of host-level PostgreSQL, I created PostgreSQL as a Dokploy-managed service.

For the internal connection string, I explicitly used:

  • internal hostname/network routing
  • sslmode=disable

That setting only affects DB traffic inside the private network and is separate from public HTTPS.

Step 6: Deploy the API service

In Dokploy, I created a GitHub-connected Docker app and pointed it to:

  • repository
  • main branch
  • Dockerfile build
  • internal app port

Then I added environment variables based on .env.example:

  • production mode
  • database credentials
  • JWT secret
  • API keys
  • allowed hosts
  • frontend origin
  • base URL

The startup script handled migrations automatically on boot.

Step 7: Enable HTTPS

Once DNS and ports were correct, Traefik handled TLS issuance and routing.

Important detail: the app container still listens on internal HTTP. HTTPS is terminated at Traefik.

Deployment request flow from browser to FastAPI container

Step 8: Verify the deployment

I verified with a health endpoint, not /.

A successful verification means:

  • HTTPS works
  • domain resolves correctly
  • container is running
  • /health returns success

Lessons learned

1) App readiness comes first

Docker alone is not production readiness. Startup behavior, migrations, logging, host validation, and env hygiene matter just as much.

2) Internal DB SSL and external HTTPS are different layers

  • DB SSL settings apply to database connectivity
  • HTTPS applies to public web traffic

They solve different problems.

3) DNS and ports are common failure points

When TLS fails, usual causes are:

  • DNS not propagated
  • port 80 blocked
  • domain not properly attached
  • wrong internal target port

4) 4 GB VPS is a practical baseline

It’s enough for a small production backend stack without premature complexity.

Final architecture

  • DigitalOcean VPS: compute
  • Dokploy: deployment manager
  • Docker: runtime
  • PostgreSQL container: database
  • Traefik: SSL + routing
  • GitHub: source and deployment trigger
  • Health endpoint: operational check

Closing thoughts

This setup feels production-grade without being heavy. For a solo dev or small team, it is a practical path: harden the app, containerize it, deploy with Dokploy, and keep operations simple.

Share this article

Help others discover this content