1. 从HTTP到HTTPS:为什么你的GitLab必须升级?
如果你还在用HTTP访问你的GitLab,那感觉就像把公司代码库的钥匙挂在办公室门口的信箱上——理论上只有你知道,但任何一个路过的人都有可能顺手牵羊。HTTP协议下,所有数据,包括你的用户名、密码、API令牌,甚至每一次代码推送的内容,都是以明文形式在网络中裸奔。这绝不是危言耸听,尤其是在内网环境中,很多人误以为“内网就是安全的”,从而放松了警惕。实际上,内网嗅探、中间人攻击(MITM)的风险同样存在。HTTPS的核心价值,就是为这趟“裸奔”套上一件加密的“防护服”,通过SSL/TLS协议,在客户端(你的浏览器或Git客户端)和服务器(你的GitLab实例)之间建立一条加密通道,确保数据的机密性和完整性。
对于GitLab这种承载着团队核心知识产权(源代码)和协作流程(CI/CD)的平台,启用HTTPS不是“锦上添花”,而是“安全基线”。没有它,你无法放心地通过Web界面管理项目,更无法安全地让CI/CD Runner与GitLab通信。很多人在初次搭建GitLab时,为了图省事跳过了HTTPS配置,结果在后续集成CI/CD、配置Webhook或者使用高级功能时,会遇到一堆令人头疼的“SSL证书验证失败”错误。与其亡羊补牢,不如在搭建之初就一步到位。
本指南将带你完整走通GitLab的HTTPS配置流程。我们将聚焦于最常见的场景:使用Nginx作为反向代理,并为它配置一个有效的SSL证书。无论你是使用自签名证书在测试环境快速验证,还是为生产环境申请并部署受信任的CA(证书颁发机构)签发的证书,核心原理和步骤都是相通的。我会基于多年的运维经验,不仅告诉你每一步怎么做,更会解释为什么这么做,以及过程中可能遇到的“坑”和避坑技巧。
2. 配置前的核心准备:证书、域名与Nginx角色
在动手修改任何配置文件之前,我们必须把“地基”打好。这个阶段准备工作的充分与否,直接决定了后续配置是顺风顺水还是一路坎坷。
2.1 SSL证书的获取与选择
SSL证书是HTTPS的基石。你可以把它理解为一本由权威机构(或你自己)签发的“数字护照”,里面包含了你的服务器域名、公钥以及签发机构的数字签名。浏览器或Git客户端会用它来验证服务器的身份并建立加密连接。
1. 自签名证书:
- 是什么:自己充当CA,为自己签发证书。成本为零,随时可生成。
- 适用场景:内部测试、开发环境、或者短期内无法绑定公网域名的内网服务。
- 缺点:不受客户端(浏览器、Git、各种SDK)信任。首次访问时,客户端会抛出严重的警告,需要手动确认并添加例外。这对于自动化工具(如CI/CD Runner)来说是致命的,因为它们无法像人一样去点击“继续前往不安全网站”。
- 生成命令示例(使用OpenSSL):
# 生成一个有效期10年的RSA私钥 openssl genrsa -out gitlab.example.com.key 2048 # 使用该私钥创建证书签名请求(CSR),这里需要交互式输入信息,其中Common Name(CN)必须填写你访问GitLab使用的域名 openssl req -new -key gitlab.example.com.key -out gitlab.example.com.csr # 自签名,生成证书文件 openssl x509 -req -days 3650 -in gitlab.example.com.csr -signkey gitlab.example.com.key -out gitlab.example.com.crt注意:对于现代浏览器和工具,仅
crt和key可能不够。你可能还需要生成一个包含Subject Alternative Name (SAN)的证书,以兼容性更好。更推荐使用一条命令生成包含SAN的自签名证书,但这需要额外的配置文件。
2. 受信任的CA签发证书:
- 是什么:由全球或区域受信的CA(如Let‘s Encrypt, DigiCert, GlobalSign等)签发的证书。
- 适用场景:任何面向公网或需要被广泛信任的生产环境。
- 优点:被所有主流浏览器和操作系统信任,无安全警告。
- 获取方式:
- 商业购买:从证书服务商处购买,通常提供保险和更长的有效期(1-2年)。
- 免费申请:Let‘s Encrypt是目前最流行的免费、自动化证书颁发机构。它通过ACME协议验证你对域名的控制权(例如,在服务器上放置特定文件或添加DNS解析记录),然后签发有效期为90天的证书。可以通过
certbot等工具自动完成申请和续期。对于公有云用户,阿里云、腾讯云等也提供一年期的免费单域名证书。
选择建议:对于生产环境,无脑选择Let‘s Encrypt或其他受信CA证书。自签名证书仅用于临时测试,并务必清楚其局限性。
2.2 域名的正确绑定
无论使用哪种证书,一个关键前提是:你必须有一个确定的域名(或主机名)来访问你的GitLab服务器,并且这个域名要与SSL证书中的“Common Name (CN)”或“Subject Alternative Name (SAN)”完全匹配。
- 公网场景:你需要拥有一个域名(例如
gitlab.yourcompany.com),并将其A记录或CNAME记录解析到你的服务器公网IP。 - 纯内网场景:你需要在内部DNS服务器上为GitLab服务器创建一个主机记录(例如
gitlab.internal),或者,更常见的做法是,在所有需要访问该GitLab的客户端机器的/etc/hosts(Linux/macOS)或C:\Windows\System32\drivers\etc\hosts(Windows)文件中添加一条记录,例如:192.168.1.100 gitlab.internal。证书中的域名必须与你在浏览器地址栏或Git远程仓库地址中输入的域名一致。
2.3 理解GitLab与Nginx的关系
这是很多初学者困惑的地方。GitLab本身内置了一个轻量级的Web服务器(Unicorn或Puma)来处理Ruby on Rails应用,同时它也捆绑了一个Nginx。在默认的Omnibus安装包中,这个捆绑的Nginx被配置为直接为GitLab服务。
当我们配置HTTPS时,实际上主要是在配置这个Nginx。有两种架构模式:
- 使用捆绑的Nginx(推荐给大多数用户):直接修改GitLab的配置文件,管理起来最方便,所有配置集中在一处。
- 使用独立安装的Nginx作为反向代理:你可以在服务器上先安装一个Nginx,然后让它代理到GitLab内置应用服务器(监听在某个如
127.0.0.1:8080的端口)上。这种方式更灵活,比如你可以在同一台服务器上用同一个Nginx代理多个Web服务。但配置稍复杂,需要同时维护Nginx和GitLab两边的配置。
本指南将以使用GitLab捆绑的Nginx为标准路径进行讲解,因为这是Omnibus安装包下的最佳实践,能减少不必要的复杂度。
3. 基于Omnibus安装包的HTTPS核心配置实战
假设你已经通过Omnibus包(如gitlab-ce或gitlab-ee)在Linux服务器上安装好了GitLab,并且目前通过HTTP(如http://gitlab.example.com)可以正常访问。现在我们要将其切换为HTTPS。
3.1 放置SSL证书文件
首先,将你的证书文件(.crt或.pem文件)和私钥文件(.key文件)放到服务器上。GitLab Omnibus包期望的默认位置是/etc/gitlab/ssl/目录。你需要以root或有sudo权限的用户操作。
sudo mkdir -p /etc/gitlab/ssl sudo chmod 700 /etc/gitlab/ssl # 将你的证书和私钥文件复制到此目录,并确保命名规范 # 通常使用你的域名作为文件名前缀,例如: sudo cp /path/to/your/gitlab.example.com.crt /etc/gitlab/ssl/ sudo cp /path/to/your/gitlab.example.com.key /etc/gitlab/ssl/ # 设置严格的权限,私钥必须只有root可读 sudo chmod 600 /etc/gitlab/ssl/gitlab.example.com.key关键细节与避坑:
- 目录权限:
/etc/gitlab/ssl目录权限设为700,私钥文件权限设为600,这是安全硬性要求,过宽的权限可能导致Nginx启动失败并报错。 - 文件命名:Omnibus GitLab的Nginx配置默认会查找以
gitlab.example.com命名的证书和密钥。如果你使用其他域名,需要稍后在配置中明确指定路径。 - 证书链:如果你的CA提供的是中级证书(Intermediate CA Certificate),你需要将你的域名证书和中级证书合并成一个文件。通常顺序是:你的证书在上,中级证书在下。你可以用文本编辑器合并,或使用
cat命令:
私钥文件(cat gitlab.example.com.crt intermediate.crt > /etc/gitlab/ssl/gitlab.example.com.crt.key)不需要合并。
3.2 修改GitLab主配置文件
核心配置都在/etc/gitlab/gitlab.rb这个文件中。这是一个Ruby语法格式的配置文件,我们需要修改其中的相关参数。
sudo vim /etc/gitlab/gitlab.rb找到并修改或添加以下配置项:
# 1. 配置外部访问URL,必须使用HTTPS协议 external_url 'https://gitlab.example.com' # 2. 告诉GitLab我们使用内置的Nginx并启用SSL nginx['enable'] = true nginx['redirect_http_to_https'] = true # 自动将HTTP请求重定向到HTTPS nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.example.com.crt" nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.example.com.key" # 3. (可选但推荐)配置更强的SSL协议和加密套件,禁用不安全的旧协议 nginx['ssl_protocols'] = "TLSv1.2 TLSv1.3" nginx['ssl_ciphers'] = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" # 上述加密套件列表是一个兼顾安全性和兼容性的示例,你可以根据需求调整。 # 4. (重要)如果证书是自签名的,需要禁用客户端证书验证,否则GitLab内置服务(如Workhorse)会报错 # 对于自签名证书,必须设置: gitlab_rails['gitlab_https'] = true gitlab_rails['gitlab_ssh_host'] = 'gitlab.example.com' # SSH克隆地址,通常与域名相同或不同端口 # 关键设置:绕过SSL验证(仅限自签名证书环境) gitlab_rails['gitlab_ssl_verify'] = false # 对于受信任的CA证书,则不需要设置 `gitlab_ssl_verify` 为 false,或者可以设为 true。配置解析与经验谈:
external_url:这是最重要的配置。它不仅决定了用户访问的链接,还会影响GitLab内部生成的仓库克隆地址(HTTPS和SSH)。一旦这里改成https://,GitLab的所有链接生成、Webhook回调地址等都会基于HTTPS。nginx['redirect_http_to_https']:强烈建议开启。这样即使用户输入了http://,也会被301重定向到https://,确保流量始终加密。- 自签名证书的特殊处理:
gitlab_rails['gitlab_ssl_verify'] = false这一行至关重要。GitLab由多个组件构成(Rails, Workhorse, GitLab Shell等),它们内部会通过HTTP/HTTPS进行通信。当使用自签名证书时,这些组件间的SSL握手会失败,因为对方不信任你的自签名CA。设置为false是告诉这些组件“不要验证对方证书的有效性”。在生产环境使用受信证书时,绝不应该设置此项为false。 - 关于加密套件:我提供的
ssl_ciphers示例禁用了老旧的、不安全的算法(如SSLv3, TLSv1.0/1.1,以及RC4, DES等),优先使用前向保密(Forward Secrecy)的ECDHE套件。你可以使用在线工具(如SSL Labs的测试)来检查你的配置安全性。
3.3 应用配置并重启服务
修改完gitlab.rb后,需要运行GitLab的重配置命令,它会根据这个文件生成所有组件的实际配置文件(包括Nginx的配置文件),并重启相关服务。
sudo gitlab-ctl reconfigure这个命令会运行一段时间,屏幕上会滚动大量输出,显示它正在配置什么服务。请耐心等待其完成。
3.4 验证配置是否生效
检查Nginx配置:生成的Nginx配置文件通常在
/var/opt/gitlab/nginx/conf/gitlab-http.conf。你可以查看其中是否包含了正确的ssl_certificate和ssl_certificate_key路径,以及listen 443 ssl;这样的指令。sudo grep -n “ssl_certificate” /var/opt/gitlab/nginx/conf/gitlab-http.conf检查服务状态:确保所有GitLab核心服务运行正常。
sudo gitlab-ctl status重点关注
nginx,gitlab-workhorse,puma等服务是否都是run状态。浏览器访问:打开浏览器,访问
https://gitlab.example.com。如果使用受信证书,你应该能看到绿色的锁标志。如果使用自签名证书,你会看到“不安全连接”的警告,需要手动点击“高级”->“继续前往”才能访问(这是预期行为)。检查克隆地址:登录GitLab,进入任意项目,查看仓库的克隆地址。HTTPS克隆地址应该显示为
https://gitlab.example.com/username/project.git。
4. 配置后的关键调整与故障排查
配置生效只是第一步,要让整个GitLab生态在HTTPS下顺畅工作,还需要注意以下几个关键点。
4.1 Git客户端配置调整
服务器启用HTTPS后,本地Git客户端克隆或推送代码时,可能会遇到证书验证问题。
- 对于受信CA证书:通常无需任何配置,Git(使用curl或OpenSSL后端)会自动信任系统信任库中的CA。
- 对于自签名证书:Git会报错
SSL certificate problem: self signed certificate。你有几种选择:- 临时跳过验证(不推荐用于脚本或自动化):
git -c http.sslVerify=false clone https://gitlab.example.com/xxx/xxx.git - 全局关闭SSL验证(极不推荐,存在安全风险):
git config --global http.sslVerify false - 将自签名证书添加到Git的信任列表(推荐):将你的
.crt文件导出为PEM格式(如果还不是),然后将其添加到Git的专用CA包或系统CA包中。具体步骤因操作系统和Git版本而异。例如,在Linux上,你可以将证书复制到/usr/local/share/ca-certificates/然后运行sudo update-ca-certificates。更通用的方法是配置Git使用特定的CA包文件:git config --global http.sslCAInfo /path/to/your/self-signed-cert.pem
- 临时跳过验证(不推荐用于脚本或自动化):
4.2 容器化环境(Docker)的特殊考量
如果你使用Docker运行GitLab,HTTPS配置的逻辑是相似的,但路径和方式略有不同。
挂载证书:在运行
docker run命令时,你需要将宿主机上的证书目录挂载到容器内的/etc/gitlab/ssl目录。docker run -d \ --hostname gitlab.example.com \ -p 443:443 -p 80:80 -p 22:22 \ --name gitlab \ --restart always \ -v /your/host/path/ssl:/etc/gitlab/ssl \ -v /your/host/path/gitlab/config:/etc/gitlab \ -v /your/host/path/gitlab/logs:/var/log/gitlab \ -v /your/host/path/gitlab/data:/var/opt/gitlab \ gitlab/gitlab-ce:latest注意,你需要确保宿主机
/your/host/path/ssl目录下已经放置了正确命名的证书和密钥文件。修改配置:你可以进入容器内部修改
/etc/gitlab/gitlab.rb,但更好的做法是在宿主机修改挂载的配置文件(/your/host/path/gitlab/config/gitlab.rb),然后在容器内执行gitlab-ctl reconfigure。环境变量:GitLab的Docker镜像也支持通过环境变量
GITLAB_OMNIBUS_CONFIG来传递配置,可以在docker run命令中直接设置,避免进入容器修改。例如:-e GITLAB_OMNIBUS_CONFIG="external_url 'https://gitlab.example.com/'; nginx['redirect_http_to_https'] = true;"
4.3 常见故障与排查思路
即使按照步骤操作,也可能会遇到问题。以下是一些常见故障及排查方法:
Nginx启动失败,报错
SSL_CTX_use_PrivateKey或BIO_new_file:- 可能原因1:证书或密钥文件路径错误,或Nginx进程没有读取权限。
- 排查:检查
gitlab.rb中nginx['ssl_certificate']和nginx['ssl_certificate_key']的路径是否正确。使用sudo ls -la检查文件是否存在,以及密钥文件权限是否为600。 - 可能原因2:证书和密钥不匹配。
- 排查:使用OpenSSL命令验证:
两次命令输出的MD5值必须完全一致。openssl x509 -noout -modulus -in /etc/gitlab/ssl/gitlab.example.com.crt | openssl md5 openssl rsa -noout -modulus -in /etc/gitlab/ssl/gitlab.example.com.key | openssl md5
可以HTTPS访问网页,但Git克隆/推送失败:
- 可能原因:GitLab内部组件(如Workhorse)通信问题,特别是自签名证书环境下
gitlab_ssl_verify未设置为false。 - 排查:检查
/var/log/gitlab/gitlab-workhorse/current或/var/log/gitlab/nginx/current日志,看是否有SSL验证相关的错误。确认gitlab.rb中已正确设置gitlab_rails['gitlab_ssl_verify'] = false(自签名证书)并已执行reconfigure。
- 可能原因:GitLab内部组件(如Workhorse)通信问题,特别是自签名证书环境下
HTTPS访问正常,但CI/CD Runner注册或连接失败:
- 可能原因:Runner在向GitLab API发起请求时,同样遇到了证书信任问题。
- 排查:如果是自签名证书,在注册Runner时,可以使用
--tls-ca-file参数指定CA证书文件:
对于已注册的Runner,可以在其配置文件(sudo gitlab-runner register -n \ --url https://gitlab.example.com \ --registration-token YOUR_PROJECT_TOKEN \ --tls-ca-file /path/to/your-ca.crt/etc/gitlab-runner/config.toml)中对应的[[runners]]部分添加tls-ca-file = "/path/to/your-ca.crt"。
HTTP到HTTPS重定向不工作或出现重定向循环:
- 可能原因:负载均衡器或前置代理(如云服务商的SLB、自己搭建的HAProxy)已经处理了SSL,并以HTTP协议将请求转发给后端的GitLab Nginx。此时,GitLab Nginx看到的是HTTP请求,但又配置了重定向到HTTPS,导致循环。
- 解决方案:在这种情况下,需要告诉GitLab Nginx,它虽然收到的是HTTP请求,但外部用户实际使用的是HTTPS。在
gitlab.rb中设置:
同时,你需要在你的前置代理上正确设置这些HTTP头。nginx['listen_port'] = 80 nginx['listen_https'] = false # 不在这个Nginx上处理HTTPS nginx['redirect_http_to_https'] = false # 关闭重定向,因为SSL已在外部终结 # 关键:设置代理协议头,让GitLab知道原始请求是HTTPS nginx['proxy_set_headers'] = { "X-Forwarded-Proto" => "https", "X-Forwarded-Ssl" => "on" }
配置HTTPS的过程,本质上是一个理解Web通信安全模型和GitLab内部架构的过程。每一步配置背后都有其安全性和功能性的考量。我强烈建议在生产环境部署前,先在测试环境中完整演练一遍,并尝试模拟各种客户端(浏览器、Git命令行、CI Runner)的连接,确保万无一失。毕竟,代码仓库的安全,怎么重视都不为过。