Every setting can be passed as an option to Socketelx.start_link/1 (or as
{Socketelx, opts} in a supervision tree) or set as an environment
variable. An explicit option wins over the environment variable.
Environment variables are named SOCKETELX_*. The older PUSHER_* spelling of the
same names (PUSHER_APP_ID, PUSHER_REDIS_URL, ...) is still accepted, so an
existing deployment keeps working; if both are set, SOCKETELX_* wins.
| Option | Env var | Default | Notes |
|---|---|---|---|
:app_id | SOCKETELX_APP_ID | "app-id" | Must match what your backend's Pusher library uses. Also namespaces Redis keys. |
:app_key | SOCKETELX_APP_KEY | "app-key" | Public; used in the WebSocket URL /app/:app_key. |
:app_secret | SOCKETELX_APP_SECRET | "app-secret" | Keep private. The default is public and logs a warning. |
:port | PORT | 6001 | Plain HTTP/WS. Put TLS in front. |
:webhook_url | SOCKETELX_WEBHOOK_URL | none | Where webhooks are POSTed. |
:client_messages_enabled | SOCKETELX_ENABLE_CLIENT_MESSAGES | true | false rejects all client-* events. |
:redis_url | SOCKETELX_REDIS_URL | none | Enables multi-server mode. rediss:// for TLS. |
:redis_opts | none | [] | Extra Redix options, e.g. ssl: true. |
:webhook_retries | SOCKETELX_WEBHOOK_RETRIES | 3 | Retries after the first attempt. 0 turns retries off. |
:webhook_retry_base_ms | none | 1000 | First retry delay; doubles each time. |
:rest_rate_limit | SOCKETELX_REST_RATE_LIMIT | none | Max REST API requests per second for the instance. |
:client_event_rate_limit | SOCKETELX_CLIENT_EVENT_RATE_LIMIT | none | Max client events per second, per connection. |
:max_connections | SOCKETELX_MAX_CONNECTIONS | none | Max WebSocket connections on this node. |
:batch_limit | SOCKETELX_BATCH_LIMIT | 10 | Max events in one batch_events request. Pusher's own limit is 10. |
:metrics | SOCKETELX_METRICS | false | Serve Prometheus metrics at GET /metrics. |
:metrics_token | SOCKETELX_METRICS_TOKEN | none | Require Authorization: Bearer <token> on /metrics. |
:cluster | SOCKETELX_CLUSTER | none | erlang turns on the experimental Redis-free cluster mode. Not combinable with :redis_url. See Multi-server. |
:cluster_nodes | SOCKETELX_CLUSTER_NODES | none | Comma-separated Erlang node names to connect to (socketelx@host1,socketelx@host2). Optional if your app already forms a cluster. |
:cluster_dns | SOCKETELX_CLUSTER_DNS | none | A hostname that resolves to every node's IP; nodes are named <basename>@<ip>. |
:cluster_node_basename | SOCKETELX_CLUSTER_NODE_BASENAME | socketelx | The part before the @ used with :cluster_dns. |
:name | none | Socketelx | Embedded only. Unique per instance. |
In Docker, cluster mode also uses the release's own variables, which are not
Socketelx settings: RELEASE_COOKIE (shared secret, required in practice),
RELEASE_NODE and RELEASE_DISTRIBUTION. See Multi-server.
:allowed_origins | SOCKETELX_ALLOWED_ORIGINS | all origins | Which websites may open a WebSocket. See Allowed origins. |
:max_connections_per_ip | SOCKETELX_MAX_CONNECTIONS_PER_IP | none | Simultaneous WebSocket connections per client IP. See Per-IP limit. |
:client_ip_header | SOCKETELX_CLIENT_IP_HEADER | none | Take the client IP from this header (behind a proxy). |
:webhook_queue_path | SOCKETELX_WEBHOOK_QUEUE_PATH | none | Directory where failed webhooks wait, so they survive a restart. |
:tls_certfile, :tls_keyfile | SOCKETELX_TLS_CERTFILE, SOCKETELX_TLS_KEYFILE | none | Serve HTTPS and WSS directly, without a proxy. |
:apps | SOCKETELX_APPS | none | Several apps in one server. See Several apps. |
One app, or several
By default a server has one app (one id, key and secret). To serve several apps from one port, see Several apps in one server.
Allowed origins
Browsers send an Origin header when opening a WebSocket. By default every
origin is accepted. To accept only your own sites:
SOCKETELX_ALLOWED_ORIGINS=https://chat.example.com,*.example.org
Each entry is one of:
| Entry | Matches |
|---|---|
https://chat.example.com | exactly that origin (scheme and port included) |
chat.example.com | that host on any scheme or port |
*.example.org | any subdomain of example.org, but not example.org itself |
* | everything (the default) |
A refused connection receives pusher:error 4009 and is closed. Connections
without an Origin header (backend scripts, mobile apps) are not affected: this
stops other websites from using your visitors' browsers, it is not a login. In
Elixir, pass a list: allowed_origins: ["https://chat.example.com"].
Per-IP limit
SOCKETELX_MAX_CONNECTIONS_PER_IP=20 allows each client address at most 20
simultaneous WebSocket connections (more get pusher:error 4100). Behind a
proxy or tunnel every connection looks like it comes from the proxy, so also set
SOCKETELX_CLIENT_IP_HEADER to the header your proxy fills in with the real
address (cf-connecting-ip on Cloudflare, x-forwarded-for for most others;
the first address in a list is used). Only set it when the proxy overwrites that
header, otherwise clients can fake it.
Built-in TLS
Set SOCKETELX_TLS_CERTFILE and SOCKETELX_TLS_KEYFILE (PEM files) and the
server speaks HTTPS and WSS on its port. Most deployments terminate TLS at a
proxy or Cloudflare instead, which is fine; use this when nothing sits in front.
Certificates are read at start, so restart to renew.
User sign-in and events to one user
pusher.signin() in pusher-js identifies the person behind a connection.
Point userAuthentication.endpoint at a route that calls
Socketelx.authenticate_user/4 (or signs socket_id::user::user_data with
HMAC-SHA256 in any language). Once signed in, an event triggered on the channel
#server-to-user-<id> reaches every connection of that user, on any node.
Client events
Clients can send client-* events on private and presence channels, only to
channels they are subscribed to, and never on public channels. Set
SOCKETELX_ENABLE_CLIENT_MESSAGES=false to refuse them all (the client receives
error 4301).
Webhooks
With SOCKETELX_WEBHOOK_URL set, the server POSTs JSON for these events:
channel_occupied,channel_vacatedmember_added,member_removed(presence channels)client_event
Each request carries X-Pusher-Key and X-Pusher-Signature (HMAC-SHA256 of the
raw body with your app secret), the same as Pusher's webhooks. Verify the
signature before trusting a request.
Delivery runs in the background and never blocks a connection. A failed
delivery (network error, timeout, HTTP 5xx, 408 or 429) is retried up to
SOCKETELX_WEBHOOK_RETRIES times (default 3) with a doubling delay: 1 s, 2 s,
4 s. Other 4xx responses are not retried, because the receiver rejected the
payload. Two things to design for:
- By default retries are held in memory, so a webhook still waiting for a retry
is lost if the node stops. Set
SOCKETELX_WEBHOOK_QUEUE_PATHto a directory (a mounted volume in Docker) and a webhook that failed its first attempt is saved there and sent again after a restart. It protects against the node restarting, not against losing the disk. - Retried events can arrive after later events, so make your receiver idempotent and don't rely on order.
Rate limits and capacity
All are off by default.
SOCKETELX_REST_RATE_LIMIT=100allows 100 REST API requests per second for the whole instance (the health check and/metricsare exempt). Extra requests get429withRetry-After: 1. Most server libraries treat that as a failed publish, so set it above your real peak.SOCKETELX_CLIENT_EVENT_RATE_LIMIT=10allows each connection 10 client events per second. Extra events are dropped and the client getspusher:error4301.SOCKETELX_MAX_CONNECTIONS=10000refuses new WebSocket connections on this node beyond that count withpusher:error4004. Clients reconnect, and with a load balancer they may land on another node.
The limits are per instance and per node. With several nodes, each node applies its own limit.
Metrics
Set SOCKETELX_METRICS=true and scrape GET /metrics (Prometheus text format).
Counters are per node and reset on restart; scrape every node.
| Metric | Type |
|---|---|
socketelx_connections | gauge: open WebSocket connections on this node |
socketelx_channels | gauge: channels with a subscriber on this node |
socketelx_connections_total, socketelx_connections_rejected_total | counter |
socketelx_subscriptions_total | counter |
socketelx_events_triggered_total | counter: events delivered via the REST API, one per channel |
socketelx_client_events_total, socketelx_client_events_rate_limited_total | counter |
socketelx_rest_requests_total, socketelx_rest_rate_limited_total | counter |
socketelx_webhooks_sent_total, socketelx_webhook_retries_total, socketelx_webhooks_failed_total | counter |
Set SOCKETELX_METRICS_TOKEN to require Authorization: Bearer <token>. Without
a token anyone who can reach the port can read /metrics, so block that path
at your proxy.
Redis
See Multi-server. Redis is used only when :redis_url is set.