Skip to content

McGo/proxypark

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🅿️ proxypark

Local reverse-proxy & DNS manager for macOS. Zero port conflicts, parallel development, trusted HTTPS — all from a single CLI.

proxypark replaces the infrastructure layer of tools like Laravel Valet with a framework-agnostic setup built on Traefik, dnsmasq, and mkcert.

Browser → https://myapp.test
              │
         ┌────┴─────┐
         │  Traefik  │  :443 (only port listener)
         └────┬──────┘
              │
         File-provider
         (~/.proxypark/dynamic/)
              │
    ┌─────────┼──────────────┐
    │         │              │
    ▼         ▼              ▼
 park link  park link:docker  park valet enable
 localhost  container:port    Valet catchall
 (exposed)  (no exposed       on localhost:8080
             ports needed)

Why?

If you run Docker-based projects alongside native services (PHP, Node, etc.), you've likely hit port conflicts — every project wants :80 and :3000. proxypark solves this by routing everything through Traefik using hostnames instead of ports.

  • No port conflicts — Everything routes by hostname, not port.
  • Parallel development — Run 5+ projects at once, each on its own *.test domain.
  • Trusted HTTPS — Per-domain mkcert certificates, accepted by all browsers including Firefox.
  • Mix Docker & native — Services registered via park link, Valet as optional fallback.
  • Framework-agnostic — Works with any stack. Laravel, Nuxt, Rails, Go, whatever.
  • No Docker socket needed — Uses Traefik's file-provider exclusively. No socket permission headaches.

Quick start

# Clone and symlink
git clone git@github.com:McGo/proxypark.git ~/proxypark
ln -sf ~/proxypark/park /usr/local/bin/park

# Run setup (installs mkcert, dnsmasq, starts Traefik)
park install

# Link a local service
park link myapp 3000
# → https://myapp.test

# Optional: route unmatched domains to Valet
park valet enable

Commands

Infrastructure

Command Description
park install First-time setup
park uninstall Remove everything
park start Start Traefik
park stop Stop Traefik
park restart Restart Traefik
park status Health check
park doctor [--fix] Diagnose and auto-fix common issues
park trust (Re-)install mkcert CA (system + Firefox)
park certs Regenerate certificates from current links
park logs Tail Traefik logs
park dashboard Open Traefik dashboard

Projects

Use dot notation for subdomains: api.myapphttps://api.myapp.test

Command Description
park link <name> <port> Link local service → https://<name>.test
park link:docker <name> <container>[:<port>] Link Docker container (no exposed ports)
park unlink <name> Remove link
park list Show all routes
park open <name> Open project in browser
park scaffold <name> Generate docker-compose.yml template

Valet integration

Command Description
park valet enable [port] Route unmatched *.test to Valet (default: 8080)
park valet disable Remove Valet catchall

How it works

File-provider architecture

proxypark uses Traefik's file-provider exclusively. No Docker socket is mounted — this avoids permission issues with Docker Desktop, OrbStack, Colima, etc.

Each park link creates a small YAML config in ~/.proxypark/dynamic/. Traefik watches this directory and picks up changes instantly — no restart needed.

Per-domain certificates

.test is on the Public Suffix List, which means browsers reject wildcard certificates (*.test) just like they would reject *.com. proxypark solves this by generating explicit per-domain certificates via mkcert.

Every park link and park unlink automatically regenerates the certificate bundle to include all currently linked domains. Traefik picks up the new certs via its file-watcher.

DNS

proxypark installs its own dnsmasq config (independent of Valet) that resolves all *.test domains to 127.0.0.1. A macOS resolver entry at /etc/resolver/test tells the OS to use the local dnsmasq for .test lookups.

Valet coexistence

If you still have Valet projects, park valet enable creates a low-priority catchall that routes any *.test domain not matched by an explicit link to Valet on port 8080. Explicit park link entries always take priority.

