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.
Configuration
Section titled “Configuration”| Variable | Default | Description |
|---|---|---|
NORA_STORAGE_MODE | local | Set to s3 to enable object storage |
NORA_STORAGE_S3_URL | — | S3-compatible endpoint URL (e.g. http://minio:9000) |
NORA_STORAGE_BUCKET | registry | Bucket name. Must exist before NORA starts |
NORA_STORAGE_S3_ACCESS_KEY | — | Access key. If omitted, anonymous access is used |
NORA_STORAGE_S3_SECRET_KEY | — | Secret key |
NORA_STORAGE_S3_REGION | us-east-1 | Region. 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.
Docker Compose
Section titled “Docker Compose”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:Verify
Section titled “Verify”# Push a Docker imagedocker tag alpine:latest localhost:4000/test/alpine:latestdocker push localhost:4000/test/alpine:latest
# Pull it backdocker rmi localhost:4000/test/alpine:latestdocker pull localhost:4000/test/alpine:latest
# Upload a raw filecurl -X PUT -d "hello s3" http://localhost:4000/raw/test/hello.txtcurl http://localhost:4000/raw/test/hello.txtCheck MinIO Console at http://localhost:9001 — you should see objects in the nora-storage bucket.
RustFS
Section titled “RustFS”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.
Docker Compose
Section titled “Docker Compose”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:AWS S3
Section titled “AWS S3”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-1config.toml
Section titled “config.toml”[storage]mode = "s3"s3_url = "http://minio:9000"bucket = "nora-storage"s3_access_key = "noraadmin"s3_secret_key = "changeme"s3_region = "us-east-1"Troubleshooting
Section titled “Troubleshooting”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:
docker exec nora env | grep NORA_STORAGEYou should see:
NORA_STORAGE_MODE=s3NORA_STORAGE_S3_URL=http://minio:9000NORA_STORAGE_BUCKET=nora-storage...Connection refused to S3 endpoint
Section titled “Connection refused to S3 endpoint”Ensure the S3 service is healthy before NORA starts. In Docker Compose, use depends_on with condition: service_healthy.
Bucket does not exist
Section titled “Bucket does not exist”NORA does not create buckets. Pre-create with mc mb or an init container (see examples above).
See Also
Section titled “See Also”- Settings — all configuration options
- Production Guide — deployment best practices
- Docker Proxy — pull-through cache setup