Issue #120 routes an existing SSE-C replica through PutObjectHandler and NewMultipartUploadHandler. On main those handlers assigned the incoming retention and legal hold directly, without the source-timestamp ordering #111 added to CopyObjectHandler and without persisting the ordering timestamps, so in active-active replication a retransmit carrying an older value could overwrite a destination version's newer lock state. Share #111's ordering decision as applyReplicatedObjectLock in cmd/bucket-object-lock.go and call it from CopyObject, PUT and multipart initiation. A request that is not an actual trusted replica keeps ordinary write semantics (a validated value is applied and stamped now); only a real replica update is ordered against the stored version, so a marker-only peer write no longer drops a validated hold or default retention. CopyObject keeps its SSE-C key-rotation encMetadata reconciliation inline. putReplicationOpts now emits a stored retention ordering timestamp even when the value keys are absent, so a removal recorded on the retransmit PUT path still replicates onward. replicateAll marks Failed and carries the error when putReplicationOpts fails. The handler decision is made against the version as it stands then, which a concurrent lock update can outrun before the write commits, and for multipart across the whole initiation-to-completion span. Close that window under the object write lock the receiving erasure set holds: a trusted SSE-C replica full write sets ObjectOptions.ReplicaLockReconcile, and erasureObjects.PutObject and CompleteMultipartUpload re-run the ordering (reconcileStoredObjectLock, which orders retention and legal hold independently by their reserved timestamps) against the destination version read on that set before committing. Persisted upload metadata records the null version as an empty VersionID, so completion looks that up as the null version rather than the latest. The reconcile runs only against an existing version; a not-found destination keeps the write's own accepted lock, including a pre-upgrade upload that persisted values without ordering timestamps, and a non-not-found read error fails the write. Scoped to the SSE-C paths this issue enables; CopyObject is left as #111 wrote it. Scope: this orders Object Lock against the destination version under the write lock and is correct for a single erasure set. A multi-pool deployment -- where a version can have duplicate copies across pools, object ModTime ties do not track per-field lock timestamps, and the object namespace lock is per-pool -- needs a cross-pool lock-safe reconcile and is deliberately out of scope here, tracked in pgsty/silo#TBD-multipool-lock. Tests: TestAPISSECReplicaRetransmitObjectLockOrdering and its multipart sibling; TestAPIReplicaMultipartNewerHoldSurvivesCompletion and TestReplicaPutObjectLockReconcileUnderWriteLock (a hold or retention reaching the version after the handler decision, or after multipart initiation, survives the commit; a pre-upgrade upload on an absent version keeps its lock); TestReplicaLockReconcileNullVersion (a null-version completion reconciles the null version, not a coexisting UUID version, and an absent null version keeps its accepted lock); TestAPIReplicaMarkerOnlyAppliesObjectLock; TestReplicaStoredLock; the timestamp-only putReplicationOpts round trip; and the retransmit, exemption and target-head tests. The #111 CopyObject replica suite and the existing #120 suite stay green, as do the PUT/multipart handler and object-layer regression suites. Compatibility: the shared helper preserves #111's CopyObject behavior; a non-replica PUT or multipart initiation that sets Object Lock now also stamps the reserved ordering timestamp, matching CopyObject since #111; only trusted SSE-C replica writes take the in-lock reconcile. Refs pgsty/silo#120 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L7qJqWwy8oFA6aCXWRzXQe Signed-off-by: Feng Ruohang <rh@vonng.com>
S3-compatible object storage — a MinIO fork maintained by PGSTY
Website · Documentation · Download · Release Notes · Compatibility · Manifesto · Security · 中文
Important
PGSTY Silo (hereinafter “Silo”) is an independent, community-maintained fork of the open-source MinIO server, published by Pigsty from
pgsty/silo. It is not affiliated with, endorsed by, or sponsored by MinIO, Inc. “MinIO” is used only to identify the upstream project and compatibility lineage.
Note
Renamed from
pgsty/miniotopgsty/silo, default branchmaster→main, on 2026-08-06. Artifacts under the original MinIO identity stay published on the archivedminiobranch and in releases up toRELEASE.2026-08-04T00-00-00Z.
Overview
PGSTY SILO keeps one maintained release line of the open-source MinIO server alive after upstream ended community distribution: builds, packages, multi-arch images, security fixes, and the full web console. Pigsty runs it in production as its PostgreSQL backup repository.
It follows one rule — the product and its delivery surfaces are renamed; the protocol and your data are not. Everything else lives on silo.pgsty.com.
Related: pgsty/mc client (shipped as mcli) · pgsty/silo-console · pgsty/silo-pkg · pgsty/pigsty
Quick Start
docker run -d --name silo -p 9000:9000 -p 9001:9001 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=change-me-long-password \
-v "$PWD/data:/data" \
docker.io/pgsty/silo:latest server /data --console-address ":9001"
Console on http://localhost:9001, S3 API on http://localhost:9000. The image bundles the client as mcli:
docker exec silo mcli alias set local http://127.0.0.1:9000 minioadmin change-me-long-password
docker exec silo mcli mb local/demo && docker exec silo mcli ls local
Warning
For production, pin a release, use unique credentials and TLS, monitor the service, keep independent backups, and test recovery. Start from the documentation.
Install
| Method | Where |
|---|---|
| Container | pgsty/silo, multi-arch for linux/amd64 and linux/arm64 |
| Binaries | GitHub Releases — Linux, macOS, Windows on amd64 and arm64 |
| Packages | RPM, DEB, and APK, also via the Pigsty repository |
| Kubernetes | Helm chart, see Download & Install |
| Source | go build -o silo . && ./silo --version |
Every release ships checksums, SPDX SBOMs, Sigstore-signed manifests, and GitHub build attestations. Installation methods and verification commands are documented at Download & Install; migrating from upstream MinIO — taking over an existing minio.service and its /etc/default/minio, and keeping data ownership stable with a /etc/systemd/system/silo.service.d/10-legacy-user.conf drop-in — is covered by the migration guide and the binary & service notes.
Compatibility
The S3 API, MINIO_* variables, minio_* metrics, x-minio-* headers, /minio/* routes, the github.com/minio/* import paths, and the on-disk format (including .minio.sys) are preserved and held in place by a CI compatibility check. Only Silo-owned delivery surfaces change: the silo executable, package, service, Helm chart, and container image — no minio binary alias is installed.
Every divergence from upstream is listed in the code-verified compatibility audit. Treat each release as a downstream upgrade: pin versions, read the release notes, and keep a rollback path.
Security & Contributing
Report vulnerabilities privately as described in SECURITY.md; every fix ships with a public advisory. Contributions are accepted inbound=outbound under AGPL-3.0-or-later with no CLA — only DCO sign-off (git commit -s) is required; see CONTRIBUTING.md.
Contributors
The cards highlight community changes merged into main; the avatar wall includes every other
community member who has opened an issue or pull request.
![]() @h5vx Per-bucket CORS · #71 |
![]() @ycjlin Missing-bucket listing · #37 |
![]() @Dansyuqri Multipart checksum type · #57 |
![]() @pinginfo Notification streaming · #34 |
![]() @ZouhairCharef CVE-2026-34986 · #18 |
![]() @mfredenhagen CVE-2026-39883 · #19 |
![]() @waterkip Documentation links · #41 |
GitHub does not generate a contributor graph for forks, so CONTRIBUTORS.md — not the Insights page — is this project's attribution record. It names all 37 community contributors alongside the change or report they contributed.
Background
Upstream wound down its community edition: the web console was cut back to a stub, prebuilt community binaries stopped, and the community repository was archived. Silo exists to keep those deployments running. The fork is a means, not an identity — if upstream restores its community edition, we will narrow our scope and offer the fixes back.
The Manifesto is the project's public commitment in eleven articles, under one discipline: every article is either something already done with public evidence, or something explicitly refused. In short:
- Compatibility contract — the protocol and your data do not change, and every release documents its tested rollback target and path.
- The license cannot change — AGPLv3, no CLA, no copyright aggregation; nobody here, ourselves included, holds enough copyright to relicense on everyone else's behalf.
- The never list, append-only — no paywalling existing features, no registration wall on downloads, no telemetry (upstream's phone-home paths are removed outright), no CLA, no license change, no trademark enforcement against normal use.
- Security and release discipline — a public advisory for every fix, and a release every one to two months, at most a quarter apart. Judge both against the public record.
Essays: MinIO Is Dead · Who Takes Over? · Long Live MinIO · Promise Kept
License & Trademark
Silo is AGPL-3.0-or-later, derived from minio/minio with upstream copyright and third-party notices preserved in NOTICE and CREDITS. MinIO is a trademark of MinIO, Inc.; the name is used here only to identify the upstream project and compatibility lineage.
Details: license · attribution · trademark








