An implementation of Crystade Proxy Server.
- ✅ Custom header-based proxying (
X-Proxy-Upstream) - ✅ IP blacklist (RFC 1918 private networks, loopback, link-local)
- ✅ DNS resolution with fresh lookups per request
- ✅ Loop detection via
X-Proxy-Stateheader - ✅ Optional authentication via
X-Proxy-Auth - ✅ Optional redirect following (
X-Proxy-Follow-Redirects) - ✅ TLS certificate validation
- ✅ Connection lifecycle management (client/upstream disconnection handling)
- ✅ Proper error responses with
X-Proxy-State: ERROR
All configuration is via environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
HOST |
No | localhost |
Host/interface to bind to (e.g., 0.0.0.0, localhost) |
PORT |
No | 8080 |
Port to listen on (e.g., 8080) |
AUTH_SECRET |
No | "" |
If set, requires X-Proxy-Auth header with this value |
UPSTREAM_TIMEOUT |
No | 30s |
Timeout for upstream connections (e.g., 10s, 1m) |
DISABLE_TLS_VERIFY |
No | false |
Disable TLS certificate verification (dev only) |
go build -o proxy-server .# Basic usage (defaults to localhost:8080)
./proxy-server
# Custom port
PORT=9000 ./proxy-server
# Bind to all interfaces
HOST=0.0.0.0 PORT=8080 ./proxy-server
# With authentication
PORT=8080 AUTH_SECRET=my-secret-token ./proxy-server
# With custom timeout
PORT=8080 UPSTREAM_TIMEOUT=10s ./proxy-server# Basic request
curl -H "X-Proxy-Upstream: https://api.example.com/data" \
http://localhost:8080/
# With authentication
curl -H "X-Proxy-Upstream: https://api.example.com/data" \
-H "X-Proxy-Auth: my-secret-token" \
http://localhost:8080/
# POST request with body
curl -X POST \
-H "X-Proxy-Upstream: https://api.example.com/submit" \
-H "Content-Type: application/json" \
-d '{"key":"value"}' \
http://localhost:8080/
# With redirect following (same-origin only)
curl -X POST \
-H "X-Proxy-Upstream: https://api.example.com/submit" \
-H "X-Proxy-Follow-Redirects: same-origin" \
-H "Content-Type: application/json" \
-d '{"key":"value"}' \
http://localhost:8080/By default, the proxy forwards 3xx redirect responses to the client unchanged. To have the proxy follow redirects automatically:
# Follow same-origin redirects only
# (redirect must have same scheme, host, and port as original URL)
curl -H "X-Proxy-Upstream: https://api.example.com/redirect" \
-H "X-Proxy-Follow-Redirects: same-origin" \
http://localhost:8080/
# Follow cross-origin redirects
# (cookies are stripped when origin changes for security)
curl -H "X-Proxy-Upstream: https://api.example.com/redirect" \
-H "X-Proxy-Follow-Redirects: cross-origin" \
http://localhost:8080/Redirect Following Behavior:
- Follows up to 5 consecutive redirects (returns
508 Loop Detectedif exceeded) - Only follows
301,302,307, and308status codes withLocationheader - Methods are transformed per HTTP semantics:
301/302: Changes toGET(exceptHEADremainsHEAD)307/308: Preserves original method
- In
same-originmode: Blocks redirects to different origins - In
cross-originmode: StripsCookieheader when origin changes - All redirect targets are validated against IP blacklist
- Only the final response is returned to the client
Every response includes X-Proxy-State:
X-Proxy-State: FORWARDED- Response is from the upstream serverX-Proxy-State: ERROR- Response is a proxy-generated error
| Status | Reason |
|---|---|
400 Bad Request |
Missing or invalid X-Proxy-Upstream, invalid URL scheme, or auth over plain HTTP |
401 Unauthorized |
Missing or invalid X-Proxy-Auth |
403 Forbidden |
Upstream IP is blacklisted (private/loopback/link-local) |
501 Not Implemented |
Protocol upgrade requested (WebSocket, etc.) |
502 Bad Gateway |
Upstream unreachable (DNS failure, connection refused, etc.) |
504 Gateway Timeout |
Upstream connection timeout |
508 Loop Detected |
Upstream response contains X-Proxy-State header, or redirect chain exceeds 5 hops |
- Strong authentication (
AUTH_SECRET) - TLS/HTTPS on the client-proxy connection
- Network-layer access controls (firewall, VPC, etc.)
- Additional security measures (mTLS, IP allowlisting, etc.)
The proxy blocks connections to:
- RFC 1918 private networks:
10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 - Loopback:
127.0.0.0/8,::1/128 - Link-local:
169.254.0.0/16,fe80::/10 - IPv6 unique local:
fc00::/7 - Current network:
0.0.0.0/8
$ curl -v -H "X-Proxy-Upstream: https://httpbin.org/get" http://localhost:8080/
< HTTP/1.1 200 OK
< X-Proxy-State: FORWARDED
< Content-Type: application/json
...$ curl -v -H "X-Proxy-Upstream: http://192.168.1.1/" http://localhost:8080/
< HTTP/1.1 403 Forbidden
< X-Proxy-State: ERROR
< Content-Type: application/json
{"reason":"upstream IP is forbidden","detail":"target ip 192.168.1.1 is blocked by 192.168.0.0/16"}$ curl -v http://localhost:8080/
< HTTP/1.1 400 Bad Request
< X-Proxy-State: ERROR
< Content-Type: application/json
{"reason":"missing X-Proxy-Upstream header"}This project is licensed under the MIT License - see the LICENSE file for details.