Skip to main content

Overview

Tambo360 includes complete Docker configuration for both development and production environments. This guide covers setting up and running the application using Docker containers.
Docker simplifies deployment by containerizing the backend, frontend, and database into isolated, reproducible environments.

Prerequisites

Docker

Version 20.10 or higher

Docker Compose

Version 2.0 or higher

Install Docker

# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker

Verify Docker Installation

docker --version
# Docker version 20.10.x or higher

docker compose version
# Docker Compose version 2.x.x or higher

Docker Architecture

Tambo360’s Docker setup includes three main services:

Services Configuration

ServiceContainer NamePortBase Image
Databasetambo-db5433:5432postgres:15
BackendAuto-generated3000:3000node:20-slim
FrontendAuto-generated5173:5173node:18-alpine

Docker Compose Configuration

The docker-compose.yml file defines the complete application stack:
docker-compose.yml
version: '3.8'

services:
  db:
    image: postgres:15
    container_name: tambo-db
    restart: always
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: tambo360
      POSTGRES_DB: tambo
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  backend:
    build:
      context: ./apps/backend
      target: development
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=${NODE_ENV}
      - PORT=${PORT}
      - DATABASE_URL=${DATABASE_URL}
      - JWT_SECRET=${JWT_SECRET}
      - FRONTEND_URL=${FRONTEND_URL}
    volumes:
      - ./apps/backend:/app
      - /app/node_modules
    depends_on:
      - db

  frontend:
    build:
      context: ./apps/frontend
      target: development
    ports:
      - "5173:5173"
    environment:
      - VITE_API_URL=http://localhost:3000/api
    volumes:
      - ./apps/frontend:/app
      - /app/node_modules
    depends_on:
      - backend

volumes:
  postgres_data:

networks:
  default:
    name: example-auth-network

Backend Dockerfile

The backend uses a multi-stage Dockerfile for optimal image sizes:
apps/backend/Dockerfile
# -------- BASE --------
FROM node:20-slim AS base

RUN apt-get update -y \
  && apt-get install -y openssl \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY package*.json ./

# -------- DEVELOPMENT --------
FROM base AS development

RUN npm install
COPY . .

EXPOSE 3000

CMD ["sh", "-c", "npx prisma generate && npx prisma migrate deploy && npm run dev"]

# -------- BUILD --------
FROM base AS build

RUN npm install
COPY . .

RUN npx prisma generate
RUN npm run build

# -------- PRODUCTION --------
FROM node:20-slim AS production

RUN apt-get update -y \
  && apt-get install -y openssl ca-certificates \
  && update-ca-certificates \
  && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY package*.json ./
RUN npm install --omit=dev

COPY prisma ./prisma
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules/.prisma ./node_modules/.prisma

ENV NODE_ENV=production

EXPOSE 3000

CMD ["node", "dist/server.js"]

Build Stages Explained

  • Uses Node.js 20 slim image
  • Installs OpenSSL (required for Prisma)
  • Sets up working directory
  • Copies package files
  • Installs all dependencies including devDependencies
  • Generates Prisma client
  • Runs database migrations
  • Starts development server with hot reload
  • Compiles TypeScript to JavaScript
  • Generates optimized Prisma client
  • Prepares production artifacts
  • Uses minimal Node.js image
  • Installs only production dependencies
  • Copies compiled code from build stage
  • Runs compiled JavaScript (not TypeScript)

Frontend Dockerfile

The frontend also uses multi-stage builds with different targets:
apps/frontend/Dockerfile
FROM node:18-alpine AS base

WORKDIR /app

COPY package*.json pnpm-lock.yaml* ./

RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile && pnpm store prune

# Development stage
FROM base AS development

COPY . .

EXPOSE 5173

CMD ["pnpm", "run", "dev"]

# Build stage
FROM base AS build

COPY . .

RUN pnpm run build

# Production stage
FROM nginx:alpine AS production

COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD wget --no-verbose --tries=1 --spider http://localhost/ || exit 1

CMD ["nginx", "-g", "daemon off;"]
The production frontend uses Nginx to serve static files efficiently.

Running with Docker Compose

Development Environment

1

Create environment file

Create a .env file in the root directory:
.env
NODE_ENV=development
PORT=3000
DATABASE_URL=postgresql://postgres:tambo360@db:5432/tambo
JWT_SECRET=your-secret-key-change-in-production
FRONTEND_URL=http://localhost:5173
EMAIL_USER=[email protected]
EMAIL_PASS=your-app-password
2

Start all services

docker compose up --build
This command:
  • Builds Docker images for backend and frontend
  • Pulls the PostgreSQL 15 image
  • Creates a Docker network
  • Starts all containers
  • Streams logs to the console
3

Access the applications

Run in Detached Mode

To run containers in the background:
docker compose up -d

View Logs

# View all logs
docker compose logs -f

# View specific service logs
docker compose logs -f backend
docker compose logs -f frontend
docker compose logs -f db

Stop Services

# Stop containers (preserves volumes)
docker compose stop

# Stop and remove containers
docker compose down

# Stop and remove containers + volumes (deletes database data)
docker compose down -v

Production Deployment

For production, use the production build targets:
1

Update docker-compose.yml for production

Uncomment the production backend service and modify environment variables:
docker-compose.prod.yml
version: '3.8'

services:
  backend:
    build:
      context: ./apps/backend
      target: production
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:tambo360@db:5432/tambo
    restart: always

  frontend:
    build:
      context: ./apps/frontend
      target: production
    ports:
      - "80:80"
    restart: always
2

Build and run production containers

docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
3

Run database migrations

docker compose exec backend npx prisma migrate deploy
Always use secure passwords and secrets in production. Never commit .env files to version control.

Docker Commands Reference

Container Management

# List running containers
docker compose ps

# Restart a specific service
docker compose restart backend

# Execute command in running container
docker compose exec backend sh

# View container resource usage
docker stats

Image Management

# Rebuild images without cache
docker compose build --no-cache

# Pull latest base images
docker compose pull

# List all images
docker images

# Remove unused images
docker image prune -a

Volume Management

# List volumes
docker volume ls

# Inspect database volume
docker volume inspect tambo360_postgres_data

# Backup database volume
docker run --rm -v tambo360_postgres_data:/data -v $(pwd):/backup ubuntu tar czf /backup/db-backup.tar.gz /data

# Remove all unused volumes
docker volume prune

Health Checks

The backend includes a health check endpoint:
# Check backend health
curl http://localhost:3000/api/health

# View health status in Docker
docker inspect --format='{{.State.Health.Status}}' <container-id>

Troubleshooting

If ports 3000, 5173, or 5433 are already in use:
# Find process using port
lsof -ti:3000 | xargs kill -9

# Or change ports in docker-compose.yml
ports:
  - "3001:3000"  # Use different host port
Ensure the database service is running:
docker compose ps db
docker compose logs db

# Restart database service
docker compose restart db
Regenerate Prisma client inside the container:
docker compose exec backend npx prisma generate
docker compose restart backend
On Linux, you may need to fix permissions:
sudo chown -R $USER:$USER ./apps
Check container logs for errors:
docker compose logs --tail=100 backend

# View exit code
docker compose ps

Best Practices

Use .dockerignore

Exclude node_modules, .git, and other unnecessary files from the build context.

Multi-stage Builds

Keep production images small by using multi-stage builds and only copying necessary artifacts.

Health Checks

Implement health checks for automatic container restart on failures.

Volume Backups

Regularly backup database volumes before updates or migrations.

Next Steps

Database Setup

Configure PostgreSQL and run migrations

Environment Variables

Complete configuration reference

Deployment

Deploy to production platforms

Build docs developers (and LLMs) love