proxypark is an open-source CLI tool (park) for local reverse-proxy management on macOS.
It uses Traefik + dnsmasq + mkcert to give every local project a clean https://*.test domain
with trusted certificates — no port conflicts, parallel development, Valet migration path.
Repo: git@github.com:McGo/proxypark.git
License: MIT
CLI command: park
These are hard-won lessons from the initial setup session. Do NOT change these without good reason:
Traefik's Docker provider requires mounting /var/run/docker.sock. On macOS with Docker Desktop,
this fails with empty API responses due to socket symlink issues (/var/run/docker.sock →
~/.docker/run/docker.sock). Even mounting the real path doesn't work reliably.
Decision: We use Traefik's file-provider exclusively. Each park link writes a YAML config
to ~/.proxypark/dynamic/. Traefik watches the directory and picks up changes instantly.
.test is on the Public Suffix List (PSL). Browsers (Firefox, Chrome) reject wildcard certs
for PSL TLDs — *.test is treated like *.com. mkcert also doesn't support double wildcards
(*.*.test throws "not a valid hostname").
Decision: We generate explicit per-domain certs. Every park link and park unlink calls
regenerate_certs which collects all domains from link-*.yml files and runs mkcert with the
full list. The cert file is always named wildcard.test.pem (for config stability) but contains
SANs for each individual domain.
Traefik v3 changed the HostRegexp syntax. The old v2 syntax HostRegexp({name:.+}.test) no
longer works. The correct v3 syntax is:
rule: "HostRegexp(`.+\\.test`)"Valet can coexist by running on port 8080. The park valet enable command creates a catchall
router with priority: 1 (lowest). Explicit park link entries always win because Traefik
assigns higher priority to more specific rules.
proxypark/
├── park # Single-file Bash CLI (~1080 lines)
├── README.md
├── LICENSE # MIT
├── CLAUDE.md # This file
└── .gitignore
Runtime data (NOT in repo):
~/.proxypark/
├── docker-compose.yml
├── certs/
│ ├── wildcard.test.pem
│ └── wildcard.test-key.pem
└── dynamic/
├── tls.yml
├── valet.yml (optional)
├── link-*.yml
└── link-docker-*.yml
- Single-file CLI:
parkis one Bash script. Keep it that way for now — no build step, no dependencies beyond Bash, mkcert, dnsmasq, Docker. - macOS only: We assume Homebrew,
/etc/resolver/,opencommand, Apple Silicon + Intel paths. Linux support is a future goal, not a current constraint. - All state in
~/.proxypark/: The repo is stateless. You canrm -rf ~/.proxyparkandpark installto start fresh. - Cert regeneration is automatic:
park link,park link:docker, andpark unlinkall callregenerate_certsand restart Traefik. Never require the user to manually runpark certs. - Dot notation for subdomains:
park link api.myapp 3000replaces the oldpark link:sub.link:substill works as legacy alias. - link:docker compose integration: After linking a Docker container,
park link:dockerchecks the localdocker-compose.ymlforcontainer_nameandproxynetwork, and offers to add them automatically so the link survivesdocker compose down/up. - macOS grep compatibility: Never use
grep -P(GNU Perl regex). Usesedfor pattern extraction instead — BSD grep on macOS doesn't support-P.
Priority order for development:
✅ — Implemented. 16 checks with auto-fix (park doctor--fixflag).- Zsh completions —
park <TAB>for commands,park unlink <TAB>for link names. - Homebrew tap —
brew install McGo/tap/proxyparkfor easy distribution. park serve— Start a PHP built-in server or Vite dev server in CWD and auto-link.- Docker provider (optional) — Re-add as opt-in if socket issues get resolved. The file-provider path must always work as primary.
Currently no automated tests. Manual testing workflow:
# Fresh install
park install
park status
# Link a service
park link testapp 8000
park list
curl -k https://testapp.test # Should route to localhost:8000
# Unlink
park unlink testapp
park list
# Valet integration
park valet enable
park valet disable
# Clean teardown
park uninstall