Ubuntu 22.04 安装 Centrifugo 指南

在 Ubuntu 22.04 服务器安装 Centrifugo v6.10.1:packagecloud 在线源、deb 离线包、tar.gz 二进制三种方案实测与 systemd 托管,含生成 JWT、连接订阅、HTTP API 发布、消息送达全链路验证。

Centrifugo即时通信Centrifugo2026/10/21

Ubuntu 22.04 安装 Centrifugo 指南

目标:在 Ubuntu 22.04 服务器上从零安装 Centrifugo v6.10.1 实时消息服务器,覆盖在线仓库、deb 离线包、tar.gz 二进制三种安装方案与 systemd 托管,并完成「生成 JWT → 建立连接 → 订阅频道 → HTTP API 发布 → 消息送达」全链路验证。已在 Ubuntu 22.04.5 LTS(x86_64)服务器实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64),systemd 运行中
  • Centrifugo 版本:v6.10.1(Go version: go1.27.3)
  • 服务器主机名:centrifugo-server
  • 服务监听:0.0.0.0:8130(默认端口 8000,本机 8000 已被其他服务占用,本文统一调整为 8130,调整方法见 4.5 节)
  • 配置文件:/etc/centrifugo/config.json(JSON 格式,v6 起为嵌套结构)
  • systemd 服务:centrifugo.service(随 deb/rpm 包提供)
  • 运行用户:centrifugo(系统用户,uid 999,shell 为 /bin/false,家目录 /var/lib/centrifugo)
  • 数据/日志目录:/var/lib/centrifugo、/var/log/centrifugo
  • 软件包来源:packagecloud.io/FZambia/centrifugo(官方 apt/yum 仓库)与 GitHub Releases(离线包)

二、前置条件

  1. 一台 64 位 Linux 服务器(amd64 / arm64 / armv6 均有官方构建),本文以 Ubuntu 22.04 amd64 为准。Centrifugo 是 Go 语言编译的单二进制程序,无任何外部运行时依赖(不需要 JDK、Python、Node 等),空载常驻内存约 30 MB,1 核 1 GB 的云主机即可稳定跑通本文全部内容。
  2. 具备 sudo/root 权限。
  3. 安装基础下载工具(在线方案需要):
sudo apt-get update && sudo apt-get install -y curl wget
  1. 服务器需可访问外网(在线方案 A);断网服务器走方案 B/C,仅需能从内网跳板机传入安装包。
  2. 如服务器启用了防火墙(ufw),放行 Centrifugo 对外端口(本文为 8130):
sudo ufw allow 8130/tcp

三、版本选型说明

3.1 版本现状

截至 2026-10-21 查询 GitHub centrifugal/centrifugo 仓库 Releases:最新稳定版为 v6.10.1(v6.10.0 的补丁版),同日可见的版本序列为 v6.10.1 → v6.10.0 → v6.10.0-rc.1(预发布)→ v6.9.7 …,v6 系列处于活跃维护期,补丁版本迭代密集。本文选择 v6.10.1。

从 v6.10.0 起,官方对发布产物启用了 Sigstore 无密钥签名(keyless signing),并随版本提供 SBOM(软件物料清单)与 SHA-256 校验文件,离线场景可以逐项验证安装包完整性(见 5.2 节)。

3.2 官方包支持的发行版

官方 deb/rpm 包支持(摘自 centrifugal.dev 安装文档,查询日期 2026-10-21):64 位 Debian 10/11/12、Ubuntu 20.04/22.04/24.04、CentOS 7。32 位架构二进制可用但不再提供打包。Ubuntu 22.04 正好在官方支持列表内。

3.3 v6.10.1 Release 资产清单(GitHub Releases)

资产名说明
centrifugo_6.10.1-0_amd64.debDebian/Ubuntu 离线 deb 包(注意版本号带 -0 后缀)
centrifugo-6.10.1-0.x86_64.rpmRHEL/CentOS 离线 rpm 包
centrifugo_6.10.1_linux_amd64.tar.gzLinux amd64 二进制压缩包(方案 C)
centrifugo_6.10.1_linux_arm64.tar.gzLinux arm64 二进制压缩包
centrifugo_6.10.1_checksums.txt全部产物的 SHA-256 校验值
centrifugo_6.10.1_checksums.txt.sigstore.jsonSigstore 签名文件
*.sbom.json各产物对应的 SBOM

关键差异:deb/rpm 包自带 systemd 单元、logrotate 配置、专用系统用户并自动生成含随机密钥的初始配置,适合直接上服务器;tar.gz 只有一个裸二进制,适合无包管理器的环境与多版本并存管理。三种方案完整对比见第七章。

四、在线安装方案(A:官方 packagecloud apt 源,推荐)

4.1 方案说明

