7.2 KiB
Setup and deployment
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. opensslfor the token-generation command below andcurlfor 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.