##
##
######
########
##########
############
##############
################## ##
################## ####
#################### ######
##############################
################################
############ ##################
############ ##################
########## ##################
######## ##################
######## ################
######## ############
######## ##########
######## ######
###### ####
╦═╗╔═╗╔╦╗ ╔═╗╔═╗╦═╗╔═╗╔═╗
╠╦╝║╣ ║║ ╠╣ ║ ║╠╦╝║ ╦║╣
╩╚═╚═╝═╩╝ ╚ ╚═╝╩╚═╚═╝╚═╝
A high-performance TCP to Unix socket proxy for Redis, written in Zig.
Red Forge provides a TCP interface to Redis instances that are configured to listen only on Unix sockets. This is useful for:
- Exposing Unix socket-only Redis to TCP clients
- Adding a network layer for monitoring/debugging
- Bridging containerized applications to host Redis instances
- Load balancing and connection pooling scenarios
- High Performance: Written in Zig for minimal overhead and maximum throughput
- Multi-threaded: Configurable worker threads (defaults to CPU count)
- Idle Connection Management: Automatic cleanup of idle connections
- Bidirectional Proxying: Full duplex communication between TCP and Unix socket
- Graceful Shutdown: Waits for active connections to complete
- CLI Client: Built-in Redis command-line interface
- Zig 0.15.0 or later
- GNU Make (optional, for convenience commands)
# Clone the repository
git clone https://github.com/salesforge/red-forge.git
cd red-forge
# Build release binaries
make
# Or build directly with Zig
zig build -Doptimize=ReleaseFast# Install binaries, config, and systemd service
sudo make install
# Enable and start the service
sudo systemctl daemon-reload
sudo systemctl enable red-forge
sudo systemctl start red-forgesudo make uninstallThe main proxy server that listens for TCP connections and forwards them to a Redis Unix socket.
red-forge [OPTIONS]| Option | Default | Description |
|---|---|---|
--config=PATH | /etc/red-forge/redis.conf | Configuration file path |
--listen-at=HOST:PORT | 127.0.0.1:6879 | TCP address to listen on |
--redis-socket=PATH | /run/redis.sock | Path to Redis Unix socket |
--thread-count=N | CPU count | Number of worker threads |
--close-idle=BOOL | true | Enable idle connection timeout |
--close-idle-after=DUR | 30s | Idle timeout duration (supports s, m, h suffixes) |
-h, --help | Show help message | |
-v, --version | Show version |
# Start with defaults
red-forge
# Custom listen address and socket path
red-forge --listen-at=0.0.0.0:6379 --redis-socket=/var/run/redis/redis.sock
# With custom thread count and idle timeout
red-forge --thread-count=8 --close-idle-after=1m
# Using a custom config file
red-forge --config=/etc/red-forge/custom.confInteractive Redis command-line interface that connects to a red-forge server instance.
red-forge-cli [OPTIONS]| Option | Default | Description |
|---|---|---|
--host=HOST | 127.0.0.1 | Host to connect to |
--port=PORT | 6879 | Port to connect to |
--config=PATH | /etc/red-forge/redis.conf | Config file (reads listen-at for connection) |
-h, --help | Show help message | |
-v, --version | Show version |
# Connect to local server with defaults
red-forge-cli
# Connect to remote server
red-forge-cli --host=192.168.1.100 --port=6379
# Use config file for connection settings
red-forge-cli --config=/etc/red-forge/redis.confOnce connected, you can type any Redis command:
127.0.0.1:6879> PING
"PONG"
127.0.0.1:6879> SET mykey "Hello World"
"OK"
127.0.0.1:6879> GET mykey
"Hello World"
127.0.0.1:6879> KEYS *
1) "mykey"
127.0.0.1:6879> quit
Bye!
Type quit or exit to disconnect.
The default configuration file is located at /etc/red-forge/redis.conf:
# red-forge configuration file# TCP to Unix socket proxy for Redis# TCP address to listen onlisten-at=127.0.0.1:6879
# Path to Redis Unix socketredis-socket=/run/redis.sock
# Number of worker threads (0 = auto-detect CPU count)thread-count=0
# Close idle connectionsclose-idle=true
# Idle timeout duration (supports s/m/h suffix)close-idle-after=30s
# Log connection open/close eventslog-connections=true
# TCP control mode: ondemand, static, or dynamictcp-control-mode=ondemandRed Forge supports three connection management modes (config file only):
| Mode | Description |
|---|---|
ondemand | Accept unlimited connections until OS limit (default) |
static | Fixed pool size, rejects new connections when full |
dynamic | Flexible pool with configurable min/max bounds |
tcp-control-mode=static
tcp-control-static-connections=1000 # Max simultaneous connectionstcp-control-static-allow-exceed=false # Allow exceeding limit (idle cleanup handles excess)tcp-control-mode=dynamic
tcp-control-dynamic-min=100 # Minimum pool sizetcp-control-dynamic-max=20000 # Maximum pool sizetcp-control-dynamic-allow-exceed=false # Allow exceeding max temporarilyWhen close-idle=true, idle connections are cleaned up based on the TCP control mode:
| Mode | Idle Cleanup Behavior |
|---|---|
ondemand | All idle connections are closed after timeout |
static | Idle connections closed only when above static-connections |
dynamic | Idle connections closed only when above dynamic-min |
This ensures a minimum pool of connections is maintained while excess connections are cleaned up.
Settings are applied in the following order (later overrides earlier):
- Built-in defaults
- Configuration file
- Command-line arguments
The systemd service file is installed to /usr/lib/systemd/system/red-forge.service:
[Unit]Description=Red Forge - TCP to Unix socket proxy for Redis
After=network.target redis.service
Wants=redis.service
[Service]Type=simple
ExecStart=/usr/bin/red-forge --config=/etc/red-forge/redis.conf
Restart=on-failure
RestartSec=5s
[Install]WantedBy=multi-user.target# Start/stop/restart
sudo systemctl start red-forge
sudo systemctl stop red-forge
sudo systemctl restart red-forge
# Check status
sudo systemctl status red-forge
# View logs
sudo journalctl -u red-forge -f
# Enable/disable on boot
sudo systemctl enable red-forge
sudo systemctl disable red-forgered-forge/
├── src/
│ ├── main.zig # Server implementation
│ └── cli.zig # CLI client implementation
├── build.zig # Zig build configuration
├── Makefile # Build automation
├── redis.conf # Default configuration template
├── red-forge.service # Systemd service file
├── VERSION # Version file
├── README.md
├── .gitignore
└── LICENSE
| Target | Description |
|---|---|
make | Build release binaries |
make build | Build release binaries |
make debug | Build debug binaries |
make clean | Remove build artifacts |
make test | Run tests |
make run | Build and run server |
make cli | Build and run CLI client |
make install | Install to system (requires sudo) |
make uninstall | Remove from system (requires sudo) |
make enable | Enable and start systemd service |
make disable | Disable and stop systemd service |
make status | Show service status |
make logs | Follow service logs |
make help | Show all available targets |
# Debug build
make debug
# Release build
make
# Run tests
make test# Clean build artifacts
make clean# Redis configured with: unixsocket /run/redis.sock# Expose on all interfaces
red-forge --listen-at=0.0.0.0:6379 --redis-socket=/run/redis.sock# On host: run red-forge
red-forge --listen-at=0.0.0.0:6879 --redis-socket=/run/redis.sock
# In container: connect via host IP
redis-cli -h host.docker.internal -p 6879# Proxy with shorter idle timeout for development
red-forge --listen-at=127.0.0.1:6379 --close-idle-after=10sRed Forge is designed for minimal overhead:
- Zero-copy proxying where possible
- Thread-per-connection model for simplicity
- Automatic idle connection cleanup
- Connection limits via TCP control modes
When handling many concurrent connections, you may encounter "Too many open files" or ProcessFdQuotaExceeded errors. Each connection requires file descriptors for both the client TCP socket and the Redis Unix socket.
For systemd service:
The systemd service file includes LimitNOFILE=65536 by default. After modifying, reload:
sudo systemctl daemon-reload
sudo systemctl restart red-forgeFor local/manual execution:
Set the limit before running:
ulimit -n 65536
./zig-out/bin/red-forge --listen-at=127.0.0.1:6879 --redis-socket=/run/redis.sockCheck current limit:
ulimit -nFor persistent system-wide limits:
Edit /etc/security/limits.conf:
* soft nofile 65536
* hard nofile 65536
Then log out and back in (or start a new shell session).
Change limit for running process (no restart):
sudo prlimit --pid $(pgrep red-forge) --nofile=65536:65536Verify limit for running process:
prlimit --pid $(pgrep red-forge) --nofile
# or
cat /proc/$(pgrep red-forge)/limits | grep "open files"For high connection counts (10000+), you may exhaust available local ports. Each connection requires an ephemeral port from the system's port range.
Check current range:
cat /proc/sys/net/ipv4/ip_local_port_range
# Default: 32768 60999 (28231 ports)Increase port range (temporary):
sudo sysctl -w net.ipv4.ip_local_port_range="1024 65535"Increase port range (persistent):
Add to /etc/sysctl.conf:
net.ipv4.ip_local_port_range = 1024 65535
Then apply:
sudo sysctl -pThis increases available ports from ~28K to ~64K, allowing more concurrent connections.
Note: Both server and benchmark tool may need this when handling many connections.
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit issues and pull requests.