# go-httpbin: a Go port of httpbin you can run in your own tests

> go-httpbin is a Go implementation of the httpbin service with no dependencies outside the standard library, shipped as a container image, a standalone binary and an importable package, so a test can exercise timeouts, redirects and status codes without reaching the internet. It suits Go teams testing HTTP client behaviour.

**mccutchen/go-httpbin** — A reasonably complete and well-tested golang port of httpbin, with zero dependencies outside the go stdlib.

- Repository: https://github.com/mccutchen/go-httpbin
- Website: https://httpbingo.org
- Stars: 888 · Forks: 185
- Language: Go
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/mccutchen-go-httpbin

## The library form is the interesting one

There are three ways to use this project and the third is the reason it exists. It can be run as a server, in Docker or as a standalone binary, but it can also be imported as a package and used inside your own test, and the documentation gives a worked example that shows why. The package path is the httpbin package, and a test creates an app with httpbin.New(), wraps it in an httptest server, and then makes a request that the server is going to be slow to answer:

```go
func TestSlowResponse(t *testing.T) {
	app := httpbin.New()
	testServer := httptest.NewServer(app)
	defer testServer.Close()

	client := http.Client{
		Timeout: time.Duration(1 * time.Second),
	}

	_, err := client.Get(testServer.URL + "/delay/10")
	if !os.IsTimeout(err) {
		t.Fatalf("expected timeout error, got %s", err)
	}
}
```

This is the pattern that matters. A test that asserts your client times out does not need a network, a fixture server on another machine, or a real slow endpoint, because the server is created in the same process and torn down with it. The go.mod file has no require block at all, which is the zero dependencies outside the Go standard library claim taken literally, and for a test helper that means the dependency graph of your test suite does not change when you add it.

## Running it as a service, three ways

The service side is equally well covered. Prebuilt images for linux/amd64 and linux/arm64 are published automatically for every tagged release to the GitHub container registry, which the documentation marks as recommended, and to Docker Hub, and starting one is a single command with the port mapped dynamically:

```bash
$ docker run -P ghcr.io/mccutchen/go-httpbin
```

For Kubernetes there is a kustomize directory, and the apply is a single line pointing at the repository:

```bash
$ kubectl apply -k github.com/mccutchen/go-httpbin/kustomize
```

For a standalone binary the installation is a go install of the command, and the running form uses go run with a host and port, which is convenient for a quick look without installing anything. The service also runs over HTTPS, and the example shows how, with a self-signed certificate generated using openssl and then passed to the binary with the certificate and key file flags. A third-party GitHub Action, lfreleng-actions/go-httpbin-action, makes a local instance available to other steps in a workflow, which is how you would use it to test a service under test inside a pipeline. The public instance of the service is at httpbingo.org, which is the same project deployed for general use.

## The configuration table is where the production risk lives

The configuration is a table of command line arguments, environment variables, documentation and defaults, and reading it tells you what a public instance is exposed to. The host defaults to 0.0.0.0 and the port to 8080. The maximum body size is one megabyte and the maximum duration a response may take is ten seconds, both of which are limits that exist to stop a public instance being used to exhaust somebody's memory or hold a connection open. There is a maximum header bytes setting for the underlying http.Server along with read header and read timeouts, which is the same reason. Two options are explicitly about hiding information, and both default to off. The full version option exposes the release, commit, build date and Go runtime through the version endpoint, with the service name only by default, and the real hostname option exposes what os.Hostname reports at the hostname endpoint. A third one is in a separate section under a warning, and it is the one to be careful with. The dangerous responses option allows endpoints to return unescaped HTML when clients control the response Content-Type, which enables cross site scripting attacks, and it is off by default. The readme points at the production considerations section for guidance on safe configuration of public instances.

## Non-root containers, and the two ways that breaks

Since image version 2.19.0 the prebuilt images run as a non-root user by default, which improves container security at the cost of some complexity for non-standard deployments, and the documentation explains both of the cases where that bites. The first is a privileged port combined with the Docker host network, where you may need to run the container as root to enable the CAP_NET_BIND_SERVICE capability, and the example shows the flags for it, with the network set to host, the user set to root, all capabilities dropped and then the one capability added back, running the binary directly on port 80. The second is enabling HTTPS inside the image, where the certificate and private key files have to be readable by the user running the process, and the example shows the permission changes, including a comment identifying the group id 65532 as the primary group of the nonroot user in the distroless static nonroot base image. The Dockerfile itself explains the choice of base images, building from a Go image and running the result on distroless static nonroot, and it exposes port 8080 with the binary as the command.

