# go-drive: a self-hosted file manager that mounts ten storage backends behind one web UI

> go-drive is a Go server with a Vue and TypeScript front end that presents local disks, FTP, SFTP, WebDAV, S3, OneDrive, Google Drive, MEGA, Dropbox and Qiniu as a single browsable tree, shipped as one binary with the interface embedded. The interesting parts are the JavaScript drive extension model, the permission model built on virtual root paths, and the default credentials you are told to change immediately.

**devld/go-drive** — A simple cloud drive mapping web app supports local, FTP/SFTP, S3, OneDrive, WebDAV, Google Drive.

- Repository: https://github.com/devld/go-drive
- Website: https://go-drive.top/
- Stars: 803 · Forks: 72
- Language: Go
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/devld-go-drive

## Ten storage backends, one virtual tree, one binary

go-drive is a lightweight file-management server written in Go with a Vue and TypeScript frontend, and the whole point is that a storage provider is not a separate application any more. The supported list is a table, not a paragraph: Local for files on the host filesystem, FTP, SFTP, WebDAV for any WebDAV-compatible server, S3 for Amazon S3 and S3-compatible object storage, OneDrive, Google Drive, MEGA, and Dropbox.

The last two are worth a second look because they are implemented differently. Dropbox and Qiniu are described as scripted JavaScript drives, while the rest are native Go implementations compiled into the binary. That distinction is the extension model showing through: a provider can be added by writing JavaScript, with no recompilation required.

The deployment story is unusually simple, and that is a design decision rather than an accident. The entire application ships as a single self-contained binary with the web UI and the internationalisation assets embedded, which the README frames as making deployment on a server, a NAS or inside a container trivial. The Makefile shows what the embedding costs: the frontend must be built before linking, and the web UI embed only happens under the release build tag, so a plain go test or go build does not need web/dist present.

There is a live demo at demo.go-drive.top and documentation at go-drive.top, and the project ships a Chinese README alongside the English one.

## The Docker path, and why the data directory is mapped outside the container

The quickest way to see it running is a container, and the official image is on Docker Hub as devld/go-drive. The command is short:

```shell
mkdir go-drive-data
docker run -d --name go-drive \
  -p 8089:8089 \
  -v "$(pwd)/go-drive-data:/app/data" \
  devld/go-drive
```

Two things in that snippet are deliberate. The data directory is created and then mapped from outside the container, and the README explains why: mapping it outside ensures your data survives application upgrades. Everything the server keeps lives under /app/data, including the database, sessions, thumbnails and local files, so an unmapped container would lose all of it on recreate. The port mapping exposes 8089, and once the container is up you open http://localhost:8089.

The image also carries extras. The official Docker image bundles ffmpeg and libvips and automatically enables the video and audio thumbnail handlers and the high-performance image handler, so a plain docker run already gives you media previews without extra setup.

If you want to change the configuration, the documented method is to extract the default config.yml from a throwaway container and mount it back:

```shell
# Extract config.yml from a throwaway container
cid=$(docker run -d devld/go-drive) && docker cp "$cid:/app/config.yml" . && docker stop "$cid" && docker rm "$cid"
```

Then you add a second volume for the file, and the container runs with both the data directory and the configuration mapped outside. The compose equivalent is a short service definition:

```yaml
services:
  go-drive:
    image: devld/go-drive
    container_name: go-drive
    ports:
      - "8089:8089"
    volumes:
      - ./go-drive-data:/app/data
    restart: unless-stopped
```

and it comes up with docker compose up -d.

## Running the binary directly, and the flags worth knowing before you start

If you would rather not containerise, the Releases page carries an archive for your platform. On Linux you run the binary directly:

```shell
./go-drive
```

On Windows you run go-drive.exe. By default the server reads config.yml from the working directory if one is present, and listens on :8089. Three flags are documented and one of them saves real debugging time:

```shell
./go-drive -c /path/to/config.yml   # use a specific config file
./go-drive -show-config             # print the parsed configuration
./go-drive -v                       # print version information
```

-show-config prints the configuration the server actually parsed, which is the fastest way to find out whether your file is being read from where you think it is, whether a value was overridden, or whether a typo left a setting at its default.

The configuration itself is YAML, and a fully documented reference lives at docs/config.yml in the repository, which the README says you should copy and adjust. The options table shows the shape of the thing. listen defaults to :8089 and is the address the HTTP server binds to. data-dir defaults to ./data and holds all application data, including the database, sessions, thumbnails and local files. temp-dir defaults to data-dir/temp. max-concurrent-task defaults to 100, covering copy, move and delete work.

Two of these deserve a second look before you expose the server. trusted-proxies affects how client addresses are read behind a reverse proxy, and free-fs defaults to false, and when enabled it lets Local drives use absolute paths, which the table flags as a security risk.

## Default credentials of admin and 123456 are the first thing to change

The README states the default credentials in a blockquote with a bold instruction attached: user admin, password 123456, and change the password immediately after the first login.

It is worth taking that instruction seriously rather than treating it as boilerplate, because of what this application is. go-drive can mount a Local drive at the root of the host filesystem, it can write to S3 buckets and to OneDrive and Google Drive accounts you connect, it can run cron-scheduled copy, move and delete jobs, and it exposes file buckets with token-protected upload and public-read endpoints. The default credential is the only thing standing between an unauthenticated visitor and all of that on a fresh install.

The access control model is what you configure after you are inside. Users, groups and anonymous visitors are isolated with virtual root paths and fine-grained per-path read and write permissions, so a user can be given a subtree rather than the whole tree. LDAP and LDAPS connections are supported, with just-in-time user creation and automatic group synchronisation, which is the route to take if you already run a directory.

Given that anonymous access and virtual roots exist, the security posture of a deployment is a configuration decision rather than a code property. The presence of the free-fs flag, which the option table labels a security risk, makes that point plainly.

## Adding a storage backend in JavaScript, without recompiling the server

The extensible drives feature is the most unusual thing in this project, and it changes what a drive implementation costs.

The README lists the drives that are implemented as scripted JavaScript drives: Dropbox and Qiniu. The project also has a script-drives/ directory at the root alongside script/, and the extension model is described as adding new storage backends with JavaScript, with no recompilation required.

The runtime for that is goja, the JavaScript engine for Go, which appears in go.mod as a dependency. A JavaScript drive therefore runs inside the same process as the Go server, which is convenient and also means the script has the same access the server has. That is a meaningful trust boundary to think about before you install a third-party drive script.

The scripted approach has an obvious appeal for a project with a broad provider matrix. Writing a first-class native drive for every storage service means a dependency per service, as the go.mod shows with the AWS SDK for S3, the Google API client, pkg/sftp, jlaffaye/ftp, go-ldap and the OAuth2 package. A script keeps the provider-specific surface out of the binary, at the cost of running untyped logic in a general-purpose interpreter.

For an administrator, the practical question is which providers you actually need natively and whether the scripted route is acceptable for the rest.

## Preview, search, jobs and buckets: the features beyond browsing files

Once you are past basic file management, the feature list shows how far the project goes.

Browsing and organising is the base: browse, copy, move, rename and delete with drag-and-drop and paste-to-upload. Transfers use chunked uploads for large files, and zip packaging for batch downloads. Previewing is unusually broad: an image gallery powered by PhotoSwipe, built-in audio and video players, a PDF viewer, and configurable external previewers. Text editing uses CodeMirror and full code editing uses Monaco Editor. Archives can be browsed in the browser across ZIP, 7z and RAR, with individual entries downloadable or a selection packed as a zip. Thumbnails are generated for images, text, video and audio through pluggable handlers, with optional libvips and ffmpeg behind them, which is exactly what the official Docker image provides.

Then there is the automation layer. Scheduled jobs run copy, move, delete, flow and JavaScript actions on cron schedules or on file events, with execution history and logs retained. The scheduling is handled by gocron and robfig/cron, both in go.mod. Filename search across mounted drives is optional and index-backed. WebDAV access exposes your drives over the WebDAV protocol, so existing clients can mount the server itself.

File buckets publish token-protected upload endpoints and public-read endpoints, with path templates, type and size limits, caching and hotlink protection. That is the feature to think hardest about before enabling it, because a public-read endpoint on a bucket that happens to be mounted over your S3 storage is a data exposure with a URL in it.

## The licence is custom, and the build ships three separate licence files

The licence needs reading, for one reason beyond the fact that the repository records it as a custom one that GitHub cannot classify.

The README badge says MIT, and the LICENSE file is at the root, but the picture is more layered than a single file. The root has both LICENSE and NOTICE, and the Makefile shows that a release build assembles the licence set explicitly. It copies LICENSE and NOTICE into the build directory, and it copies two more files from elsewhere in the tree: a LICENSE from server/webdav, and a LICENSE from drive/mega/internal/gomega, each placed next to the binary under its own name.

That is a deliberate and correct thing to do. A server that embeds a WebDAV implementation and a MEGA client is distributing third-party code, and shipping those components' licences alongside the binary keeps the attribution obligations intact. The project is not wrong to do it, but it does mean a single MIT badge is an incomplete description of what you receive, and the actual terms are in the root LICENSE file, which you should read.

The module path is simply go-drive, and the Go version is 1.26.4 with the badge reading Go 1.26. Development is quick: the last push was on 2026-10-19, v0.18.0 shipped on 2026-10-17, and there is a nightly build tag published alongside the releases, so the project is actively shipping, and a release number that is 0.x tells you the API is still moving.

## Conclusion

Adopt go-drive if you want one interface over storage you already own across several providers, especially on a NAS or home server, since the single-binary deployment and the mounted virtual tree make it cheap to try. Do not adopt it as a public file-sharing service without changing the default admin credentials, restricting anonymous access, and understanding that the free-fs option allows Local drives to reach absolute paths on the host. Before you deploy, read the LICENSE file rather than the badge, since the repository licence is custom and the build also bundles separate licences for the WebDAV and MEGA components, and check that the Docker image you pull matches the release you intend to run.

## FAQ

### How do I run go-drive with Docker?

Create a data directory, then run the devld/go-drive image with port 8089 published and the data directory mapped to /app/data from outside the container, so your data survives application upgrades. Then open http://localhost:8089 and change the default password, which is 123456 for the user admin.

### Which storage backends does go-drive support?

Local, FTP, SFTP, WebDAV, S3 including S3-compatible object storage, OneDrive, Google Drive and MEGA, plus Dropbox and Qiniu, which are implemented as scripted JavaScript drives rather than native Go ones.

### Can I add a new drive type without recompiling go-drive?

Yes. The feature list describes extensible drives that let you add new storage backends with JavaScript, with no recompilation required, and Dropbox and Qiniu ship as scripted drives built that way.

### What is the free-fs configuration option in go-drive?

It defaults to false. When enabled it allows Local drives to use absolute paths, and the configuration table in the README marks that as a security risk.

## Sources

- [devld/go-drive on GitHub](https://github.com/devld/go-drive)
- [Issues](https://github.com/devld/go-drive/issues)
- [Project website](https://go-drive.top/)
- [README](https://github.com/devld/go-drive/blob/master/README.md)
- [Releases](https://github.com/devld/go-drive/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/devld-go-drive
