Ubuntu 22.04 安装 Apache rivet 指南

在 Ubuntu 22.04 上从零安装 Apache Rivet 的完整指南,覆盖 apt 软件源方案(3.2.1)与源码编译方案(3.3.1)的实操流程、模块加载与虚拟主机最小配置,并以 curl 验证首个 .rvt 页面返回 200。

Apache rivetApache rivetUbuntuUbuntu 22.04httpdLinux2026/10/16

Ubuntu 22.04 安装 Apache rivet 指南

目标:在全新 Ubuntu 22.04 服务器上把 Apache Rivet 装好、加载进 httpd、跑出第一个返回 200 的 .rvt 页面。全文两条路线:apt 软件源方案(版本旧但省事)与源码编译方案(拿最新稳定版 3.3.1),均实测验证,并给出选型建议与踩坑记录。实验命令均在 /root 下执行。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(jammy,x86_64)
  • 内核与 shell:Linux 5.15+,bash
  • Apache:2.4.52(event MPM)
  • Tcl:8.6.12
  • 目标软件:Apache Rivet
    • apt 方案版本:libapache2-mod-rivet 3.2.1-5(jammy/universe)
    • 源码方案版本:rivet-3.3.1(当前最新稳定版,2026-09-05 发布)
  • 实机验证系统版本:
cat /etc/os-release | head -2
PRETTY_NAME="Ubuntu 22.04.x LTS"
NAME="Ubuntu"
VERSION_ID="22.04"

💡 技术拓展:Rivet 由「httpd 模块 mod_rivet.so + Tcl 运行库(init.tcl、命令库、扩展包)」两部分构成,二者版本必须严格配套——3.2.x 的模块加载 3.3.x 的 Tcl 库会直接段错误(本文第九章有实测记录)。因此任何安装方式都要确认两部分的来源与版本一致。

二、前置条件

2.1 更新软件源索引

apt-get update 2>&1 | tail -3
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done
Building dependency tree... Done

2.2 安装 Apache 与 Tcl

DEBIAN_FRONTEND=noninteractive apt-get install -y apache2 tcl-dev apache2-dev build-essential curl wget 2>&1 | tail -5
Setting up apache2-dev (2.4.52-1ubuntu4.25) ...
Setting up tcl-dev:amd64 (8.6.12+1build2) ...
Setting up libsqlite3-tcl:amd64 (3.37.2-2) ...
Processing triggers for man-db (2.10.2-1) ...

各包用途说明:

包用途
apache2Web 服务器本体
apache2-dev提供 apxs(Apache 扩展编译工具),编译 mod_rivet 必需
tcl-devTcl 头文件与 tclConfig.sh,编译 mod_rivet 必需
build-essentialgcc/make 编译工具链

2.3 确认关键路径

apxs -V | head -2; ls /usr/bin/apxs
APACHE_MODULEDIR=/usr/lib/apache2/modules
/usr/bin/apxs
find /usr/lib -name tclConfig.sh 2>/dev/null
/usr/lib/x86_64-linux-gnu/tcl8.6/tclConfig.sh

三、方案对比与选型

维度方案 A:apt 软件源方案 B:源码编译
版本3.2.1-5(2022 年冻结)3.3.1(当前最新稳定)
依赖处理自动(itcl3、tcllib 一并装齐)需手工补齐(libsqlite3-tcl、itcl3、tcllib)
部署速度一条命令约 10 分钟
跟随安全更新随 Ubuntu 源需自行跟踪 ASF 版本
模块与库配套包内严格配套编译时自动配套
适用快速验证、老版本可满足生产部署、需要 3.3.x 新特性

建议:新部署直接选方案 B 拿 3.3.x;方案 A 适合一次性的可用性验证。两方案不要混装同一台机器(第九章实测混装后果)。

四、方案 A:apt 软件源安装(3.2.1)

4.1 查询与安装

apt-cache policy libapache2-mod-rivet | head -3
libapache2-mod-rivet:
  Candidate: 3.2.1-5
  Version table:
     3.2.1-5 500
DEBIAN_FRONTEND=noninteractive apt-get install -y libapache2-mod-rivet 2>&1 | tail -4
Setting up libapache2-mod-rivet-doc (3.2.1-5) ...
Setting up libapache2-mod-rivet (3.2.1-5) ...
Processing triggers for apache2 (2.4.52-1ubuntu4.25) ...

包依赖会自动带入 itcl3、tcllib(Session/DIO 扩展包所需),免去手工补齐。

4.2 包布局与自动配置

dpkg -L libapache2-mod-rivet | grep -E 'modules|tcltk|mods-enabled' | head -8
/usr/lib/apache2/modules/mod_rivet.so
/usr/lib/tcltk/rivet3
/etc/apache2/mods-available/rivet.load
/etc/apache2/mods-available/rivet.conf

