Sockudo
Deployment

Docker and Compose

Run Sockudo in containers with mounted configuration, correct limits, health checks, and shared backends.

The published Sockudo image runs as a non-root user and starts the binary with --config /app/config/config.json. For production, pin a release tag, mount or generate the exact configuration, inject secrets separately, and set limits on the container itself.

Production-like docker run

docker run -d \
  --name sockudo \
  --restart unless-stopped \
  --init \
  --stop-timeout 45 \
  --ulimit nofile=262144:262144 \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  --mount type=bind,src="$PWD/config.toml",dst=/app/config/production.toml,readonly \
  --env-file "$PWD/sockudo.env" \
  -p 6001:6001 \
  -p 127.0.0.1:9601:9601 \
  ghcr.io/sockudo/sockudo:5.0.0 \
  sockudo --config /app/config/production.toml

The arguments after the image replace its default command, so include both sockudo and --config. Mount metrics only on a private or loopback interface unless the network policy already restricts it.

The CONFIG_FILE environment value embedded in the image is descriptive; the server selects a non-default file through --config.

Compose profile

This example keeps the Sockudo process immutable and connects it to an external or separately managed Redis:

name: sockudo

services:
  sockudo:
    image: ghcr.io/sockudo/sockudo:5.0.0
    command: ["sockudo", "--config", "/app/config/production.toml"]
    restart: unless-stopped
    init: true
    stop_grace_period: 45s
    read_only: true
    tmpfs:
      - /tmp:size=64m,mode=1777
    ulimits:
      nofile:
        soft: 262144
        hard: 262144
    ports:
      - "6001:6001"
      - "127.0.0.1:9601:9601"
    volumes:
      - ./config/production.toml:/app/config/production.toml:ro
    env_file:
      - ./secrets/sockudo.env
    environment:
      HOST: "0.0.0.0"
      PORT: "6001"
      METRICS_HOST: "0.0.0.0"
      METRICS_PORT: "9601"
      INSTANCE_PROCESS_ID: "compose-1"
    healthcheck:
      test: ["CMD", "curl", "-fsS", "http://127.0.0.1:6001/up/production"]
      interval: 10s
      timeout: 3s
      start_period: 20s
      retries: 3
    logging:
      driver: local
      options:
        max-size: "20m"
        max-file: "5"

For local development, adding Redis to the same Compose project is convenient. In production, a single-host Redis container has the same host failure domain as Sockudo. Use a managed or independently operated Redis topology when the shared adapter, cache, queue, or rate limiter must survive that host.

Configuration and secrets

Prefer this separation:

  • mount the complete non-secret TOML or JSON read-only
  • supply secret-backed environment variables through the orchestrator
  • mount TLS keys, provider credentials, and service-account JSON as read-only secret files
  • reference secret file paths from Sockudo configuration or environment

An env_file is still a plaintext secret file on the Docker host. Limit its owner and mode, keep it out of image build context and source control, and rotate it through the host's secret-management workflow.

Do not use Docker build arguments for credentials. Build arguments and layers can remain visible in image metadata or caches.

Limits: host versus container

Three different layers can cap a container:

LayerCheckConfigure
Sockudo admissionSOCKUDO_MAX_CONNECTIONSStatic config or environment
Process nofiledocker exec sockudo sh -c 'ulimit -n'--ulimit or Compose ulimits
Host kernel and service managersysctl, Docker daemon unit limitsHost image, sysctl, and daemon configuration

Changing /etc/security/limits.d inside the image does not raise the running container's file limit. Set it through the runtime and verify from inside the container.

Host-level connection queues and NIC settings remain host concerns. Namespaced sysctls may be set per container, but only after confirming the runtime supports them and the value is safe for other workloads.

CPU and memory

Start with a memory limit that leaves room for peak sockets, payload buffers, adapter queues, and allocator fragmentation. An out-of-memory kill disconnects every client on that container at once.

CPU quotas can create latency cliffs during reconnect or fanout bursts. Set CPU reservations, watch throttling metrics, and add a hard CPU limit only when multi-tenant isolation requires one and the load test includes the same quota.

Measure:

docker stats sockudo
docker inspect sockudo --format '{{json .HostConfig.Ulimits}}'
docker exec sockudo sh -c 'ulimit -n; cat /proc/1/limits'
docker exec sockudo sh -c 'curl -fsS http://127.0.0.1:6001/live'

Health and startup ordering

Use /live when the runtime needs to decide whether the process is alive. Use /up or /up/<app-id> when the load balancer needs dependency-aware readiness.

Compose depends_on can order startup, but it does not make a dependency permanently available. Sockudo must still expose failed readiness and operators must alert on adapter, cache, queue, and app-manager failures.

Do not restart a healthy process merely because Redis or a database is briefly slow. Repeated container restarts amplify reconnect load.

Multi-host containers

Moving Compose services onto two VMs does not create Sockudo clustering automatically. Every Sockudo replica must have:

  • the same app identity and policy, or access to one shared app manager
  • a unique INSTANCE_PROCESS_ID
  • a shared horizontal adapter
  • a shared cache for cross-node coordination and distributed limits
  • durable queue and state backends where the enabled features require them
  • a WebSocket-aware load balancer with readiness and connection drain

Do not place a local memory adapter behind a multi-host load balancer. Clients connected to different hosts would occupy isolated realtime islands.

For larger container deployments, use the Kubernetes and Helm guide. For one dedicated container host, also apply the measured host guidance from Linux VM and bare metal.

On this page