1. 项目概述为什么你的GitLab必须上HTTPS如果你在公司内部或者自己的服务器上搭了个GitLab代码库也建好了团队开始往里推代码这时候你可能觉得“能用就行”。但某一天你发现同事在咖啡厅连公司Wi-Fi提交代码时密码和代码内容在网络里是“裸奔”的或者安全扫描工具给你亮了个高危警告说你的Git服务缺乏传输加密。这时候给GitLab配置HTTPS就从“可选项”变成了“必选项”。简单来说这个项目就是为你的GitLab服务器穿上“加密铠甲”。GitLab默认安装后通常使用HTTP协议这意味着用户登录的账号密码、每一次git clone、git push操作传输的代码内容都是以明文形式在网络上传输的。在任何一个网络节点比如不安全的公共Wi-Fi甚至是你公司内网的某个交换机都可能被截获和窥探。启用HTTPS后通过SSL/TLS证书对通信进行加密和身份验证确保数据从用户的浏览器或Git客户端到你的GitLab服务器之间的传输是私密且完整的。这不仅仅是安全合规很多行业标准要求的一步更是提升团队信任感和专业度的基础建设。想象一下你让新同事克隆项目他打开终端输入git clone http://git.your-company.com/group/project.git浏览器却弹出一个“不安全”的警告第一印象就会大打折扣。换成https://开头的地址一切就显得正规、可靠。接下来我会以一个典型的、使用Nginx作为反向代理的Omnibus GitLab安装环境为例手把手带你走通从零配置HTTPS的全过程。无论你的证书是来自云服务商如阿里云、腾讯云的免费证书还是企业内部自签的证书核心思路和步骤都是相通的。我会重点解释每个配置项背后的含义以及我在多次部署中踩过的坑和总结的技巧让你不仅能配通更能配得明白、配得稳健。2. 整体方案设计与核心组件解析在开始动手修改配置文件之前我们需要先理清GitLab HTTPS的几种典型架构并理解其中涉及的核心组件是如何协同工作的。这能帮助你在遇到问题时快速定位是哪个环节出了岔子。2.1 主流部署架构与选型对于使用官方Omnibus包最常见的方式安装的GitLab它本身已经捆绑了一个Nginx服务器。这个内置的Nginx我们通常称之为“GitLab内置Nginx”或“bundled Nginx”。在这种架构下配置HTTPS主要有两种思路方案一使用GitLab内置Nginx直接处理HTTPS这是最直接、最推荐给大多数单机部署场景的方案。你只需要将你的SSL证书和私钥文件放到GitLab指定的目录然后在GitLab的主配置文件中开启HTTPS相关设置重启服务即可。内置Nginx会自动读取配置并启用443端口。优点配置简单管理方便所有配置集中在一个文件/etc/gitlab/gitlab.rb中。Omnibus包已经帮你处理好了Nginx与GitLab应用Unicorn/Puma、Sidekiq等之间的代理和路由逻辑。缺点灵活性相对较低。如果你需要在这个服务器上运行其他Web服务比如一个静态博客或另一个Web应用并共用80/443端口配置起来会有点麻烦。适用场景GitLab作为该服务器上唯一的或主要的Web服务。方案二使用外部独立的Nginx/Apache作为反向代理在这种架构下你禁用了GitLab内置的Nginx然后在它前面架设一个独立的、你自己安装和配置的Nginx或Apache服务器。这个外部Nginx监听80和443端口负责SSL终止即解密HTTPS请求然后将解密后的HTTP请求转发给GitLab内置的Web服务通常监听另一个端口如8080。优点灵活性极高。你可以在同一个服务器上通过这个外部Nginx代理多个不同的后端服务实现基于域名的虚拟主机。你也可以更精细地控制Nginx的各项参数和模块。缺点配置更复杂需要维护两个地方的配置外部Nginx和GitLab自身出问题时排查链路更长。适用场景服务器上需要部署多个Web应用你对Nginx有深度定制需求已有现成的Nginx运维体系。我的选择建议除非你有明确的、强烈的理由需要使用外部代理比如公司已有统一的Nginx入口网关否则强烈建议新手和绝大多数标准部署采用方案一。它能减少很多不必要的复杂度。本文后续的详细配置也将以方案一作为基准展开。2.2 核心组件与数据流向当我们通过浏览器访问https://gitlab.yourcompany.com时请求是如何被处理的理解这个流程对调试至关重要。客户端浏览器/Git发起一个到gitlab.yourcompany.com:443的HTTPS连接请求。DNS解析将域名解析为你GitLab服务器的公网IP地址。网络与防火墙请求到达服务器确保服务器的防火墙如firewalld、ufw或云服务商的安全组已开放443端口TCP。GitLab内置Nginx监听443端口的正是它。它首先进行SSL握手出示你的服务器SSL证书。与客户端协商加密套件建立加密通道。请求代理Nginx解密请求后根据配置的规则将请求以HTTP协议此时已是内部明文转发给后端的GitLab应用服务器默认是Puma。GitLab应用Puma处理具体的业务逻辑如用户认证、仓库操作等生成响应。响应返回响应沿原路返回经过Nginx时被加密再发送给客户端。在整个链条中SSL证书、Nginx配置、GitLab应用配置是三个关键点。证书不对连接建立不了Nginx配置错了请求转发不到正确的地方GitLab配置不对它生成的链接可能还是http://导致重定向循环或样式丢失。2.3 SSL证书准备选型与获取这是HTTPS的基石。证书主要分两类1. 受信任的CA签发证书推荐用于生产环境免费证书Let‘s Encrypt是最佳选择自动化程度高有效期90天需自动续期。阿里云、腾讯云等厂商也提供一年期的免费单域名证书。付费证书提供更长的有效期如一年、两年、更高的保险金额和更广泛的操作系统/浏览器兼容性保证虽然现在免费证书兼容性也很好了。通常用于企业级对外服务。获取后你会得到两个关键文件your_domain.crt证书文件或包含证书链的fullchain.crt。your_domain.key私钥文件。此文件必须严格保密2. 自签名证书仅用于测试或内部开发环境优点自己生成完全免费随时创建。缺点浏览器和Git客户端会发出强烈的安全警告每次都需要手动确认或添加信任体验极差。不适合任何需要协作的正式环境。生成命令示例sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/gitlab/ssl/gitlab.yourcompany.com.key \ -out /etc/gitlab/ssl/gitlab.yourcompany.com.crt运行后会交互式地询问国家、地区、组织等信息其中Common Name (e.g. server FQDN or YOUR name)必须输入你的GitLab域名如gitlab.yourcompany.com。实操心得即使是内部测试我也建议尽量使用Let‘s Encrypt的免费证书。可以利用certbot工具自动化获取和续期避免每三个月手动操作的麻烦。对于无法公开访问的内网服务器可以使用DNS验证方式如果域名解析服务商提供API来申请证书。3. 基于内置Nginx的HTTPS详细配置这是最核心的实操部分。请确保你已准备好证书文件.crt或.pem以及.key并拥有服务器的sudo权限。3.1 环境与文件准备首先我们需要创建一个目录来存放SSL证书并设置正确的权限。Omnibus GitLab有它预期的位置。# 1. 创建GitLab期望的SSL证书目录 sudo mkdir -p /etc/gitlab/ssl sudo chmod 755 /etc/gitlab/ssl # 2. 将你的证书和私钥文件复制到该目录 # 假设你的证书文件是 gitlab.yourcompany.com.crt私钥是 gitlab.yourcompany.com.key # 请根据你的实际文件名和路径进行修改 sudo cp /path/to/your/gitlab.yourcompany.com.crt /etc/gitlab/ssl/ sudo cp /path/to/your/gitlab.yourcompany.com.key /etc/gitlab/ssl/ # 3. 设置严格的私钥文件权限非常重要 sudo chmod 600 /etc/gitlab/ssl/gitlab.yourcompany.com.key关键细节chmod 600意味着只有文件所有者root可以读写其他任何用户都无法访问。这是保护私钥安全的基本要求。如果权限太开放如644Nginx在启动时可能会出于安全考虑拒绝加载它。3.2 编辑GitLab主配置文件所有Omnibus GitLab的配置都集中在/etc/gitlab/gitlab.rb这个文件中。我们不需要直接修改Nginx的配置文件而是通过修改这个Ruby文件来生成最终的Nginx配置。使用你熟悉的编辑器如vim或nano打开它sudo vim /etc/gitlab/gitlab.rb接下来找到并修改以下关键配置项。你可以用搜索功能在vim中按/在nano中按CtrlW。# 1. 配置GitLab的外部访问URL。这是最重要的设置之一 # 将 http://gitlab.example.com 替换为你的HTTPS地址。 external_url https://gitlab.yourcompany.com # 2. 告诉GitLab内置Nginx监听HTTPS nginx[redirect_http_to_https] true # 自动将80端口的HTTP请求重定向到443端口的HTTPS nginx[listen_port] 80 # Nginx仍然监听80端口用于重定向 nginx[listen_https] true # 启用HTTPS监听 nginx[ssl_certificate] /etc/gitlab/ssl/gitlab.yourcompany.com.crt # 证书路径 nginx[ssl_certificate_key] /etc/gitlab/ssl/gitlab.yourcompany.com.key # 私钥路径 # 3. 可选但推荐配置SSL协议和加密套件禁用不安全的旧协议 nginx[ssl_protocols] TLSv1.2 TLSv1.3 # 只启用TLS 1.2和1.3 # 下面是一个较安全的加密套件配置示例你可以根据情况调整 nginx[ssl_ciphers] ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384 nginx[ssl_prefer_server_ciphers] on # 4. 重要如果你使用的是自签名证书或内部CA签发的证书需要禁用客户端证书验证 # 否则GitLab的CI/CD Runner等组件可能无法连接。 nginx[ssl_verify_client] off配置项解读与避坑指南external_url这个参数是“总开关”。GitLab的许多功能如仓库克隆地址、邮件中的链接、API端点都基于这个URL生成。一旦这里改为https://GitLab会认为自己正在通过HTTPS服务。务必确保这里的域名和你的证书域名完全一致。nginx[redirect_http_to_https]设为true后用户即使输入http://gitlab.yourcompany.com也会被自动301重定向到https://版本。这对用户体验和SEO都有好处。SSL协议与套件禁用老旧的、不安全的SSLv3和TLSv1.0、TLSv1.1是安全最佳实践。上面的ssl_protocols设置是一个安全的选择。加密套件ssl_ciphers的配置比较复杂如果你不确定可以暂时注释掉这一行使用Nginx的默认安全配置现代版本的Nginx默认配置已经比较安全。关于证书链如果你的证书提供商给了你两个文件一个是你的域名证书your_domain.crt一个是中间证书intermediate.crt你需要将它们合并成一个文件供Nginx使用。sudo cat /etc/gitlab/ssl/your_domain.crt /etc/gitlab/ssl/intermediate.crt /etc/gitlab/ssl/gitlab.yourcompany.com.crt然后将nginx[ssl_certificate]指向这个合并后的文件。很多云平台下载的证书包中会直接提供一个fullchain.crt或bundle.crt文件这就是已经合并好的证书链直接使用它即可。3.3 应用配置并重启服务修改完配置文件后需要让GitLab重新生成所有组件的配置并重启。# 1. 检查配置文件语法非必需但推荐 sudo gitlab-ctl reconfigure --dry-run # 如果没有报错再进行下一步 # 2. 重新配置并应用更改。这条命令会 # - 根据 /etc/gitlab/gitlab.rb 生成所有组件Nginx, Puma, Postgresql等的配置文件。 # - 重启受影响的服务。 sudo gitlab-ctl reconfigure # 3. 重启所有GitLab服务通常在上一步已经完成但有时为了确保万无一失可以再执行一次 sudo gitlab-ctl restartgitlab-ctl reconfigure是一个强大的命令它是Omnibus包管理的核心。每次修改gitlab.rb后都应该运行它而不是手动去修改分散在各处的配置文件。3.4 验证配置是否生效服务重启后通过以下步骤验证HTTPS是否配置成功浏览器访问直接打开https://gitlab.yourcompany.com。你应该能看到GitLab登录页面并且浏览器地址栏显示锁形图标对于受信任证书或安全警告对于自签名证书。检查Nginx状态sudo gitlab-ctl status nginx确保nginx服务是run状态。查看Nginx监听的端口sudo netstat -tulpn | grep :443应该能看到nginx进程正在监听443端口。测试Git操作git clone https://gitlab.yourcompany.com/your-group/your-project.git如果之前配置过HTTP现在用HTTPS克隆应该能成功并且会提示输入用户名和密码或使用访问令牌。4. 高级配置与调优基础配置完成后为了更安全、更高效我们可以进行一些优化。4.1 启用HSTS (HTTP Strict Transport Security)HSTS是一种安全策略机制它告诉浏览器“在接下来的一段时间内对于此域名及其子域名必须使用HTTPS连接”。这可以防止SSL剥离攻击并且能避免用户手动输入http://导致的未加密访问。在/etc/gitlab/gitlab.rb中添加nginx[hsts_max_age] 63072000 # HSTS有效期单位秒这里设为2年 nginx[hsts_include_subdomains] true # 是否包含子域名重要警告一旦启用HSTS并经过浏览器接收在有效期内你将很难再降级回HTTP。请确保你的HTTPS配置完全稳定后再启用此选项。对于测试环境可以将hsts_max_age设为一个很小的值如300秒。4.2 调整SSL会话缓存与会话票据SSL/TLS握手是一个计算密集型过程。启用会话缓存和会话票据可以减少重复握手带来的开销提升性能。nginx[ssl_session_cache] builtin:1000 shared:SSL:10m # 使用内置和共享缓存 nginx[ssl_session_timeout] 10m # 会话超时时间 nginx[ssl_session_tickets] on # 启用会话票据 (TLS session tickets)4.3 配置OCSP StaplingOCSP在线证书状态协议用于实时检查证书是否被吊销。默认情况下浏览器需要额外向CA的OCSP服务器发起查询这可能会拖慢页面加载速度并泄露用户隐私。OCSP Stapling允许Nginx在TLS握手时就将由CA签名过的证书状态证明OCSP响应一并发送给客户端从而解决上述问题。nginx[ssl_stapling] on nginx[ssl_stapling_verify] on # 你需要配置一个DNS解析器用于查询OCSP服务器 nginx[resolver] [8.8.8.8, 8.8.4.4] # 例如使用Google的公共DNS注意配置OCSP Stapling需要你的证书支持并且Nginx需要能访问外网以获取OCSP响应。配置后可以使用openssl s_client -connect gitlab.yourcompany.com:443 -status -servername gitlab.yourcompany.com命令来验证是否生效在输出中查找OCSP Response Status: successful。4.4 使用强密码保护私钥可选但重要如果你的私钥文件没有设置密码-nodes参数生成那么任何能读取该文件的人都可以冒充你的服务器。为私钥添加密码可以增加一层保护但这会导致Nginx每次启动都需要手动输入密码不适合自动化部署。一个折中的方案是在安全的环境下生成带密码的私钥然后在部署时使用一个去除了密码的版本仅用于Nginx而将带密码的原版妥善保管。# 移除私钥密码请确保操作环境绝对安全 sudo openssl rsa -in /etc/gitlab/ssl/gitlab.yourcompany.com.key -out /etc/gitlab/ssl/gitlab.yourcompany.com.key.nopass sudo mv /etc/gitlab/ssl/gitlab.yourcompany.com.key.nopass /etc/gitlab/ssl/gitlab.yourcompany.com.key sudo chmod 600 /etc/gitlab/ssl/gitlab.yourcompany.com.key5. 故障排查与常见问题实录即使按照步骤操作你也可能会遇到一些问题。下面是我在多次部署中遇到的典型问题及其解决方法。5.1 Nginx启动失败SSL相关错误问题现象执行sudo gitlab-ctl reconfigure或sudo gitlab-ctl restart nginx后nginx服务无法启动查看日志sudo gitlab-ctl tail nginx发现SSL错误。错误1SSL_CTX_use_PrivateKey_file失败原因私钥文件格式错误或者与证书不匹配。排查# 检查私钥和证书是否匹配 sudo openssl x509 -noout -modulus -in /etc/gitlab/ssl/gitlab.yourcompany.com.crt | openssl md5 sudo openssl rsa -noout -modulus -in /etc/gitlab/ssl/gitlab.yourcompany.com.key | openssl md5两个命令输出的MD5值必须相同否则就是不匹配。解决重新获取或生成匹配的证书和私钥对。错误2PEM_read_bio_X509_AUX失败原因证书文件格式错误或内容不全。可能是复制粘贴时格式乱了或者证书链不完整。排查# 检查证书文件格式 sudo openssl x509 -in /etc/gitlab/ssl/gitlab.yourcompany.com.crt -text -noout如果命令报错说明证书文件无效。解决确保证书文件是纯文本的PEM格式以-----BEGIN CERTIFICATE-----开头。如果是.pfx或.p12格式需要转换。确保证书链完整。错误3权限问题nginx: [emerg] open() /etc/gitlab/ssl/xxx.key failed (13: Permission denied)原因Nginx工作进程通常是gitlab-www用户没有读取私钥文件的权限。解决sudo chown root:root /etc/gitlab/ssl/gitlab.yourcompany.com.key sudo chmod 600 /etc/gitlab/ssl/gitlab.yourcompany.com.key # 同时检查目录权限 sudo chmod 755 /etc/gitlab/ssl5.2 浏览器访问显示“不安全”或证书错误自签名证书警告这是预期行为。对于内部测试你可以在浏览器中导出证书然后将其导入到“受信任的根证书颁发机构”存储区操作有风险请谨慎。更好的办法是使用受信任的CA证书。证书域名不匹配证书的Common Name或Subject Alternative Name不包含你正在访问的域名。确保external_url中的域名和证书签发的域名完全一致包括是否带www。证书已过期检查证书有效期openssl x509 -in your.crt -noout -dates。免费证书如Let‘s Encrypt需要设置自动续期。证书链不完整浏览器没有收到完整的中间证书链。你需要将中间证书和你的域名证书合并成一个文件如3.2节所述。5.3 Git客户端SSL证书验证失败问题现象浏览器访问正常但使用git clone、git push时失败错误信息包含SSL certificate problem。对于自签名证书临时跳过验证不推荐用于生产git config --global http.sslVerify false这会让Git接受任何证书非常不安全仅用于临时测试。将自签名证书添加到Git的信任列表将你的.crt文件导出为PEM格式如果还不是。配置Git使用系统或自定义的CA包git config --global http.sslCAInfo /path/to/your/self-signed-cert.pem对于内部CA签发的证书确保Git客户端或操作系统信任了你内部CA的根证书。将内部CA的根证书安装到系统的受信任根证书存储区或者同样通过http.sslCAInfo指定。5.4 GitLab页面样式丢失或重定向循环问题现象启用HTTPS后能打开首页但CSS/JS加载不了页面布局错乱或者登录后陷入无限重定向。根本原因GitLab应用如Puma、Workhorse仍然以为自己在HTTP环境下运行生成的静态资源链接或重定向URL仍然是http://。解决方案99%的情况是因为external_url没有正确设置为https://开头。请仔细检查/etc/gitlab/gitlab.rb中的external_url设置确保它是https://your.domain.com。彻底排查检查external_url。运行sudo gitlab-ctl reconfigure确保配置生效。检查GitLab的当前配置sudo gitlab-rake gitlab:env:info查看输出的GitLab URL是否正确。如果使用了负载均衡器或外部代理确保它正确地设置了X-Forwarded-Proto头为https并在GitLab配置中设置了nginx[real_ip_trusted_addresses]和gitlab_rails[trusted_proxies]。5.5 使用Let‘s Encrypt证书自动续期失败如果你使用Omnibus GitLab内置的Let‘s Encrypt集成通过设置letsencrypt[enable] true续期是自动的。如果失败可以手动测试续期sudo gitlab-ctl renew-le-certs查看日志sudo gitlab-ctl tail letsencrypt常见失败原因网络问题服务器无法访问Let‘s Encrypt的ACME服务器。域名验证失败你的服务器公网IP对应的80或443端口无法被Let‘s Encrypt访问以完成HTTP-01或TLS-ALPN-01挑战。检查防火墙和安全组。证书目录权限问题确保/etc/gitlab/ssl目录存在且权限正确。6. 配置后的维护与监控HTTPS配置不是一劳永逸的需要持续的维护。证书过期监控证书过期是线上事故的常见原因。设置监控告警在证书到期前30天、7天、1天发出通知。你可以写一个简单的脚本定期检查#!/bin/bash DOMAINgitlab.yourcompany.com CRT_FILE/etc/gitlab/ssl/${DOMAIN}.crt EXPIRY_DATE$(openssl x509 -enddate -noout -in $CRT_FILE | cut -d -f2) EXPIRY_SEC$(date -d $EXPIRY_DATE %s) CURRENT_SEC$(date %s) DAYS_LEFT$(( (EXPIRY_SEC - CURRENT_SEC) / 86400 )) if [ $DAYS_LEFT -lt 30 ]; then echo 警告: ${DOMAIN} 的SSL证书将在 ${DAYS_LEFT} 天后过期 # 这里可以加入发送邮件或钉钉/企业微信告警的逻辑 fi将其加入crontab定期执行。安全扫描与评级定期使用在线工具如SSL Labs的SSL Server Test扫描你的GitLab域名。它会给出从A到F的评分并详细指出配置中的安全问题如不安全的协议、弱加密套件等。根据报告建议调整nginx[ssl_protocols]和nginx[ssl_ciphers]配置。备份证书和私钥证书和私钥是核心资产务必将其纳入你的备份策略。丢失私钥意味着现有的证书将无法使用需要重新申请。关注GitLab升级在升级GitLab大版本如从15.x到16.x前查阅官方升级文档。虽然SSL配置通常兼容但偶尔也会有关于Nginx或SSL配置的变更提示。在测试环境先行升级验证总是一个好习惯。我个人在维护多个GitLab实例的经验是将SSL配置gitlab.rb中相关部分和证书文件纳入版本控制系统当然私钥要加密存储任何变更都有记录可循。每次reconfigure之后除了在浏览器测试一定要用git clone和git push完整走一遍流程确保整个Git协议栈在HTTPS下也是畅通无阻的。这套流程跑顺了你的代码仓库就有了一个安全可靠的高速通道。