Self-hosting a chat server: choices and architecture

自建聊天服务器:选型与架构(中文)

Want to run your own chat server — DMs inside your app, community super-groups, or customer support on your own metal? The problems you must solve are the same every time. This page breaks them down, compares the three common routes, and gives a reference architecture with real capacity numbers using IMCore as the example, so you can decide whether to buy, assemble, or build.

1. What a chat server actually has to solve

Getting from “can send a message” to production-grade is at least these eight things:

  1. Connection gateway: WebSocket long connections at scale, heartbeats, reconnects, routing of connection state.
  2. Reliable delivery: ACKs, retries, deduplication and ordering — “an occasionally dropped message” is not acceptable in production.
  3. Offline and push: messages persist when the peer is offline; APNs / vendor channels wake backgrounded apps.
  4. Group fan-out: one group message must reliably fan out to thousands of member connections — the core throughput bottleneck of any IM system.
  5. History and storage: conversation history, server-side search, multi-device sync; object storage for files, images and voice.
  6. Presence and receipts: online/offline, typing indicators, read receipts — each is a state machine, not one broadcast.
  7. Multi-device and accounts: concurrent logins, kick-out, message roaming.
  8. Security and compliance: transport encryption (wss/TLS), auth (JWT), moderation hooks, retention policy.

Most “build a chat room in a weekend” tutorials stop at item 1. The engineering bulk of a production system lives in items 2–6.

2. Choosing among the three routes

SaaS IM/support SDK Open-source assembly (XMPP/Matrix/oss IM) Self-hosted engine (IMCore et al.)
Time to launch Fastest — integrate the SDK Slow — assembly plus lots of glue code Fast — full server + client SDKs
Data sovereignty Data in the vendor’s cloud Fully yours Fully yours
Cost model Recurring MAU/seat fees Free in theory, expensive in headcount One-time license (with a free Basic tier)
Production hardening Vendor’s job Push, moderation, clustering, monitoring — all yours Ships with the release
Customization depth SDK boundaries Unlimited (you write it) Server APIs + UIKit at source level

Rules of thumb:

  • Demo phase / non-sensitive use → a SaaS SDK is fastest.
  • Dedicated IM team evolving your own protocol long-term → open-source assembly or full self-build.
  • Data must stay on your infrastructure yet you don’t want to reinvent the wheel (finance, healthcare, government, compliance-driven products, or chat as a core product feature) → a self-hosted engine is the “both” answer.

Head-to-head tables against specific competitors live on the comparison pages.

3. Reference architecture: single node to cluster

Single node (Basic edition):

clients ──wss──> [websocket server] ──> PostgreSQL (messages/accounts/history)
                        │
                        └──> Redis (presence / routing cache / session state)

One binary (or container) plus PostgreSQL and Redis is the complete server. This is the simplest deployment (see Production deployment with Docker Compose) and covers most small-to-medium self-hosted scenarios.

Clustered (Pro and up):

clients ──> [websocket × N] ──shared──> Redis (state)
                 │
                 └──> message queue (RabbitMQ / NATS / Redis Streams)
                          │
                 [persist_consumer × N] ──> PostgreSQL (batch writes)

Multiple instances fan out and persist through the queue and scale horizontally; every replica shares the same Redis and broker. No client code changes — the upgrade is purely a deployment change.

4. Capacity reference: measured numbers

Saturation test of a single IMCore instance (4C8G, multi-room scenario, 200 msg/s send rate):

Concurrent connections Fan-out p50 p99 Errors
5,000 19,222 msg/s 52ms 93ms 0
10,000 38,506 msg/s 83ms 153ms 0

One 4C8G instance carries ten thousand concurrent connections and nearly 40k group fan-out messages per second at p99 under 155ms; beyond that, scale out via the clustered topology. For capacity planning, estimate fan-out demand as “peak concurrency × group amplification factor” and compare against instance sizing.

5. Pre-launch security checklist

  • Expose only 443 (wss/TLS); database, Redis and the queue stay on the internal network (the Compose guide shows the isolated topology).
  • Clients authenticate with JWTs minted by your own backend; never ship the signing secret inside a client bundle.
  • Daily database backups stored off-host; retention policy aligned with your compliance requirements.
  • Wire moderation hooks into the send path before public launch (Pro includes moderation callbacks).

Next steps