Local Development Domains Without Port Conflicts, Without Framework Lock-In
As a Laravel developer, Valet had been my go-to solution for years: domains, certificates, routing — all automatic, as long as you stay within the PHP ecosystem. The problem starts as soon as Docker containers or other frameworks enter the picture. A Nuxt project on port 3000, a Go API on port 8080, a Docker-based service with no exposed ports — Valet knows nothing about any of them. Suddenly projects compete for ports, certificates are missing and /etc/hosts becomes administrative busywork.
This is exactly where proxypark comes in. A single Bash script that combines DNS, TLS certificates, reverse proxy and Docker integration into one consistent toolchain. No framework lock-in, no daemon, no dependencies of its own. The result: park link myapp 3000 — and https://myapp.test works immediately, in the browser, with a green padlock. Existing Valet projects keep running unchanged — proxypark can operate alongside Valet and only takes over the projects that Valet cannot serve.
This post explains why I built proxypark, what alternatives exist and why none of them solve the complete problem.
proxypark on GitHub
Open source, MIT-licensed. A single Bash script — installation in 30 seconds, no dependencies of its own. Clone, symlink, park install, done.
The Problem: Four Pain Points, No Common Denominator
Local development has four infrastructure problems that are almost always solved individually:
DNS — Every .test domain needs to resolve to 127.0.0.1 somewhere. Either manually via /etc/hosts or through dnsmasq, which you have to configure yourself.
Certificates — Modern browsers enforce HTTPS. Self-signed certificates produce warnings, wildcard certificates for .test are rejected since the domain was added to the Public Suffix List. Every domain needs its own certificate.
Routing — A reverse proxy must route requests to the correct port based on the hostname. Without one, all projects compete for ports 80 and 443.
Docker integration — Containers that don't expose ports are invisible from the host. Reaching them requires either port mappings or a network bridge to the proxy.
Each of these problems has its own tools. But no single tool solves all four at once — and that was the trigger for proxypark.
How proxypark Works
proxypark builds on three proven components: dnsmasq for DNS resolution, mkcert for trusted certificates and Traefik as reverse proxy. The connection between them is what matters.
Each park link command creates a small YAML file in the ~/.proxypark/dynamic/ directory. Traefik watches this directory via its file provider and picks up changes instantly — no restart, no reload. At the same time, proxypark regenerates the certificate bundle so the new domain is immediately reachable via HTTPS.
For Docker containers, park link:docker connects containers directly through an internal Docker network — no exposed ports, no Docker socket access. This bypasses the well-known issues with Docker Desktop, OrbStack and Colima on macOS, where the socket is redirected via symlinks and permission problems arise.
# Link a local service
park link myapp 3000
# → https://myapp.test
# Docker container without exposed ports
park link:docker api api-container:8080
# → https://api.test → api-container:8080
# Subdomains via dot notation
park link admin.myapp 3001
# → https://admin.myapp.test
The Alternatives — And Why They Fall Short
Laravel Valet
Valet is the best-known solution in the PHP ecosystem and still excellent for Laravel projects. It handles DNS, certificates and reverse proxy — but only for PHP. Valet starts its own nginx, expects a specific directory structure and only knows Laravel, Symfony and similar frameworks. As soon as a Nuxt frontend, a Go API or a Docker-based service enters the mix, Valet's scope ends. proxypark is stack-agnostic: anything listening on a port can be linked — and thanks to park valet enable, both tools run side by side. Valet continues serving PHP projects, proxypark handles the rest.
Traefik with Docker Labels
The "official" way to use Traefik in Docker environments. Each container gets labels like traefik.http.routers..., Traefik reads the Docker socket and configures itself. Sounds elegant, but works unreliably on macOS — Docker Desktop redirects the socket via symlinks, OrbStack and Colima have their own quirks. proxypark bypasses this entirely: it writes YAML files that Traefik reads via the file provider. No socket, no permission issues, no dependency on the Docker runtime.
Caddy
Caddy can achieve something similar with its automatic HTTPS feature and a simple Caddyfile. But Caddy only solves the proxy part — DNS and certificate distribution for .test domains must be set up separately. proxypark provides the complete chain: dnsmasq for DNS, mkcert for trusted certificates, Traefik for routing.
Manual nginx/Apache with /etc/hosts
The old-school approach. Write a config file for each project, generate certificates, reload nginx, maintain /etc/hosts. It works, but with five or more projects it becomes administrative overhead. proxypark reduces this to park link name port — one command instead of five files.
What proxypark Does Differently
The core of proxypark is not a technical breakthrough, but a design decision: A single Bash script with no dependencies of its own. Installation means cloning and symlinking. Uninstallation means deleting a directory. There is no daemon, no build step, no package manager.
Yet it solves all four problems simultaneously — DNS, certificates, routing, Docker integration — while remaining framework-agnostic. Whether Laravel, Nuxt, Rails or a Go service: anything listening on a port or running in a container gets a .test domain with trusted HTTPS.
A deliberate design decision is seamless coexistence with Laravel Valet. park valet enable creates a catchall that routes all .test domains not explicitly linked to Valet. In practice this means: shift Valet to port 8080, activate the catchall — and from that point on proxypark serves Docker and non-PHP projects while Valet delivers Laravel projects as usual. Explicit park link entries always take priority. Migration is not all-or-nothing, but a gradual process.
Conclusion
proxypark was born from daily work on multiple projects simultaneously — with different stacks, different runtimes and the same infrastructure overhead every time. It is deliberately minimal: one script, three proven tools, zero abstraction on top.
If you want local development with clean domains, trusted HTTPS and no port conflicts, you don't need a complex platform for that. One command is enough.
Call to Action
proxypark is open source and available on GitHub: https://github.com/McGo/proxypark
If you need support setting up local development environments — whether for a single team or an entire department — feel free to reach out. As a backend and solution architect, I know the stumbling blocks between "works on my machine" and a reproducible development environment.