# http-server: a zero-config static file server that still handles proxying, TLS and basic auth

> The npm package most developers meet as a one-line local server does considerably more than serve a directory. Here is the option surface that is genuinely useful, and the parts that quietly do not work the way the flag names suggest.

**http-party/http-server** — A simple, zero-configuration, command-line http server

- Repository: https://github.com/http-party/http-server
- Stars: 14,236 · Forks: 1,557
- Language: JavaScript
- License: MIT
- Published: 2026-10-06 · Updated: 2026-10-06 · Language: en
- Canonical page: https://hysenlabs.com/projects/http-party-http-server

## Installing it three ways in under a minute

The fastest path uses npx, which runs the package without installing it. This is the one to reach for when you want a server for thirty seconds and do not want it in your dependency tree:

```bash
npx http-server [path] [options]
npm install --global http-server
brew install http-server
npm install http-server
```

Those four lines cover the four real install routes: on demand via npx, globally via npm, globally via Homebrew on macOS, and as a dependency inside an existing package. The last one is the one people forget. Because `http-server` is an ordinary npm package with a `bin` entry, it can be a devDependency and run from project scripts, which is how it usually ends up in real repositories.

The Docker route exists but with an explicit caveat: no public image is provided, so you build it yourself from the included Dockerfile. That file is five effective lines and gives you the essentials:

```bash
FROM node:16-alpine
VOLUME /public
WORKDIR /srv/http-server
EXPOSE 8080
ENTRYPOINT ["node", "./bin/http-server"]
```

Note what the Dockerfile does not do. It sets no user, so the container runs as root inside, and the `VOLUME` declaration is the mount point you bind to. The README's own run example mounts the working directory onto `/public`, which is where the server looks by default.

One requirement is easy to miss. The manifest declares `node >=16.20.2` in its engines field, and the Dockerfile is pinned to `node:16-alpine`. That base image is long past its upstream support window, so treat the container path as something to rebuild on a current Node release if you depend on it.

## Which directory gets served, and what happens when nothing is there

The usage line is short, `http-server [path] [options]`, but the default path rule is where confusion starts. If a `./public` directory exists, it is served. Otherwise the server serves the current directory. That single rule explains the most common support question about this package, which is why a freshly cloned project with a `public` folder will not serve what you expected.

```bash
http-server -p 8080 -c-1
```

Once running, the server listens on `http://localhost:8080`. Three defaults are worth internalizing before you change anything. Caching is on, with a default cache-control max-age of 3600 seconds, which surprises people who edit a file and see the old version. The disable flag is `-c-1`. Directory listings are on by default, controlled by `-d`, and the connection timeout defaults to 120 seconds, disabled with `-t0`.

The auto-index behaviour has a companion switch worth pairing with it. `-i` controls the auto-index display, and `--dir-overrides-404` decides whether a directory listing takes precedence over a custom `404.html`. Left at its default of false, a directory request serves your custom error page instead of the file listing, which is the behaviour you want for a single-page app and not what you want when you are browsing a tree.

Magic files do the rest. `index.html` answers any directory request, and `404.html` is served when a file is missing. The README names the second use explicitly: point it at a single-page app's entry page and deep links resolve to your app instead of an error.

## The proxy flags, and the catch-all redirect built on them

This is the feature that separates http-server from the dozen one-line static servers, and it is the reason it has survived since 2014. `-P` or `--proxy` forwards requests that cannot be resolved locally to a given URL. `--proxy-all` goes further and forwards everything, ignoring local files. Two further flags tune the proxy itself: `--proxy-options` passes nested dotted options through to the node-http-proxy layer, and `--proxy-config` takes a JSON file path or a stringified object.

The catch-all redirect is the cleverest thing in the README and the reason a lot of people keep this installed. Point the proxy at the local server's own address with a trailing question mark:

```bash
http-server --proxy http://localhost:8080?
```

Anything that resolves to a real file is served locally. Everything else falls through to the same server with the `?` appended, which lands on the index page. That single line gives you single-page app host routing on a server that knows nothing about routers, and the README credits the trick to a contributor rather than claiming it as a core feature, which tells you it arrived from outside and stuck.

Compression flags sit alongside the proxy in the same spirit. `--gzip` serves `some-file.js.gz` in place of `some-file.js` when the compressed file exists and the request accepts gzip, and `--brotli` does the same for `.br`. When both are enabled, brotli is tried first. Neither compresses anything for you, so the compressed artefact has to be in the served directory already.

For access control there are `--user` and `--password` for basic authentication. That is real HTTP basic auth, which means credentials travel base64-encoded unless you combine it with `-S`.

## HTTPS, headers and the flags that quietly change behaviour

TLS is three flags: `-S` or `--ssl` to enable it, `-C` or `--cert` pointing at a certificate file, and `-K` or `--key` for the key. Defaults are `cert.pem` and `key.pem` in the working directory, and openssl generates a self-signed pair with one command:

```bash
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
```

That certificate is self-signed, so browsers will warn on every visit unless you trust it locally. Fine for a LAN test, unsuitable for anything else.

