Tunneling
This page covers the transports used to carry the agent’s outbound SSH data connection. That connection carries shells, file transfers, proxies, forwards, and other operator data. If an SSH transport fails, the agent automatically falls back to the next configured method.
The agent also maintains a separate Socket.IO control connection for registration, heartbeats, metadata, and control instructions. Socket.IO uses HTTP long polling, WebSocket over HTTP(S), or WebSocket encapsulated over DNS; it is not carried directly by the SSH, TLS, or QUIC data transports. See Connection flow for the complete two-path model.
Choose a transport
Use the simplest transport that the target network permits:
| Network condition | Recommended configuration |
|---|---|
| Direct outbound TCP | Direct SSH |
| TLS allowed, SSH blocked | SSH over TLS |
| HTTP(S) egress only | SSH over WebSocket or HTTP |
| DNS is the only permitted egress | SSH over DNS |
| QUIC is available and desired | SSH over QUIC |
Set the SSH data transport order with --rssh-order. The agent tries each configured transport in order and continues with the next one after a failure. The agent also derives compatible Socket.IO connection attempts from this order, but the control connection remains a separate protocol and connection.
Supported transports
The agent can connect using these transports (in default order):
- Direct SSH connection
- SSH over TLS
- SSH over WebSocket
- SSH over HTTP
- SSH over DNS
- SSH over QUIC (optional, requires
--rssh-orderconfiguration)
Default behavior
For each SSH data transport and compatible Socket.IO control strategy, the agent attempts connection with a 60-second timeout (configurable with --timeout). After exhausting the configured order, the agent retries indefinitely by default during the kill-switch duration (7 days by default), after which the agent kills itself. Each retry cycle starts from the beginning.
Connection timeouts
--timeout (default: 60 seconds) is the single timeout governing every connection the agent makes to the server. It bounds:
- each SSH tunnel attempt, per data transport;
- each Socket.IO control connection strategy attempted;
- the configuration exchange that follows registration;
- the keepalive liveness check: if the server does not answer a keepalive ping within this period, the control connection is considered dead and the agent restarts (see Connection flow).
Without these bounds the agent could stay blocked indefinitely against a server that accepts a connection but never replies. Reaching any of them makes the agent give up and restart, so it retries from the beginning of the transport order rather than hanging.
Slow transports need a higher value. Over DNS in particular, a single round trip is many queries and responses, and the default 60 seconds can be too short, both for the configuration exchange and for keepalive replies. Raise --timeout when using DNS, otherwise a healthy but slow agent may restart repeatedly.
--timeout 0 means unlimited and disables all of the bounds above, including the liveness checks. The agent will then wait forever on an unresponsive server instead of restarting.
This flag was previously named --ssh-timeout, since it only bounded SSH tunnel attempts. --ssh-timeout still works on the command line as an alias, but the configuration file key has changed from ssh-timeout to timeout. A configuration file still using ssh-timeout is ignored silently and the agent falls back to the 60-second default, which matters most on DNS, where a tuned value is usually required. Rename the key when upgrading:
# before
ssh-timeout: 120
# after
timeout: 120
Configure transport selection
SSH data transport order and retry behavior can be customized:
--rssh-order(short-O): Customize the order in which the agent tries SSH data transports. The agent attempts each transport sequentially until one succeeds. Example:--rssh-order=ssh,tls,ws,http,dnstries SSH first, then TLS, then WebSocket, and so on. For an HTTP(S)-only deployment, use-O WSor--rssh-order WS; addDNSas a fallback when DNS egress is also available. The agent maps these choices to compatible Socket.IO control strategies: HTTP polling, WebSocket over HTTP(S), or WebSocket over DNS.--max-retries: Limit retry attempts (example:--max-retries 5stops after 5 failed cycles; default is unlimited). Independently of this flag, the retry loop is also bounded by the kill-switch duration (see Killswitch); use--kill-switch 0to disable that time bound for a truly indefinite retry loop.
--rssh-order also accepts these special values:
browser: Use a browser-based tunnel (see Browser proxy)bind: Bind to a local socket (see Agent binding)relay: Route traffic through a relay agent, whose address is given by--server(see Relay)
Direct SSH connection
Use this when the target can reach the server’s SSH listener directly.
Flags
--ssh-server: ([IP/Hostname]:[PORT])--rssh-port: the remote port the SSH tunnel binds to on the server side (default:0, meaning a random port is chosen).
SSH over TLS
The SSH connection is encapsulated over a TLS connection.
TLS is used for proxy compatibility, not encryption: some proxies may allow TLS while blocking SSH.
Flags
--tls-server: ([IP/Hostname]:[PORT]) address of the TLS listener on the server.
The target SSH service itself is still the one configured via the --ssh-server flag; --tls-server only configures the TLS transport used to reach it.
SSH over WebSocket
The SSH connection is encapsulated over a WebSocket connection.
This makes it easier to bypass restrictive proxies while maintaining acceptable performance.
Flags
--server: the WebSocket endpoint is[server]/wssh/
SSH over HTTP
The SSH connection is encapsulated over HTTP requests/responses.
This transport is considerably slower than the previous ones, but allows traffic to pass through proxies that block WebSockets for instance.
Flags
--server: the HTTP endpoint is[server]/sshttp/
SSH over DNS
This transport encapsulates SSH traffic inside DNS queries and responses, allowing communication in highly restricted environments where only DNS traffic is permitted.
This transport is considerably slower than the previous ones, but allows traffic to pass through proxies that block WebSockets.
Flags
--dns-server: DNS resolvers used to reach the Goauld DNS server. Optionally includes the Goauld server itself if directly reachable.- The special value
systemautomatically adds detected system DNS servers to the list.
- The special value
--dns-domain: the domain on which DNS queries are performed
Shorter domain names allow more payload data per query, improving throughput.
--custom-dns-command: in some cases, the DNS queries are not feasible directly, but system commands such asResolve-DnsNameare still allowed to perform DNS queries. When this flag is used, the provided command is executed for each DNS query. The command is responsible for performing the DNS query, and parsing the DNS response and returning the response as raw bytes.
((Resolve-DnsName -Type TXT -Server 127.0.0.1 '%s')[0].Strings -join '' -replace '\s+', '' -split '..' | ForEach-Object { [Convert]::ToByte($_,16) } )
dig +short +unknownformat -t TXT '%s' @127.0.0.1 | head -n1 | cut -d ' ' -f3- | tr -d ' ' | xxd -r -p
SSH over QUIC
The SSH connection is encapsulated over QUIC. This transport is opt-in and not part of the default --rssh-order (see the note above); add quic to --rssh-order to enable it.
Flags
--quic-domain: the QUIC domain used to tunnel traffic.
Browser proxy
The agent can use a web browser to tunnel all the traffic.
- The agent exposes a simple web page with custom JavaScript. The JavaScript opens 4 WebSocket connections
- Two connecting to the server (Control & data)
- Two connecting to the agent (Control & data)
- The agent exposes a custom endpoint to allow the browser to initiate the connection to the agent
- The web page pipes the WebSocket connections
Flags
--browser-proxy-port: the port used to expose the custom web pages and the WebSocket endpoints used by the browser to connect to the agent.
Egress proxies
If required, the agent will try to reach the server using the proxy configuration identified on the system (see https://github.com/aus/proxyplease?tab=readme-ov-file#proxy-selection).
Flags
--proxy: use a custom proxy instead of the system proxy--proxy-username: Username to authenticate on the proxy--proxy-password: Password to authenticate on the proxy--proxy-domain: Domain to authenticate on the proxy--no-proxy: Ignore the system proxy
The proxy will be selected by the following priority:
Windows
--proxy [PROXY_URL](or any other means allowing configuration of theproxyflag; see Compilation)- Environment Variable:
HTTPS_PROXY,HTTP_PROXY,FTP_PROXY, orALL_PROXY.NO_PROXYis respected. - Internet Options: Automatically detect settings (
WPAD) - Internet Options: Use automatic configuration script (
PAC) - Internet Options: Manual proxy server
- WINHTTP: (
netsh winhttp)
Linux
--proxy [PROXY_URL](or any other means allowing configuration of theproxyflag; see Compilation)- Environment Variable:
HTTPS_PROXY,HTTP_PROXY,FTP_PROXY, orALL_PROXY.NO_PROXYis respected.
macOS
--proxy [PROXY_URL](or any other means allowing configuration of theproxyflag; see Compilation)- Environment Variable:
HTTPS_PROXY,HTTP_PROXY,FTP_PROXY, orALL_PROXY.NO_PROXYis respected. - Network Settings:
scutil
Agent binding
The client connects directly to the port exposed by the agent (see Agent binding).
Flags
--rssh-order=bind--bind-port
--bind-port is an alias of --browser-proxy-port (see Browser proxy above): both flags configure the same underlying port.