servd

module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: MIT

README

servd

CI Go Report Card Go Reference Go Version

Run and manage many local dev servers at once.

servd runs your registered web projects on stable ports and reverse-proxies them as friendly nip.io subdomains — so a folder of client sites becomes http://acme.127.0.0.1.nip.io:8080/, http://blog.127.0.0.1.nip.io:8080/, and so on, all managed from one CLI or an interactive TUI.

It is not tied to any one generator. jigyll/Jekyll is just one of several detectors; Node, Hugo, just/make recipes, plain static dirs, and any project with a Procfile work too.

Install

Homebrew — macOS and Linux
brew install reidransom/tap/servd
Scoop — Windows
scoop bucket add reidransom https://github.com/reidransom/scoop-bucket
scoop install reidransom/servd
Release archive

Download the archive for your operating system and architecture, plus checksums.txt, from the latest GitHub release. Windows archives are ZIP files; macOS and Linux archives are tarballs. Verify the archive before extracting it:

# macOS or Linux: compare this hash with the matching checksums.txt entry
shasum -a 256 servd_Darwin_arm64.tar.gz
# Windows: compare this hash with the matching checksums.txt entry
Get-FileHash .\servd_Windows_x86_64.zip -Algorithm SHA256

Each archive contains servd (servd.exe on Windows), README.md, and LICENSE.

Go install

With the Go version declared in go.mod or newer:

go install github.com/reidransom/servd/cmd/servd@latest

Every installation method can report its exact version without reading config or starting the TUI:

servd version

Quick start

servd add ~/clients/acme  # detect the launcher, assign a port + slug
servd up --all            # start every registered dev server
servd proxy up            # start the nip.io reverse proxy on :8080
servd                     # open the interactive dashboard (TUI)

Every entry in sites.toml is managed by servd and participates in up --all and restart --all. To start a single registered site, name it: servd up acme.

Then visit http://<slug>.127.0.0.1.nip.io:8080/ for any site, or http://127.0.0.1:8080/ for a landing page listing them all. nip.io resolves *.127.0.0.1.nip.io to 127.0.0.1 with zero DNS setup.

How a project is launched

For each site, servd resolves a launch command in this order (first match wins):

  1. Manual override — a command pinned at registration, either quoted (servd add . --cmd "…") or unquoted after -- (servd add . -- bundle exec middleman serve -p {port}).
  2. .servd.toml in the project directory — a one-line cmd = "bundle exec middleman serve -p {port}" lets any project declare how to serve itself, next to its code.
  3. Procfile (or Procfile.dev) — the web: process, run with $PORT and $HOST exported (foreman/Heroku convention). The universal escape hatch.
  4. Launcher rules — declarative match-and-run rules, tried in order. Your own rules from ~/.config/servd/launchers.toml come first, then the built-in defaults:
    Rule Trigger Command
    jigyll / Jekyll _config.yml jigyll serve -s . -H {host} -P {port} -w
    Hugo hugo.toml / content dir hugo serve --bind {host} -p {port}
    Node package.json dev/serve/start script npm run <script> (+--port for vite/next/astro)
    just justfile with serve recipe just serve
    make Makefile with serve target make serve PORT={port}
    static an index.html built-in file server (no dependency)

PORT and HOST are always exported to the child, and {port}/{host} placeholders are substituted — so Procfiles and rule commands share one port-injection mechanism. Run servd which <slug> to see exactly what a project resolves to.

Custom launcher rules

The built-in table above is data, not code — every rule is defined in the same TOML format you can write yourself. servd launchers prints the effective rule set; copy any rule into ~/.config/servd/launchers.toml to change it (same name replaces the built-in, disabled = true turns it off), or add rules for tools servd has never heard of:

[[launcher]]
name = "middleman"
matches = { file = "Gemfile", regex = "middleman" }   # file content regex
bin = "middleman"                                     # required on PATH
cmd = "bundle exec middleman serve -p {port}"

[[launcher]]
name = "static"        # replace the built-in fallback file server
exists = ["index.html"]
bin = "python3"
cmd = "python3 -m http.server -b {host} {port}"

User rules are always tried before the built-ins, in file order. A rule matches a directory when all of its predicates hold; list values match any-of:

Predicate Meaning
exists = ["hugo.*"] any file matches (globs ok)
dirs = ["content"] any directory matches (globs ok)
bin = "hugo" binary is on PATH
recipe = { files = ["justfile"], target = "serve" } make/just file declares the target
matches = { file = "Gemfile", regex = "…" } file content matches the regex
npm_script = ["dev", "serve"] package.json has one of these scripts

In cmd, {port}/{host} are substituted at launch, {script} is the matched npm_script entry, and {self} is the servd binary itself. For dev servers that ignore $PORT, port_flag = " -- --port {port}" is appended when any port_flag_deps entry appears in package.json dependencies.

Commands

Command Purpose
servd add <path> [--slug] [--port] [--cmd] [-- <command>…] register one project
servd rm <slug> stop and unregister a site
servd which <slug> show the resolved launch command
servd launchers print the effective launcher rules (yours + built-ins)
servd status [slug] (alias ls) table of every site, or one named site, with live status (--json for machines)
servd up [slug…] [--all] start sites (--all starts every registered site; --wait/--json for scripts)
servd down [slug…] [--all] stop sites (--all stops every registered site)
servd restart [slug…] [--all] restart sites (--all restarts every registered site)
servd logs <slug> [-f] show / follow a site's server output
servd open <slug> open the nip.io URL in a browser
servd proxy up|down|status manage the background reverse proxy
servd proxy run the proxy in the foreground
servd doctor check tools, ports and nip.io resolution
servd version / servd --version report version, commit, and build date
servd / servd tui interactive dashboard

