Migrate from MinIO to Silo
Migrating from MinIO to Silo is an in-place binary replacement, not a data migration. Nothing is exported or re-imported. In a container deployment the only required change is the image name. For RPM/DEB installations, see Native Package Migration.
What changes
In order of importance:
- Container image:
minio/minio,quay.io/minio/minio, andpgsty/minioare all replaced bydocker.io/pgsty/silo. - Package, systemd service, and server executable:
minio→silo. - Upstream services: the in-place updater and MinIO-operated callhome/SUBNET are disabled; upgrades go through packages, images, or your orchestrator.
- Default OS service account:
silo— fresh installations only; migrations keep running as the existing data owner. - Default local configuration directory:
~/.minio→~/.silo(fresh processes only; see server compatibility for the certificate fallback order — an existing~/.minio/certskeeps being honored). - Branding: banners, Console appearance, log wording, and product links say Silo.
What stays
- Object data and the
.minio.sysmetadata directory — the on-disk format is unchanged and remains interoperable with MinIO in both directions. - Buckets, versions, users, access keys, policies, lifecycle rules, replication state, encryption metadata.
- S3 API, SigV4 signing, SDKs,
mc/mcli, presigned URL behavior. - Endpoint hostname, API port
9000, Console port, volume mounts. MINIO_*environment variables and existing server options./minio/*routes,x-minio-*headers,minio_*metrics.- Policy-namespace identifiers:
arn:minio:*ARNs,minio:s3and the other service namespaces in IAM policies, notifications, and audit events keep their exact spelling. There is noSILO_*alias namespace — scripts and policies addressing the identifiers above need no change.
There is no data-conversion step. If your MinIO build is years old, validate the version distance itself in staging; it is a large software upgrade, not a format change.
Docker migration
Whichever image you run today, replace it with:
Tags: immutable RELEASE.YYYY-MM-DDTHH-MM-SSZ (pin these), rolling latest, and the -distroless variants below. The old pgsty/minio repository stays published, frozen at its final tag.
In Compose, change only the image line:
The entrypoint translates the legacy first argument, so an inherited command: minio server /data keeps working. A hard-coded entrypoint: /usr/bin/minio must change to /usr/bin/silo. Existing mc ready local healthchecks keep working; the native replacement is test: ["CMD", "silo", "healthcheck", "ready"] (reference). Do not run docker compose down -v — -v deletes the data volume.
Distroless variant
pgsty/silo:<RELEASE-tag>-distroless ships the silo binary only: no shell, no mc, no curl. It has a built-in HEALTHCHECK (the native probe) and works under any --user:
The same deployment as a Compose file:
depends_on: condition: service_healthy works against it with no healthcheck: block. The volume format is the same as the classic image and MinIO — the variants are interchangeable over the same data. TLS certificates mount at /tmp/.silo/certs. If command-line flags move the listen address, point the built-in probe with MINIO_HEALTHCHECK_URL. There is no shell inside; debug with docker debug / kubectl debug.
Kubernetes
Kubelet probes are httpGet requests in the pod spec; Docker HEALTHCHECK is ignored, so both image variants are probed identically and existing probe configs keep working. For Helm releases, keep the release identity with nameOverride/fullnameOverride and compare helm template output before applying (details).
Rollback
The disk format is unchanged and works with both servers: set image: back to the recorded MinIO tag and docker compose up -d. The same volume stays attached, and data written by Silo remains readable by MinIO.
Upgrading from RELEASE.2026-08-06
The release after RELEASE.2026-08-06T00-00-00Z tightens several behaviors that 20260806 accepted. Check these before upgrading:
- Explicit version deletes need
s3:DeleteObjectVersion.DeleteObjectandDeleteObjectsentries that carry aversionIdare authorized ass3:DeleteObjectVersion, as on AWS. Grant it to principals that delete specific versions, and addDeny s3:DeleteObjectVersionnext to anyDeny s3:DeleteObjectthat is meant to block permanent deletes. - Enable and disable are separate admin actions.
admin:EnableUser/admin:DisableUserand the group equivalents are checked against the requested status; a policy that grants only one of them loses the other operation. - New and updated policies reject bare ARN prefixes such as
arn:aws:s3:::, and statements that combineResourcewithNotResource. Stored policies keep loading; automation that re-applies such policies fails. - Legacy database notification targets need a connection string. An enabled pre-KV PostgreSQL or MySQL target without
connection_string/dsn_stringstops startup with a credential-free error; 20260806 silently dropped every notification target in that situation. - Checksum requests are validated. Unknown
x-amz-checksum-*algorithms,CRC64NVMEcombined withCOMPOSITE, and checksum-type assertions that contradict the upload are rejected with400. The default behavior of the AWS SDKs,minio-go, andmcliis unaffected. - Per-bucket CORS is real. A bucket with its own CORS configuration is served by that configuration only;
MINIO_API_CORS_ALLOW_ORIGINapplies to buckets without one. In a site-replication group, configure bucket CORS only after every site runs the new release: older peers accept but ignore the configuration and keep reporting a CORS mismatch. - Rollback keeps the data readable. 20260806 ignores bucket CORS configuration and drops it when it rewrites that bucket’s metadata; recreate the configuration after upgrading again.
Console regressions in the September 3 release
RELEASE.2026-09-03T13-18-01Z stopped recognizing forwarded client addresses from unconfigured local proxies and discarded the four CONSOLE_WS_MAX_* connection settings. This can change IP Allow/Deny decisions and prevent operators from raising the eight-connection anonymous per-address limit.
Builds containing the fixes restore loopback TCP-peer trust for embedded Console unless MINIO_API_TRUSTED_PROXIES=none/off, and preserve all four limits from the environment or MINIO_CONFIG_ENV_FILE. Remote proxies still need an explicit IP/CIDR list. Standalone defaults, forwarded-chain trust rules and connection budgets remain unchanged; invalid configuration becomes a startup error. See Console settings for the policy table and configuration constraints. Track availability in #147 and #148; the 0903 image does not include these fixes.
On 0903, explicitly listing the local proxy peer in MINIO_API_TRUSTED_PROXIES restores client attribution, but also switches the S3 listener on port 9000 to listed mode; include its other required proxies too. Custom WebSocket limits require a fixed Server build or standalone Console.
One cluster, one binary
Distributed nodes verify each other’s binary at bootstrap. A node started among peers running a different binary does not fail — it waits indefinitely in activating, logging:
This applies to any pair of different binaries: MinIO next to Silo, and one Silo version next to another. So do not migrate — or later upgrade — a cluster node by node. Switch all nodes in one pass: stop the old binary everywhere, start the new one everywhere (in Compose: change the image for all nodes in one edit, docker compose up -d once). Single-node deployments are unaffected. The same applies to rollback. Rolling restarts of the same binary work normally; gate them with silo healthcheck --maintenance cluster (exit 0 = safe to stop this node).
Verification
Before touching anything, record the artifacts you are leaving behind: the running image digest (or package version and binary checksum), the unit status and enabled state, and the UID/GID that owns the data directory. Rollback is only as precise as that record.
Then download a known object and compare its checksum, exercise one application through its existing SDK, restart the service once, and re-check. One more rollback precondition: do not enable features in the migration window that the old version cannot understand — rolling back means rolling back to what the old binary can parse.