Port Management & Reverse Proxy
Pitchfork provides smart port management and an optional reverse proxy that gives your daemons stable, human-friendly URLs.
Port Assignment
Expected Ports
Configure the ports your daemon expects to use:
[daemons.api]
run = "node server.js"
expected_port = [3000]Pitchfork will:
- Check if port 3000 is available before starting
- Inject
PORT=3000into the daemon's environment - Fail with a clear error if the port is already in use
Auto Port Bumping
When a port is occupied, pitchfork can automatically find the next available port:
[daemons.api]
run = "node server.js"
expected_port = [3000]
auto_bump_port = trueWith auto_bump_port = true, pitchfork tries 3000, 3001, 3002, ... until it finds a free port. The daemon receives the actual port via $PORT.
Control how many attempts are made:
[daemons.api]
run = "node server.js"
expected_port = [3000]
auto_bump_port = true
port_bump_attempts = 10 # try up to 10 ports (default: 3)Or via environment variable:
PITCHFORK_PORT_BUMP_ATTEMPTS=10 pitchfork start apiActive Port Tracking
After a daemon starts, pitchfork detects which port the process is actually listening on. This detected port is the source of truth for the reverse proxy — it's what gets routed when you access the proxy URL.
Reverse Proxy
The reverse proxy routes requests from stable URLs to the daemon's actual port.
Why Use the Proxy?
Without the proxy, you need to know the actual port your daemon is running on — which can change if ports are auto-bumped. With the proxy:
https://myapp.localhost → http://localhost:3001The URL stays the same even if the port changes. This is especially useful for:
- Sharing URLs with teammates
- AI agents that need stable endpoints
- Browser bookmarks
- Webhook configurations
Quick start
- Enable the proxy in
pitchfork.toml:
[settings.proxy]
enable = true- Start the supervisor:
sudo pitchfork supervisor start --force # port 80 or 443 requires sudo- Add a slug in the global config:
pitchfork proxy add api
# or with explicit dir and daemon name:
pitchfork proxy add api --dir /path/to/project --daemon serverThis registers the slug in ~/.config/pitchfork/config.toml:
[slugs]
api = { dir = "/path/to/project", daemon = "server" }- Start the daemon:
pitchfork start api- Open the proxy URL:
open https://api.localhostIf this is your first time using the auto-generated HTTPS certificate, trust it once:
pitchfork proxy trust # On Linux, run the trust step with `sudo`Slugs
Slugs are defined in the global config (~/.config/pitchfork/config.toml) under [slugs]. Each slug maps to a project directory and (optionally) a specific daemon name:
# ~/.config/pitchfork/config.toml
[slugs]
api = { dir = "/home/user/my-api", daemon = "server" }
frontend = { dir = "/home/user/my-app", daemon = "dev" }
# If daemon name matches slug, it can be omitted:
docs = { dir = "/home/user/docs-site" } # defaults daemon = "docs"Why global config only?
- Single source of truth — no sync step needed, no risk of stale state
- Cross-directory resolution — slugs work from any directory
- Explicit and auditable — one file shows all your proxied services
- Auto-start ready — the proxy knows the dir and can load project config automatically
URL format
Proxy URLs use this shape:
https://<slug>.<tld>Examples:
https://myapp.localhost— standard HTTPS port 443, by defaulthttps://api.localhost:7777— custom port
Managing slugs
# Add a slug for current directory
pitchfork proxy add myapp
# Add a slug with explicit dir and daemon
pitchfork proxy add api --dir /home/user/api --daemon server
# Remove a slug
pitchfork proxy remove api
# or: pitchfork proxy rm api
# Show all slugs and their status
pitchfork proxy statusStandard Ports (80/443)
To use standard HTTP/HTTPS ports without the port number in URLs:
http://api.localhost (port 80)
https://api.localhost (port 443)Binding to Privileged Ports
Ports below 1024 require elevated privileges on Unix systems. You must start the supervisor with sudo:
# HTTP on port 80
sudo PITCHFORK_PROXY_PORT=80 PITCHFORK_PROXY_HTTPS=false pitchfork supervisor start
# HTTPS on port 443 (default)
sudo pitchfork supervisor startOr in pitchfork.toml:
[settings.proxy]
enable = true
port = 80 # requires: sudo pitchfork supervisor start
https = falseRequires sudo
Binding to ports below 1024 (including 80 and 443) requires the supervisor to be started with sudo. The proxy will fail to start if it cannot bind to the configured port.
HTTPS Support
Auto-Generated Certificate
When proxy.https = true (the default) and no certificate is configured, pitchfork auto-generates a self-signed certificate:
[settings.proxy]
enable = true
# https = true is the default
# port = 443 is the defaultThe certificate is stored in $PITCHFORK_STATE_DIR/proxy/cert.pem.
Trusting the Certificate
Install the auto-generated certificate into your system trust store:
pitchfork proxy trustOn macOS, this installs the certificate into your user login keychain — no sudo required.
On Linux, this requires sudo:
sudo pitchfork proxy trustCustom Certificate
Provide your own certificate (e.g., from mkcert or Let's Encrypt):
[settings.proxy]
enable = true
https = true
tls_cert = "/path/to/cert.pem"
tls_key = "/path/to/key.pem"Using mkcert for a locally-trusted certificate:
# Install mkcert and set up local CA
mkcert -install
# Generate certificate for your TLD
mkcert "*.localhost" localhost 127.0.0.1
# Configure pitchfork to use it[settings.proxy]
enable = true
https = true
tls_cert = "/path/to/_wildcard.localhost+2.pem"
tls_key = "/path/to/_wildcard.localhost+2-key.pem"Custom TLD
Use a custom TLD instead of localhost:
[settings.proxy]
enable = true
tld = "test"This requires wildcard DNS resolution for *.test. On macOS with dnsmasq:
# Install dnsmasq
brew install dnsmasq
# Add wildcard DNS entry
echo "address=/.test/127.0.0.1" >> /usr/local/etc/dnsmasq.conf
# Configure macOS resolver
sudo mkdir -p /etc/resolver
echo "nameserver 127.0.0.1" | sudo tee /etc/resolver/test
# Start dnsmasq
sudo brew services start dnsmasqINFO
Later we will add built-in support for custom TLDs without manual DNS configuration.
Proxy Commands
# Show all registered slugs and their status
pitchfork proxy status
# Add a slug for the current directory
pitchfork proxy add myapp
# Add with explicit project dir and daemon name
pitchfork proxy add api --dir /path/to/project --daemon server
# Remove a slug
pitchfork proxy remove api
# Install TLS certificate into system trust store
pitchfork proxy trust
# Install a custom certificate
pitchfork proxy trust --cert /path/to/cert.pemViewing Proxy URLs
Proxy URLs are shown in CLI output when the proxy is enabled and the daemon has a registered slug:
$ pitchfork start api
Daemon 'myproject/api' started on port(s): 3000
→ Proxy: https://api.localhost
$ pitchfork list
Name PID Status Proxy URL
api 12345 running https://api.localhost
$ pitchfork status api
Name: myproject/api
PID: 12345
Status: running
Port: 3000 (active)
Proxy: https://api.localhost