Skip to content
FLAVIO COPES
flaviocopes.com
Local Hoster diagram routing a project through Caddy to a stable localhost address

CLI · version 1.0

Local Hoster

A zero-runtime-dependency Node.js CLI that gives every local project one stable URL such as https://dashboard.localhost. Even when the framework’s usual port is already occupied, you keep opening the same memorable address instead of chasing 3001, 3002, or another port.

Node.jsCLICaddy.localhostNode test runner

Join the Flavio Copes newsletter

Join the newsletter to access my complete download library, including books, courses, and software. I’ll also email you about new software, building products with AI, and my courses. You can unsubscribe anytime.

Your email is stored on a secure server in the EU. Every email has an unsubscribe link. Unsubscribing stops future emails; you can keep using the public download library.

Why I built this

I was tired of remembering whether a project was running on 3000, 4321, 5173, or something else. If the usual port was already occupied, the framework would jump to another number and the browser history became even less useful. I wanted the project URL to stay the same regardless.

Local Hoster makes the project name the address. Add one package.json field, put localhoster before the development command, and Caddy gives the project a stable HTTP and HTTPS URL. The implementation stays intentionally small, readable, tested, and free of runtime npm dependencies.

From project name to stable local origin

One command connects the whole local route.

  1. Read and validate the project hostname.
  2. Choose its stable development port.
  3. Register HTTP, HTTPS, and local TLS.
  4. Run the server and clean up on exit.

Features

The same URL every time

When a framework’s usual port is busy, keep opening dashboard.localhost instead of hunting for whichever numbered localhost address it chose.

Local HTTPS

Use Caddy’s internal certificate authority for secure cookies, service workers, WebAuthn, and other HTTPS-only browser behavior.

One-command workflow

Run localhoster astro dev—or another compatible command—and keep the normal development output in the same terminal.

Deterministic ports

Map each validated hostname to the same preferred port across restarts for predictable local origins.

Temporary Caddy config

Register tagged HTTP, HTTPS, and TLS objects at startup, then remove all of them when the child process exits.

Zero runtime dependencies

Use Node.js built-ins for files, processes, HTTP requests, validation, and the automated test suite.

Use cases

Daily web development

Give every Astro, Vite, Next.js, or compatible project a short address that remains memorable.

HTTPS feature testing

Exercise secure cookies, service workers, browser credentials, and callback flows on a trusted local origin.

Multi-project workspaces

Run a frontend, API, documentation site, and admin interface behind distinct local hostnames.

Team conventions

Standardize predictable development URLs across repositories and onboarding documentation.

Proxy-learning reference

Study a compact implementation of Caddy’s JSON admin API, internal TLS, and process cleanup.

Local platform foundation

Extend the command into a project registry, dashboard, request inspector, or container-aware development router.

Tech stack

Runtime

Node.js

Reads project metadata, validates hostnames, computes ports, talks to Caddy, and manages the child process.

Reverse proxy

Caddy

Accepts local HTTP and HTTPS traffic and forwards each hostname to its assigned development port.

Dynamic configuration

Caddy admin API

Adds and removes tagged routes and TLS policies without rewriting a shared Caddyfile.

Local addressing

.localhost

Uses the browser-reserved loopback domain so projects need no hosts-file entries or custom DNS server.

Local certificates

Internal CA

Issues development certificates locally after the owner deliberately trusts the Caddy installation.

Verification

Node test runner

Covers hostname rules, stable ports, command arguments, generated Caddy configuration, and cleanup.

CLI

The ZIP contains the complete command source and tests. Link it locally, add a hostname to any compatible project, and place localhoster before the normal development command.

localhoster astro dev

Run an Astro project behind its configured .localhost hostname.

localhoster vite

Run a Vite project on its stable Local Hoster port.

localhoster --help

Show the compact command guide and package configuration example.

npm test

Verify hostname, port, Caddy configuration, and cleanup behavior.

Screenshots and demos

Local Hoster terminal showing stable HTTP and HTTPS URLs for an Astro project
Local Hoster terminal showing stable HTTP and HTTPS URLs for an Astro project. Open the full-size image.

Usage manual

Run it and make it yours.

The setup and usage guide from the ZIP. Read it before downloading so you know what the software needs.

