Local HTTPS reverse proxy and port registry for local development.
Note
gate is a local development tool for developer machines. It is intended for testing local services, not for production traffic or hosted environments.
Using Homebrew:
brew install jinyongp/tap/gateOr using the install script:
curl -fsSL https://raw.githubusercontent.com/jinyongp/gate/main/scripts/install.sh | shSupported platforms: macOS and Linux (darwin, linux) on arm64 and amd64.
Tip
The install script writes gate to ~/.local/bin by default. If that
directory is not in PATH, the installer offers to update your shell startup
file and also prints the exact line you can add manually.
For full usage, see docs/usage.md. For detailed setup notes and internals, see docs/spec.md.
Using Homebrew:
brew update
brew upgrade gateOr using gate's built-in upgrade command:
gate upgradeThis updates gate to the latest GitHub release.
If the running gate binary is Homebrew-managed, gate upgrade uses
brew upgrade gate; otherwise it runs the standalone installer.
During installation gate shows a single status indicator and hides installer
logs unless the install command fails.
After a successful upgrade, gate automatically runs doctor and prints any
stale local state with the matching gate doctor --fix repair hint.
Remove gate's local state, trust entry, managed hosts/PATH blocks, and known binaries:
gate uninstallNon-interactive:
gate uninstall -yIf the running gate binary is Homebrew-managed, gate uninstall runs
brew uninstall gate as its final step. Use --keep-brew to leave the
Homebrew package installed. Use --keep-trust to leave trust store entries in
place.
If the gate binary is already gone, use the standalone uninstall script:
curl -fsSL https://raw.githubusercontent.com/jinyongp/gate/main/scripts/uninstall.sh | sh# non-interactive
curl -fsSL https://raw.githubusercontent.com/jinyongp/gate/main/scripts/uninstall.sh | sh -s -- -yThe script first attempts to remove gate's trusted root CA from OS/browser trust stores, then removes only files and directories it discovers on the current machine. If privileged setup artifacts were never created, they are not removed. Homebrew-managed symlinks are skipped by the script, so it does not remove the Homebrew package itself.
Run this inside your app repository.
-
Trust gate's local HTTPS certificate authority once:
gate trust
This may ask for administrator approval.
-
Create
gate.toml:gate init
For a non-interactive default:
gate init -y
Or edit the generated file to add more services:
[project] name = "my-project" base = "my-project.localhost" [services.web] [services.api] port = 3001 env = "API_URL"
-
Start gate and run your dev server through the reserved port:
gate up -d gate run web -- pnpm dev
Replace
pnpm devwith your app's dev-server command.gate runinjectsPORT, peerGATE_<SERVICE>_*values, and configured service env names such asAPI_URL. -
Open:
https://web.my-project.localhostUse the route printed by
gate up; if your project name or domain differs, the URL differs too.
.localhost domains need no DNS setup. Custom domains need /etc/hosts or
another local DNS setup, so gate up may ask for administrator approval.
For LAN access, gate expose <service> --via lan derives a .local alias from
the service domain: .local stays unchanged, .localhost becomes .local, and
other domains append .local.
Gate daemons are keyed by listener address, not by project. The default listener
owns HTTPS :443 and HTTP :80, so project and global reservations that use the
same listener are served by the same daemon. gate up -d starts that listener
daemon when needed, then reloads its routes. Use gate daemon status --all to
inspect every known listener daemon.
Global reservations are machine-local mappings without gate.toml:
gate add -g web 3000 --domain web.localhost
gate daemon start
gate run -g web -- pnpm dev
gate rm -g webRegistry commands use the current project by default when gate.toml is
discoverable, and the global scope otherwise. Use -g/--global for global
reservations or -p/--project <name> for a named project. gate rm removes by
service/name. Use gate clear -y, gate clear -g -y, or
gate clear -p <project> -y to remove every reservation in one scope.
base, domain, host, and port can read environment variables when a team
needs per-developer values:
[project]
name = "my-project"
env_files = [".env.local", ".env"]
base = "${BASE_DOMAIN:-example.localhost}"
[services.web]
port = "${WEB_PORT:-3000}"
[services.api]
port = "${API_PORT}"
env = "API_URL"env_files are resolved relative to gate.toml. Missing files are ignored, so
session environment variables still work without a local dotenv file. Process
environment values win over dotenv values, and earlier dotenv files win over
later ones. ${NAME} is required and fails if unset; ${NAME:-default} uses
the default when unset or empty.
Development uses the repository checkout and the just command runner.
Prerequisites:
- Go
just
Development recipes fetch Go tools such as golangci-lint, govulncheck, and
goimports with go run, so they do not need separate manual installation.
Set up a checkout:
git clone https://github.com/jinyongp/gate.git
cd gate
just buildRun from source:
just gate --help
just gate lsRun validation before opening a pull request:
just checkUseful development commands:
just fmt
just test
just lint-json
just vulnLocal smoke tests are available for contributors:
just smoke check
just smoke serve
just smoke routeThose smoke recipes build the local bin/gate binary from this checkout, run
the sample app through gate on random front-proxy ports, and clean up their
temporary gate state when they exit. For full command usage, see
docs/usage.md.