The compose.yml file
The initial compose file
The first step is to create a Docker Compose file. We will call it compose.yml.
services:
postgres:
image: postgres:16-alpine
env_file:
- .env
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kaneo -d kaneo"]
interval: 10s
timeout: 5s
retries: 5
kaneo:
image: ghcr.io/grootbro/workboard:latest
ports:
- "5173:5173"
env_file:
- .env
depends_on:
postgres:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5173/api/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 60s
volumes:
postgres_data:
The services and volumes
Workboard uses the following services:
postgres: The PostgreSQL database.kaneo: The combined API and web container.
Additionally, the following volumes are used:
postgres_data: The PostgreSQL data.
Required URL configuration
Copy .env.sample to .env and uncomment or set these values:
KANEO_CLIENT_URL=http://localhost:5173
POSTGRES_DB=kaneo
POSTGRES_USER=kaneo
POSTGRES_PASSWORD=changeme
AUTH_SECRET= # generate: openssl rand -hex 32
KANEO_API_URL defaults to KANEO_CLIENT_URL/api; set it explicitly only if you need to override the default (e.g. a reverse proxy changes the path).
This keeps the browser on one origin while the container proxies /api requests to the internal API process.
For this Compose setup, the bundled Kaneo container reaches PostgreSQL at the service hostname postgres.
If you run the API directly on your host instead, use localhost or set DATABASE_URL explicitly.
Notes on object storage
Workboard uses S3-compatible object storage for private uploads in task descriptions and comments.
- Object storage is optional. Workboard runs without it, but uploads in task descriptions and comments will be unavailable.
- For local/self-hosted setups, MinIO is the recommended option when you want uploads.
- The Workboard API creates presigned upload URLs and the browser uploads files directly to the configured storage backend.
- Workboard serves uploaded assets back through its own API, so the bucket does not need to be public.
- If you do not configure object storage, leave the
S3_*variables unset. - For a complete MinIO example and backend-specific setup notes, see the storage backends guide.
Optional MinIO service
Add this service and volume to your compose.yml only if you want uploads:
services:
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
env_file:
- .env
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio_data:/data
restart: unless-stopped
volumes:
minio_data:
Set the matching S3_* environment variables in your .env file. See the environment variables page.
Example .env values for MinIO
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
S3_ENDPOINT=http://minio:9000
S3_BUCKET=kaneo-uploads
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_REGION=us-east-1
S3_FORCE_PATH_STYLE=true
Create the bucket before testing uploads. With MinIO, you can do that from the MinIO Console at http://localhost:9001.
Using fs instead of MinIO
If you want to use fs, you can point the same S3_* variables at its endpoint instead of MinIO. Workboard only needs an S3-compatible API endpoint, credentials, and a bucket.
When using fs, keep these differences in mind:
- Set
S3_FORCE_PATH_STYLE=true. - Create buckets through the S3 API or CLI, not through a web console.
- Browser uploads may require reverse-proxy CORS handling, because
fsdoes not currently implement S3 CORS APIs.
After creating the compose file, the next step is to set up the environment variables.