搭建自己的git http(s)私有服务器

平时自己喜欢写点代码,在家里、办公室、手机上同步代码是一件烦人的事,怎么解决呢?自然是想要一个git中心化服务。虽然git本身是去中心化的,但是想要让多个节点之间保持同步,必须有一个在公网同时可访的节点作为桥梁,只要在任何环境、设备下,这台机器都可以被访问,通过git获取和推送代码,就算实现了我的目标。于是开始折腾。

搭建git服务

搭建一台git服务非常方便,去腾讯云购买最便宜的云服务器。我喜欢ubuntu,所以下面都是在ubuntu的服务器上作业。git是点对点的服务,所以,搭建一台git服务超级简单,你都不需要做任何操作,系统自带了git。如果系统不自带git,用内置的安装命令安装它就可以了。

当你的服务器安装好git之后,就具备了git服务。由于git是去中心化的,每一个安装了git的电脑,都可以为其他节点提供服务(其实并没有提供服务,而只是提供了数据传输的方式,怎么传输,还是要靠协议层)。它可以依托ssh, http(s)协议来传输数据。默认,ssh是最便捷的git传输协议。基于ssh,你在clone的时候,甚至不需要在仓库地址中写协议段。

在服务器上一个比较好记的路径下创建一个空目录,在该目录下执行:

git init --bare

其中—bare参数表示,这个目录要作为裸库,也就是纯粹作为存储代码的地方,而非进行代码撰写的地方。而普通执行git init会在当前目录下创建一个.git目录,在*nix系统中是个隐藏目录。它里面的内容个执行git init —bare产生的内容结构一模一样。

也就是说,无论是用—bare创建的裸库,还是直接生成的.git目录,都可以被别人克隆和推送。

当我们在服务器上创建一个仓库之后,其他节点就可以通过ssh或http(s)连接和拉取、推送了:

git clone user1@127.0.0.1:/home/user1/gittest

上面的连接方式基于ssh,user1是ssh登陆用户,@后面是主机地址,:后面是git仓库目录的路径。执行上面命令后,会要求你输入主机上user1的密码,这样就可以把远程的仓库克隆到本地当前目录下。

启用http服务

前面已经启用了ssh服务,这样虽然我们可以连接到服务器上获取代码,但是有一个问题,如果在一些屏蔽了22端口的网络环境下怎么办呢?这种事情常有发生,因为很多公司内部为了安全起见,都会封闭大部分端口,只保留几个端口,比如常用的80、443、8080。如果是这样,那上面那种直接使用git内置连接方式连接的办法就不行了,因为git内置的连接办法是ssh的,也就是需要支持22端口(当然,你可以在本机的ssh config中进行配置,但是,你总不可能在本地和服务器上都为了git而修改ssh的配置吧。而且,即使这样,你也得让你的网关支持你修改的端口。

既然这样,我们就要像github一样,实现一种基于http(s)的服务,这样,在这样的公司内网,就可以通过http(s)来拉取和推送代码了。

git支持的http协议,是称为“亚协议”的http协议方式。这可以在git的官网查到。简单说,就是,你可以把你的仓库放在一个http请求目录下,然后直接用git clone对应的url路径即可。这样,git会根据你提供的路径的协议自己选择使用什么协议来传输文件。

搭建http服务这里就不赘述了,对于ubuntu服务器而言,直接安装apache2即可。

但是就如上一段讲到的,你只能通过http clone这个仓库,只能拉取代码,推送代码是无效的。怎么样才能通过http推送代码上去呢?

git提供了一个叫git-http-backend的程序,它可以帮助你实现推送。简单的说,它跟php一样,接收你git push的内容,然后将这些内容写入到服务器的文件系统。总之,利用这个程序就可以实现git push了。但是,到底要怎么实现呢?

其实,你可以这样理解。它就是一段特殊的程序,就像你要让apache支持php一样,要给apache挂载一个插件(姑且这么讲吧),这样,当一个请求到达时,就会把这个请求转发给这个程序去处理。

你需要在apche2的配置文件中增加这个逻辑。

<VirtualHost *:80>
  SetEnv GIT_HTTP_EXPORT_ALL
  SetEnv GIT_PROJECT_ROOT /home/git/repos
  ScriptAlias / /usr/lib/git-core/git-http-backend/
  DocumentRoot /home/git/repos

  RewriteEngine On
  RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
  RewriteCond %{REQUEST_URI} /git-receive-pack$
  RewriteRule ^/ - [E=AUTHREQUIRED]
</VirtualHost>

红色部分是关键,GIT_PROJECT_ROOT表示要使用git backend的目录。不过,我这个配置完全忽略了和其他服务共存的情况,直接采用了/作为ScriptAlias的路径。你可以根据自己的实际情况进行调整。

简单总结,就是在apache的配置中增加ScriptAlias,通过一个类似alias的规则,把一个特定uri下的访问交给git http backen这个程序去处理,这样,在接收到这个uri的git push请求时,就可以交给这个程序去完成写入仓库的逻辑。

鉴权

接下来要解决的问题是,要阻止别人提交代码到你的仓库。你需要设置密码,就像github一样。那要怎么弄呢?

其实很简单。http的鉴权有两种方式,一种是自建权限系统,另一种,是直接利用htpasswd鉴权。无论哪种,都是对每一个请求进行鉴权,在请求交给应用程序去处理之前先拦截下来,鉴权通过再继续这个流程,否则直接拒绝请求。

相对来说,直接利用htpasswd鉴权最简单。这种鉴权方式传统,到有效。说它传统,是因为只有老式的网站通过这种方式使网站变为私有网站,进入网站会弹出一个对话框,必须输入正确的用户名和密码才能进入。

这种鉴权方法对任何http(s)网站都是通用的,这里说下怎么实现。

先在/home/git目录下执行:

htpasswd -c http.passwd [username]

执行之后,会让你输入密码。这样,就会创建一个名叫http.passwd的文件,并且里面包含了你刚才创建和输入的用户和密码信息。

接下来,要在apache配置文件中配置:

<VirtualHost *:80>
  SetEnv GIT_HTTP_EXPORT_ALL
  SetEnv GIT_PROJECT_ROOT /home/git/repos
  ScriptAlias / /usr/lib/git-core/git-http-backend/
  DocumentRoot /home/git/repos

  <Location />
    AuthType Basic
    AuthName "Git Acess"
    AuthUserFile /home/git/http.passwd
    Require valid-user
    Allow from all
  </Location>

  RewriteEngine On
  RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
  RewriteCond %{REQUEST_URI} /git-receive-pack$
  RewriteRule ^/ - [E=AUTHREQUIRED]
</VirtualHost>

说到底,这个配置跟git一点关系都没有,它仅不过是apache自带的一种认证方式。

结语

本文解释了利用自己的服务器,给自己提供一个在线的git服务的的方法,利用git自带的功能,提供一个git节点,并通过配置apache实现可通过http传输的方式,最后,利用apache自己的功能,实现http鉴权,这样就可以给自己提供一个在线的git仓库,走到哪里都可以方便地在不同设备之间同步代码了。

2018-11-24 69

为价值买单

本文价值0.69RMB