42 releases (23 breaking)
|0.24.0||Jul 6, 2023|
|0.23.0||Mar 1, 2023|
|0.22.0||Sep 20, 2022|
|0.20.0||Jun 26, 2022|
|0.1.5||May 17, 2018|
#17 in HTTP server
1,143 downloads per month
miniserve - a CLI tool to serve files and dirs over HTTP
For when you really just want to serve some files over HTTP right now!
miniserve is a small, self-contained cross-platform CLI tool that allows you to just grab the binary and serve some file(s) via HTTP. Sometimes this is just a more practical and quick way than doing things properly.
How to use
Serve a directory:
Serve a single file:
Set a custom index file to serve instead of a file listing:
miniserve --index test.html
Serve an SPA (Single Page Application) so that non-existent paths are forwarded to the SPA's router instead
miniserve --spa --index index.html
miniserve --auth joe:123 unreleased-linux-distros/
Require username/password as hash:
pw=$(echo -n "123" | sha256sum | cut -f 1 -d ' ') miniserve --auth joe:sha256:$pw unreleased-linux-distros/
Generate random 6-hexdigit URL:
miniserve -i 192.168.0.1 --random-route /tmp
Bind to multiple interfaces:
miniserve -i 192.168.0.1 -i 10.13.37.10 -i ::1 /tmp/myshare
Start with TLS:
miniserve --tls-cert my.cert --tls-key my.key /tmp/myshare
Upload a file using
miniserve -u -- . curl -F "path=@$FILE" http://localhost:8080/upload\?path\=/
$FILE is the path to the file. This uses miniserve's default port of 8080)
Note that for uploading, we have to use
-- to disambiguate the argument to
This is because
-u can also take a path (or multiple). If a path argument to
-u is given,
uploading will only be possible to the provided paths as opposed to every path.
Another effect of this is that you can't just combine flags like this
-u is used. In
this example, you'd need to use
Create a directory using
miniserve --upload-files --mkdir . curl -F "mkdir=$DIR_NAME" http://localhost:8080/upload\?path=\/
$DIR_NAME is the name of the directory. This uses miniserve's default port of 8080.)
Take pictures and upload them from smartphones:
miniserve -u -m image -q
This uses the
--media-type option, which sends a hint for the expected media type to the browser.
Some mobile browsers like Firefox on Android will offer to open the camera app when seeing this.
- Easy to use
- Just works: Correct MIME types handling out of the box
- Single binary drop-in with no extra dependencies required
- Authentication support with username and password (and hashed password)
- Mega fast and highly parallel (thanks to Rust and Actix)
- Folder download (compressed on the fly as
- File uploading
- Directory creation
- Pretty themes (with light and dark theme support)
- Scan QR code for quick access
- Shell completions
- Sane and secure defaults
- TLS (for supported architectures)
- Supports README.md rendering like on GitHub
- Range requests
For when you really just want to serve some files over HTTP right now! Usage: miniserve [OPTIONS] [PATH] Arguments: [PATH] Which path to serve [env: MINISERVE_PATH=] Options: -v, --verbose Be verbose, includes emitting access logs [env: MINISERVE_VERBOSE=] --index <INDEX> The name of a directory index file to serve, like "index.html" Normally, when miniserve serves a directory, it creates a listing for that directory. However, if a directory contains this file, miniserve will serve that file instead. [env: MINISERVE_INDEX=] --spa Activate SPA (Single Page Application) mode This will cause the file given by --index to be served for all non-existing file paths. In effect, this will serve the index file whenever a 404 would otherwise occur in order to allow the SPA router to handle the request instead. [env: MINISERVE_SPA=] -p, --port <PORT> Port to use [env: MINISERVE_PORT=] [default: 8080] -i, --interfaces <INTERFACES> Interface to listen on [env: MINISERVE_INTERFACE=] -a, --auth <AUTH> Set authentication. Currently supported formats: username:password, username:sha256:hash, username:sha512:hash (e.g. joe:123, joe:sha256:a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3) [env: MINISERVE_AUTH=] --route-prefix <ROUTE_PREFIX> Use a specific route prefix [env: MINISERVE_ROUTE_PREFIX=] --random-route Generate a random 6-hexdigit route [env: MINISERVE_RANDOM_ROUTE=] -P, --no-symlinks Hide symlinks in listing and prevent them from being followed [env: MINISERVE_NO_SYMLINKS=] -H, --hidden Show hidden files [env: MINISERVE_HIDDEN=] -c, --color-scheme <COLOR_SCHEME> Default color scheme [env: MINISERVE_COLOR_SCHEME=] [default: squirrel] [possible values: squirrel, archlinux, zenburn, monokai] -d, --color-scheme-dark <COLOR_SCHEME_DARK> Default color scheme [env: MINISERVE_COLOR_SCHEME_DARK=] [default: archlinux] [possible values: squirrel, archlinux, zenburn, monokai] -q, --qrcode Enable QR code display [env: MINISERVE_QRCODE=] -u, --upload-files [<ALLOWED_UPLOAD_DIR>] Enable file uploading (and optionally specify for which directory) [env: MINISERVE_ALLOWED_UPLOAD_DIR=] -U, --mkdir Enable creating directories [env: MINISERVE_MKDIR_ENABLED=] -m, --media-type <MEDIA_TYPE> Specify uploadable media types [env: MINISERVE_MEDIA_TYPE=] [possible values: image, audio, video] -M, --raw-media-type <MEDIA_TYPE_RAW> Directly specify the uploadable media type expression [env: MINISERVE_RAW_MEDIA_TYPE=] -o, --overwrite-files Enable overriding existing files during file upload [env: OVERWRITE_FILES=] -r, --enable-tar Enable uncompressed tar archive generation [env: MINISERVE_ENABLE_TAR=] -g, --enable-tar-gz Enable gz-compressed tar archive generation [env: MINISERVE_ENABLE_TAR_GZ=] -z, --enable-zip Enable zip archive generation WARNING: Zipping large directories can result in out-of-memory exception because zip generation is done in memory and cannot be sent on the fly [env: MINISERVE_ENABLE_ZIP=] -D, --dirs-first List directories first [env: MINISERVE_DIRS_FIRST=] -t, --title <TITLE> Shown instead of host in page title and heading [env: MINISERVE_TITLE=] --header <HEADER> Set custom header for responses [env: MINISERVE_HEADER=] -l, --show-symlink-info Visualize symlinks in directory listing [env: MINISERVE_SHOW_SYMLINK_INFO=] -F, --hide-version-footer Hide version footer [env: MINISERVE_HIDE_VERSION_FOOTER=] --hide-theme-selector Hide theme selector [env: MINISERVE_HIDE_THEME_SELECTOR=] -W, --show-wget-footer If enabled, display a wget command to recursively download the current directory [env: MINISERVE_SHOW_WGET_FOOTER=] --print-completions <shell> Generate completion file for a shell [possible values: bash, elvish, fish, powershell, zsh] --print-manpage Generate man page --tls-cert <TLS_CERT> TLS certificate to use [env: MINISERVE_TLS_CERT=] --tls-key <TLS_KEY> TLS private key to use [env: MINISERVE_TLS_KEY=] --readme Enable README.md rendering in directories [env: MINISERVE_README=] -h, --help Print help (see a summary with '-h') -V, --version Print version
How to install
On Linux: Download
miniserve-linux from the releases page and run
chmod +x miniserve-linux ./miniserve-linux
Alternatively, if you are on Arch Linux, you can do
pacman -S miniserve
pkg install miniserve
On OSX: Download
miniserve-osx from the releases page and run
chmod +x miniserve-osx ./miniserve-osx
Alternatively install with Homebrew:
brew install miniserve miniserve
On Windows: Download
miniserve-win.exe from the releases page and run
Alternatively install with Scoop:
scoop install miniserve
With Cargo: Make sure you have a recent version of Rust. Then you can run
cargo install --locked miniserve miniserve
With Docker: Make sure the Docker daemon is running and then run
docker run -v /tmp:/tmp -p 8080:8080 --rm -it docker.io/svenstaro/miniserve /tmp
With Podman: Just run
podman run -v /tmp:/tmp -p 8080:8080 --rm -it docker.io/svenstaro/miniserve /tmp
If you'd like to make use of the built-in shell completion support, you need to run
miniserve --print-completions <your-shell> and put the completions in the correct place for your shell. A
few examples with common paths are provided below:
miniserve --print-completions bash > ~/.local/share/bash-completion/completions/miniserve miniserve --print-completions zsh > /usr/local/share/zsh/site-functions/_miniserve miniserve --print-completions fish > ~/.config/fish/completions/miniserve.fish
A hardened systemd-compatible unit file can be found in
packaging/miniserve@.service. You could
install this to
/etc/systemd/system/miniserve@.service and start and enable
miniserve as a
daemon on a specific serve path
/my/serve/path like this:
systemctl enable --now miniserve@-my-serve-path
Keep in mind that you'll have to use
systemd-escape to properly escape a path for this usage.
In case you want to customize the particular flags that miniserve launches with, you can use
systemctl edit miniserve@-my-serve-path
and set the
[Service] part in the resulting
override.conf file. For instance:
[Service] ExecStart=/usr/bin/miniserve --enable-tar --enable-zip --no-symlinks --verbose -i ::1 -p 1234 --title hello --color-scheme monokai --color-scheme-dark monokai -- %I
Make sure to leave the
%I at the very end in place or the wrong path might be served. You
might additionally have to override
IPAddressDeny if you plan on making
miniserve directly available on a public interface.
For convenience reasons, miniserve will try to bind on all interfaces by default (if no
-i is provided).
It will also do that if explicitly provided with
-i 0.0.0.0 or
In all of the aforementioned cases, it will bind on both IPv4 and IPv6.
If provided with an explicit non-default interface, it will ONLY bind to that interface.
You can provide
-i multiple times to bind to multiple interfaces at the same time.
Why use this over alternatives?
- darkhttpd: Not easily available on Windows and it's not as easy as download-and-go.
- Python built-in webserver: Need to have Python installed, it's low performance, and also doesn't do correct MIME type handling in some cases.
- netcat: Not as convenient to use and sending directories is somewhat involved.
This is mostly a note for me on how to release this thing:
- Make sure
CHANGELOG.mdis up to date.
cargo release <version>
cargo release --execute <version>
- Releases will automatically be deployed by GitHub Actions.
- Update Arch package.