官方将 deb/rpm 包发布在 packagecloud.io 托管的软件仓库,仓库路径为 FZambia/centrifugo(FZambia 是 Centrifugo 作者 German Sokolov 的账号名,官方安装文档指向该仓库)。添加源后 apt install 一步完成安装,后续 apt upgrade 可随系统升级,这是有外网服务器的首选方案。

4.2 添加软件源

一条管道命令完成仓库注册与 GPG 密钥导入:

curl -fsSL "https://packagecloud.io/install/repositories/FZambia/centrifugo/script.deb.sh" | sudo bash

实测回显(末尾节选):

Installing /etc/apt/sources.list.d/FZambia_centrifugo.list...done.
Importing packagecloud gpg key... Packagecloud gpg key imported to /etc/apt/keyrings/FZambia_centrifugo-archive-keyring.gpg
done.
Running apt-get update... done.

The repository is setup! You can now install packages.

⚠️ 排障实录:网络上大量旧教程把仓库路径写成 centrifugo/centrifugo,执行脚本会直接报 curl: (22) The requested URL returned error: 404。官方文档(centrifugal.dev/docs/getting-started/installation)明确的仓库路径是 FZambia/centrifugo,请以官方文档为准。

4.3 安装

sudo apt-get install -y centrifugo

实测回显(节选):

Fetched 42.3 MB in 12s (3391 kB/s)
Selecting previously unselected package centrifugo.
(Reading database ... 7333 files and directories currently installed.)
Preparing to unpack .../centrifugo_6.10.1-0_amd64.deb ...
Unpacking centrifugo (6.10.1-0) ...
Setting up centrifugo (6.10.1-0) ...

验证版本:

centrifugo version

实测回显:

Centrifugo v6.10.1 (Go version: go1.27.3)

4.4 了解包安装布局

dpkg -L centrifugo

实测回显:

/.
/etc
/etc/logrotate.d
/etc/logrotate.d/centrifugo
/etc/centrifugo
/usr
/usr/share
/usr/share/doc
/usr/share/doc/centrifugo
/usr/share/doc/centrifugo/changelog.gz
/usr/lib
/usr/lib/centrifugo
/usr/lib/centrifugo/scripts
/usr/lib/centrifugo/scripts/centrifugo.service
/usr/lib/centrifugo/scripts/initd.sh
/usr/lib/centrifugo/scripts/centrifugo.upstart
/usr/lib/centrifugo/scripts/initd.el6.sh
/usr/bin
/usr/bin/centrifugo

要点:二进制在 /usr/bin/centrifugo;systemd 单元模板在 /usr/lib/centrifugo/scripts/,安装脚本会将其部署为 /lib/systemd/system/centrifugo.service(Ubuntu 22.04 上 /lib 是 /usr/lib 的符号链接);logrotate 轮转配置在 /etc/logrotate.d/centrifugo(daily、保留 7 份、copytruncate、压缩)。

安装脚本同时完成三件事:创建系统用户 centrifugo(uid 999)、创建空的 /etc/default/centrifugo 环境变量文件、首次安装时自动生成含随机密钥的初始配置 /etc/centrifugo/config.json。

查看服务单元内容(后续排障会用到):

cat /lib/systemd/system/centrifugo.service

实测回显:

[Unit]
Description=Centrifugo real-time messaging server
Documentation=https://github.com/centrifugal/centrifugo
# start once the network and logging subsystems available
After=network.target

[Service]
User=centrifugo
Group=centrifugo
LimitNOFILE=65536
Environment="CONFIG=/etc/centrifugo/config.json"
EnvironmentFile=/etc/default/centrifugo
ExecStartPre=/usr/bin/centrifugo checkconfig -c $CONFIG
ExecStart=/usr/bin/centrifugo -c $CONFIG $CENTRIFUGO_OPTS
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -SIGTERM $MAINPID
TimeoutStopSec=10
KillMode=control-group
RestartSec=1
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=centrifugo.service

三个值得记住的设计:ExecStartPre 先跑 centrifugo checkconfig 做配置预检,配置非法时服务不会带病启动;ExecReload 发送 SIGHUP 让服务热重载配置(无需重启进程);Restart=on-failure 异常退出自动拉起。

4.5 修复配置文件权限(v6.10.1-0 包必踩的坑)

直接启动服务会失败:

sudo systemctl start centrifugo

实测回显:

Job for centrifugo.service failed because the control process exited with error code.
See "systemctl status centrifugo.service" and "journalctl -xeu centrifugo.service" for details.

定位根因:

journalctl -u centrifugo --no-pager | tail -5

实测回显:

Oct 21 14:55:06 centrifugo-server centrifugo[3517]: config file not found
Oct 21 14:55:06 centrifugo-server systemd[1]: centrifugo.service: Control process exited, code=exited, status=1/FAILURE
Oct 21 14:55:06 centrifugo-server systemd[1]: centrifugo.service: Failed with result 'exit-code'.
Oct 21 14:55:06 centrifugo-server systemd[1]: Failed to start Centrifugo real-time messaging server.
Oct 21 14:55:07 centrifugo-server systemd[1]: centrifugo.service: Start request repeated too quickly.

