Skip to main content

Overview

Docker provides a containerized deployment of PhotoFlow that includes:
  • PostgreSQL database - Isolated database container
  • PhotoFlow application - Production-optimized build
  • Persistent storage - Data persists across container restarts
  • Automated setup - Database migrations run automatically
Docker deployment is recommended for production use as it provides consistency, isolation, and easy updates.

Prerequisites

Before deploying with Docker:

Docker Engine

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
sudo usermod -aG docker $USER

# Log out and back in for group changes to take effect

Verify Installation

docker --version
docker compose version

Understanding the Dockerfile

PhotoFlow uses a multi-stage build for optimization:
Dockerfile
FROM node:20-bookworm AS base

# Stage 1: Install dependencies
FROM base AS deps
WORKDIR /app

COPY package.json package-lock.json* ./
RUN npm ci

COPY prisma ./prisma/
RUN npx prisma generate

# Stage 2: Build application
FROM base AS builder
WORKDIR /app

COPY --from=deps /app/node_modules ./node_modules
COPY --from=deps /app/prisma ./prisma
COPY . .

RUN npm run build

# Stage 3: Production runtime
FROM base AS runner
WORKDIR /app

ENV NODE_ENV=production

COPY --from=builder /app/build ./build
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json
COPY --from=builder /app/prisma ./prisma
COPY --from=builder /app/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh

EXPOSE 3000

ENV PORT=3000

ENTRYPOINT ["/docker-entrypoint.sh"]
Benefits of multi-stage build:
  • Smaller final image (only runtime dependencies)
  • Faster deployments
  • Better security (no build tools in production)
  • Cached layers speed up rebuilds

Docker Compose Configuration

The docker-compose.yml defines the complete stack:
docker-compose.yml
services:
  postgres:
    image: postgres:15-alpine
    container_name: photoflow_postgres
    environment:
      POSTGRES_USER: photoflow
      POSTGRES_PASSWORD: photoflow_password
      POSTGRES_DB: photoflow
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U photoflow -d photoflow"]
      interval: 5s
      timeout: 5s
      retries: 5

  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: photoflow_app
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://photoflow:photoflow_password@postgres:5432/photoflow
      - NODE_ENV=production
      - VITE_SOCKET_URL=http://localhost:3000
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

volumes:
  postgres_data:
Key features:
  • Health checks ensure database is ready before app starts
  • Named volumes persist data across restarts
  • Service dependencies manage startup order
  • Restart policy keeps services running

Deployment Steps

1

Clone Repository

Get the PhotoFlow source code:
git clone https://github.com/DomenicWalther/PhotoFlow.git
cd PhotoFlow
2

Configure Environment (Optional)

For custom configuration, create a .env file:
.env
POSTGRES_USER=photoflow
POSTGRES_PASSWORD=your_secure_password_here
POSTGRES_DB=photoflow
VITE_SOCKET_URL=http://your-server-ip:3000
Change the default password in production!
3

Build and Start Containers

Launch PhotoFlow with Docker Compose:
docker compose up -d
This command:
  • Pulls the PostgreSQL image
  • Builds the PhotoFlow image
  • Creates containers
  • Starts services in detached mode
First build may take several minutes as it installs dependencies and builds the application.
4

Verify Deployment

Check that containers are running:
docker compose ps
You should see:
NAME                  STATUS
photoflow_app         Up
photoflow_postgres    Up (healthy)
5

Access PhotoFlow

Open your browser and navigate to:
http://localhost:3000
From other PCs on your network:
http://[server-ip]:3000

The Entrypoint Script

The docker-entrypoint.sh script handles startup tasks:
docker-entrypoint.sh
#!/bin/bash
set -e

echo "Generating Prisma client..."
npx prisma generate

echo "Running database migrations..."
npx prisma migrate deploy

echo "Starting the application..."
exec node build
What it does:
  1. Generates Prisma client - Creates the database client
  2. Runs migrations - Updates database schema (production-safe)
  3. Starts the app - Launches the Node.js server
prisma migrate deploy only applies already-created migration files. It won’t generate new migrations, making it safe for production.

Managing the Deployment

View Logs

Monitor application logs:
# All services
docker compose logs -f

# Just the app
docker compose logs -f app

# Just the database
docker compose logs -f postgres

