High-performance reverse DNS proxy with TCP/UDP tunneling and WebSocket support for games.
relay.name is a Go-based reverse DNS proxy service that allows you to control DNS records and route traffic through custom domain patterns. With built-in tunneling (like ngrok) and optimized for low-latency game connections, it's perfect for exposing local game servers, APIs, and services.
Pricing: $1/month per DNS record
We chose Go for this project because:
- ✅ Low Latency: Compiled language with minimal overhead, perfect for real-time game connections
- ✅ Excellent Concurrency: Goroutines handle thousands of simultaneous connections efficiently
- ✅ Native Networking: Built-in TCP/UDP/WebSocket support in standard library
- ✅ High Performance: Used by ngrok, Cloudflare Tunnel, and other production tunneling services
- ✅ Simple Deployment: Single binary, no runtime dependencies
- ✅ Memory Efficient: Lower memory footprint than Node.js/Python for high-traffic scenarios
[name1].relay.name/[name2]/[name3]/[etc...]
Example:
alice.relay.name/bob/carol→ Routes to the target configured for "alice" with path segments "bob/carol"myapp.relay.name/api/users→ Routes to "myapp" target with path "/api/users"
Use Cases:
- Preserve TLD structure while adding path-based routing
- Single subdomain can handle multiple routes
- Clean separation between domain identifier and path segments
word1.word2.word3.relay.name
Example:
happy.blue.moon.relay.name→ Routes to target configured for "happy.blue.moon"first.second.third.relay.name→ Routes to target configured for "first.second.third"
Use Cases:
- Human-readable, memorable addresses
- No path segments needed - the entire subdomain is the identifier
- Great for simple, direct routing
[first-name-address].relay.name/[lastname-address]
Example:
john.relay.name/doe→ Routes to target configured for "john" with path segment "doe"company.relay.name/service→ Routes to "company" target with path "service"
Use Cases:
- Combines subdomain identification with path-based routing
- Flexible for hierarchical structures
Standard HTTP reverse proxy with path routing support.
Full bidirectional WebSocket proxy for real-time game connections:
- Low-latency message forwarding
- Binary and text message support
- Automatic reconnection handling
Raw TCP connection tunneling for game servers:
- Custom protocol: Send subdomain in first packet
- Bidirectional data streaming
- Perfect for game protocols (Minecraft, custom game servers, etc.)
UDP packet forwarding for game networking:
- Low-latency packet routing
- Connection pooling for performance
- Ideal for real-time multiplayer games
- Language: Go 1.21+
- Database: SQLite (can be swapped to PostgreSQL)
- Networking: Native Go net package
- WebSocket: gorilla/websocket
- Deployment: Single binary
-
HTTP Server (Port 8080)
- Handles HTTP reverse proxy
- API endpoints for DNS record management
- Subdomain-based routing
-
WebSocket Server (Port 8083)
- Dedicated WebSocket proxy for games
- Low-latency message forwarding
- Supports binary and text frames
-
TCP Tunneling Server (Port 8081)
- Raw TCP connection tunneling
- Custom protocol:
SUBDOMAIN\n+ data - Bidirectional streaming
-
UDP Tunneling Server (Port 8082)
- UDP packet forwarding
- Connection pooling
- Low-latency routing
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email VARCHAR(255) UNIQUE,
wallet_address VARCHAR(255),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE dns_records (
id INTEGER PRIMARY KEY AUTOINCREMENT,
subdomain VARCHAR(255) NOT NULL UNIQUE,
target VARCHAR(500) NOT NULL,
pattern_type VARCHAR(50) NOT NULL, -- 'subdomain_path', 'multi_word', 'hybrid'
protocol VARCHAR(20) NOT NULL DEFAULT 'http', -- 'http', 'tcp', 'udp', 'ws'
user_id INTEGER NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME,
is_active BOOLEAN DEFAULT 1,
FOREIGN KEY (user_id) REFERENCES users(id)
);
CREATE TABLE subscriptions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
dns_record_id INTEGER NOT NULL,
status VARCHAR(50) DEFAULT 'active',
billing_cycle_start DATE,
billing_cycle_end DATE,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (dns_record_id) REFERENCES dns_records(id)
);POST /api/dns/records
Content-Type: application/json
{
"subdomain": "alice",
"target": "http://localhost:3000",
"pattern_type": "subdomain_path",
"protocol": "http",
"user_id": 1
}Response:
{
"id": 1,
"message": "DNS record created"
}GET /api/dns/records?user_id=1Response:
[
{
"id": 1,
"subdomain": "alice",
"target": "http://localhost:3000",
"pattern_type": "subdomain_path",
"protocol": "http",
"user_id": 1,
"is_active": true,
"created_at": "2024-01-01T00:00:00Z",
"expires_at": null
}
]PUT /api/dns/records/1
Content-Type: application/json
{
"target": "http://new-target.com",
"protocol": "ws"
}DELETE /api/dns/records/1NEW! Create persistent tunnels from your local machine:
# Run client on your machine
./client/relay-client -server=relay.name:8084 -port=3000
# Output: ✅ Tunnel established!
# 🌐 Public URL: http://tunnel-123456.relay.nameSee TUNNEL_GUIDE.md for complete tunnel documentation.
- Go 1.21 or later
- SQLite3 (included with Go binary)
- Clone the repository:
git clone https://github.com/yourusername/relay.name.git
cd relay.name- Install dependencies:
go mod download- Build the server:
go build -o relay-server main.go proxy.go udp.go- Run the server:
./relay-server \
-http=8080 \
-tcp=8081 \
-udp=8082 \
-ws=8083 \
-db=./relay.db \
-domain=relay.nameSet environment variables or use command-line flags:
Server Settings:
-http: HTTP server port (default: 8080)-tcp: TCP tunneling port (default: 8081)-udp: UDP tunneling port (default: 8082)-ws: WebSocket server port (default: 8083)-tunnel: Tunnel server port for client connections (default: 8084)-db: Database path (default: ./relay.db)-domain: Base domain (default: relay.name)-tls-cert: TLS certificate path (optional)-tls-key: TLS key path (optional)
DNS Management (Automatic DNS Record Creation):
-dns-provider: DNS provider:cloudflareordigitalocean(empty = manual)-dns-api-key: API key/token from DNS provider-dns-zone-id: Zone ID (Cloudflare) or domain name (DigitalOcean)-dns-email: Email (Cloudflare only)-server-ip: Your server's public IP address
Example with automatic DNS management:
./relay-server \
-dns-provider=cloudflare \
-dns-api-key=YOUR_API_KEY \
-dns-zone-id=YOUR_ZONE_ID \
-dns-email=admin@relay.name \
-server-ip=1.2.3.4See DNS_MANAGEMENT.md for detailed DNS setup.
Important: The Go server is NOT a DNS server. It's a reverse proxy that receives traffic AFTER DNS resolution. You need to configure DNS records that point to your server IP.
Quick Setup (Recommended: Cloudflare):
- Sign up for Cloudflare (free): https://cloudflare.com
- Add domain
relay.nameto Cloudflare - Get nameservers from Cloudflare (e.g.,
alice.ns.cloudflare.com) - Configure Namecheap:
- Domain List → Manage → Nameservers → Custom DNS
- Enter Cloudflare nameservers
- Add DNS records in Cloudflare:
Arecord:@→YOUR_SERVER_IPArecord:*→YOUR_SERVER_IP(wildcard)
See DNS_SETUP.md for detailed instructions including:
- Cloudflare setup (recommended)
- AWS Route 53 setup
- Self-hosted DNS (BIND9, CoreDNS)
- Namecheap configuration steps
# Create DNS record
curl -X POST http://localhost:8080/api/dns/records \
-H "Content-Type: application/json" \
-d '{
"subdomain": "myapp",
"target": "http://localhost:3000",
"pattern_type": "subdomain_path",
"protocol": "http",
"user_id": 1
}'
# Access via: http://myapp.relay.name/api/users# Create WebSocket DNS record
curl -X POST http://localhost:8080/api/dns/records \
-H "Content-Type: application/json" \
-d '{
"subdomain": "game-server",
"target": "ws://localhost:8080",
"pattern_type": "multi_word",
"protocol": "ws",
"user_id": 1
}'
# Connect via: ws://game-server.relay.name# Create TCP tunnel record
curl -X POST http://localhost:8080/api/dns/records \
-H "Content-Type: application/json" \
-d '{
"subdomain": "minecraft",
"target": "localhost:25565",
"pattern_type": "multi_word",
"protocol": "tcp",
"user_id": 1
}'
# Connect via TCP port 8081
# Send: "minecraft\n" followed by game data# Create UDP tunnel record
curl -X POST http://localhost:8080/api/dns/records \
-H "Content-Type: application/json" \
-d '{
"subdomain": "game-udp",
"target": "localhost:7777",
"pattern_type": "multi_word",
"protocol": "udp",
"user_id": 1
}'
# Send UDP packets to port 8082
# Format: "game-udp\n" + packet data- Latency: < 1ms overhead per request (local network)
- Throughput: 10,000+ concurrent connections
- Memory: ~50MB base + ~1KB per connection
- CPU: Efficient goroutine scheduling
// Client-side
const ws = new WebSocket('wss://mygame.relay.name');
ws.onopen = () => {
console.log('Connected to game server');
ws.send(JSON.stringify({ type: 'join', player: 'Alice' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Game update:', data);
};// Your game server
listener, _ := net.Listen("tcp", ":25565")
// relay.name will tunnel connections to your server
// Players connect to: tcp://minecraft.relay.name:8081- $1/month per active DNS record
- Automatic expiration handling
- Subscription tracking in database
- Integration ready for Stripe/PayPal
go test ./...go build -ldflags="-s -w" -o relay-server main.go proxy.go udp.godocker build -t relay-name .
docker run -p 8080:8080 relay-name- TLS/SSL termination
- Rate limiting
- Authentication/Authorization
- Metrics and monitoring
- Docker containerization
- Kubernetes deployment
- Payment integration (Stripe)
- Web dashboard
- Client SDKs (Go, Node.js, Python)
See LICENSE file for details.
Contributions welcome! Please open an issue or submit a pull request.