Skip to main content

Docker Compose

Self-host NestForge Pro on any VPS (DigitalOcean, Hetzner, Linode, etc.) using Docker Compose. The API includes a multi-stage Dockerfile that produces a lean production image.

Prerequisites

  • A server with Docker and Docker Compose installed
  • A domain name (optional but recommended)

The Dockerfile

NestForge ships a three-stage Dockerfile at apps/api/Dockerfile:

  1. deps -- installs all npm dependencies
  2. builder -- generates the Prisma client and builds the NestJS app
  3. runner -- copies only production artifacts into a minimal node:20-alpine image, runs as a non-root nestforge user, and exposes port 4000

The image includes a built-in health check at /health.

Compose file

A docker-compose.yml is included at the project root. Here is what it contains:

version: "3.8"

services:
api:
build:
context: .
dockerfile: apps/api/Dockerfile
ports:
- "4000:4000"
environment:
DATABASE_URL: postgresql://nestforge:nestforge@postgres:5432/nestforge
REDIS_URL: redis://redis:6379
JWT_SECRET: ${JWT_SECRET}
JWT_REFRESH_SECRET: ${JWT_REFRESH_SECRET}
STRIPE_SECRET_KEY: ${STRIPE_SECRET_KEY}
STRIPE_WEBHOOK_SECRET: ${STRIPE_WEBHOOK_SECRET}
RESEND_API_KEY: ${RESEND_API_KEY}
EMAIL_FROM: ${EMAIL_FROM}
APP_URL: ${APP_URL}
API_URL: ${API_URL}
NODE_ENV: production
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped

postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: nestforge
POSTGRES_PASSWORD: nestforge
POSTGRES_DB: nestforge
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U nestforge"]
interval: 5s
timeout: 3s
retries: 5

redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redisdata:/data
restart: unless-stopped

volumes:
pgdata:
redisdata:

Steps

1. Create a .env file

Copy the example and fill in your secrets:

cp .env.example .env

At minimum, set JWT_SECRET, JWT_REFRESH_SECRET, APP_URL, and API_URL. Generate secrets with:

openssl rand -base64 32

2. Build and start

docker compose up -d --build

3. Run database migrations

docker compose exec api npx prisma migrate deploy --schema=./prisma/schema.prisma

4. Verify

curl http://localhost:4000/health

Serving the frontend

Build the web app locally (or in CI) and serve the static files with nginx or Caddy:

cd apps/web
VITE_API_URL=https://api.yourdomain.com npm run build

The output in apps/web/dist can be served by any static file server. A minimal nginx config:

server {
listen 80;
server_name yourdomain.com;
root /var/www/nestforge/dist;
index index.html;

location / {
try_files $uri $uri/ /index.html;
}
}

Updating

Pull the latest code, rebuild, and re-run migrations:

git pull
docker compose up -d --build
docker compose exec api npx prisma migrate deploy --schema=./prisma/schema.prisma