Skip to main content
The midPilot Connector Generator provides a complete Docker setup with PostgreSQL database and automatic migrations. This guide covers containerized deployment.

Prerequisites

Docker

Docker Engine 20.10 or later

Docker Compose

Docker Compose V2 or later
Verify installation:
docker --version
docker compose version

Docker Architecture

The Docker setup includes two services:
1

PostgreSQL Database

Container: db
Image: postgres:15-alpine
Purpose: Data persistence and storage
Features:
  • Health checks for reliable startup
  • Persistent volume for data
  • Automatic initialization from .env
2

API Service

Container: api
Image: midpilot-connector-gen:latest
Purpose: FastAPI application server
Features:
  • Depends on healthy database
  • Includes Playwright for web scraping
  • Auto-runs migrations on startup

Quick Start

1

Configure environment

Create and configure your .env file:
cp .env-example .env
nano .env
Set at minimum:
DATABASE__NAME=connector_db
DATABASE__USER=connector_user
DATABASE__PASSWORD=secure_password_here
LLM__OPENAI_API_KEY=your-api-key
2

Build the image

docker compose build
This process:
  • Uses Python 3.13 base image
  • Installs dependencies with UV
  • Installs Playwright browsers
  • Creates optimized production image
3

Start the services

docker compose up
To run in detached mode:
docker compose up -d
4

Verify the services

# Check running containers
docker compose ps

# Check API health
curl http://localhost:8090/health

# View logs
docker compose logs -f

Docker Compose Configuration

The docker-compose.yaml defines the complete stack:
services:
  midpilot-connector-gen:
    build: .
    image: midpilot-connector-gen:latest
    container_name: api
    depends_on:
      db:
        condition: service_healthy
    env_file:
      - .env
    environment:
      LOGGING__LEVEL: info
      DATABASE__HOST: db
      DATABASE__PORT: 5432
      DATABASE__URL: postgresql+asyncpg://${DATABASE__USER}:${DATABASE__PASSWORD}@db:5432/${DATABASE__NAME}
    ports:
      - "${HOST_PORT:-8090}:8090"

  db:
    image: postgres:15-alpine
    container_name: db
    restart: unless-stopped
    env_file:
      - .env
    environment:
      POSTGRES_DB: ${DATABASE__NAME}
      POSTGRES_USER: ${DATABASE__USER}
      POSTGRES_PASSWORD: ${DATABASE__PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DATABASE__USER} -d ${DATABASE__NAME}"]
      interval: 5s
      timeout: 3s
      retries: 20
      start_period: 5s
    ports:
      - ${DATABASE__PORT}:${DATABASE__PORT}
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
    driver: local

Key Features

The database service includes health checks to ensure it’s ready before the API starts:
healthcheck:
  test: ["CMD-SHELL", "pg_isready -U ${DATABASE__USER} -d ${DATABASE__NAME}"]
  interval: 5s
  timeout: 3s
  retries: 20
  start_period: 5s
The API service depends on a healthy database:
depends_on:
  db:
    condition: service_healthy
Database data is persisted using Docker volumes:
volumes:
  - postgres_data:/var/lib/postgresql/data
Data survives container restarts and recreations.
Both services load from .env:
env_file:
  - .env
The API service overrides DATABASE__HOST to use the internal service name db.
Customize the exposed port:
# In .env
HOST_PORT=3000
Default is 8090.

Dockerfile Breakdown

The multi-stage Dockerfile optimizes the build:
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim

WORKDIR /app

# UV settings
ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy

# Install dependencies (cached layer)
RUN --mount=type=cache,target=/root/.cache/uv \
    --mount=type=bind,source=uv.lock,target=uv.lock \
    --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
    uv sync --locked --no-install-project --no-dev

# Copy project and install
COPY . /app
RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked --no-dev
ENV PATH="/app/.venv/bin:$PATH"

# Install Playwright browsers
RUN python -m playwright install --with-deps chromium

ENV PLAYWRIGHT_BROWSERS_PATH=/root/.cache/ms-playwright

EXPOSE 8090

CMD ["python", "server.py"]

Build Optimizations

Cache Mounts

UV cache is preserved between builds for faster rebuilds

Layer Ordering

Dependencies install before code copy for efficient caching

Bytecode Compilation

Python bytecode compiled during build for faster startup

No Dev Dependencies

Production image excludes development tools

Docker Commands

Common Operations

# Start in foreground
docker compose up

# Start in background
docker compose up -d

# Start and rebuild
docker compose up --build

Database Management

# Backup database
docker compose exec db pg_dump -U ${DATABASE__USER} ${DATABASE__NAME} > backup.sql

# Backup with compression
docker compose exec db pg_dump -U ${DATABASE__USER} ${DATABASE__NAME} | gzip > backup.sql.gz

Production Considerations

These recommendations apply when deploying to production environments.

Security

Use Secrets Management

Store sensitive values in Docker secrets or external secret managers

Restrict Network Access

Use Docker networks to isolate services

Non-Root User

Run containers as non-root user

Scan Images

Regularly scan images for vulnerabilities

Scaling

# docker-compose.prod.yaml
services:
  midpilot-connector-gen:
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '1'
          memory: 2G

Monitoring

services:
  midpilot-connector-gen:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8090/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

Troubleshooting

Symptom: API can’t connect to databaseSolution:
# Check database health
docker compose ps

# View database logs
docker compose logs db

# Verify environment variables
docker compose exec midpilot-connector-gen env | grep DATABASE
Ensure DATABASE__HOST=db in the API service environment.
Symptom: Error: bind: address already in useSolution:
# Change port in .env
HOST_PORT=8091

# Or stop conflicting service
lsof -i :8090
kill <PID>
Symptom: Build errors or timeoutSolution:
# Clean build cache
docker compose build --no-cache

# Prune Docker system
docker system prune -a

# Check disk space
df -h
Symptom: Container exits immediatelySolution:
# View recent logs
docker compose logs --tail=50 midpilot-connector-gen

# Check for missing environment variables
docker compose config

# Run migrations manually
docker compose exec midpilot-connector-gen uv run alembic upgrade head

Next Steps

Database Setup

Learn about migrations and database management

API Reference

Explore available endpoints

Build docs developers (and LLMs) love