Skip to content

Repository files navigation

Red Forge

 ##
##
######
########
##########
############
##############
################## ##
################## ####
#################### ######
##############################
################################
############ ##################
############ ##################
########## ##################
######## ##################
######## ################
######## ############
######## ##########
######## ######
###### ####
╦═╗╔═╗╔╦╗ ╔═╗╔═╗╦═╗╔═╗╔═╗
╠╦╝║╣ ║║ ╠╣ ║ ║╠╦╝║ ╦║╣
╩╚═╚═╝═╩╝ ╚ ╚═╝╩╚═╚═╝╚═╝

A high-performance TCP to Unix socket proxy for Redis, written in Zig.

Overview

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

Features

  • 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

Installation

Prerequisites

  • Zig 0.15.0 or later
  • GNU Make (optional, for convenience commands)

Building from Source

# 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

System Installation

# 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-forge

Uninstallation

sudo make uninstall

Binaries

red-forge (Server)

The main proxy server that listens for TCP connections and forwards them to a Redis Unix socket.

red-forge [OPTIONS]

Options

OptionDefaultDescription
--config=PATH/etc/red-forge/redis.confConfiguration file path
--listen-at=HOST:PORT127.0.0.1:6879TCP address to listen on
--redis-socket=PATH/run/redis.sockPath to Redis Unix socket
--thread-count=NCPU countNumber of worker threads
--close-idle=BOOLtrueEnable idle connection timeout
--close-idle-after=DUR30sIdle timeout duration (supports s, m, h suffixes)
-h, --helpShow help message
-v, --versionShow version

Examples

# 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.conf

red-forge-cli (Client)

Interactive Redis command-line interface that connects to a red-forge server instance.

red-forge-cli [OPTIONS]

Options

OptionDefaultDescription
--host=HOST127.0.0.1Host to connect to
--port=PORT6879Port to connect to
--config=PATH/etc/red-forge/redis.confConfig file (reads listen-at for connection)
-h, --helpShow help message
-v, --versionShow version

Examples

# 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.conf

Interactive Commands

Once 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.

Configuration

Configuration File

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=ondemand

TCP Control Modes

Red Forge supports three connection management modes (config file only):

ModeDescription
ondemandAccept unlimited connections until OS limit (default)
staticFixed pool size, rejects new connections when full
dynamicFlexible pool with configurable min/max bounds

Static Mode Settings

tcp-control-mode=static
tcp-control-static-connections=1000 # Max simultaneous connectionstcp-control-static-allow-exceed=false # Allow exceeding limit (idle cleanup handles excess)

Dynamic Mode Settings

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 temporarily

Idle Cleanup Behavior

When close-idle=true, idle connections are cleaned up based on the TCP control mode:

ModeIdle Cleanup Behavior
ondemandAll idle connections are closed after timeout
staticIdle connections closed only when above static-connections
dynamicIdle connections closed only when above dynamic-min

This ensures a minimum pool of connections is maintained while excess connections are cleaned up.

Configuration Priority

Settings are applied in the following order (later overrides earlier):

  1. Built-in defaults
  2. Configuration file
  3. Command-line arguments

Systemd Service

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

Service Management

# 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-forge

Development

Project Structure

red-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

Make Targets

TargetDescription
makeBuild release binaries
make buildBuild release binaries
make debugBuild debug binaries
make cleanRemove build artifacts
make testRun tests
make runBuild and run server
make cliBuild and run CLI client
make installInstall to system (requires sudo)
make uninstallRemove from system (requires sudo)
make enableEnable and start systemd service
make disableDisable and stop systemd service
make statusShow service status
make logsFollow service logs
make helpShow all available targets

Building

# Debug build
make debug
# Release build
make
# Run tests
make test# Clean build artifacts
make clean

Use Cases

1. Exposing Unix Socket Redis to Network

# 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

2. Docker Container to Host Redis

# 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

3. Local Development Proxy

# Proxy with shorter idle timeout for development
red-forge --listen-at=127.0.0.1:6379 --close-idle-after=10s

Performance

Red 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

File Descriptor Limits

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-forge

For 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.sock

Check current limit:

ulimit -n

For 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:65536

Verify limit for running process:

prlimit --pid $(pgrep red-forge) --nofile
# or
cat /proc/$(pgrep red-forge)/limits | grep "open files"

Ephemeral Port Range

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 -p

This increases available ports from ~28K to ~64K, allowing more concurrent connections.

Note: Both server and benchmark tool may need this when handling many connections.

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

About

Redis Proxy to solve needs of efficiently handling TCP <-> Unix:Socket communication

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages