【Linux】09.WSL+SVN部署操作说明

环境准备

首先通过 wsl 安装一个 Ubuntu 环境,

shell 复制代码
wsl --install -d Ubuntu24.04 --name Ubuntu-SVN --web-download

安装 SVN

输入以下命令安装 subversion,

shell 复制代码
sudo apt install -y subversion

执行结束后,检测安装是否成功,

shell 复制代码
# 检测svn版本号
svn --version

# 检测svnserve版本号
svnserve --version

创建仓库

使用 svnadmin 命令创建一个仓库,该仓库的位置可自定义,

shell 复制代码
## 创建仓库目录
sudo mkdir -p /var/svn

## 使用svnadmin创建仓库
sudo svnadmin create /var/svn/repository

## 提升db文件夹的权限
sudo chmod -R 777 /var/svn/repository/db

编辑 svnserve.conf 文件,将以下内容的注释去掉,

plain 复制代码
[general]
## 控制未认证用户的权限,none-不可读不可写,read-只读,write-读写
anon-access = none
## 控制认证用户的权限,none-不可读不可写,read-只读,write-读写
auth-access = write
## 设置用户密码的文件
password-db = passwd
## 设置用户权限的文件
authz-db = authz
## 设置仓库的名称
realm = repository

配置用户和权限

新增用户

编辑仓库目录下的 password 文件,将需要添加的用户新增到 [user] 内容中,

shell 复制代码
sudo vi /var/svn/repository/config/password
plain 复制代码
### This file is an example password file for svnserve.
### Its format is similar to that of svnserve.conf. As shown in the
### example below it contains one section labelled [users].
### The name and password for each user follow, one account per line.

[users]
zhangsan = 123456

一个用户占一行,参考示例,每个用户为一个键值对,键为用户名,值为密码。修改完成后保存退出。

新增权限

编辑仓库目录下的 authz 文件,

shell 复制代码
sudo vi /var/svn/repository/config/authz
plain 复制代码
### As shown below each section defines authorizations for the path and
### (optional) repository specified by the section name.
### The authorizations follow. An authorization line can refer to:
###  - a single user,
###  - a group of users defined in a special [groups] section,
###  - an alias defined in a special [aliases] section,
###  - all authenticated users, using the '$authenticated' token,
###  - only anonymous users, using the '$anonymous' token,
###  - anyone, using the '*' wildcard.
###
### A match can be inverted by prefixing the rule with '~'. Rules can
### grant read ('r') access, read-write ('rw') access, or no access
### ('').

[aliases]
# joe = /C=XZ/ST=Dessert/L=Snake City/O=Snake Oil, Ltd./OU=Research Institute/CN=Joe Average

[groups]
# harry_and_sally = harry,sally
# harry_sally_and_joe = harry,sally,&joe

# [/foo/bar]
# harry = rw
# &joe = r
# * =

# [repository:/baz/fuz]
# @harry_and_sally = rw
# * = r
[/]
zhangsan = rw

基于路径的访问控制

svnserve 可以通过 [repos-name:path][path] 对仓库的文件夹或文件进行访问控制。repos-name 为仓库的名称,当指定了 repos-name 时会在指定的仓库生效,不指定时会在所有仓库的相同路径生效。

基于 svnserve 服务时可以不在意仓库名称,因为权限文件一般都在每个仓库中,不需要跨仓库访问。

基于 httpd 和 Apache 时,节名只有这两种形式: 如果使用了配置指令 AuthzSVNAccessFile, 则要么是 [repos-name:path], 要么是 [path]。如果使用了配置指令 AuthzSVNReposRelativeAccessFile 指定了每个仓库的访问权限配置文件, 则只能使用 [path] 这种形式。

例如在示例文件中,用户 harry 对所有仓库的 /foo/bar 路径下的文件具备读写权限。同时,用户 harry 在用户组 harry_and_sally 组中,对 repository 库下的 /baz/fuz 路径下的文件具备读写权限。

当一个用户具备多个路径权限时,遵循以下原则,优先匹配更详细的路径,再匹配他的父目录,相同的路径优先匹配指定仓库名的权限。

