I put together a simple static file server in Go - useful for local testing of web applications. Check it out at https://github.com/eliben/static-server

If you have Go installed on your machine, you don't have to download anything else; you can run:

$ go run github.com/eliben/static-server@latest

And it will start serving the current directory! Run it with -help for usage information. No configuration files needed - the default is useful and you can adjust it to your needs using command-line flags.

Why

When developing web applications locally, for basic test cases we can open an HTML file directly in the browser (using file:/// scheme). However, this is sometimes insufficient, and in several scenarios it's necessary to properly serve the HTML (along with its JS and CSS). Some cases where I encountered this are web applications that use at least one of:

  • Web workers
  • Web sockets
  • WASM
  • Separate API servers, requiring CORS

In the past, when I was more active in the Python ecosystem, I used python -m SimpleHTTPServer <port> quite a bit. While it's nice, it has some issues too: it's not very configurable, and it requires Python to be installed.

Another option I've used is http-server from the Node.js ecosystem; in fact, it has served as the inspiration for static-server. You can run it with npx without installing, and it's also configurable through command-line flags, without requiring configuration files.

But we can't expect all Go developers to have npm or npx installed. Moreover, sometimes you want to tweak the server a bit and digging in JavaScript is not any Go programmer's idea of a good time. Like many tools in that ecosystem, this Node.js-based HTTP server is all in on dependencies - with 13 of them, it's not easy to understand or modify its code; much of it is split across multiple helper packages, and making changes can be tricky.

How

Spinning up a static file server in Go is very easy - I wrote a whole blog post about the possibilities at some point. The simplest static server to serve the current working directory is just:

package main

import "net/http"

func main() {
  port := ":8080"
  handler := http.FileServer(http.Dir("."))
  http.ListenAndServe(port, handler)
}

Having found myself plopping a small server.go with these contents in too many web projects, I decided enough was enough. Thus static-server was born.

static-server is simple, yet versatile. It will do the right thing by default, with no flags whatsoever. But you can also use flags to configure a few aspects, e.g.: the port it serves on, CORS support, serving via TLS, control how logging is done.

static-server is hackable and easy to understand. All the code is in a single file (with fewer than 200 lines of code, including comments and handling flags) and there are no dependencies (except one package that is only used for testing).

I find static-server very useful, and I hope others will too. If you run into any problems or have questions, open a GitHub issue or send me an email.