Skip to content

Latest commit

 

History

History
200 lines (159 loc) · 6.22 KB

File metadata and controls

200 lines (159 loc) · 6.22 KB

Self-hosting

Docker Compose setup for self-hosting Planka + the MCP server.

Already running Planka? You only need the mcp-server service — drop everything else from the compose and point PLANKA_URL at your existing instance.

Planka docs: docs.planka.cloud — configuration, upgrades, backup, etc.

Prerequisites

  • Docker + Docker Compose v2

Files to create

Create these two files in the same directory and run docker compose up -d.

docker-compose.yml

services:
  planka:
    image: ghcr.io/plankanban/planka:2.0.1
    restart: unless-stopped
    ports:
      - "1337:1337"
    volumes:
      - ./data/planka-data:/app/data
    environment:
      - BASE_URL=${PLANKA_BASE_URL}
      - DATABASE_URL=postgresql://${POSTGRES_USER}@postgres:5432/${POSTGRES_PLANKA_DB}
      - SECRET_KEY=${PLANKA_SECRET_KEY}
      - DEFAULT_ADMIN_EMAIL=${PLANKA_ADMIN_EMAIL}
      - DEFAULT_ADMIN_PASSWORD=${PLANKA_ADMIN_PASSWORD}
      - DEFAULT_ADMIN_NAME=${PLANKA_ADMIN_NAME}
      - DEFAULT_ADMIN_USERNAME=${PLANKA_ADMIN_USERNAME}
      - S3_ENDPOINT=http://minio:9000
      - S3_REGION=${MINIO_REGION}
      - S3_ACCESS_KEY_ID=${MINIO_ROOT_USER}
      - S3_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
      - S3_BUCKET=${MINIO_BUCKET}
      - S3_FORCE_PATH_STYLE=true
    depends_on:
      postgres:
        condition: service_healthy
      minio:
        condition: service_started

  mcp-server:
    image: ghcr.io/ashkuc/charlieplan-mcp/mcp-server:${MCP_IMAGE_TAG}
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://${POSTGRES_USER}@postgres:5432/${POSTGRES_MCP_DB}
      - PLANKA_URL=http://planka:1337
      - SERVER_URL=${MCP_SERVER_URL}
      - CODE_SECRET=${MCP_CODE_SECRET}
    depends_on:
      postgres:
        condition: service_healthy
      planka:
        condition: service_started

  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    volumes:
      - ./data/postgres-data:/var/lib/postgresql/data
      - ./postgres-init:/docker-entrypoint-initdb.d
    environment:
      - POSTGRES_DB=${POSTGRES_PLANKA_DB}
      - POSTGRES_HOST_AUTH_METHOD=trust
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_PLANKA_DB}"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 10s

  minio:
    image: minio/minio:latest
    restart: unless-stopped
    command: server /data --console-address ":9001"
    environment:
      - MINIO_ROOT_USER=${MINIO_ROOT_USER}
      - MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
    volumes:
      - ./data/minio-data:/data
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 30s
      timeout: 5s
      retries: 5
      start_period: 10s

postgres-init/create_mcp_database.sql

-- Creates the charlieplan database for the MCP server.
-- The planka database is created automatically via POSTGRES_DB env var.
CREATE DATABASE "charlieplan";
GRANT ALL PRIVILEGES ON DATABASE "charlieplan" TO postgres;

.env

# ── MCP Server ────────────────────────────────────────────────────────────────
# Image tag to deploy. Find available tags in the GitHub Container Registry.
MCP_IMAGE_TAG=latest

# ── Planka ────────────────────────────────────────────────────────────────────
# Public base URL of the Planka instance (no trailing slash)
PLANKA_BASE_URL=https://planka.example.com

# Encryption key — generate: openssl rand -hex 64
PLANKA_SECRET_KEY=

# Default admin account, created on first run
PLANKA_ADMIN_EMAIL=admin@example.com
PLANKA_ADMIN_PASSWORD=
PLANKA_ADMIN_NAME=Admin
PLANKA_ADMIN_USERNAME=admin

# ── MinIO ─────────────────────────────────────────────────────────────────────
MINIO_ROOT_USER=minioadmin
# Generate: openssl rand -hex 16
MINIO_ROOT_PASSWORD=
MINIO_BUCKET=planka
MINIO_REGION=us-east-1

# ── MCP Server ────────────────────────────────────────────────────────────────
# Public URL of the MCP server (no trailing slash). Required for OAuth.
MCP_SERVER_URL=https://charlieplan-mcp.example.com

# OAuth authorization code signing key — generate: openssl rand -hex 32
MCP_CODE_SECRET=

# ── PostgreSQL ────────────────────────────────────────────────────────────────
POSTGRES_USER=postgres
POSTGRES_PLANKA_DB=planka
POSTGRES_MCP_DB=charlieplan

First-time setup

1. Fill in .env

At minimum set PLANKA_BASE_URL and MCP_SERVER_URL to your public URLs, then generate secrets:

openssl rand -hex 64   # PLANKA_SECRET_KEY
openssl rand -hex 32   # MCP_CODE_SECRET
openssl rand -hex 16   # MINIO_ROOT_PASSWORD

2. Start services

docker compose up -d

Postgres runs the init script on first start — creates both planka and charlieplan databases. The MCP server runs Drizzle migrations automatically on startup.

3. Verify

curl http://localhost:3000/health
# → {"ok":true}

4. Create a Planka API key

Log in to Planka → Profile → API Keys → create a key. This is what MCP clients pass as a Bearer token.

Tip: create a dedicated non-admin user for MCP usage and generate the key from that account.

5. Connect an MCP client

Point your client at http://host:3000/mcp and authenticate via the OAuth flow with the API key.

Upgrading

# Update MCP_IMAGE_TAG in .env, then:
docker compose pull mcp-server
docker compose up -d mcp-server

Data

All persistent data is in ./data/. Back up this directory.

Path Contents
./data/planka-data Planka uploads
./data/postgres-data PostgreSQL data
./data/minio-data MinIO object storage