Skip to main content

Lightweight local development domain router with ASGI middleware support

Project description

🌐 Devhost

CI Release PyPI Python

Secure, flexible local domain routing for developers.

Devhost allows you to map subdomains of a base domain (default: localhost, e.g. myapp.localhost) to local app ports, with optional HTTPS and wildcard routing via Caddy and a Python backend.

Installation

PyPI Package (Recommended)

pip install devhost

After installation, use the devhost CLI directly:

devhost add hello 3000
devhost list
devhost open hello

Git Clone (Development)

For development or customization:

git clone https://github.com/Patoruzuy/devhost.git
cd devhost
python install.py --linux  # or --macos, --windows

Features

  • CLI Tool: Map subdomains to ports (e.g., app.localhostlocalhost:1234)
  • Custom Base Domain: Change from localhost to anything (e.g., app.flask, api.devhost)
  • ASGI Middleware: Embed subdomain routing in FastAPI/Starlette apps
  • Remote Network Devices: Map to any IP on your network (e.g., rpi.localhost192.168.1.100:8080)
  • HTTPS Support: Via Caddy's internal CA (use --https)
  • Cross-Platform: Works on macOS, Linux, and Windows
  • Hot Reload: Changes take effect immediately without restart
  • Factory Functions: Easy integration with existing FastAPI apps

Use Cases

1. CLI Tool (Traditional Usage)

Manage local development domains from the command line:

devhost add api 8000
devhost add frontend 3000
devhost list

2. ASGI Middleware (New in v2.1+)

Embed Devhost routing directly in your FastAPI application:

from fastapi import FastAPI
from devhost_cli.middleware.asgi import DevhostMiddleware

app = FastAPI()
app.add_middleware(DevhostMiddleware)

@app.get("/")
def read_root():
    return {"message": "Hello from FastAPI with Devhost routing!"}

3. Factory Functions

Create a complete Devhost-enabled app with one function:

from devhost_cli.factory import create_devhost_app

# Creates FastAPI app with subdomain routing + proxy endpoints
app = create_devhost_app()

More examples: View all integration patterns on GitHub →

Custom Base Domains

By default, Devhost uses .localhost (e.g., app.localhost, api.localhost), but you can change it to any domain you want.

Change the base domain:

devhost domain flask

Now all your routes use .flask instead:

devhost add app 3000     # Creates app.flask → localhost:3000
devhost add api 8000     # Creates api.flask → localhost:8000
devhost add rpi 192.168.1.100:8080  # Creates rpi.flask → 192.168.1.100:8080

Visit app.flask, api.flask, or rpi.flask in your browser!

Why use custom domains?

  • Project-specific namespaces: Use myproject domain for all related services
  • Better organization: Separate domains for different projects (frontend.prod, api.staging)
  • Avoid conflicts: If another tool uses .localhost, switch to .dev or .local
  • Memorable names: blog.gatsby is easier to remember than blog.localhost

Setup requirements:

After changing the domain, re-run the installer to update DNS/resolver configuration:

devhost domain myproject
python install.py --linux --domain myproject  # or --macos, --windows

All routes automatically use your custom domain - both localhost ports AND remote network devices!

Benefits for Devs

  • No need to remember localhost:PORT combos
  • Clean and memorable dev URLs
  • HTTP by default; HTTPS available with --https
  • Works with any language/framework running locally

Quickstart

Install via pip:

pip install devhost

Add your first route:

devhost add hello 3000
devhost list
devhost open hello

Visit hello.localhost in your browser.

From Source (Development)

git clone https://github.com/Patoruzuy/devhost.git
cd devhost
python install.py --linux
devhost add hello 3000
devhost list
devhost remove hello

Note: the devhost CLI is implemented in Python (cross-platform).

Installation Options

The installer supports various flags to customize the setup process:

Flag Description Platforms
--yes Accept all prompts automatically (non-interactive mode) All
--dry-run Show what would be done without making any changes All
--domain <name> Set custom base domain (default: localhost) All
--start-dns Automatically start DNS service (dnsmasq) macOS, Linux
--install-completions Install shell completions for bash/zsh macOS, Linux
--caddy Install and configure Caddy web server Windows
--clean Remove existing installation before reinstalling Windows