Local Hoster is a small Node.js command-line tool that gives local development projects stable URLs such as https://dashboard.localhost. It registers temporary HTTP and HTTPS reverse-proxy routes through Caddy, starts the chosen development command on a deterministic port, and removes its routes when the command exits.

Current release: 1.0 (1.0.0 in package metadata). See CHANGELOG.md for release notes.

Features

  • Memorable *.localhost URLs without editing /etc/hosts
  • Local HTTPS through Caddy's internal certificate authority
  • Stable project-to-port mapping across restarts
  • Runtime route registration through Caddy's local admin API
  • Automatic route and TLS-policy cleanup
  • Hostname validation and clear setup errors
  • Zero runtime npm dependencies
  • Automated tests for hostname, port, route, and cleanup behavior

Requirements

  • macOS or another Unix-like system supported by Caddy
  • Node.js 18 or newer
  • Caddy installed and running with its admin API on localhost:2019

Quick start

From code/:

npm link
brew install caddy
touch /opt/homebrew/etc/Caddyfile
brew services start caddy
caddy trust

In the project you want to run, add a hostname and wrap its development command:

{
  "localhost": "myapp",
  "scripts": {
    "dev": "localhoster astro dev"
  }
}

Then run npm run dev and open https://myapp.localhost.

Verify the source

npm run check
npm test

Project structure

├── code/
│   ├── index.mjs
│   ├── package.json
│   └── test/localhoster.test.mjs
├── AGENTS.md
├── ARCHITECTURE.md
├── BUILDING.md
├── CHANGELOG.md
├── CONFIGURATION.md
├── CUSTOMIZATION.md
├── DECISIONS.md
├── DEPLOYMENT.md
└── SECURITY.md

Start with ARCHITECTURE.md to understand the Caddy configuration flow and SECURITY.md before changing the admin endpoint or process behavior.

License

MIT. Keep the included license notice with substantial copies of the source.

Architecture

See how the software is put together.

Review the system flow, boundaries, integrations, and replaceable parts before you download it.

Local Hoster is a zero-runtime-dependency Node.js CLI that coordinates a project command and a local Caddy reverse proxy. The executable is localhoster; the public product name is Local Hoster.

System flow

flowchart TD
  project["package.json<br/>localhost: myapp"] --> cli["Local Hoster"]
  command["Development command"] --> cli

  cli --> validate["Validate hostname"] --> port["Choose stable port"]
  port --> child["Start child process<br/>localhost:PORT"]
  port --> caddy["Configure Caddy"]
  caddy --> http["HTTP route"]
  caddy --> https["HTTPS route"]
  caddy --> tls["Local TLS certificate"]

  browser["Browser"] --> url["https://myapp.localhost"]
  url --> caddy --> child

  stopped["Ctrl+C or child exit"] --> cleanup["Remove HTTP, HTTPS,<br/>and TLS objects"] --> status["Exit with child status"]
  child -. lifecycle .-> stopped

  classDef entry fill:#332d23,stroke:#e8a830,stroke-width:2px,color:#f0e4cc
  classDef core fill:#c85520,stroke:#e8a830,stroke-width:2px,color:#fff8ea
  classDef service fill:#2d2a25,stroke:#a87628,color:#f0e4cc
  classDef output fill:#211f1c,stroke:#5b5143,color:#d2c4aa

  class project,command,browser,stopped entry
  class cli core
  class validate,port,caddy,cleanup service
  class child,http,https,tls,url,status output

Components

Command entry point

code/index.mjs parses help and version flags, reads the current project's package.json, validates its localhost field or name, computes a stable port, and starts the requested development command.

Hostname and port rules

Names are normalized to lowercase and suffixed with .localhost. Each label must contain letters, numbers, or internal hyphens. A deterministic string hash maps the hostname into ports 10000–59999. This makes the same project choose the same port after restarts; it does not reserve the port globally, so ordinary port-conflict handling still applies.

Caddy adapter

The CLI reads Caddy's JSON configuration from the local admin API, ensures HTTP and HTTPS servers exist, adds tagged reverse-proxy routes, and installs a tagged internal-TLS automation policy. It then loads the updated configuration in one request.

Every object receives a stable @id. Cleanup deletes all three objects by ID, avoiding stale routes and certificate policies after the development command exits.

Child process lifecycle