The header flags cover most of what a front-end developer needs in a dev server. `--cors` sets `Access-Control-Allow-Origin` and optionally takes comma-separated values to add to `Access-Control-Allow-Headers`. `--coop` enables the `Cross-Origin-Opener-Policy` header, and `--private-network-access` sets `Access-Control-Allow-Private-Network`, which is the header modern browsers require before a public page can reach a service on your local network. `-H` adds an arbitrary response header and can be repeated.

Then there is the set that changes defaults you would otherwise expect to be fixed. `--allowed-hosts` takes a comma-separated list and restricts which hostnames may reach the server, which turns a dev tool that binds to `0.0.0.0` by default into something less exposed on a shared network. `--no-dotfiles` hides dotfiles from listings and requests. `--no-panic` redirects stack traces into a log file rather than the console. `-T` sets a custom terminal window title.

Two flags exist purely for convenience and are easy to over-use: `-o` opens a browser window after startup and accepts a path to open instead of the root, and `-U` switches log timestamps to UTC.

Robots exclusion is `-r`, which auto-generates a `/robots.txt` defaulting to disallowing everything. Useful for staging a build you do not want indexed, provided you remember it is off by default.

## Testing setup, the release history and what the project does not claim

The repository is small and well organised. `lib/` holds the implementation, `bin/` the executable, `test/` the test suite, `doc/` a man page, and `public/` the default served directory. There is a `Dockerfile`, a `SECURITY.md`, a `CODE_OF_CONDUCT.md`, and the continuous integration badge points at a GitHub Actions workflow running on Node. The test script uses tap with a terse reporter:

```bash
"start": "node ./bin/http-server",
"test": "tap --reporter=terse --allow-incomplete-coverage test/*.test.js"
```

The published npm package includes only `lib`, `bin` and `doc`, which is a sensible trim: you install a server, not a repository.

The release history is short and explains something. Three releases are recorded: v13.1.0 and v14.1.0, both published on the same day in January 2022, and v14.1.1 in May 2022. The January pair are an emergency backport, replacing the `colors.js` dependency with `chalk` after the colours package caused a widely publicised incident in the wider npm ecosystem. The May release is a patch for CVE-2021-44906 plus a dependency bump of `follow-redirects`. The manifest in the repository already reads version 14.1.2, which was never tagged.

So the honest summary is that releases have been quiet for a long time while commits continued, with the last push on 2026-04-15. For a tool whose whole purpose is serving files, that is a defensible place to be. It is also a reminder that the dependency on `follow-redirects`, which was bumped specifically to address a redirect-following vulnerability, is worth checking in any long-lived install of your own.

There is no claim here of a feature set beyond static serving plus those options. The README describes the project as simple and hackable, and it is worth resisting the temptation to treat it as a production web server, because the option list is long enough to create that impression while containing nothing about concurrency limits, request logging to a file, rate limiting or process supervision.

## Conclusion

http-server is the right choice when you need to serve a directory over HTTP in under a minute, and the wrong choice the moment you need multi-user isolation, HTTPS with a real certificate, or anything resembling request routing. The proxy flags are the reason many people stay with it, and the catch-all redirect trick built on top of them is genuinely clever. Its last push was on 2026-04-15 and the newest tagged release is v14.1.1 from 2022, while the manifest already reads 14.1.2, so install from npm rather than expecting a fresh tag. License is MIT.

## FAQ

### How do I install http-server and serve a directory?

Run `npx http-server [path]` for a one-off server with no install, or `npm install --global http-server` to have the command available everywhere. The path defaults to `./public` when that directory exists and to the current directory otherwise, so being explicit about the path avoids the most common surprise. The server listens on http://localhost:8080 by default.

### How do I turn off caching so I see my latest file changes?

Add `-c-1` to the command line. The default cache-control max-age is 3600 seconds, which is why edits sometimes appear not to take effect. The `-c` flag takes a value in seconds, so `-c10` sets a ten second cache instead.

### How do I serve an HTTPS site locally with http-server?

Generate a self-signed pair with openssl, producing `key.pem` and `cert.pem`, then start the server with `-S`, or `--ssl`. Those are also the default file names the flags look for. Because the certificate is self-signed, browsers warn on every visit unless you add it to your local trust store.

### What does the --proxy flag do, and what is the catch-all redirect trick?

`-P` forwards requests that cannot be resolved to a local file to the URL you give it. The catch-all redirect runs the server as its own proxy by pointing `--proxy` at the server's own address with a trailing question mark, as in `http-server --proxy http://localhost:8080?`. Files are served normally and everything else falls through to the index page, which gives single-page app routing without a router.

## Sources

- [http-party/http-server on GitHub](https://github.com/http-party/http-server)
- [Issues](https://github.com/http-party/http-server/issues)
- [License: MIT](https://github.com/http-party/http-server/blob/master/LICENSE)
- [README](https://github.com/http-party/http-server/blob/master/README.md)
- [Releases](https://github.com/http-party/http-server/releases)

---

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