A TCP relay that forwards a public ingress port to one backend target. I built it to practice deploying and operating a small Linux service.
GateRelay carries bytes between TCP connections. It does not inspect or modify them. It has one backend target. There is no TLS termination, health endpoint, metrics exporter, load balancing, or automated test suite. Use HAProxy or nginx when a production service needs those features.
go build -o gaterelayGateRelay requires Go 1.21 or newer. Its only dependency is
github.com/BurntSushi/toml.
The default config path is /etc/gaterelay/config.toml. Override it with
-config.
listen_addr = "0.0.0.0"
listen_port = 4000
target_addr = "10.0.0.20"
target_port = 5000
max_conns = 200
idle_timeout_secs = 60
connect_timeout_secs = 5
shutdown_grace_secs = 10
log_level = "info"Startup fails on an invalid port, empty target, or unknown log level.
idle_timeout_secs measures inactivity. Reads and writes in either direction
move the deadline forward. A value of zero disables the deadline.
max_conns is a hard cap. The accept loop claims a slot before it starts the
connection goroutine.
sudo ./deploy/scripts/install.sh
sudo ./deploy/scripts/setup-firewall.sh 4000 22 192.168.1.0/24
sudo ./deploy/scripts/harden-ssh.sh
sudo systemctl enable --now gaterelayThe scripts target Ubuntu Server 22.04 LTS and Debian 12. Confirm key-based SSH
login before running harden-ssh.sh. That script disables password login.
The systemd unit runs under a dedicated account with no login shell. It drops
capabilities, sets NoNewPrivileges, uses ProtectSystem=strict, creates a
private temporary directory, limits address families, and filters syscalls.
The firewall script denies traffic except for the relay port and SSH.
| File | Contents |
|---|---|
| ARCHITECTURE.md | Design, data flow, threat model, and failure modes |
| DEPLOYMENT.md | Deployment from a clean VM |
| OPERATIONS.md | Operations and recovery |
| HARDENING.md | Hardening checklist |
MIT. See LICENSE.