在下面的示例中,用户 harry 拥有对 calc 仓库 /branches/calc/bug-142 目录下所有文件的读写权限,但除了 secret 目录。

plain 复制代码
[calc:/branches/calc/bug-142]
harry = rw
sally = r

[calc:/branches/calc/bug-142/secret]
harry =

分组权限

可在 [groups] 区域对用户进行分组,每一行为一组,分配权限时在组名前要添加@符。例如:

plain 复制代码
[groups]
calc-developers = harry, sally, joe
paint-developers = frank, sally, jane
everyone = harry, sally, joe, frank, jane

[calc:/projects/calc]
@calc-developers = rw

[paint:/projects/paint]
jane = r
@paint-developers = rw

同一用户在不同分组时,权限是会进行叠加的,例如,用户 jane 在 paint-developers 组中,对 paint 库的 /projects/paint 目录具有读写权限,且单独对该目录声明了一个读权限,因此通过叠加,用户 jane 对该目录还是拥有读写权限。

通配符

可以通过*表示所有的用户,对所有的用户进行赋权。例如,

plain 复制代码
[/]
## 所有用户对所有仓库的根目录下的文件拥有读权限
* = r

使用 $authenticated 表示所有的认证用户,$anonymous 表示所有未认证用户。例如,

plain 复制代码
[calendar:/projects/calendar]
$anonymous = r
$authenticated = rw

使用~表示排除某些用户,例如,

plain 复制代码
[calendar:/projects/calendar]
~$authenticated = r
~$anonymous = rw

该效果与上一个例子相同。

别名

对于较长的用户名可以对该用户名起一个别名,放在 [aliases] 区域内。例如,

plain 复制代码
[aliases]
harry = CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com
sally = CN=Sally Swatterbug,OU=Engineers,DC=red-bean,DC=com
joe = CN=Gerald I. Joseph,OU=Engineers,DC=red-bean,DC=com
...

某些认证系统仅支持相对较短的用户名, 例如 <font style="color:rgb(0, 0, 0);">harry</font>, <font style="color:rgb(0, 0, 0);">sally</font>, <font style="color:rgb(0, 0, 0);">joe</font> 这样简短的名字, 而其他一些认证系统---例如那些使用了 LDAP 和 SSL 的认证系统一却支持更复杂的用户名, 例如在一个使用了 LDAP 的认证系统中, Harry 的用户名可以是 <font style="color:rgb(0, 0, 0);">CN=Harold Hacker,OU=Engineers,DC=red-bean,DC=com</font>. 如果在访问权限配置文件里出现这些用户名, 文件将变得非常臃肿, 这些又长又晦涩的用户名还很容易写错.

启动 SVN

执行以下命令启动 svnserve,

shell 复制代码
sudo svnserve -d -r /var/svn

参数说明:

-d:调用守护进程

-r:指定仓库运行的位置,如果不指定,那么需要在访问时在路径中写出仓库的绝对路径,例如:svn://127.0.0.1/var/svn/repository才可以访问到仓库,当指定了目录后直接写仓库的名称即可,即:svn://127.0.0.1/repository,这样更加安全。

--listen-port:可选,指定访问端口,默认为 3690。

--listen-host:可选,指定监听的 IP,默认会监听所有 IP。

需要停止服务时,可以查看进程并杀死进程再重新启动。

shell 复制代码
## 查找进程PID
ps -ef | grep "svnserve"

## 结束进程
sudo kill -9 xxx

SVN 仓库迁移

导出

使用 svnadmin dump 命令导出仓库为一个二进制文件,

shell 复制代码
## 查看当前版本号
svnloop youngest myrepository

## 导出当前仓库
svnadmin dump myrepository > myrepository.dump

导出的文件会比仓库本身的文件要大,这是因为每个文件的每个版本在转储文件中都是全文本表示。这是最快速和最简单的方式。

可以使用 <font style="color:rgb(0, 0, 0);">-r</font> 参数来指定要导出的版本范围,例如,

shell 复制代码
## 导出23号版本的仓库
svnadmin dump myrepos -r 23 > rev-23.dumpfile
## 导出100-200号版本的仓库
svnadmin dump myrepos -r 100:200 > revs-100-200.dumpfile

