前篇文章讲解了如何在centos下搭建git的服务器(搭建git服务器及备份服务器),但是以这种方式搭建的git服务器只能支持git(git@gitserver.com:/git/test.git
)的方式访问,这种格式本质上还是以ssh的方式访问的,如果某些情况下服务器上没有开放ssh端口或禁止以ssh的方式连接服务器,那就不能访问git数据了,本文将在前篇文章的基础上,讲解如何搭建支持http方式的git服务器。
环境
os版本及用到的组件和版本:
OS:CentOS 7.2
Git:1.8.3.1
fcgi:2.4.0-25.el7
fcgi-devel:2.4.0-25.el7
fcgiwrap:1.1.0-12
spawn-fcgi:1.6.3-5.el7
说明:
fcgi、fcgi-devel、fcgiwrap、spawn-fcgi都是用在nginx中将http请求转发给git后台的工具,因为如果想让git支持http或https,需要用到git自带的git-http-backend
工具,该工具是使用CGI编写的,而ngxin不支持cgi,但是支持fcgiwrap,所以需要用到这一堆组件来让nginx支持cgi。
GIT官网上自带了一个使用apache web服务器来配置git-http-backend的例子,如果使用apache服务器的话可以参考:
GIT官网文档:https://git-scm.com/docs/git-http-backend
中文文档:https://cloud.tencent.com/developer/section/1138695
开始
安装组件
安装GIT
安装GIT的过程前篇文章已经讲解,这里不再赘述。
参见:搭建git服务器及备份服务器
安装fcgi组件
需要安装fcgi、fcgi-devel、fcgiwrap、spawn-fcgi组件来使nginx支持cgi应用,我这边CentOS的仓库中已经自带了这些组件,可以直接使用以下命令安装:
yum install -y fcgi fcgi-devel fcgiwrap spawn-fcgi
如果某个组件不在当前系统的仓库中,可以通过添加源或使用源码方式安装,网上有很多文章讲解源码安装方式,可以参考。
配置
配置fcgiwrap开机脚本
vi /etc/init.d/fcgiwrap
输入以下内容:
#! /bin/sh
# chkconfig: 2345 55 25
DESC="fcgiwrap daemon"
DEAMON=/usr/bin/spawn-fcgi
PIDFILE=/var/run/spawn-fcgi.pid
FCGI_SOCKET=/var/run/fcgiwrap.socket
FCGI_PROGRAM=/usr/local/sbin/fcgiwrap
FCGI_USER=www
FCGI_GROUP=www
FCGI_EXTRA_OPTIONS="-M 0770"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -S $FCGI_EXTRA_OPTIONS -F 1 -P $PIDFILE -- $FCGI_PROGRAM"
do_start() {
$DEAMON $OPTIONS || echo -n "$DESC already running"
}
do_stop() {
kill -INT `cat $PIDFILE` || echo -n "$DESC not running"
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
do_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
exit 3
;;
esac
exit 0
需要检查及修改的地方:
第四行:DEAMON=/usr/bin/spawn-fcgi
,spawn-fci是用来允许fcgi应用的一个容器,这里是指定本机上安装的spawn-fcgi命令的位置。
第七行:FCGI_PROGRAM=/usr/sbin/fcgiwrap
,指定本机上安装的fcgiwrap命令的位置。
第八、九行:FCGI_USER=admin FCGI_GROUP=admin
,指示要运行fcgiwrap时的用户和组,最好配置成和运行nginx的用户一致。
其他的保持默认就可以。
该脚本的意思使用spawn-fcgi来启动fcgiwrap,以unix通道监听的方式,该脚本启动成功后会在FCGI_SOCKET=/var/run/fcgiwrap.socket
配置的位置处生成指定的unix通道文件,该文件将配置给nginx用来转发请求使用。
重要:完成后检查该脚本文件的属性,该文件需要配置上可执行属性:
-rwxr-xr-x 1 root root 817 Mar 19 10:47 /etc/init.d/fcgiwrap
【可选】配置spawn-fcgi以服务的方式启动
该方式是上一步的另一种配置方式,可以将spawn-fcgi配置为fcgiwrap的服务。
vi /etc/sysconfig/spawn-fcgi
安装了spawn-fcgi后,该文件应该存在,默认情况下,该文件的内容为:
# You must set some working options before the "spawn-fcgi" service will work.
# If SOCKET points to a file, then this file is cleaned up by the init script.
#
# See spawn-fcgi(1) for all possible options.
#
# Example :
#SOCKET=/var/run/php-fcgi.sock
#OPTIONS="-u apache -g apache -s $SOCKET -S -M 0600 -C 32 -F 1 -P /var/run/spawn-fcgi.pid -- /usr/bin/php-cgi"
在文件原有内容后面追加如下内容:
FCGI_SOCKET=/var/run/fcgiwrap.socket
FCGI_PROGRAM=/usr/sbin/fcgiwrap
FCGI_USER=nginx
FCGI_GROUP=nginx
FCGI_EXTRA_OPTIONS="-M 0700"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -s $FCGI_SOCKET -S $FCGI_EXTRA_OPTIONS -F 1 -P /var/run/spawn-fcgi.pid -- $FCGI_PROGRAM -f"
【可选】生成用户认证信息
http的方式加上用户认证的话比较安全。
可以使用htpasswd
工具来生成用户认证文件给nginx使用。如果系统上没有该工具,可以使用以下命令查找该工具所在的软件包并安装:
yum provides */bin/htpasswd
完成后可以使用以下命令生成用户名和密码文件:
htpasswd -bc git.auth git git123456
以上命令会生成用户名为git密码为git123456的文件git.auth,文件存放到运行命令的当前目录,也可以指定其他位置。
如果不想安装该工具的话也可以使用在线生成网站:https://tool.oschina.net/htpasswd
在生成的结果拷贝保存到本机的文件上。
本机采用的是在线网站的方式,加密结果存放在nginx的conf目录下的git.auth文件中。
配置nginx
修改<nginx_dir>/conf/nginx.conf
配置文件,添加如下server定义:
server {
listen 80;
server_name git.xxx.com;
access_log /servers/nginx/logs/access.log;
error_log /servers/nginx/logs/error.log;
auth_basic "git login"; #basic auth name, whatever text
auth_basic_user_file "/servers/nginx/conf/git.auth";
####gitweb
#static resources
location ~* ^.+\.(css|js|png|jpg|jpeg)$ {
root /var/www;
expires 24h;
access_log /servers/nginx/logs/gitweb_access.log;
error_log /servers/nginx/logs/gitweb_error.log;
}
#location ~ ^/gitweb/.*\.cgi$ {
location /gitweb {
root /var/www;
auth_basic "gitweb login";
auth_basic_user_file "/servers/nginx/conf/git.auth";
access_log /servers/nginx/logs/gitweb_access.log;
error_log /servers/nginx/logs/gitweb_error.log;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /var/www/gitweb/gitweb.cgi;
fastcgi_pass localhost:9000;
include /servers/nginx/conf/fastcgi_params;
}
####gitweb end
# static repo files for cloning over http
location ~ ^.*\.git/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx))$ {
root /git/repos/;
}
# requests that need to go to git-http-backend
location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ {
root /git/repos/;
access_log /servers/nginx/logs/git_access.log;
error_log /servers/nginx/logs/git_error.log;
client_max_body_size 500m;
include /servers/nginx/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend; #tell fastcgi to pass the request to the git backend
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT $document_root;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $uri; #Takes the url to git-http-backend.
fastcgi_pass unix:/var/run/fcgiwrap.socket; #pass the request to fastcgi.
}
中间的gitweb
部分,如果不使用gitweb的话可以忽略。
简单解释一下:
server开头那部分比较简单。
listen 80
:监听在80端口。
server_name git.xxx.com
:域名,以该域名起始的url匹配该server的配置。
access_log <file_path>
:定义该server的访问日志存放位置,如果location里未定义该配置,则使用该配置记录访问日志。
error_log <file_path>
:定义该server的错误日志存放位置,记录逻辑同access_log。
auth_basic <auth_name>
:定义用户认证,使用Basic的用户名和密码认证方式,auth_name可以随便写。
auth_basic_user_file <auth_file_location>
:用户认证文件位置,就是上一步中生成的用户认证文件。如果不想使用用户认证可以删除这两行。
最后的两个location:
# static repo files for cloning over http
location ~ ^.*\.git/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx))$ {
root /git/repos/;
}
# requests that need to go to git-http-backend
location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ {
root /git/repos/;
access_log /servers/nginx/logs/git_access.log;
error_log /servers/nginx/logs/git_error.log;
client_max_body_size 500m;
include /servers/nginx/conf/fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend; #tell fastcgi to pass the request to the git backend
fastcgi_param GIT_HTTP_EXPORT_ALL "";
fastcgi_param GIT_PROJECT_ROOT $document_root;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param PATH_INFO $uri; #Takes the url to git-http-backend.
fastcgi_pass unix:/var/run/fcgiwrap.socket; #pass the request to fastcgi.
}
第一个location匹配的是git的静态资源下载请求,这部分请求直接以文件的形式提供访问即可。
第二个location匹配的是git的协议请求,这部分请求需要转发给git-http-backend来处理。
root /git/repos/;
:定义git的库文件夹地址。
client_max_body_size 500m;
:设置客户端请求的最大报文限制。
include /servers/nginx/conf/fastcgi_params;
:将fastcgi的默认参数配置包含进来,nginx默认自带了该文件。
fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
:设置fcgi的SCRIPT_FILENAME参数,值为git-http-backend的位置。
fastcgi_param GIT_HTTP_EXPORT_ALL "";
:git参数,表示可访问任何git目录,如果不设置该参数,则仅能访问明确标记为导出的git目录。
fastcgi_param GIT_PROJECT_ROOT $document_root;
:git参数,表示git库的地址。这里设置为nginx的内置变量$document_root
,该变量表示设置的root的值。
fastcgi_param REMOTE_USER $remote_user;
:fcgi参数,git也用,表示请求的用户。
fastcgi_param PATH_INFO $uri;
:【重要】git参数,表示请求的git路径,这里将请求地址直接转给git来处理,如果设计的url跟git库中的地址不一致,则需要通过正则表达式匹配出要访问的git地址,然后把git地址传给git后台服务,例如设置为fastcgi_param PATH_INFO $1;
,表示将正则匹配到的第一个组设置为git地址传给git后台。
fastcgi_pass unix:/var/run/fcgiwrap.socket;
:上一步fcgiwrap启动时创建的unix管道。
启动
启动fastcgi
如果是采用上面《配置fastcgi开机脚本》的方式,使用如下命令启动fastcgi:
/etc/init.d/fastwrap start
如果是采用上面《配置spawn-fcgi服务的方式》,则使用如下命令启动:
# 配置为开始启动,只允许一次即可
chkconfig --levels 2345 spawn-fcgi on
# 启动spawn-fcgi
service spawn-fcgi start
启动nginx
如果nginx未启动,使用如下命令启动nginx:
cd <nginx_dir>
sbin/nginx -c conf/nginx.conf
如果nginx已启动,使用如下命令使nginx重新加载配置:
cd <nginx_dir>
sbin/nginx -s reload
至此,完成所有配置。
测试
现在可以通过git客户端或命令行访问一下服务器上的git项目来测试一下吧。
git clone http://git.xxx.com/test.git
git clone http://git.xxx.com/group/test.git
可能遇到的问题
- git push时提示“remote: error: insufficient permission for adding an object to repository database ./objects
remote: fatal: failed to write object
error: remote unpack failed: unpack-objects abnormal exit”。
该问题主要是由于用户权限问题导致。
以上方式搭建的http服务器涉及到三个用户:nginx用户、启动fcgiwrap的用户和git资源库的所属用户。
通常这个问题是由于fcgiwrap的用户对git资源库没有写权限导致的,解决方案有以下几种:
- 修改启动fcgiwrap的脚本中的user,使用与git库一样的用户。
- 将git资源库中的项目文件夹设置为777模式。(简单粗暴)
- 如果fcgiwrap启动用户和git库所属用户不一致,又不想简单的设置git资源库为777,那么可以把fcgiwrap启动用户加入到git资源库所属用户的用户组,然后设置组访问权限:
以上面启动fcgiwrap的用户www
为例:
加入git用户所属的用户组(git)
usermod -a -G git www
设置用户组权限:
cd <your git repo> #eg. cd /git/repos/test.git
sudo chmod -R g+ws * # 允许后续其他用户新建的文件保持组级别的权限访问
sudo chgrp -R <yourgroup> * #eg. sudo chgrp -R git *
git config core.sharedRepository true
这种方式需要重启fcgiwrap才能生效,因为用户加入新用户组需要重启生效。
安装gitweb
gitweb是一个简单的git管理网站,可以通过浏览器查看git服务器上的项目及其中的文件资源。
官方文档-中文:https://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-GitWeb
官方文档-英文:https://git-scm.com/book/en/v2/Git-on-the-Server-GitWeb
界面截图如下:
gitweb是git提供的一个简单的web浏览器,默认样式下比较简陋难看,聊胜于无。
如果服务器可联网的话,可以安装gitlab来在线查看和管理git,gitlab更美观易用。
安装gitweb
yum install -y gitweb
安装成功后会在生成/var/www/git
资源文件夹和/etc/gitweb.conf
文件。
配置gitweb
vi /etc/gitweb.conf
加入以下内容:
$projectroot = "/git/repos"; #git项目库地址
@git_base_url_list = ("git://git.xxx.com", "http://git.xxx.com"); #指定支持两种git url格式
$git_temp = "/tmp";
$home_text = "index.html";
@stylesheets = ("gitweb.css");
$javascript = "gitweb.js";
@diff_opts = ()
$feature{'highlight'}{'default'} = [1];
配置中最重要的是$projectroot
,其他的不加也可以。
配置fcgiwrap
gitweb也是一个cgi程序,配置一个fcgiwrap来运行gitweb,为了避免跟git-http-backend的fcgiwrap冲突,这次我们创建一个监听tcp端口的fcgiwrap,并配置为开机启动:
vi /etc/init.d/fcgiwrap_tcp
#! /bin/sh
# chkconfig: 2345 55 25
DESC="fcgiwrap daemon"
DEAMON=/usr/bin/spawn-fcgi
PIDFILE=/var/run/spawn-fcgi-tcp.pid
FCGI_PORT=9000
FCGI_PROGRAM=/usr/sbin/fcgiwrap
FCGI_USER=admin
FCGI_GROUP=admin
FCGI_EXTRA_OPTIONS="-M 0770"
OPTIONS="-u $FCGI_USER -g $FCGI_GROUP -p $FCGI_PORT -S $FCGI_EXTRA_OPTIONS -F 1 -P $PIDFILE -- $FCGI_PROGRAM -f"
do_start() {
$DEAMON $OPTIONS || echo -n "$DESC already running"
}
do_stop() {
kill -INT `cat $PIDFILE` || echo -n "$DESC not running"
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
do_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
do_stop
echo "."
;;
restart)
echo -n "Restarting $DESC: $NAME"
do_stop
do_start
echo "."
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2
exit 3
;;
esac
exit 0
需要注意的依然是spawn-fcgi和fcgiwrap可执行文件的位置,例子中我们配置了监听9000端口。
配置nginx
开始前让我们先把/var/www/git
重命名为/var/www/gitweb
,这样就可以使用http://git.xxx.com/gitweb/gitweb.cgi来访问了(偷个懒_)。
上面配置http git服务器的时,配置nginx时已经配置了gitweb,如下:
####gitweb
#static resources
location ~* ^.+\.(css|js|png|jpg|jpeg)$ {
root /var/www;
expires 24h;
access_log /servers/nginx/logs/gitweb_access.log;
error_log /servers/nginx/logs/gitweb_error.log;
}
#location ~ ^/gitweb/.*\.cgi$ {
location /gitweb {
root /var/www;
auth_basic "gitweb login";
auth_basic_user_file "/servers/nginx/conf/git.auth";
access_log /servers/nginx/logs/gitweb_access.log;
error_log /servers/nginx/logs/gitweb_error.log;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /var/www/gitweb/gitweb.cgi;
fastcgi_pass localhost:9000;
include /servers/nginx/conf/fastcgi_params;
}
####gitweb end
第一个location配置了gitweb静态资源的访问规则,直接文件下载即可。
第二个location配置了gitweb.cgi的访问:
auth_xxx
部分:定义了访问时需要用户认证,这里跟git服务器使用同一套认证。
xxx_log
部分:定义了访问日志和错误日志的记录位置。
fastcgi_param SCRIPT_FILENAME /var/www/gitweb/gitweb.cgi;
:定义了gitweb.cgi的位置,以该url访问时fastcgi会调用gitweb.cgi去处理请求。
fastcgi_pass localhost:9000;
:指定nginx将该请求转发给本机9000端口的fastcgi,也就是我们在上一步为fastcgi配置的端口。
启动
启动fastcgi
/etc/init.d/fcgiwrap_tcp start
启动nginx
sbin/nginx -c conf/nginx.conf
或
sbin/nginx -s reload
浏览器访问
打开浏览器,访问:http://git.xxx.com/gitweb/gitweb.cgi
本文是在配置启动成功后整理材料写成,成文仓促,记忆不全可能存在疏漏之处,有任何错误欢迎指正。