The dashboard is a split view: the site list on the left, and a live tail of the highlighted site's log on the right, led by the $ command that started (or would start) it. Moving the selection switches the log panel; tab moves focus to the log so ↑/↓ scroll it (scroll up to pause the tail, scroll back to the bottom to resume following).

TUI keys

↑/↓ move · tab focus list/log · s start · x stop · r restart · a start-all · X stop-all · o open · p toggle proxy · A add a site (type a path, tab completes) · h show/hide this key help · q quit

Agents and scripts

Coding agents (and shell scripts) shouldn't have to parse tables or babysit long-running processes. Two flags give them a structured interface:

servd status --json            # everything an agent needs to discover servers
servd status acme --json       # status for one known server

status --json prints one object: proxy (running, accepting, pid, port, url) plus a sites array (containing only the requested site when a slug is supplied) where each site carries slug, path, port, url (through the proxy), direct_url (straight to the dev server), launcher, status (stopped | starting | running), and — when live — pid, cmd, log, started_at, uptime_seconds. Match your project by path to find its slug, then hit direct_url (or url if the proxy is accepting).

up --wait polls until the server actually accepts connections (default --timeout 30s), and exits non-zero — with the log tail in the error — if the process dies or never binds. With --json the per-site results (including any error) go to stdout as an array. Servers are already detached by default, so up never needs backgrounding tricks; a second up on a running site is a no-op.

Use these instead of reading state.json directly — the file's format is internal and may change.

Files

  • ~/.config/servd/config.toml — settings (port_range_start, proxy_port, domain_suffix, bind_host)

  • ~/.config/servd/sites.toml — the site registry

  • ~/.config/servd/launchers.toml — your launcher rules (optional, see above)

  • <project>/.servd.toml — per-project launch command (optional)

  • ~/.local/state/servd/state.json — live pids/ports (self-healing)

  • ~/.local/state/servd/logs/<slug>.log — per-site server output

Compatibility: legacy enabled site keys and default_enabled settings keys are ignored and may be deleted.

Servers are launched detached in their own process groups, so they keep running after the CLI or TUI exits; servd down signals the whole group. The reverse proxy passes through websocket upgrades, so live-reload / HMR works.

Platform behavior

  • LAN mDNS publishing is available on macOS and Linux. Windows reports it as unsupported in servd doctor; regular loopback and nip.io routing still work.
  • Hosts-file synchronization requires an elevated terminal. The hosts file is /etc/hosts on macOS and Linux, and %SystemRoot%\System32\drivers\etc\hosts on Windows.
  • Launcher tools such as Node, Hugo, jigyll, Jekyll, just, and make are optional host dependencies. servd doctor reports which capabilities are available.
  • User-authored commands run through sh on macOS and Linux and through cmd.exe on Windows. Commands that depend on POSIX shell syntax are not portable to Windows.

Development

go build ./... && go vet ./... && go test ./... -race

Proxy and the Host header

The proxy rewrites the Host header to the backend's own address (e.g. 127.0.0.1:4001), so dev servers with host allowlists (Vite 5+, Next, Rails host authorization) accept proxied requests out of the box. The original host is still available to the backend via X-Forwarded-Host / X-Forwarded-Proto.

If a site builds absolute URLs from Host and needs the nip.io address instead, set preserve_host = true on its [[site]] entry in sites.toml — and add the nip.io hostname to that dev server's own allowed-hosts setting.


MIT licensed. Maintained by r2ware.

Directories

Path Synopsis
cmd
servd command
Command servd runs and manages many local dev servers at once.
Command servd runs and manages many local dev servers at once.
internal
app
Package app holds small helpers shared by the CLI commands and the TUI (which can't import each other).
Package app holds small helpers shared by the CLI commands and the TUI (which can't import each other).
buildinfo
Package buildinfo resolves and formats servd's build metadata.
Package buildinfo resolves and formats servd's build metadata.
commands
Package commands wires up the servd CLI (Cobra) and its subcommands.
Package commands wires up the servd CLI (Cobra) and its subcommands.
config
Package config loads and persists servd's settings and the site registry.
Package config loads and persists servd's settings and the site registry.
flock
Package flock provides advisory file locking for servd's read-modify-write cycles on its persistent files (state.json, sites.toml).
Package flock provides advisory file locking for servd's read-modify-write cycles on its persistent files (state.json, sites.toml).
hostnames
Package hostnames composes and validates the DNS names served by servd.
Package hostnames composes and validates the DNS names served by servd.
hostsfile
Package hostsfile manages the servd-owned block in the system hosts file.
Package hostsfile manages the servd-owned block in the system hosts file.
launcher
Package launcher resolves a project directory into a concrete command for starting its dev server.
Package launcher resolves a project directory into a concrete command for starting its dev server.
mdns
Package mdns publishes servd LAN hostnames for the lifetime of the proxy.
Package mdns publishes servd LAN hostnames for the lifetime of the proxy.
netcheck
Package netcheck has small TCP port probes shared by site registration, doctor, and the proxy control code.
Package netcheck has small TCP port probes shared by site registration, doctor, and the proxy control code.
proxy
Package proxy is an exact-host routing reverse proxy.
Package proxy is an exact-host routing reverse proxy.
registration
Package registration registers individual projects with stable slugs and ports.
Package registration registers individual projects with stable slugs and ports.
state
Package state tracks the live runtime of supervised dev servers.
Package state tracks the live runtime of supervised dev servers.
supervisor
Package supervisor starts, stops and inspects dev-server processes.
Package supervisor starts, stops and inspects dev-server processes.
tui
Package tui implements servd's interactive dashboard (Bubble Tea).
Package tui implements servd's interactive dashboard (Bubble Tea).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL