--- title: The compose.yml file description: The Docker Compose file is used to start the required services. --- ## The initial compose file The first step is to create a Docker Compose file. We will call it `compose.yml`. ```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/usekaneo/kaneo: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 Kaneo 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: ```env 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 Kaneo uses S3-compatible object storage for private uploads in task descriptions and comments. - Object storage is optional. Kaneo 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 Kaneo API creates presigned upload URLs and the browser uploads files directly to the configured storage backend. - Kaneo 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](/core/installation/storage-backends). ### Optional MinIO service Add this service and volume to your `compose.yml` only if you want uploads: ```yml 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](/core/installation/environment-variables). ### Example `.env` values for MinIO ```env 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`](https://github.com/ferdzo/fs), you can point the same `S3_*` variables at its endpoint instead of MinIO. Kaneo 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 `fs` does not currently implement S3 CORS APIs. After creating the compose file, the next step is to set up the environment variables.