Erugo: a self-hosted file sharing service with a rebuilt upload engine
A powerful, self-hosted file-sharing platform built with PHP and Laravel with a Vue.js frontend. It offers secure, customizable file-transfer capabilities through an elegant user interface, giving you complete control over your data while providing a seamless experience for both senders and recipients.
At a glance
- What is it?
- Erugo is a Laravel and Vue.js file sharing platform you run on your own server, with resumable uploads, human-readable share URLs, reverse shares, and a white-labelable interface. The version 0.2.0 release replaced the upload engine with tusd, and the project is a small-team effort still on a 0.x version line.
- Who is it for?
- Adopt Erugo if you want to run your own file transfer service on infrastructure you control, with resumable uploads for large files, share-level access rules and a branding layer your organisation can put its name on. Do not adopt it if you need a service with a support team behind it, or if you need features the project has not built, since it is a 0.x project with a small maintainer base.
- Can I use it commercially?
- Yes. MIT 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 76 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Erugo is, and the case for running your own file transfer
Erugo is a self-hosted file-sharing platform built with PHP and Laravel on the back end and a Vue.js front end. The primary language of the repository is PHP, the licence is MIT, and the homepage is erugo.app.
The README frames the value proposition in three sections, and the first is the one that defines the category. Your Data, Your Rules: files stay on your infrastructure, with no third-party access, no data mining and no surprises. Deploy Anywhere: run it on your own server, a VPS, or even a Raspberry Pi, with Docker making setup straightforward. Open Source Forever: MIT licensed, so you can inspect the code, contribute features, or fork it.
Those are familiar arguments, and the interesting question is whether this implementation is credible. The feature list is a real file transfer product rather than a demo. Uploads support multiple files with progress tracking, folder uploads that maintain structure, large files with automatic resume, and drag and drop. Shares can carry a password, an expiration date, and a download limit. There is a reverse share feature that invites guests to upload files into your account with a one-time token, which is the part that distinguishes it from a plain WeTransfer replacement, since it turns the service into an intake form for a team. There is email support for notifications and password reset, an interactive first-run setup, automatic deletion of expired shares, and a dashboard for tracking downloads, extending expiration and revoking access.
The white-labeling angle is real too, with built-in light and dark themes, custom themes through the web interface, and logo and color customization, and the README explicitly lists easy white-labeling for your organization as a goal. Six languages are listed as supported, with French, Portuguese and others credited to named contributors.
So the audience is a team that needs to move files to and from its own users, on its own infrastructure, with its own name on the interface.
The upload engine rebuilt on tusd, and what that changes
The v0.2.0 release note is the most informative line about the project, and it is worth reading closely: a large release featuring self-registration, user management improvements, a new command palette, custom share URLs, a rebuilt upload engine powered by tusd, and much more, published on 2025-12-25.
The upload engine is the part that matters most for a file sharing service, and rebuilding it around tusd rather than continuing to extend a bespoke implementation is a significant architectural decision. tus is an open protocol for resumable uploads, and the client side of that protocol is in the dependency list as tus-js-client. The protocol's core idea is that a client that loses its connection does not restart the upload, it asks the server how much has been received and continues. For a service whose users are uploading multi-gigabyte files over connections that drop, that is the difference between a usable product and a support queue.
A second effect of the protocol is that the upload is no longer necessarily a request to the Laravel application itself. The tus protocol is designed to be served by a dedicated service, and the client side of that protocol is in the dependency list as tus-js-client.
The same release brought custom share URLs, which connects to the memorable URL feature the README describes. Instead of a cryptic string, you get something like you.com/shares/quiet-cloud-shrill-thunder, a three-word phrase that a person can read out over a phone call. It is a small design decision that changes how the service feels in use, and it also means a share URL is guessable in a way a random token is not, which is exactly why the password, expiry and download limit options matter alongside it.
The other release in the recent list is v0.2.15, labelled a Security Release, published on 2026-01-28.
Running it with Docker, and the storage volume that matters
The quick start in the README is a compose file you can paste.
services:
app:
image: wardy784/erugo:latest
restart: unless-stopped
volumes:
- ./erugo-storage:/var/www/html/storage # Use a dedicated folder
ports:
- "9998:80"Then one command starts it:
docker compose up -dThe README says this provides a basic configuration starting point that will get Erugo up and running with a default sqlite database. That is the whole installation for a first evaluation, and it is worth understanding what the two parts of it mean.
The volume mount is the important one. Files live under /var/www/html/storage, and the comment says to use a dedicated folder, which is a warning about two things. Your uploads are the valuable data, and you do not want them lost when the container is replaced. And the storage directory is also where the SQLite database sits by default, according to the environment configuration, where DB_CONNECTION is sqlite and DB_DATABASE is database/database.sqlite. A SQLite file on a network filesystem, or on a volume that does not support the locking the database needs, is a common way a containerised PHP application misbehaves. The development compose file in the repository treats the database as a named volume specifically to support WAL mode properly, with a comment saying exactly that, and the same care is worth applying in production.
The port mapping publishes the application on 9998 on the host, with the web server inside on port 80. The image on Docker Hub is wardy784/erugo, and the repository also carries a publish-docker-image.sh script and a docker-compose-prod.yml alongside the development docker-compose.yml.
The.env.example shows what the application expects. Beyond the standard Laravel keys, the ones specific to this application are APP_KEY, which is empty and must be generated, and the JWT block, with JWT_SECRET and JWT_ALGO set to HS256, which is the token configuration for the API the Vue front end talks to. The frontend variable VITE_API_URL points at http://localhost by default. There is also an APP_LOCALE and APP_FALLBACK_LOCALE set to en, with APP_FAKER_LOCALE set to en_GB.
The Laravel and Vue stack, and the front-end build
The repository is a standard Laravel application with a Vue front end built by Vite, and the file layout makes the structure clear.
At the top level there are the Laravel directories, app/, bootstrap/, config/, database/, public/, resources/, routes/, storage/ and tests/, plus the artisan console entry point, composer.json and composer.lock, phpunit.xml and a .prettierrc. There is a vite.config.js and a postcss.config.js, and a package.json that is marked private with type module, which is what a Vite project looks like.
The front-end dependencies describe what the interface does. Bootstrap 5.3.3 and flag-icons provide the layout and the country flags in the language picker. lucide-vue-next is the icon set. CodeMirror 6 with the HTML language mode and the one-dark theme, wrapped by vue-codemirror, is the code editor, which for a file transfer service means a text preview of uploaded files. jszip is the client-side zip handling, and jwt-decode is how the front end reads the tokens the API issues. vue-toastification handles notifications, mitt is the event bus, and vue-color-kit is the colour picker behind the theme customisation.
The build tooling is Vite 6 with the laravel-vite-plugin, so the standard split applies: npm run dev serves assets with hot reload, npm run build produces the production bundle, and Laravel's Vite integration reads the manifest. Autoprefixer and sass-embedded are in the dev dependencies, so the styles are Sass compiled through PostCSS.
Localisation runs through Tolgee, with @tolgee/vue and @tolgee/format-icu in the dependencies and a tolgee block in the package.json pointing at an apiUrl, a projectId, and a pull path of ./resources/js/i18n. That configuration is worth noticing. Tolgee is a translation management platform, and the apiUrl in the package.json points at a specific self-hosted-looking host rather than the default service, which suggests the project runs its own instance for its own translations. For a self-hosted product that has to work offline in an air-gapped deployment, that is a meaningful choice, and it also means the translation catalogue is pulled at build time rather than fetched at runtime.
Where Erugo is the wrong tool
There are three honest limits, and the first is about scale and support rather than features.
Erugo is a 0.x project maintained by a small group. The release history shows 0.1.1 in April 2025, a large 0.2.0 in December 2025, and a security release 0.2.15 in January 2026. The last push was on 2026-08-08. That is a real project with a real cadence, and the fact that a version was explicitly labelled a security release says the maintainer treats security seriously. It is still a project where one person is a large part of the delivery, and a file transfer service holds data that people will not want to lose. An organisation that needs a support contact, an SLA and a response time is looking for something else.
The second limit is the one that comes from being self-hosted at all. The README's promise is that files stay on your infrastructure, which is the point, but it also means the operator owns backups, TLS termination, upgrades, database maintenance, disk monitoring and abuse handling. Uploads consume disk until they expire, and the automatic cleanup of expired shares is a feature that also means expired files are gone, so the operator needs to decide whether there is a backup of the storage volume and, if so, that the backup does not quietly keep deleted data alive in a way the deletion was supposed to achieve.
The third is that the file sharing model has limits. The README does not mention virus scanning, content type restrictions, or any moderation of what is uploaded. It does not mention an audit log, an administrator's view of every share across users, or rate limiting on the public upload endpoint. The features are all present, but they are present at the level of an individual share: a password, an expiry, a download limit. If you need to know what your users are sharing, the dashboard as described tracks downloads and activity for a given account, and there is an invite system for user management, which is account-scoped rather than a platform-wide content governance tool.
One practical point on the demo and the sample install: uploads are disabled on the demo site, which is offered so you can see the recipient's view, and the community install guides referenced in the README are third-party articles rather than upstream documentation.
Erugo against the alternatives
The comparison that matters is against the hosted file transfer services, and the difference in approach is architectural rather than cosmetic.
A hosted service runs the storage, the bandwidth and the operation, and gives you a URL. The cost is that your data passes through someone else's infrastructure and someone else's retention policy, and the cost of leaving is your existing links break and your recipients lose access to the history. Erugo's answer is to run the same shape of service yourself, so the URL points at your own domain and the files never move.
The alternative inside the self-hosted category is to use a general-purpose file server, a Nextcloud instance or a Syncthing or SFTP setup, and manage sharing links yourself. The difference in approach is what the service is built around. Erugo is a transfer service: upload, configure, share, expire. A general-purpose file server is a filesystem with a web interface, where sharing is a feature you configure among many, and the recipient's experience is a file browser rather than a single download. Erugo's reverse share feature, which is the closest thing to a distinctive capability, is a one-time token that lets a guest upload into your account, and that is a workflow built for collecting files from people outside your organisation, which a file server does not offer in the same shape.
The other alternative is to write your own upload form on an object store. That gives you the most control and the least software, and for a one-off internal transfer tool it may be the right answer. The trade is that the recipient experience, the expiry handling, the download counting and the password protection are all yours to build and to keep working.
The deciding question is therefore operational rather than technical. If you want the convenience of a transfer service and the control of your own infrastructure, Erugo gives you that, and the Docker compose file makes the first run a single command. If you need the file management of a storage platform, use a file server instead.
Editorial conclusion
Adopt Erugo if you want to run your own file transfer service on infrastructure you control, with resumable uploads for large files, share-level access rules and a branding layer your organisation can put its name on. Do not adopt it if you need a service with a support team behind it, or if you need features the project has not built, since it is a 0.x project with a small maintainer base. Verify first that the image you deploy matches the release you read about, that your storage volume is on a filesystem which supports the SQLite write patterns the app needs.
Frequently asked questions
How do I run Erugo with Docker?
The README gives a compose file with the image wardy784/erugo, a storage volume mounted at /var/www/html/storage and port 9998 published to 80, then `docker compose up -d`. That starting configuration comes up with a default sqlite database.
What does the reverse share feature do?
It lets you invite guests to upload files to your account using a one-time token, so external people can send you files without creating an account. The feature list describes it as Reverse Share, and the README's screenshot caption calls it a one-time reverse share token.
Does Erugo support resumable uploads?
Yes. The README lists large file support with automatic resume, and the v0.2.0 release is described as featuring a rebuilt upload engine powered by tusd. The client library tus-js-client appears in the front-end dependencies.
Which languages does the Erugo interface support?
The README lists English, French, German, Italian, Dutch and Portuguese, with translations contributed through the project's Discord server. The application is fully translatable, and localisation is handled with the Tolgee tooling.
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/erugooss-erugo)Was this useful?