http-server: a zero-config static file server that still handles proxying, TLS and basic auth
A simple, zero-configuration, command-line http server
At a glance
- What is it?
- 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.
- Who is it for?
- 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.
- 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 175 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 October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
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:
npx http-server [path] [options]
npm install --global http-server
brew install http-server
npm install http-serverThose 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:
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.
http-server -p 8080 -c-1Once 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:
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:
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pemThat 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:
"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.
Editorial 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.
Frequently asked questions
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.
Official sources
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.
[](https://hysenlabs.com/projects/http-party-http-server)