Debian 12 部署 Kiwi IRC 1.7.1 指南
在 Debian 12 上部署 Kiwi IRC 1.7.1 的全流程实测:源码构建与官方预构建包双方案获取前端、Ergo 2.7.0 对端开启 WebSocket 监听、config.json 直连模式逐项配置、nginx 静态托管与 WebSocket 反代,完成 101 握手、浏览器入频、频道收发与 TCP 侧交叉验证。
Debian 12 部署 Kiwi IRC 1.7.1 指南
目标:在 Debian 12 上从零部署一套可用的 Kiwi IRC 1.7.1 网页版 IRC 客户端:前端以「源码构建」与「官方预构建包」两种方式获取,运行时配置 config.json 完成直连(direct)模式定制,nginx 承担静态托管与 WebSocket 反代,最后以 Ergo 2.7.0 作为 IRC 服务端对端,完成浏览器连接、入频与频道收发的全链路实测。本篇全部命令与回显均为 2026-10-26 实测所得。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 实测日期 | 2026-10-26 |
| 操作系统 | Debian GNU/Linux 12 (bookworm) |
| Kiwi IRC | v1.7.1(当前最新稳定 tag,2023-09-13 发布) |
| Node.js | v18.20.4(nodejs 18.20.4+dfsg-1~deb12u3,Debian 12 bookworm-security 官方源) |
| yarn | 1.22.22(npm 全局安装) |
| nginx | 1.31.8(实测环境;Debian 12 官方源默认 1.22.x 亦满足,WebSocket 反代能力自 nginx 1.3.13 起内建) |
| IRC 服务端对端 | Ergo 2.7.0(ergo-2.7.0-9851d2e9bcbb02ae) |
| 服务器内网 IP | 192.168.146.131(示例,下同) |
| 服务端口 | 8143(nginx 站点与 WebSocket 统一入口)、6667(ircd WebSocket 监听)、6668(ircd 纯 TCP 监听) |
💡 说明:Kiwi IRC 是纯静态前端(构建产物为 index.html + static/ 目录),本身没有常驻服务进程;聊天链路是「浏览器 → nginx(静态资源 + WebSocket 反代)→ IRC 服务端」。因此本篇对端选择了一个支持 WebSocket 监听的 ircd(Ergo),部署完成后两个角色同机运行。
二、前置条件
2.1 系统与账号
- 一台 Debian 12 服务器,具备 root 或 sudo 权限;
- 能访问 GitHub(下载源码与发行包);网络受限时可为 wget 配置代理。
2.2 安装 Node.js 与 yarn(方案 A 需要)
Debian 12 官方源的 nodejs 已是 18.x 系列,满足 Kiwi IRC 构建要求:
apt update
apt install -y nodejs npm
npm install -g yarn
验证版本(逐行照抄):
$ node -v
v18.20.4
$ yarn -v
1.22.22
2.3 准备 IRC 服务端对端
浏览器端的 JavaScript 无法直接对话经典 IRC 的原始 TCP 端口,直连模式要求 ircd 开启 WebSocket 监听。若你已有支持 WebSocket 的 ircd(Ergo、InspIRCd 等均可),可跳过第五章;没有的话按第五章用 Ergo 2.7.0 部署一个最小对端(本篇实测即采用该路线)。
三、版本选型说明
3.1 版本现状
- v1.7.1 是 kiwiirc/kiwiirc 仓库当前最新 tag,发布于 2023-09-13(GitHub Releases 实查);
- 项目 1.x 系列长期演进,2026 年仍有代码推送(最近一次 2026-06-19 实查);升级以「替换静态文件」为主,无数据库迁移负担。
3.2 发行形态对照(2026-10-26 实查 v1.7.1 Release 附件)
| 附件 | 形态 | 体积 | 适用 |
|---|---|---|---|
| kiwiirc-client_v1.7.1-2_any.zip | 纯前端静态包(index.html + static/) | 2.6 MB | 自托管网页客户端,解压即用 |
| kiwiirc-desktop_v1.7.1-2_linux_amd64.deb 等 | Electron 桌面端 | 65–72 MB | 桌面 App,非本篇场景 |
| kiwiirc-server_v1.7.1-2_linux_amd64.deb 等 | 旧代际 Node 服务端 | 9–11 MB | 网关/旧形态服务端,非本篇场景 |
另需注意:官方下载页 kiwiirc.com/downloads/ 目前提供的 deb/rpm 仍是旧代际 kiwiirc_20.05.24.1(2020 年代、内嵌 Node 服务端的形态),与 1.7.1 不是同一代产物,选型时不要混淆。
3.3 本篇路线
- 方案 A(主线):源码构建——官方 README 标准路径(yarn install && yarn run build),本文完整实测;
- 方案 B:官方预构建 client zip——GitHub Release 附件,下载解压即用,本文完整实测;
- 两者产物体积一致(均为 9.4 MB、同为 index.html + static/ 结构),运行时行为相同,区别只在获取方式与是否可改源码。
四、获取 Kiwi IRC 前端
4.1 方案 A:源码构建(官方标准路径,本文主线)
下载并解压官方源码包:
cd /opt
wget https://github.com/kiwiirc/kiwiirc/archive/refs/tags/v1.7.1.tar.gz -O kiwiirc-1.7.1.tar.gz
tar -xzf kiwiirc-1.7.1.tar.gz
cd kiwiirc-1.7.1
安装依赖(首次安装会完整下载依赖,视网络耗时数分钟;依赖已就位时重跑会秒级完成,以下为依赖就位后的重跑回显,逐行照抄):
$ yarn install
yarn install v1.22.22
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.23s.
执行生产构建:
$ yarn run build
输出较长(逐个列出产物文件与体积),以下为输出尾部逐行照抄:
dist/static/js/chunk-vendors.92080668. 988.25 KiB 312.75 KiB
js
dist/static/js/app.5e59f89a.js 489.85 KiB 106.02 KiB
dist/static/css/app.16b2d763.css 116.51 KiB 21.22 KiB
dist/static/themes/radioactive/theme.c 26.96 KiB 5.70 KiB
ss
dist/static/themes/common/base.css 24.97 KiB 3.88 KiB
dist/static/themes/nightswatch/theme.c 8.96 KiB 1.88 KiB
ss
dist/static/themes/elite/theme.css 6.18 KiB 1.44 KiB
dist/static/themes/dark/theme.css 5.41 KiB 1.26 KiB
dist/static/themes/coffee/theme.css 4.30 KiB 1.14 KiB
dist/static/themes/grayfox/theme.css 4.30 KiB 1.11 KiB
dist/static/themes/osprey/theme.css 3.65 KiB 0.96 KiB
dist/static/themes/sky/theme.css 3.38 KiB 0.93 KiB
dist/static/themes/default/theme.css 3.14 KiB 0.86 KiB
Images and other types of assets omitted.
Build at: 2026-10-26T07:26:41.089Z - Hash: ad689ca9a92f4971 - Time: 31170ms
DONE Build complete. The dist directory is ready to be deployed.
INFO Check out deployment instructions at https://cli.vuejs.org/guide/deployment.html
Done in 33.08s.
构建完成后的产物结构:
dist/
├── index.html
└── static/
├── config.json ← 运行时配置(第六章)
├── css/ js/ fonts/ img/ locales/ emoticons/ ...
└── themes/ ← 内置主题(default/dark/coffee/grayfox/nightswatch/osprey/radioactive/sky/elite/common)
⚠️ 注意:官方 README 明确 dist/ 每次构建都会被覆盖,应把产物拷贝到 Web 服务器站点目录而不是直接在源码树里对外服务;同时 yarn run dev(开发热重载模式)仅供本地开发,不要用于生产。
4.2 方案 B:官方预构建 client zip
直接下载 v1.7.1 Release 附件 kiwiirc-client_v1.7.1-2_any.zip(2,687,471 字节,2023-09-15 构建)并解压:
cd /opt
wget https://github.com/kiwiirc/kiwiirc/releases/download/v1.7.1/kiwiirc-client_v1.7.1-2_any.zip
unzip -q kiwiirc-client_v1.7.1-2_any.zip
验证内容(逐行照抄):
$ ls kiwiirc_v1.7.1-2/
LICENSE
index.html
static
$ du -sh kiwiirc_v1.7.1-2/
9.4M kiwiirc_v1.7.1-2/
预构建包内置默认配置 static/config.json 与源码构建默认一致,关键字段节选(逐行照抄):
{
"windowTitle": "Kiwi IRC - The web IRC client",
"startupScreen": "welcome",
"kiwiServer": "/webirc/kiwiirc/",
"restricted": false,
"themes": [
{ "name": "Default", "url": "static/themes/default" },
{ "name": "Dark", "url": "static/themes/dark" },
...
],
"startupOptions" : {
"channel": "#kiwiirc-default",
"nick": "kiwi-n?"
},
...
}
其中 kiwiServer: "/webirc/kiwiirc/" 是官方 webircgateway 网关的默认路径约定——预构建包默认假设你后续挂网关;本篇采用直连(direct)模式,将在第六章整体替换该配置。
4.3 方案对比与选择建议
| 维度 | 方案 A:源码构建 | 方案 B:预构建 zip |
|---|---|---|
| 获取成本 | 需 Node.js + yarn 环境,首次安装依赖耗时 | 下载 2.6 MB 解压即用 |
| 可定制性 | 可改源码、可做插件级二开 | 只能改运行时 config.json |
| 与官方一致性 | 本文锁定 v1.7.1 tag 构建 | 官方 CI 产物,与 Release 严格对应 |
| 产物 | dist/ 9.4 MB | kiwiirc_v1.7.1-2/ 9.4 MB |
建议:快速上线、纯运维场景选方案 B;需要二次开发(定制界面文案、集成插件、改主题)选方案 A。两方案后续步骤(第五~九章)完全相同。
五、部署 IRC 服务端对端(Ergo 2.7.0)
以下部署一个最小可用的 Ergo ircd,关键是让 6667 端口开启 WebSocket 监听。
5.1 下载与解压
cd /opt
wget https://github.com/ergochat/ergo/releases/download/v2.7.0/ergo-2.7.0-linux-x86_64.tar.gz
tar -xzf ergo-2.7.0-linux-x86_64.tar.gz
cd ergo-2.7.0
解压后目录内包含 ergo 主程序、default.yaml 与 traditional.yaml 两份示例配置、ergo.motd 公告文件以及 languages/ 多语言目录(后续 ircd.yaml 会引用)。
5.2 生成与修改配置
cp default.yaml ircd.yaml
修改 ircd.yaml 中三处(其余保持默认)。网络与服务器名:
network:
name: KiwiTest
server:
name: irc.kiwitest.local
监听器(核心改动):default.yaml 的 6667 本是普通明文 TCP 监听,把它改成 WebSocket 监听,并另开 6668 作为纯 TCP 监听供命令行 IRC 客户端使用;6697 TLS 监听保留默认:
listeners:
":6667":
websocket: true
":6668":
":6697":
tls:
cert: fullchain.pem
key: privkey.pem
proxy: false
min-tls-version: 1.2
⚠️ 注意:Ergo 中
websocket: true的语义是「该监听只服务 WebSocket」,原始 TCP 客户端连上会得到 HTTP 400(见 FAQ Q1);因此务必像上面一样另开一个纯 TCP 监听(6668),否则 irssi/WeeChat 等传统客户端无法接入。6697 TLS 监听保留默认即可,首次启动时 Ergo 会自动生成自签证书(fullchain.pem/privkey.pem)。
5.3 启动与验证
cd /opt/ergo-2.7.0
./ergo run
启动回显(逐行照抄,2026-10-26 实测):
2026-10-26T06:46:55.574Z : info : server : ergo-2.7.0-9851d2e9bcbb02ae starting
2026-10-26T06:46:55.574Z : info : server : Using config file : ircd.yaml
2026-10-26T06:46:55.574Z : info : server : Using datastore : ircd.db
2026-10-26T06:46:55.574Z : info : server : Proxied IPs will be accepted from : localhost
2026-10-26T06:46:55.574Z : info : listeners : now listening on :6697, tls=true, proxy=false, tor=false, websocket=false.
2026-10-26T06:46:55.574Z : info : listeners : now listening on :6667, tls=false, proxy=false, tor=false, websocket=true.
2026-10-26T06:46:55.574Z : info : listeners : now listening on :6668, tls=false, proxy=false, tor=false, websocket=false.
2026-10-26T06:46:55.574Z : warn : listeners : Warning: your server is configured with public plaintext listener :6668. Consider disabling it for improved security and privacy.
2026-10-26T06:46:55.575Z : info : server : Server running
关键行是 6667 的 websocket=true。ergo run 是前台进程,生产建议配 systemd 常驻:
# /etc/systemd/system/ergo.service
[Unit]
Description=Ergo IRC server
After=network.target
[Service]
WorkingDirectory=/opt/ergo-2.7.0
ExecStart=/opt/ergo-2.7.0/ergo run
Restart=on-failure
[Install]
WantedBy=multi-user.target
六、运行时配置 config.json
6.1 位置与加载机制
- 源码树中位于 static/config.json,构建后随 dist/ 分发,页面加载后由前端运行时拉取生效;
- 解析器为 JSON5:允许注释与尾逗号,语法错误时精确报出行号与列号;
- 主题、服务器默认值、窗口行为、嵌入限制等全部运行时行为都由这一个文件驱动,无需改代码。
6.2 本文生产配置(直连模式)
将 dist/static/config.json(方案 B 则为 kiwiirc_v1.7.1-2/static/config.json)整体替换为:
{
"windowTitle": "KiwiTest Web IRC",
"startupScreen": "customServer",
"kiwiServer": "",
"restricted": true,
"theme": "Default",
"themes": [
{ "name": "Default", "url": "static/themes/default" },
{ "name": "Dark", "url": "static/themes/dark" }
],
"startupOptions": {
"server": "192.168.146.131",
"port": 8143,
"tls": false,
"direct": true,
"direct_path": "/ircws/",
"channel": "#kiwitest",
"nick": "guest_?",
"greetingText": "连接 KiwiTest IRC 网络",
"buttonText": "连接"
},
"plugins": [
{ "name": "customise", "url": "static/plugins/customise.html" }
]
}
6.3 逐项说明(实测口径)
| 字段 | 实测值 | 作用 |
|---|---|---|
| windowTitle | "KiwiTest Web IRC" | 浏览器标签页标题 |
| startupScreen | "customServer" | 启动页显示「服务器/昵称/频道」三要素表单;welcome 则是网络列表欢迎页 |
| kiwiServer | "" | 网关模式的后端地址;直连模式留空 |
| restricted | true | 隐藏用户自助改网络的入口,锁定为配置里的服务器 |
| theme / themes | Default + Dark | 默认主题与可选主题清单 |
| startupOptions.server | "192.168.146.131" | IRC 服务器地址(连接页预填) |
| startupOptions.port | 8143 | WebSocket 入口端口——注意这是 nginx 端口而非 ircd 的 6667(浏览器只跟 nginx 说话) |
| startupOptions.tls | false | 是否走 wss/https |
| startupOptions.direct | true | 直连模式:浏览器 WebSocket 经 nginx 反代直达 ircd |
| startupOptions.direct_path | "/ircws/" | 直连模式的 WebSocket 路径,对应第七章 nginx 的 /ircws/ 反代段 |
| startupOptions.channel | "#kiwitest" | 连接后自动加入的频道(连接页预填) |
| startupOptions.nick | "guest_?" | 昵称模板,? 会被随机数字替换(实测连接页预填为 guest_99 一类随机值) |
| greetingText / buttonText | 中文文案 | 连接页提示语与按钮文字定制 |
七、nginx 静态托管与 WebSocket 反代
7.1 部署站点目录
mkdir -p /var/www/kiwiirc
cp -r /opt/kiwiirc-1.7.1/dist/* /var/www/kiwiirc/ # 方案 A 产物
# 或:cp -r /opt/kiwiirc_v1.7.1-2/* /var/www/kiwiirc/ # 方案 B 产物
7.2 站点配置
新建 /etc/nginx/conf.d/kiwi.conf:
server {
listen 8143;
server_name _;
root /var/www/kiwiirc;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /ircws/ {
proxy_pass http://127.0.0.1:6667/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
}
逐项说明:
| 配置行 | 作用 |
|---|---|
| listen 8143 | 站点与 WebSocket 统一入口,与 config.json 的 port 一致 |
| try_files $uri $uri/ /index.html | 单页应用回退:静态资源命中即返回,未命中回退 index.html |
| proxy_pass http://127.0.0.1:6667/ | /ircws/ 反代到 Ergo 的 WebSocket 监听;末尾斜杠使 /ircws/ 前缀被剥掉后转发 |
| proxy_http_version 1.1 + Upgrade/Connection 两行头 | WebSocket 协议升级三件套,缺一则握手必败 |
| proxy_read/send_timeout 3600s | 长连接空闲超时放宽到 1 小时,避免 nginx 默认 60 秒掐断空闲聊天连接 |
7.3 生效与验证
$ nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ systemctl reload nginx
八、连通验证与浏览器实测
8.1 WebSocket 握手验证
不进浏览器先验证反代链路(Sec-WebSocket-Key 取 RFC 6455 示例值):
$ curl -s -i \
-H 'Connection: Upgrade' -H 'Upgrade: websocket' \
-H 'Sec-WebSocket-Version: 13' \
-H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
-H 'Origin: http://192.168.146.131:8143' \
http://192.168.146.131:8143/ircws/
HTTP/1.1 101 Switching Protocols
Server: nginx/1.31.8
Date: Mon, 26 Oct 2026 07:18:41 GMT
Connection: upgrade
Upgrade: websocket
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
出现 101 Switching Protocols,即「浏览器 → nginx → ircd」整条 WebSocket 链路已通。
8.2 浏览器打开与连接页
浏览器访问 http://192.168.146.131:8143/ ,页面标题与启动表单预填值实测如下(浏览器内读取页面 DOM 所得,逐行照抄):
title = KiwiTest Web IRC
form values: ["192.168.146.131:8143","kiwibrowser","#kiwitest"]
三个输入框依次为服务器地址(预填 server:port)、昵称(预填 guest_? 模板生成的随机昵称,实测改为 kiwibrowser)、频道(预填 #kiwitest)。点击「连接」按钮。
8.3 连接成功判定
连接成功后进入频道视图,消息列表实测内容(逐行照抄):
Load previous messages
→ kiwibrowser has joined
HistServ 07:27:15
kiwibrowser joined the channel
「→ kiwibrowser has joined」即本端入频成功;HistServ 行是 Ergo 历史服务记录的入频事件。
8.4 频道发言实测
在底部输入框输入消息回车发送,消息列表实测(逐行照抄):
Load previous messages
→ kiwibrowser has joined
HistServ 07:27:15
kiwibrowser joined the channel
K
@kiwibrowser 07:27:19
大家好,这是网页端发出的第一条测试消息
@kiwibrowser 的一条消息出现在消息列表中,网页端发言成功。
九、频道收发交叉验证(TCP 侧)
为证明「网页端发言真的经 nginx 进入 ircd 并向全频道广播」,用任意传统 IRC 客户端从纯 TCP 监听(6668)加入 #kiwitest 观察。以下是该客户端视角的原始协议日志(节选关键行,逐行照抄):
:irc.kiwitest.local 001 rawbot :Welcome to the KiwiTest IRC Network rawbot
:irc.kiwitest.local 002 rawbot :Your host is irc.kiwitest.local, running version ergo-2.7.0-9851d2e9bcbb02ae
:webuser1!~u@25nkt9y3jextg.irc JOIN #kiwitest
:webuser1!~u@25nkt9y3jextg.irc PRIVMSG #kiwitest :大家好,这是来自 Kiwi IRC 网页端(WebSocket 直连)的测试消息
其中 webuser1 是网页端昵称,PRIVMSG 行即网页端发出的消息——TCP 侧客户端原样收到,双向链路闭环。反方向同理:TCP 客户端在频道里发言,网页端消息列表即时出现。
十、常见问题(FAQ)
Q1:raw TCP 客户端连 6667 收到 HTTP 400? A:websocket: true 是「仅 WebSocket」语义,该监听只讲 HTTP/WebSocket,原始 IRC 客户端发 NICK/USER 会被当作畸形 HTTP 而得到 400。按第五章另开纯 TCP 监听(如 6668)给传统客户端。
Q2:网页端输入框打字正常但消息发不出去? A:检查 ircd 的 WebSocket 帧语义。实测 Ergo 2.7.0 的约定是「每条 IRC 协议行一个 WebSocket 帧,行尾不带 CRLF」;若调试脚本把多行拼进一帧或补 \r\n,服务端会整体拒绝。Kiwi IRC 本身遵守该语义,此问题一般只在绕过 Kiwi IRC 直写 WebSocket 时出现。
Q3:页面报 Config file error: JSON5 ...? A:config.json 由 JSON5 解析,语法错误会精确报出行号列号(例如 at 22:16 表示第 22 行第 16 列附近),按提示修正即可。中文文案可直接书写,无需转义。
Q4:能不能用 yarn run dev 直接对外服务? A:不能。官方 README 明确开发模式(热重载、监听 8080)体积大且不安全,仅限本地开发;生产一律用构建产物 + Web 服务器托管。
Q5:8143 端口想换掉? A:三处联动:nginx 的 listen、config.json 的 startupOptions.port、防火墙放行规则。缺一处都会出现「页面能开但连不上」或「页面开不了」。
Q6:nginx 反代下握手返回 400/426? A:多半是漏了 proxy_http_version 1.1 与 Upgrade/Connection 两行头,或 proxy_pass 忘写末尾斜杠导致路径拼接错误,对照第七章逐行核对。
Q7:https 站点嵌入后连不上 ws://? A:浏览器混合内容策略会拦截 https 页面发起的 ws:// 连接。整站上 TLS(含 wss),同步把 config.json 的 tls 改为 true,ircd 侧启用 TLS 监听。
Q8:Ergo 启动报 Could not load languages: open languages: no such file or directory? A:工作目录缺 languages/ 目录(ircd.yaml 的 languages.path 指向发行包内目录)。在发行包解压目录内运行,或把 languages/ 拷到配置指向的路径。
十一、升级与卸载
11.1 升级
- 备份运行时配置:
cp /var/www/kiwiirc/static/config.json /root/config.json.bak; - 方案 A:下载新 tag 源码 → yarn install && yarn run build → 用新 dist/ 替换站点目录 → 回填备份的 config.json;
- 方案 B:下载新版 client zip → 解压替换站点目录 → 回填 config.json;
- 静态替换无需 reload nginx,回填配置后浏览器强制刷新即生效。
11.2 卸载
rm -rf /var/www/kiwiirc
rm -f /etc/nginx/conf.d/kiwi.conf && systemctl reload nginx
# 若按 5.3 配置了 systemd 单元:
systemctl stop ergo && systemctl disable ergo
rm -rf /opt/ergo-2.7.0 /opt/kiwiirc-1.7.1 /opt/kiwiirc_v1.7.1-2 /opt/kiwiirc-client_v1.7.1-2_any.zip
十二、参考链接
官方资源:
- Kiwi IRC 仓库:https://github.com/kiwiirc/kiwiirc
- v1.7.1 Release(client zip 附件处):https://github.com/kiwiirc/kiwiirc/releases/tag/v1.7.1
- 官方 README(构建与部署说明):https://github.com/kiwiirc/kiwiirc/blob/master/README.md
- 配置 wiki:https://github.com/kiwiirc/kiwiirc/wiki/Configuration
- webircgateway(网关模式组件):https://github.com/kiwiirc/webircgateway
- KiwiBNC(bouncer 组件):https://github.com/kiwiirc/kiwibnc
- Ergo(本篇对端 ircd):https://github.com/ergochat/ergo
站内相关文档: