Safebucket: presigned-URL file sharing you host yourself
On-prem file sharing made simple, fast and safe.
At a glance
- What is it?
- Safebucket is a Go and React file sharing platform that keeps upload and download traffic off the application server by handing clients presigned URLs. The architecture is the selling point, and the deployment surface it creates is the cost.
- Who is it for?
- Adopt Safebucket if you want a self-hosted share layer whose storage backend you can swap and whose file bytes never transit the API process, and if you are willing to run its database, cache, event bus and notifier alongside it. Do not adopt it if you need a single-binary deployment or if you cannot expose your object storage endpoint directly to end users.
- 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 received new commits within the last day.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Safebucket picks, and the one it refuses to solve
Most self-hosted file sharing tools put the application server in the data path. A user uploads a 2 GB file, the API process receives every byte, writes it somewhere, and the same happens in reverse on download. That works until concurrency rises, at which point the API becomes a bandwidth appliance and you scale it for a job it was never meant to do. Safebucket's README states the design goal directly: files bypass the server through direct uploads and downloads via presigned URLs. The API issues a time-limited URL pointing at the storage backend, the client talks to storage, and the Go service handles metadata, permissions and audit records. The intended audience is an operator who already runs object storage and wants a sharing front end on top of it, not someone looking for a drop-in Drive replacement with bundled storage. That distinction matters because Safebucket does not hide the storage layer. It exposes it to clients, which is precisely why the bypass works and precisely why the deployment has a network requirement most file sharing tools do not.
What actually flows where when a client requests a file
The request path splits in two. Control traffic goes to the Go backend: authentication, bucket and file metadata, role checks, share link validation, and the generation of the presigned URL. Data traffic goes from the client straight to the configured storage backend. The backend never proxies the payload, so its CPU and memory profile is dominated by request handling rather than transfer. Around that core, the README lists components that can each be replaced: storage, database, events, cache and notifier. The acknowledgments name the libraries that make this swappable shape concrete. Gorm handles the ORM layer, Goose runs database migrations, Watermill provides pub/sub integrations, and Koanf handles configuration management. That combination is why configuration keys in the README carry a double-underscore namespace, such as STORAGE__RUSTFS__EXTERNAL_ENDPOINT and APP__ALLOWED_ORIGINS. Real-time activity tracking and audit logs sit on the event path, which is where Watermill's pub/sub would be involved. The repository also ships a high-level design diagram at assets/hld.png and a list view screenshot at assets/list_view.png, so the intended topology is documented rather than implied. What the README does not provide is a written description of the event schema or the exact ordering guarantees between a completed upload and the audit record that describes it. Anyone who needs that guarantee for compliance purposes has to establish it from the code.
Bringing it up locally, and the four variables that break remote access
The quick start is three commands. Clone the repository, change into deployments/local/lite, and run docker compose up -d. The web interface then answers on http://localhost:8080 with a seeded administrator account, admin@safebucket.io, and the password ChangeMePlease. That default credential is documented in the README and is meant for a local trial, not for anything reachable from a network you do not control. The README then flags a failure mode that catches people running this on a hypervisor or a remote host. If you access Safebucket from an external machine, for example a Proxmox host, four environment variables in the .env file need to point at your host's IP or domain: STORAGE__RUSTFS__EXTERNAL_ENDPOINT, APP__ALLOWED_ORIGINS, APP__API_URL and APP__WEB_URL. The reason follows from the architecture. Because clients receive presigned URLs and then contact storage directly, the endpoint embedded in those URLs must be resolvable from the client's network, not from inside the Docker network. If it is not, uploads and downloads fail while the web interface itself loads fine, which is a confusing symptom. The variable name also tells you the default storage backend in the lite deployment is RustFS. Images are published to ghcr.io/safebucket/safebucket and signed with cosign using keyless signing through GitHub Actions OIDC. The README gives the verification command, which checks the certificate issuer against https://token.actions.githubusercontent.com and the identity against the repository path, so you can confirm provenance before running a tag.
The endpoint exposure is the design, and it is also the constraint
Every architectural benefit here has a matching operational obligation. Presigned URLs are bearer credentials for a single object with an expiry. If one leaks, whoever holds it can fetch the file until it expires, and the application server is not in the path to notice. That is inherent to the pattern rather than a defect in Safebucket, but it means the security boundary extends to your storage endpoint and to how long your signing window is. The README documents share links with a password option and limits on maximum downloads and maximum views, which mitigates casual oversharing of a link, but it does not describe the presigned URL lifetime or whether it is configurable. Treat that as unverified. The second constraint is topology. A deployment where the storage endpoint is only reachable inside a private network will not work for external users, because their browsers and clients must reach it directly. That rules Safebucket out for anyone who wanted a single ingress point with storage kept entirely private behind the application. If that isolation is a hard requirement, this is the wrong tool, regardless of how well the rest of it fits.
Where it sits against a reverse proxy and a filesystem backend
The closest thing to a comparison is the pattern most self-hosted sharing stacks use: an application server in front of local or mounted storage, with a reverse proxy handling TLS and routing. In that arrangement the application process reads and writes every file, and a single ingress is enough because nothing else needs to be publicly reachable. Safebucket inverts this. The application becomes a control plane and the storage backend becomes the data plane, which removes the transfer bottleneck and lets you scale the API independently of throughput. The trade is that you now operate and expose two services instead of one, and the storage endpoint enters your threat model. The other axis is component substitution. Because storage, database, events, cache and notifier are each replaceable, you can keep an existing database or message broker rather than adopting a new one, and the Gorm and Goose pairing means schema changes are managed through migrations rather than manual SQL. That flexibility is real, but it is also surface area: each swappable component is a configuration path that can be misconfigured, and the README's own external-access note is an example of exactly that.
Version cadence, migration cost and what the licence does not decide
The release history shows v0.7.5 on 2026-09-03, v0.7.4 the day before, and v0.7.3 on 2026-08-24, with the last push to main on 2026-09-07. A patch released one day after the previous one is normal for a project at this stage, but it also means you should not treat any single tag as a long-term anchor. The version numbers are still in the 0.x range, so the project makes no stability promise through its versioning. The practical upgrade cost is tied to Goose migrations: a release that changes the schema will run migrations against your database on startup, which means your rollback plan is a database restore, not an image downgrade. Test upgrades against a copy of the database before applying them to a production instance. On licensing, Safebucket is Apache-2.0, which permits commercial use and modification and includes an explicit patent grant. It does not require you to publish modifications. What it does not do is settle the licence terms of the storage backend, database or message broker you plug in, and those are separate decisions with their own obligations. That is a question for your own review, not something the repository's licence answers.
Who should run this, and what to confirm before the first real upload
Safebucket fits an operator who already runs object storage, wants SSO through any OIDC provider with local auth for external collaborators, and needs bucket-level and platform-level role checks plus audit logging. The TOTP multifactor support, file expiration and trash retention settings, and the admin dashboard statistics all point at an internal deployment serving a known set of users rather than an anonymous public service. It does not fit someone who wants one container and a volume, or someone whose security model requires storage to be unreachable from client networks. Before deploying past localhost, confirm four things from the material. First, which storage backend the compose file in deployments/local/lite actually starts and whether that is the backend you intend to run in production. Second, that STORAGE__RUSTFS__EXTERNAL_ENDPOINT resolves from every client network you serve, since this is the documented cause of remote-access failures. Third, that APP__ALLOWED_ORIGINS, APP__API_URL and APP__WEB_URL match the hostname users will actually type. Fourth, that you have replaced the documented default administrator password. The presigned URL lifetime is the fifth item, and it is the one the README does not answer, so read the configuration code before you assume a value.
Editorial conclusion
Adopt Safebucket if you want a self-hosted share layer whose storage backend you can swap and whose file bytes never transit the API process, and if you are willing to run its database, cache, event bus and notifier alongside it. Do not adopt it if you need a single-binary deployment or if you cannot expose your object storage endpoint directly to end users. Before committing, read the compose file in deployments/local/lite, confirm which storage backend it wires up by default, and check whether STORAGE__RUSTFS__EXTERNAL_ENDPOINT must be a hostname reachable from every client network you serve.
Community notes