突然想起来我在Hetzner那里还有一台闲置的纯IPv6服务器。想来想去，闲着也是闲着，不如拿来挂IRC。本文记述在这台服务器上搭建Quassel core的艰难坎坷。太长不看：IPv4的命还长着呢。IRC虽然我还年轻，但我觉得IRC这个东西挺酷的。尽管IRC并不是去中心化的，也不能发送文本之外的内容，但它可以self-host啊。如果我没记错的话，能够self host并且能做到不需要购买商业许可的聊天方案里，就只有Element/Matrix和IRC了，其他像是什么Threema OnPerm这些基本都要支付授权费。而即便是现代化的Element/Matrix，我认为在用户体验上也不是很能打IRC。当然，Element/Matrix在功能上更复杂，也更注重安全，同时还能够在不同服务器间互联，但从我的体验来说，Matrix这一套使用下来还是多多少少有一些恼人的Bug，十分影响体验；而IRC赢就赢在了功能简单，虽然打不过Matrix，但用起来没有问题，而且很纯粹。高情商：纯粹；低情商：简陋。总之，Matrix我也有在用，但是目前为止我个人更偏向IRC一些。但是IRC有一个致命的缺点，因为他太简单了，服务器甚至不会为你存储消息。也就是说，如果别人发消息时你没在线，那你就收不到消息了。这里我就不多费笔墨在介绍IRC协议上了。IRC协议作为一个已经发布了35年的经典协议，而且现今仍在使用，我想网络上一定有不少介绍和入门资料。Quassel既然IRC服务器不给我们存储消息，那我们就找一个服务器替我们挂机就是了。在众多IRC客户端中，Quassel是一个采用分离结构的IRC客户端。它分为Quassel Core和Quassel Client。其中Core的部分负责与IRC服务器交互，而Client则负责与Core交互。Core会一直在服务器上运行，与IRC服务器保持连接、接收指定频道的消息并将其存储到数据库中。而Client则运行在PC上，与Core交互，接收来自IRC的消息，也可以从数据库中调取以往的消息。如果你更倾向于在浏览器中使用IRC，你可以尝试诸如Convos等网页客户端。Convos支持在服务端持久化保存收到的消息，同时提供了一个十分易用的网页界面。我个人更喜欢在PC上以应用程序的方式使用IRC，所以我选择Quassel。安装废话不多说，我们不妨切入主题，直接说安装的部分。Quassel Core可以在没有任何依赖的情况下独立运行，此时数据存入SQLite数据库。这个数据库对于少量数据还可以应付，如果是长期使用积累下来的IRC消息，在数据量很大的情况下官方也有提示，使用SQLite数据库可能会导致拉取过往消息时出现超时或失败的情况。官方推荐使用PostgreSQL作为数据库。听人劝吃饱饭，我也决定使用PostgreSQL数据库。此外，我还想使用TLS加密Quassel Client与Core之间的通讯，我原本想使用Tailscale，但我又想使用公网访问，想来想去发现Quassel Core没办法在一个端口上提供两个不同的TLS证书，最终还是以公网访问为主，通过增加DNS的A记录指向Tailscale的IP来实现tailscale访问。具体的安装流程如下：安装Docker使用Docker安装PostgreSQL安装Quassel Core（在我的电脑上）安装Quassel Client并配置Quassel Core虽然在Docker中使用PostgreSQL数据库并不是生产环境的最佳实践，但从安全角度来说可能是最方便的。我在映射端口时可以直接把数据库端口映射到127.0.0.1上，而无需使用防火墙或修改数据库配置来实现。数据库的数据会映射到宿主机上，所以完全不需要担心数据丢失的问题。Docker我真是万万没想到，安装docker的环节都需要拿来说一下。我的服务器使用的是Ubuntu 2204LTS，安装Docker的过程遵照官方文档就是了，这个没什么可说的。意外发生在安装之后的验证阶段：docker run hello-world这一条命令本是用来验证Docker已经安装成功并且能够正常运行的。可是我一个回车按下去，却得到了一行错误：docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 44.205.64.79:443: connect: network is unreachable.不知道为什么，Ubuntu上安装docker的默认仓库是registry-1.docker.io，而这个仓库是不支持IPv6访问的，我的服务器又没有v4地址，那肯定会网络不可达。我去网络上搜索了一圈，发现Docker hub其实早就已经支持IPv6访问了。我们只需要修改/etc/docker/daemon.json，将镜像仓库设置为registry.docker.io就好了：{ "registry-mirrors": ["https://registry.docker.com"] }千万记得前面的https://，不然Docker daemon跑不起来。保存修改后重启Docker服务，再次运行那个命令，就可以看到Docker已经能够正常拉取镜像了。理论上也可以不进行修改，但每次拉取镜像时就需要指定仓库了：docker run registry.docker.com/library/hello-world会显得很麻烦PostgreSQL解决了Docker的问题，PostgreSQL就好办了：docker run -d \ --name quassel-postgres \ --restart always \ -p 127.0.0.1:5432:5432 \ -e POSTGRES_PASSWORD=【密码】 \ -e PGDATA=/var/lib/postgresql/data/pgdata \ -v /var/lib/postgresql/quassel-data:/var/lib/postgresql/data \ postgres:latest容器的默认用户名和数据库名都是postgres，密码则通过POSTGRES_PASSWORD设置。这里我将数据库的端口映射到了127.0.0.1，只有本机能够访问，足够安全。Quassel Core这里我们需要安装两个软件包：apt install quassel-core libqt5sql5-psql前者是Quassel Core本体，后者则用于支持PostgreSQL的支持。如果没有第二个软件包的话，在下面使用Client配置Core时会发现只能使用SQLite数据库。安装完成后我们还需要配置一下TLS证书。证书位于/var/lib/quassel/quasselCert.pem，其格式就是证书的key和certs拼接到一起：-----BEGIN EC PRIVATE KEY----- 私钥。。。 -----END EC PRIVATE KEY----- -----BEGIN CERTIFICATE----- 证书链。。。 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 证书链。。。 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- 证书链。。。 -----END CERTIFICATE-----大概是这种样子，证书链的数量取决于你的CA，关键在于这个pem文件里要提供你的私钥、域名证书和用于整明域名证书的CA证书（ca-bundle）。配置好之后，重启quasselcore服务即可让证书生效。如果quassel core启动失败，那多半是你的pem文件有问题。关于证书的部分，我原本想使用两套证书，在100.64.0.0/10上提供Tailscale的证书，在其他接口上提供公网TLS证书，但后来我发现Quassel Core做不到。后来我又想，能不能让Tailscale和公网证书用一个key。我首先用tailscale生成一套证书，然后用这套证书的key生成csr，通过acme.sh等服务请求一个公网证书。但是安装acme.sh的时候我发现纯IPv6的服务器没办法访问Github。都2023年了，微软你在干什么啊。总之这个想法就此作罢。但是我还是希望使用Tailscale访问Quassel Core，所以我只能在公网DNS上添加一条A记录来指向Tailscale里的服务器。理论上来说我这套野路子应该是可行的（取决于客户端能不能从一堆合法的证书中找到正确的证书链），甚至还可以搞一个简单的自动化。但我比较懒，这条路就暂且告一段落。当然，最理想的情况就是Tailscale能够提供一个用于进行DNS-01验证的接口，这样我们就可以自己申请证书，在申请过程中同时验证Tailscale提供的域名和我们自己的域名，这样会更舒服一些。Quassel Client接下来在我的PC上安装客户端，连接到运行在服务器上的Core，默认端口号4242。第一次连接会有一个向导来帮助你配置Quassel Core的账户（用于验证连接到core的客户端）、存储后端（PostgreSQL）。接下来你可以配置一些IRC的身份、服务器和频道等。关于Quassel Client的使用，这里就不多说了，可以参考官方文档。这里说一下主题。默认情况下Quassel Client提供了一个亮色主题，但我个人更倾向于暗色主题。我搜索了一圈，发现也就Dracula主题还能用。在安装主题之后，还需要将窗口风格切换成Fusion，不然在设置窗口和其他窗口下会看起来怪怪的。Quassel Client支持Windows和MacOS，如果想要在移动端使用的话，安卓上可以考虑Quasseldroid，iOS人士就自求多福吧，我不熟。用量统计为了具体测量数据库磁盘用量的增长趋势，我写了一个简单的bash脚本来查询文件大小：#!/bin/bash while : do (du -sb /var/lib/postgresql/quassel-data && date +%s) | tee -a result.txt sleep 1200 # every 20 minutes done这个脚本每隔20分钟查询一次数据库占用的大小，并且将当时的时间戳一起追加到result.txt里。为了分析结果，我写了一段简单的kotlin程序来处理数据：import java.io.File object ResultCounting { @JvmStatic fun main(args: Array<String>) { val startTimestamp = 1685330000 println("\n".repeat(5)) File("result.txt").readLines() .chunked(2) .map { it[0].split("\t")[0].toLong() to it[1].toLong() } .forEach { println("${it.second - startTimestamp}\t${it.first}") } println("\n".repeat(20)) } }这段程序从startTimestamp为起点输出时间T和对应的数据量。打印出来的数据刚好可以复制粘贴到excel表格里。在Excel里面做一个图标，加一个线性的趋势线，趋势线的斜率就是平均每秒增加的字节数：这里可以看到一个比较大的转折点。这是因为刚开始加入了几个IRC服务器，什么频道都想看，所以一下子加了差不多得有30多个频道，每个频道的在线人数从几十到几百不等，消息也很多。那个时候差不多每秒增加60到70字节。后来意识到加入了太多频道，平时也不看消息，于是就退出了一些频道，只留下了每天会看的，我感兴趣的频道。比如Libera Chat的#linuxba和#opensuse之类的频道。两个阶段平均起来是每秒新增30字节的数据，但从后半段的图表来看，其实实际用量应该还会更低。结语这套配置我用了得有一周了，感觉下来还是挺不错的。从服务器资源占用方面来说，Quassel Core和PostgreSQL数据库加起来内存用了不到150MB（不愧是C++写的，换成Java的话1GB都不够塞牙缝的），CPU占用就更轻松一些了。我挂了三个服务器，每个服务器差不多都有10多个频道。后来退出了一些频道，CPU和内存占用就更小了。有一些服务器不支持同时登陆多个账号，而Quassel也恰巧解决了这个问题，多个Client能够同时连接到一个Core上收发消息。还是很不错的。-全文完-