Open-source project
codeskyblue/gohttpserver avatar
codeskyblue/gohttpserver

gohttpserver: a single-binary file server that tells you to stop using it

The best HTTP Static File Server, write with golang+vue

2,841 stars583 forksJavaScriptMIT

At a glance

What is it?
The README's first line says not maintained and names three alternatives, yet the repository still has commits from July 2026 and a feature list that reads like a working tool.
Who is it for?
gohttpserver does one thing well and says so itself. If you need a single binary that serves a directory over HTTP with a browsable interface, upload, basic auth, zip download of a folder, and QR codes for Android and Apple install packages, this still does that, and the checked items in the feature list are specific enough to check against your own requirements.
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 96 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The first line of the README is an exit notice

The README opens with the title `gohttpserver (not maintained)` and then a short Alternatives list: dufs written in Rust, copyparty written in Python, and servefs, described as a new port file server project by the same author. Everything after that is documentation for a project the author is telling you to move away from.

That framing is worth taking seriously rather than treating as a formality, because it is corroborated by the release history. There are three published releases: 1.3.0 on 2024-12-04, and then 1.1.4 and 1.1.3 both on 2022-07-26. The last push to the repository was on 2026-07-03, which is nearly two years after the newest tag. So commits continue, dependency updates arrive, and no release is cut for them. A `go install github.com/codeskyblue/gohttpserver@latest` will therefore give you something different from the last tagged release.

The stated goal, in the doc's own terms, is to make the best HTTP file server, with human-friendly UI, file upload support, and direct QR code generation for Apple and Android install packages. The Chinese in the README says the same thing. That is a narrow, opinionated goal rather than a general-purpose web server, and the feature list that follows is built to match it: what is checked is what you need to hand someone an APK or an IPA and let them install it.

Install paths, and the Go version the module declares

There are three documented ways to get it, and the first is the shortest:

bash
go install github.com/codeskyblue/gohttpserver@latest

Binaries can also be downloaded from the repository's releases, which matters if you are not writing Go. On macOS there is a Homebrew tap:

bash
brew install codeskyblue/tap/gohttpserver

Running it takes one flag to be useful. The usage example listens on port 8000 of all interfaces with upload enabled:

bash
gohttpserver -r ./ --port 8000 --upload

The `--help` output is the reference for everything else, and the flags in this project are parsed with kingpin rather than the standard library flag package, which is why the long forms in the README use hyphens like `--auth-type`.

On the version question, the README says it was tested with go-1.16 and `go.mod` agrees, declaring `go 1.16`. The dependency list is where the interesting detail sits. Several direct requirements are old, including `gorilla/mux` at 1.6.2, `gorilla/sessions` at 1.2.0 and `howett.net/plist` pinned to a 2020 commit, while `golang.org/x/net` sits at v0.38.0 and `golang.org/x/text` at v0.23.0, which are current. The release notes for 1.3.0 record the x/net bump from 0.17.0 to 0.23.0 as a dependabot change, so the tree has moved well past that. Some requirements are also authored by the same person, including `codeskyblue/dockerignore`, `codeskyblue/go-accesslog` and `codeskyblue/openid-go`, which tells you that some of this server's plumbing is maintained alongside it.

Three auth modes and one of them is company-internal

Authentication is where a file server stops being a toy, so this is the section to read closely. There are three modes plus an upload switch.

Basic HTTP authentication takes repeated pairs, so multiple users are configured by repeating the flag:

bash
gohttpserver --auth-type http --auth-http username1:password1 --auth-http username2:password2

OpenID is the second, and the README annotates it with an unusually candid caveat: it works only in netease company. The flag points at your provider's endpoint:

bash
gohttpserver --auth-type openid --auth-openid https://login.example-hostname.com/openid/

The third defers authentication to a reverse proxy entirely, which is the pattern most people running this in production would actually choose:

bash
gohttpserver --auth-type oauth2-proxy

In that mode the backend trusts identity information in request headers, and the README lists them exactly: `X-Auth-Request-Email` as the userId, `X-Auth-Request-Fullname` as the user's display name, urlencoded, and `X-Auth-Request-User` as the user's nickname, mostly an email prefix. It also says plainly that you configure the oauth2 reverse proxy yourself. That is the important caveat for anyone evaluating this mode: the trust boundary is a header, so the server must not be reachable except through the proxy, and nothing in the documentation enforces that for you.

Write access is a separate switch from auth. `--upload` enables uploading and `--delete` enables deletion and folder creation. So a read-only authenticated server is the default shape, and enabling deletion is an explicit decision.

Per-directory rules in .ghs.yml, the htaccess analogue

The access control model is a YAML file placed in a subdirectory, and the README compares it to `.htaccess`, which is the right comparison for anyone coming from Apache. The file name is `.ghs.yml`, and there is a `--conf` flag for choosing a different config file name, with an example at `testdata/config.yml`.

Here is the documented example, where the directory denies upload and delete by default and grants both to one named user:

yaml
---
upload: false
delete: false
users:
- email: "[email protected]"
  delete: true
  upload: true
  token: 4567gf8asydhf293r23r

The semantics depend on the auth mode. The README's explanation of that example is conditional: if openid auth is enabled and that user has logged in, they can delete and upload under the directory holding the `.ghs.yml`. That conditional is doing a lot of work, and it is worth noticing that the example is keyed on an email address, which only lines up naturally with the openid or oauth2-proxy modes. With basic auth the usernames are whatever you passed to `--auth-http`.

The `token` field is a second, separate credential for upload over HTTP, so a client without a session can still write. The README's directory-hierarchy example makes the scoping concrete: a `.ghs.yml` inside `foo` grants rights in `foo` and below, while `bar` and below are unaffected.

