http.server (🐍); http-server (JS); devd (golang); miniserve (Rust)
Whether exfiltrating company seekrits, letting a friend quickly grab some movie you torrented, or legitimately needing to test some HTML/JS/WASM/CSS creation you've built, sometimes you just need to fire up a web server right now with as little pain as possible. Depending on your preferred base environment, you may be able to "live off the land" and not even have to install anything; or, you may want to BYO cross-platform single-executable wherever you find yourself. Regardless of the environment, there are some considerations to take into account:
Do you need TLS enabled?
Is CGI functionality necessary?
Would having an automagically available domain name to use be helpful?
How fancy do you need the default directory viewer
Will your use-case benefit from being able to monitor files for changes?
Might CORS support be helpful?
Should it support file uploads and/or authentication?
Each section has some short commentary, repo links and the "help" output for each. There will, ofc, be some obligatory pot shots at the truly inferior members of the list.
If you’re on a larger glowing rectangle, scroll through each section for the commentary, but the help output will be hard to sift through, so here are the four options:
and, an easier-to-browse-on-mobile experience in this gist.
With the final coming of age of an almost usable-by-default Python installation (i.e., later Python 3.x versions), gone are the days of the “venerable”
-m SimpleHTTPServer command line parameters which would have made the current, or specified, directory available locally or to the local LAN or scary internets. Now, said incantation is an easier to type
-m http.server with the barest of bones for options:
usage: server.py [-h] [--cgi] [--bind ADDRESS] [--directory DIRECTORY] [port] positional arguments: port specify alternate port (default: 8000) options: -h, --help show this help message and exit --cgi run as CGI server --bind ADDRESS, -b ADDRESS specify alternate bind address (default: all interfaces) --directory DIRECTORY, -d DIRECTORY specify alternate directory (default: current directory)
Python is, sadly, likely taking up precious storage space on any given system you may find yourself using, making this the most ubiquitously supported way to get your web on.
npm install -g http-server gives you loads of options to choose from:
usage: http-server [path] [options] options: -p --port Port to use. If 0, look for open port.  -a Address to use [0.0.0.0] -d Show directory listings [true] -i Display autoIndex [true] -g --gzip Serve gzip files when possible [false] -b --brotli Serve brotli files when possible [false] If both brotli and gzip are enabled, brotli takes precedence -e --ext Default file extension if none supplied [none] -s --silent Suppress log messages from output --cors[=headers] Enable CORS via the "Access-Control-Allow-Origin" header Optionally provide CORS headers list separated by commas -o [path] Open browser window after starting the server. Optionally provide a URL path to open the browser window to. -c Cache time (max-age) in seconds , e.g. -c10 for 10 seconds. To disable caching, use -c-1. -t Connections timeout in seconds , e.g. -t60 for 1 minute. To disable timeout, use -t0 -U --utc Use UTC time format in log messages. --log-ip Enable logging of the client's IP address -P --proxy Fallback proxy if the request cannot be resolved. e.g.: http://someurl.com --proxy-options Pass options to proxy using nested dotted objects. e.g.: --proxy-options.secure false --username Username for basic authentication [none] Can also be specified with the env variable NODE_HTTP_SERVER_USERNAME --password Password for basic authentication [none] Can also be specified with the env variable NODE_HTTP_SERVER_PASSWORD -S --tls --ssl Enable secure request serving with TLS/SSL (HTTPS) -C --cert Path to TLS cert file (default: cert.pem) -K --key Path to TLS key file (default: key.pem) -r --robots Respond to /robots.txt [User-agent: *\nDisallow: /] --no-dotfiles Do not show dotfiles --mimetypes Path to a .types file for custom mimetype definition -h --help Print this list and exit. -v --version Print the version and exit.
making this one of the most flexible options, provided you don't mind bringing a few dependencies along for the ride:
If both portability and high functionality are in your “must have” list, then, perhaps, look no further than the treasured golang utility, devd.
This utility seems to grok the needs of both developers and “hackers”:
usage: devd [<flags>] <route>... Flags: -h, --help Show context-sensitive help (also try --help-long and --help-man). -A, --address="127.0.0.1" Address to listen on -a, --all Listen on all addresses -c, --cert=PATH Certificate bundle file - enables TLS -C, --color Enable colour output, even if devd is not connected to a terminal -d, --down=N Throttle downstream from the client to N kilobytes per second -f, --notfound=PATH ... Default when a static file is not found -H, --logheaders Log headers -I, --ignore=REGEX ... Disable logging matching requests. Regexes are matched over 'host/path' -L, --livereload Enable livereload -l, --livewatch Enable livereload and watch for static file changes -m, --modd Modd is our parent - synonym for -LCt -n, --latency=N Add N milliseconds of round-trip latency -o, --open Open browser window on startup -p, --port=PORT Port to listen on - if not specified, devd will auto-pick a sensible port -P, --password=USER:PASS HTTP basic password protection -q, --quiet Silence all logs -s, --tls Serve TLS with auto-generated self-signed certificate (~/.devd.cert) -t, --notimestamps Disable timestamps in output -T, --logtime Log timing -u, --up=N Throttle upstream from the client to N kilobytes per second -w, --watch=PATH ... Watch path to trigger livereload -X, --crossdomain Set the CORS header Access-Control-Allowed: * -x, --exclude=PATTERN ... Glob pattern for files to exclude from livereload --debug Debugging for devd development --version Show application version. Args: <route> Routes have the following forms: [SUBDOMAIN]/<PATH>=<DIR> [SUBDOMAIN]/<PATH>=<URL> <DIR> <URL>
One of the more fun bits of trivia surrounding this server is the
devd.io domain which has an
A record that points to IPv4
$ dig +short devd.io 127.0.0.1
(this means you can use it with anything that bins to
Last, but far from “least”, is miniserve, a Rust-based web server with more options than you'll ever truly need:
miniserve 0.22.0 Sven-Hendrik Haase <firstname.lastname@example.org>, Boastful Squirrel <email@example.com> For when you really just want to serve some files over HTTP right now! USAGE: miniserve [OPTIONS] [--] [PATH] ARGS: <PATH> Which path to serve OPTIONS: -a, --auth <AUTH> Set authentication. Currently supported formats: username:password, username:sha256:hash, username:sha512:hash (e.g. joe:123, joe:sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3) -c, --color-scheme <COLOR_SCHEME> Default color scheme [default: squirrel] [possible values: squirrel, archlinux, zenburn, monokai] -d, --color-scheme-dark <COLOR_SCHEME_DARK> Default color scheme [default: archlinux] [possible values: squirrel, archlinux, zenburn, monokai] -D, --dirs-first List directories first -F, --hide-version-footer Hide version footer -g, --enable-tar-gz Enable gz-compressed tar archive generation -h, --help Print help information -H, --hidden Show hidden files --header <HEADER> Set custom header for responses --hide-theme-selector Hide theme selector -i, --interfaces <INTERFACES> Interface to listen on --index <index_file> The name of a directory index file to serve, like "index.html" -l, --show-symlink-info Visualize symlinks in directory listing -m, --media-type <MEDIA_TYPE> Specify uploadable media types [possible values: image, audio, video] -M, --raw-media-type <MEDIA_TYPE_RAW> Directly specify the uploadable media type expression -o, --overwrite-files Enable overriding existing files during file upload -p, --port <PORT> Port to use [default: 8080] -P, --no-symlinks Hide symlinks in listing and prevent them from being followed --print-completions <shell> Generate completion file for a shell [possible values: bash, elvish, fish, powershell, zsh] --print-manpage Generate man page -q, --qrcode Enable QR code display -r, --enable-tar Enable uncompressed tar archive generation --random-route Generate a random 6-hexdigit route --readme Enable README.md rendering in directories --route-prefix <ROUTE_PREFIX> Use a specific route prefix --spa Activate SPA (Single Page Application) mode -t, --title <TITLE> Shown instead of host in page title and heading --tls-cert <TLS_CERT> TLS certificate to use --tls-key <TLS_KEY> TLS private key to use -u, --upload-files [<ALLOWED_UPLOAD_DIR>...] Enable file uploading (and optionally specify for which directory) -U, --mkdir Enable creating directories -v, --verbose Be verbose, includes emitting access logs -V, --version Print version information -W, --show-wget-footer If enabled, display a wget command to recursively download the current directory -z, --enable-zip Enable zip archive generation
FWIW, I keep multiple platform binaries of
miniserve on a USB stick that is always with me and have them at various dead-drop sites across the internet, including gDrive and other cloud drives your company's security policies gladly let you access. You never know when you're going to “need” to serve up some files.
If you use one of these already or use a different one, drop your experiences in the comments for others to learn from. ☮