Skip to content

S3 Storage

By default NORA stores artifacts on the local filesystem. For production deployments you can switch to any S3-compatible backend — AWS S3, MinIO, RustFS, Ceph RGW, and others.

VariableDefaultDescription
NORA_STORAGE_MODElocalSet to s3 to enable object storage
NORA_STORAGE_S3_URLS3-compatible endpoint URL (e.g. http://minio:9000)
NORA_STORAGE_BUCKETregistryBucket name. Must exist before NORA starts
NORA_STORAGE_S3_ACCESS_KEYAccess key. If omitted, anonymous access is used
NORA_STORAGE_S3_SECRET_KEYSecret key
NORA_STORAGE_S3_REGIONus-east-1Region. Required by some S3 implementations

MinIO is the most popular self-hosted S3-compatible storage. This example includes an init container that creates the bucket automatically.

services:
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: noraadmin
MINIO_ROOT_PASSWORD: changeme-minio-secret
ports:
- 9000:9000 # S3 API
- 9001:9001 # MinIO Console
volumes:
- minio-data:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 5
createbucket:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set myminio http://minio:9000 noraadmin changeme-minio-secret;
mc mb --ignore-existing myminio/nora-storage;
exit 0;
"
nora:
image: ghcr.io/getnora-io/nora:latest
depends_on:
createbucket:
condition: service_completed_successfully
environment:
NORA_HOST: "0.0.0.0"
NORA_STORAGE_MODE: s3
NORA_STORAGE_S3_URL: http://minio:9000
NORA_STORAGE_BUCKET: nora-storage
NORA_STORAGE_S3_ACCESS_KEY: noraadmin
NORA_STORAGE_S3_SECRET_KEY: changeme-minio-secret
NORA_STORAGE_S3_REGION: us-east-1
ports:
- 4000:4000
restart: unless-stopped
volumes:
minio-data:
Terminal window
# Push a Docker image
docker tag alpine:latest localhost:4000/test/alpine:latest
docker push localhost:4000/test/alpine:latest
# Pull it back
docker rmi localhost:4000/test/alpine:latest
docker pull localhost:4000/test/alpine:latest
# Upload a raw file
curl -X PUT -d "hello s3" http://localhost:4000/raw/test/hello.txt
curl http://localhost:4000/raw/test/hello.txt

Check MinIO Console at http://localhost:9001 — you should see objects in the nora-storage bucket.

RustFS is a lightweight S3-compatible storage written in Rust. Configuration is identical to MinIO with one difference: the health check endpoint is /health instead of /minio/health/live.

services:
rustfs:
image: rustfs/rustfs:latest
command: server /data --console-address ":9001"
environment:
RUSTFS_ROOT_USER: noraadmin
RUSTFS_ROOT_PASSWORD: changeme-rustfs-secret
ports:
- 9000:9000 # S3 API
- 9001:9001 # Console
volumes:
- rustfs-data:/data
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/health"]
interval: 5s
timeout: 5s
retries: 5
createbucket:
image: minio/mc:latest
depends_on:
rustfs:
condition: service_healthy
entrypoint: >
/bin/sh -c "
mc alias set myrustfs http://rustfs:9000 noraadmin changeme-rustfs-secret;
mc mb --ignore-existing myrustfs/nora-storage;
exit 0;
"
nora:
image: ghcr.io/getnora-io/nora:latest
depends_on:
createbucket:
condition: service_completed_successfully
environment:
NORA_HOST: "0.0.0.0"
NORA_STORAGE_MODE: s3
NORA_STORAGE_S3_URL: http://rustfs:9000
NORA_STORAGE_BUCKET: nora-storage
NORA_STORAGE_S3_ACCESS_KEY: noraadmin
NORA_STORAGE_S3_SECRET_KEY: changeme-rustfs-secret
NORA_STORAGE_S3_REGION: us-east-1
ports:
- 4000:4000
restart: unless-stopped
volumes:
rustfs-data:

For AWS S3, point NORA_STORAGE_S3_URL to the regional endpoint:

environment:
NORA_STORAGE_MODE: s3
NORA_STORAGE_S3_URL: https://s3.eu-central-1.amazonaws.com
NORA_STORAGE_BUCKET: my-nora-registry
NORA_STORAGE_S3_ACCESS_KEY: AKIA...
NORA_STORAGE_S3_SECRET_KEY: wJal...
NORA_STORAGE_S3_REGION: eu-central-1
[storage]
mode = "s3"
s3_url = "http://minio:9000"
bucket = "nora-storage"
s3_access_key = "noraadmin"
s3_secret_key = "changeme"
s3_region = "us-east-1"

NORA starts but artifacts go to local storage

Section titled “NORA starts but artifacts go to local storage”

Check NORA_STORAGE_MODE is set to exactly s3 (lowercase). Any misspelling causes a silent fallback to local mode. Run:

Terminal window
docker exec nora env | grep NORA_STORAGE

You should see:

NORA_STORAGE_MODE=s3
NORA_STORAGE_S3_URL=http://minio:9000
NORA_STORAGE_BUCKET=nora-storage
...

Ensure the S3 service is healthy before NORA starts. In Docker Compose, use depends_on with condition: service_healthy.

NORA does not create buckets. Pre-create with mc mb or an init container (see examples above).