Automatic .localhost DNS names for every HTTP service on your machine.
Start any local server, and it's instantly reachable at a human-friendly URL. No config files, no /etc/hosts edits, no DNS servers. Just run your service and open http://myapp.localhost.
Inspired by dns-to-port by Florian Margaine. See COMPARISON.md for a detailed comparison.
Website: nameport.eu
nameport is a daemon + CLI that watches your machine for HTTP services, names them, and reverse-proxies them through port 80 with .localhost domains.
$ cd ~/projects/myapp && npm start # listening on :3000
# → http://myapp.localhost (auto-discovered, auto-named)
$ cd ~/work/api && flask run # listening on :5000
# → http://api.localhost (named from directory)
$ cd ~/projects/myapp && npm run dev # listening on :3001
# → http://myapp-1.localhost (collision handled)It also handles services you don't run yourself -- macOS apps, Docker containers, and remote machines all get names:
$ nameport list
NAME TARGET PID COMMAND
ollama.localhost 127.0.0.1:11434 1033 /Applications/Ollama.app/...
dropbox.localhost 127.0.0.1:17600 48354 /Applications/Dropbox.app/...
api.localhost 127.0.0.1:3000 62138 node server.js
neverssl.localhost 34.223.124.45:80 0 manual # remote proxy# Build
make
# Start the daemon (requires root for port 80)
sudo ./nameport-daemon
# Start any local HTTP server
cd ~/projects/myapp && python3 -m http.server 3000
# Open in browser -- it just works
open http://myapp.localhost
# See all discovered services
./nameport list
# View the web dashboard
open http://localhost/- Automatic service discovery -- scans for listening TCP ports every 2 seconds
- HTTP verification -- only proxies services that actually speak HTTP
- Smart naming -- 17 built-in rules extract names from project directories, macOS app bundles, script paths, and working directories
- Collision handling --
myapp.localhost,myapp-1.localhost,myapp-2.localhost - Remote target proxying -- proxy to Docker containers, VMs, or machines on your LAN
- Docker container detection -- auto-discovers containers with exposed ports; use the
nameport.nameDocker label to set a custom name - No DNS server needed --
.localhostis an IANA-reserved TLD that browsers resolve to127.0.0.1
- Web dashboard at
http://localhost/with real-time health status, rename, keep, and blacklist controls - CLI for all operations:
list,rename,keep,add,remove,blacklist,rules,notify - Persistent names -- custom renames survive daemon restarts
- Keep mode -- pin services in the dashboard even when they're offline
- Persistent blacklist -- block services by PID, executable path, or regex pattern
- Customizable naming rules -- data-driven JSON rules with user overrides and priority ordering
- Desktop notifications for service discovered, offline, and renamed events (macOS and Linux)
- Per-event filtering -- enable/disable individual notification types
- Persistent config at
~/.config/nameport/notify.json - Notification app name:
nameport
- Two-tier TLS certificate authority -- "nameport Root CA" with "nameport Intermediate CA" (ECDSA P-256), ready for local HTTPS
- Domain policy enforcement -- CA only issues certs for safe TLDs (
.localhost,.test,.internal), blocks all IANA public TLDs - Trust store integration -- installs as
nameport.crt(Debian) ornameport.pem(Fedora) - systemd/launchd integration -- auto-start support for production-like setups
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Browser │────▶│ nameport │────▶│ Your Service │
│ (myapp.local) │ │ (reverse proxy │ │ (port 3000) │
│ │◀────│ on port 80) │◀────│ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
│
▼
┌──────────────────┐
│ Port Scanner │
│ (Linux: /proc) │
│ (macOS: lsof) │
└──────────────────┘
Requires Go 1.21+.
# Build for current platform
make
# Build for Linux (from macOS or Linux)
make build-linux
# Clean build artifacts
make clean# Build daemon
go build -o nameport-daemon ./cmd/daemon
# Build CLI
go build -o nameport ./cmd/cliThe daemon must run as root to bind port 80:
sudo ./nameport-daemonOptional: specify custom config path:
sudo ./nameport-daemon /path/to/services.jsonList all discovered services:
./nameport listRename a service:
./nameport rename myapp.localhost api.localhostToggle keep status (persist service even when not running):
./nameport keep myapp.localhost # Enable keep
./nameport keep myapp.localhost false # Disable keepAdd a manual service entry (for services not currently running):
./nameport add staging.localhost 8080Add a service targeting a remote host (Docker container, another machine on the LAN, etc.):
./nameport add myapp.localhost 192.168.0.1:3000
./nameport add docker-app.localhost 172.17.0.2:8080Blacklist services:
./nameport blacklist pid 12345 # By PID
./nameport blacklist path /usr/sbin/cupsd # By executable path
./nameport blacklist pattern "^nameport" # By regex pattern
./nameport blacklist list # List all user blacklist entries
./nameport blacklist remove <id> # Remove a blacklist entryManage naming rules:
./nameport rules list # Show active rules with priority
./nameport rules export # Export rules as JSON
./nameport rules import my-rules.json # Import custom rulesManage notifications:
./nameport notify status # Show notification config
./nameport notify enable # Enable notifications
./nameport notify disable # Disable notifications
./nameport notify events service_offline off # Disable specific event type
./nameport notify events service_discovered on # Re-enable specific event typeAccess the dashboard at http://localhost/ (or any unrecognized hostname).
Features:
- View all services with real-time health status
- Click service names to open them
- Rename services inline
- Toggle "Keep" to persist services when stopped
- Blacklist unwanted services
- Auto-refreshing status indicators
For testing on a clean Linux environment, use Orbstack or any VM provider.
# Create a new Ubuntu VM in Orbstack
orb create ubuntu nameport-test
# SSH into the VM
orb ssh nameport-test# Download and install Go
wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.6.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Verify
go version# Clone the project to the VM
cd ~
git clone https://github.com/OriPekelman/nameport.git
cd nameport
# Build
go build -o nameport-daemon ./cmd/daemon
go build -o nameport ./cmd/cliTerminal 1 - Start the daemon:
sudo ./nameport-daemonTerminal 2 - Start a test HTTP server:
mkdir -p /tmp/myapp
cd /tmp/myapp
python3 -m http.server 8000Terminal 3 - Check discovery:
./nameport list
# Should show: myapp.localhost -> 127.0.0.1:8000Terminal 4 - Test the proxy:
curl http://myapp.localhost
# Should show directory listing from Python serverStart another server from the same directory:
cd /tmp/myapp
python3 -m http.server 8001Check the list:
./nameport list
# Should show:
# myapp.localhost -> port 8000
# myapp-1.localhost -> port 8001./nameport rename myapp.localhost coolapp.localhost
./nameport list
curl http://coolapp.localhostgo build -o nameport-daemon ./cmd/daemon
go build -o nameport ./cmd/clisudo ./nameport-daemonTerminal 2:
mkdir -p /tmp/myapp
cd /tmp/myapp
python3 -m http.server 8000Terminal 3:
./nameport list
# Should show: myapp.localhost -> 127.0.0.1:8000curl http://myapp.localhost
# Should show directory listing from Python serverIssue: lsof permission denied
- Solution: Go to System Settings > Privacy & Security > Full Disk Access and add your terminal application
Issue: Port 80 already in use
- Solution: macOS may have a service on port 80. Try:
sudo lsof -i :80to find it
Linux:
- Parse
/proc/net/tcpand/proc/net/tcp6for listening sockets - Extract socket inode numbers
- Scan
/proc/<pid>/fd/to map inodes to PIDs - Read
/proc/<pid>/exeand/proc/<pid>/cmdlinefor process info
macOS:
- Run
lsof -nP -iTCP -sTCP:LISTENto get listening ports - Parse output to extract PID and port for each socket
- Use
lsof -p <pid>to get executable path - Use
psto get command line arguments
The tool uses several heuristics to generate the best possible name:
1. macOS App Bundles
/Applications/Ollama.app/Contents/MacOS/Ollama
↓
"Ollama"
↓
ollama.localhost
2. Script Paths (Node, Python, etc.)
node /home/user/projects/webapp/index.js
↓
"webapp"
↓
webapp.localhost
3. Parent Directory (fallback)
/home/user/projects/myapp/server.js
↓
"myapp"
↓
myapp.localhost
4. Working Directory (for directory-serving tools)
cd ~/projects/myapp && serve
↓
"myapp" (from CWD)
↓
myapp.localhost
Tools that use CWD for naming:
serve,http-server,live-serverpython -m http.servernpxcommands
Collision Handling: myapp.localhost → myapp-1.localhost → myapp-2.localhost
The dashboard shows real-time health indicators:
| Status | Color | Meaning |
|---|---|---|
| Green | #4caf50 | 2xx Success (200, 201, etc.) |
| Orange | #ff9800 | 4xx Client Error (403, 404, etc.) - Normal for root path |
| Red | #f44336 | 5xx Server Error or Offline |
| Gray | #9e9e9e | Service inactive (PID not found) |
The following services are automatically ignored:
- System binaries (
/usr/sbin/*,/usr/bin/*,/bin/*,/sbin/*) - System daemons (
/usr/libexec/*,/usr/lib/*) - The daemon itself (
nameport-daemon)
Exception: Scripts running through interpreters (Python, Node, etc.) are NOT blacklisted if the script is in a user directory (/home/*, /Users/*, /tmp/*).
Sends a simple HTTP request and verifies the response starts with HTTP/.
Uses SHA256 hash of realpath(exe) + args for stable identification across restarts.
Default config location: ~/.config/nameport/services.json
Example:
[
{
"id": "a1b2c3d4...",
"name": "myapp.localhost",
"port": 3000,
"pid": 12345,
"exe_path": "/usr/bin/node",
"args": ["/home/user/projects/myapp/server.js"],
"user_defined": false,
"is_active": true,
"keep": false,
"last_seen": "2026-02-17T20:00:00Z"
},
{
"id": "manual-docker.localhost-172.17.0.2-8080",
"name": "docker.localhost",
"port": 8080,
"target_host": "172.17.0.2",
"pid": 0,
"exe_path": "manual",
"args": [],
"user_defined": true,
"is_active": false,
"keep": true,
"last_seen": "2026-02-17T20:00:00Z"
}
]Fields:
id: Unique identifier (SHA256 hash of exe path + args)name: The .localhost domain nameport: Service port numbertarget_host: Target IP or hostname (default:127.0.0.1, omitted when default)pid: Process ID (0 if manual entry)exe_path: Path to executableargs: Command line argumentsuser_defined: Whether name was manually setis_active: Whether service is currently runningkeep: Whether to keep in dashboard when stoppedlast_seen: Last time service was detected
Service name: com.nameport.daemon
Service name: nameport.service
Daemon logs are written to /var/log/nameport.log.
If you see "permission denied" errors:
# The daemon runs as root, so storage may be owned by root
sudo chown $USER:$USER ~/.config/nameport/services.json-
Check if the service is actually listening:
# Linux ss -tlnp | grep LISTEN # macOS lsof -nP -iTCP -sTCP:LISTEN
-
Verify it's HTTP (not just TCP):
curl -I http://127.0.0.1:<port>
-
Check daemon logs:
sudo ./nameport-daemon 2>&1 | tee daemon.log
Clear the storage and restart:
sudo rm ~/.config/nameport/services.json
sudo ./nameport-daemonFind and stop the process:
# Linux
sudo lsof -i :80
sudo kill <pid>
# macOS
sudo lsof -i :80
sudo kill <pid>Go to System Settings > Privacy & Security > Full Disk Access and add your terminal application.
Services are marked inactive when their PID disappears. They'll be hidden unless "Keep" is enabled. Use the dashboard or CLI to manage keep status:
./nameport keep myapp.localhost false- Port 80: Needs root/sudo to bind privileged port
- HTTP only: HTTPS services not yet supported
- Auto-discovery is local only: Automatic scanning only finds services on 127.0.0.1 (use
addwith a host for remote targets) - macOS: Uses
lsofwhich may require approving terminal in System Settings > Privacy & Security
The daemon exposes a REST API on port 80:
GET /api/services- List all services with health statusPOST /api/rename- Rename a service ({"oldName": "...", "newName": "..."})POST /api/keep- Update keep status ({"name": "...", "keep": true/false})POST /api/blacklist- Add to blacklist ({"type": "pid|path|pattern", "value": "..."})
See ROADMAP.md for the full development roadmap with detailed specs, dependency graphs, and parallelism guide.
- macOS support using
lsof - Web dashboard for managing services
- Service lifecycle management (keep/persist)
- Health status monitoring
- Manual service entries
- Remote target proxying (Docker, LAN machines)
- Persistent blacklist configuration (1.1)
- Data-driven naming heuristics with JSON rules (1.2)
- Two-tier TLS certificate authority (2.1)
- TLS domain policy with IANA TLD blocklist (2.4)
- Docker container auto-detection (3.1)
- Connection and I/O metrics (5.1)
- systemd/launchd auto-start support (6.1)
- Desktop notifications (6.2)
| Milestone | Highlights |
|---|---|
| 1. Core Hardening | |
| 2. Local Dev TLS | |
| 3. Containers | |
| 4. Peer-to-Peer | mDNS discovery, access teammates' services as subdomains |
| 5. Observability | |
| 6. System Integration | |
| 7. Advanced Routing | Custom TLD support with local DNS resolver |
The docs/ directory is served via GitHub Pages as the project website at nameport.eu.
MIT license