Cross-platform installer (uses the Python CLI):

python install.py --linux

macOS example:

python install.py --macos --yes --start-dns --install-completions

Windows example (PowerShell):

python .\install.py --windows --caddy

To change the base domain (for example, hello.flask), set it once and re-run your installer to update DNS/resolvers:

devhost domain flask
python install.py --domain flask

Run the router locally (development):

cd router
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn app:app --host 127.0.0.1 --port 5555 --reload

Run the router in Docker (quick):

docker compose up --build -d
# then open http://127.0.0.1:5555 with Host header set to <name>.localhost

docker-compose.yml mounts the repo devhost.json into the container so edits take effect immediately.

Notes & safety

  • install.py handles Linux/macOS/Windows and will prompt you about DNS changes. Review DNS/resolver changes before applying them on systems using systemd-resolved.
  • We now generate the project caddy/Caddyfile, the user ~/.config/caddy/Caddyfile, and (if present) /etc/caddy/Caddyfile to keep system Caddy installs in sync.
  • The router loads devhost.json per request so CLI changes take effect immediately without restarting the router.

Quick Commands

  • devhost add <name> <port|host:port> — add a mapping (e.g. devhost add hello 3000).
  • devhost add <name> <ip:port> — add remote IP mapping (e.g. devhost add rpi 192.168.1.100:8080).
  • devhost add <name> --http <port|host:port> — force HTTP when opening the dev URL.
  • devhost add <name> --https <port|host:port> — force HTTPS when opening the dev URL.
  • devhost remove <name> — remove a mapping.
  • devhost list — show active mappings.
  • devhost list --json — show mappings as JSON.
  • devhost url <name> — print the URL and press Ctrl+O to open it in the browser.
  • devhost open <name> — open the URL in the default browser.
  • devhost validate — quick health checks (config JSON, router health, DNS).
  • devhost export caddy — print the generated Caddyfile to stdout.
  • devhost edit — open devhost.json in $EDITOR (fallback: nano/vi).
  • devhost resolve <name> — show DNS resolution and port reachability for a mapping.
  • devhost doctor — deeper diagnostics (dnsmasq/systemd-resolved/Caddy).
  • devhost doctor --windows — Windows-specific diagnostics (Caddy, port 80, hosts).
  • devhost doctor --windows --fix — attempt Windows fixes (hosts sync + free port 80 + start Caddy).
  • devhost info — show all commands and usage.
  • devhost status --json — print router status as JSON (running, pid, health).
  • devhost domain [name] — show or set the base domain (default: localhost).
  • devhost hosts sync — re-apply hosts entries for all mappings on Windows (admin).
  • devhost hosts clear — remove all devhost entries from the Windows hosts file (admin).
  • devhost caddy start|stop|restart|status — manage Caddy on Windows.
  • devhost fix-http — convert all https:// mappings to http:// and regenerate Caddyfile.

Remote IP Support

Devhost supports mapping subdomains to devices on your local network, not just localhost ports. Remote devices use the same base domain as your localhost routes.

Perfect for:

  • Raspberry Pi projects
  • IoT devices
  • Other computers on your network
  • Docker containers with bridge networking

Examples

With default .localhost domain:

Raspberry Pi running a web server:

devhost add rpi 192.168.1.100:8080
# Access at http://rpi.localhost

Network attached storage (NAS):

devhost add nas 192.168.1.50:5000
devhost open nas  # Opens http://nas.localhost

With custom .devhost domain:

# First, change the base domain
devhost domain devhost

# Then add remote devices
devhost add rpi 192.168.1.100:8080    # Access at rpi.devhost
devhost add nas 192.168.1.50:5000     # Access at nas.devhost
devhost add router 192.168.1.1:80     # Access at router.devhost

Mix localhost and remote IPs (all use same domain):

devhost domain myproject
devhost add frontend 3000                    # frontend.myproject → localhost:3000
devhost add api 8000                         # api.myproject → localhost:8000  
devhost add rpi 192.168.1.100:8080          # rpi.myproject → 192.168.1.100:8080
devhost add staging 10.0.0.25:3000          # staging.myproject → 10.0.0.25:3000

