Sockudo
Server

SSL & Deployment

TLS termination, Unix sockets, reverse proxy setup, and deployment strategies.

TLS Termination

Sockudo can terminate TLS directly using PEM-encoded certificates, powered by Rustls.

Configuration

{
  "ssl": {
    "enabled": true,
    "cert_path": "/etc/ssl/certs/sockudo.pem",
    "key_path": "/etc/ssl/private/sockudo-key.pem",
    "redirect_http": true,
    "http_port": 80
  }
}
SettingEnv VarDefaultDescription
enabledSSL_ENABLEDfalseEnable TLS
cert_pathSSL_CERT_PATH""Path to PEM certificate file
key_pathSSL_KEY_PATH""Path to PEM private key file
passphrasenullKey passphrase (reserved, not yet supported)
ca_pathnullCA certificate (reserved, not yet supported)
redirect_httpSSL_REDIRECT_HTTPfalseStart an HTTP redirect server
http_portSSL_HTTP_PORT80HTTP port for the redirect server

HTTP to HTTPS Redirect

When redirect_http is enabled, Sockudo starts a secondary HTTP server that responds with 301 Permanent Redirect to the HTTPS equivalent:

http://example.com/app/my-key  →  https://example.com:6001/app/my-key

The redirect preserves the original host and URI path.

