Almost every machine you might want to reach — a home server, a cloud VM, a box on someone else’s corporate LAN — sits behind NAT. It has no public address, no listening port you can hit, and frequently a firewall that permits nothing except outbound HTTPS. Reaching one of these boxes without reconfiguring the router, standing up a VPN, or buying a static IP is a problem most operators bump into eventually.
The clean answer is GG-Socket: a relay you run yourself that lets both endpoints connect outward, so no inbound port has to be open on either machine you care about.
Why Reaching Inward Fails
Conventional SSH assumes the target owns a routable IP and exposes port 22. That assumption collapses across the common cases:
- Carrier-grade NAT — providers pile thousands of subscribers behind one public address. You cannot forward a port because the address is not uniquely yours to begin with.
- Office and guest networks — inbound is blocked at the edge; only outbound 443 and DNS are let through.
- Rotating addresses — even a genuinely public IP wanders. Dynamic DNS papers over it but introduces its own failure modes.
- Private cloud topologies — many deployments front instances behind balancers and never expose them directly at all.
The fix is not to punch another hole inbound. It is to reverse the direction: have the box dial out to a rendezvous point, and dial that same point yourself from wherever you are.
How GG-Socket Realizes That Pattern
GG-Socket is the rendezvous point. It is a small Go process with a simple job:
- It accepts TCP connections over TLS on port 443.
- From each connection it reads a secret key and the peer’s role (target or client).
- It parks the first peer to arrive for a given secret, and when a second peer shows up with the same secret and the opposite role, it pairs them and splices their streams.
Both halves are outbound, so neither endpoint needs a public address or an open port. The relay terminates TLS and forwards encrypted application bytes blindly — it never interprets the traffic it carries.
What You Need
- One VPS with a public address (any inexpensive plan is plenty).
- Your domain pointed at it.
- Docker and Docker Compose on that VPS.
- Outbound HTTPS reachability on the two machines you want to connect.
The one-time relay deploy is covered in the Quick Start. After that, every new tunnel is just two peers dialling the same secret.
Step 1: Stand Up the Relay
On the VPS, bring up the stack:
git clone <repo> gg_socket && cd gg_socket
cp notify.env.example notify.env # edit secrets
docker compose up -d --build
The relay publishes TLS on :443 and exposes health and metrics on the loopback. Confirm it is listening:
curl -s http://127.0.0.1:9001/health
# {"status":"ok","active_connections":0,...}
That address — r.ggsocket.com:443 — is the rendezvous point both peers will dial.
Step 2: Dial In From Both Ends
Agree on a secret, then have each peer connect outward with it. The exact command depends on the client you use; with a generic secret-key client it looks like:
# on the box you want to reach
gs-target GGK-M1SDZI-MP4V7P-6JCV4T-G9O5AV -r r.ggsocket.com:443
# from your laptop
gs-client GGK-M1SDZI-MP4V7P-6JCV4T-G9O5AV -r r.ggsocket.com:443
The relay sees two connections presenting the same secret, replies matched to each, and begins copying bytes in both directions. Close either side and the session ends.
Both legs are outbound TCP. Neither peer holds a public address or an open port. The only host that must be reachable from the internet is the relay itself.
Step 3: Watch It Work
The relay reports live counters, which is the easiest way to confirm a session formed:
curl -s http://127.0.0.1:9001/metrics | grep -E 'active|sessions|bytes'
# goodsocket_active_connections 2
# goodsocket_sessions_total 1
# goodsocket_bytes_relayed_total 48211
Active connections climbs by two on a match, sessions by one, and bytes as traffic flows. If the numbers look right, the tunnel is up.
Tuning the Limits
Two knobs govern how the relay treats incoming traffic, both set through environment variables in the compose file:
GGSOCKET_RELAY_RATE_LIMIT— new connections allowed per source IP per 60-second window (default 20).GGSOCKET_RELAY_MAX_CONNS— the overall concurrent-connection ceiling enforced by a semaphore (default 10,000).
Raise them for busy deployments; leave them be for a personal relay.
When Something Does Not Connect
A peer sits on “waiting” and never pairs
The other peer is not dialling, or is dialling a different secret. Re-check that both sides use the identical key and point at r.ggsocket.com:443. The waiting peer gives up after GGSOCKET_RELAY_WAIT_TTL seconds (default 60).
Connections rejected as rate-limited
A single source IP opened more than the allowed connections in a minute. It clears by itself once the 60-second window rolls over; if it keeps happening, raise GGSOCKET_RELAY_RATE_LIMIT.
Connection refused on 443
The relay container is not running or a firewall is in the way. Check docker compose ps and confirm the host allows inbound 443.
Run your own rendezvous point.
One VPS. One secret. No port forwarding anywhere else.
docker compose up -d --buildFull Quick Start →