localproxy — Guide & Tips

localproxy is a lightweight local HTTP proxy for browser-based tools — download, start, configuration and endpoints to fetch URLs without CORS.

localproxy is a lightweight, secure local HTTP proxy for browser-based online tools. It binds exclusively to 127.0.0.1 and lets your web applications fetch external URLs — safely bypassing the browser's CORS restrictions.

Guide

Requirements

  • A pre-built binary for your platform (Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD — common architectures each)
  • Alternatively, to build from source: Go 1.26+

Download the binary

Pre-built binaries for all platforms are available under Releases in the repository (e.g. localproxy-linux-amd64, localproxy-macos-apple-silicon, localproxy-windows-amd64.exe).

Make it executable (macOS / Linux)

chmod +x ./localproxy-macos-apple-silicon
# macOS: clear the Gatekeeper warning for the unsigned binary:
xattr -dr com.apple.quarantine ./localproxy-macos-apple-silicon

Start it

In the simplest case, with no further configuration:

./localproxy

On startup a banner shows the key values: the address (http://127.0.0.1:PORT — a random free port without --port), the token regenerated on every start, the DNS servers in use and the allowed origins.

Configuration

--port      int     TCP port to listen on (0 = random free port)          [default: 0]
--origin    string  Allowed origins, comma-separated
--timeout   int     Upstream request timeout in seconds                    [default: 30]
--max-mb    int64   Maximum upstream response size in MB (0 = unlimited)   [default: 50]
--dns       string  DNS servers, comma-separated, or "system" for OS DNS   [default: "1.1.1.1,8.8.8.8"]
--version           Print version information and exit

Examples:

# Production: allow only one specific tool
./localproxy --origin https://yourtool.example.com

# Custom DNS servers (Quad9 + Cloudflare)
./localproxy --dns "9.9.9.9,1.1.1.1"

# Use the operating system's DNS resolver
./localproxy --dns system

By default localproxy resolves names via Cloudflare (1.1.1.1) and Google (8.8.8.8) — independent of the host's DNS configuration, which keeps results consistent across machines. If the --dns value omits a port, :53 is appended automatically.

Endpoints

Endpoint Auth Description
GET/POST/HEAD /proxy?url=... yes (X-Proxy-Token) Forward the request to the target URL (body streaming, metadata headers)
GET /inspect?url=... yes Connection metadata as JSON (SSL, timing, IP, headers); &body=1 includes the body
GET /page?url=... yes Full page analysis: redirect chain + body + SSL + timing in one JSON
`OPTIONS /proxy /inspect /page`
GET /ping no Health check (returns localproxy ok)
GET /version no Version info as JSON

Integrating it in a tool

  1. The user enters the address (http://127.0.0.1:PORT) and token in the online tool.
  2. The tool verifies the connection via /ping.
  3. All further requests go through /proxy?url=... with the X-Proxy-Token header. Example:
const response = await fetch(
  `${PROXY_BASE}/proxy?url=${encodeURIComponent(targetUrl)}`,
  { headers: { "X-Proxy-Token": PROXY_TOKEN } }
);

Every /proxy response also carries upstream metadata as headers: X-Upstream-Protocol, X-Upstream-IP, X-Upstream-Timing (e.g. dns=12;tcp=45;ssl=23;ttfb=156;total=234), X-Upstream-Content-Encoding and X-Upstream-Content-Length. All upstream headers are readable from JavaScript.

Tips & Tricks

  • Restrict origins in production: Without --origin all origins are allowed. For production use, always allow the specific tool via --origin https://yourtool.example.com.
  • HTTPS page calling HTTP localhost — no problem: Browsers treat http://127.0.0.1 as a "potentially trustworthy origin" (W3C Secure Contexts). Requests from an HTTPS page to the local proxy are not blocked as mixed content; Chrome's Private Network Access preflight is answered automatically.
  • /page saves round-trips: The endpoint traces the redirect chain (up to 20 hops), downloads the body, inspects SSL and measures timing in a single JSON — replacing multiple /proxy and /inspect calls.
  • SSL details the browser won't give you: /inspect returns certificate information (version, issuer, validity, SANs, chain) that the Fetch API can't access. Without body=1 it sends only a HEAD request upstream (faster, no body download).
  • Security defaults: 48-character session token regenerated on each start, SSRF protection (target hosts are resolved and checked against private/loopback CIDRs), upstream TLS verification always on, redirects are not followed automatically (the client decides), response size capped via --max-mb.
  • Concurrency & compression: The proxy handles requests concurrently (one goroutine per connection); each upstream request uses a fresh connection for accurate timing. Brotli, gzip and deflate pass through transparently on /proxy — the browser handles decompression.
  • Build from source: With Go 1.26+ via go build -o localproxy .; cross-compile with GOOS/GOARCH (e.g. GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -trimpath -o localproxy.exe .). A Git tag (git tag v1.0.5 && git push origin v1.0.5) triggers cross-platform release builds automatically via GitHub Actions.
  • Tests & linting: go test -race ./... for the race detector; the project is linted with staticcheck (CI blocks the release on any finding). staticcheck is dev tooling only and never ships with the binary.

Further reading