Files
Agent 85e8324e80 Initial commit: add Proxy Bridge and documentation
Authored by GPT 6.1 Sol (Codex)

Agent-Changeset: 4e096c95e0aaf6618de717fe53786ee2
2026-10-27 21:06:55 +00:00

7.2 KiB
Raw Permalink Blame History

Setup and deployment

Back to README

Requirements:

  • An upstream host with working SOCKS5 proxies. This program connects to existing proxies; it does not create them.
  • TCP connectivity from the Go client to the Go server, directly or through a TCP tunnel. Both programs can run on the same host.
  • Go 1.27.1 or later on the build machine. Go is not required on a machine that only runs a compiled binary. The build downloads the pinned dependencies in go.mod/go.sum.
  • openssl for the token-generation command below and curl for the usage test.

Build

Run the following from the project root:

mkdir -p bin
go build -trimpath -o bin/proxy-server ./server
go build -trimpath -o bin/proxy-client ./client
cp server/config.example.json server/config.json
cp client/config.example.json client/config.json

Configure

Edit the JSON files before starting. Generate a bridge token with openssl rand -hex 32 and put the same value in both files. Set a separate application password in the client config. Replace all example secrets and restrict the real config files to their service users (chmod 600). Real config files are gitignored. Copy only the relevant binary and config to each host; pass an absolute -config path if launching from a different working directory. The binary must match the target operating system and CPU architecture. Build on each target or cross-compile; for example, prefix the appropriate build command with GOOS=linux GOARCH=amd64 for a Linux x86-64 target.

On the upstream host, replace the proxies field in server/config.json with the required named upstreams. This fragment belongs inside the full example JSON object:

"proxies": {
  "proxy-1": {
    "address": "127.0.0.1:1080",
    "username": "upstream-user",
    "password": "upstream-password",
    "max_connections": 256
  },
  "proxy-2": { "address": "127.0.0.1:1081" }
}

Upstream authentication is optional. An omitted/zero upstream connection limit defaults to 256. IDs are exact, case-sensitive SOCKS usernames (1–255 bytes). Restart the Go server to change its proxy map; existing connections are interrupted.

The bridge uses these credentials:

Credential Where it belongs Purpose
bridge_token Both Go configs, with the same value Authenticates persistent bridge sessions
Application password Go client config and calling applications Allows applications to select proxy IDs

Any upstream SOCKS username/password goes only in that proxy's Go server config. Use different values for the different tokens/passwords.

Connect the client and server

Set bridge_address in the client config to an address that reaches the Go server's listen endpoint. The connection can be direct or forwarded by a TCP tunnel. The example client uses 127.0.0.1:18080 as a tunnel endpoint; change it for a direct connection.

Same host

Keep the server's default listen of 127.0.0.1:18081 and set the client's bridge_address to 127.0.0.1:18081. The application-facing SOCKS listener stays at 127.0.0.1:8080. No tunnel is required.

Separate hosts

For a direct connection, bind the server to a reachable interface and set the client's bridge_address to that host and port. Restrict access to the intended client. The bridge protocol uses plain TCP: bridge_token authenticates sessions but does not encrypt traffic. Use an encrypted private network or TCP tunnel when crossing untrusted networks.

For a forwarded connection, point bridge_address at the tunnel's local endpoint and forward it to the Go server. The rathole example below illustrates one option.

Start the programs

Start the Go server on the upstream host:

./bin/proxy-server -config server/config.json

If using a tunnel, start it before starting the Go client. Start the Go client on the gateway host:

./bin/proxy-client -config client/config.json

Wait for bridge session ready messages before sending traffic. These confirm that the client reached the Go server and authenticated.

These commands run in the foreground. For unattended operation, supervise each binary with an existing process manager, using an absolute config path and restart-on-failure. Supervise any tunnel processes too. SIGINT/SIGTERM stops the Go programs and interrupts active connections; there is no drain/reload command.

Send a request

From the gateway host, using the application password from its client config:

curl --noproxy '' --proxy 'socks5h://proxy-1:[email protected]:8080' https://example.com
curl --noproxy '' --proxy 'socks5h://proxy-2:[email protected]:8080' https://example.com

proxy-1 selects the upstream; the password authenticates the application to the Go client. URL-encode credentials containing URL-special characters. socks5h passes destination hostnames through to the upstream proxy for resolution. Unknown IDs fail and never fall back to another proxy. The shared application password grants access to all configured proxy IDs; this is not per-user access control.

Optional: rathole tunnel

For a reverse tunnel with rathole, install rathole on both hosts. Its server runs on the gateway host and its client runs on the upstream host. These roles are separate from the Go binary names.

Use server/rathole-client.example.toml on the upstream host and client/rathole-server.example.toml on the gateway host, or merge their service sections into an existing encrypted rathole configuration. The service names and service tokens must match.

Use a separate, matching rathole service token in both rathole configs.

The example uses Noise encryption. Run rathole --genkey to generate the gateway host's keypair: the private key belongs on the gateway host and the public key on the upstream host. TLS is also suitable. The bridge's token authentication does not encrypt its traffic: keep both Go listeners and the forwarded rathole service on loopback, and use an encrypted rathole transport for the internet link. Keep rathole's default TCP_NODELAY enabled.

The bundled rathole examples use these ports:

Location Address Purpose
Gateway host 127.0.0.1:8080 The single SOCKS port used by every application
Gateway host 127.0.0.1:18080 Private rathole service, dialed by the Go client
Upstream host 127.0.0.1:18081 Go server, dialed by the local rathole client
Gateway host 0.0.0.0:2333 Internet-facing rathole tunnel listener

Reuse an existing tunnel

An existing encrypted rathole tunnel can carry the bridge. Add a dedicated TCP service, or adapt an existing service with matching names and tokens on both hosts. Set its client-side local_addr to the Go server's listen, and set the Go client's bridge_address to its server-side bind_addr.

Keep the forwarded service on loopback and choose a port distinct from the Go client's application-facing listen. Ports on different hosts are independent. Edit existing service sections rather than creating duplicates, then restart or reload rathole to apply the configuration.