Safebucket: self-hosted file sharing where uploads bypass the server
On-prem file sharing made simple, fast and safe.
At a glance
- What is it?
- Safebucket is an Apache-2.0 Go and React file sharing platform that hands clients presigned URLs so file bytes never pass through the application. Here is how its pluggable infrastructure works, how to run the lite compose stack, and where the design still leaves gaps.
- Who is it for?
- Safebucket fits teams that already run S3-compatible object storage and want share links, OIDC login and audit logs without paying per-seat for a hosted service. It is a poor fit for anyone who wants a single binary with local disk and no object store, because the storage layer is the thing the design is built around.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 4 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem Safebucket solves for on-prem teams
Most self-hosted file sharing tools put the application server in the middle of every transfer. A user uploads a 4 GB video, the request lands on the Go or Node process, the process writes to disk or streams to object storage, and the server's bandwidth, memory and connection pool carry the whole file twice. That works at small scale and falls over at medium scale, because the bottleneck is the application tier rather than the network or the storage.
Safebucket takes the opposite position. The README describes it as "an open source file sharing platform with pluggable infrastructure where files bypass the server". The server issues presigned URLs and tracks metadata; the bytes move between the client and the storage backend directly. That single decision shapes the rest of the product.
The audience is an operations or platform team that already runs object storage, wants share links with passwords, download limits and expiry, and needs SSO through an existing OIDC provider rather than another local user table. The feature list covers role-based access control at platform and bucket level, TOTP multifactor authentication, trash with configurable retention, audit logs and an admin dashboard. It is aimed at internal deployments, not at replacing a public consumer service.
How the presigned URL flow and pluggable backends fit together
The architecture diagram in the repository shows a high-level design rather than a call trace, but the dependency list in go.mod makes the shape of the system fairly clear. The HTTP layer is chi, configuration is Koanf with YAML, environment and file providers, migrations run through Goose, and events go through Watermill, which has adapters for AWS, Google Cloud and NATS in the module graph. Persistence is Gorm with a SQL backend, and the cache client is rueidis, which speaks to Redis.
Storage is the interesting part. The module list includes the AWS SDK v2 S3 client, the MinIO Go client, Google Cloud Storage, and the Azure blob and queue SDKs. So the storage abstraction is not a thin wrapper around one provider; it is a port with several real implementations behind it. The same pattern applies to events, cache and notifier, which is what the README means by swappable infrastructure: each component is meant to be replaceable at deployment time rather than by patching the source.
The data flow follows from that. A client asks the API for an upload target, the API checks permissions and returns a presigned URL, the client PUTs the object straight to the bucket, and the metadata row is written on the application side. Downloads work the same way in reverse. The consequence is that the application server's CPU and memory scale with the number of metadata operations, not with the size of the files. It also means the storage backend must be reachable from the client's network, which is a network design constraint rather than a code one.
Search is handled by Bleve, an embedded Go search index, so full-text search over file metadata does not require a separate search cluster. That is a reasonable choice for a single-node deployment and a question mark for a multi-replica one, since the index is embedded in the process.
Running the lite compose stack and logging in for the first time
The README's Quick Start points at a lite deployment under deployments/local/lite. Clone the repository, change into that directory, and bring the stack up with Docker Compose.
git clone https://github.com/safebucket/safebucket.git
cd safebucket/deployments/local/lite
docker compose up -dOnce the containers are running, the web interface is served on port 8080. The README gives the seeded credentials as [email protected] with the password ChangeMePlease. Those are published in the repository, so they are a first-login credential and nothing more.
If the browser is not on the same machine as the containers, the README calls out four environment variables in the .env file that must be changed to the host's IP or domain: STORAGE__RUSTFS__EXTERNAL_ENDPOINT, APP__ALLOWED_ORIGINS, APP__API_URL and APP__WEB_URL. The first one matters most, because the presigned URL returned to the browser has to be resolvable from the browser. A stack that works on localhost will produce broken upload links the moment a colleague opens it from another machine, and the failure looks like a storage error rather than a configuration one.
The double-underscore naming is Koanf's nesting separator, so STORAGE__RUSTFS__EXTERNAL_ENDPOINT maps to a storage.rustfs.external_endpoint key in the YAML configuration. If you deploy outside the lite compose file, expect to supply the same values through the file provider or environment variables, since the README documents configuration only through that local example.
For image provenance, the README states that all published container images are signed with cosign using keyless signing through GitHub Actions OIDC, with no manual keys involved. Verification is a single command against the registry:
cosign verify \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity-regexp=https://github.com/safebucket/safebucket/ \
ghcr.io/safebucket/safebucket:<tag>Replace the tag with the release you intend to run. The repository's most recent releases at the time of writing are v0.7.5, v0.7.4 and v0.7.3, all from late August and early September 2026, so the tag you pick should be a release tag rather than latest if you want reproducibility.
Where the design creates friction
The presigned URL model is not free. Every deployment needs object storage that clients can reach directly, which rules out the simplest single-container setups where the application owns a local directory. The RustFS endpoint variable in the lite compose file exists precisely because the storage service has to be addressable from outside the compose network.
Configuration is the second friction point. The README documents exactly one deployment path and four variables within it. Anything beyond that, including how to point the platform at AWS S3, Google Cloud Storage or Azure Blob, is left to the documentation site rather than the repository. The Go module list shows those backends are supported in code, but the README does not walk through their configuration, so an operator moving from the lite stack to a production backend is working from the docs site, not from the repository.
Embedded Bleve search is a third constraint. Because the index lives inside the application process, running multiple API replicas means each replica has its own view of the index unless something else coordinates it. The repository does not describe a coordination mechanism, so horizontal scaling of the API tier is an area to verify against your own deployment rather than assume.
Finally, the seeded admin account is a documented default. Any deployment reachable from a network you do not fully control needs that password changed before anything else, and the README does not describe a forced rotation on first login.
Safebucket compared with Nextcloud and plain MinIO
The obvious comparison is Nextcloud, which also offers self-hosted file sharing with share links, expiry and access control. The difference is architectural. Nextcloud is a PHP application that handles file transfers through its own web tier, with a database and optional object storage behind it; the application is the path the bytes take. Safebucket inverts that, using presigned URLs so the application only brokers permissions and metadata. For a team whose transfers are large or frequent, that is a meaningful difference in what the application servers have to do. For a team that wants a mature ecosystem of apps, calendars, contacts and desktop clients, Nextcloud is far broader, and Safebucket's README does not claim to compete on that surface.
The second comparison is running MinIO or another S3-compatible store directly with hand-rolled presigned URLs. That gives you the same bypass property with no application at all, and it is a legitimate answer for a small team. What Safebucket adds on top is the layer MinIO does not provide: OIDC login, roles at platform and bucket level, TOTP, share links with password and download limits, trash retention, audit logs and an admin dashboard. If none of those matter to you, the platform is overhead. If they do, writing them yourself against the S3 API is the alternative you are weighing against.
A third option worth naming is a hosted service. Safebucket's argument against that is the on-prem requirement itself: the data stays in storage you control, and the deployment is a compose file rather than a vendor account.
Maintenance, releases and the Apache-2.0 licence
The repository is not archived, and the last push was on 2026-09-07. Releases v0.7.3 through v0.7.5 landed within roughly two weeks of each other in late August and early September 2026, which suggests a steady patch cadence at the 0.7 line rather than a frozen codebase. The version numbers still start with zero, so treat the API and configuration surface as pre-1.0 and read the release notes before upgrading.
Upgrades are container swaps in the compose deployment, but the migration story matters more than the image pull. The project uses Goose for database migrations, and the README does not document a rollback procedure. If a migration is not reversible, downgrading the image is not a safe operation, so the practical approach is to back up the database before each upgrade and verify the migration direction in the Goose files rather than assume it can be undone.
On licensing, the repository is Apache-2.0, which permits commercial use, modification and redistribution provided the licence and notices are preserved. That is a permissive licence with an explicit patent grant, and it does not carry the network-service copyleft obligations of AGPL projects in this space. The repository also notes that the UI is built on Radix UI and shadcn/ui, which carry their own licences, so a redistribution that bundles the frontend should check those separately. This is a description of the licence text, not legal advice.
The Dockerfile builds a distroless runtime image running as a non-root user, which reduces the container's attack surface and also means there is no shell inside the image for interactive debugging. Plan on logs and metrics rather than exec sessions.
Editorial conclusion
Safebucket fits teams that already run S3-compatible object storage and want share links, OIDC login and audit logs without paying per-seat for a hosted service. It is a poor fit for anyone who wants a single binary with local disk and no object store, because the storage layer is the thing the design is built around. Before adopting it, read the compose file in deployments/local/lite, change the seeded admin credentials and the four host-dependent environment variables, and confirm your OIDC provider's issuer and client settings match what the configuration expects.
Frequently asked questions
What is Safebucket and who is it for?
Safebucket is an open source file sharing platform built with Go and React, licensed under Apache-2.0. It targets teams that want to self-host file sharing on infrastructure they control, with OIDC single sign-on, role-based access control and share links that support passwords, maximum downloads and maximum views.
How do I install Safebucket and log in for the first time?
The README's Quick Start clones the repository, changes into deployments/local/lite and runs docker compose up -d. The web interface is then available on port 8080, and the documented first login is [email protected] with the password ChangeMePlease.
Why do uploads bypass the Safebucket server?
The platform issues presigned URLs, so the client transfers file data directly to the storage backend while the application only handles metadata and permissions. The README describes this as direct uploads and downloads via presigned URLs, and it is the reason the storage endpoint must be reachable from the client's network.
Which storage backends does Safebucket support?
The go.mod file lists clients for AWS S3, MinIO, Google Cloud Storage and Azure Blob, and the README describes storage as one of the swappable components alongside database, events, cache and notifier. The README itself only documents the local lite deployment, so backend-specific configuration is left to the documentation site.
What should I change before exposing Safebucket to other machines?
The README states that deployments accessed from an external machine must update STORAGE__RUSTFS__EXTERNAL_ENDPOINT, APP__ALLOWED_ORIGINS, APP__API_URL and APP__WEB_URL in the .env file with the host's IP or domain. The seeded admin password is published in the repository and should be changed as well.
How can I verify that a Safebucket container image is authentic?
The README states that published images are signed with cosign using keyless signing through GitHub Actions OIDC, with no manual keys. It gives a cosign verify command that checks the certificate OIDC issuer and the certificate identity regexp against ghcr.io/safebucket/safebucket at the tag you want to verify.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/safebucket-safebucket)