概述
本教程目标:在 arm64 Ubuntu 20.04 本机编译 Transmission 4.0.6,打包为与官方
2.94 安装包行为完全一致的 .deb,包括:
- systemd 服务、init.d 脚本
- transmission 系统用户自动创建
- /var/lib/transmission-daemon/info/settings.json 配置
- Web UI 界面
- transmission-daemon / transmission-cli / transmission-remote 等全套工具
输出三个包(与官方结构一致):
transmission-common_4.0.6_all.deb — Web UI + 共享文件
transmission-daemon_4.0.6_arm64.deb — daemon 主程序 + 服务
transmission-cli_4.0.6_arm64.deb — CLI 工具集
第一步:卸载旧版本(保留配置和数据)
# 停止服务
systemctl stop transmission-daemon
# 备份配置(两个路径都备份,以防万一)
cp -a /var/lib/transmission-daemon /var/lib/transmission-daemon.bak
cp -a /etc/transmission-daemon /etc/transmission-daemon.bak 2>/dev/null || true
# 仅卸载程序,保留配置文件(切勿用 purge,那会删数据)
apt remove transmission-daemon transmission-cli transmission-common
验证旧数据保留:
ls /var/lib/transmission-daemon.bak/
# 应看到 info/ 目录(含 settings.json 和 torrents/)
第二步:安装编译依赖
apt-get update
apt-get install -y \
build-essential cmake ninja-build pkg-config git \
libssl-dev \
libcurl4-openssl-dev \
libsystemd-dev \
libevent-dev \
libminiupnpc-dev \
libnatpmp-dev \
zlib1g-dev \
dpkg-dev debhelper devscripts
检查最低版本要求:
cmake --version # 需要 >= 3.16,focal 自带 3.16.3 ✓
g++ --version # 需要支持 C++17,focal 自带 g++ 9.4 ✓
第三步:获取源码
export BUILD_ROOT=/opt/transmission-build
mkdir -p ${BUILD_ROOT}/{src,pkg,install}
cd ${BUILD_ROOT}/src
git clone --recurse-submodules https://github.com/transmission/transmission.git
cd transmission
git checkout 4.0.6
git submodule update --init --recursive
# 确认版本标签
grep 'set(TR_VERSION' CMakeLists.txt
# 期望:set(TR_VERSION "4.0.6")
第四步:编译
4.1 处理 libdeflate
apt-cache show libdeflate-dev 2>/dev/null | grep Version
存在 → 安装它:
apt-get install -y libdeflate-dev
export USE_DEFLATE="-DUSE_SYSTEM_DEFLATE=ON"
不存在 → 使用 Transmission 内置版本(无需任何额外操作):
export USE_DEFLATE="-DUSE_SYSTEM_DEFLATE=OFF"
4.2 cmake 配置
cd ${BUILD_ROOT}/src/transmission
cmake -B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_INSTALL_PREFIX=/usr \
-DENABLE_DAEMON=ON \
-DENABLE_CLI=ON \
-DENABLE_GTK=OFF \
-DENABLE_QT=OFF \
-DENABLE_MAC=OFF \
-DENABLE_TESTS=OFF \
-DINSTALL_DOC=OFF \
-DUSE_SYSTEM_EVENT2=ON \
-DUSE_SYSTEM_MINIUPNPC=ON \
-DUSE_SYSTEM_NATPMP=ON \
-DUSE_SYSTEM_PSL=OFF \
-DUSE_SYSTEM_DEFLATE=OFF \
2>&1 | tee ${BUILD_ROOT}/cmake.log
# 确认关键库已找到
grep -E "OpenSSL|CURL|libevent|miniupnpc|natpmp" ${BUILD_ROOT}/cmake.log
报错处理:若提示 Could not find miniupnpc,改用 -DUSE_SYSTEM_MINIUPNPC=OFF;
natpmp 同理。使用内置版本功能完全一致,只是不依赖系统库。
4.3 编译并安装到临时目录
cmake --build build -j$(nproc) 2>&1 | tee ${BUILD_ROOT}/build.log
# 检查有无编译错误
grep -E "^.*error:.*$" ${BUILD_ROOT}/build.log | grep -v "warning:" | head -20
# 安装到临时目录
DESTDIR=${BUILD_ROOT}/install cmake --install build
# 验证产物
file ${BUILD_ROOT}/install/usr/bin/transmission-daemon
# ELF 64-bit LSB pie executable, ARM aarch64 ✓
${BUILD_ROOT}/install/usr/bin/transmission-daemon --version
# transmission-daemon 4.0.6 (...) ✓
ldd ${BUILD_ROOT}/install/usr/bin/transmission-daemon | grep "not found"
# 无任何输出 = 所有依赖均满足 ✓
第五步:制作 deb 包
5.1 推导精确的运行时依赖包名
在写 control 文件之前,先精确推导依赖,避免手写错误:
ldd ${BUILD_ROOT}/install/usr/bin/transmission-daemon \
| awk '/=>/{print $1}' \
| while read lib; do
pkg=$(dpkg -S "$(ldconfig -p | grep "${lib}" | awk '{print $NF}' | head -1)" \
2>/dev/null | awk -F: '{print $1}' | head -1)
echo " ${lib} => ${pkg}"
done
典型输出(请以实际输出为准):
libssl.so.1.1 => libssl1.1
libevent_core-2.1.so.7 => libevent-2.1-7
libcurl.so.4 => libcurl4
libminiupnpc.so.17 => libminiupnpc17
libnatpmp.so.1 => libnatpmp1
libsystemd.so.0 => libsystemd0
libstdc++.so.6 => libstdc++6
libc.so.6 => libc6
5.2 transmission-common(Web UI + 共享文件)
PKG_ROOT=${BUILD_ROOT}/pkg
PKG_COMMON=${PKG_ROOT}/transmission-common_4.0.6_all
mkdir -p ${PKG_COMMON}/DEBIAN
mkdir -p ${PKG_COMMON}/usr/share/transmission
mkdir -p ${PKG_COMMON}/usr/share/doc/transmission-common
# Web UI 文件
cp -r ${BUILD_ROOT}/install/usr/share/transmission/public_html \
${PKG_COMMON}/usr/share/transmission/
# 版权文件(dpkg 要求必须存在)
cat > ${PKG_COMMON}/usr/share/doc/transmission-common/copyright << 'EOF'
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: transmission
Source: https://github.com/transmission/transmission
Files: *
Copyright: 2005-2024 The Transmission Project
License: GPL-2+
EOF
cat > ${PKG_COMMON}/DEBIAN/control << 'EOF'
Package: transmission-common
Version: 4.0.6
Architecture: all
Maintainer: Local Build <root@localhost>
Description: lightweight BitTorrent client (common files)
Transmission is a free, lightweight BitTorrent client.
This package contains the Web interface and other shared files.
EOF
5.3 transmission-daemon
PKG_DAEMON=${PKG_ROOT}/transmission-daemon_4.0.6_arm64
mkdir -p ${PKG_DAEMON}/DEBIAN
mkdir -p ${PKG_DAEMON}/usr/bin
mkdir -p ${PKG_DAEMON}/usr/share/doc/transmission-daemon
mkdir -p ${PKG_DAEMON}/lib/systemd/system
mkdir -p ${PKG_DAEMON}/etc/init.d
mkdir -p ${PKG_DAEMON}/etc/default
# 二进制(去除调试符号)
strip --strip-unneeded ${BUILD_ROOT}/install/usr/bin/transmission-daemon
strip --strip-unneeded ${BUILD_ROOT}/install/usr/bin/transmission-remote
cp ${BUILD_ROOT}/install/usr/bin/transmission-daemon \
${BUILD_ROOT}/install/usr/bin/transmission-remote \
${PKG_DAEMON}/usr/bin/
# systemd 服务文件
cat > ${PKG_DAEMON}/lib/systemd/system/transmission-daemon.service << 'EOF'
[Unit]
Description=Transmission BitTorrent Daemon
After=network.target
Wants=network-online.target
[Service]
User=debian-transmission
Group=debian-transmission
Type=notify
EnvironmentFile=-/etc/default/transmission-daemon
ExecStart=/usr/bin/transmission-daemon -f --log-level=error
ExecReload=/bin/kill -s HUP $MAINPID
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/var/lib/transmission-daemon /tmp
ProtectHome=true
LimitNOFILE=65536
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# /etc/default 环境文件
cat > ${PKG_DAEMON}/etc/default/transmission-daemon << 'EOF'
# Transmission daemon extra options
# See transmission-daemon(1) for available options
OPTIONS=""
EOF
# init.d 脚本(兼容非 systemd 环境)
cat > ${PKG_DAEMON}/etc/init.d/transmission-daemon << 'INITEOF'
#!/bin/sh
### BEGIN INIT INFO
# Provides: transmission-daemon
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Transmission BitTorrent Daemon
### END INIT INFO
NAME=transmission-daemon
DAEMON=/usr/bin/transmission-daemon
CONFIG_DIR=/var/lib/transmission-daemon/info
PIDFILE=/var/run/transmission-daemon.pid
USER=debian-transmission
. /lib/lsb/init-functions
[ -f /etc/default/transmission-daemon ] && . /etc/default/transmission-daemon
do_start() {
start-stop-daemon --start --background --make-pidfile \
--pidfile $PIDFILE --chuid $USER \
--exec $DAEMON -- --config-dir $CONFIG_DIR -f $OPTIONS
}
do_stop() {
start-stop-daemon --stop --pidfile $PIDFILE --retry TERM/30/KILL/5
rm -f $PIDFILE
}
case "$1" in
start) log_daemon_msg "Starting $NAME"; do_start; log_end_msg $? ;;
stop) log_daemon_msg "Stopping $NAME"; do_stop; log_end_msg $? ;;
reload) kill -HUP $(cat $PIDFILE 2>/dev/null) 2>/dev/null || true ;;
restart) do_stop; sleep 1; do_start ;;
status) status_of_proc -p $PIDFILE $DAEMON $NAME ;;
*) echo "Usage: $0 {start|stop|restart|reload|status}"; exit 1 ;;
esac
INITEOF
chmod 755 ${PKG_DAEMON}/etc/init.d/transmission-daemon
# 版权文件
cp ${PKG_COMMON}/usr/share/doc/transmission-common/copyright \
${PKG_DAEMON}/usr/share/doc/transmission-daemon/copyright
# conffiles(升级时不覆盖用户的配置)
cat > ${PKG_DAEMON}/DEBIAN/conffiles << 'EOF'
/etc/default/transmission-daemon
EOF
# preinst:创建系统用户(与官方 2.94 完全一致)
cat > ${PKG_DAEMON}/DEBIAN/preinst << 'EOF'
#!/bin/sh
set -e
case "$1" in
install|upgrade)
if ! getent group debian-transmission > /dev/null 2>&1; then
addgroup --system debian-transmission
fi
if ! getent passwd debian-transmission > /dev/null 2>&1; then
adduser --system \
--ingroup debian-transmission \
--home /var/lib/transmission-daemon \
--no-create-home \
--shell /usr/sbin/nologin \
--disabled-password \
--gecos "Transmission BitTorrent Daemon" \
debian-transmission
fi
;;
esac
exit 0
EOF
# postinst:设置目录权限、生成默认配置、启动服务
cat > ${PKG_DAEMON}/DEBIAN/postinst << 'EOF'
#!/bin/sh
set -e
case "$1" in
configure)
# 目录结构
mkdir -p /var/lib/transmission-daemon/info
mkdir -p /var/lib/transmission-daemon/downloads
mkdir -p /var/lib/transmission-daemon/incomplete
# /etc/transmission-daemon 软链接(与 2.94 一致)
if [ ! -e /etc/transmission-daemon ]; then
ln -s /var/lib/transmission-daemon/info /etc/transmission-daemon
fi
# 权限
chown -R debian-transmission:debian-transmission \
/var/lib/transmission-daemon
chmod 750 /var/lib/transmission-daemon
chmod 750 /var/lib/transmission-daemon/info
# 全新安装时生成默认 settings.json
if [ ! -f /var/lib/transmission-daemon/info/settings.json ]; then
cat > /var/lib/transmission-daemon/info/settings.json << 'SETTINGS'
{
"download-dir": "/var/lib/transmission-daemon/downloads",
"incomplete-dir": "/var/lib/transmission-daemon/incomplete",
"incomplete-dir-enabled": false,
"rpc-authentication-required": true,
"rpc-bind-address": "0.0.0.0",
"rpc-enabled": true,
"rpc-password": "transmission",
"rpc-port": 9091,
"rpc-username": "transmission",
"rpc-whitelist": "127.0.0.1",
"rpc-whitelist-enabled": true
}
SETTINGS
chown debian-transmission:debian-transmission \
/var/lib/transmission-daemon/info/settings.json
chmod 600 /var/lib/transmission-daemon/info/settings.json
fi
# 启用并启动 systemd 服务
if [ -d /run/systemd/system ]; then
systemctl daemon-reload || true
systemctl enable transmission-daemon.service || true
systemctl start transmission-daemon.service || true
fi
;;
esac
exit 0
EOF
# prerm:停止服务
cat > ${PKG_DAEMON}/DEBIAN/prerm << 'EOF'
#!/bin/sh
set -e
case "$1" in
remove|upgrade|deconfigure)
if [ -d /run/systemd/system ]; then
systemctl stop transmission-daemon.service || true
systemctl disable transmission-daemon.service || true
fi
;;
esac
exit 0
EOF
# postrm:purge 时清理用户和数据
cat > ${PKG_DAEMON}/DEBIAN/postrm << 'EOF'
#!/bin/sh
set -e
case "$1" in
purge)
deluser --system debian-transmission 2>/dev/null || true
delgroup --system debian-transmission 2>/dev/null || true
rm -rf /var/lib/transmission-daemon
rm -f /etc/transmission-daemon
;;
remove)
if [ -d /run/systemd/system ]; then
systemctl daemon-reload || true
fi
;;
esac
exit 0
EOF
# 权限修正
chmod 755 ${PKG_DAEMON}/DEBIAN/{preinst,postinst,prerm,postrm}
find ${PKG_DAEMON}/usr/bin -type f -exec chmod 755 {} \;
# control 文件(Depends 以第 5.1 节的实际输出为准)
cat > ${PKG_DAEMON}/DEBIAN/control << 'EOF'
Package: transmission-daemon
Version: 4.0.6
Architecture: arm64
Maintainer: Local Build <root@localhost>
Depends: transmission-common (= 4.0.6),
libc6,
libgcc-s1,
libstdc++6,
libsystemd0,
libssl1.1,
libcurl4,
libevent-2.1-7,
libminiupnpc17,
libnatpmp1,
adduser,
lsb-base
Description: lightweight BitTorrent client (daemon)
Transmission is a free, lightweight BitTorrent client.
This package contains the daemon, controllable via web UI or
transmission-remote.
EOF
5.4 transmission-cli
PKG_CLI=${PKG_ROOT}/transmission-cli_4.0.6_arm64
mkdir -p ${PKG_CLI}/DEBIAN
mkdir -p ${PKG_CLI}/usr/bin
mkdir -p ${PKG_CLI}/usr/share/doc/transmission-cli
for bin in transmission-cli transmission-create transmission-edit transmission-show; do
src=${BUILD_ROOT}/install/usr/bin/${bin}
if [ -f "${src}" ]; then
strip --strip-unneeded "${src}"
cp "${src}" ${PKG_CLI}/usr/bin/
chmod 755 ${PKG_CLI}/usr/bin/${bin}
fi
done
cp ${PKG_COMMON}/usr/share/doc/transmission-common/copyright \
${PKG_CLI}/usr/share/doc/transmission-cli/copyright
cat > ${PKG_CLI}/DEBIAN/control << 'EOF'
Package: transmission-cli
Version: 4.0.6
Architecture: arm64
Maintainer: Local Build <root@localhost>
Depends: transmission-common (= 4.0.6),
libc6,
libgcc-s1,
libstdc++6,
libssl1.1,
libcurl4,
libevent-2.1-7
Description: lightweight BitTorrent client (command line programs)
Transmission is a free, lightweight BitTorrent client.
This package contains: transmission-cli, transmission-create,
transmission-edit, transmission-remote, and transmission-show.
EOF
第六步:构建 .deb 文件
cd ${PKG_ROOT}
dpkg-deb --root-owner-group --build transmission-common_4.0.6_all
dpkg-deb --root-owner-group --build transmission-daemon_4.0.6_arm64
dpkg-deb --root-owner-group --build transmission-cli_4.0.6_arm64
ls -lh *.deb
构建前做一次完整性检查:
# 检查包结构
for pkg in transmission-common_4.0.6_all \
transmission-daemon_4.0.6_arm64 \
transmission-cli_4.0.6_arm64; do
echo "=== ${pkg} ==="
dpkg-deb -I ${pkg}.deb | grep -E "Package|Version|Architecture|Depends"
echo "文件数: $(dpkg-deb -c ${pkg}.deb | wc -l)"
echo ""
done
# 检查维护脚本语法
for script in ${PKG_ROOT}/transmission-daemon_4.0.6_arm64/DEBIAN/{preinst,postinst,prerm,postrm}; do
bash -n "${script}" && echo "$(basename ${script}): OK"
done
第七步:安装与验证
# 按依赖顺序安装
dpkg -i \
${PKG_ROOT}/transmission-common_4.0.6_all.deb \
${PKG_ROOT}/transmission-daemon_4.0.6_arm64.deb \
${PKG_ROOT}/transmission-cli_4.0.6_arm64.deb
# 如有依赖缺失,自动补全
apt-get install -f
验证安装结果:
# 版本
transmission-daemon --version
# transmission-daemon 4.0.6 (...)
# 系统用户
id debian-transmission
# uid=xxx(debian-transmission) gid=xxx groups=xxx(debian-transmission)
# 服务状态
systemctl status transmission-daemon
# 配置文件
ls -la /var/lib/transmission-daemon/info/
cat /var/lib/transmission-daemon/info/settings.json
# 软链接
ls -la /etc/transmission-daemon
# /etc/transmission-daemon -> /var/lib/transmission-daemon/info
# Web UI(等服务起来后测试)
curl -s http://127.0.0.1:9091/transmission/web/ | head -5
第八步:迁移旧数据
# 停止服务
systemctl stop transmission-daemon
# 将 2.94 的数据覆盖进来(格式完全兼容)
cp -a /var/lib/transmission-daemon.bak/info/. \
/var/lib/transmission-daemon/info/
# 修复权限
chown -R debian-transmission:debian-transmission /var/lib/transmission-daemon
chmod 600 /var/lib/transmission-daemon/info/settings.json
# 启动
systemctl start transmission-daemon
systemctl status transmission-daemon
附录:常见错误
| 错误信息 | 原因 | 解决方法 |
|----------|------|----------|
| Could not find miniupnpc | 系统版本太低或未安装 | 加 -DUSE_SYSTEM_MINIUPNPC=OFF |
| libdeflate required | 系统无此库 | 加 -DUSE_SYSTEM_DEFLATE=OFF |
| dpkg: dependency problems | control Depends 包名错误 | 用第 5.1 节脚本重新推导 |
| postinst returned error code 1 | 脚本内部命令失败 | bash -x DEBIAN/postinst configure 调试 |
| 服务启动后立刻退出 | settings.json 格式错误 | python3 -m json.tool settings.json |
| Web UI 显示 404 | public_html 未打入 common 包 | 检查 dpkg-deb -c transmission-common*.deb |
| ldd: not found 有输出 | 链接了系统没有的库 | 对应库改用内置版本(-DUSE_SYSTEM_XX=OFF) |