From 8c0e9b193107735b14c04a2b700c00b422307d3f Mon Sep 17 00:00:00 2001 From: "Ishaan (OpenClaw)" Date: Fri, 6 Feb 2026 20:02:48 +0000 Subject: [PATCH] Add Dockerfiles and compose quickstart --- .env.example | 23 ++++++++++++++++ backend/Dockerfile | 44 +++++++++++++++++++++++++++++ compose.yml | 67 +++++++++++++++++++++++++++++++++++++++++++++ frontend/Dockerfile | 38 +++++++++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 .env.example create mode 100644 backend/Dockerfile create mode 100644 compose.yml create mode 100644 frontend/Dockerfile diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..d24078a9 --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# Root compose defaults (safe for local self-host / dev) +# Copy to .env to override. + +# --- app ports (host) --- +FRONTEND_PORT=3000 +BACKEND_PORT=8000 + +# --- database --- +POSTGRES_DB=openclaw_agency +POSTGRES_USER=postgres +POSTGRES_PASSWORD=postgres +POSTGRES_PORT=5432 + +# --- redis --- +REDIS_PORT=6379 + +# --- backend settings (see backend/.env.example for full list) --- +CORS_ORIGINS=http://localhost:3000 +DB_AUTO_MIGRATE=true + +# --- frontend settings --- +# Public URL used by the browser to reach the API +NEXT_PUBLIC_API_URL=http://localhost:8000 diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 00000000..df5a5870 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,44 @@ +# syntax=docker/dockerfile:1 + +FROM python:3.12-slim AS base + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +WORKDIR /app + +# System deps (keep minimal) +RUN apt-get update \ + && apt-get install -y --no-install-recommends curl ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Install uv (https://github.com/astral-sh/uv) +RUN curl -LsSf https://astral.sh/uv/install.sh | sh +ENV PATH="/root/.local/bin:${PATH}" + +# --- deps layer --- +FROM base AS deps + +# Copy only dependency metadata first for better build caching +COPY pyproject.toml uv.lock ./ + +# Create venv and sync deps (including runtime) +RUN uv sync --frozen --no-dev + +# --- runtime --- +FROM base AS runtime + +# Copy virtual environment from deps stage +COPY --from=deps /app/.venv /app/.venv +ENV PATH="/app/.venv/bin:${PATH}" + +# Copy app source +COPY alembic ./alembic +COPY alembic.ini ./alembic.ini +COPY app ./app + +# Default API port +EXPOSE 8000 + +# Run the API +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/compose.yml b/compose.yml new file mode 100644 index 00000000..f6a43a9a --- /dev/null +++ b/compose.yml @@ -0,0 +1,67 @@ +name: openclaw-mission-control + +services: + db: + image: postgres:16-alpine + environment: + POSTGRES_DB: ${POSTGRES_DB:-openclaw_agency} + POSTGRES_USER: ${POSTGRES_USER:-postgres} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres} + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "${POSTGRES_PORT:-5432}:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 5s + timeout: 3s + retries: 20 + + redis: + image: redis:7-alpine + volumes: + - redis_data:/data + ports: + - "${REDIS_PORT:-6379}:6379" + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 5s + timeout: 3s + retries: 20 + + backend: + build: + context: ./backend + env_file: + - ./backend/.env.example + environment: + # Override localhost defaults for container networking + DATABASE_URL: postgresql+psycopg://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-openclaw_agency} + REDIS_URL: redis://redis:6379/0 + CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000} + DB_AUTO_MIGRATE: ${DB_AUTO_MIGRATE:-true} + depends_on: + db: + condition: service_healthy + redis: + condition: service_healthy + ports: + - "${BACKEND_PORT:-8000}:8000" + + frontend: + build: + context: ./frontend + args: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000} + env_file: + - ./frontend/.env.example + environment: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8000} + depends_on: + - backend + ports: + - "${FRONTEND_PORT:-3000}:3000" + +volumes: + postgres_data: + redis_data: diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 00000000..4a87dcd6 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,38 @@ +# syntax=docker/dockerfile:1 + +FROM node:20-alpine AS deps +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci + +FROM node:20-alpine AS builder +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . ./ + +# Allows configuring the API URL at build time. +ARG NEXT_PUBLIC_API_URL=http://localhost:8000 +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} + +RUN npm run build + +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production + +# If provided at runtime, Next will expose NEXT_PUBLIC_* to the browser as well +# (but note some values may be baked at build time). +ENV NEXT_PUBLIC_API_URL=http://localhost:8000 + +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder /app/package.json ./package.json +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/next.config.ts ./next.config.ts + +EXPOSE 3000 + +CMD ["npm", "run", "start"]