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:
- deps -- installs all npm dependencies
- builder -- generates the Prisma client and builds the NestJS app
- runner -- copies only production artifacts into a minimal
node:20-alpineimage, runs as a non-rootnestforgeuser, and exposes port4000
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