Skip to content

crystade/proxy-server-node

Repository files navigation

Proxy Server (Node.js/TypeScript)

An implementation of Crystade Proxy Server.

Features

  • Custom Header-Based Proxying - Uses X-Proxy-Upstream header instead of CONNECT method
  • SSRF Protection - Comprehensive IP blacklist prevents access to private networks
  • Loop Detection - Prevents infinite proxy chains
  • Authentication - Optional token-based authentication with constant-time comparison
  • Redirect Following - Optional same-origin and cross-origin redirect handling
  • Streaming - Efficient streaming of request and response bodies
  • Cloudflare Workers Compatible - Runs on edge runtimes and serverless platforms
  • TypeScript - Full type safety and excellent IDE support

Installation

# Install dependencies
pnpm install

# Build TypeScript
pnpm build

Configuration

Configuration is done via environment variables:

Variable Required Default Description
HOST No localhost Server bind address (standalone mode only)
PORT No 8080 Server port (standalone mode only)
AUTH_SECRET No - Authentication secret token (recommended for production)
UPSTREAM_TIMEOUT No 30000 Upstream request timeout in milliseconds
DISABLE_TLS_VERIFY No false Disable TLS verification in standalone Node mode only (development only, never use in production)

Example Configuration

# Copy example environment file
cp .env.example .env

# Edit .env with your configuration
# Generate a secure auth secret:
openssl rand -base64 32

Usage

Standalone Server

# Development mode (with auto-reload)
pnpm dev

# Production mode
pnpm build
pnpm start

The server will start on http://localhost:8080 (or your configured HOST:PORT).

Cloudflare Workers

  1. Configure wrangler.toml with your settings
  2. Set secrets:
    wrangler secret put AUTH_SECRET
  3. Deploy:
    pnpm worker:deploy

API Reference

Request Headers

X-Proxy-Upstream (Required)

The target URL to proxy the request to.

X-Proxy-Upstream: https://api.example.com/data

Requirements:

  • Must be a valid HTTP or HTTPS URL
  • Must not contain credentials (username/password)
  • Hostname must not resolve to private IP ranges (RFC 1918, loopback, link-local, etc.)

X-Proxy-Auth (Optional)

Authentication token for the proxy. Required if AUTH_SECRET is configured.

X-Proxy-Auth: your-secret-token

Security:

  • Must be sent over HTTPS (TLS)
  • Plain HTTP requests with this header will be rejected
  • Uses constant-time comparison to prevent timing attacks

X-Proxy-Follow-Redirects (Optional)

Enable automatic redirect following.

X-Proxy-Follow-Redirects: same-origin

Values:

  • same-origin - Follow redirects only within the same origin (scheme, host, port)
  • cross-origin - Follow redirects across origins (cookies are stripped for cross-origin redirects)
  • Empty or omitted - Don't follow redirects (default)

Behavior:

  • Maximum 5 redirects per request
  • 301/302 redirects change method to GET (except HEAD)
  • 307/308 redirects preserve the original method
  • Each redirect target is validated against the IP blacklist

Response Headers

X-Proxy-State (Always Present)

Indicates whether the response is from the upstream or the proxy itself.

Values:

  • FORWARDED - Response is from the upstream server
  • ERROR - Response was generated by the proxy (error condition)

Error Responses

All proxy-generated errors include X-Proxy-State: ERROR and a JSON body:

{
  "reason": "human-readable error message",
  "detail": "optional technical details"
}

Common Error Codes:

Status Reason Description
400 Bad Request Missing or invalid X-Proxy-Upstream, invalid redirect mode, etc.
401 Unauthorized Missing or invalid X-Proxy-Auth header
403 Forbidden Upstream resolves to a blacklisted IP address
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 Redirect chain exceeds 5 hops or upstream contains X-Proxy-State

Examples

Basic Proxy Request

curl -X GET http://localhost:8080/ \
  -H "X-Proxy-Upstream: https://api.github.com/users/octocat"

