socat: Forward Ports and Bridge Connections in CI
socat connects two byte streams, so it can forward a local port to a remote service or expose a UNIX socket over TCP for a test.
socat is netcat with two addresses. In CI it bridges a service the test cannot reach directly, for example forwarding localhost to a container or a UNIX socket to a TCP port.
What it does
socat opens two address specifications and copies data between them in both directions. Each address can be a TCP listener, a TCP connection, a UNIX socket, a file, or a process, so it stitches together endpoints that would not otherwise talk.
Common usage
# forward local 5432 to a remote db (e.g. through a bastion-reachable host)
socat TCP-LISTEN:5432,reuseaddr,fork TCP:db.internal:5432
# expose a docker UNIX socket on a TCP port for a client
socat TCP-LISTEN:2375,reuseaddr,fork UNIX-CONNECT:/var/run/docker.sockOptions
| Address / option | What it does |
|---|---|
| TCP-LISTEN:<port> | Listen for inbound TCP connections on a port |
| fork | Handle each accepted connection in a child process |
| reuseaddr | Allow rebinding the port immediately (SO_REUSEADDR) |
| TCP:<host>:<port> | Connect outbound to a remote TCP endpoint |
| UNIX-CONNECT:<path> | Connect to a UNIX domain socket |
In CI
Always add fork to TCP-LISTEN or socat serves exactly one connection and exits, which makes a forwarder that mysteriously dies after the first request. Run it in the background (append &) and nc -z the listen port before launching the client that depends on it.
Common errors in CI
"socat ... bind: Address already in use" means the listen port is taken; add reuseaddr or pick another port. "Connection refused" on the TCP: side means the upstream is not up yet. "Permission denied" on UNIX-CONNECT to docker.sock means the runner user is not in the docker group.