> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kvelden.com/llms.txt
> Use this file to discover all available pages before exploring further.

# MinIO

> Connect a self-hosted MinIO instance as a Bring Your Own Storage backend. MinIO is fully S3-compatible and supports Enclave's presigned upload pipeline.

## Overview

[MinIO](https://min.io) is a high-performance, self-hosted object storage server compatible with the AWS S3 API. Enclave treats MinIO identically to AWS S3 under the hood — the only differences are the custom endpoint URL and the requirement to enable **Force path-style** access.

<Info>
  Enclave automatically configures CORS on your MinIO bucket during the first connection test, so presigned browser uploads work without any manual CORS setup on your side.
</Info>

***

## Prerequisites

Before adding MinIO as a BYOS backend, ensure:

* **Enclave**: Owner role + Enterprise Advanced plan (BYOS required)
* **MinIO**: A running MinIO instance (single-node or distributed) reachable from the Enclave server **and** from user browsers (presigned URLs point to the same endpoint)
* **Port**: MinIO's S3-compatible API runs on port **9000** by default. Port **9001** is the web console — do not use it as the endpoint
* **TLS** *(recommended for production)*: If MinIO is behind a reverse proxy with TLS, use an `https://` endpoint. Self-signed certificates require additional CA trust configuration on the Enclave server
* **Bucket**: An existing MinIO bucket to store Enclave files
* **Access Key**: A MinIO access key and secret key with read/write permissions on the bucket

***

## Step 1 — Prepare MinIO

### Create a bucket

Open the MinIO console at `http://YOUR_MINIO_HOST:9001`, log in as admin, and:

1. Go to **Buckets** → **Create Bucket**
2. Enter a bucket name (e.g. `enclave-storage`)
3. Click **Create Bucket**

<Note>
  Bucket names in MinIO follow DNS naming rules: lowercase letters, numbers, and hyphens only. No underscores.
</Note>

### Create an access key

1. Go to **Access Keys** → **Create Access Key**
2. MinIO will generate an Access Key ID and Secret Key — copy both immediately, the secret is shown only once
3. Optionally restrict the access key with a policy. The minimum required permissions are:

```json theme={null}
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "s3:GetObject",
      "s3:PutObject",
      "s3:DeleteObject",
      "s3:ListBucket",
      "s3:GetBucketLocation",
      "s3:HeadBucket"
    ],
    "Resource": [
      "arn:aws:s3:::YOUR_BUCKET_NAME",
      "arn:aws:s3:::YOUR_BUCKET_NAME/*"
    ]
  }]
}
```

***

## Step 2 — Add MinIO in Enclave

Navigate to **Organization → Storage**, click **Add Storage Backend**, and fill in the form:

### Storage Provider

Select the **MinIO** card from the provider grid. Force path-style access is enabled automatically for MinIO — no toggle needed.

### Core fields

| Field        | Value                                                                      |
| ------------ | -------------------------------------------------------------------------- |
| Bucket Name  | The bucket you created in Step 1 (e.g. `enclave-storage`)                  |
| Region       | Enter `us-east-1` — MinIO ignores this field but the form requires a value |
| Endpoint URL | Your MinIO S3 API URL, e.g. `http://192.168.1.100:9000`                    |

<Warning>
  **Port matters.** Use port `9000` (the S3 API), not port `9001` (the MinIO web console). Using `9001` will result in a connection failure.
</Warning>

<Warning>
  **Presigned URL reachability.** The endpoint URL you enter is embedded directly into presigned upload URLs that are sent to users' browsers. The URL must be reachable both from the Enclave backend server (for connection tests and server-mediated operations) and from user browsers (for direct presigned uploads). If users are on a VPN or internal network, use the internal IP. If users access over the internet, use a publicly accessible hostname.
</Warning>

### Credentials

| Field      | Value                         |
| ---------- | ----------------------------- |
| Access Key | The access key ID from Step 1 |
| Secret Key | The secret key from Step 1    |

### Storage name (optional)

Leave blank to use the auto-generated name **MinIO Storage**, or enter a custom name to identify this backend.

***

## Step 3 — Test the connection

Click **Test Connection**. Enclave will:

1. Connect to your MinIO endpoint using the provided credentials
2. Run a `HeadBucket` check to verify bucket access
3. Automatically configure CORS on the bucket to allow presigned browser uploads (PUT method from any origin)

A green "Connection verified" message confirms everything is working.

<Tip>
  If the test fails, see the [Troubleshooting](#troubleshooting) section below before clicking Save.
</Tip>

***

## Step 4 — Save the backend

Click **Save Storage**. The backend is saved in **inactive** state — no files are routed to it yet.

***

## Step 5 — Activate the backend

Return to **Organization → Storage**. Your new MinIO backend appears in the **Your Storage Backends** table with status **Inactive**.

To start routing uploads to MinIO:

1. Click the **⋯** menu on the MinIO backend row
2. Click **Activate**

Enclave atomically deactivates any previously active backend for the same scope and activates this one.

***

## Step 6 — Assign to a scope

Activating the backend makes it eligible for use, but you still need to assign it to an org unit scope to control which part of your organisation uses it.

Navigate to **Security → Policies → Storage** and assign the MinIO backend to the desired scope (tenant-wide, domain, or department). Files in the assigned scope will be stored in MinIO from the next upload onwards.

***

## CORS

Enclave calls `PutBucketCors` on your bucket automatically when you first test the connection. The CORS configuration applied is:

```json theme={null}
{
  "CORSRules": [{
    "AllowedMethods": ["PUT"],
    "AllowedOrigins": ["*"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"]
  }]
}
```

This is required for presigned browser uploads. If your MinIO instance is locked down and does not allow `PutBucketCors`, presigned uploads will fail with a CORS error in the browser. In that case, configure the CORS rule manually in the MinIO console under **Buckets → YOUR\_BUCKET → Summary → CORS**.

***

## Network requirements

| Direction              | What needs to be reachable                |
| ---------------------- | ----------------------------------------- |
| Enclave server → MinIO | Port `9000` for all backend S3 operations |
| User browsers → MinIO  | Port `9000` for presigned `PUT` uploads   |

If MinIO is on a private network and users access Enclave from outside that network, the MinIO endpoint will not be reachable from browsers. In this case, either:

* Place MinIO behind a reverse proxy (nginx, Caddy, Traefik) with a publicly accessible hostname and TLS
* Use the Enclave server as a proxy (server-mediated uploads) — not currently supported for BYOS presigned paths

***

## Troubleshooting

| Symptom                                 | Likely cause                                                                                                                        |
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `Connection refused` on port 9001       | Wrong port — use port `9000` not `9001`                                                                                             |
| `Access Denied`                         | Access key does not have the required permissions, or the bucket name is wrong                                                      |
| `InvalidAccessKeyId`                    | Access key ID was copied incorrectly or has been deleted in MinIO                                                                   |
| `NoSuchBucket`                          | Bucket name is wrong. Bucket names are case-sensitive in MinIO                                                                      |
| `Path-style requests are not supported` | Force path-style is not enabled. Re-add the backend by selecting the **MinIO** card (force path-style is applied automatically)     |
| Browser upload fails with CORS error    | CORS was not applied (MinIO policy may be blocking `PutBucketCors`). Configure CORS manually in the MinIO console                   |
| Presigned URLs fail from browser        | MinIO endpoint is not reachable from the user's browser. Check network/VPN/firewall rules for port 9000                             |
| TLS certificate error                   | MinIO is using a self-signed certificate that the Enclave server does not trust. Add the CA certificate to the server's trust store |

***

## Example: local VM setup (VMware / VirtualBox)

If MinIO is running on an Ubuntu VM on your workstation:

1. Find the VM's IP: run `ip a` inside the VM — note the IP on the bridged adapter (e.g. `192.168.1.150`)
2. MinIO S3 API endpoint: `http://192.168.1.150:9000`
3. Ensure the VM's firewall allows inbound TCP on port 9000: `sudo ufw allow 9000/tcp`
4. Both the Enclave server (running on your host or another machine) and your browser must be able to reach `192.168.1.150:9000`

For a quick test, use VMware's **bridged networking** mode so the VM gets its own IP on your LAN, visible to all devices on the network.