With Authentication

curl -X GET https://proxy.example.com/ \
  -H "X-Proxy-Upstream: https://api.example.com/data" \
  -H "X-Proxy-Auth: your-secret-token"

With Redirect Following

curl -X GET http://localhost:8080/ \
  -H "X-Proxy-Upstream: https://example.com/redirect-me" \
  -H "X-Proxy-Follow-Redirects: cross-origin"

POST Request with Body

curl -X POST http://localhost:8080/ \
  -H "X-Proxy-Upstream: https://api.example.com/data" \
  -H "Content-Type: application/json" \
  -d '{"key": "value"}'

Security Considerations

IP Blacklist

The proxy blocks access to the following IP ranges to prevent SSRF attacks:

IPv4:

  • 10.0.0.0/8 - Private network (RFC 1918)
  • 172.16.0.0/12 - Private network (RFC 1918)
  • 192.168.0.0/16 - Private network (RFC 1918)
  • 127.0.0.0/8 - Loopback
  • 169.254.0.0/16 - Link-local
  • 0.0.0.0/8 - Current network

IPv6:

  • fc00::/7 - Unique Local Addresses (RFC 4193)
  • fe80::/10 - Link-local (RFC 4291)
  • ::1/128 - Loopback (RFC 4291)

DNS Rebinding Protection

The proxy performs fresh DNS resolution for each request and validates the resolved IP address against the blacklist before establishing a connection. This prevents DNS rebinding attacks where a hostname initially resolves to a public IP but later changes to a private IP.

Authentication Best Practices

  1. Always use AUTH_SECRET in production
  2. Use HTTPS for the client-proxy connection when authentication is enabled
  3. Generate strong secrets: Use at least 128 bits of entropy
    openssl rand -base64 32
  4. Rotate secrets regularly
  5. Use additional network-layer protections (VPC, firewall rules, mTLS)

Deployment Recommendations

  • Never expose the proxy to the public internet without authentication
  • Use network segmentation (VPC, VLAN) to isolate the proxy
  • Apply firewall rules to restrict ingress
  • Monitor for unusual traffic patterns
  • Set appropriate UPSTREAM_TIMEOUT values to prevent resource exhaustion

Development

# Install dependencies
pnpm install

# Run in development mode with auto-reload
pnpm dev

# Build TypeScript
pnpm build

# Run tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Lint code
pnpm lint

# Format code
pnpm format

Testing

# Run all tests
pnpm test

# Run tests in watch mode
pnpm test -- --watch

# Generate coverage report
pnpm test:coverage

Cloudflare Workers Deployment

Prerequisites

  • Cloudflare account
  • Wrangler CLI installed (pnpm install -g wrangler)

Configuration

  1. Update wrangler.toml:

    name = "proxy-server"
    main = "src/worker.ts"
    compatibility_flags = ["nodejs_compat"]
    compatibility_date = "2026-05-16"
    
    [vars]
    UPSTREAM_TIMEOUT = "30000"
  2. Set secrets:

    wrangler secret put AUTH_SECRET

Deploy

# Deploy to production
pnpm worker:deploy

# Test locally
pnpm worker:dev

Limitations

Known Limitations

  1. Request Body Replay: For 307/308 redirects that preserve the HTTP method, the request body cannot be replayed. The redirect request will have an empty body.

  2. WebSocket Not Supported: The proxy does not support protocol upgrades (WebSocket, HTTP/2 upgrade, etc.). Requests with the Upgrade header are rejected with 501 Not Implemented.

  3. HTTP/3 Not Supported: The proxy does not support HTTP/3 (QUIC).

Cloudflare Workers Specific

  • DNS resolution uses Cloudflare's DNS over HTTPS (1.1.1.1)
  • DISABLE_TLS_VERIFY does not apply on Cloudflare Workers
  • Maximum request/response size limits apply per Cloudflare Workers limits

License

MIT License - see LICENSE file for details.

About

Crystade Proxy Server implementation in Node.js

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors