# localproxy — Anleitung & Tipps

> localproxy ist ein schlanker lokaler HTTP-Proxy für Browser-basierte Online-Tools — Download, Start, Konfiguration und Endpunkte, um externe URLs ohne CORS-Probleme abzurufen.

Source: https://www.jpkc.com/db/guides/proxy-jpkcom-dev-tools/

localproxy ist ein schlanker, sicherer lokaler HTTP-Proxy für Browser-basierte Online-Tools. Er bindet ausschließlich an `127.0.0.1` und erlaubt deinen Web-Anwendungen, externe URLs abzurufen — ohne an den CORS-Beschränkungen des Browsers zu scheitern.

## Anleitung

### Voraussetzungen

- Eine vorgefertigte Binary für deine Plattform (Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD — jeweils gängige Architekturen)
- Alternativ für den Build aus dem Quellcode: [Go 1.26+](https://go.dev/dl/)

### Binary herunterladen

Vorgefertigte Binaries für alle Plattformen liegen im Repository unter **Releases** (z. B. `localproxy-linux-amd64`, `localproxy-macos-apple-silicon`, `localproxy-windows-amd64.exe`).

### Ausführbar machen (macOS / Linux)

```bash
chmod +x ./localproxy-macos-apple-silicon
# macOS: Gatekeeper-Warnung der unsignierten Binary aufheben:
xattr -dr com.apple.quarantine ./localproxy-macos-apple-silicon
```

### Starten

Im einfachsten Fall ohne weitere Konfiguration:

```bash
./localproxy
```

Beim Start zeigt ein Banner die wichtigen Werte an: die **Adresse** (`http://127.0.0.1:PORT` — ohne `--port` ein zufälliger freier Port), das bei jedem Start neu erzeugte **Token**, die verwendeten **DNS-Server** und die zugelassenen **Origins**.

### Konfiguration

```
--port            int     TCP-Port (0 = zufälliger freier Port)                  [Standard: 0]
--origin          string  Erlaubte Origins, kommagetrennt
--timeout         int     Timeout für Upstream-Anfragen in Sekunden              [Standard: 30]
--max-mb          int64   Maximale Antwortgröße in MB (0 = unbegrenzt)           [Standard: 50]
--dns             string  DNS-Server, kommagetrennt, oder "system" für OS-DNS    [Standard: "1.1.1.1,8.8.8.8"]
--allow-any-host          Nicht-lokale Host-Header akzeptieren (nicht empfohlen)
--version                 Versionsinformation ausgeben und beenden
```

`--port`, `--timeout` und `--max-mb` werden beim Start validiert — ein Wert außerhalb des zulässigen Bereichs bricht mit einer Meldung ab, statt später verwirrend fehlzuschlagen.

Beispiele:

```bash
# Produktion: nur ein bestimmtes Tool zulassen
./localproxy --origin https://deintool.example.com

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

# DNS-Resolver des Betriebssystems verwenden
./localproxy --dns system
```

Standardmäßig löst localproxy Namen über **Cloudflare (1.1.1.1)** und **Google (8.8.8.8)** auf — unabhängig von der DNS-Konfiguration des Hosts, was über Maschinen hinweg konsistente Ergebnisse liefert. Fehlt beim `--dns`-Wert der Port, wird `:53` automatisch ergänzt.

#### `--allow-any-host`

Standardmäßig beantwortet localproxy nur Anfragen, deren `Host`-Header das Loopback-Interface benennt (`127.0.0.0/8`, `localhost` oder `[::1]`, mit beliebigem Port). Das blockiert DNS-Rebinding: Ohne die Prüfung könnte eine Webseite einen von ihr kontrollierten Hostnamen auf `127.0.0.1` zeigen lassen und den Proxy aus deinem Browser heraus ansprechen.

`--allow-any-host` brauchst du nur, wenn du den Proxy unter einem anderen lokalen Namen erreichst — etwa über einen Container-Alias. Greif lieber zu `--origin`, statt die Prüfung abzuschalten.

### Endpunkte

| Endpunkt | Auth | Beschreibung |
|---|---|---|
| `GET/POST/HEAD /proxy?url=...` | ja (`X-Proxy-Token`) | Anfrage an die Ziel-URL weiterleiten (Body-Streaming, Metadaten-Header) |
| `GET /inspect?url=...` | ja | Verbindungs-Metadaten als JSON (SSL, Timing, IP, Header, `http3`); `&body=1` inkl. Body |
| `GET /page?url=...` | ja | Vollständige Seitenanalyse: Redirect-Kette + Body + SSL + Timing + `http3` in einem JSON |
| `OPTIONS /proxy|/inspect|/page` | nein | CORS-Preflight (204 mit CORS- und PNA-Headern) |
| `GET /ping` | nein | Health-Check (gibt `localproxy ok` zurück) |
| `GET /version` | nein | Versionsinfo als JSON |

### Einbindung im Tool

1. Nutzer gibt **Adresse** (`http://127.0.0.1:PORT`) und **Token** im Online-Tool ein.
2. Das Tool prüft die Verbindung über `/ping`.
3. Alle weiteren Anfragen laufen über `/proxy?url=...` mit dem Header `X-Proxy-Token`. Beispiel:

```javascript
const response = await fetch(
  `${PROXY_BASE}/proxy?url=${encodeURIComponent(targetUrl)}`,
  { headers: { "X-Proxy-Token": PROXY_TOKEN } }
);
```

Jede `/proxy`-Antwort liefert zusätzlich Upstream-Metadaten als Header: `X-Upstream-Protocol`, `X-Upstream-IP`, `X-Upstream-Timing` (z. B. `dns=12;tcp=45;ssl=23;ttfb=156;total=234`), `X-Upstream-Content-Encoding`, `X-Upstream-Content-Length` und — nur wenn der Body die `--max-mb`-Grenze gerissen hat und abgeschnitten wurde — `X-Upstream-Truncated: 1`. Alle Upstream-Header sind per JavaScript lesbar.

**Fehler sind auswertbar:** Alle 4xx-Antworten tragen CORS-Header und einen JSON-Body mit maschinenlesbarem Code (`bad_request`, `forbidden`, `blocked_target`, `method_not_allowed`) — ein falsches Token ist damit von einem nicht erreichbaren Proxy unterscheidbar. Nur abgelehnte Origins bekommen bewusst ein nacktes 403 ohne CORS-Header.

**Diese Header gehen nicht ans Ziel:** `Cookie`, `Cookie2`, `Authorization`, `Proxy-Authorization`, `Origin`, `Referer` und `Sec-Fetch-*` werden nie weitergereicht, damit Anmeldedaten und Identitätssignale des Aufrufers nicht beim Zielserver landen. Header, die du bewusst setzt — `Accept`, `User-Agent`, `Accept-Language`, eigene `X-*` — passieren weiterhin.

## Tipps & Tricks

- **In Produktion Origins einschränken:** Ohne `--origin` sind alle Origins erlaubt. Für den produktiven Einsatz immer das konkrete Tool per `--origin https://deintool.example.com` freigeben.
- **HTTPS-Seite ruft HTTP-localhost auf — kein Problem:** Browser behandeln `http://127.0.0.1` als „potentially trustworthy origin" (W3C Secure Contexts). Anfragen von einer HTTPS-Seite an den lokalen Proxy werden **nicht** als Mixed Content blockiert; Chromes Private-Network-Access-Preflight wird automatisch beantwortet.
- **`/page` spart Roundtrips:** Der Endpunkt verfolgt die Redirect-Kette (bis zu 20 Hops), lädt den Body, inspiziert SSL und misst Timings in einem einzigen JSON — er ersetzt mehrere `/proxy`- und `/inspect`-Aufrufe. Seit 1.1.0 leitet er sein gesamtes Zeitbudget aus dem Request-Kontext des Clients ab: Bricht der Client ab, endet auch die Arbeit am Server. Vorher liefen Redirect-Hops und Encoding-Proben mit `context.Background()`, sodass 20 langsame Redirects einen Handler minutenlang am Leben halten konnten.
- **SSL-Details, die der Browser nicht hergibt:** `/inspect` liefert Zertifikatsinformationen (Version, Aussteller, Gültigkeit, SANs, Chain — inklusive IP-SANs), die über die Fetch-API nicht zugänglich sind. Ohne `body=1` wird upstream nur ein HEAD-Request gesendet (schneller, kein Body-Download).
- **HTTP/3 erkennen, ohne HTTP/3 zu sprechen:** `/inspect` und `/page` liefern seit Version 1.1.0 ein Feld `http3`. Es beantwortet „unterstützt dieses Ziel HTTP/3?" — **nicht** „lief diese Anfrage über HTTP/3?". Die Antwort stammt aus dem `Alt-Svc`-Feld der Zielantwort (RFC 7838, ALPN-Token `h3` nach RFC 9114); genau so entdecken Browser HTTP/3 auch, nämlich über TCP. Es ist also kein QUIC-Stack im Spiel. Entwurfs-Token wie `h3-29` werden ignoriert, das rohe `Alt-Svc`-Feld bleibt in der `headers`-Map verfügbar. `protocol` sagt weiterhin, worüber diese eine Anfrage tatsächlich lief — die Kombination `{"protocol": "HTTP/2.0", "http3": true}` ist der Normalfall, kein Widerspruch.
- **Sicherheits-Defaults:** 48-Zeichen-Session-Token bei jedem Start neu, SSRF-Schutz, TLS-Upstream-Verifikation immer aktiv, Redirects werden **nicht** automatisch gefolgt (der Client entscheidet), Antwortgröße per `--max-mb` gedeckelt, Token-Vergleich in konstanter Zeit, `X-Content-Type-Options: nosniff` auf allen selbst erzeugten Antworten.
- **SSRF-Schutz greift erst im Dialer:** Seit 1.1.0 wird die Zieladresse **nach** der DNS-Auflösung und **vor** dem Verbindungsaufbau geprüft. Die frühere Vorab-Prüfung löste den Namen getrennt vom HTTP-Client auf — eine vom Angreifer kontrollierte Zone mit kurzer TTL konnte der Prüfung eine öffentliche und der Verbindung eine Loopback-Adresse liefern. Die Vorab-Prüfung bleibt als schneller Abbruchpfad erhalten und ist auf 5 s begrenzt. Die Sperrliste deckt jetzt auch reservierten IPv4-Raum (`0/8`, `192.0.0.0/24`, `198.18/15`, Multicast, `240/4`) und die IPv6-Formen mit eingebetteter IPv4-Adresse ab — IPv4-mapped, NAT64 (`64:ff9b::/96`) und 6to4 (`2002::/16`). `64:ff9b::7f00:1` erreicht in einem NAT64-Netz `127.0.0.1` und war einer rein v4-basierten Prüfung vorher unsichtbar.
- **Nebenläufigkeit & Kompression:** Der Proxy bearbeitet Anfragen parallel (eine Goroutine pro Verbindung); jede Upstream-Anfrage nutzt eine frische Verbindung für genaues Timing. Brotli, gzip und deflate werden bei `/proxy` transparent durchgereicht — die Dekompression übernimmt der Browser. Bei `/inspect` mit `body=1` dekomprimiert der Proxy selbst; `Content-Encoding: deflate` versteht seit 1.1.0 sowohl zlib-verpackte Daten (RFC 1950) als auch rohes DEFLATE (RFC 1951) — vorher kam die zlib-Variante, die ein großer Teil der Server sendet, leer oder beschädigt zurück.
- **Aus dem Quellcode bauen:** Mit Go 1.26+ via `go build -o localproxy .` (die Releases werden mit Go 1.26.5 gebaut); Cross-Compiles über `GOOS`/`GOARCH` (z. B. `GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags="-s -w" -trimpath -o localproxy.exe .`). Ein Git-Tag (`git tag v1.1.0 && git push origin v1.1.0`) stößt über GitHub Actions automatisch plattformübergreifende Release-Builds an.
- **Tests & Linting:** `go test -race ./...` für den Race-Detector; das Projekt wird mit [staticcheck](https://staticcheck.dev/) gelintet, dazu kommen `govulncheck` und eine `gofmt`-Prüfung (CI blockt den Release bei jedem Befund). Seit 1.1.0 läuft die CI bei jedem Push und Pull Request, nicht mehr nur auf Tags — ein kaputter Test fällt damit nicht erst zum Release auf. staticcheck ist reines Dev-Tooling und landet nie in der Binary.

## Weiterführende Informationen

- Quellcode auf GitHub: <https://github.com/JPKCom/proxy-jpkcom-dev-tools>
- [Go (Download & Installation)](https://go.dev/dl/)
- [staticcheck](https://staticcheck.dev/)
- [Changelog dieses Projekts](https://www.jpkc.com/db/changelog/proxy-jpkcom-dev-tools/)