The same file also controls visibility, through an `accessTables` list of regular expressions and an allow flag, which is how you hide a file in one directory without touching the rest of the server:

yaml
accessTables:
- regex: block.file
  allow: false
- regex: visual.file
  allow: true

Upload by curl, including unzip on the way in

Uploads are ordinary multipart form posts, which means the server can be driven without the browser interface at all. Posting a file to a directory path puts it there:

sh
curl -F [email protected] localhost:8000/somedir

and the response is a small JSON object naming the destination and success. Two extra form fields change the behaviour. A `token` field supplies the upload credential for the case where you have no session, and a `filename` field overrides the name, so `curl -F [email protected] -F filename=hi.txt localhost:8000/somedir` stores the file as `hi.txt`.

There is also an `unzip` flag on the form, which extracts an uploaded archive in place:

bash
curl -F [email protected] -F unzip=true localhost:8000/somedir

The tree also contains a `Procfile`, a `.goreleaser.yml` and a `build.sh`, so binary releases and one-command deployment were part of the plan. The Docker path is documented too, sharing the current directory on port 8000:

bash
docker run -it --rm -p 8000:8000 -v $PWD:/app/public --name gohttpserver codeskyblue/gohttpserver

and the same container accepts the auth flags described above. Building the image locally needs `docker build -t codeskyblue/gohttpserver -f docker/Dockerfile .` from the repository root.

What the checklist admits is missing

The feature list is a markdown task list with 38 entries, and the unchecked ones are as informative as the checked ones. Not implemented: download count statistics, offline download, code file preview, editing files in place, md5sum and sha calculation, folder upload, and sorting by size or modified time. There is also an unchecked item for an info API at `/-/info/some.(apk|ipa)`, next to a checked one for the Android package info API at `/-/apk/info/some.apk`. That pairing suggests the Android parsing exists and the cross-platform version was planned.

What is implemented is a coherent set for one job. QR code generation, a breadcrumb path that can be changed by clicking, all assets packaged into a standalone binary, a distinct icon per file type, hiding or showing hidden files, upload authorised by token or session, README.md preview in the browser, HTTP basic auth, partial page reload when a directory changes, path collapsing when a directory contains only one subdirectory, directory zip download, CORS enabled, global file search, theme selection, working behind nginx, showing folder size, creating folders, skipping the delete confirmation when alt is held, adding the version to the index page, a custom title, and unzipping archives on upload. The `.ghs.yml` support and automatic version tagging round it out.

The QR code feature deserves its own note because it is the reason this server exists. For an Apple install package it generates a `.plist` file and the README says the QR code can be recognised by an iPhone, which requires https. There is a plist proxy for servers without it, configurable with `--plistproxy`, defaulting to a public host at plistproxy.herokuapp.com, and the README notes the proxy is disabled automatically when the server sits behind nginx with https configured. Sending a plist to the proxy returns a key, and fetching that key returns the content.

For code structure, the Go side is a handful of files with names that match the features: `main.go`, `httpstaticserver.go`, `res.go`, `zip.go`, `ipa.go`, `oauth2-proxy.go`, `openid-login.go`, `utils.go` and `assets.go`. Tests exist alongside in `httpstaticserver_test.go`, `utils_test.go` and `zip_test.go`, with fixtures in `testdata/`. The repository's language field reads JavaScript rather than Go, which reflects where the interface lives: the Vue frontend is embedded through `assets.go` and compiled into the binary, so the Go files and the frontend assets ship as one executable.

Editorial conclusion

gohttpserver does one thing well and says so itself. If you need a single binary that serves a directory over HTTP with a browsable interface, upload, basic auth, zip download of a folder, and QR codes for Android and Apple install packages, this still does that, and the checked items in the feature list are specific enough to check against your own requirements. The caveat is stated in the first line of the README rather than buried: the project is marked not maintained, and it names dufs, copyparty and a newer Go port as alternatives. What that means in practice is a gap between the last release, 1.3.0 on 2024-12-04, and repository activity continuing to 2026-07-03, so a dependency bump landed on master without a tag behind it. If you deploy this, pin to a release rather than to master, read the dependencies in `go.mod` before you build, and read the auth section carefully: the openid mode is documented as working only inside one specific company, which tells you how much testing each mode gets. `httpstaticserver.go` is where the routing and upload handling live if you need to patch rather than adopt.

Frequently asked questions

Is gohttpserver still maintained?

The README's title says not maintained and its first section names dufs, copyparty and a newer Go port by the same author as alternatives. The last release was 1.3.0 on 2024-12-04, though commits and dependency updates have continued to 2026-07-03 without a new tag, so master is ahead of the newest release.

How do I run gohttpserver with a folder shared over HTTP?

Pass a root directory with `-r`, a port with `--port`, and `--upload` if you want writes enabled, for example `gohttpserver -r ./ --port 8000 --upload`. There is also a Docker form that mounts the current directory to `/app/public` and publishes port 8000.

How do I restrict who can upload or delete files in gohttpserver?

Create a `.ghs.yml` in the directory you want to control, set `upload` and `delete` to false, and grant them to specific users under `users` with an email and a token. The rules apply to that directory and below, and the `token` is the credential a client passes as a form field when uploading over HTTP.

Can I use gohttpserver with Google or GitHub login?

Not directly. The built-in options are HTTP basic authentication, an openid mode the README says works only inside one company, and an oauth2-proxy mode that trusts headers from a reverse proxy you run yourself. In that last mode the server reads the userId from `X-Auth-Request-Email` and the display name from `X-Auth-Request-Fullname`.

Official sources

  1. codeskyblue/gohttpserver on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/codeskyblue-gohttpserver.svg)](https://hysenlabs.com/projects/codeskyblue-gohttpserver)