dpkg -L 可见:模块装到 httpd 模块目录,Tcl 运行库装到 /usr/lib/tcltk/rivet3(3.2.1 的库路径与源码方案的 /usr/local/apache2/lib/ 不同,属于包管理器规范化路径),并自带 mods-available/rivet.load 与 rivet.conf。

4.3 启用模块与验证

a2enmod rivet 2>&1 | tail -1
apachectl -k restart
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/hello.rvt
Enabling module rivet.
200

⚠️ 实测坑点:若机器上先前已经手工编译安装过 3.3.1,apt install libapache2-mod-rivet 会因 rivet.load/rivet.conf 已存在而触发 conffile 冲突,非交互终端下安装会中断在半完成状态;随后 3.2.1 模块 + 3.3.1 库混用会段错误。因此"换方案"前先彻底卸载旧文件,避免版本混装(详见第九章)。

五、方案 B:源码编译安装(3.3.1,推荐)

5.1 下载与完整性校验

cd /root
wget -q https://archive.apache.org/dist/tcl/rivet/rivet-3.3.1.tar.gz
wget -q https://archive.apache.org/dist/tcl/rivet/rivet-3.3.1.tar.gz.sha512
sha512sum -c rivet-3.3.1.tar.gz.sha512
rivet-3.3.1.tar.gz: OK

5.2 解压与 configure

tar xzf rivet-3.3.1.tar.gz
cd rivet-3.3.1
./configure --with-apxs=/usr/bin/apxs --with-tcl=/usr/lib/x86_64-linux-gnu/tcl8.6 --enable-threads 2>&1 | tail -25
configure: Rivet package version is 3.3
checking if the worker MPM bridge will run in single thread mode... no, maximal number of Tcl threads
checking if we want the worker bridge to serialize HTTP requests... no, HTTP requests will not be serialized
checking if we are building mod_rivet for debugging... no, ordinary build
checking Major version... 3
checking Minor version... 3
checking Point version... 1
checking if the commands in ::rivet namespace will be exported... yes
checking Debian TCL_PACKAGE_PATH workaround... loading
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile

(以上为 ./configure ... 2>&1 | tail -25 的真实回显节选;worker 桥多线程检查通过即 event/worker MPM 可用。)

configure 关键参数说明:

参数作用实测取值
--with-apxs指定 apxs,决定模块安装路径/usr/bin/apxs → 模块装入 /usr/lib/apache2/modules/
--with-tcltclConfig.sh 位置/usr/lib/x86_64-linux-gnu/tcl8.6
--enable-threads启用 Tcl 线程化构建,worker/event MPM 需要开启
--with-rivet-target-dir自定义 Tcl 库安装目录不设则默认 /usr/local/apache2/lib/rivet3.3.1
--with-upload-dir默认上传临时目录不设则用编译默认值
--with-post-maxPOST 请求体上限(字节)默认值编译期内置

💡 技术拓展:--enable-threads 与 MPM 的关系——Ubuntu 默认 event MPM 是多线程模型,Rivet 的 worker 桥在多线程下运行,Tcl 必须以线程化方式构建,否则解释器无法隔离到线程,请求会串数据。configure 输出中 checking if the worker MPM bridge will run in single thread mode... no, maximal number of Tcl threads 即该检查的结果(确认 worker 桥运行在多线程模式)。

5.3 编译与安装

make 2>&1 | tail -4
successful sourcing of packages/form/form22.tcl
packages provided were {form 2.2}
successful loading of librivetlib.so
packages provided were {rivetlib 3.3.1}
successful loading of librivetparser.so
packages provided were {rivetparser 0.2}
make install 2>&1 | grep -E 'install|successful' | head -20
 /bin/bash ../libtool   --mode=install /bin/bash ../tclconfig/install-sh -c   mod_rivet.la '/usr/lib/apache2/modules'
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/mod_rivet.so /usr/lib/apache2/modules/mod_rivet.so
 /bin/bash ../libtool   --mode=install /bin/bash ../tclconfig/install-sh -c   librivetparser.la librivetlib.la '/usr/local/apache2/lib/rivet3.3.1'
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/librivetparser.so /usr/local/apache2/lib/rivet3.3.1/librivetparser.so
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/librivetlib.so /usr/local/apache2/lib/rivet3.3.1/librivetlib.so
 /bin/bash ../libtool   --mode=install /bin/bash ../tclconfig/install-sh -c   rivet_worker_mpm.la rivet_prefork_mpm.la rivet_lazy_mpm.la '/usr/local/apache2/lib/rivet3.3.1/mpm'
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/rivet_worker_mpm.so /usr/local/apache2/lib/rivet3.3.1/mpm/rivet_worker_mpm.so
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/rivet_prefork_mpm.so /usr/local/apache2/lib/rivet3.3.1/mpm/rivet_prefork_mpm.so
libtool: install: /bin/bash ../tclconfig/install-sh -c .libs/rivet_lazy_mpm.so /usr/local/apache2/lib/rivet3.3.1/mpm/rivet_lazy_mpm.so
echo 'target install-data-hook: removing unwanted libtool .la files from /usr/local/apache2/lib/rivet3.3.1 /usr/lib/apache2/modules /usr/local/apache2/lib/rivet3.3.1/mpm'

安装产物核对:

ls -la /usr/lib/apache2/modules/mod_rivet.so
ls /usr/local/apache2/lib/rivet3.3.1/
-rwxr-xr-x 1 root root 449552 Oct 16 04:07 /usr/lib/apache2/modules/mod_rivet.so
default_request_handler.tcl
init.tcl
librivetlib.so
librivetparser.so
mpm
packages
pkgIndex.tcl
rivet-tcl

六、加载模块与最小站点配置

6.1 模块加载文件

源码方案不自带 Debian 风格的 mods 文件,需要手工创建(与 apt 方案的 rivet.load 语法一致):

cat > /etc/apache2/mods-available/rivet.load <<'EOF'
LoadModule rivet_module /usr/lib/apache2/modules/mod_rivet.so
EOF
cat > /etc/apache2/mods-available/rivet.conf <<'EOF'
<IfModule rivet_module>
    AddType application/x-httpd-rivet .rvt
    AddType application/x-rivet-tcl .tcl
</IfModule>
EOF
a2enmod rivet
Enabling module rivet.
To activate the new configuration, you need to run:
  service apache2 restart

配置要点:

  • AddType application/x-httpd-rivet .rvt 把 .rvt 后缀映射给 mod_rivet 处理(源码中模板处理器的匹配类型即为 application/x-httpd-rivet);
  • AddType application/x-rivet-tcl .tcl 让 .tcl 后缀作为"整页 Tcl 脚本"处理(无模板,纯 Tcl 输出);
  • 若要仅在单个虚拟主机生效,也可把两行 AddType 移入 <VirtualHost> 段,见 6.3。

6.2 启动与首个 .rvt 页面验证

写一个最小模板(注意:<? ?> 内是 Tcl 代码,<?= ?> 是插值输出):

cat > /var/www/html/hello.rvt <<'EOF'
<? set title "Hello Rivet" ?>
<html>
<head><title><?= $title ?></title></head>
<body>
<h1><?= $title ?></h1>
<p>Powered by Apache Rivet, server time: <? puts [clock format [clock seconds] -format "%Y-%m-%d %H:%M:%S"] ?></p>
</body>
</html>
EOF

启动服务并验证:

apachectl -k restart
sleep 1
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/hello.rvt
200
curl -s http://localhost/hello.rvt
<html>
<head><title>Hello Rivet</title></head>
<body>
<h1>Hello Rivet</h1>
<p>Powered by Apache Rivet, server time: 2026-10-16 04:07:12</p>
</body>
</html>

.tcl 整页脚本方式同样验证一次:

cat > /var/www/html/info.tcl <<'EOF'
puts -nonewline "<h1>Rivet Tcl script</h1><p>pid=[pid], tcl=[info patchlevel]</p>"
EOF
curl -s http://localhost/info.tcl
<h1>Rivet Tcl script</h1><p>pid=11235, tcl=8.6.12</p>

⚠️ 实测坑点:向 .rvt 文件写入内容时若用不带引号的 shell heredoc(<<EOF),Tcl 变量 $title、$t 会被 shell 提前替换成空字符串,页面看似 200 但插值丢失。必须使用带引号的 <<'EOF',或用编辑器等可原样落盘的方式写入。这是实测踩过的第一个坑,也是"页面 200 但内容不对"的最常见原因。

6.3 虚拟主机最小配置

示例:站点 site1.example.com 仅在自身目录启用 .rvt 处理,并使用独立 DocumentRoot。

mkdir -p /var/www/site1
cat > /etc/apache2/sites-available/site1.conf <<'EOF'
<VirtualHost *:80>
    ServerName site1.example.com
    DocumentRoot /var/www/site1

    <Directory /var/www/site1>
        Options Indexes FollowSymLinks
        AllowOverride None
        Require all granted

        AddType application/x-httpd-rivet .rvt
        AddType application/x-rivet-tcl .tcl
    </Directory>
</VirtualHost>
EOF
a2ensite site1
echo 'test page' > /var/www/site1/index.rvt

启用与验证(本机用 Host 头模拟域名):

apachectl -k restart
curl -s -H 'Host: site1.example.com' http://localhost/index.rvt
test page

💡 技术拓展:.rvt 处理粒度由 AddType 的作用域决定——写在 rivet.conf 全局段则所有虚拟主机都处理 .rvt;写在某个 <Directory>/<VirtualHost> 内则只有该范围生效。多站点混部(部分站点 PHP、部分站点 Rivet)推荐按虚拟主机隔离,避免后缀被误解释。