这里需要注意的是,指定版本号时会与第一个版本进行对比,生成一个完整的仓库。因此,导出时会把仓库的第一个版本作为转储的第一个版本。

当使用了 --incremental 参数时,svnadmin 会把转储的第一个版本号与前一个版本号作比较,跟转储范围中剩下的其他 版本号那样,只输出在版本号中被修改了的内容。根据这个特性,可以分批次导出一个较大的仓库,

shell 复制代码
svnadmin dump myrepos -r 0:1000 > dumpfile1
svnadmin dump myrepos -r 1001:2000 --incremental > dumpfile2
svnadmin dump myrepos -r 2001:3000 --incremental > dumpfile3

再依次将转储文件导入到新的仓库中。

导入

使用 svnadmin load 命令即可将转储文件导入到指定的新仓库中,

shell 复制代码
svnadmin load newrepos < oldrepos.dump

从 Windows 系统仓库导入 Linux 系统

在 Windows 系统中可以通过界面转储仓库文件,

选择 [ Export repository dump ],点击 [ Next ] 进入下一步,

选择文件的存储路径和文件名称,如果需要压缩转储文件可以勾选 [ Compress dump using GZIP ],点击 [ Export ] 导出文件。

将转储的文件拷贝至 Linux 服务器,使用 svnadmin load 进行导入。

注意:不要使用 PowerShell 命令导出仓库,可能会出现编码异常。

httpd 搭建版本管理服务器

httpd 安装

当前使用的环境是 Ubuntu 24.04,使用以下命令安装 apache2,

在 Ubuntu 环境下,安装包的名字是 apache2,CentOS 环境是 httpd。详情可查看官方文档的安装说明,

https://httpd.apache.org/docs/2.4/install.html

https://ubuntu.com/server/docs/how-to/web-services/install-apache2/

shell 复制代码
## 安装 apache2
sudo apt install apache2 libapache2-mod-svn -y

libapache2-mod-svn 为 subversion 对 httpd 的支持模块,安装完成后自动启用该模块,不需要再单独启用。

使用以下命令检查 httpd 是否安装成功,

shell 复制代码
## 检查 apache2 的版本号
dugh@Ubuntu-Dev:~$ apache2ctl -v
Server version: Apache/2.4.58 (Ubuntu)
Server built:   2026-05-05T13:22:45

或者在浏览器中直接访问 http://172.20.1.168/ 能够直接打印 Apache 首页,则表示安装成功。

使用以下命令检查 subversion 模块是否安装成功并启用,

shell 复制代码
## 查看httpd支持的模块
dugh@Ubuntu-Dev:~$ apache2ctl -M | grep "svn"
 dav_svn_module (shared)
 authz_svn_module (shared)

能够打印 dav_svn_module 说明 httpd 已支持 subversion 模块。


踩坑

如果直接使用 apache2 命令的话,会打印 AH00111: Config variable ${APACHE_RUN_DIR} is not defined,该命令不会加载 envvars 的环境变量。在 apache2.conf 中也有描述文本,

plain 复制代码
# * The binary is called apache2. Due to the use of environment variables, in
#   the default configuration, apache2 needs to be started/stopped with
#   /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
#   work with the default configuration.

基础配置

安装完成 libapache2-mod-svn 后,会在 /etc/apache2/mods-enabled 目录下生成一个 dav_svn.conf 的配置文件,我们编辑该文件,代理仓库。

shell 复制代码
## 编辑 dav_svn.conf 文件
sudo vi /etc/apache2/mods-enabled/dav_svn.conf

在文件中添加以下内容,

plain 复制代码
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on
</Location>

这里建议将仓库文件添加到 apache2 的默认用户和用户组上,使得 apache2 可以有权限访问仓库目录,

shell 复制代码
sudo chown -R www-data:www-data /var/lib/svn

浏览器直接访问 http://hostname/svn/repository 就能够访问 repository 仓库的内容。

这里需要注意一点,如果创建的仓库名称是中文的,需要在 dav_svn.conf 中添加 SVNUseUTF8 配置,该配置要添加在 Location 标签外,否则 apache2 无法启动,

