Nginx使用svn来发布内容,填坑

[ 29 天前 ]

为什么使用svn而不使用ftp
最大的好处就是版本控制了,svn在同步众多小文件的效率上要高出ftp不少,你试试分别上传一个discuz就明白我在说什么了

下面以centos为例
首先安装svn,安装方法不详细说明了,重点说明下如何配置
首先创建一个addsvn.sh的文件,这里放入/root目录中,给予执行权限

#!/bin/bash
repo_path=/www/svnroot        #svn仓库目录
web_path=/www/wwwroot         #网站根目录

if [ ! -d "$repo_path/" ];then  
mkdir -p  $repo_path
chmod -R 777 $repo_path
fi 

echo -n "请输入网站SVN名称:"
read svn_name

/usr/bin/svnadmin create $repo_path/$svn_name
echo "网站仓库创建成功." 

sed -i 's/^# anon-access = read/anon-access = none/' $repo_path/$svn_name/conf/svnserve.conf
sed -i 's/^# auth-access = write/auth-access = write/' $repo_path/$svn_name/conf/svnserve.conf
sed -i 's/^# password-db = passwd/password-db = passwd/' $repo_path/$svn_name/conf/svnserve.conf
sed -i 's/^# authz-db = authz/authz-db = authz/' $repo_path/$svn_name/conf/svnserve.conf
echo "svnserve.conf文件修改成功." 

echo -n "请输入SVN用户名:"
read name
echo -n "请输入SVN密码: "
read passwd

echo "$name = $passwd" >> $repo_path/$svn_name/conf/passwd
echo "$name $passwd write on passwd file."
echo "admin = $name" >> $repo_path/$svn_name/conf/authz
echo -e  "[$svn_name:/]\n@admin = rw" >> $repo_path/$svn_name/conf/authz
echo "$name 用户密码写入成功." 

/usr/bin/svn co file://$repo_path/$svn_name  $web_path/$svn_name
echo "同步到WEB目录成功"

cp $repo_path/$svn_name/hooks/post-commit.tmpl $repo_path/$svn_name/hooks/post-commit 
chmod 755 $repo_path/$svn_name/hooks/post-commit
sed -i '/mailer/d' $repo_path/$svn_name/hooks/post-commit
echo "export LANG=zh_CN.UTF-8" >> $repo_path/$svn_name/hooks/post-commit
echo "svn update $web_path/$svn_name --username=$name --password=$passwd --no-auth-cache" >> $repo_path/$svn_name/hooks/post-commit
echo "chown -R www:www $web_path/$svn_name/*" >> $repo_path/$svn_name/hooks/post-commit
echo "钩子HOOK成功" 

#下面是你的nginx配置文件,请务必添加,否则有安全隐患

sed -i '$i\\tlocation ~ ^(.*)\\/\\.svn\\/\n\t{\n\t\treturn 404;\n\t}' $web_path/vhost/$svn_name.conf

#如果你启用了https,这里也一并修改
sed -i '$i\\tlocation ~ ^(.*)\\/\\.svn\\/\n\t{\n\t\treturn 404;\n\t}' $web_path/vhost/$svn_name-https.conf
nginx reload >log.txt
echo "nginx屏蔽.svn目录成功"

echo "svn://x.x.x.x:port/$svn_name"  #这里填写你的ip和端口,默认端口不用填写

这个文件是我写的自动化脚本,如果你添加的网站目录为 /www/wwwroot/heylc_com,那么对应的仓库就是/www/svnroot/heylc_com
创建好网站后,登录ssh,输入/root/adddsvn.sh,输入svn名称和密码,相应的svn就创建完成了,只需本地检出就可以使用了

填坑
这个方法有个弊端,因为实际使用中至少是检出了2个副本,一个就是Nginx对应的web目录,一个是本地修改使用的副本,本地的副本可以直接commit提交版本库后再通过钩子来更新对应的网站目录副本,但是网站副本运行中生成的一些文件则无法更新到版本库(例如网页上传,生成的日志缓存,在线更新下载的文件,例如wordpress在线更新等),造成副本之间不同步,也容易造成冲突
为解决这个问题,我又写了个shell脚本来同步到版本库,仍然在/root中新建一个svn_auto_sync.sh

#!/bin/bash
website_root=("/www/wwwroot/heylc_com/" "/www/wwwroot/xxx_com/")  #这里是一个数组,需要一起更新的网站添加进数组
for webdir in ${website_root[@]}  
do  
    repo_path=${webdir}
    echo "==============start sync "$repo_path"================"
    /usr/bin/svn st $repo_path | awk '{if ( ($1 == "?" || $1 == "A" ) && $2 != "'$repo_path'xxx.xxx" ) { print $2}}' | xargs -r svn add
    /usr/bin/svn st $repo_path | awk '{if ( ($1 == "!" || $1 == "D" ) && $2 != "'$repo_path'xxx.xxx" ) { print $2}}' | xargs -r svn delete
    /usr/bin/svn commit -m "" $repo_path
done 

xxx.xxx是你需要过滤的文件,不需要可以去除,你可以将svn_auto_sync.sh添加到Crontab中(记得要加执行权限,否则不会自动运行),每隔一段时间运行一次,基本上完美解决

BUT
如果你的文件名称存在空格,那么就会出现错误,将上面的代码替换下面这段

#!/bin/bash
website_root=("/www/wwwroot/heylc_com/" "/www/wwwroot/xxx_com/")
for webdir in ${website_root[@]}  
do  
    repo_path=${webdir}
    echo "==============start sync "$repo_path"================"
    /usr/bin/svn st $repo_path | awk '{if ( ($1 == "?" || $1 == "A" ) && $2 != "'$repo_path'xxx.xxx" ) { print substr($0,2) }}' | sed 's/^\s*//;s/\s*$//' | xargs -d'\n' -r  svn add
    /usr/bin/svn st $repo_path | awk '{if ( ($1 == "!" || $1 == "D" ) && $2 != "'$repo_path'xxx.xxx" ) { print substr($0,2) }}' | sed 's/^\s*//;s/\s*$//' | xargs -d'\n' -r svn delete
    /usr/bin/svn commit -m "" $repo_path
done

结束
这段代码使用xargs -d指定了自定义分隔符,为了解决xargs的怪异问题,死了好多脑细胞,好了,尽情享用!