Skip to main content

Overview

Kaneo uses S3-compatible object storage for uploads in:
  • task descriptions
  • task comments
The browser uploads directly to the configured storage backend using presigned URLs. Kaneo then serves uploaded assets back through its own API. Current behavior:
  • images render inline
  • non-image files such as CSV, PDF, and ZIP render as attachment cards/links
  • assets are private by default
That means one rule matters for every backend:
  • S3_ENDPOINT must be reachable by the browser
Do not use a Docker-internal hostname such as http://minio:9000 for a public deployment unless the browser can actually reach it.

Required Kaneo variables

Notes:
  • S3_FORCE_PATH_STYLE=true is usually needed for MinIO.
  • S3_FORCE_PATH_STYLE=false is usually correct for AWS S3 and R2.
  • S3_PUBLIC_BASE_URL is optional and not required for the current private asset flow.

MinIO

MinIO is the recommended self-hosted option.

Local Docker setup

For local development, this is fine:
This works when Kaneo and MinIO are on the same Docker network and your browser reaches MinIO through localhost.

Public deployment

For a public deployment, expose MinIO on its own hostname through your reverse proxy. Example:
  • Kaneo: https://cloud.kaneo.app
  • MinIO: https://files.cloud.kaneo.app
This can be done with Caddy, Nginx, Traefik, or any other reverse proxy. Then use:
You also need:
  • a created bucket
  • a dedicated, non-root MinIO user with access limited to that bucket
  • MinIO CORS allowing your Kaneo origin
  • no anonymous bucket read policy is required
Never expose MinIO with its default minioadmin root credentials. Generate unique credentials for every deployment and keep the MinIO Console private.

AWS S3

AWS S3 is the simplest managed option. Use a bucket and an IAM user with access to that bucket. Example:
For another AWS region, adjust:
  • S3_ENDPOINT

Using an IAM role instead of an access key

If Kaneo runs on AWS (EC2, ECS, or EKS), you can omit S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY entirely and let Kaneo authenticate with the instance’s IAM role. Leave both unset and the AWS SDK resolves credentials from its default provider chain (instance profile, ECS task role, or EKS IRSA).
Set both keys or neither: configuring only one is rejected. The role must allow s3:PutObject, s3:GetObject, and s3:DeleteObject on the bucket. Recommended S3 CORS policy:

Cloudflare R2

R2 works well because it exposes an S3-compatible API. Use your account endpoint, bucket, and R2 access keys. Example:
Notes:
  • S3_REGION=auto is typical for R2
  • a public bucket is not required for Kaneo’s current private asset flow

One copy-paste self-hosted example

This example gives you Kaneo + MinIO in one Compose file.
Matching .env:
Before testing uploads:
  1. Create the kaneo-uploads bucket.
  2. Configure MinIO CORS for your Kaneo origin.
  3. Make sure files.cloud.kaneo.app resolves publicly.

Troubleshooting

If uploads fail:
  • check that the bucket exists
  • check that S3_ENDPOINT is public and browser-reachable
  • check CORS on your storage backend
  • check that the access key can PutObject and GetObject