Docker Deployment

Deploy GritCMS with Docker Compose using PostgreSQL, with all three services containerized.

Docker Compose is the recommended way to deploy GritCMS in a production or staging environment. It packages the API, admin dashboard, and public site into containers alongside a PostgreSQL database.

Prerequisites

  • Docker 20.10+ installed on your server or local machine
  • Docker Compose v2 (included with Docker Desktop, or install separately on Linux)
  • At least 1 GB RAM available for the containers

Architecture

The Docker Compose setup runs four containers:

ServiceImagePortDescription
apiBuilt from apps/api8080Go backend
adminBuilt from apps/admin3000Next.js admin dashboard
webBuilt from apps/web3001Next.js public site
dbpostgres:16-alpine5432PostgreSQL database

Example docker-compose.yml

version: "3.8"
 
services:
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_USER: gritcms
      POSTGRES_PASSWORD: your_secure_password
      POSTGRES_DB: gritcms
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"
 
  api:
    build:
      context: .
      dockerfile: apps/api/Dockerfile
    restart: unless-stopped
    depends_on:
      - db
    environment:
      DATABASE_URL: postgres://gritcms:your_secure_password@db:5432/gritcms?sslmode=disable
      JWT_SECRET: your_jwt_secret_here
      PORT: "8080"
    ports:
      - "8080:8080"
    volumes:
      - uploads:/app/uploads
 
  admin:
    build:
      context: .
      dockerfile: apps/admin/Dockerfile
    restart: unless-stopped
    depends_on:
      - api
    environment:
      NEXT_PUBLIC_API_URL: http://api:8080
    ports:
      - "3000:3000"
 
  web:
    build:
      context: .
      dockerfile: apps/web/Dockerfile
    restart: unless-stopped
    depends_on:
      - api
    environment:
      NEXT_PUBLIC_API_URL: http://api:8080
    ports:
      - "3001:3001"
 
volumes:
  pgdata:
  uploads:

Environment Variables

Configure these environment variables in the docker-compose.yml file or via a .env file:

API Service

VariableRequiredDescription
DATABASE_URLYesPostgreSQL connection string
JWT_SECRETYesSecret key for JWT authentication
PORTNoAPI port (default: 8080)
UPLOAD_DIRNoUpload directory (default: /app/uploads)

Frontend Services (Admin & Web)

VariableRequiredDescription
NEXT_PUBLIC_API_URLYesURL of the API service

Building and Running

From the project root directory, build and start all services:

docker compose up -d --build

This builds the Docker images for all three application services, pulls the PostgreSQL image, and starts everything in detached mode.

To check that all containers are running:

docker compose ps

To view logs:

docker compose logs -f

Persistent Volumes

The docker-compose.yml defines two named volumes:

  • pgdata -- stores PostgreSQL data. Your database persists across container restarts and rebuilds.
  • uploads -- stores user-uploaded files (images, media, etc.). This ensures uploads are not lost when the API container is recreated.

Never delete these volumes unless you intentionally want to wipe data.

Seeding Default Data

After the first deployment, seed the database with default settings:

curl -X POST http://localhost:8080/api/seed-defaults

Or from within the Docker network:

docker compose exec api curl -X POST http://localhost:8080/api/seed-defaults

Updating the Deployment

To deploy a new version of GritCMS:

git pull
docker compose up -d --build

Docker Compose rebuilds only the images that have changed. The database volume is preserved, so your data remains intact.

Production Considerations

  • Replace default secrets. Always set a strong, unique JWT_SECRET and POSTGRES_PASSWORD in production.
  • Use a reverse proxy. Place Nginx, Caddy, or Traefik in front of the services to handle SSL termination and route traffic to the correct ports.
  • Back up the database. Schedule regular backups of the pgdata volume or use pg_dump inside the database container.
  • Resource limits. Consider setting memory and CPU limits on each service in the Compose file for predictable resource usage.