usm serve¶
Full-featured directory server — uploads, drag-and-drop UI, range
requests, on-the-fly zip / tar.gz, QR codes, basic auth — built on
miniserve (a single Rust
binary). usm auto-installs the binary on first run, locally or on a
remote SSH host. No system packages, no sudo.
usm serve ./reports # serve the directory locally
usm serve ~/data -p 8000 --bind 0.0.0.0 # expose on the LAN
usm serve ~/data --no-upload # read-only
usm serve ~/data -a alice:wonderland -q # basic auth + terminal QR code
usm serve user@host:/srv/logs # spawn miniserve on the remote
usm serve user@host:~/models -p 8080 # ssh -L brings it to localhost
usm serve ~/data --tunnel u@bastion # push: serve locally, expose on bastion
What it does¶
- Resolves a binary: prefers
~/.cache/usm/bin/miniserve(the usm-managed install), then$PATH, otherwise downloads the appropriate pinned release into~/.cache/usm/bin/miniserve(chmod +x). On the remote, same logic — miniserve lives under~/.cache/usm/bin/miniserveand is downloaded viacurl,wget, orpython3urllib (whichever the host has). - Spawns miniserve:
- Local source — directly, on
--bind:--port. - Remote source (
user@host:/path) — overssh -L LPORT:127.0.0.1:RPORTso the server stays on the remote's127.0.0.1and you get it on your laptop. - Forwards Ctrl-C to the whole tree (server + ssh) for clean shutdown.
Defaults¶
| Option | Default | Why |
|---|---|---|
--upload / --no-upload |
upload | Uploads (with mkdir + overwrite) are on; pass --no-upload for read-only. |
--delete |
off | Deletion is destructive — opt-in only. |
--hidden / --no-hidden |
hidden | Dotfiles are listed by default (it's almost always what you want when sharing your own files). |
--bind |
127.0.0.1 |
LAN exposure is explicit (--bind 0.0.0.0). |
--auth |
none | Set with USER:PASS; see miniserve docs for hashed form. |
| archives | on | Three download buttons (.tar, .tar.gz, .zip) at the top of every folder page; pass --no-archive to disable. |
--upgrade (-U) |
— | Force re-download of the miniserve binary on this run. |
--ssh-timeout |
30 |
Seconds per remote setup command, including connection/authentication. Binary installation allows at least 180 seconds. |
SSH setup timeouts¶
A path/platform probe timed out error happens before miniserve starts.
The timeout covers connection, authentication, remote shell startup, and the
path/platform command; it does not identify which stage stalled. Increase the
budget for a slow host or jump connection:
Setup commands use non-interactive SSH (BatchMode=yes): key/agent
authentication must already work. They disable TTY allocation, configured
RemoteCommand, and inherited port forwards, while still using the host alias,
user, identity, and proxy settings in your SSH config. The serving session also
disables TTY allocation and RemoteCommand, but keeps its requested -L tunnel.
On timeout, serve includes any captured SSH stderr and a matching ssh -vvv
diagnostic command. Run that command in the same terminal/environment as
usm. If it also stalls, inspect the last verbose messages for proxy,
authentication, or remote shell startup problems; increasing a timeout will
not fix a blocked login or shell startup script.
Local vs. remote — picking the right command¶
usm share |
usm serve |
|
|---|---|---|
| Engine | stdlib http.server |
miniserve (Rust binary) |
| Extra install | none | ~2.3 MB binary, auto-downloaded |
| Range / resume | no | yes |
| Upload | no | yes (drag-drop UI) |
| Directory zip / tar.gz | no | yes |
| Browser UI | basic listing | dark-themed, sortable, searchable |
| Remote runtime | python3 / uv | self-contained binary |
Use share for the absolute minimal-dependency case (and when you
just want to push something to a teammate's box). Use serve for
serious browsing / large files / uploads / "give me the whole
folder".
Security notes¶
- Default bind is
127.0.0.1; you have to be explicit to expose on the LAN. - Uploads default to on because that's the whole point of running
this instead of
usm share. If you're serving over a network you don't trust, add--auth USER:PASS(or pass--no-upload). - Remote (
user@host:/path) mode binds miniserve to the remote's127.0.0.1only; the ssh tunnel does the rest. No remote port is exposed publicly.