Configuration Format

Remote IPs can be added in several formats:

  • 192.168.1.100:8080 - Full IP with port
  • 10.0.0.25:3000 - Any valid IPv4 address
  • Combined with other targets in devhost.json:
{
  "hello": 3000,
  "api": 8000,
  "rpi": "192.168.1.100:8080",
  "nas": "192.168.1.50:5000"
}

Notes

  • The remote device must be reachable from your machine
  • Ensure firewalls allow traffic to the target port
  • IP addresses are validated when adding routes
  • Use devhost resolve <name> to test connectivity

Configuration

The project uses a devhost.json file (project root) with a simple mapping of names to ports. Example:

{
	"hello": 3000,
	"api": 8000
}

This file is created/updated by the CLI and is meant to be local (it’s gitignored). The router reads DEVHOST_CONFIG if set; otherwise it looks for the project root devhost.json (even when run from router/). The base domain comes from DEVHOST_DOMAIN or .devhost/domain (default: localhost).

Router endpoints

  • GET /health — liveness + route count + uptime.
  • GET /metrics — basic request metrics (totals, per-status, per-subdomain).
  • GET /routes — current routes with parsed targets.
  • GET /mappings — current routes with basic TCP health checks.

Logging

  • DEVHOST_LOG_LEVEL controls router log verbosity (default: INFO).
  • DEVHOST_LOG_FILE writes logs to a file in addition to stdout.
  • DEVHOST_LOG_REQUESTS=1 enables per-request logging.

Quick test (curl)

Run the router (locally or via Docker) and test with curl by setting the Host header:

curl -H "Host: hello.localhost" http://127.0.0.1:5555/

Regenerating Caddyfile

The devhost CLI writes both the project caddy/Caddyfile (generated, gitignored) and, when present, the user ~/.config/caddy/Caddyfile. Inspect generated files before reloading system Caddy and, when appropriate, reload the service:

# inspect
less caddy/Caddyfile
# if using system Caddy (Linux)
sudo systemctl reload caddy

Troubleshooting

General Issues

  • Check mappings: devhost list - Verify your routes are configured correctly.
  • Router health: curl http://127.0.0.1:5555/health should return { "status": "ok" }.
  • Check router logs: Look for request IDs in logs to trace specific requests (X-Request-ID header).
  • Validate setup: devhost validate - Quick health checks for config, router, and DNS.
  • Deep diagnostics: devhost doctor - Comprehensive system diagnostics.

DNS & Domain Issues

  • Linux DNS issues: Check systemd-resolved and /etc/resolv.conf for unintended changes.
  • macOS DNS issues: Verify /etc/resolver/<domain> file exists and contains nameserver 127.0.0.1.
  • Windows DNS issues: Wildcard DNS requires a local resolver like Acrylic DNS. Alternatively, use devhost hosts sync to add individual entries to hosts file.
  • Domain resolution: devhost resolve <name> - Show DNS resolution and port reachability.

Windows-Specific Issues

Hosts File Management

When to use hosts file (Windows only):

  • You don't have a wildcard DNS resolver installed (like Acrylic DNS)
  • You want individual domain entries instead of wildcard DNS
  • Testing specific routes without full DNS setup

Admin elevation required:

  • devhost hosts sync - Adds/updates all routes in C:\Windows\System32\drivers\etc\hosts (requires admin)
  • devhost hosts clear - Removes all devhost entries from hosts file (requires admin)

Admin NOT required:

  • devhost add/remove/list - Regular route management
  • devhost start/stop/status - Router process management
  • devhost validate - Health checks

The hosts file commands modify system files and therefore require administrator privileges. The CLI will automatically attempt to relaunch with elevation if needed.

Other Windows Issues

  • Port 80 conflicts: Run devhost doctor --windows to check what's using port 80.
  • Port 80 auto-fix: devhost doctor --windows --fix - Attempts to free port 80 and start Caddy.
  • Caddy not running: devhost caddy status - Check Caddy status.
  • Start Caddy: devhost caddy start - Start Caddy web server.
  • Windows diagnostics: devhost doctor --windows - Windows-specific checks.

