今天主要敘述在家里台式機的虛擬機上搭建支持 https 的 ubuntu git 服務器。
實際上,從一個用戶請求家里 git 服務器代碼,最終完成代碼的傳輸,主要是通過以下的過程:
首先,從外界尋找到連接上互聯網的家里的路由器,由路由器發送請求到虛擬機的 host,由 host 發送到虛擬機,由虛擬機的 apache 服務器將 https 請求轉化為 git 數據請求發送給 git 服務程序,git 服務器程序拿到數據以后原路返還,下面一點一點的將這個過程說清楚。
第一步:從外界找到家里的路由器
由於家里的網絡是動態撥號,沒有固定 ip,所以想實現這個需求,就必須使用動態 DNS
可以使用花生殼的 DDNS,這一步每一個路由器都不同,所以不再詳述。
第二步:從路由器發送到 host
發送到 host 的過程主要用到路由器的端口映射功能,並且需要配置 host 的防火牆以保證入站是通暢的。
-
規划好路由器對外暴露的端口和主機暴露的端口,以及主機的局域網 ip
路由器對外暴露的端口,最后我們會以 https://XXXX.YYYYY.CCCCC:路由器對外端口/XX的形式訪問到內部服務,這里假設為 10086
Host 暴露的接口,路由器會將請求發送給這個端口,以提供服務,這里假設為 56789。
主機的局域網 ip 用來配置端口映射時,讓路由器知道應該將請求發送到哪個機器去,這里假設為 192.168.3.50
-
配置主機 ip
有兩個方法,一個是主機直接在 ip 設置里面手動配置,但是這種配制方法不一定能完全消除 ip 沖突(雖然家庭局域網的 ip 沖突不常見),所以可以利用路由器的 ip 分配功能,每個路由器不一樣,在我的路由器界面如下:
為特定 mac 地址分配了特定的 ip
-
配置路由器到主機的端口映射
這一步每個路由器的界面都不一樣,但是配置的原理是共通的
我使用的是 netgear orbi,其配置界面如下(高級——高級設置——端口映射/端口觸發——添加自定義服務),外部端口組指的是路由器對外開放的端口,內部端口組是局域網提供服務主機的端口。
- 為主機添加防火牆規則
進入以上界面,點擊"入站規則"后,再點擊右側欄的"新建規則",出現以下界面:
至此,第二步配置完畢
第三步:從 host 轉發到虛擬機
這一步需要配置虛擬機 NAT 模式的端口轉發,並且設置虛擬機的 ip 地址,還要配置虛擬機 apache 服務器 https git 服務的端口
-
規划虛擬機 ip、服務端口、網段等
這里假設子網 ip 為 192.168.158.0,掩碼是 255.255.255.0
虛擬機 ip 是 192.168.158.20
給虛擬機分配的 git 服務端口是 5000
-
設置虛擬機軟件
以 vmware 為例(其他虛擬機軟件也有類似功能),點擊"編輯"——"虛擬網絡編輯器",按照如下界面配置
之所以 dhcp 從 128 開始,是因為保證 .20 這個地址沒有自動分配到別的虛擬機去。
-
配置主機虛擬機軟件的端口轉發規則
注意這里的網關 ip,下面要用到
-
設置虛擬機
開啟虛擬機,這里以 ubuntu 16.04 LTS 英文版版本為例,其他版本大同小異
"system settings"——"network"
注意,這里的 DNS Server 和上面的網關 ip 設置一樣,也可以設置為家里路由器的地址,比如 192.168.3.1
然后關閉並打開下圖的開關,重新讓虛擬機連一下網,使之分配到新的 ip 去
嘗試在虛擬機里連接一下網絡,測試一下。
至此,第三步已經全部完畢。
關於第三步,實際上可以使用虛擬機的橋接模式,使之成為局域網中的一個獨立機器,這樣,直接從路由器就可以給虛擬機分配一個 ip(詳見步驟二),並且配置端口轉發。這種方法省去了配置 host 防火牆的步驟,容易維護(不用修改虛擬機 NAT 規則,也不用在虛擬機里面配置靜態 ip,直接使用路由器的預留 ip,虛擬機使用 dhcp 獲得就可以了)
但是我這里之所以使用了 NAT 模式,是因為我上一個路由器這樣做有 bug(吐槽榮耀 pro……),在如此配置之后,路由器只能識別虛擬機的網卡,卻不能識別主機的網卡,導致分配到主機的其他服務全都用不了了,所以只能使用 NAT 模式,如果路由器能支持識別橋接的虛擬機,那當然要用橋接。我這里就不改了,算是提供一個橋接不行的時候的思路。
第四步:從 apache 服務器將 https 請求轉化為 git 數據請求發送給數據程序
這一步需要配置 apache 的服務器,開啟 https 支持,開啟 git 支持,增加 Git 賬戶名和密碼。
進入虛擬機:
-
安裝 apache2 的相關工具
sudo apt-get install apache2 apache2-utils openssl
-
Create git repository folder
創建一個用於存儲代碼倉庫的文件夾,后面配置服務器主機的時候會用到
cd /opt
sudo mkdir git
sudo chown youraccountname:www-data git
之所以將 owner 變為當前登錄服務器的用戶名,是因為這樣好管理,后來管理代碼庫時,用不着每一次都 sudo
-
創建 CA 證書,這里以 self signed 為例
這里創建的是自己簽名的 CA 證書,實際上網上也有很多免費的 CA 證書,比如騰訊雲的。之所以這里選擇自己簽名的,是因為大多數情況下這種方法夠用(畢竟是自己的服務器,幾乎只有自己用),不過,自己簽名的 CA 證書在 git clone 的時候可能遇到問題,后面步驟會有解決方案。
我們假設把證書存儲在了 /opt/sites_conf 目錄中
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /opt/sites_conf/apache.key -out /opt/sites_conf/apache.crt
運行以后,填寫方法大概如下:
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:這里隨便填
Organizational Unit Name (eg, section) []:這里隨便填
Common Name (e.g. server FQDN or YOUR name) []:這里一定要填寫個人服務器的域名,在本例中,就是 XXXX.YYYYY.CCCCC,如果不一致,后面的 ssl 驗證會失敗
Email Address []:隨便填
-
Enable apache modules
sudo a2enmod cgi alias env rewrite
-
Listen port 5000
sudo gedit /etc/apache2/ports.conf
在這個文件里面加入一行:
Listen 5000
然后保存退出
-
Config virtual machine
cd /etc/apache2/sites-available
創建新的配置文件並且填入內容:
sudo gedit git_server.conf
填入如下內容
<VirtualHost *:5000>
ServerAdmin you@example.com
ServerName RukaCode
SetEnv GIT_PROJECT_ROOT /opt/git
SetEnv GIT_HTTP_EXPORT_ALL
SSLEngine on
SSLCertificateFile /opt/sites_conf/apache.crt
SSLCertificateKeyFile /opt/sites_conf/apache.key
DocumentRoot /opt/git
<Files "git-http-backend">
AuthType Basic
AuthName "Git Access"
AuthUserFile /opt/sites_conf/htpasswd
Require valid-user
Order deny,allow
Deny from env=AUTHREQUIRED
Satisfy any
</Files>
<Location />
AuthType Basic
AuthName "Git Repositories"
AuthUserFile /opt/sites_conf/htpasswd
Require valid-user
Order allow,deny
Allow from all
</Location>
ScriptAlias / /usr/lib/git-core/git-http-backend/
RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
RewriteCond %{REQUEST_URI} /git-receive-pack$
RewriteRule ^/ - [E=AUTHREQUIRED]
</VirtualHost>
這里的配置阻止了 invalid user 的 clone,並且也阻止了 http 的訪問。如果不需要阻止 invalid user 的 clone(比如開源項目),那么可以將 <Location> 那一段去掉。此時 invalid user 可以 clone 但是不能 push。
接着,需要將此配置 link 到 enable 文件夾里面去
cd ../sites-enabled
sudo ln -s ../sites-available/git_server.conf .
-
啟動虛擬機
sudo apachectl start
或者如果已經啟動了虛擬機的話,那就
sudo apachectl restart
-
在 /opt/git 里面創建需要的代碼庫
cd /opt/git
mkdir test_repo.git
cd test_repo.git
git init --bare
sudo chgrp www-data -R .
-
在 /opt/sites_conf 里面創建用戶名、密碼文件
htpasswd -c /opt/sites_conf/htpasswd yourusername
這里的文件路徑一定要和上面配置文件里面的
AuthUserFile /opt/sites_conf/htpasswd
對應
至此,服務器端已經配置完畢。接下來還需要有兩個步驟,一個步驟是創建一個 git 代碼庫,並且 push 到服務器上去,因為此時創建的 test_repo.git 是空的,其他用戶 clone 下來是一個空的 repo,其 HEAD、upstream 等都沒有設置好,所以此步驟解決這個問題。還有一個步驟,是將服務器的 self signed 的 CA 證書添加到 git 的信任 sites 里面,這一步主要是因為我們的證書是自簽名的,因此 git 在 clone 的時候驗證其合法性時,會直接 deny 掉這個請求,需要將其添加到信任證書里。
-
在任意機器上,創建一個本地 repo,假設這個 repo 在 ~/my_test_repo 文件夾下
mkdir ~/my_test_repo
cd my_test_repo
git init
touch README.txt
git add .
git commit -m 'add read me file'
-
添加服務器證書到 git 信任列表里
git 信任列表由 http.sslCAInfo 來控制,設置這個值為一個文件,git 就會在這個文件里面查找是否是一個受信任的主機,所以我們要做的就是將服務器的 crt 文件內容復制到這里的文件里面。
要顯示服務器的 crt 文件內容,最簡單的就是使用瀏覽器,但是由於我們並沒有給 git 服務器配置網頁以供瀏覽(可以用 Gitweb 實現),所以瀏覽器如果直接鍵入網址的話會 deny
那么只好用命令行,輸入以下命令:
openssl s_client -showcerts -connect yoursitedomain:yoursiteport|sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p'
注意,要將 yoursitedomain:yoursiteport 轉化為你的 git 服務器的網址和端口,回到第一步可以看到,這里的例子為 XXXX.YYYYY.CCCCC:10086
如果連接沒問題,就會看到如下的信息
-----BEGIN CERTIFICATE-----
MIIEGTCCAwGgAwIBAgIJAISj2sI7kbd3MA0GCSqGSIb3DQEBCwUAMIGiMQswCQYD
VQQGEwJDTjEQMA4GA1UECAwHQmVpamluZzEQMA4GA1UEBwwHQmVpamluZzEVMBMG
A1UECgwMU25pcGVyIFN3b3JkMRUwEwYDVQQLDAxTbmlwZXIgU3dvcmQxHDAaBgNV
BAMME3NuaXBlcnN3b3JkLnFpY3AuaW8xIzAhBgkqhkiG9w0BCQEWFGNsY3ZhbXBp
cmVAZ21haWwuY29tMB4XDTE3MDExNTEzMzgzMFoXDTE4MDExNTEzMzgzMFowgaIx
CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlqaW5nMRAwDgYDVQQHDAdCZWlqaW5n
MRUwEwYDVQQKDAxTbmlwZXIgU3dvcmQxFTATBgNVBAsMDFNuaXBlciBTd29yZDEc
MBoGA1UEAwwTc25pcGVyc3dvcmQucWljcC5pbzEjMCEGCSqGSIb3DQEJARYUY2xj
dmFtcGlyZUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQDmrlk2Y3k9OJOg3YPOkJf2f1QcvYwsiRcdSemtWAqNGyXVdGlrXPQNpRgDfOPs
Qmb5V/ELX6Gl+0rSiKS7N+tKlmru8oJgGvADGUTTU9gMDeGR5ztUmqhik57C3E+V
AL+Oq2TaJqWoseDB1KdF4/4p3PmFDfeGg+vdWEaSihWG/p2lfRPjH+hr9mH/R2Pn
ZO7Y+TvNevU8pBVmdhh88nHYorIZ0m1/Zk11ADyVuCBVF3ygt4QYv7Lb/N67SiyT
uqlfifEZR+CEVfaBkaIqhC21YG6NtnQ40LFa2uqr7Hbx2xz30yYrUmlhcHtEop5w
ZxdsM7iXvt4aYOyOjhljZ4gXAgMBAAGjUDBOMB0GA1UdDgQWBBTbbonTeEU+JIls
axkFePsbFVqsjzAfBgNVHSMEGDAWgBTbbonTeEU+JIlsaxkFePsbFVqsjzAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQARaDGHn9/9RT0Qk0AcztRMyjrU
KOcxgad5SAGmG/8BNJR5zEmgeUm+Az31qKBT1m2JNy16cD1+3ulNTKVkZ7j8judt
EZiUEzsJxgZ4seQ5eQIeORS1IKuadyQevnjMvubzPOmDzOt4DdQNuHcq+Xmv4XP/
2afrtYseGTWJl66qH2ssQ9ilkg8ju7G/7MGiFpF+pBve3tWyvcltsmgcDEcJotJq
BY4uqrVAko+28aPhwVyR63CIk52G7WwJcoJ1sCm0SCzbHbTTNJLqRCbuYBWgXCrb
kyHbS7ACz8onV219sghBQpsyHjVsIg6nFem9pufa1xbwkI1R3wMEfCqZZZM1
-----END CERTIFICATE-----
將這個信息復制到一個文件里(注意,--BEGIN CERTIFICATE— 和 –END CERTIFICATE— 也要一並復制),比如 ~/git_trust_ca.crt,並保存
然后設置:
git config --global http.sslCAInfo '/home/xxxxxx/git_trust_ca.crt'
-
第1小步已經創建好了 repo,這一步將其 up 到服務器上去:
git remote add origin https://XXXX.YYYYY.CCCCC:10086/test_repo.git
git push origin master
此時出現輸入用戶名和密碼的地方,直接輸入即可 push
至此,git 個人服務器已經全部搭建完畢,實際上接下來還可以給 git 服務器增加 web 界面,便於管理項目等