# Last 100 lines
docker compose logs --tail=100 app

Restart Services

# Restart all services
docker compose restart

# Restart specific service
docker compose restart app

Stop Services

# Stop containers (keeps data)
docker compose stop

# Stop and remove containers (keeps data in volumes)
docker compose down

# Stop, remove containers, and delete volumes (DELETES DATA!)
docker compose down -v

Update PhotoFlow

To update to the latest version:
# Pull latest code
git pull origin main

# Rebuild and restart
docker compose up -d --build
This will rebuild the container. Database data persists in the named volume.

Database Management

Access Database Shell

Connect to PostgreSQL:
docker compose exec postgres psql -U photoflow -d photoflow

Backup Database

Create a backup:
# Create backup file
docker compose exec postgres pg_dump -U photoflow photoflow > backup_$(date +%Y%m%d).sql

# Or with compression
docker compose exec postgres pg_dump -U photoflow photoflow | gzip > backup_$(date +%Y%m%d).sql.gz

Restore Database

Restore from backup:
# From SQL file
docker compose exec -T postgres psql -U photoflow photoflow < backup_20260301.sql

# From compressed file
gunzip -c backup_20260301.sql.gz | docker compose exec -T postgres psql -U photoflow photoflow

View Database Files

Inspect the volume:
docker volume inspect photoflow_postgres_data

Network Configuration

Expose to Local Network

By default, PhotoFlow is accessible at http://localhost:3000. To allow other PCs on your network to connect:
  1. Find your server’s IP address:
# Linux/macOS
ip addr show  # or ifconfig

# Windows
ipconfig
  1. Update VITE_SOCKET_URL in docker-compose.yml:
environment:
  - VITE_SOCKET_URL=http://192.168.1.100:3000  # Use your server IP
  1. Restart containers:
docker compose up -d
  1. Configure firewall to allow port 3000:
# Linux (ufw)
sudo ufw allow 3000/tcp

# Linux (firewalld)
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload

Use Different Ports

To change the exposed port, edit docker-compose.yml:
app:
  ports:
    - "8080:3000"  # Host:Container
Access at http://localhost:8080

Production Considerations

Security

  • Change default passwords
  • Use strong database credentials
  • Enable HTTPS with a reverse proxy
  • Restrict network access

Performance

  • Monitor resource usage
  • Set container resource limits
  • Use SSD storage for database
  • Regular database maintenance

Backups

  • Schedule automated backups
  • Test restore procedures
  • Store backups off-server
  • Keep multiple backup versions

Monitoring

  • Monitor container health
  • Track application logs
  • Set up alerts for failures
  • Monitor disk space
See the Production Checklist for detailed recommendations.

Resource Limits

Set resource limits to prevent containers from consuming excessive resources:
docker-compose.yml
services:
  postgres:
    # ... other config ...
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
        reservations:
          cpus: '0.5'
          memory: 512M

  app:
    # ... other config ...
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 2G
        reservations:
          cpus: '1'
          memory: 1G

Troubleshooting

Check logs for errors:
docker compose logs app
Common issues:
  • Port already in use: Change port in docker-compose.yml
  • Build errors: Check Dockerfile syntax
  • Missing files: Ensure all files are in build context
Verify database is healthy:
docker compose ps
Check database logs:
docker compose logs postgres
Ensure DATABASE_URL matches PostgreSQL credentials.
  1. Verify firewall allows port 3000
  2. Check VITE_SOCKET_URL uses server’s IP, not localhost
  3. Ensure both PCs are on same network
  4. Test connectivity: curl http://[server-ip]:3000
Ensure you’re not using docker compose down -v which deletes volumes.Check volumes exist:
docker volume ls | grep photoflow
If volumes were deleted, restore from backup.
Clean up unused Docker resources:
docker system prune -a
docker volume prune  # Be careful! Only if you have backups
Check migration history:
docker compose exec app npx prisma migrate status
Reset if needed (WARNING: deletes data):
docker compose down -v
docker compose up -d

Next Steps

Coolify Deployment

Deploy with Coolify for easier management

Production Checklist

Ensure your deployment is production-ready

Network Setup

Configure multi-PC network access

Environment Variables

Learn about all configuration options

Build docs developers (and LLMs) love