The requested command is spawned directly, without a shell, with --port <stable-port> appended. Standard input and output are inherited. When the child exits, Local Hoster removes its Caddy configuration and returns the child's exit status. On SIGINT or SIGTERM, it cleans up before forwarding the signal to the child.

Tests

code/test/localhoster.test.mjs uses Node's built-in test runner. It covers hostname validation, deterministic ports, command arguments, generated Caddy configuration, and cleanup requests without requiring a live Caddy process.

Trust boundaries

  • The project directory controls the hostname and command.
  • Caddy's admin API is assumed to be local and owner-controlled.
  • The spawned command is supplied by the user and is never passed through a shell.
  • Local HTTPS uses a local certificate authority; it is not public TLS.

Replaceable pieces

The hostname validator, port strategy, Caddy adapter, and child-process runner are explicit functions. You can replace Caddy with another proxy, add a port-availability check, support commands with different port flags, or port the workflow to another language while preserving the product behavior.

What’s included

  • Local Hoster version 1.0 with complete reviewed Node.js source and the localhoster executable
  • Stable hostname and deterministic-port behavior
  • HTTP, HTTPS, internal-TLS registration, and symmetric cleanup
  • Direct process spawning with child exit-status preservation
  • Automated tests using only Node.js built-ins
  • README, changelog, and build, agent, architecture, decisions, customization, configuration, security, and distribution guides
  • Package manifest and audited ZIP included in the free ZIP download
  • No credentials, personal paths, databases, telemetry, dependencies, or build output

Documentation

The ZIP includes project context for you and your coding agents.

README.md

The starting point: what the software does, prerequisites, local setup, commands, and the shortest path to a working copy.

CHANGELOG.md

The release history and the public changes included in each version.

BUILDING.md

The build story: how the software was made, the difficult parts, how it was verified, and what could come next.

AGENTS.md

Project context and operating rules for Codex, Claude Code, Cursor, and other AI coding agents.

ARCHITECTURE.md

How the major parts fit together, where data flows, and where to make structural changes.

DECISIONS.md

The main technical and product choices, including tradeoffs worth preserving or revisiting.

CUSTOMIZATION.md

A practical map for changing the brand, interface, features, data model, and integrations.

DEPLOYMENT.md

A production checklist covering resources, environment setup, builds, and deployment verification.

CONFIGURATION.md

Every setting and environment variable, where it is used, and how to configure local and production environments.

SECURITY.md

Credential handling, trust boundaries, sensitive data, and checks to run before publishing your version.

WHY.md

Additional project documentation included with the source package.

Why download this

  • Stop rebuilding the same local-proxy glue for every development machine
  • Start with a working Caddy configuration lifecycle instead of a fragile shell script
  • Give an AI coding agent explicit architecture, invariants, tests, and customization guidance
  • Keep the runtime understandable and free of dependency churn
  • Own and adapt the complete source for personal, client, or commercial projects
  • Use the complete source with no subscription or hosted service attached

Customize it

Use the working source as a foundation. Keep it small, change it for your own workflow, or turn it into a different product.

  1. Turn it into the local-dev router your whole team standardizes on: aliases, auto-open links, and a live map of every project URL.
  2. Ship an internal npm or Homebrew package so new hires get pretty local domains on day one.
  3. Add request logging and a small web dashboard that shows which apps are up without digging through terminals.
  4. Support custom port flags and env vars so frameworks that are picky still fit the same workflow.
  5. Replace Caddy behind an adapter and port the idea to another OS or reverse-proxy stack.
  6. Grow it into a companion for Port Pilot: one tool finds ports, the other gives them human names.

MIT license

Every source ZIP includes an MIT LICENSE file. You can use, copy, change, publish, distribute, sublicense, or sell the code, including as part of a commercial product.

Keep the copyright and license notice with copies or substantial portions of the code. Third-party dependencies and assets keep their own licenses.

Keep learning

Bootcamp

Use a predictable local setup while you learn to build and ship complete web applications.

Explore Bootcamp →

Join the newsletter to access my complete download library, including books, courses, and software. I’ll also email you about new software, building products with AI, and my courses. You can unsubscribe anytime.

Your email is stored on a secure server in the EU. Every email has an unsubscribe link. Unsubscribing stops future emails; you can keep using the public download library.