# Plik: a self-hosted temporary file upload system in Go

> Plik is a WeTransfer-style upload server written in Go, with a Vue 3 web UI, a CLI client, pluggable storage and metadata backends, and optional Age end-to-end encryption. It fits teams that want to run their own share links; it is not a managed transfer service.

**root-gg/plik** — Plik is a temporary file upload system (Wetransfer like) in Go.

- Repository: https://github.com/root-gg/plik
- Website: https://plik.root.gg
- Stars: 1,820 · Forks: 197
- Language: Go
- License: NOASSERTION
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/root-gg-plik

## What Plik solves, and who should run it

Sending a large file to someone outside your organisation usually means either an email attachment that bounces, or an account on a hosted transfer service that logs who sent what. Plik takes the third route: you run the server, and it hands out a link that expires. The README describes it as a "scalable & friendly temporary file upload system, like WeTransfer, self-hosted", and the feature list backs that up with configurable TTL, auto-cleanup, password-protected uploads, and OneShot downloads where the file is deleted after the first download.

The audience is narrower than "anyone who shares files". Plik targets people who can run a Go binary or a container and want upload links to live on infrastructure they control. The repository ships a Dockerfile, a Helm chart under charts/, and an apt repository, so the intended deployment path is a container or a package on a host you administer, not a laptop-only tool. If you cannot operate a server, the live demo at plik.root.gg shows the interface but does not replace a deployment.

## Architecture: a Go server, a Vue webapp, and pluggable backends

Plik is a single Go server, plikd, that serves both an HTTP API and the compiled Vue 3 frontend. The Makefile separates the build into three targets: frontend runs npm ci and npm run build inside webapp/, server compiles ./server/plikd, and client compiles ./client/plik. The Dockerfile mirrors this with three stages: a node:24-alpine stage that builds the frontend, a golang:1-bookworm stage that cross-compiles the clients, and a final stage that links the server for the target architecture.

The interesting part is what sits behind the HTTP layer. Storage is not fixed: the README lists local disk, S3, OpenStack Swift, and Google Cloud Storage, and go.mod confirms the dependencies (minio-go, ncw/swift, cloud.google.com/go/storage). Metadata is similarly swappable, with SQLite, PostgreSQL, and MySQL drivers present through GORM, plus gormigrate for schema migrations. Authentication is pluggable too, with local accounts plus Google, GitHub, OVH, and OIDC providers wired through golang.org/x/oauth2.

That design has a cost. Every backend combination is a configuration surface you have to get right, and the README does not enumerate which combinations are tested together. The repository does contain a testing/ directory, which suggests integration testing exists, but the README does not describe its coverage. Treat backend selection as a decision you validate yourself rather than one the documentation settles for you.

## Installing Plik with Docker and uploading a first file

The README's quick start gives a one-line Docker command. It publishes port 8080, and the README says to open the web interface at http://127.0.0.1:8080 afterwards.

```bash
docker run -p 8080:8080 rootgg/plik
```

For a Debian or Ubuntu host, the README documents an apt repository. The first command fetches the signing key, the second adds the source list, and the third installs and starts the service.

```bash
curl -fsSL https://root-gg.github.io/plik/apt/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/plik.gpg
echo "deb [signed-by=/etc/apt/keyrings/plik.gpg] https://root-gg.github.io/plik/apt stable main" | sudo tee /etc/apt/sources.list.d/plik.list
sudo apt update && sudo apt install plik-server
sudo systemctl start plikd
```

Uploading from the command line needs the separate client. The README shows the client invocation and the output it produces: an upload URL of the form http://127.0.0.1:8080/#/?id=vDPmPEUqc5oCt31T, a progress bar, and a curl command for retrieving the file.

```bash
plik myfile.txt
```

If you would rather not install the client, the README gives a curl equivalent that posts the file as multipart form data and prints the resulting file URL.

```bash
curl --form 'file=@/path/to/myfile.txt' http://127.0.0.1:8080
```

The client installation steps are not in the README itself; it points to the CLI client documentation page at root-gg.github.io/plik for those. The README also lists Kubernetes via Helm, and a from-source path that runs make and then ./plikd from the server directory.

## End-to-end encryption with Age, and what it does not cover

The README lists "End-to-end encryption with Age (CLI to Web interoperable)" and go.mod pins filippo.io/age. The interoperability claim is the notable one: a file encrypted by the CLI can be decrypted in the browser, and the reverse is implied by the same phrase. That matters because it means the server is not required to hold a key to complete the round trip.

What the README does not describe is the key exchange, how recipients obtain the passphrase or identity, or what happens when a recipient lacks the client. There is a docs/ directory in the repository and a documentation site, so the detail likely lives there, but the README alone is not enough to assess the threat model. If your use case depends on the server never seeing plaintext, verify the encryption flow against the documentation and your own test upload before you rely on it. The same caution applies to the MCP server feature: the README links a documentation page for it, and go.mod includes the modelcontextprotocol Go SDK, but the README does not describe what an AI assistant can do through it or how it is authenticated.

## Where Plik is the wrong tool

Plik is a transfer service, not a sync service. There is no client that watches a folder, no conflict resolution, and no persistent file tree. If you want Dropbox-style behaviour, this is the wrong project.

The stream mode is the clearest example of a design trade-off. The README describes it as "uploader to downloader, nothing stored". That is useful for a one-time handoff, but it means the upload only completes when a downloader is present. A stream-mode upload is not a durable artefact, and anything that assumes a file exists on the server after upload will break against it.

OneShot downloads have a similar edge. The README states the file is deleted after the first download. If the first download is interrupted, the file may be gone, and there is no documented recovery path in the README. For anything where the recipient might need a second attempt, OneShot is the wrong setting.

Finally, the project is a self-hosted server, so availability, backups, and upgrades are yours. The README does not document rollback procedures, and the repository metadata reports the licence as NOASSERTION even though the README links an MIT badge. That mismatch is worth resolving with your own legal review before you depend on it.

## How Plik differs from other self-hosted upload tools

The searches that lead people to Plik often mention Uguu, Pingvin, and Chibisafe, so those are the natural comparisons. This article does not describe those projects in detail, so the honest comparison is about shape rather than features.

Plik's distinguishing trait is that it is a Go server with a compiled CLI client and a documented HTTP API, and the README presents the CLI as a first-class interface alongside the web UI. The upload example shows the client printing both a web URL and a curl command for the same file, which is a workflow aimed at scripting. A tool that is browser-only would not need that.

The second trait is backend pluggability. Storage can be local, S3, Swift, or GCS; metadata can be SQLite, PostgreSQL, or MySQL. That is a lot of operational flexibility for a file transfer tool, and it is the main reason to pick Plik over a simpler single-binary uploader that only writes to local disk. If you only ever want local storage and SQLite, you are paying configuration complexity for options you will not use.

The third trait is the feature set around the transfer itself: TTL with auto-cleanup, OneShot, stream mode, password protection, Age encryption, Prometheus metrics, and an MCP server. That is broader than a minimal upload endpoint, and it is the strongest argument for Plik when you need more than posting a file and getting a link.

## Maintenance, releases, and upgrade cost

The last push to the default branch was on 2026-09-09, and the most recent release listed is 1.4.2 from 2026-03-31, preceded by 1.4.1 on 2026-03-08 and 1.4.0 on 2026-03-03. The repository is not archived. The gap between the March release and the September push suggests ongoing work between releases rather than a dormant project, but the README does not describe a release cadence or a support policy.

Upgrade cost depends on your backend choices. The server uses gormigrate for schema migrations, so a metadata schema change is handled by the application rather than by hand. The Dockerfile builds the frontend and clients in separate stages and then cross-compiles the server, which means a version bump rebuilds all three artefacts. If you deploy from the apt repository or the Helm chart, the upgrade path is whatever those channels provide; the README does not document a rollback procedure for either.

On licensing, the README shows an MIT badge and links a LICENSE file, but the repository metadata reports the licence as NOASSERTION. Those two signals disagree. The README also credits third-party clients (ShareX, plikSharp, Filelink for Plik) that live in separate repositories with their own licences. If you are redistributing Plik or bundling it into a product, read the LICENSE file in the repository rather than the badge.

## Conclusion

Adopt Plik if you need share links that expire, a CLI that scripts cleanly, and storage you control; skip it if you need an SLA, managed support, or a feature set that only a commercial service provides. Before rolling it out, verify which storage and metadata backends you will actually use, confirm the MCP server and Age encryption behaviour in your own deployment, and check the LICENSE file in the repository, since the README links MIT but the repository metadata reports NOASSERTION.

## FAQ

### How do I install Plik?

The README gives four paths: a Docker command that runs rootgg/plik on port 8080, an apt repository for Debian and Ubuntu that installs the plik-server package, a release tarball with a prebuilt plikd binary, and a from-source build using make. It also lists a Helm chart for Kubernetes.

### Does Plik support end-to-end encryption?

The README lists end-to-end encryption with Age and states that the CLI and web interfaces are interoperable. It does not describe the key exchange or how recipients obtain the passphrase, so the detailed flow has to be checked in the project documentation.

### What is the difference between Plik and a service like WeTransfer?

Plik is self-hosted: you run the server, and the README describes it as a temporary file upload system like WeTransfer. That means you control storage and metadata backends, but you also own availability, backups, and upgrades, which a hosted service handles for you.

## Sources

- [Issues](https://github.com/root-gg/plik/issues)
- [Project website](https://plik.root.gg)
- [README](https://github.com/root-gg/plik/blob/master/README.md)
- [Releases](https://github.com/root-gg/plik/releases)
- [root-gg/plik on GitHub](https://github.com/root-gg/plik)

---

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