When the firewall blocks you but work must go on
Over two years ago, I ran into a frustrating situation: an internal server in our datacenter was running a service on port 5432 (PostgreSQL), but the firewall only allowed traffic through port 443. The dev team needed remote access but didn’t want to touch the firewall config — because touching it meant opening a ticket, waiting for approval, and losing an entire day.
The solution I reached for that day was socat. One command, done in 30 seconds. Ever since, I’ve kept this tool handy whenever I need to “bridge” two network endpoints without configuring anything complicated.
socat (short for SOcket CAT) is a command-line tool that creates bidirectional connections between any two addresses. Those endpoints can be TCP ports, UDP ports, Unix sockets, files, or even stdin/stdout. If netcat is a pocket knife, socat is a Swiss Army knife with a screwdriver and bottle opener thrown in.
How socat works
Just remember one pattern:
socat [options] <address1> <address2>
Declare two “addresses” and socat handles the rest — establishing the connection and shuttling data back and forth between the two ends. It supports a wide range of address types:
TCP:host:port— connect via TCP to host:portTCP-LISTEN:port— listen for TCP connections on a portUDP:host:port/UDP-LISTEN:port— same but for UDPSSL:host:port— SSL/TLS connectionUNIX-CONNECT:/path/to/socket— Unix domain socketEXEC:/path/to/program— run a program and pipe its stdioSTDIN/STDOUT/FILE:/path— files and stdio
Quick install before we get started:
# Debian/Ubuntu
sudo apt install socat
# RHEL/CentOS/Rocky
sudo dnf install socat
Hands-on: The most common use cases
1. Simple port forwarding
This is the use case I reach for most often. For example, forward all connections on port 8080 to port 80 on the same machine:
socat TCP-LISTEN:8080,fork TCP:localhost:80
The fork option is critical — without it, socat handles exactly one connection and exits. With fork, each new connection spawns its own child process.
A more realistic scenario: forward a port from your local machine to an internal server that isn’t exposed externally:
# On the jump server (with a public IP), forward port 5432 to an internal DB server
socat TCP-LISTEN:5432,fork,reuseaddr TCP:192.168.1.50:5432
The reuseaddr option lets socat rebind the port immediately after a restart, so you don’t have to wait out the TCP TIME_WAIT timeout (typically 60–120 seconds). For scenarios where you need more visibility into what’s traversing these connections, tcpdump and Wireshark are excellent companions.
2. Building a relay — forwarding across multiple hops
I have offices in Hanoi and Osaka. Some internal services in Hanoi need to be accessible from Osaka, but direct routing is blocked by the firewall. The solution is a VPS in the middle acting as a relay:
# On the intermediary VPS (e.g., Singapore)
# Listen on port 9000, forward to Hanoi server port 22
socat TCP-LISTEN:9000,fork,reuseaddr TCP:hanoi-server.internal:22
From Osaka, SSHing into the Singapore VPS on port 9000 is effectively SSHing into Hanoi:
ssh -p 9000 [email protected]
This type of relay adds no extra encryption — traffic between the VPS and the Hanoi server is still plain TCP. If the application layer is already encrypted (SSH, HTTPS), there’s nothing to worry about. For more structured tunneling over SSH, local, remote, and dynamic port forwarding via SSH is worth exploring.
3. UDP relay — something netcat can’t do easily
UDP relaying is more complex than TCP because there’s no connection state. socat handles it cleanly with its own syntax:
# Forward UDP port 514 (syslog) to a centralized log server
socat UDP-RECVFROM:514,fork UDP-SENDTO:logserver.internal:514
Use UDP-RECVFROM instead of UDP-LISTEN so multiple clients can send at the same time without contending with each other.
4. SSL tunnel — underrated and more useful than you’d think
Got a plain TCP service you want to expose over an encrypted connection, but don’t want to set up nginx or stunnel? socat can do it — you just need a certificate.
Generate a self-signed cert (or use an existing one):
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt
cat server.crt server.key > server.pem
On the server — wrap the plain TCP service with SSL:
# Listen for SSL on port 8443, forward to plain TCP port 8080 on localhost
socat SSL-LISTEN:8443,cert=server.pem,verify=0,fork TCP:localhost:8080
On the client — connect to the SSL endpoint and expose it on a local port:
# Connect to the SSL server, expose locally on port 8080
socat TCP-LISTEN:8080,fork SSL:yourserver.com:8443,verify=0
The verify=0 option skips certificate verification — fine for internal environments. In production, use a valid certificate and drop this option.
5. Quick debugging — simulating a TCP server
When I need to check whether a client can connect, or want to see what it’s actually sending, I use:
# Listen on port 8080, print everything the client sends to the terminal
socat -v TCP-LISTEN:8080,fork -
The -v option prints both the data and connection info in each direction. Far more convenient than Wireshark when you just need to inspect raw requests from an application. To go deeper into diagnosing connectivity problems, the full guide to ip, route, dig, and netcat covers the broader toolkit.
Or simulate a server that returns a fixed response:
# Every connection to port 9999 gets the contents of response.txt
socat TCP-LISTEN:9999,fork OPEN:response.txt,rdonly
6. Running socat as a systemd service
In the office environments I manage, some relays need to run continuously. Rather than leaving a terminal open, set up a systemd service to keep things clean:
# /etc/systemd/system/socat-relay.service
[Unit]
Description=socat port relay 8080 -> internal:80
After=network.target
[Service]
ExecStart=/usr/bin/socat TCP-LISTEN:8080,fork,reuseaddr TCP:192.168.1.10:80
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now socat-relay
Practical notes to keep in mind
- Security:
socathas no built-in authentication. Binding to a public interface means anyone can connect. Pair it withufw/iptablesto whitelist source IPs. - The
bindoption: By default,socatlistens on all interfaces. To restrict it to localhost, addbind=127.0.0.1:TCP-LISTEN:8080,bind=127.0.0.1,fork - IPv6: Use
TCP6-LISTENandTCP6instead ofTCPwhen IPv6 support is needed. If you’re working in a dual-stack environment, configuring IPv6 on Linux servers is a solid reference. - Connection limits: The
max-children=10option caps the number of concurrent child processes — a useful safeguard against floods when exposing a port publicly.
When to use socat — and when not to
I think of socat as a situational tool — it shows up when you need a quick fix without touching system configuration. It excels at:
- Temporary port forwarding (testing, debugging, emergency fixes)
- Simple relays that don’t need complex configuration
- Quickly wrapping plain TCP in SSL
- Low-level network communication debugging
But don’t reach for socat when:
- You need load balancing or health checks → HAProxy/nginx are far better suited
- You need a production reverse proxy with logging, retries, and timeouts —
socatisn’t feature-rich enough - You need a VPN tunnel with strong encryption → WireGuard/OpenVPN are the right choices
Thirty seconds typing a socat command is sometimes more effective than two hours configuring something else. It can’t replace HAProxy or nginx — but it was never meant to. Every tool has its job.
Add socat to your toolbox if it isn’t there already. You won’t use it every day — but when you need it, nothing else quite fits.

