CentOS下搭建基于nginx的http方式访问的git服务器

前篇文章讲解了如何在centos下搭建git的服务器(搭建git服务器及备份服务器),但是以这种方式搭建的git服务器只能支持git([email protected]:/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

修改/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 :定义该server的访问日志存放位置,如果location里未定义该配置,则使用该配置记录访问日志。
error_log :定义该server的错误日志存放位置,记录逻辑同access_log。
auth_basic :定义用户认证,使用Basic的用户名和密码认证方式,auth_name可以随便写。
auth_basic_user_file :用户认证文件位置,就是上一步中生成的用户认证文件。如果不想使用用户认证可以删除这两行。

最后的两个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 
sbin/nginx -c conf/nginx.conf

如果nginx已启动,使用如下命令使nginx重新加载配置:

cd 
sbin/nginx -s reload

至此,完成所有配置。

测试

现在可以通过git客户端或命令行访问一下服务器上的git项目来测试一下吧。

git clone http://git.xxx.com/test.git
git clone http://git.xxx.com/group/test.git

可能遇到的问题

  1. 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  #eg. cd /git/repos/test.git

sudo chmod -R g+ws * # 允许后续其他用户新建的文件保持组级别的权限访问
sudo chgrp -R  * #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截图

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

本文是在配置启动成功后整理材料写成,成文仓促,记忆不全可能存在疏漏之处,有任何错误欢迎指正。

你可能感兴趣的:(CentOS下搭建基于nginx的http方式访问的git服务器)