Sign inSign up

hightemp/https_proxy

By hightemp

Updated 20 days ago

A secure HTTP/HTTPS proxy server in Go with Basic authentication, TLS support.

Image
Networking
0

983

hightemp/https_proxy repository overview

Secure HTTP Proxy Server

GitHub Repo Go Version License: MIT GitHub release GitHub Downloads Docker Pulls GitHub Workflow Status Tests

A secure HTTP/HTTPS proxy server in Go with Basic authentication, TLS support, and upstream proxy chaining.

Features

  • HTTP and HTTPS proxy modes
  • HTTP/2 CONNECT multiplexing in HTTPS mode with HTTP/1.1 fallback
  • Optional privacy mode for stripping client-IP and proxy-chain headers
  • Basic authentication
  • TLS with configurable certificates
  • Upstream proxy chaining (proxy chain support)
    • Supports HTTP and HTTPS upstream proxies
    • Configurable via config.yaml or environment variables (HTTPS_PROXY, HTTP_PROXY)
    • Basic authentication to upstream proxy
  • Selectable outbound network (auto, IPv4-only, or IPv6-only)
  • Bounded dial, TLS handshake, and response-header timeouts
  • Configurable via YAML file
  • Systemd service support
  • Graceful shutdown of HTTP requests and HTTP/1.1 or HTTP/2 CONNECT tunnels

Installation

From release

Download the latest binary from the Releases page.

Docker

https://hub.docker.com/r/hightemp/https_proxy

One-liner (HTTP proxy on port 8080, no authentication):

docker run -d --name https_proxy -p 8080:8080 hightemp/https_proxy:latest

Enable Basic auth via env vars:

docker run -d --name https_proxy -p 8080:8080 \
  -e PROXY_USERNAME=alice -e PROXY_PASSWORD=s3cret \
  hightemp/https_proxy:latest

If both username and password are empty, authentication is disabled.

With a custom config:

docker run -d --name https_proxy -p 8080:8080 -v $(pwd)/config.yaml:/etc/https_proxy/config.yaml:ro hightemp/https_proxy:latest
Environment variables

Any of these override the corresponding YAML field:

