Skip to main content
SociApp provides a complete Docker setup for easy deployment with separate containers for backend and frontend services.

Docker Compose Setup

The application uses Docker Compose to orchestrate multiple services:
# docker-compose.yml:1
version: "3.8"

services:
  backend:
    build: ./backend
    container_name: nest-backend
    restart: always
    env_file:
      - ./backend/.env
    environment:
      - FRONTEND_URL=http://16.171.57.244
    networks:
      - app-network
    ports:
      - "3000:3000"
      - "3001:3001"
    volumes:
      - ./backend/uploads:/app/uploads

  frontend:
    build:
      context: ./frontend
      args:
        - VITE_API_URL=http://16.171.57.244:3000
    container_name: vue-frontend
    restart: always
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Backend Dockerfile

The backend uses a lightweight Node.js Alpine image:
# backend/dockerfile:1
# Lightweight base image
FROM node:22-alpine

# Working directory inside container
WORKDIR /app

# Copy dependencies first (improves cache)
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy the rest of the code
COPY . .

# Build project
RUN npm run build

# Expose port
EXPOSE 3000

# Start command
CMD ["node", "dist/main.js"]

Backend Build Process

1

Base Image

Uses node:22-alpine for a minimal footprint (approximately 180MB vs 1GB for full Node image)
2

Dependency Installation

Copies package*.json first to leverage Docker layer caching. Dependencies only rebuild when package files change.
3

Build Stage

Runs npm run build to compile TypeScript to JavaScript in the dist/ directory
4

Runtime

Executes the compiled application using node dist/main.js

Frontend Dockerfile

The frontend uses a multi-stage build for optimal production size:
# frontend/dockerfile:1
# ---------- STAGE 1: Build ----------
FROM node:22-alpine as build

WORKDIR /app

# Build argument for API URL
ARG VITE_API_URL
ENV VITE_API_URL=$VITE_API_URL

COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build-only

# ---------- STAGE 2: Serve ----------
FROM nginx:alpine

COPY --from=build /app/dist /usr/share/nginx/html

# Copy nginx configuration for SPA
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Multi-Stage Build Benefits

The final image only contains the built static files and nginx, not Node.js or build dependencies. Typical size: ~25MB vs 400MB+
The VITE_API_URL argument is injected at build time and baked into the JavaScript bundle.
Nginx serves the static files with optimal performance and SPA routing support.

Environment Variables

Backend Environment

Create a .env file in the backend/ directory:
# Database
DB_HOST=your-database-host
DB_PORT=3306
DB_USERNAME=your-db-user
DB_PASSWORD=your-db-password
DB_NAME=your-database-name

# JWT Secrets
JWT_ACCESS_SECRET=your-secure-access-secret-here
JWT_REFRESH_SECRET=your-secure-refresh-secret-here

# Email Service
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USER=[email protected]
MAIL_PASSWORD=your-email-password
MAIL_FROM=[email protected]

# Application
NODE_ENV=production
FRONTEND_URL=http://your-domain.com
Never commit .env files to version control. Add them to .gitignore.

Frontend Build Arguments

The frontend requires the API URL at build time:
frontend:
  build:
    context: ./frontend
    args:
      - VITE_API_URL=http://your-api-domain.com:3000

Port Configuration

Backend Ports

  • 3000: Main API server
  • 3001: Secondary service (if needed)

Frontend Port

  • 80: HTTP web server (nginx)

Port Mapping

ports:
  - "host-port:container-port"
  • Host Port: Accessible from outside the container
  • Container Port: Internal port inside the container
Example: "3000:3000" maps container port 3000 to host port 3000.

Volume Mounts

The backend uses a volume for file uploads:
volumes:
  - ./backend/uploads:/app/uploads
This ensures uploaded files persist even if the container is recreated.

Volume Benefits

Files survive container restarts and rebuilds
Files are accessible both from the container and host filesystem
Simple to back up by copying the host directory

Networking

Services communicate through a bridge network:
networks:
  app-network:
    driver: bridge

Internal Communication

Services can reference each other by name:
// Frontend can call backend using container name
const response = await fetch('http://backend:3000/api/stats');

Deployment Scenarios

For local development with hot reload:
services:
  backend:
    build: ./backend
    volumes:
      - ./backend/src:/app/src
    environment:
      - NODE_ENV=development
    command: npm run start:dev

  frontend:
    build: ./frontend
    volumes:
      - ./frontend/src:/app/src
    command: npm run dev
    ports:
      - "5173:5173"
Run with:
docker-compose -f docker-compose.dev.yml up

Production Best Practices

1. Use Health Checks

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s

2. Set Resource Limits

deploy:
  resources:
    limits:
      cpus: '1'
      memory: 512M
    reservations:
      cpus: '0.5'
      memory: 256M

3. Enable Logging

logging:
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

4. Use Secrets for Sensitive Data

secrets:
  db_password:
    file: ./secrets/db_password.txt

services:
  backend:
    secrets:
      - db_password

5. Implement SSL/TLS

frontend:
  environment:
    - NGINX_SSL=true
  volumes:
    - ./ssl/cert.pem:/etc/nginx/ssl/cert.pem:ro
    - ./ssl/key.pem:/etc/nginx/ssl/key.pem:ro

Common Commands

Build and Start

# Build images and start containers
docker-compose up --build

# Start in detached mode
docker-compose up -d

# Rebuild specific service
docker-compose build backend

Management

# View logs
docker-compose logs -f

# View logs for specific service
docker-compose logs -f backend

# Stop containers
docker-compose down

# Stop and remove volumes
docker-compose down -v

# Restart a service
docker-compose restart backend

Debugging

# Execute command in running container
docker-compose exec backend sh

# View container stats
docker stats

# Inspect container
docker inspect nest-backend

Troubleshooting

Check logs:
docker-compose logs backend
Common issues:
  • Missing environment variables
  • Port already in use
  • Database connection failed
Clear build cache:
docker-compose build --no-cache backend
Check disk space:
docker system df
docker system prune
Recreate network:
docker-compose down
docker network prune
docker-compose up
Fix permissions:
sudo chown -R $USER:$USER ./backend/uploads
chmod -R 755 ./backend/uploads

Security Considerations

Environment Variables

Store secrets in .env files, never in docker-compose.yml

Non-Root User

Run containers as non-root user when possible

Network Isolation

Use internal networks for service-to-service communication

Image Updates

Regularly update base images for security patches

Build docs developers (and LLMs) love