OtterIO is a high-performance, S3-compatible object storage server. It is suitable for building infrastructure for machine learning, analytics, backup, and general application data workloads.
This README covers running OtterIO on bare metal, Docker, and from source. For deeper topics (erasure coding, distributed mode, KMS, replication, etc.) see the docs/ folder.
Important
OtterIO is an independent, community-maintained fork of the upstream Apache-licensed MinIO codebase. It is not affiliated with, endorsed by, or sponsored by MinIO, Inc. See Trademark & Upstream Notice and the Security Advisory before deploying.
OtterIO is a customized fork of the last Apache License 2.0 release of MinIO (≈ RELEASE.2021-04-22T15-44-28Z). It differs from upstream in the following ways:
- HTTP layer — request router built on
gofiber/fiber/v3instead ofgorilla/mux. - Bucket notification targets — only
elasticsearch,mysql,postgresql,redis, andwebhookare supported. The message-queue targets (Kafka, NATS, NATS Streaming, NSQ, AMQP, MQTT) have been removed. - Gateways — only
nasands3remain. Theazure,gcs, andhdfsgateways have been removed. - Toolchain — requires Go
1.26or newer (seego.mod). - Container images — published at
soulteary/otterio(Docker Hub) andghcr.io/soulteary/otterio(GitHub Container Registry).
OtterIO continues to be distributed under the Apache License, Version 2.0. All original copyright notices are retained — see NOTICE.
Run a single-node OtterIO instance with Docker:
docker run -p 9000:9000 -p 9001:9001 \
-v /mnt/data:/data \
soulteary/otterio:latest server /data --console-address ":9001"Default root credentials are otterioadmin:otterioadmin. Once running, see Verify to connect via the web console or mc.
Note
Standalone OtterIO servers are best suited for development and evaluation. Production deployments should run distributed mode with Erasure Coding enabled — at least 4 drives per server. See docs/erasure/README.md and docs/distributed/README.md.
OtterIO publishes container images to both Docker Hub and the GitHub Container Registry:
# Docker Hub
docker pull soulteary/otterio:latest
# GitHub Container Registry
docker pull ghcr.io/soulteary/otterio:latest| Tag | Description |
|---|---|
latest |
Latest stable release. |
edge |
Bleeding-edge build from main — for testing only. |
Run a standalone server with an ephemeral volume:
docker run -p 9000:9000 soulteary/otterio:latest server /dataFor persistent storage, map a host directory to /data:
docker run -p 9000:9000 -v /mnt/data:/data soulteary/otterio:latest server /databrew install otterio/stable/otterio
otterio server /dataIf you previously installed OtterIO from a different tap, reinstall from the official tap:
brew uninstall otterio
brew install otterio/stable/otterioPre-built macOS binaries are published on GitHub Releases. Download the appropriate archive, then:
chmod +x otterio
./otterio server /dataPre-built Linux binaries are published on GitHub Releases. Download the asset that matches your architecture and run it as otterio:
chmod +x otterio
./otterio server /dataThe release pipeline (.goreleaser.yml) currently produces Linux binaries for the following architectures:
| Architecture | goarch |
|---|---|
| 64-bit Intel/AMD | amd64 |
| 64-bit ARM | arm64 |
| 64-bit PowerPC LE | ppc64le |
.deb and .rpm packages are also produced for the supported architectures.
Pre-built Windows binaries (amd64) are published on GitHub Releases. After downloading otterio.exe, run it from the directory where it lives, or add that directory to the system PATH:
otterio.exe server D:\OtterIO does not currently provide an official FreeBSD package. Build from source on FreeBSD using the Build from Source instructions below.
Source builds are intended for developers and advanced users. Make sure you have a working Go toolchain (Go 1.26 or newer — see How to install Go).
git clone https://github.com/soulteary/otterio.git
cd otterio
make build
./otterio server /dataWarning
We strongly recommend against running compiled-from-source binaries in production. Use a tagged release for production deployments.
By default the web console and the S3 API share the listener bound to --address. OtterIO can serve the web UI and admin API on a dedicated port so that reverse proxies, firewalls, and network policies can govern S3 traffic and console traffic independently.
Enable the dedicated console listener via the --console-address flag or the OTTERIO_BROWSER_ADDRESS environment variable:
# CLI flag
otterio server --address ":9000" --console-address ":9001" /data
# Environment variable (equivalent)
export OTTERIO_BROWSER_ADDRESS=":9001"
otterio server --address ":9000" /dataWhen the dedicated console listener is enabled:
:9000only serves the S3 API, STS, health, and metrics. Browser requests are no longer redirected to the web UI.:9001serves the web console (/otterio/) and the admin API (/otterio/admin/v3/*).- The console port must differ from the S3 port; otherwise startup fails fast.
Ctrl+C/SIGTERMshuts down both listeners gracefully.
Note
The admin API (used by mc admin ...) is served from the console port in this mode. Configure your mc alias to point at the console URL when issuing admin commands. Regular S3 operations (mc cp, mc ls, etc.) continue to use the S3 port.
If --console-address is not provided, both surfaces share a single port (the original behaviour).
When you split listeners, you can also point the console at its own TLS keypair so the S3 API and the web console can use different certificates (e.g. an internal CA-signed cert for :9000 and a public cert for :9001). Use --console-certs-dir or OTTERIO_BROWSER_CERTS_DIR:
otterio server \
--address ":9000" \
--console-address ":9001" \
--certs-dir /etc/otterio/certs/s3 \
--console-certs-dir /etc/otterio/certs/console \
/dataThe directory pointed to by --console-certs-dir must contain public.crt and private.key, the same layout used by --certs-dir. Notes:
--console-certs-dirrequires--console-address; otherwise startup fails fast.- If
--console-certs-diris not set, the console listener reuses the certificates loaded from--certs-dir(the legacy behaviour). - The S3 listener always uses
--certs-dir; only the console listener honours--console-certs-dir. - Both keypairs are watched and hot-reloaded by the same certificate manager used for
--certs-dir.
By default OtterIO listens on port 9000 for S3 traffic (and 9001 if the console listener is split out). Some platforms block these ports until you explicitly open them.
ufw (Debian / Ubuntu)
ufw allow 9000
# Range
ufw allow 9000:9010/tcpfirewall-cmd (CentOS / RHEL)
firewall-cmd --get-active-zones
firewall-cmd --zone=public --add-port=9000/tcp --permanent
firewall-cmd --reload--permanent makes the rule persist across reboots and reloads.
iptables (RHEL, CentOS, etc.)
iptables -A INPUT -p tcp --dport 9000 -j ACCEPT
service iptables restart
# Range
iptables -A INPUT -p tcp --dport 9000:9010 -j ACCEPT
service iptables restartWhen deployed on a single drive, OtterIO server lets clients access any pre-existing data in the data directory. For example, if OtterIO is started with otterio server /mnt/data, any pre-existing data in /mnt/data is accessible to clients. The same applies to all gateway backends.
Once OtterIO is running, the deployment uses default root credentials otterioadmin:otterioadmin (override via MINIO_ROOT_USER / MINIO_ROOT_PASSWORD environment variables in production).
Point a browser at http://127.0.0.1:9000 (or the console port if you split listeners). Log in with the root credentials to create buckets, upload objects, and browse contents.
mc is a modern command-line client that speaks S3 and local filesystem URIs (similar to ls, cp, mirror, diff, etc.). Configure an alias against your OtterIO endpoint:
mc alias set local http://127.0.0.1:9000 otterioadmin otterioadmin
mc mb local/test-bucket
mc cp ./somefile local/test-bucket/
mc ls local/test-bucket/OtterIO is wire-compatible with the AWS S3 API, so aws-cli, s3cmd, and the various AWS SDKs all work out of the box — point them at your OtterIO endpoint with the root credentials (or an IAM-issued access key).
- Erasure Coding
- Distributed mode
- Multi-user / IAM
- STS — temporary credentials
- TLS
- KMS
- Bucket notifications
- Bucket replication
- Bucket lifecycle / retention / versioning / quota
- Metrics & Prometheus
- Logging
- Docker · Orchestration
- Security advisories backlog
- LDAP DN normalisation migration
- Limits
The links below point to the original upstream MinIO project's documentation. They remain useful as background reading on S3-compatible workflows, but they describe upstream MinIO behaviour and are not maintained by OtterIO:
- Erasure Code Quickstart Guide (upstream)
mcClient Quickstart (upstream)aws-cliwith MinIO (upstream)s3cmdwith MinIO (upstream)- Go SDK Quickstart (upstream)
Contributions are welcome via the project repository at https://github.com/soulteary/otterio. For coding conventions inherited from the upstream baseline, see the original Contributor's Guide.
Click to expand — please read before deploying.
Because OtterIO is forked from the last Apache 2.0 release of MinIO (≈ RELEASE.2021-04-22T15-44-28Z), every CVE / GHSA published against upstream minio/minio after that date must be evaluated and back-ported separately. OtterIO does not automatically inherit those fixes.
Backlog status (as of 2026-06): 14 closed, 2 not-applicable, 0 open. Every advisory currently triaged against the post-2021-04 baseline has been resolved on main — see docs/security/upstream-cve-backlog.md for the per-item table with the OtterIO codepath, the upstream reference, and the regression tests pinning each fix. New upstream advisories will be added with status Pending and tracked from there.
Operators upgrading from a previous OtterIO build that used LDAP should consult docs/security/ldap-dn-normalization-migration.md before rolling out: the new release canonicalises every LDAP DN before it touches the IAM policy map, which is a one-shot breaking change for deployments that happened to rely on case-only DN differences.
Before adopting OtterIO, please evaluate fitness against your own deployment context — workload profile, capacity / throughput targets, compliance and data-residency requirements, supported-version policy, and your organisation's change-management expectations. As with any infrastructure component, we recommend a staged rollout (lab → staging → production) and validating the relevant codepaths against your own regression suite. See SECURITY.md for the disclosure policy and the supported-versions matrix.
Relative to the 2021-04-22 Apache-licensed MinIO baseline OtterIO has back-ported and (where applicable) hardened the following upstream advisories — full per-item context, codepaths, and regression tests live in docs/security/upstream-cve-backlog.md:
- SSE metadata injection (GHSA-3rh2-v3gr-35p9 class) — reserved-prefix metadata is rejected at both the router edge and
extractMetadata. - Precondition GET / HEAD metadata disclosure (GHSA-95fr-cm4m-q5p9 / CVE-2024-36107) —
s3:ExistingObjectTag/*ands3:RequestObjectTag/*are now first-class condition keys, and the precondition path re-runs auth before writingETag/Last-Modifiedso a tag-gated deny no longer leaks object state. - SSE-KMS context binding (multiple post-2022 CVEs) — bucket / object AAD is reconstructed from the runtime
(bucket, object)on every seal and unseal, hostile or tamperedMetaContextblobs are rejected with a dedicated 403 sentinel before the KMS is ever called, and the seven legacyErrNotImplementedPUT-handler stubs have been replaced with a singleenforceSSEKMSRequestsecurity gate covering single-PUT, multipart, copy and post-policy paths. - Service-account privilege escalation —
GHSA-jjjj-jwhf-8rgr(own-account create-SA bypass), the RELEASE.2025-10-15 sub-policy escalation, andGHSA-xx8w-mq23-29g4 / CVE-2024-24747(admin:UpdateServiceAccount) are all closed; sub-policies must be a subset of the caller's capability. AddUserPolicyName privilege escalation (CVE-2021-43858) — defence-in-depth at both the handler (HTTP 400) and IAM-layer (silent strip).- LDAP DN normalisation family (2022–2024 advisories) — RFC 4514 + RFC 4518 canonicalisation at every DN egress and at the IAM boundary, with a one-shot persisted-data migration; see the migration note linked above.
- Bucket / IAM policy parsing —
Principal/Resource/Actionunmarshal panics fixed, attacker-controlled input no longer reflected into error messages, fuzz corpus added. - SigV4 signed-headers and chunked-upload hardening — empty
X-Amz-Content-Sha256is treated as "not provided" instead of coercing the canonicaliser,SignedHeadersis case-folded, and aws-chunked uploads must signx-amz-decoded-content-length. - Replication-header IAM gate — fork-private
X-Otterio-Source-*headers now require thes3:ReplicateObjectaction viaenforceSourceHeaderIAM, closing a forge path that could rewrite object mtime / ETag or force delete-markers under ordinarys3:PutObject/s3:DeleteObjectpermissions. - CVE-2023-28432 bootstrap info disclosure —
VerifyHandleris now gated on the same inter-node JWT validator used by peer-rest / storage-rest / lock-rest; onlyHealthHandlerremains anonymous. - Multi-value
Hostheader smuggle (fork-introduced concern) — audited and pinned: both fasthttp and net/http collapse or reject duplicate Host headers before any handler runs, and SigV4 reads only the scalarr.Host, so the two-header smuggle is not constructible.
Two further upstream advisories (CVE-2021-41137 regular-user policy bypass and GHSA-cwq8-g58r-32hg ImportIAM privilege escalation) are not applicable to the 2021-04 baseline — see the backlog for the audit trail and the negative-pinning regression tests.
Click to expand
OtterIO is an independent, community-maintained fork of the upstream Apache-licensed MinIO codebase. This project is not affiliated with, endorsed by, or sponsored by MinIO, Inc.
"MinIO" is a trademark of MinIO, Inc., used here solely to identify the upstream project from which this fork is derived. No trademark rights are granted by the Apache License 2.0 (see Section 6 of the license).
OtterIO is based on the last Apache License 2.0 release of MinIO, prior to MinIO's relicensing to the GNU AGPLv3, and remains distributed under the Apache License, Version 2.0. The original copyright notices of MinIO, Inc. and all third-party subcomponents are retained — see NOTICE.
OtterIO publishes its own container images at soulteary/otterio (Docker Hub) and ghcr.io/soulteary/otterio (GitHub Container Registry). Other links in this guide pointing to docs.min.io, dl.min.io, etc. still refer to the original upstream project, not to OtterIO. Build OtterIO from source (see Build from Source) to use the OtterIO customizations.
Project home: https://github.com/soulteary/otterio
OtterIO is governed by the Apache License, Version 2.0, found at LICENSE. Attribution and third-party notices are listed in NOTICE.
"MinIO" is a trademark of MinIO, Inc. OtterIO is not affiliated with, endorsed by, or sponsored by MinIO, Inc.