plain 复制代码
# 设置为UTF-8编码
SVNUseUTF8 On
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on
</Location>

如果不设置,当访问中文仓库时,会报 Can't convert string from 'UTF-8' to native encoding 错误。

身份认证

Basic 认证

我们采用 apache2 提供的基础认证功能,为 dav_svn.conf 添加以下内容,

plain 复制代码
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on

  # 设置apache2的认证模式为Basic认证
  AuthType Basic
  # 设置认证的名称,可以随意命名
  AuthName "Subversion repository"
  # 设置Basic认证的提供方式,默认值为file,可以不添加
  AuthBasicProvider file
  # 设置用户文件的位置
  AuthUserFile /etc/svn-auth.htpasswd
</Location>

用户文件我们需要通过 htpasswd 命令进行创建,

shell 复制代码
# 创建harry用户,文件位置为/etc/svn-auth.htpasswd
dugh@Ubuntu-Dev:~$ sudo htpasswd -c -m /etc/svn-auth.htpasswd lisi
New password:
Re-type new password:
Adding password for user lisi

-c 创建 passwdfile。如果 passwdfile 已经存在,它将被重写并截断。此选项不能与 -n 选项结合使用。

-m 对密码使用 MD5 哈希。这是默认值(从版本 2.2.18 开始)。如果需要使用其他的加密方式,可以参照官方文档进行选择。

如果需要修改某个用户的密码或在当前配置文件中新增某个用户,则只需要去掉 -c 命令,重新输入密码即可。

Digest 认证

Digest 认证会比 Basic 认证更加安全,具体描述可查看官方文档。

https://svnbook.subversion.org.cn/nightly/en/svn.serverconfig.httpd.html#svn.serverconfig.httpd.authn.digest

修改 dav_svn.conf 文件,

plain 复制代码
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on

  # 设置apache2的认证模式为Digest认证
  AuthType Digest
  # 设置认证的名称,可以随意命名
  AuthName "Subversion repository"
  # 设置Digest认证的提供方式,默认值为file,可以不添加
  AuthDigestProvider file
  # 设置用户文件的位置
  AuthUserFile /etc/svn-auth.htdigest
</Location>

在使用 Digest 认证时,需要先启用 mod_auth_digest模块。

shell 复制代码
## 启用digest模块
sudo a2enmod auth_digest

## 查看已启用的模块
apache2ctl -M | grep "digest"

用户文件可以通过 htdigest 命令生成,

shell 复制代码
## 生成用户文件
sudo htdigest -c /etc/svn-auth.htdigest "Subversion repository" zhangsan

-c 创建 passwdfile。如果 passwdfile 已经存在,则先删除它。如果要修改用户的密码可以去掉 -c 参数。

权限认证

在 7.3 的案例中虽然设置了身份认证,当是通过浏览器访问时还是可以直接访问。所以可以在 dav_svn.conf 中添加 Require 配置,该配置可以要求所有访问的用户都需要进行身份认证。如果需要限制请求类型,则可以使用 Limit 和 LimitExecpt 标签限制或排除某一类请求的身份认证。

plain 复制代码
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on

  # 设置apache2的认证模式为Basic认证
  AuthType Basic
  # 设置认证的名称,可以随意命名
  AuthName "Subversion repository"
  # 设置Basic认证的提供方式,默认值为file,可以不添加
  AuthBasicProvider file
  # 设置用户文件的位置
  AuthUserFile /etc/svn-auth.htpasswd

  # 限制请求类型的身份认证
  #<LimitExcept GET PROPFIND OPTIONS REPORT>
  # 所有请求都需要进行身份认证
  Require valid-user
  #</LimitExcept>
</Location>

apache 也可以像 svnserver 一样进行权限认证,这里需要添加以下配置,