七、可选:会话/表单扩展的运行时依赖

若计划使用 Session/DIO/表单扩展包(安装已完成,是源码包自带的 packages/),还需三个系统包,实测版本:

DEBIAN_FRONTEND=noninteractive apt-get install -y libsqlite3-tcl itcl3 tcllib 2>&1 | tail -3
dpkg -l libsqlite3-tcl itcl3 tcllib | awk '/^ii/{print $2, $3}'
itcl3             3.4.3+dfsg-1build2
libsqlite3-tcl    3.37.2-2
tcllib            2.0+dfsg-1
包提供能力被 Rivet 哪部分依赖
itcl3Tcl 面向对象扩展(Itcl 包)DIO、Session 均为 itcl 类,缺它直接报 can't find package Itcl
libsqlite3-tclTcl 的 sqlite3 绑定Session 默认经 DIO 落 sqlite 库
tcllibmd5/sha 等标准库Session 会话 ID 生成依赖 md5

验证三者可用:

echo 'package require Itcl; package require sqlite3; package require md5; puts ok' | tclsh
ok

八、安装验证清单

安装完成后按序自检:

#检查项命令预期
1模块文件存在ls /usr/lib/apache2/modules/mod_rivet.so存在
2模块已启用ls /etc/apache2/mods-enabled/ | grep rivetrivet.load、rivet.conf 两个符号链接
3配置语法apachectl -tSyntax OK
4模块注册类型curl -s -o /dev/null -w '%{http_code}' http://localhost/hello.rvt200
5模板插值curl -s http://localhost/hello.rvt | grep -c 'Hello Rivet'≥ 1
6.tcl 处理器curl -s http://localhost/info.tcl输出 Tcl 版本
7会话依赖echo 'package require Itcl;package require sqlite3;package require md5;puts ok' | tclshok

第 3 项的实测回显:

apachectl -t
Syntax OK

第 2 项的实测回显:

ls /etc/apache2/mods-enabled/ | grep rivet
rivet.conf
rivet.load

九、常见问题与回退

9.1 模块加载但 .rvt 不被处理(返回 404 之外的原文下载)

现象:curl 得到模板源码。原因:AddType 未生效或写在 <IfModule> 外被注释。排查:

apachectl -M | grep rivet
 rivet_module (shared)

模块已在但类型未映射,检查 rivet.conf 中的 AddType 行是否被正确包含。

9.2 3.2.1 模块与 3.3.1 库混装段错误

实测记录:先以源码方案装 3.3.1,再 apt 安装 3.2.1(覆盖 /usr/lib/apache2/modules/mod_rivet.so),启动后错误日志持续出现:

[Fri Oct 16 04:24:09.689402 2026] [core:notice] [pid 9601:tid 130689066289024] AH00051: child pid 11791 exit signal Segmentation fault (11), possible coredump in /etc/apache2

处理流程(实测有效):

DEBIAN_FRONTEND=noninteractive dpkg --configure -a --force-confold   # 先结束半安装状态
apt-get remove -y --purge libapache2-mod-rivet libapache2-mod-rivet-doc
cp /root/mod_rivet-3.3.1.so /usr/lib/apache2/modules/mod_rivet.so    # 恢复配套版本
rm -f /run/apache2/apache2.pid                                        # 清理残留 pid
apachectl -k start
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/hello.rvt
200

⚠️ 注意:purge 包时其 postrm 会顺带删除 mods-enabled 下的 rivet 链接与包自带的 rivet.load/rivet.conf,需按 6.1 重建并 a2enmod rivet;若 apachectl 报 httpd already running 但进程已为僵尸,先删 /run/apache2/apache2.pid。

9.3 heredoc 写模板导致变量丢失

现象:页面 200,但 <?= $title ?> 输出为空。原因:bash -c 内非引用 heredoc 的 $ 被展开。修复:heredoc 定界符加引号(<<'EOF')。排查方法:

cat -A /var/www/html/hello.rvt | head -3

若 <?= ?> 中间变量名已消失,即可确认是文件写入问题而非 Rivet 问题。

9.4 完全卸载

源码方案卸载:

rm -f /etc/apache2/mods-enabled/rivet.load /etc/apache2/mods-enabled/rivet.conf
rm -f /etc/apache2/mods-available/rivet.load /etc/apache2/mods-available/rivet.conf
rm -f /usr/lib/apache2/modules/mod_rivet.so
rm -rf /usr/local/apache2/lib/rivet3.3.1
apachectl -k restart

apt 方案卸载:

apt-get remove -y --purge libapache2-mod-rivet libapache2-mod-rivet-doc
apachectl -k restart

十、参考链接