Storage overview
Relic keeps file content in object storage and everything else in the
database. Object storage is an S3-compatible service
(RELIC_OBJECT_STORAGE_TYPE=s3, the default), Azure Blob Storage (azure),
Google Cloud Storage (gcs), or a local directory on a single node
(filesystem).
- SeaweedFS (recommended for self-hosted storage)
- Amazon S3
- Cloudflare R2
- MinIO
- Google Cloud Storage
- Azure Blob Storage
- Backblaze B2
- Other S3-compatible services: Ceph, Wasabi, DigitalOcean Spaces, Garage
- Filesystem: a local directory, one node only
What goes where
| Database | Object storage |
|---|---|
| Repositories, items, properties, checksums, builds, users, tokens, permissions, scan results, the job queue. | File content, stored once per SHA-256. |
Buckets
| Bucket | Holds | Behaviour |
|---|---|---|
artifacts | Content under sha256/<aa>/<bb>/<sha256> | Objects never change. Identical files share one object. Garbage collection deletes an object once nothing has referenced it for RELIC_GARBAGE_COLLECTION_GRACE_PERIOD (default one hour). |
temporary | Uploads in progress | New content is copied server-side into artifacts, then deleted here. Garbage collection deletes objects older than a day. |
artifacts also holds layout.json ({"version":1}). Relic refuses to start
on a store that records another layout version. Keep the file in backups.
Clients never reach the storage: Relic reads every download from the bucket and
sends it on. Only Relic needs network access to the storage, and with a cloud
provider each download is a bucket read you pay for, so run Relic in the same
region. The daily storage check adds a listing of artifacts and up to 10 GiB
of reads to verify content.
Bucket requirements
- Create both buckets yourself. Relic never creates buckets; only the Helm chart's bundled SeaweedFS and the Compose stack do.
- Use two different buckets on the same endpoint, both readable and writable with one key pair.
- On both buckets, expire incomplete multipart uploads after one day. Relic cannot see them.
- Turn off versioning and object lock on
artifacts, or expire noncurrent versions. Object lock makes deletes fail. - Keep both buckets private.
- Unless
RELIC_OBJECT_STORAGE_SSEis set, the bucket's default encryption applies.
Permissions
| Operation | Bucket | Why |
|---|---|---|
PutObject, CreateMultipartUpload, UploadPart, CompleteMultipartUpload, AbortMultipartUpload | temporary | Stage uploads. |
CopyObject, UploadPartCopy (over 5 GiB) | temporary to artifacts | Move an upload to its content address. |
GetObject with byte ranges, HeadObject | both | Downloads, scanning, the readiness and storage checks. |
ListObjectsV2 | both | Garbage collection and the storage check. |
DeleteObject | both | Clean up staged uploads; garbage collection. |
The readiness check (/readyz) sends HeadObject for the missing key
readyz/probe and expects "not found". An "access denied" answer keeps Relic
unready. On Amazon S3 this happens when the key lacks s3:ListBucket.
Connection settings
| Variable | Default | Meaning |
|---|---|---|
RELIC_OBJECT_STORAGE_ENDPOINT | (empty) | The S3 API's base URL, with scheme. Empty means Amazon S3. |
RELIC_OBJECT_STORAGE_REGION | us-east-1 | The region Relic signs requests for. |
RELIC_OBJECT_STORAGE_ACCESS_KEY, RELIC_OBJECT_STORAGE_SECRET_KEY | (empty) | A static key pair. Without one, Relic uses the AWS default credential chain. |
RELIC_OBJECT_STORAGE_ARTIFACTS_BUCKET, RELIC_OBJECT_STORAGE_TEMPORARY_BUCKET | artifacts, temporary | Bucket names. They must differ. |
In the Helm chart, these are objectStorage.* values; the key pair is
objectStorageAccessKey and objectStorageSecretKey in the Secret. See
Helm.
What Relic does not support
No setting changes these.
- Virtual-hosted-style URLs on a custom endpoint. With an endpoint set,
Relic sends path-style requests (
<endpoint>/<bucket>/<key>). - A session token setting. Without a static key pair, Relic uses the AWS
default credential chain:
AWS_*variables, shared credential files, IRSA, EKS Pod Identity and instance profiles. - TLS options. Relic verifies
https://endpoints against the system CA bundle, whichSSL_CERT_FILEandSSL_CERT_DIRreplace. The Helm chart has no value to mount such a file. - Signing options. Uploads carry the AWS SDK's CRC32 checksums. For a
service that rejects them, set
RELIC_OBJECT_STORAGE_CHECKSUM=when_required. - ACL headers. The bucket's defaults apply.
Sizes and throughput
- A file can be up to 5 TiB with
Content-Length, and up to 64 GiB without (a chunked transfer). - Uploads go in 5 MiB parts (larger above about 49 GiB), two in flight per upload, so memory stays bounded.
- Objects up to 5 GiB move into
artifactswith oneCopyObject; larger ones withUploadPartCopyin 512 MiB parts. - Range requests pass straight through to
GetObject.
Moving to another provider
Object keys are the same on every provider.
- Create the buckets on the new service.
- Copy
artifactswith an S3 sync tool, such asrclone sync. - Stop the server and the worker. Run the copy again. Point
RELIC_OBJECT_STORAGE_*at the new service and start both.
You do not need to copy temporary.
Backups
Back up the database first, then copy artifacts. Backup
explains why the order matters.