plain 复制代码
# 设置访问的路径
<Location /svn>
  # Uncomment this to enable the repository
  DAV svn

  # 如果只是指定单一的仓库,可以使用SVNPath配置
  #SVNPath /var/lib/svn/repository

  # 如果在该目录下有多个仓库
  SVNParentPath /var/lib/svn

  # 在根路径上列出所有的仓库信息(为了安全不建议这么操作)
  #SVNListParentPath on

  # 设置apache2的认证模式为Basic认证
  AuthType Basic
  # 设置认证的名称,可以随意命名
  AuthName "Subversion repository"
  # 设置Basic认证的提供方式,默认值为file,可以不添加
  AuthBasicProvider file
  # 设置用户文件的位置
  AuthUserFile /etc/svn-auth.htpasswd

  # 设置SVN权限认证文件的相对位置
  #AuthzSVNReposRelativeAccessFile authz

  # 设置SVN权限认证文件的绝对位置
  AuthzSVNAccessFile /var/lib/svn/authz

  # 限制请求类型的身份认证
  #<LimitExcept GET PROPFIND OPTIONS REPORT>
  # 所有请求都需要进行身份认证
  Require valid-user
  #</LimitExcept>
</Location>

subversion 提供了两个配置项,AuthzSVNAccessFileAuthzSVNReposRelativeAccessFile,这两个配置的区别是 AuthzSVNAccessFile 指定的文件会作用于所有的仓库,所有仓库的权限都会依赖该文件;而 AuthzSVNReposRelativeAccessFile 指定了相对于每个仓库 conf 目录下的权限文件,这样可以给不同的仓库匹配属于自己的权限文件。

认证文件可以参考 4.2 章节的内容进行编写。

启用 SSL

使用 http 协议可能存在被监听的风险,因此可以开启 apache 的 ssl 功能,使用 https 访问仓库。首先要启用 SSL 模块(默认已经安装)。

shell 复制代码
sudo a2ensite default-ssl
sudo a2enmod ssl

执行完成后,重启 apache2 服务,检查该功能是否启动成功,

shell 复制代码
apache2ctl -M | grep "ssl"

要启用 SSL 功能,还需要 ssl-cert 包的支持,安装该功能,

shell 复制代码
sudo apt install ssl-cert -y

当前使用的是 WSL 的 Ubuntu 环境,系统已安装了 ssl-cert,因此不需要再安装,

shell 复制代码
dugh@Ubuntu-Dev:~$ apt search ssl-cert
Sorting... Done
Full Text Search... Done
ssl-cert/noble,now 1.1.2ubuntu1 all [installed,automatic]
  simple debconf wrapper for OpenSSL

安装成功后会在 /etc/ssl/private 目录生成对应 hostname 的证书密钥以及对应的证书。只需要在 /etc/apache2/sites-available/default-ssl.conf 文件中检查一下 SSLCertificateKeyFile 和 SSLCertificateFile 的值是否正确即可。

plain 复制代码
SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
SSLCertificateKeyFile   /etc/ssl/private/ssl-cert-snakeoil.key

如果需要重新创建证书,执行以下命令,

shell 复制代码
make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /path/to/cert-file.crt

使用浏览器访问 https://172.20.1.168/svn/repository/ 就可以正常访问了。

相关推荐
哈德森hh2 小时前
我的 Twitter 自动化运营流程
运维·自动化·twitter
ElevenS_it1883 小时前
连锁门店IT运维监控实战:200+门店网络设备+POS统一纳管+按区域分组告警路由完整配置(Zabbix Proxy架构)
运维·网络·架构·zabbix
dualven_in_csdn3 小时前
mqtt消息及日志查看
linux·运维·服务器
呉師傅3 小时前
东芝e-STUDIO 3525ac提示黄色和品红色墨粉盒在耗尽前被更换。请重新插入之前的墨粉盒并用至耗尽如何操作
运维·windows·电脑
都在酒里3 小时前
Linux字符设备驱动开发(四):进入硬件世界——GPIO子系统与LED设备驱动
linux·运维·驱动开发
无足鸟ICT3 小时前
【RHCA+】fortune命令(输出一句话)
linux
Coin_learning3 小时前
Linux 基础命令完全教程:从入门到实战
linux
Yupureki3 小时前
《MySQL数据库基础》9.索引原理
linux·运维·服务器·网络·数据库·mysql
睡不醒男孩0308233 小时前
StarRocks导入数据:从本地文件导入数据(Stream Load)
linux·数据库