HTTPS & Certificate Issues

  • Browser forcing HTTPS: Clear HSTS settings for the domain or change base domain (devhost domain devhost2).
  • Caddy not running: Ensure Caddy is running if you depend on system TLS (systemctl status caddy on Linux).
  • Convert to HTTP: devhost fix-http - Convert all HTTPS mappings to HTTP.

Remote IP Issues

  • Remote device unreachable: Verify the remote IP/port is accessible from your machine (curl http://192.168.1.100:8080).
  • Network firewall: Ensure firewall rules allow traffic to the remote device.
  • Wrong IP address: Check the device's current IP (devhost list to see configured IPs).

Platform notes

  • install.py targets Linux/macOS/Windows; it reads DEVHOST_DOMAIN or .devhost/domain to configure DNS for the base domain.
  • On Windows, run the installer from an elevated PowerShell if you want hosts entries updated automatically, or use a local DNS resolver (Acrylic) for wildcard domains.

Release notes

See CHANGELOG.md for the v1.0.0 release notes.

macOS installer

Run the Python installer to generate the LaunchAgent plist (from router/devhost-router.plist.tmpl), create /etc/resolver/<domain>, and optionally start dnsmasq via Homebrew:

# dry-run (print actions)
python install.py --macos --dry-run

# run interactively (will prompt for username and uvicorn path)
python install.py --macos

Non-interactive example (accept all prompts and start dnsmasq if available):

python install.py --macos --yes --start-dns

To use a custom base domain on macOS:

devhost domain flask
python install.py --macos --domain flask

Windows installer

Run the Python installer from PowerShell to prepare the venv, router deps, and initial config:

python .\install.py --windows --caddy
python .\devhost add hello 8000

To clean and reinstall:

python .\install.py --windows --clean

If you want a shortcut in PowerShell without typing python, use:

.\devhost.ps1 add hello 8000
.\devhost.ps1 start

Note: the router requires a Host header. Don’t browse http://127.0.0.1:5555 directly — use devhost open <name> or:

curl -H "Host: hello.localhost" http://127.0.0.1:5555/

Tip (Windows): if your app only listens on IPv4, Devhost uses `127.0.0.1` for numeric ports to avoid IPv6 `::1` connection errors.

Tip: On Windows, devhost.ps1 start will try to start Caddy (if installed) before starting the router.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

devhost-2.1.6.tar.gz (32.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

devhost-2.1.6-py3-none-any.whl (32.7 kB view details)

Uploaded Python 3

File details

Details for the file devhost-2.1.6.tar.gz.

File metadata

  • Download URL: devhost-2.1.6.tar.gz
  • Upload date:
  • Size: 32.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for devhost-2.1.6.tar.gz
Algorithm Hash digest
SHA256 ffaaa11fe39e0f14638f9e5a663d05ca5777a402a52f0b144cbbbcdd5f9ae5e9
MD5 37453555dd2f149db612177599413f68
BLAKE2b-256 aefbf14f507f0ff7fd8ce22166af7725d6a03e6833199dd05a460ce126f44398

See more details on using hashes here.

Provenance

The following attestation bundles were made for devhost-2.1.6.tar.gz:

Publisher: publish.yml on Patoruzuy/Devhost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file devhost-2.1.6-py3-none-any.whl.

File metadata

  • Download URL: devhost-2.1.6-py3-none-any.whl
  • Upload date:
  • Size: 32.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for devhost-2.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 9bcb918a817fb4af980d5cbb8e57d6007277a1f8623d4c368297fd6c52536781
MD5 9e3af8bc072dcbb6effcfe446623158f
BLAKE2b-256 d7fa618bc6c7804bbeac490bc51d9d3f5c5e00dcc44eca4edb1ea6802125bd35

See more details on using hashes here.

Provenance

The following attestation bundles were made for devhost-2.1.6-py3-none-any.whl:

Publisher: publish.yml on Patoruzuy/Devhost

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page