Certificate Requirements

  • Certificates must be PEM-encoded (not DER or PKCS#12).
  • Certificate and key must be in separate files.
  • For Let's Encrypt, use fullchain.pem as cert_path and privkey.pem as key_path.

Example: Let's Encrypt

SSL_ENABLED=true
SSL_CERT_PATH=/etc/letsencrypt/live/ws.example.com/fullchain.pem
SSL_KEY_PATH=/etc/letsencrypt/live/ws.example.com/privkey.pem
SSL_REDIRECT_HTTP=true

Unix Socket

Sockudo can listen on a Unix domain socket instead of (or in addition to) a TCP port. This is useful when running behind a reverse proxy on the same machine - Unix sockets avoid TCP overhead and provide file-based access control.

{
  "unix_socket": {
    "enabled": true,
    "path": "/var/run/sockudo/sockudo.sock",
    "permission_mode": "660"
  }
}
SettingEnv VarDefaultDescription
enabledUNIX_SOCKET_ENABLEDfalseEnable Unix socket listener
pathUNIX_SOCKET_PATH/var/run/sockudo/sockudo.sockSocket file path (must be absolute)
permission_modeUNIX_SOCKET_PERMISSION_MODE660Octal file permissions

Security

  • The socket path must be absolute (starts with /).
  • Directory traversal (../) is rejected.
  • World-writable permissions (xx7) generate a warning.
  • Using /tmp/ in production generates a warning - use /var/run/sockudo/ instead.

Permission Mode Examples

ModeMeaning
660Owner and group can read/write (recommended)
750Owner full access, group read/execute
700Owner only

Reverse Proxy Setup

For production, running Sockudo behind a reverse proxy is recommended. The reverse proxy handles TLS, load balancing, and static assets while Sockudo focuses on WebSocket connections.

Nginx

upstream sockudo {
    # TCP
    server 127.0.0.1:6001;
    # Or Unix socket
    # server unix:/var/run/sockudo/sockudo.sock;
}

server {
    listen 443 ssl http2;
    server_name ws.example.com;

    ssl_certificate     /etc/letsencrypt/live/ws.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ws.example.com/privkey.pem;

    location / {
        proxy_pass http://sockudo;
        proxy_http_version 1.1;

        # WebSocket upgrade
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Forward client IP
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Timeouts
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
    }
}
Set proxy_read_timeout higher than Sockudo's activity_timeout (default 120s) to prevent the proxy from closing idle connections before Sockudo does.

Caddy

ws.example.com {
    reverse_proxy 127.0.0.1:6001
}

Caddy handles WebSocket upgrades, TLS (automatic via Let's Encrypt), and HTTP/2 out of the box.

HAProxy

frontend ws_frontend
    bind *:443 ssl crt /etc/haproxy/certs/ws.example.com.pem
    default_backend sockudo_nodes

backend sockudo_nodes
    balance leastconn
    option http-server-close
    
    # Sticky sessions for WebSocket
    stick-table type ip size 200k expire 30m
    stick on src

    server node1 10.0.0.1:6001 check
    server node2 10.0.0.2:6001 check
    server node3 10.0.0.3:6001 check
WebSocket connections are long-lived. Use sticky sessions (source IP or cookie-based) to ensure a client always reaches the same node for the duration of its connection. Session affinity is not required for correctness (the adapter syncs state), but it avoids unnecessary reconnections.

Docker Deployment

Basic Docker Run

docker run -d \
  --name sockudo \
  -p 6001:6001 \
  -p 9601:9601 \
  -v ./config:/app/config:ro \
  -e ADAPTER_DRIVER=redis \
  -e DATABASE_REDIS_HOST=redis \
  sockudo/sockudo:latest

Docker Compose

services:
  sockudo:
    image: sockudo/sockudo:latest
    ports:
      - "6001:6001"
      - "9601:9601"
    environment:
      HOST: "0.0.0.0"
      PORT: "6001"
      ADAPTER_DRIVER: "redis"
      DATABASE_REDIS_HOST: "redis"
      SOCKUDO_DEFAULT_APP_ID: "my-app"
      SOCKUDO_DEFAULT_APP_KEY: "my-key"
      SOCKUDO_DEFAULT_APP_SECRET: "my-secret"
    depends_on:
      - redis

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

Docker Compose with Multiple Nodes

services:
  sockudo-1:
    image: sockudo/sockudo:latest
    ports:
      - "6001:6001"
    environment:
      ADAPTER_DRIVER: "redis"
      DATABASE_REDIS_HOST: "redis"
      SOCKUDO_DEFAULT_APP_ID: "my-app"
      SOCKUDO_DEFAULT_APP_KEY: "my-key"
      SOCKUDO_DEFAULT_APP_SECRET: "my-secret"
    depends_on:
      - redis

  sockudo-2:
    image: sockudo/sockudo:latest
    ports:
      - "6002:6001"
    environment:
      ADAPTER_DRIVER: "redis"
      DATABASE_REDIS_HOST: "redis"
      SOCKUDO_DEFAULT_APP_ID: "my-app"
      SOCKUDO_DEFAULT_APP_KEY: "my-key"
      SOCKUDO_DEFAULT_APP_SECRET: "my-secret"
    depends_on:
      - redis

  redis:
    image: redis:7-alpine

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - sockudo-1
      - sockudo-2

Systemd Service

For bare-metal or VM deployments:

[Unit]
Description=Sockudo WebSocket Server
After=network.target redis.service
Wants=redis.service

[Service]
Type=simple
User=sockudo
Group=sockudo
WorkingDirectory=/opt/sockudo
ExecStart=/opt/sockudo/sockudo --config /opt/sockudo/config/config.json
Restart=always
RestartSec=5

# Environment
Environment=HOST=0.0.0.0
Environment=PORT=6001
Environment=ADAPTER_DRIVER=redis

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/run/sockudo

# Resource limits
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
sudo systemctl enable sockudo
sudo systemctl start sockudo
Set LimitNOFILE high enough for your expected connection count. Each WebSocket connection uses one file descriptor.

Build Features

Compile only the backends you need for smaller binaries:

# Minimal (local adapter only)
cargo build --release

# Redis adapter + PostgreSQL app manager
cargo build --release --features "redis,postgres"

# Full build with all backends
cargo build --release --features full

Available features:

FeatureWhat It Enables
redisRedis adapter, cache, queue, rate limiter
redis-clusterRedis Cluster support for all backends
natsNATS adapter
mysqlMySQL app manager
postgresPostgreSQL app manager
dynamodbDynamoDB app manager
scylladbScyllaDB app manager
sqsSQS queue
lambdaAWS Lambda webhook delivery
fullAll features

Health Checks

Sockudo exposes health and metrics endpoints for monitoring:

EndpointPortDescription
/6001Returns OK if the server is running
/metrics9601Prometheus metrics

Use these for load balancer health checks, Kubernetes liveness probes, or Docker healthchecks:

# Docker Compose
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:6001/"]
  interval: 10s
  timeout: 5s
  retries: 3
# Kubernetes
livenessProbe:
  httpGet:
    path: /
    port: 6001
  initialDelaySeconds: 5
  periodSeconds: 10

Production Checklist

  • Use a horizontal adapter (redis, redis-cluster, or nats) if running multiple nodes
  • Set SOCKUDO_DEFAULT_APP_SECRET to a strong random value
  • Enable rate limiting with redis backend for cluster-wide enforcement
  • Set RATE_LIMITER_API_TRUST_HOPS to match your proxy chain depth
  • Configure allowed_origins per app to restrict WebSocket connections
  • Set LimitNOFILE / ulimit high enough for your connection target
  • Enable metrics and set up Prometheus scraping
  • Use TLS - either via Sockudo directly or via a reverse proxy
  • Configure webhook endpoints if you need server-side event notifications
  • Set ENVIRONMENT=production for production-appropriate defaults
Copyright © 2026