Linux离线安装SVN完整指南:RPM与源码编译两种实战路线
2026/9/18 1:38:40 网站建设 项目流程

我帮朋友装过一台完全断网的生产服务器,对方给的唯一要求就是"把SVN跑起来"。没有外网、没有本地镜像源、甚至没有图形界面,这种情况下最忌讳的就是上来就yum install subversion,然后被一连串的依赖报错卡到怀疑人生。这篇文章不是抄官方文档,就是针对离线环境的一次完整实操记录。我会把两条可行的路线(RPM依赖包离线安装、源码编译安装)都走一遍,把每一步为什么这么做讲清楚,最后补充仓库初始化和最常见的排坑经验。

1. 先想清楚:离线装SVN,本质上是在解决什么

很多人在内网环境装SVN,第一反应是"我没有外网,怎么下载软件包"。这个问题其实只答对了一半。离线安装真正麻烦的地方在于:SVN服务端(subversion)本身只是一个主程序,它依赖一堆底层库,比如aprapr-utilsqliteexpatzlibopenssl等等。在有网环境下,包管理器会帮你自动搞定这些依赖;一旦断网,这些依赖全部要你手动收集齐,少一个就装不上。

1.1 先明确你装的到底是什么

SVN分服务端和客户端。我们常说的TortoiseSVN是Windows下的图形化客户端,svn命令行工具是客户端,而svnserve(SVN自带的一个轻量服务进程)和Apache + mod_dav_svn(通过WebDAV协议提供服务)才是服务端。

离线安装搭建SVN服务端,核心任务就是安装subversion这个软件包,并让它依赖的库在系统里就位。至于客户端工具svn,其实是随服务端一起装上的,因为subversion这个包本身就包含了svnsvnservesvnadmin等全套命令行工具。所以装好服务端之后,本地命令行也能直接当客户端用,不算额外工作。

1.2 两条路线的选型逻辑

离线安装SVN,主流就两条路线:

  • 路线A:下载RPM依赖包,通过rpm -ivhyum localinstall安装。适合操作系统版本明确(比如CentOS 7.x / RHEL系),且在另一台同版本、同架构的机器上可以临时联网的场景。优点是安装快、路径规范、用系统自带的方式管理服务;缺点是必须精确匹配系统版本和内核架构,跨大版本很容易翻车。

  • 路线B:下载源码包,编译安装。适合内网机器系统版本老旧、找不到对应RPM包,或者LD长治要求指定安装路径的场景。缺点是编译时间较长,而且离线环境下还需要提前准备好编译器(gcc、make)和一堆依赖库的源码,门槛更高。

我个人的建议是:能用RPM优先用RPM。因为源码编译虽然看起来"万能",但离线环境下如果缺了某个开发库,需要手动下载对应源码再编一次,那才是真的折磨。RPM方式最符合"简单、完整、一目了然"这个目标。

2. 动手之前的环境确认:少做一步,后面全是坑

这部分容易被忽略,但恰恰是离线安装成败的关键。我见过不少同事跳过环境确认直接去下包,结果下载回来的RPM包跟目标系统不兼容,白白浪费时间。

2.1 确认目标系统的版本和架构

在目标Linux机器上执行:

cat /etc/os-release uname -m

/etc/os-release会告诉我用的是哪种发行版、主版本号是多少;uname -m确认是x86_64还是aarch64(ARM架构)。这两项信息决定了后续要去哪里下载RPM包、下载哪个版本。

比如一台CentOS 7.9 x86_64的机器,那么下载RPM包时就要认准el7.x86_64的标识;如果是Kylin或openEuler这类国产系统,则要看它兼容的是el7还是el8的包规范。不同大版本之间RPM包不能混装,el7的包装到el8上几乎必出依赖冲突。

2.2 检查系统是否已经自带了SVN

这一步90%的人会跳过。有些精简版系统或者往届同事已经装过一部分组件,执行:

which svnserve svnserve --version