# Shift Valet to port 8080
valet stop && valet port 8080 && valet start

# Enable catchall in proxypark
park valet enable

Using with Docker projects

Option A: With exposed ports (park link)

If your containers expose ports to the host, use park link like any local service:

park link myapp 3000
# → https://myapp.test

Option B: Without exposed ports (park link:docker)

park link:docker connects containers directly via Docker's proxy network — no port mapping needed:

park link:docker myapp myapp-container
# → https://myapp.test → myapp-container:80

park link:docker myapp myapp-container:3000
# → https://myapp.test → myapp-container:3000

When called without arguments in a directory with a docker-compose.yml, it shows available services:

park link:docker
# SERVICE     CONTAINER        STATE
# api         myapp-api        running
# app         myapp-app        stopped

After linking, park link:docker checks your docker-compose.yml and offers to add container_name and the proxy network if missing — so containers stay reachable after docker compose down/up.

Subdomains (dot notation)

Use dot notation for subdomains with both link and link:docker:

park link api.myapp 8001
# → https://api.myapp.test

park link:docker api.myapp api-container:3000
# → https://api.myapp.test → api-container:3000

Use park scaffold <name> to generate a boilerplate docker-compose.yml.

Integrating with an existing local dev stack

If you already have a docker-compose.yml with shared services (Postgres, Redis, etc.), you can add Traefik as a service. Add this to your existing compose file:

services:
  traefik:
    image: traefik:v3.2
    container_name: proxypark
    restart: unless-stopped
    command:
      - --api.insecure=true
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entrypoint.to=websecure
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --providers.file.directory=/etc/traefik/dynamic
      - --providers.file.watch=true
      - --log.level=INFO
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - ~/.proxypark/dynamic:/etc/traefik/dynamic:ro
      - ~/.proxypark/certs:/etc/traefik/certs:ro
    networks:
      - proxy
    extra_hosts:
      - "host.docker.internal:host-gateway"

networks:
  proxy:
    name: proxy
    external: true

Then use park link to route services with web UIs:

park link mailpit 8025        # https://mailpit.test
park link meilisearch 7700    # https://meilisearch.test

Migrating from Valet

  1. Run park install
  2. Shift Valet to port 8080: valet stop && valet port 8080 && valet start
  3. Enable Valet catchall: park valet enable
  4. For each project you want explicit HTTPS:
    • park link projectname <port>
  5. Once all projects are migrated: valet stop && valet uninstall && park valet disable

Configuration

All runtime data lives in ~/.proxypark/:

~/.proxypark/
├── docker-compose.yml          # Traefik container (standalone mode)
├── certs/
│   ├── wildcard.test.pem       # Per-domain cert bundle
│   └── wildcard.test-key.pem
└── dynamic/                    # Traefik file-provider configs
    ├── tls.yml                 # TLS certificate reference
    ├── valet.yml               # Valet catchall (optional)
    ├── link-myapp.yml          # park link
    ├── link-api-myapp.yml      # park link (subdomain)
    └── link-docker-myapp.yml   # park link:docker

Customize via environment variables:

export PROXYPARK_TLD=dev        # Use .dev instead of .test
export PROXYPARK_DATA_DIR=...   # Different data path

Troubleshooting

Port 80 already in use:

lsof -i :80   # Find the culprit
# Common: nginx, apache, Valet

DNS not resolving:

dscacheutil -flushcache
dig myapp.test @127.0.0.1    # Should return 127.0.0.1
park status                   # Full health check

HTTPS certificate not trusted:

park trust        # Reinstall CA (system + Firefox via nss)
# Then restart your browser

Certificate doesn't cover a domain:

park certs        # Regenerate from all current links

Requirements

Roadmap

  • park doctor – Automated diagnostics and fixes
  • Zsh/Bash completions
  • Homebrew tap (brew install McGo/tap/proxypark)
  • park serve – Start a simple PHP/Node server and auto-link

License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages