# RustFS — Components Deep Dive

*A study guide to RustFS, an open-source, S3-compatible distributed object store written in Rust: what each component is, the commands and settings you will actually use, when to use it, the traps, and where the docs live.*

> **How to read this guide.** Each component has (1) a mental model, (2) the code or config, (3) a *when to use / when not to* verdict, (4) traps and (5) 📖 doc links. The decision tables are in §2 (which deployment mode) and §11 (should I use RustFS at all). The sibling page *Prefect — Components Deep Dive* covers an orchestrator that can use an S3-compatible store for results and code. **Version note:** written 23 Oct 2026 from docs.rustfs.com. The S3 compatibility page was snapshotted by RustFS against a commit dated 9 Aug 2026, so treat counts as a moving target. ⚑ marks items from prior knowledge or inference rather than the pages I read (boto3 usage, exact Prefect wiring). **Read §11 before adopting:** this is a young project, so verify production readiness yourself.

---

## 0. The map: what RustFS is

> **Analogy: a warehouse of labelled bins with a front desk that speaks Amazon's language.** Customers (applications) hand over boxes (objects) with a bin label (bucket) and a shelf label (key). The front desk (the S3 API) uses the same forms as Amazon's warehouse, so existing tools just work. Behind the desk, each box is split into pieces and spread over many shelves (disks) so a few broken shelves do not lose anything.

- **What:** a distributed object storage system in Rust, **Apache 2.0** licensed, S3-compatible, aimed at private cloud, data lakes, AI/ML and cloud-native workloads. It runs on Linux, Windows, macOS, FreeBSD and containers across x86, ARM and RISC-V.
- **Positioning from the project:** the permissive licence is the headline contrast with AGPL-licensed alternatives; it claims migration and coexistence with S3-compatible platforms such as MinIO and Ceph. The README also claims 2.3x faster than MinIO for 4 KB payloads. **That is a vendor benchmark; reproduce it on your hardware and object sizes before it informs a decision.**
- **Components:** the `rustfs` server (S3 API on port 9000), the web **Console** (port 9001), the `rc` command-line client, optional protocol gateways (WebDAV, FTP/FTPS, SFTP, OpenStack Swift), background services (scanner for bit-rot, healing, lifecycle, replication), Kubernetes Helm chart and Operator, and an MCP server for AI assistants.
- **Object-store vocabulary:** an object is a blob plus metadata, addressed by `bucket/key`. Keys look like paths but the namespace is flat; 'folders' are just key prefixes.

**Addressing.** Path-style by default (`http://host:9000/my-bucket/path/to/hello.txt`). For virtual-host style (`https://my-bucket.s3.example.com/hello.txt`) set `RUSTFS_SERVER_DOMAINS=s3.example.com` and create wildcard DNS (`*.s3.example.com`) pointing at RustFS.

