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

# S3 Storage Configuration

> Configure S3-compatible storage for file uploads and downloads

## Overview

Azalt supports file storage via:

* **AWS S3** (default)
* **S3-compatible services** (MinIO, private cloud S3, etc.)

File storage is optional. If not configured, file upload features will be disabled.

## Environment Variables

### Required for File Storage

| Variable               | Description                                         |
| ---------------------- | --------------------------------------------------- |
| `S3_BUCKET_NAME`       | The S3 bucket name                                  |
| `S3_ACCESS_KEY_ID`     | AWS access key or S3-compatible service credentials |
| `S3_SECRET_ACCESS_KEY` | AWS secret key or S3-compatible service credentials |

### Optional Configuration

| Variable              | Default        | Description                                             |
| --------------------- | -------------- | ------------------------------------------------------- |
| `S3_REGION`           | `eu-central-1` | AWS region or S3-compatible service region              |
| `S3_ENDPOINT`         | *(none)*       | Custom endpoint URL for S3-compatible services          |
| `S3_PUBLIC_ENDPOINT`  | *(none)*       | Browser-accessible URL for presigned URLs               |
| `S3_FORCE_PATH_STYLE` | `false`        | Set to `true` for MinIO and most S3-compatible services |

## Configuration Scenarios

### AWS S3 (Standard)

For standard AWS S3, only the basic credentials are needed:

```bash theme={null}
S3_BUCKET_NAME=my-bucket
S3_ACCESS_KEY_ID=AKIA...
S3_SECRET_ACCESS_KEY=...
S3_REGION=eu-central-1
```

The AWS SDK automatically uses public AWS endpoints. No `S3_ENDPOINT` or `S3_PUBLIC_ENDPOINT` needed.

### MinIO (Browser-Accessible)

If your MinIO instance is directly accessible from browsers (e.g., exposed via public IP or domain):

```bash theme={null}
S3_BUCKET_NAME=azalt
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_ENDPOINT=https://minio.example.com
S3_FORCE_PATH_STYLE=true
```

No `S3_PUBLIC_ENDPOINT` needed since `S3_ENDPOINT` is browser-accessible.

### MinIO (Docker/Kubernetes Internal)

If MinIO is only accessible internally (e.g., Docker network or Kubernetes cluster):

```bash theme={null}
S3_BUCKET_NAME=azalt
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_ENDPOINT=http://minio:9000                    # Internal URL for server operations
S3_PUBLIC_ENDPOINT=https://example.com/s3        # External URL for browser access
S3_FORCE_PATH_STYLE=true
```

### Private Cloud S3

For internal S3-compatible storage in private clouds (e.g., bank infrastructure):

```bash theme={null}
S3_BUCKET_NAME=azalt
S3_ACCESS_KEY_ID=...
S3_SECRET_ACCESS_KEY=...
S3_ENDPOINT=https://s3.internal.bank.com         # Internal S3 endpoint
S3_PUBLIC_ENDPOINT=https://s3.external.bank.com  # Browser-accessible endpoint (if different)
S3_FORCE_PATH_STYLE=true                         # Usually required for S3-compatible services
```

If your internal S3 endpoint is accessible from browsers (e.g., users are on VPN), you can omit `S3_PUBLIC_ENDPOINT`.

## How Presigned URLs Work

When a user uploads or downloads a file, Azalt generates a presigned URL that the browser uses directly.

### Endpoint Resolution Order

For presigned URLs (browser file access):

1. `S3_PUBLIC_ENDPOINT` if set
2. `S3_ENDPOINT` if set
3. AWS SDK defaults (for standard AWS S3)

For server operations (uploads, validation):

1. `S3_ENDPOINT` if set
2. AWS SDK defaults

## Helm Values (Kubernetes)

In `values.yaml`:

```yaml theme={null}
env:
  secrets:
    S3_ENDPOINT: "http://minio.storage.svc.cluster.local:9000"
    S3_PUBLIC_ENDPOINT: "https://s3.example.com"
    S3_BUCKET_NAME: "azalt"
    S3_ACCESS_KEY_ID: "..."
    S3_SECRET_ACCESS_KEY: "..."
    S3_FORCE_PATH_STYLE: "true"
  config:
    S3_REGION: "eu-central-1"
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Error: S3 storage is not configured">
    Ensure all three required variables are set:

    * `S3_BUCKET_NAME`
    * `S3_ACCESS_KEY_ID`
    * `S3_SECRET_ACCESS_KEY`
  </Accordion>

  <Accordion title="Warning: S3_ENDPOINT is set but S3_PUBLIC_ENDPOINT is not">
    This warning appears when `S3_ENDPOINT` is configured but `S3_PUBLIC_ENDPOINT` is not. The app will use `S3_ENDPOINT` for presigned URLs.

    **Action needed if**: `S3_ENDPOINT` is an internal URL (Docker/Kubernetes service name) that browsers cannot reach. Set `S3_PUBLIC_ENDPOINT` to the browser-accessible URL.

    **No action needed if**: `S3_ENDPOINT` is already browser-accessible (users on VPN, public endpoint, etc.).
  </Accordion>

  <Accordion title="File uploads/downloads fail with signature errors">
    This usually means there's a mismatch between the URL used for signing and the URL browsers actually access.

    1. Verify `S3_PUBLIC_ENDPOINT` points to where browsers can reach S3
    2. Check that any reverse proxy preserves the path correctly
    3. Ensure `S3_FORCE_PATH_STYLE` matches your S3 service requirements
  </Accordion>

  <Accordion title="CORS errors on file uploads">
    Ensure your S3 bucket has proper CORS configuration allowing requests from your application domain.
  </Accordion>
</AccordionGroup>