报错文案是 config file not found,但文件明明存在——查看权限即水落石出:

ls -la /etc/centrifugo/config.json

实测回显:

-rw------- 1 root root 490 Oct 21 14:54 /etc/centrifugo/config.json

根因:安装脚本以 root 身份调用 centrifugo genconfig 生成初始配置,而 Centrifugo 出于安全考虑以 0600 权限写配置文件(配置里含 HMAC 密钥等敏感信息,程序显式指定权限,与 umask 无关)。但服务单元以 User=centrifugo 普通用户运行,读不到这个 root 私有文件,于是抛出误导性的 config file not found。修复方式是把配置属组交给 centrifugo 并放开组读:

sudo chown root:centrifugo /etc/centrifugo/config.json
sudo chmod 640 /etc/centrifugo/config.json
ls -la /etc/centrifugo/config.json

实测回显:

-rw-r----- 1 root centrifugo 490 Oct 21 15:04 /etc/centrifugo/config.json

4.6 调整监听端口(8000 → 8130)

Centrifugo 默认监听 8000 端口。本机 8000 已被其他服务占用,因此本文将监听端口调整为 8130,后续所有命令与验证均基于 8130(如果你的 8000 空闲,可以保留默认值,把下述配置中的 8130 换回 8000 即可)。

编辑 /etc/centrifugo/config.json,加入 http_server 段(v6 起配置为嵌套 JSON,完整参数解析见《Centrifugo 6.10 配置参数详解》):

sudo python3 - <<'PYEOF'
import json
cfg = json.load(open("/etc/centrifugo/config.json"))
cfg["http_server"] = {"address": "0.0.0.0", "port": 8130}
json.dump(cfg, open("/etc/centrifugo/config.json", "w"), indent=2)
PYEOF

改后先跑一次配置预检再启动(与服务单元的 ExecStartPre 行为一致):

sudo centrifugo checkconfig -c /etc/centrifugo/config.json && echo CONFIG_OK

实测回显:

CONFIG_OK

💡 说明:checkconfig 对合法配置静默通过(退出码 0,无输出)。它还有 -s/--strict 严格模式,会拒绝配置文件里的未知字段,适合版本升级时兜底校验,用法详见《Centrifugo 6.10 常用 CLI 命令详解》。

4.7 systemd 托管与开机自启

sudo systemctl enable centrifugo
sudo systemctl restart centrifugo

验证运行状态:

systemctl is-active centrifugo
systemctl status centrifugo --no-pager

实测回显(节选,省略 CGroup 详情行):