## The build and test tooling is pinned and thorough

The Makefile shows how seriously the project treats its toolchain. The third party tools are not installed but run at pinned versions through go run, with gofumpt at 0.9.2, goreleaser at 2.15.2, pinact at 4.1.0 for the GitHub Actions pinner, reflex at 0.3.2, revive at 1.15.0 and staticcheck at 2026.1. The build target produces a static binary with CGO disabled, and it stamps the commit and the build date into the binary through linker flags, which is what makes the version endpoint able to report the build date as well as the release. The test target runs go test with the race detector enabled by default through a variable, and the coverage target adds an atomic cover mode and a profile written to a coverage file, with the test arguments and the coverage arguments both overridable. A separate target builds a test binary, and the examples directory has its own build-all script. The repository also carries a golangci configuration, a goreleaser configuration, a pinact configuration for the workflow action pins, a codecov configuration, a development document and a security policy.

## An active project, and a v2 module path

The maintenance picture is straightforward. The releases are v2.26.0 on 2026-10-15, v2.25.0 on 2026-07-26 and v2.24.0 on 2026-07-15, and the last push was on 2026-10-15, so the project ships regularly and the newest tag matches the newest commit. The module path carries the major version, github.com/mccutchen/go-httpbin/v2, which is the Go convention for a module at version 2 and above, and it appears in every import path in the documentation, in the go get line, the go install line and the go run invocations. The licence is MIT. The project also carries a codecov badge, a build status badge and a Docker pulls badge, which is the usual set of signals for a service that is both a library and a running thing. The top level has an examples directory with a build-all script and a custom-instrumentation example, and the httpbin directory is the package that holds the handlers, with an internal directory alongside it, a cmd directory for the binary and the kustomize directory for the Kubernetes deployment.

## Conclusion

go-httpbin is a good fit for a Go team whose tests depend on an upstream service that misbehaves on demand, because the library gives you a server that can delay, redirect, fail and lie about its content type, and the importable package means the test does not need a running container. It is the wrong choice if you need a public service on the open internet, since the documentation is explicit that a public instance needs careful configuration, and it is the wrong choice if you need behaviour that the port does not implement, since it covers the httpbin API rather than all of it. It is also the wrong choice if you are not on Go, since the whole point is the importable package and the zero dependency footprint. Before exposing an instance, read the production considerations section and at minimum restrict the redirect-to endpoint, and note that the default configuration exposes a full version endpoint and a real hostname. The project is MIT licensed, the last push was on 2026-10-15, and the current release is v2.26.0 from the same day.

## FAQ

### What is go-httpbin and what does it give you over the original httpbin?

It is a reasonably complete and well-tested Go port of Kenneth Reitz's httpbin service, with zero dependencies outside the Go standard library, so the go.mod file has no requirements at all. It ships as container images, a standalone binary and an importable package, and a public instance runs at httpbingo.org.

### How do I use go-httpbin inside a Go test?

Import the httpbin package, create an app with httpbin.New(), wrap it in an httptest.NewServer, and make requests against it. The documented example asserts a timeout against the delay endpoint using a client with a one second timeout, and the server is closed with defer so nothing leaks between tests.

### How do I install go-httpbin as a dependency or as a binary?

As a dependency with go get -u github.com/mccutchen/go-httpbin/v2, and as a binary with go install github.com/mccutchen/go-httpbin/v2/cmd/go-httpbin@latest. You can also run it on demand with go run pointing at the same command path, passing a host and a port.

### What configuration is dangerous in go-httpbin?

The dangerous responses option, which allows endpoints to return unescaped HTML when clients control the response Content-Type and thereby enables cross site scripting attacks, is off by default and the documentation marks it as dangerous and deprecated. On a public instance you also want to restrict the domains the redirect-to endpoint may send traffic to, and keep the full version and real hostname options disabled.

### How do the go-httpbin container images handle non-root execution?

Prebuilt images at version 2.19.0 and later run as a non-root user by default, on a distroless static nonroot base, and the documentation explains the two cases that need extra work, running on a privileged port with host networking where you need root to enable CAP_NET_BIND_SERVICE, and serving HTTPS from inside the image where the certificate and key files must be readable by the running user.

## Sources

- [License: MIT](https://github.com/mccutchen/go-httpbin/blob/main/LICENSE)
- [mccutchen/go-httpbin on GitHub](https://github.com/mccutchen/go-httpbin)
- [Project website](https://httpbingo.org)
- [README](https://github.com/mccutchen/go-httpbin/blob/main/README.md)
- [Releases](https://github.com/mccutchen/go-httpbin/releases)

---

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