📖 [Docs home](https://docs.rustfs.com/en) · [S3 protocol](https://docs.rustfs.com/en/administration/protocols/s3) · [Virtual-host access](https://docs.rustfs.com/en/integration/virtual) · [GitHub](https://github.com/rustfs/rustfs)

---

## 1. Installing it

<table id="bkmrk-goalpathtry-it-local"><thead><tr><th>Goal</th><th>Path</th></tr></thead><tbody><tr><td>Try it locally</td><td>One-command install script, or a container</td></tr><tr><td>Single-server production</td><td>SNSD (one disk) or SNMD (several disks), on Linux</td></tr><tr><td>Multi-server production</td><td>MNMD after the pre-installation checklists</td></tr><tr><td>Kubernetes</td><td>Helm chart (standalone or distributed) or the RustFS Operator (tenants, pools, KMS)</td></tr><tr><td>Windows or macOS</td><td>Native install; **the Windows build is for development and debugging only**</td></tr></tbody></table>

### 1.1 Docker, the fastest start

```
docker volume create rustfs-data
docker run -d --name rustfs --restart unless-stopped \
  -p 9000:9000 -p 9001:9001 -v rustfs-data:/data \
  -e RUSTFS_ACCESS_KEY='<your-access-key>' -e RUSTFS_SECRET_KEY='<your-secret-key>' \
  -e RUSTFS_ADDRESS=':9000' -e RUSTFS_CONSOLE_ADDRESS=':9001' -e RUSTFS_CONSOLE_ENABLE=true \
  rustfs/rustfs:latest /data
curl --fail http://localhost:9000/health         # S3 API health; Console on :9001
```

- **Change the default credentials immediately.** Never use the well-known `rustfsadmin` value. On Linux set `RUSTFS_ACCESS_KEY` and `RUSTFS_SECRET_KEY` in `/etc/default/rustfs` and restart; with containers pass them at creation (recreate the container if it started without them; the volume survives).
- **The container runs as non-root user `rustfs`, UID 10001.** A bind-mounted host directory must be owned by 10001 (`chown -R 10001:10001 /path`) or you get permission denied. Named volumes need no setup.
- **Flags win over env vars** when both are given (`--access-key`, `--address`, `--console-enable`).
- **Compose:** the repository ships a `docker-compose.yml` with optional Grafana, Prometheus, OpenTelemetry collector and Jaeger under `--profile observability`; start only the server with `docker compose up -d rustfs`. An init container fixes volume ownership.
- **Multi-node containers** need `--network host` (the default bridge network does not support it) and name resolution (`/etc/hosts` on every node): `RUSTFS_VOLUMES='http://node{1...4}:9000/data/rustfs{0...3}'`.
- **TLS:** mount a cert directory and set `RUSTFS_TLS_PATH=/certs`. For HTTPS in front, the docs cover Nginx, Traefik, Caddy, Envoy, HAProxy and Apache with separate hostnames for S3 and Console.

📖 [Installation](https://docs.rustfs.com/en/installation) · [Docker](https://docs.rustfs.com/en/installation/container/docker) · [Linux](https://docs.rustfs.com/en/installation/linux) · [Kubernetes](https://docs.rustfs.com/en/installation/cloud-native) · [Checklists](https://docs.rustfs.com/en/installation/requirement/checklists) · [TLS](https://docs.rustfs.com/en/integration/tls-configured) · [Reverse proxy](https://docs.rustfs.com/en/developer/integration/reverse-proxy)

---

## 2. Deployment modes: which one?

<table id="bkmrk-modenodesdisksfault-"><thead><tr><th>Mode</th><th>Nodes</th><th>Disks</th><th>Fault tolerance</th><th>Use for</th></tr></thead><tbody><tr><td>**SNSD**</td><td>1</td><td>1</td><td>None. Rely on backups</td><td>Dev, test, small non-critical</td></tr><tr><td>**SNMD**</td><td>1</td><td>Several</td><td>Up to M parity disks inside the node; the node itself is a single point of failure</td><td>Mid-sized non-critical on one server</td></tr><tr><td>**MNMD**</td><td>4 or more</td><td>Several per node</td><td>Disk- and node-level via erasure coding across servers</td><td>Production</td></tr></tbody></table>

**Decision rule:** if losing a server or its data would hurt, you need MNMD *plus* a backup or replication strategy (erasure coding protects against disk failures, not against deletion, corruption by software, or a lost site). SNSD is a development tool, not a storage strategy.

**Disk preparation (Linux).** Use dedicated data disks, format, mount and verify them before installing (the docs refer to XFS and a verification step); keep identical service environment configuration on every node. Work through the hardware, network, software and security checklists first.

📖 [SNSD](https://docs.rustfs.com/en/installation/linux/single-node-single-disk) · [SNMD](https://docs.rustfs.com/en/installation/linux/single-node-multiple-disk) · [MNMD](https://docs.rustfs.com/en/installation/linux/multiple-node-multiple-disk) · [Disk preparation](https://docs.rustfs.com/en/installation/requirement/disk-preparation) · [Hardware selection](https://docs.rustfs.com/en/installation/requirement/checklists/hardware-selection)

---

## 3. Erasure coding and capacity

> **Analogy: a jigsaw with spare pieces.** Each object is cut into N-M data pieces plus M extra 'parity' pieces, then spread across N disks. Any N-M of the N pieces rebuild the object, so up to M pieces can be lost.

- **Reed-Solomon erasure coding.** Each pool is divided into one or more *erasure sets*. For a set of `N` drives with `M` parity shards: data shards = N-M; tolerable unavailable shards = M; capacity efficiency about (N-M)/N. A 16-drive set with `EC:4` stores 12 data and 4 parity shards, about 75% efficiency before file-system, metadata and operational overhead.
- **Failure-domain caveat (from the docs):** parity covers unavailable shards *within one set*. Node-level tolerance depends on how a set's drives are spread over nodes; **do not assume `EC:4` survives four whole nodes**, because one node may hold several drives of the same set.

<table id="bkmrk-drives-per-set-%28n%29au"><thead><tr><th>Drives per set (N)</th><th>Automatic STANDARD parity</th><th>Approx. efficiency</th></tr></thead><tbody><tr><td>1</td><td>EC:0</td><td>100%</td></tr><tr><td>2-3</td><td>EC:1</td><td>50-67%</td></tr><tr><td>4-5</td><td>EC:2</td><td>50-60%</td></tr><tr><td>6-7</td><td>EC:3</td><td>50-57%</td></tr><tr><td>8-16</td><td>EC:4</td><td>50-75%</td></tr></tbody></table>

```
# /etc/default/rustfs
RUSTFS_STORAGE_CLASS_STANDARD=          # recommended: leave empty for automatic per-pool parity
# or pin explicitly (must be valid for the NARROWEST pool):
RUSTFS_STORAGE_CLASS_STANDARD=EC:4
RUSTFS_STORAGE_CLASS_RRS=EC:1           # REDUCED_REDUNDANCY writes; default 1 parity on multi-drive sets
RUSTFS_ERASURE_SET_DRIVE_COUNT=16       # pin set width only if you verified the whole layout
```

- **Rules for explicit parity:** M &lt;= N/2 in every target set; STANDARD parity &gt;= RRS parity when both non-zero; valid for every pool. An invalid value makes *startup fail* rather than silently weakening parity.
- **Set widths** range from 2 to 16 drives, selected automatically from the topology. Validate against the set width, *not* the cluster's total drive count.
- **Capacity estimate:** usable is roughly raw x (N-M)/N. Sixteen 10 TiB drives as one 16-drive set with EC:4 gives about 120 TiB, and you must still reserve space for metadata, versioning, incomplete multipart uploads, healing and headroom.
- **Verify after start:** Console Status page or `rc admin info cluster` shows layout, parity, drive availability and pool membership.

**Trap.** More parity buys durability at the price of usable capacity and write cost; do not pin high parity on small sets without checking the efficiency. Leaving the default is the documented recommendation unless you have a validated requirement.

📖 [EC configuration](https://docs.rustfs.com/en/installation/requirement/ec-configuration) · [Status check](https://docs.rustfs.com/en/operations/status-check) · [Storage env vars](https://docs.rustfs.com/en/reference/environment-variables#storage--erasure)

---

## 4. Configuration surface

<table id="bkmrk-settingpurposerustfs"><thead><tr><th>Setting</th><th>Purpose</th></tr></thead><tbody><tr><td>`RUSTFS_ACCESS_KEY` / `RUSTFS_SECRET_KEY`</td><td>Root credentials. Set unique values</td></tr><tr><td>`RUSTFS_ADDRESS`</td><td>S3 API bind address (default `:9000`)</td></tr><tr><td>`RUSTFS_CONSOLE_ADDRESS`, `RUSTFS_CONSOLE_ENABLE`</td><td>Console bind address and switch (port 9001)</td></tr><tr><td>`RUSTFS_VOLUMES`</td><td>The storage endpoints; supports `{1...4}` range expansion for multi-node</td></tr><tr><td>`RUSTFS_SERVER_DOMAINS`</td><td>Domain for virtual-host style access</td></tr><tr><td>`RUSTFS_TLS_PATH`</td><td>Directory with certificates</td></tr><tr><td>`RUSTFS_STORAGE_CLASS_*`, `RUSTFS_ERASURE_SET_DRIVE_COUNT`</td><td>Erasure coding (§3)</td></tr><tr><td>`RUSTFS_OBS_*`</td><td>Logging and observability (level, log directory)</td></tr></tbody></table>

The reference page also lists variables for KMS, the scanner, healing and event targets. `rustfs` has subcommands and server flags with environment equivalents (CLI reference). Keep the same environment file on every node.

📖 [Environment variables](https://docs.rustfs.com/en/reference/environment-variables) · [CLI reference](https://docs.rustfs.com/en/reference/cli) · [CORS](https://docs.rustfs.com/en/administration/cors)

---

## 5. The S3 API and compatibility

> **Analogy: speaking a dialect.** RustFS speaks Amazon S3 well enough for most everyday conversation, but not every idiom. The project says so itself: it is a *tested subset*, not a claim of full coverage.

```
# AWS CLI against RustFS: just add --endpoint-url
aws --endpoint-url "$RUSTFS_ENDPOINT" s3 cp hello.txt s3://my-bucket/path/to/hello.txt
aws --endpoint-url "$RUSTFS_ENDPOINT" s3 ls s3://my-bucket/
aws --endpoint-url "$RUSTFS_ENDPOINT" s3api head-object --bucket my-bucket --key path/to/hello.txt
aws --endpoint-url "$RUSTFS_ENDPOINT" s3 presign s3://my-bucket/path/to/hello.txt

# Python (boto3)  ⚑
import boto3
s3 = boto3.client('s3', endpoint_url='http://localhost:9000',
                  aws_access_key_id=KEY, aws_secret_access_key=SECRET, region_name='us-east-1')
s3.upload_file('hello.txt', 'my-bucket', 'path/to/hello.txt')
```

<table id="bkmrk-areastatus-in-the-co"><thead><tr><th>Area</th><th>Status in the compatibility gate</th></tr></thead><tbody><tr><td>Bucket create/delete/list/inspect, tagging, policies, public access block</td><td>Tested</td></tr><tr><td>Object put/get/copy/head/delete, listing (prefix, delimiter, marker, max-keys; V1 and V2)</td><td>Tested</td></tr><tr><td>Range and conditional reads, user metadata, object tags, presigned GET/PUT</td><td>Tested</td></tr><tr><td>Multipart create/upload/complete/abort; selected copy and checksum cases</td><td>Tested</td></tr><tr><td>Selected versioning, Object Lock, CORS and lifecycle cases; SSE-C and selected SSE-KMS</td><td>Tested (only the cases in the implemented lists)</td></tr><tr><td>Bucket access logging, bucket ownership controls, POST Object form checksum handling</td><td>Planned (not implemented)</td></tr><tr><td>ACL authorisation</td><td>Excluded: intentionally unsupported</td></tr><tr><td>Multipart upload listing and part-lookup edge cases</td><td>Excluded from the default gate</td></tr></tbody></table>

- **Gate size (Aug 2026 snapshot):** 455 implemented cases, 5 lifecycle cases, 17 planned, 270 excluded, from Ceph s3-tests lists. Read the numbers as 'a lot is covered, but 270 are excluded', not as 'complete'.
- **Encrypted objects are not portable.** A passing encryption test means RustFS can read what RustFS encrypted; it does not mean it can read an encrypted object copied raw from another implementation.
- **S3 Select** currently accepts only uncompressed input.
- **Other protocols:** WebDAV, FTP/FTPS, SFTP and (optional build) OpenStack Swift gateways over the same buckets.

**Practical advice:** if you depend on ACLs, bucket access logging, or exotic multipart listing behaviour, test those exact calls against RustFS before committing. Use `rclone` or your SDK's integration test suite as a smoke test.

📖 [S3 compatibility matrix](https://docs.rustfs.com/en/reference/s3-compatibility) · [SDKs](https://docs.rustfs.com/en/developer/sdk) · [Python](https://docs.rustfs.com/en/developer/sdk/python) · [SFTP](https://docs.rustfs.com/en/administration/protocols/sftp) · [WebDAV](https://docs.rustfs.com/en/administration/protocols/webdav)

---

## 6. Data management features

<table id="bkmrk-featurewhat-it-doesu"><thead><tr><th>Feature</th><th>What it does</th><th>Use it for</th><th>Gotcha</th></tr></thead><tbody><tr><td>**Versioning**</td><td>Keeps prior versions; deletes create markers</td><td>Recover from overwrites and accidental deletes</td><td>Storage grows; required by replication</td></tr><tr><td>**Object Lock**</td><td>Retention periods and legal holds on versioned objects</td><td>WORM and compliance retention</td><td>Needs versioning; test retention modes before relying on them</td></tr><tr><td>**Lifecycle rules**</td><td>Expire or transition objects by age</td><td>Cost control, log retention</td><td>Managed with the `rc` client; verify rules fire</td></tr><tr><td>**Tiered storage**</td><td>Lifecycle-driven transition to a remote storage tier</td><td>Move cold data to cheaper storage</td><td>Reads of tiered objects depend on the remote tier</td></tr><tr><td>**Bucket quota**</td><td>Hard storage quota per bucket</td><td>Multi-tenant limits</td><td>Hard limit: writes fail at the cap</td></tr><tr><td>**Bucket replication**</td><td>Asynchronous replication between versioned buckets</td><td>Copies in another cluster</td><td>Async, so a failover can lose the last writes; both ends need versioning</td></tr><tr><td>**Site replication**</td><td>Multi-site replication managed with `rc`</td><td>Disaster recovery across sites</td><td>Plan network and consistency expectations</td></tr><tr><td>**Multipart upload**</td><td>Parts for large objects; Console task monitor</td><td>Big files, resumable uploads</td><td>Incomplete uploads consume space; clean up</td></tr><tr><td>**Scanner**</td><td>Background object scan with a bit-rot cycle and metrics</td><td>Detect silent corruption</td><td>Watch its metrics to confirm scans still run</td></tr><tr><td>**S3 Tables**</td><td>Table buckets with a built-in Iceberg REST catalog</td><td>Lakehouse without a separate catalog</td><td>Newer feature; test with your engines (PyIceberg, Spark docs exist)</td></tr><tr><td>**Event notifications**</td><td>Filtered bucket events to external targets (webhook and others)</td><td>React to uploads, trigger pipelines</td><td>Targets and queue directories need persistent storage</td></tr></tbody></table>

📖 [Versioning](https://docs.rustfs.com/en/administration/data/object/versioning) · [Object Lock](https://docs.rustfs.com/en/administration/data/object/object-lock) · [Lifecycle](https://docs.rustfs.com/en/administration/data/lifecycle-management) · [Tiering](https://docs.rustfs.com/en/administration/data/tiered-storage) · [Quota](https://docs.rustfs.com/en/administration/data/bucket/quota) · [Bucket replication](https://docs.rustfs.com/en/administration/data/bucket/replication) · [Site replication](https://docs.rustfs.com/en/operations/high-availability/site-replication) · [Scanner](https://docs.rustfs.com/en/administration/data/object/scanner) · [S3 Tables](https://docs.rustfs.com/en/administration/data/s3-tables) · [Event notifications](https://docs.rustfs.com/en/operations/event-notifications)

---

## 7. Security

> **Analogy: badges, keys and a locked cabinet.** IAM decides who may enter which room (badges). Encryption keeps the contents unreadable even if someone steals a disk (locked cabinet). TLS protects the hallway.

- **IAM:** users, groups and policies; policy attachment and evaluation semantics are documented. **Service accounts and STS** issue scoped, short-lived credentials for applications. **Access keys** are managed per identity. Prefer service accounts or STS for applications and keep the root key out of code.
- **Bucket policies** are applied through the S3 API; **public access block** exists. ACLs are intentionally unsupported.
- **OIDC:** Console single sign-on with providers such as Keycloak and GitLab.
- **Encryption at rest:** **SSE-S3** (server-managed keys), **SSE-C** (customer-provided AES-256 keys) and **SSE-KMS** with a local or HashiCorp Vault backend; the Operator can configure KMS for tenants. *Note:* the project README marks its KMS as 'under testing' while the docs describe KMS configuration, so validate your key-management path and recovery procedure before putting regulated data on it.
- **TLS** with `RUSTFS_TLS_PATH`; mTLS and cert-manager are documented for Helm deployments.
- **Audit targets** deliver request-level audit records to external systems. **Credential management** has its own page; rotate the root credentials.

**Traps.** Default credentials left in place. Exposing the Console (9001) to the internet. Putting RustFS behind a reverse proxy that rewrites the Host header without enabling the matching virtual-host settings. Losing the KMS key means losing the data.

📖 [Security and compliance](https://docs.rustfs.com/en/security-compliance) · [IAM](https://docs.rustfs.com/en/security-compliance/iam) · [Service accounts and STS](https://docs.rustfs.com/en/security-compliance/iam/sts) · [Encryption](https://docs.rustfs.com/en/security-compliance/encryption) · [OIDC](https://docs.rustfs.com/en/security-compliance/oidc) · [Audit](https://docs.rustfs.com/en/security-compliance/audit-logs) · [Credentials](https://docs.rustfs.com/en/operations/credentials)

---

## 8. Operations

- **The `rc` client:** a RustFS command-line client to connect to, inspect and administer a cluster, including lifecycle rules, replication, heal tasks and `rc admin info cluster`.
- **Health and status:** `/health` on the S3 port; the Console Status page; the status-check workflow covers network access, health endpoints, cluster status and capacity.
- **Observability:** export metrics, traces and logs over **OTLP**; the docs list recommended alerts and metric names, and integrations with Prometheus, Grafana, Loki, Tempo and Thanos exist.
- **Scaling:** *expand* by adding a storage pool; *rebalance* to redistribute existing objects over active pools; *decommission* to drain and retire a pool and verify the data moved. Pools are the unit of growth, so plan pool sizes and symmetry up front.
- **Healing and failures:** replace a failed drive and let RustFS heal the missing shards onto it; for a lost node prepare a replacement, update its configuration, restore cluster membership and watch healing. Manual heal tasks can be bounded with `rc`.
- **Upgrades:** binary, container and Kubernetes procedures that preserve availability. Rehearse on a non-production cluster first.
- **Kubernetes:** the Helm chart (standalone or distributed, probes, hardening, pool expansion) or the Operator (multi-tenant isolation, pool expansion, KMS).

**Runbook items to write before go-live:** disk replacement, node replacement, credential rotation, certificate renewal, capacity alert thresholds, upgrade order, restore test from backup or replica.

📖 [rc client](https://docs.rustfs.com/en/operations/rc) · [Observability](https://docs.rustfs.com/en/operations/observability) · [Scaling](https://docs.rustfs.com/en/operations/scaling) · [Node healing](https://docs.rustfs.com/en/operations/high-availability/node-healing) · [Drive failures](https://docs.rustfs.com/en/troubleshooting/driver) · [Node failures](https://docs.rustfs.com/en/troubleshooting/node) · [Upgrade](https://docs.rustfs.com/en/operations/upgrade) · [Cluster lifecycle](https://docs.rustfs.com/en/operations/cluster-lifecycle)

---

## 9. Integrations relevant to a data platform

RustFS documents step-by-step integrations (mostly Docker Compose based) for tools that speak S3. Grouped by purpose:

<table id="bkmrk-purposetools-with-a-"><thead><tr><th>Purpose</th><th>Tools with a RustFS guide</th></tr></thead><tbody><tr><td>Orchestration and ingestion</td><td>Airflow (S3 provider), DolphinScheduler, SeaTunnel, Kafka Connect S3 sink, AutoMQ</td></tr><tr><td>Lakehouse and query</td><td>Apache Iceberg (Spark, REST catalog), PyIceberg via S3 Tables, Delta Lake (delta-rs), Hudi, Paimon, Hive, Spark, Flink, Trino, DuckDB (httpfs), ClickHouse (S3 disk), Databend, Doris, lakeFS</td></tr><tr><td>Vector and ML</td><td>LanceDB, Milvus, MLflow artifact store, Ray Data, vLLM model weights</td></tr><tr><td>Observability storage</td><td>Loki, Tempo, Thanos, Cortex, OpenObserve, GreptimeDB, Fluentd, OpenTelemetry, VictoriaMetrics backups</td></tr><tr><td>Backup and DR</td><td>Restic, Kopia, Velero, Longhorn, Vitess</td></tr><tr><td>DevOps and platform</td><td>Terraform state with locking, Elasticsearch and OpenSearch snapshots, Gitea LFS, Jenkins artifacts, Harbor and Docker Registry, Flux, Nextcloud</td></tr><tr><td>Filesystem views</td><td>s3fs-fuse, rclone, JuiceFS, ZeroFS (NFS), Alluxio cache, SFTPGo, OpenDAL</td></tr></tbody></table>

### 9.1 Using it with Prefect ⚑

Prefect can keep **results** and **deployment code** in S3-compatible storage through the `prefect-aws` integration. Because RustFS speaks S3, the wiring is the integration's S3 bucket block with a custom **endpoint URL** pointing at RustFS and a service-account key. I wrote this from how `prefect-aws` normally works, not from a tested RustFS example; check the *prefect-aws* docs for the current block and client-parameter names and run a write/read round trip before trusting it.

- **Results:** point result storage at a bucket such as `prefect-results`; every worker must reach the endpoint and credentials.
- **Code:** a pull step can fetch flow code from a bucket at run time.
- **Hygiene:** a dedicated service account with a bucket-scoped policy, a lifecycle rule to expire old results, TLS on the endpoint.

📖 [Integrations index](https://docs.rustfs.com/en/developer/integration) · [Airflow](https://docs.rustfs.com/en/developer/integration/big-data/airflow) · [Iceberg](https://docs.rustfs.com/en/developer/integration/big-data/iceberg) · [DuckDB](https://docs.rustfs.com/en/developer/integration/database/duckdb) · [Spark](https://docs.rustfs.com/en/developer/integration/big-data/spark) · [lakeFS](https://docs.rustfs.com/en/developer/integration/storage/lakefs) · [Terraform state](https://docs.rustfs.com/en/developer/integration/devops/terraform) · [rclone](https://docs.rustfs.com/en/developer/integration/others/rclone) · [prefect-aws](https://docs.prefect.io/integrations/prefect-aws/index)

---

## 10. Moving data in and out

- **Migration and coexistence:** the project says it supports running alongside other S3 platforms such as MinIO and Ceph. The practical tools are `rclone sync`, bucket replication (versioned buckets) and application-level dual writes.
- **Validate a migration:** compare object counts, sizes and checksums; test presigned URLs, multipart behaviour, listing order and any ACL or logging features you used, because those are the documented gaps.
- **Do not copy encrypted objects raw** between implementations (not portable); decrypt and re-encrypt through the S3 API.
- **Exit plan:** because the API is S3, leaving RustFS later is an `rclone` job, which is a point in its favour. Keep that tested.

---

## 11. Should you use RustFS? (the part to challenge)

<table id="bkmrk-situationverdictloca"><thead><tr><th>Situation</th><th>Verdict</th></tr></thead><tbody><tr><td>Local dev and CI needing an S3 endpoint</td><td>**Good fit.** One container, quick to start</td></tr><tr><td>Self-hosted S3 for logs, artefacts, backups, ML datasets where a permissive licence matters</td><td>**Reasonable**, after your own load and failure tests</td></tr><tr><td>Data lake or lakehouse storage with Iceberg or Delta</td><td>**Plausible**; documented integrations exist, but pilot with your engines and table sizes</td></tr><tr><td>Regulated or business-critical primary storage</td><td>**Proceed carefully.** Confirm KMS maturity, Object Lock behaviour, support terms and your recovery drills</td></tr><tr><td>Need full AWS S3 feature parity (ACLs, access logging, every multipart listing edge)</td><td>**Not a fit** where those are documented as excluded or planned</td></tr><tr><td>Cloud-native workload already on a managed S3</td><td>Staying on the managed service removes operations; self-host only for cost, sovereignty or latency reasons</td></tr></tbody></table>

**Questions to answer before adopting:** (1) Is the benefit the licence, the cost, performance, or Rust itself, and have you measured it? (2) Who is on call when a node dies at 3 a.m.? (3) Have you rehearsed a disk and node replacement and a restore? (4) What is the backup strategy beyond erasure coding? (5) How mature is the release you pin, and what is the upgrade policy? Pin a version rather than using `:latest` in production.

---

## 12. Trap checklist and exercises

1. Default credentials; Console exposed publicly.
2. Bind-mount directory not owned by UID 10001.
3. Believing EC:4 equals four-node tolerance.
4. Pinning parity that the narrowest pool cannot satisfy (startup fails), or setting a set width that does not divide the topology.
5. SNSD or SNMD treated as production, with no backup.
6. Replication configured without versioning; async replication assumed to be lossless.
7. Relying on ACLs, access logging or encrypted-object portability.
8. Using `:latest`; no upgrade rehearsal; no restore test.
9. Windows build used in production.

**Exercises.** (1) Start the Docker command with unique credentials, create a bucket and upload a file with the AWS CLI using `--endpoint-url`. (2) Enable versioning, overwrite the file, and recover the first version. (3) Compute usable capacity for 8 nodes x 4 x 8 TiB drives if sets are 16 wide with EC:4, and say what a node loss does to a set. (4) Add a lifecycle rule to expire objects under `tmp/` after one day and verify. (5) Run a write/read round trip from a Python script with boto3 and a presigned URL.

<details id="bkmrk-solution-notesuse-aw"><summary>Solution notes</summary>

1. Use `aws --endpoint-url http://localhost:9000 s3 mb s3://demo`, then `cp`; configure the CLI with the access key pair you set.
2. Versioning is a per-bucket setting; list versions to see both, then fetch by version ID or remove the delete marker.
3. Raw is 8 x 4 x 8 = 256 TiB; with a 16-wide set and EC:4 efficiency is 75%, so about 192 TiB before overhead. Whether a node loss is survivable depends on how many of a set's 16 drives sit on that node: if a node holds 4 drives of each set, losing it removes 4 shards, which EC:4 can reconstruct, with no margin left.
4. Lifecycle rules are managed with `rc`; confirm by checking the object disappears after the scanner or lifecycle cycle runs.
5. boto3 needs `endpoint_url`; `generate_presigned_url('get_object', ...)` gives a URL you can fetch with curl.

</details>---

**Sources:** docs.rustfs.com: [docs home](https://docs.rustfs.com/en), [installation](https://docs.rustfs.com/en/installation), [Docker](https://docs.rustfs.com/en/installation/container/docker), [EC configuration](https://docs.rustfs.com/en/installation/requirement/ec-configuration), [S3 compatibility matrix](https://docs.rustfs.com/en/reference/s3-compatibility), [S3 protocol](https://docs.rustfs.com/en/administration/protocols/s3), [docs index](https://docs.rustfs.com/llms.txt); [GitHub README](https://github.com/rustfs/rustfs) (claims). Sections 6-8 summarise the documentation index descriptions rather than every page body; items marked ⚑ are unverified.