active
● centrifugo.service - Centrifugo real-time messaging server
     Loaded: loaded (/lib/systemd/system/centrifugo.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2026-10-21 15:04:39 UTC; 2s ago
       Docs: https://github.com/centrifugal/centrifugo
     Process: 3832 ExecStartPre=/usr/bin/centrifugo checkconfig -c $CONFIG (code=exited, status=0/SUCCESS)
   Main PID: 3842 (centrifugo)
      Tasks: 12 (limit: 94371)
     Memory: 26.9M

启动日志确认所有端点已挂载:

journalctl -u centrifugo --no-pager -n 5

实测回显(末行节选):

Oct 21 15:04:39 centrifugo-server centrifugo[3842]: {"level":"info","version":"6.10.1","runtime":"go1.27.3","pid":3842,"gomaxprocs":12,"engine":"memory","time":"2026-10-21T15:04:39Z","message":"starting Centrifugo"}
Oct 21 15:04:39 centrifugo-server centrifugo[3842]: {"level":"info","algorithms":"HS256, HS384, HS512","time":"2026-10-21T15:04:39Z","message":"enabled JWT verifiers"}
Oct 21 15:04:39 centrifugo-server centrifugo[3842]: {"level":"info","time":"2026-10-21T15:04:39Z","message":"serving websocket, api endpoints on :8000"}

💡 说明:日志为 JSON 行格式(level/version/pid/message 等字段),engine":"memory" 表示当前使用内置内存引擎(单机模式);配置了 Redis 引擎后此处会变为 redis。日志级别的调整方法见配置详解篇。

4.8 HTTP 端点验证

默认配置下服务只开了 websocket 连接端点与 HTTP API。为便于运维验证,本文在 /etc/centrifugo/config.json 中补充开启健康检查、Prometheus 指标与 Swagger 文档三个端点(追加三个顶层段即可,改完 systemctl restart centrifugo):

"health":     { "enabled": true },
"prometheus": { "enabled": true },
"swagger":    { "enabled": true }

逐个验证(注意本文端口为 8130):

curl -s -o /dev/null -w "health: %{http_code}\n" http://127.0.0.1:8130/health
curl -s -o /dev/null -w "metrics: %{http_code}\n" http://127.0.0.1:8130/metrics
curl -s -o /dev/null -w "swagger: %{http_code}\n" http://127.0.0.1:8130/swagger/

实测回显:

health: 200
metrics: 200
swagger: 200

重启后再看日志,挂载端点清单已经变化(对照 4.7 节只有 websocket、api):

Oct 21 15:09:26 centrifugo-server centrifugo[4035]: {"level":"info","time":"2026-10-21T15:09:26Z","message":"serving websocket, http_stream, sse, emulation, api, admin, prometheus, health, swagger endpoints on 0.0.0.0:8130"}

(该行来自本文实验环境,额外开启了 sse/http_stream/admin 端点,读者未开启这些端点时清单会短一些。)

4.9 端到端消息链路验证(token → 连接 → 订阅 → 发布 → 送达)

这是安装成功的最终判据:走通「生成连接 JWT → WebSocket 连接并订阅 → 服务端 HTTP API 发布消息 → 客户端收到推送」完整链路。

第一步,签发一个用户 ID 为 42、有效期 1 小时的连接 JWT:

centrifugo gentoken -c /etc/centrifugo/config.json -u 42 -t 3600 -q

实测回显:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsImV4cCI6MTc5MjU5OTEyOCwiaWF0IjoxNzkyNTk1NTI4fQ.2RmvtVqaHZE2FmHOVBIzgickqp2mqH9_EQCSZsmuISs

第二步,为了让客户端能自主订阅频道,在配置中声明一个 chat 频道命名空间并放开客户端订阅权限(allow_subscribe_for_client 默认为 false,这是 v6 的安全默认值),追加 channel 段后重启服务:

"channel": {
  "namespaces": [
    {
      "name": "chat",
      "allow_subscribe_for_client": true
    }
  ]
}

第三步,安装 Python WebSocket 客户端库(服务器本机自测用):

sudo apt-get install -y python3-websocket

第四步,将下面脚本保存为 chain_test.py(订阅的频道名必须带命名空间前缀,写作 chat:main,直接写 chat 会落到无命名空间默认策略而被拒):

import websocket, json, threading, time, sys, urllib.request

TOKEN = sys.argv[1]   # 第一步生成的连接 JWT
APIKEY = "你的 http_api.key,见 /etc/centrifugo/config.json"

ws = websocket.create_connection("ws://127.0.0.1:8130/connection/websocket", timeout=10)
ws.send(json.dumps({"id": 1, "connect": {"token": TOKEN, "name": "pyclient"}}))
print("<<", ws.recv())                                # 连接回执
ws.send(json.dumps({"id": 2, "subscribe": {"channel": "chat:main"}}))
print("<<", ws.recv())                                # 订阅回执

def publish():
    time.sleep(1)
    req = urllib.request.Request("http://127.0.0.1:8130/api",
        data=json.dumps({"method": "publish", "params": {"channel": "chat:main", "data": {"text": "hello from api"}}}).encode(),
        headers={"X-API-Key": APIKEY, "Content-Type": "application/json"})
    print("API publish resp:", urllib.request.urlopen(req).read().decode())

threading.Thread(target=publish).start()
print("<<", ws.recv())                                # 收到推送
ws.close()

⚠️ 两个高频坑都写进了脚本:其一,v6 客户端协议的每条命令必须携带自增 id 字段,漏掉会收到 3501 bad request 断连(服务端源码对 id == 0 的命令直接拒绝);其二,浏览器型客户端必须被 client.allowed_origins 放行,Python websocket-client 默认携带 Origin 头,若配置保持默认空数组,握手阶段就会收到 403 Forbidden,本文示例配置需将其设为 "allowed_origins": ["*"](生产环境建议收敛为精确域名列表)。

第五步,运行脚本(TOKEN 与 APIKEY 换成你自己的实际值):

python3 chain_test.py "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI0MiIsImV4cCI6MTc5MjU5OTEyOCwiaWF0IjoxNzkyNTk1NTI4fQ.2RmvtVqaHZE2FmHOVBIzgickqp2mqH9_EQCSZsmuISs"

实测回显(密钥值各环境不同,结构一致):

<< {"id":1,"connect":{"client":"a86c3f2a-0894-4449-bb78-d900e5207b15","version":"6.10.1 OSS","expires":true,"ttl":3600,"ping":25,"pong":true}}
<< {"id":2,"subscribe":{}}
<< {"push":{"channel":"chat:main","pub":{"data":{"text": "hello from api"}}}}
API publish resp: {"result":{}}

四行输出对应四个里程碑:connect 回执(含服务端版本、连接过期时间与心跳参数 ping=25s)→ subscribe 空对象表示订阅成功 → push.pub.data 收到 API 发布的原始消息 → HTTP API 返回 {"result":{}}。看到第三行 push 即全链路打通。

五、deb 离线包安装方案(B:断网服务器)

5.1 方案说明

内网隔离服务器无法访问 packagecloud,可直接使用 GitHub Releases 提供的 deb 包。该包与仓库源的包完全同源(同一 CI 产物),区别只是分发渠道。需要在一台能上网的机器上下载并校验,再传入内网。

5.2 下载与 SHA-256 校验

在有外网的机器上下载 deb 包与官方校验文件:

wget https://github.com/centrifugal/centrifugo/releases/download/v6.10.1/centrifugo_6.10.1-0_amd64.deb
wget https://github.com/centrifugal/centrifugo/releases/download/v6.10.1/centrifugo_6.10.1_checksums.txt

⚠️ 排障实录:资产名必须带 -0。按直觉拼出的 centrifugo_6.10.1_linux_amd64.deb 会得到 ERROR 404: Not Found,正确名称是 centrifugo_6.10.1-0_amd64.deb(tar.gz 反而不带 -0)。

用官方校验文件核对 SHA-256(--ignore-missing 表示只校验本地已下载的文件):

sha256sum -c --ignore-missing centrifugo_6.10.1_checksums.txt

实测回显:

centrifugo_6.10.1-0_amd64.deb: OK

5.3 安装

把 deb 包传入内网服务器(scp/介质均可)后安装。推荐用 apt install 携带本地路径,能自动处理依赖关系:

sudo apt install ./centrifugo_6.10.1-0_amd64.deb

实测回显(在已装同版本的服务器上重装演示,首次安装输出结构一致):

Selecting previously unselected package centrifugo.
(Reading database ... 7344 files and directories currently installed.)
Preparing to unpack .../centrifugo_6.10.1-0_amd64.deb ...
Unpacking centrifugo (6.10.1-0) over (6.10.1-0) ...
Setting up centrifugo (6.10.1-0) ...

也可以用 sudo dpkg -i centrifugo_6.10.1-0_amd64.deb,输出相同;若依赖报错,补一句 sudo apt-get -f install 即可。

5.4 配置与 systemd 托管

与方案 A 完全一致:安装脚本同样生成配置、创建用户、部署单元。按 4.5 节修复配置权限、按 4.6 节调整端口后,执行:

sudo systemctl enable centrifugo
sudo systemctl start centrifugo
systemctl is-active centrifugo

实测回显:

active

5.5 验证

centrifugo version
curl -s -o /dev/null -w "health: %{http_code}\n" http://127.0.0.1:8130/health

实测回显:

Centrifugo v6.10.1 (Go version: go1.27.3)
health: 200

六、tar.gz 二进制安装方案(C:任意 Linux + 多版本管理)

6.1 方案说明

官方 tar.gz 只含一个静态编译的 centrifugo 二进制与文档文件,适合三类场景:无法使用 deb/rpm 的发行版、需要多版本并存随时回滚、以及希望把二进制放进自建目录规范管理。代价是 systemd 单元、系统用户、logrotate 都要自己搭。本方案给出生产可用的完整手工托管流程。

6.2 下载、校验与解压

wget https://github.com/centrifugal/centrifugo/releases/download/v6.10.1/centrifugo_6.10.1_linux_amd64.tar.gz
wget https://github.com/centrifugal/centrifugo/releases/download/v6.10.1/centrifugo_6.10.1_checksums.txt
sha256sum -c --ignore-missing centrifugo_6.10.1_checksums.txt

实测回显:

centrifugo_6.10.1_linux_amd64.tar.gz: OK

按版本号解压到独立目录(这个目录结构就是多版本管理的载体):

sudo mkdir -p /opt/centrifugo-6.10.1
sudo tar -xzf centrifugo_6.10.1_linux_amd64.tar.gz -C /opt/centrifugo-6.10.1
ls -la /opt/centrifugo-6.10.1

实测回显:

total 64520
drwxr-xr-x 2 root root     4096 Oct 21 15:28 .
drwxr-xr-x 1 root root     4096 Oct 21 15:28 ..
-rw-r--r--   1 1001 1001   100884 Oct 20 17:13 CHANGELOG.md
-rw-r--r--   1 1001 1001    11351 Oct 20 17:13 LICENSE
-rw-r--r--   1 1001 1001     7838 Oct 20 17:13 README.md
-rwxr-xr-x   1 1001 1001 65652736 Oct 20 17:13 centrifugo

验证二进制可独立运行:

/opt/centrifugo-6.10.1/centrifugo version

实测回显:

Centrifugo v6.10.1 (Go version: go1.27.3)

6.3 创建专用用户、目录与软链

sudo useradd --system -U -M centrifugo -s /bin/false -d /var/lib/centrifugo
sudo mkdir -p /var/lib/centrifugo /var/log/centrifugo /etc/centrifugo
sudo chown -R centrifugo:centrifugo /var/lib/centrifugo /var/log/centrifugo
sudo ln -sfn /opt/centrifugo-6.10.1/centrifugo /usr/local/bin/centrifugo

验证软链生效:

centrifugo version

实测回显:

Centrifugo v6.10.1 (Go version: go1.27.3)

6.4 生成配置文件

用 genconfig 子命令生成含随机密钥的最小配置(生成的密钥每次运行都不同):

sudo centrifugo genconfig -c /etc/centrifugo/config.json
sudo centrifugo checkconfig -c /etc/centrifugo/config.json && echo CONFIG_OK

实测回显:

CONFIG_OK

按 4.5/4.6 节同样处理:把端口改为 8130、按需开启 health 端点、并修正权限(tar.gz 方案没有安装脚本代劳,权限步骤同样不能省):

sudo chown root:centrifugo /etc/centrifugo/config.json
sudo chmod 640 /etc/centrifugo/config.json

6.5 手工编写 systemd 单元

写入 /etc/systemd/system/centrifugo.service(字段含义与官方包一致,路径改为本方案的实际路径):

[Unit]
Description=Centrifugo real-time messaging server
Documentation=https://github.com/centrifugal/centrifugo
After=network.target

[Service]
User=centrifugo
Group=centrifugo
LimitNOFILE=65536
Environment="CONFIG=/etc/centrifugo/config.json"
ExecStartPre=/usr/local/bin/centrifugo checkconfig -c $CONFIG
ExecStart=/usr/local/bin/centrifugo -c $CONFIG
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -SIGTERM $MAINPID
TimeoutStopSec=10
KillMode=control-group
RestartSec=1
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable centrifugo
sudo systemctl start centrifugo
systemctl is-active centrifugo

实测回显:

active

6.6 验证

curl -s -o /dev/null -w "health: %{http_code}\n" http://127.0.0.1:8130/health
journalctl -u centrifugo --no-pager -n 3

实测回显(health 行 + 日志末行):

health: 200
Oct 21 15:30:10 centrifugo-server centrifugo[5312]: {"level":"info","time":"2026-10-21T15:30:10Z","message":"serving websocket, api endpoints on 0.0.0.0:8130"}

之后按 4.9 节做端到端链路验证即可,两种安装方式的服务行为完全一致。

6.7 多版本并存与升级回滚

tar.gz 方案天然支持多版本并存:新版本解压到新目录、切换软链、重启服务,即可完成升级;回滚只需把软链切回旧目录:

sudo ln -sfn /opt/centrifugo-6.10.1/centrifugo /usr/local/bin/centrifugo
sudo systemctl restart centrifugo

💡 说明:软链切换前的 /usr/local/bin/centrifugo 指向目标保持不变即可实现"指回旧版本即回滚"。升级前建议用新版本二进制跑一次 checkconfig -s(严格模式,拒绝未知配置字段),确认配置与新版本兼容——Centrifugo 大版本升级时常有配置项改名或移除。

七、方案对比与选择建议

维度A:packagecloud 在线源B:deb 离线包C:tar.gz 二进制
是否需联网安装时需要仅下载机需要仅下载机需要
安装方式apt install 一步到位apt install ./xxx.deb 或 dpkg -i手工解压+建用户+写单元
systemd 单元自动部署自动部署手工编写
专用系统用户自动创建自动创建手工创建
logrotate自动配置自动配置手工配置
配置初始生成自动(含随机密钥)自动(含随机密钥)genconfig 生成
版本管理apt upgrade / 指定版本换包重装多目录+软链,最灵活
适用场景可联网的生产服务器内网隔离的 Debian/Ubuntu特殊发行版/多版本测试

选择建议:能联网直接选 A,一条 curl 管道换来长期 apt 升级能力;内网服务器选 B,包内容与 A 完全同源且同样自动配好 systemd;需要多版本并存、灰度升级或在非 Debian 系发行版上运行,选 C。

八、配置说明(三种方案共用)

8.1 配置文件与初始密钥

配置文件统一在 /etc/centrifugo/config.json(方案 C 为自定义路径)。v6 的配置是嵌套 JSON,deb/rpm 安装时由 genconfig 自动生成的初始结构如下(密钥为安装时随机生成的示例值,读者环境的值不同):

{
  "client": {
    "token": {
      "hmac_secret_key": "rrhvFSIZo7M1Sd32xolB0rr5bvK4OPGRoNW5D2whDdD_eYk8XYU1E1ODUJ-W4d8WGjA3dU-28-_d2cgEiu8Rtg"
    },
    "allowed_origins": []
  },
  "admin": {
    "enabled": false,
    "password": "isao90S5n3kxQ7q381WBiQ",
    "secret": "7OiEJ6VWrZwE5-n8bTZZONDyKYPqkVpgzS18EMsIqFzGGkwltGzQysSXe0CrqUNn0h26L6YTnFYsB2RhetRPNA"
  },
  "http_api": {
    "key": "--WZmsF-2PDKd3GpbPDRAKqvHTQwI9xdspqkMEGUB3VAhKWZnn2SfBaebicBt7SxFTgosFWa7N3_J9GbUYI9xQ"
  }
}

三个密钥的分工:client.token.hmac_secret_key 用于签发/校验连接 JWT(HS256 系列算法);http_api.key 是服务端调用 HTTP API 的凭据(请求头 X-API-Key);admin.password/secret 用于内置管理界面登录。本文实验环境将 admin.password 修改为 q1w2e3r4 并开启管理端点用于验证("admin": {"enabled": true, "external": true}),登录测试账号即 admin 角色口令 q1w2e3r4。管理界面无需单独端口,开启后直接访问服务根路径 http://127.0.0.1:8130/(页面标题为 Centrifugo admin web UI),认证接口实测为表单方式:

curl -s -X POST -d "password=q1w2e3r4" http://127.0.0.1:8130/admin/auth -w " http:%{http_code}"

实测回显:

{"token":"MTc5MjU5NjE2M3xEUXdBQ21GMWRHaHZjbWw2WldRPXwM9uF9x5Qow2Zc18L9ltHegUzAwwjgmi5MYbyjdk9flg=="} http:200

8.2 本文实验环境的完整配置

综合前面所有调整(端口 8130、放开 Origin、开启辅助端点、chat 命名空间),本文最终使用的完整配置如下,可直接作为最小可用模板:

{
  "http_server": {
    "address": "0.0.0.0",
    "port": 8130
  },
  "log": {
    "level": "info"
  },
  "client": {
    "token": {
      "hmac_secret_key": "rrhvFSIZo7M1Sd32xolB0rr5bvK4OPGRoNW5D2whDdD_eYk8XYU1E1ODUJ-W4d8WGjA3dU-28-_d2cgEiu8Rtg"
    },
    "allowed_origins": ["*"]
  },
  "admin": {
    "enabled": true,
    "external": true,
    "password": "q1w2e3r4",
    "secret": "7OiEJ6VWrZwE5-n8bTZZONDyKYPqkVpgzS18EMsIqFzGGkwltGzQysSXe0CrqUNn0h26L6YTnFYsB2RhetRPNA"
  },
  "http_api": {
    "key": "--WZmsF-2PDKd3GpbPDRAKqvHTQwI9xdspqkMEGUB3VAhKWZnn2SfBaebicBt7SxFTgosFWa7N3_J9GbUYI9xQ"
  },
  "health": {
    "enabled": true
  },
  "prometheus": {
    "enabled": true
  },
  "swagger": {
    "enabled": true
  },
  "sse": {
    "enabled": true
  },
  "http_stream": {
    "enabled": true
  },
  "channel": {
    "namespaces": [
      {
        "name": "chat",
        "allow_subscribe_for_client": true,
        "history_size": 10,
        "history_ttl": "1h"
      }
    ]
  }
}

逐项说明:http_server 绑定全部网卡并把端口改为 8130(默认 8000 被占用时的调整点);client.allowed_origins 放开浏览器来源校验(["*"] 仅供联调,生产应写精确域名,服务端也会对 * 打出 discourage 警告日志);admin 开启管理界面并暴露在外部端口;health/prometheus/swagger 三个运维端点(/health、/metrics、/swagger/);sse/http_stream 开启 WebSocket 之外的两个双向传输端点;channel.namespaces 声明 chat 命名空间允许客户端订阅并保留最近 10 条、1 小时内的历史消息。所有参数的完整语义、默认值与环境变量覆盖方式见《Centrifugo 6.10 配置参数详解》。

8.3 日常运维命令

sudo systemctl restart centrifugo   # 重启(加载所有配置变更)
sudo systemctl reload centrifugo    # 热重载配置(SIGHUP,不中断现有连接)
systemctl is-active centrifugo      # 运行状态
journalctl -u centrifugo -f         # 跟踪日志

热重载实测:修改配置后执行 systemctl reload centrifugo,日志出现确认行:

Oct 21 15:25:52 centrifugo-server centrifugo[4746]: {"level":"info","time":"2026-10-21T15:25:52Z","message":"configuration successfully reloaded"}

8.4 升级、降级与多版本管理(apt 体系)

查看仓库里可用的全部版本:

apt-cache policy centrifugo

实测回显:

centrifugo:
  Installed: 6.10.1-0
  Candidate: 6.10.1-0
  Version table:
 *** 6.10.1-0 500
        500 https://packagecloud.io/FZambia/centrifugo/ubuntu jammy/main amd64 Packages
        100 /var/lib/dpkg/status
     6.10.0-0 500

升级与降级都走同一条指定版本安装命令:

sudo apt-get install -y centrifugo=6.10.1-0    # 升级/保持
sudo apt-get install -y centrifugo=6.10.0-0    # 降级到上一版

降级前请先停止服务并用新版本语义校验过的配置做好备份;配置项在跨版本时可能增删,建议每次变更版本后执行 centrifugo checkconfig -s -c /etc/centrifugo/config.json 做严格校验。锁版本防误升:

sudo apt-mark hold centrifugo

tar.gz 方案的多版本管理见 6.7 节。

九、常见问题(FAQ)

Q1:执行 packagecloud 安装脚本报 curl: (22) The requested URL returned error: 404? 仓库路径写错了。正确的是 https://packagecloud.io/install/repositories/FZambia/centrifugo/script.deb.sh,把 FZambia 写成 centrifugo 就会 404。官方文档安装指引见参考链接。

Q2:服务起不来,journalctl 显示 config file not found,但文件明明存在? 配置文件权限问题(详见 4.5 节实测):genconfig 以 0600 权限写配置,服务以 centrifugo 用户运行读不到。执行 sudo chown root:centrifugo /etc/centrifugo/config.json && sudo chmod 640 /etc/centrifugo/config.json 后重启即可。这个错误文案有误导性,本质是「无权限读」而非「文件不存在」。

Q3:客户端 WebSocket 握手收到 403 Forbidden? 服务端按 client.allowed_origins 校验请求的 Origin 头,默认空数组拒绝所有浏览器来源。联调期可临时设 ["*"],生产环境写精确域名列表(如 ["https://app.example.com"])。服务端对 * 会输出警告日志 usage of allowed_origins * is discouraged for security reasons, consider setting exact list of origins。

Q4:WebSocket 连上后立刻被断开,服务端日志显示 bad request(关闭码 3501)? v6 客户端协议要求每条命令携带自增整数 id 字段(如 {"id":1,"connect":{...}}),缺失 id 的命令被服务端直接拒绝并断连。服务端 debug 日志中对应的判定是 cmd.Id == 0 分支。给每条命令补上 id 即可。

Q5:订阅频道返回 {"error":{"code":103,"message":"permission denied"}}? 两种原因:其一,v6 默认禁止客户端主动订阅任何频道,需要频道所属命名空间配置 allow_subscribe_for_client: true(或改用服务端订阅/订阅令牌);其二,频道名没带命名空间前缀——命名空间 chat 下的频道必须写作 chat:main,写裸的 chat 会落入无命名空间的默认策略(全部拒绝)。

Q6:HTTP API 调用返回 401? 请求头缺少 X-API-Key 或值与配置 http_api.key 不符。注意 API 请求体是 {"method":"publish","params":{...}} 的方法包裹结构,方法名拼错时返回的是 400 Bad Request 纯文本而非 JSON 错误体。

Q7:curl /health 返回 404? 健康检查端点默认关闭,配置 "health": {"enabled": true} 并重启后即可访问(4.8 节实测)。同类的 /metrics、/swagger/ 分别需要 prometheus.enabled、swagger.enabled。

Q8:管理界面(admin UI)访问 /ui/ 返回 404? v6 的管理界面不再挂在 /ui/ 路径,而是服务根路径 /,且需要 "admin": {"enabled": true, "external": true}(external 控制是否暴露在外部端口)。登录用 POST 表单提交 password 字段到 /admin/auth(JSON Content-Type 会得到 400,8.1 节有实测)。

十、卸载与清理

10.1 apt/deb 安装的卸载

sudo apt-get purge -y centrifugo

实测回显(节选):

After this operation, 92.3 MB disk space will be freed.
(Reading database ... 7344 files and directories currently installed.)
Removing centrifugo (6.10.1-0) ...
(Reading database ... 7335 files and directories currently installed.)
Purging configuration files for centrifugo (6.10.1-0) ...
dpkg: warning: while removing centrifugo, directory '/etc/centrifugo' not empty so not removed

purge 会移除二进制与 systemd 单元,但有两类残留需要手工确认清理(都是安装/运行期生成的非包属主文件):

sudo rm -f /etc/centrifugo/config.json && sudo rmdir /etc/centrifugo   # 生成的配置与目录
sudo rm -rf /var/lib/centrifugo /var/log/centrifugo                    # 数据与日志目录

💡 说明:/var/lib/centrifugo(运行数据)与 /var/log/centrifugo(日志)在卸载后仍保留,重装前清理即可;若计划重装,保留它们也无妨。

10.2 tar.gz 安装的卸载

sudo systemctl stop centrifugo
sudo systemctl disable centrifugo
sudo rm -f /etc/systemd/system/centrifugo.service && sudo systemctl daemon-reload
sudo rm -f /usr/local/bin/centrifugo
sudo rm -rf /opt/centrifugo-6.10.1 /etc/centrifugo /var/lib/centrifugo /var/log/centrifugo
sudo userdel centrifugo

十一、参考链接