如果输出版本信息,说明这台机器已经有SVN服务端了,直接跳到第五章节的仓库配置就行。判断的依据是,svnserve是SVN自带的服务进程,只要它在,基本就代表核心服务端已经就位。

2.3 整理一份依赖包清单,别指望一次全记住

下面以CentOS 7 / RHEL 7系为例,RPM安装subversion典型会涉及的包包括:

  • subversion(主包)
  • aprapr-util(Apache可移植运行时库,SVN的核心依赖)
  • sqlite(SVN存储元数据所需的轻量数据库)
  • expat(XML解析库)
  • zlib(压缩库)
  • opensslopenssl-libs(加密通信支持,若走svn://协议可以不需要,但多数系统已经自带)

这里不用硬背,最重要的是有一个可联网的同版本机器,用包管理器把这些包一次性拉下来。下一章我会给出具体的命令方式。

3. RPM离线安装完整实操:有网机器上一下包,内网机器上直接装

这是我最推荐的方式,步骤少、坑也少。核心思路是:在能联网且系统版本与目标机器一致的机器上,只下载不安装,然后把所有RPM包拷贝到目标机器,一次性本地安装。

3.1 在临时联网机器上拉取RPM包

临时联网机器的系统版本必须与目标机器一致,这一步不要有任何侥幸心理。假设我有一台CentOS 7.9 x86_64的联网机器,先配置好标准的Yum源,然后执行:

# 确保yum源可用 yum clean all && yum makecache # 安装yum-plugin-downloadonly(CentOS 7自带的yum通常已支持--downloadonly) yum install -y yum-plugin-downloadonly # 只下载subversion及其所有依赖到指定目录 mkdir -p /tmp/svn-rpms yum install --downloadonly --downloaddir=/tmp/svn-rpms subversion

执行完之后,/tmp/svn-rpms目录下会出现一连串RPM包。这里的关键是,--downloadonly会连同所有依赖一起拉取,免去了手动逐个找依赖的烦恼。如果是比较新的CentOS 8或Rocky Linux,dnf本身就支持--downloadonly,直接:

dnf install --downloadonly --downloaddir=/tmp/svn-rpms subversion

如果手头连不上标准Yum源,也可以从pkgs.org这类镜像站按包名手动搜索下载,但务必注意选择与目标系统匹配的release版本和架构。手动找包时有一个小技巧:把主包subversion先下载下来,然后反复执行rpm -Uvh --test subversion*.rpm,它会提示缺哪个依赖,再逐个下载,直到--test不再报错为止。

3.2 将RPM包拷贝到目标机器

将整个/tmp/svn-rpms目录打包后传输到内网机器。传输方式根据现场条件选择:

# 打包 cd /tmp && tar czf svn-rpms.tar.gz svn-rpms # 可以用scp(如果网络通)、U盘拷贝,或者内网FTP scp svn-rpms.tar.gz user@target-server:/tmp/

3.3 在目标机器上批量安装

解压后,进入RPM包目录,执行:

cd /tmp/svn-rpms rpm -ivh *.rpm

这里不要用rpm -ivhyum localinstall一起混用。rpm -ivh *.rpm能自动处理同目录下多个RPM包之间的依赖关系,对于离线场景已经足够。如果提示某个包已存在,可以改成rpm -Uvh *.rpm进行升级安装,作用等同于安装或更新到更高版本,覆盖场景更全。

安装完成后,验证是否成功:

svnserve --version

如果看到关于svnserve, version 1.7.x或1.10.x之类的输出,服务端和客户端命令行工具就都就位了。

提示:不要试图用rpm -ivh一个一个地装,因为依赖顺序出错会频繁报错。直接*.rpm批量装,让rpm自己解析当前目录里所有包的依赖关系,这是最简单高效的方式。

4. 源码编译安装:当RPM路线走不通时的替代方案

有些情况RPM路线确实搞不定。比如目标机器是特制内核的精简系统、或者系统的glibc版本比较特殊,导致官方RPM包装不上。这时候只能走源码编译。

4.1 编译环境准备

源码编译需要gcc、make等开发工具。如果系统里连gcc都没有,而你又身处完全离线环境,那就麻烦了,必须先解决gcc的问题。因此,走源码编译之前,要先在目标机器上确认:

gcc --version make --version

如果已经存在,很好;如果不存在,就得先找一套与系统匹配的gcc RPM包离线装上。这也是我为什么一直强调"能用RPM就用RPM"的原因之一——编译安装的前提是工具链也得齐。

4.2 获取源码包并编译

在联网机器上,从Apache SVN官网或国内镜像站下载subversion源码包,同时下载它的依赖库源码包。这里注意版本配套,比如subversion 1.14.x通常搭配apr 1.7.x和apr-util 1.6.x:

# 以subversion 1.14.2为例 wget https://archive.apache.org/dist/subversion/subversion-1.14.2.tar.gz wget https://archive.apache.org/dist/apr/apr-1.7.0.tar.gz wget https://archive.apache.org/dist/apr/apr-util-1.6.3.tar.gz

将源码包全部拷贝到目标机器后,按依赖顺序逐个编译安装:

tar xzf apr-1.7.0.tar.gz cd apr-1.7.0 ./configure --prefix=/usr/local/apr make && make install

再编apr-util,需要指定apr的安装路径:

cd ../apr-util-1.6.3 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr make && make install

最后编译subversion本体:

tar xzf subversion-1.14.2.tar.gz cd subversion-1.14.2 ./configure --prefix=/usr/local/svn --with-apr=/usr/local/apr --with-apr-util=/usr/local/apr-util make && make install

完成后,可执行文件在/usr/local/svn/bin目录下。为了方便调用,建议做个软链接:

ln -s /usr/local/svn/bin/svn /usr/local/bin/svn ln -s /usr/local/svn/bin/svnserve /usr/local/bin/svnserve ln -s /usr/local/svn/bin/svnadmin /usr/local/bin/svnadmin

4.3 源码编译与RPM方式的关键差异

源码编译和RPM方式,装完之后最大的区别在于服务管理方式。RPM方式一般会向systemd注册好服务(比如CentOS上subversion可能自带svnserve.service),直接systemctl start svnserve即可;源码编译则没有这些现成的服务脚本,需要自己写一个systemd unit文件,或者直接通过命令行启动。

另一个差异是后续升级。RPM方式升级一般就是替换新版本RPM包;源码编译升级则要重新走一遍编译流程,而且要注意原有仓库数据和配置文件的兼容性,升级前一定要做备份(后面会专门讲备份方法)。

提示:源码编译前务必在/usr/local之外规划好仓库目录(比如/data/svn),不要图省事把仓库建在安装目录里。一来方便升级时不动仓库数据,二来避免安装目录权限变动导致仓库不可访问。

5. 装完只是第一步:仓库初始化、权限配置与服务启动

很多教程写到"安装成功"就结束了,但真正让SVN可用,仓库创建和权限配置才是重头戏。这部分80%的坑都出在配置文件细节上,我会一个一个说清楚。

5.1 创建仓库目录并初始化

先规划好仓库根目录。推荐单独放一个分区或目录,方便备份:

mkdir -p /data/svn/repos svnadmin create /data/svn/repos

svnadmin create会在/data/svn/repos下生成一套完整的仓库骨架,包括conf(配置目录)、hooks(钩子脚本目录)、db(实际存储目录)等。这一步执行完,仓库就已创建成功,但还没有任何权限控制。

5.2 配置文件逐项解读:svnserve.conf是三件套的入口

进入仓库的conf目录,会发现三个关键文件:svnserve.confpasswdauthz。这是SVN权限认证的三件套。先看svnserve.conf

cd /data/svn/repos/conf vim svnserve.conf

打开后能看到几个带#注释的配置项,最核心的有:

[general] anon-access = none auth-access = write password-db = passwd authz-db = authz realm = /data/svn/repos

各项的含义:

  • anon-access = none:匿名用户不允许任何访问。如果这里改成read,任何人都能看到仓库内容;改成none是内网使用最安全的选择,因为SVN默认协议不加密,匿名可读意味着任何内网机器都能拉数据。
  • auth-access = write:认证用户拥有读写权限。
  • password-db = passwd:指定用户密码文件为同目录下passwd
  • authz-db = authz:指定权限控制文件为同目录下authz
  • realm:认证域,设置为仓库路径/data/svn/repos即可。

这里有两个非常隐蔽的坑:

  1. 配置项前不能有空格。把配置项复制出来时,很容易在行首带上一个空格,这样该项会被SVN当作无效配置直接忽略。
  2. 注释不能与配置项同行。如果写成auth-access = write # 注释,SVN无法正确解析,同样会导致配置不生效。

5.3 设置用户密码与读写权限

编辑passwd文件,添加用户和密码,格式是用户名 = 密码

[users] admin = admin123 dev = dev123 test = test123

记住:SVN的用户名和密码是用=连接的,等号两侧有没有空格都可以,但避免密码里出现特殊字符导致解析问题。明文保存,注意passwd文件的权限尽量设置为600,防止同机其他用户读到密码。

接着编辑authz文件,配置用户权限。authz的基本结构是先定义组,再给路径赋权:

[groups] devteam = dev, test [/] admin = rw @devteam = rw * = r

[/]表示仓库根目录权限;@devteam是组的写法,组名要加@前缀;* = r表示其他所有认证用户只有读权限。如果不想让未授权用户看到任何内容,可以写* =(不赋予任何权限)。注意,authz文件里的用户必须已经在passwd里定义过,否则无法完成认证。

5.4 启动服务与开机自启

如果是RPM方式安装,一般已经注册了systemd服务;如果是源码编译安装,服务需要手动配置。不管哪种方式,最稳的启动方式是用svnserve自带参数:

svnserve -d -r /data/svn --listen-port 3690

参数含义:

  • -d:后台守护进程运行。
  • -r /data/svn:指定仓库根目录。访问方式就变成svn://IP/repos
  • --listen-port 3690:默认端口就是3690,如果没被占用可以省略。

如果想做成开机自启,推荐写一个systemd unit文件。以源码编译安装为例:

vim /etc/systemd/system/svnserve.service

内容如下:

[Unit] Description=Subversion Server After=network.target [Service] Type=forking ExecStart=/usr/local/svn/bin/svnserve -d -r /data/svn --listen-port 3690 ExecReload=/bin/kill -HUP $MAINPID PIDFile=/var/run/svnserve.pid Restart=on-failure [Install] WantedBy=multi-user.target

执行:

systemctl daemon-reload systemctl enable svnserve systemctl start svnserve

如果svnserve是通过RPM装到/usr/bin/svnserve,ExecStart路径要相应调整。

5.5 本地验证:用命令确认服务真的通了

服务启动后,在同一台机器(或任何能访问到3690端口的机器)上验证:

# 第一次拉取工作副本(把仓库挂载到本地临时目录) svn co svn://127.0.0.1/repos /tmp/svn-test --username admin --password admin123 # 或者只列出仓库内容 svn list svn://127.0.0.1/repos --username admin --password admin123

如果配置正确,会看到空仓库的repos目录被checkout下来,说明SVN服务端已经工作正常。如果这里报认证失败,优先检查svnserve.conf的配置项是否有前导空格、passwdauthz的路径是否正确。

6. 踩坑记录:防火墙、SELinux与那些"看起来没问题却死活用不了"的瞬间

最后这部分写几个我在实际部署中遇到过的经典问题。这些问题如果不在刚装完的阶段解决,过几天用户开始接入时,会一个接一个爆出来,那时再排查压力更大。

6.1 防火墙拦住了3690端口

这是最最常见的"服务起来了但客户端连不上"的原因。在目标机器上检查防火墙状态:

systemctl status firewalld

如果防火墙是开启的,必须放行3690端口:

firewall-cmd --permanent --add-port=3690/tcp firewall-cmd --reload # 确认已生效 firewall-cmd --list-ports

如果系统用iptables而非firewalld,则添加规则:

iptables -A INPUT -p tcp --dport 3690 -j ACCEPT service iptables save

6.2 SELinux导致svnserve无法监听端口

在CentOS/RHEL系系统上即使防火墙放行,SELinux也可能拦截svnserve访问仓库目录或网络端口。快速判断方法是临时关闭SELinux看看服务是否恢复正常:

# 临时关闭(重启后失效),只用于排查 setenforce 0

如果关掉SELinux后一切正常,则说明是SELinux策略阻挡。更友好的做法是调整对应布尔值(SELinux布尔值是指在SELinux安全策略中控制特定功能开关的配置项,可以用它而非暴力关闭整个SELinux):

# 允许svnserve访问网络 setsebool -P httpd_can_network_connect on # 或者直接允许svnserve读写其仓库目录 chcon -R -t svnserve_content_t /data/svn/repos

chcon命令的作用是将仓库目录的SELinux安全上下文(SELinux中与进程安全域匹配的访问属性标签)改成SVN服务端需要的那个类型,这样在不关闭SELinux的前提下也能让svnserve正常访问仓库。临时关闭SELinux只用于验证问题原因,不要长时间保持关闭状态,否则生产环境的安全防护等于失效。

6.3 客户端能连上,但checkout时没有写权限

服务通了、认证也过了,但一commit东西就报Permission denied,大概率是Linux文件系统权限的问题。

svnserve是以后台进程(默认以root身份)运行的,它创建的所有仓库文件属于root。如果你用某个普通用户通过SVN提交,但SVN本身的authz配了@devteam = rw,却忘了系统级文件权限,也会出现"认证通过提交失败":

# 检查仓库目录的属主和权限 ls -la /data/svn/repos # 将仓库所属改为运行SVN的用户(比如svnuser),或直接改为有写权限的用户组 chown -R svnuser:svnuser /data/svn/repos chmod -R 775 /data/svn/repos

判断的核心点在于:SVN的应用层权限(passwd、authz)管理的是"谁能通过SVN执行操作",而Linux系统权限管理的是"运行svnserve的操作系统用户有没有写文件系统的权限"。这两层缺一不可,排查时要区分才行。建议单独创建一个svnuser系统账号来启动svnserve,并让仓库目录归属于这个账号,这样比直接用root跑更可控,也不容易误改系统文件。

6.4 配置文件的隐藏坑:权限文件路径写错、realm不一致

最后一个容易忽略的是realmsvnserve.conf里的realm值相当于一个"服务标识"。如果客户端之前访问过同样IP但不同realm的服务端,可能会触发认证缓存问题,报Authentication failed或者E170001。这种情况最直接的解决办法就是在客户端上清一下SVN认证缓存目录(rm -rf ~/.subversion/auth),再重新访问。平时配置时,不同仓库或不同服务建议设置不同的realm名称,可以避免这种脏缓存带来的诡异问题。

另外,如果仓库创建好了,但客户端访问时报No repository found,多半是启动参数里的-r指定路径和仓库实际路径不匹配。比如-r /data/svn后访问svn://IP/repos,实际对应的是/data/svn/repos;如果启动时写的是-r /data/svn/repos,那客户端访问svn://IP/repos反而找不到仓库了。这个路径拼接逻辑一定要清楚。

备份方面,SVN仓库本身是一组文件,不能简单用cp复制,推荐用官方自带的全量备份命令,可以保证数据一致性:

svnadmin hotcopy /data/svn/repos /backup/repos-$(date +%F)

svnadmin hotcopy是SVN官方的热备份工具,能够在服务运行状态下生成一个一致性的仓库副本,直接打包这个备份目录即可。定期做一次,配合仓库的hooks目录里的post-commit脚本,还能实现每次提交后自动备份。

一套流程走下来,离线安装SVN其实没有想象中那么神秘。核心思路就是:先确认系统环境,再选择合理的包获取方式,安装完之后重点做好仓库初始化和权限配置,最后把防火墙和SELinux这类"外行杀手"提前排除掉。按这个顺序操作,内网里跑起一个稳的SVN服务器,基本是板上钉钉的事。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询