VariableOverrides
PROXY_ADDRproxy_addr
PROXY_USERNAMEusername
PROXY_PASSWORDpassword
PROXY_PROTOproto (http / https)
PROXY_CERT_PATHcert_path
PROXY_KEY_PATHkey_path
PROXY_UPSTREAM_PROXYupstream_proxy (URL or direct)
PROXY_NETWORKnetwork (auto / tcp4 / tcp6)
PROXY_LOG_SENSITIVE_DATAlog_sensitive_data (true exposes full request URLs, upstream errors, and rejected credentials in logs)
PROXY_PRIVACY_MODEprivacy_mode (best-effort HTTP header privacy)
PROXY_MAX_CONNECTIONSmax_connections
PROXY_MAX_CONNECTIONS_PER_IPmax_connections_per_ip
PROXY_MAX_TUNNELSmax_tunnels
PROXY_MAX_TUNNELS_PER_IPmax_tunnels_per_ip
PROXY_HTTP2_MAX_CONCURRENT_STREAMShttp2_max_concurrent_streams (0 derives the limit from tunnel limits)
PROXY_MAX_IDLE_CONNSmax_idle_conns
PROXY_MAX_IDLE_CONNS_PER_HOSTmax_idle_conns_per_host
PROXY_MAX_HEADER_BYTESmax_header_bytes
PROXY_AUTH_MAX_FAILURESauth_max_failures
PROXY_ALLOW_PRIVATE_DESTINATIONSallow_private_destinations
PROXY_BLOCKED_DESTINATION_PORTSblocked_destination_ports (comma-separated ports or none)
PROXY_DIAL_TIMEOUTdial_timeout
PROXY_TLS_HANDSHAKE_TIMEOUTtls_handshake_timeout
PROXY_TLS_RELOAD_INTERVALtls_reload_interval
PROXY_RESPONSE_HEADER_TIMEOUTresponse_header_timeout
PROXY_IDLE_CONN_TIMEOUTidle_conn_timeout
PROXY_READ_HEADER_TIMEOUTread_header_timeout
PROXY_IDLE_TIMEOUTidle_timeout
PROXY_TUNNEL_IDLE_TIMEOUTtunnel_idle_timeout
PROXY_HTTP2_SEND_PING_TIMEOUThttp2_send_ping_timeout
PROXY_HTTP2_PING_TIMEOUThttp2_ping_timeout
PROXY_HTTP2_WRITE_BYTE_TIMEOUThttp2_write_byte_timeout
PROXY_AUTH_FAILURE_WINDOWauth_failure_window
PROXY_AUTH_BLOCK_DURATIONauth_block_duration
PROXY_SHUTDOWN_TIMEOUTshutdown_timeout
Docker Compose (HTTP + HTTPS with Let's Encrypt)

The bundled docker-compose.yml starts an HTTP proxy, an HTTPS proxy, and a certbot sidecar that issues and auto-renews Let's Encrypt certificates into a shared volume. All settings come from a .env file — no YAML editing required.

  1. Copy the env template and fill it in:

    cp .env.example .env
    # edit DOMAIN, EMAIL, PROXY_USERNAME, PROXY_PASSWORD
    
  2. Issue the initial Let's Encrypt certificate (port 80 must be reachable on $DOMAIN):

    docker compose run --rm --service-ports certbot issue
    
  3. Start the stack:

    docker compose up -d
    

Certbot checks for renewals every 12 hours. On new TLS handshakes, the HTTPS proxy checks the mounted certificate files at most once per PROXY_TLS_RELOAD_INTERVAL (one minute by default). A valid replacement is loaded without restarting the container or interrupting existing connections. If Certbot is temporarily updating the certificate/key pair or the new files are invalid, the proxy keeps the last valid certificate and retries later.

HTTPS mode advertises HTTP/2 and HTTP/1.1 through ALPN. Browsers that support an HTTP/2 secure web proxy multiplex CONNECT tunnels as independent streams on one TLS connection; other clients continue to use the HTTP/1.1 CONNECT path.

Build from source
  1. Clone the repository:

    git clone https://github.com/hightemp/https_proxy
    cd https_proxy
    
  2. Build the project:

    make build
    
Project structure
cmd/https_proxy/  application entry point
internal/config/  configuration loading and validation
internal/auth/    proxy authentication
internal/proxy/   HTTP forwarding, upstream chaining, and server lifecycle
internal/tunnel/  HTTP/1.1 and HTTP/2 CONNECT tracking and bidirectional relay

Configuration

Create a config.yaml file (see config.example.yaml):

proxy_addr: 127.0.0.1:8080
username: "your_username"
password: "your_password"
proto: http
cert_path: ""
key_path: ""
network: auto
log_sensitive_data: false
privacy_mode: false
max_connections: 1024
max_connections_per_ip: 128
max_tunnels: 256
max_tunnels_per_ip: 128
http2_max_concurrent_streams: 0
max_idle_conns: 100
max_idle_conns_per_host: 10
max_header_bytes: 65536
auth_max_failures: 10
allow_private_destinations: false
blocked_destination_ports: [21, 22, 23, 25, 110, 111, 135, 137, 138, 139, 445, 1433, 2049, 2375, 2376, 3306, 3389, 5432, 5900, 6379, 9200, 11211, 27017]
dial_timeout: 10s
tls_handshake_timeout: 10s
tls_reload_interval: 1m
response_header_timeout: 30s
idle_conn_timeout: 90s
read_header_timeout: 15s
idle_timeout: 2m
tunnel_idle_timeout: 10m
http2_send_ping_timeout: 1m
http2_ping_timeout: 15s
http2_write_byte_timeout: 30s
auth_failure_window: 1m
auth_block_duration: 5m
shutdown_timeout: 15s
# upstream_proxy: http://user:pass@upstream-proxy:8080
# upstream_proxy: direct

The example listens on localhost. Set proxy_addr to 0.0.0.0:8080 only when the proxy must accept remote connections, and configure authentication before exposing it.

ParameterDescription
proxy_addrListen address and port
usernameBasic auth username
passwordBasic auth password
protohttp or https
cert_pathPath to TLS certificate (for https mode)
key_pathPath to TLS private key (for https mode)
upstream_proxyUpstream proxy URL, direct, or empty to use proxy environment variables
networkOutbound address family: auto, tcp4, or tcp6
log_sensitive_dataLog full request URLs, upstream errors, and rejected Basic Auth username/password; disabled by default
privacy_modeStrip client-IP/forwarding headers and suppress Via for proxy-visible HTTP metadata
max_connectionsMaximum simultaneous client TCP connections
max_connections_per_ipMaximum simultaneous client connections per source IP
max_tunnelsMaximum simultaneous CONNECT tunnels
max_tunnels_per_ipMaximum simultaneous CONNECT tunnels per source IP
http2_max_concurrent_streamsMaximum streams advertised per HTTP/2 connection; 0 uses the lower of max_tunnels and max_tunnels_per_ip
max_idle_connsMaximum idle outbound HTTP connections across all destinations
max_idle_conns_per_hostMaximum idle outbound HTTP connections retained per destination
max_header_bytesMaximum size of incoming HTTP request headers
auth_max_failuresFailed authentication attempts per IP before temporary blocking
allow_private_destinationsAllow loopback, private, link-local, and other non-public destinations
blocked_destination_portsPorts denied by destination policy; use [] to clear the YAML list
dial_timeoutTCP connection timeout
tls_handshake_timeoutOutbound TLS handshake timeout
tls_reload_intervalHow often new TLS handshakes check certificate files for a valid replacement
response_header_timeoutUpstream CONNECT/HTTP response-header timeout
idle_conn_timeoutHow long an idle outbound HTTP connection remains pooled
read_header_timeoutIncoming request-header timeout
idle_timeoutIncoming keep-alive idle timeout
tunnel_idle_timeoutClose a CONNECT tunnel after no traffic in either direction
http2_send_ping_timeoutSend an HTTP/2 PING after no frame is received for this duration; 0s disables health checks
http2_ping_timeoutClose an HTTP/2 connection when a PING response is not received; 0s uses Go's default
http2_write_byte_timeoutClose an HTTP/2 connection when no response bytes can be written for this duration; 0s disables the timeout
auth_failure_windowWindow in which failed authentication attempts are counted
auth_block_durationHow long an IP is blocked after exceeding auth_max_failures
shutdown_timeoutGraceful shutdown deadline

Timeout values use Go duration syntax, for example 500ms, 10s, or 2m. Unknown YAML keys and invalid values stop the proxy at startup instead of being silently ignored.

By default, request URL userinfo and query parameters are removed from logs, upstream errors are reduced to their HTTP category, and rejected Basic Auth credentials are not logged. For temporary diagnostics, set log_sensitive_data: true or PROXY_LOG_SENSITIVE_DATA=true. This can expose passwords and tokens in plaintext logs; disable it immediately after debugging.

Privacy mode

Set privacy_mode: true or PROXY_PRIVACY_MODE=true to remove known client-address forwarding metadata from ordinary HTTP requests and trailers, including RFC Forwarded, Via, X-Forwarded-*, X-Real-IP, True-Client-IP, CDN connecting-IP headers, and common vendor equivalents. The proxy also omits its own Via header and does not forward a Via chain to an upstream proxy.

This is best-effort header privacy, not full anonymity. HTTPS/WSS traffic inside CONNECT is encrypted end-to-end, so the proxy cannot remove cookies, authorization headers, browser fingerprints, or application identifiers without acting as a TLS interception proxy. Browser traffic outside HTTP/HTTPS/WS/WSS, including WebRTC or other UDP paths, can bypass a web proxy. Sites can also classify the server's public IP as hosting, VPN, or proxy infrastructure.

Resource limits and destination policy

Connection and CONNECT limits are enforced globally and per source IP. Excess TCP connections are closed immediately; excess tunnels and rate-limited authentication attempts receive 429 Too Many Requests. A tunnel is closed when no bytes flow in either direction for tunnel_idle_timeout. Unless explicitly overridden, the HTTP/2 SETTINGS stream limit is derived from the lower tunnel limit so clients do not open streams that the proxy would immediately reject.

The default destination policy rejects loopback, private, link-local, metadata, carrier-grade NAT, and other reserved addresses. It also blocks common administration, mail, database, and cache ports. To intentionally proxy internal services, set allow_private_destinations: true. To clear only the blocked port list, use blocked_destination_ports: [] in YAML or PROXY_BLOCKED_DESTINATION_PORTS=none.

Outbound network

network: auto uses Go's normal dual-stack dialing. If the server advertises IPv6 but its IPv6 route is broken, use IPv4-only dialing so affected requests fail over immediately:

network: tcp4

The setting applies to direct CONNECT targets, ordinary forwarded HTTP requests, and the connection to an upstream proxy. When chaining through an upstream proxy, that upstream still resolves and connects to the final target itself.

Upstream Proxy (Proxy Chain)

To route all traffic through an upstream proxy, set upstream_proxy in config.yaml:

upstream_proxy: http://user:pass@upstream-proxy:8080

HTTPS upstream proxies are also supported:

upstream_proxy: https://user:pass@upstream-proxy:8443

If upstream_proxy is not set in the config, the proxy falls back to standard environment variables (HTTPS_PROXY, HTTP_PROXY, NO_PROXY).

To force direct connections and ignore those environment variables, use the explicit direct mode:

upstream_proxy: direct

An explicitly configured upstream URL is validated at startup and never silently falls back to a direct connection. Percent-encode reserved characters in credentials, for example user%40example for user@example and p%3Ass for p:ss.

TLS Certificates

Generate self-signed certificates:

bash generate_certs.sh

The generated certificate includes Subject Alternative Names for localhost, 127.0.0.1, and ::1, which are required by modern TLS clients. Trust cert.pem locally before using it; the certificate is self-signed.

Or use Let's Encrypt:

sudo certbot certonly --standalone -d example.com
cert_path: "/etc/letsencrypt/live/example.com/fullchain.pem"
key_path: "/etc/letsencrypt/live/example.com/privkey.pem"

Usage

./https_proxy -config config.yaml
Systemd Service
sudo make install

The installer creates a locked system account named https_proxy; the service does not run as root. The configuration remains owned by root, is readable by the https_proxy group, and is not writable by the service. The unit also isolates devices and home directories, denies Linux capabilities, and prevents namespace creation.

TLS files used by the system service must be readable by the https_proxy group. A protected directory is created automatically; install certificates without making the private key world-readable:

sudo install -o root -g https_proxy -m 0640 cert.pem /etc/https_proxy/certs/cert.pem
sudo install -o root -g https_proxy -m 0640 key.pem /etc/https_proxy/certs/key.pem

Then use these paths in /etc/https_proxy/config.yaml:

cert_path: /etc/https_proxy/certs/cert.pem
key_path: /etc/https_proxy/certs/key.pem

If Certbot manages the source certificate, deploy a copy with these ownership and mode settings from a renewal hook. The proxy detects the replacement automatically; no service restart is required. Direct paths under /home are intentionally inaccessible to the hardened unit.

Manage the service:

make start / stop / restart / status

Makefile Commands

CommandDescription
make buildBuild the binary
make build-staticBuild a static binary (linux/amd64)
make runRun the proxy
make installInstall binary, config and systemd service
make uninstallRemove binary and service (keep config)
make uninstall-fullRemove everything including config
make releaseTag version from VERSION file and push
make docker-buildBuild Docker image hightemp/https_proxy:VERSION and :latest
make docker-pushBuild and push image to Docker Hub
make docker-releaseAlias for docker-push

Testing

Run the complete test suite with the race detector:

go test -race ./...

Generate a local coverage summary:

go test -covermode=atomic -coverprofile=coverage.out ./...
go tool cover -func=coverage.out

The test workflow runs for pushes and pull requests and enforces at least 85% total statement coverage.

Release

  1. Update the version in the VERSION file.

  2. Run:

    make release
    

    This will commit, create a git tag vX.Y.Z, and push it. GitHub Actions will automatically build binaries and create a release.

License

This project is licensed under the MIT License.

Tag summary

Content type

Image

Digest

sha256:5f37e9a40

Size

6.9 MB

Last updated

20 days ago

docker pull hightemp/https_proxy