
1. 项目概述为什么GitLab必须上HTTPS如果你在公司内部或者自己的服务器上部署了GitLab还在用HTTP裸奔那我得提醒你这风险可不小。想象一下你团队的核心代码、数据库密码配置文件、甚至是一些敏感的设计文档在网络上传输时就像明信片一样任何一个经过的网络节点都能看得一清二楚。这不仅仅是数据泄露的问题现代浏览器对HTTP站点的标记越来越不友好很多新的Web API比如地理位置、通知在HTTP下根本无法使用。所以给GitLab配置HTTPS不是一个“可选项”而是一个“必选项”它关乎代码安全、团队协作安全甚至是公司合规性的底线。我见过不少团队初期为了图省事直接用IP加端口号访问GitLab觉得内网环境无所谓。但一旦有同事需要远程接入或者需要集成一些第三方CI/CD工具时没有HTTPS的麻烦就全来了。配置HTTPS的过程本质上是在GitLab自带的Nginx Web服务器上部署SSL/TLS证书将HTTP请求安全地重定向到HTTPS。这个过程涉及证书申请、Nginx配置、以及GitLab自身配置的联动任何一个环节出错都可能导致整个GitLab服务无法访问。接下来我会基于我多次在生产环境部署的经验把从证书准备到最终验证的完整链路拆解清楚并分享几个我踩过的大坑。2. 核心思路与方案选型给GitLab上HTTPS主流路径就两条一是使用GitLab内置的Nginx并为其配置证书二是利用外部独立的Nginx或其它Web服务器做反向代理。选哪条路取决于你的运维架构和现有基础设施。2.1 方案一使用GitLab内置Nginx推荐给大多数场景这是GitLab官方默认且文档最全的配置方式。GitLab Omnibus安装包也就是我们通常用一键脚本或Docker安装的那个已经集成了一个Nginx实例它专门用于服务GitLab的Web界面。我们的工作就是为这个“内置”的Nginx配置SSL证书。为什么推荐这个方案管理简单证书配置、HTTP到HTTPS的重定向、与GitLab Rails应用的通信全部由Omnibus包统一管理。你只需要修改一个主配置文件/etc/gitlab/gitlab.rb然后执行一条重载命令即可。升级无忧GitLab版本升级时其内置的Nginx配置模板也会同步更新你自定义的SSL配置会被安全地合并通常不会因为升级而失效。官方支持遇到任何问题官方文档和社区的支持都围绕这个模式展开排查路径清晰。这个方案最适合从零开始部署或者当前已经在使用内置Nginx的团队。你不需要额外维护一个Web服务器。2.2 方案二使用外部Nginx反向代理这个方案下你需要独立安装并运行一个Nginx将其配置为反向代理将收到的HTTPS请求转发给后端的GitLab服务GitLab自身的Nginx可能被禁用或者监听在另一个本地端口。什么情况下选这个方案统一入口服务器上已经运行了多个Web应用比如另一个网站、一个API服务你需要一个统一的Nginx来管理所有域名的SSL证书和路由。高级需求你需要用到一些GitLab内置Nginx不支持的模块或更复杂的流量控制策略。已有架构公司已有成熟的Nginx运维体系和配置管理工具如Ansible你希望将GitLab纳入统一管理。这个方案给了你最大的灵活性但代价是增加了架构的复杂性。你需要手动配置SSL终止、代理头传递如X-Forwarded-Proto等任何一个代理头没传对都可能导致GitLab生成错误的URL比如给你生成一个HTTP的仓库地址从而引发各种诡异问题。对于绝大多数只想安全稳定跑起GitLab的团队我强烈建议从方案一开始。本文后续的详细配置也将围绕方案一展开。方案二更像是一个高级运维的定制选项我们会在最后简要提及其关键差异点。3. 实操前的核心准备证书与域名动手改配置之前两样东西必须准备好一个有效的域名和一个与之匹配的SSL证书。这里面的门道不少。3.1 域名解析与绑定你不能用一个IP地址或者localhost来申请证书。你必须有一个域名例如gitlab.your-company.com并且将该域名的A记录或CNAME记录正确解析到你的GitLab服务器公网IP上。注意即使是内网使用也强烈建议使用一个内部域名可以在内部DNS服务器上配置或者直接修改所有客户端机器的hosts文件。这不仅仅是为了证书很多功能如邮件通知里的链接依赖于一个固定的域名。3.2 SSL证书的获取与选择证书有三种主要类型适用于不同场景商业证书从DigiCert、Sectigo等权威机构购买。浏览器信任度最高但需要付费。一般用于对公网提供服务的生产环境。Let‘s Encrypt免费证书这是开源社区的福音。通过ACME协议自动签发有效期90天支持自动续期。对于个人项目、测试环境或预算有限的团队这是首选。你可以使用certbot工具自动化完成申请和续期。自签名证书自己用OpenSSL生成的证书。最大的问题是浏览器会显示“不安全”警告需要手动将根证书导入到每个客户端电脑、手机的信任库中。仅适用于封闭的、可控的内部开发或测试环境不适合需要频繁多端访问的场景。如何选择公有云/对外服务如果服务器有公网IP域名能公网解析无脑选Let‘s Encrypt。自动化工具成熟完全免费。纯内网/无公网IP如果服务器在内网域名无法被Let‘s Encrypt的验证服务器访问。有两个选择自签名证书快速但每个访问者都要安装证书运维成本高。搭建内部CA在内部网络建立自己的证书颁发机构为所有内部服务签发受内部机器信任的证书。这是中大型企业内网的规范做法但搭建和维护有一定复杂度。实操心得Let‘s Encrypt申请小技巧使用certbot申请证书时如果GitLab的80或443端口已被占用certbot的默认验证方式可能会失败。这时可以使用--webroot模式指定一个目录让certbot放置验证文件然后通过配置GitLab Nginx让该目录可访问即可。命令大致如下sudo certbot certonly --webroot -w /var/www/letsencrypt -d gitlab.your-company.com --email your-emailexample.com --agree-tos这里/var/www/letsencrypt就是你指定的Web根目录。之后需要在Nginx配置中确保/.well-known/acme-challenge/路径能映射到这个目录。假设你最终获得的证书文件是证书文件/etc/letsencrypt/live/gitlab.your-company.com/fullchain.pem私钥文件/etc/letsencrypt/live/gitlab.your-company.com/privkey.pem请记下这两个路径接下来会用到。4. 详细配置步骤修改GitLab主配置一切准备就绪现在开始修改GitLab的核心配置文件/etc/gitlab/gitlab.rb。这个文件是Ruby语法但配置方式很简单主要是取消注释和赋值。4.1 配置外部访问URL和HTTPS首先告诉GitLab它应该用什么地址被访问。# 将 external_url 的值从HTTP协议改为HTTPS协议并填写你的完整域名。 external_url https://gitlab.your-company.com这个配置是最关键的一步。它不仅仅是一个显示用的URLGitLab内部的许多组件如Git clone地址、API端点、邮件中的链接都会基于这个值来生成。一旦这里写错会导致连环错误。4.2 配置内置Nginx的SSL接下来找到或添加关于Nginx和SSL的配置部分。# 告诉内置Nginx监听443端口HTTPS默认端口 nginx[listen_port] 443 nginx[listen_https] true # 指定SSL证书和私钥的路径 nginx[ssl_certificate] /etc/letsencrypt/live/gitlab.your-company.com/fullchain.pem nginx[ssl_certificate_key] /etc/letsencrypt/live/gitlab.your-company.com/privkey.pem重要参数解读与避坑指南ssl_certificate这里应该放证书链文件fullchain.pem它包含了你的站点证书和中间CA证书。有些教程错误地指向只有站点证书的文件cert.pem这可能导致某些浏览器或Git客户端因证书链不完整而报错。ssl_certificate_key你的私钥文件路径。确保这个文件的权限是600即-rw-------并且所有者是root否则Nginx会因安全原因拒绝读取。sudo chmod 600 /etc/letsencrypt/live/gitlab.your-company.com/privkey.pem关于密码如果你在生成证书或私钥时设置了密码需要在这里通过nginx[ssl_password_file]指定密码文件。但强烈不建议给私钥设密码因为每次Nginx重启都需要手动输入无法实现自动化。Let‘s Encrypt的证书私钥默认无密码。4.3 启用HTTP到HTTPS的自动重定向我们希望所有访问HTTP80端口的请求都自动跳转到HTTPS。nginx[redirect_http_to_https] true # 如果你自定义了HTTP的监听端口也需要在这里指定 # nginx[redirect_http_to_https_port] 80这个配置会让内置Nginx在80端口也开启一个监听但只做一件事返回一个301重定向响应告诉浏览器“请使用HTTPS地址访问”。4.4 可选但推荐强化SSL安全配置默认的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 nginx[ssl_prefer_server_ciphers] onssl_protocols禁用已证实不安全的TLSv1.0和TLSv1.1只启用TLSv1.2和TLSv1.3。ssl_ciphers这里定义了一个优先使用前向保密Forward Secrecy加密套件的列表。前向保密意味着即使服务器的私钥未来被泄露过去截获的加密通信也无法被解密安全性更高。你可以使用在线工具如 SSL Labs 的测试来扫描你的站点它会给出具体的配置建议。5. 应用配置与重启服务配置文件修改完成后不能直接重启Nginx因为GitLab Omnibus包管理着数十个相互依赖的服务PostgreSQL, Redis, Sidekiq, Puma等。必须使用其提供的工具来重新配置和重启。5.1 关键命令gitlab-ctl reconfigure这是最重要的命令没有之一。sudo gitlab-ctl reconfigure这条命令会解析/etc/gitlab/gitlab.rb文件。根据解析出的配置生成所有组件包括Nginx的实际运行时配置文件。如果服务需要重启它会按正确的顺序重启相关服务。实操心得一定要看日志运行reconfigure时务必关注命令的输出。如果配置有语法错误比如路径不对、权限不对通常会在这里报错。一个常见的错误是证书或私钥文件路径错误reconfigure可能会失败并提示Nginx配置生成失败。5.2 检查服务状态配置应用完成后检查所有服务是否正常运行sudo gitlab-ctl status你应该看到nginx: run的状态。如果显示nginx: down说明启动失败需要查看详细日志sudo gitlab-ctl tail nginx日志会明确告诉你失败原因比如“SSL私钥文件无法读取”或“证书格式错误”。5.3 验证HTTPS访问在浏览器中访问https://gitlab.your-company.com。成功标志地址栏显示锁形图标点击锁图标能看到证书信息网站正常加载登录页。失败情况证书无效/不安全警告检查证书是否过期、域名是否匹配、客户端是否信任颁发机构自签名证书需手动导入。无法连接检查服务器防火墙是否开放了443端口sudo ufw allow 443/tcp或对应防火墙命令。检查Nginx是否在监听443端口sudo netstat -tlnp | grep :443。6. 高级配置与疑难问题排查即使按照上述步骤操作你可能还是会遇到一些“坑”。这里我总结几个最常见的问题和进阶配置。6.1 问题排查Git Clone over HTTPS 失败这是配置HTTPS后最高频的问题。现象是在网页上复制HTTPS的仓库地址后在本地使用git clone或git push时提示SSL证书错误或一直要求输入密码。原因与解决方案自签名证书不被信任 Git客户端使用操作系统或自带的CA证书库来验证服务器证书。自签名证书不在这个库中所以被拒绝。解决方案A不推荐临时关闭验证非常不安全。绝对不要在生产环境使用。git config --global http.sslVerify false解决方案B推荐将你的自签名证书的根证书或公钥添加到Git的信任列表。# 将你的CA证书如 rootCA.pem复制到一个目录然后告诉Git信任它 git config --global http.sslCAInfo /path/to/your/rootCA.pem证书链不完整 你的nginx[ssl_certificate]可能只指向了站点证书cert.pem缺少中间证书。确保指向的是fullchain.pem。GitLab生成的克隆地址错误 检查external_url配置是否准确无误地设置为https://...。这个URL是GitLab生成所有链接的基准。6.2 问题排查邮件中的链接仍是HTTP配置了HTTPS后用户收到的密码重置邮件或通知邮件里的链接却还是http://开头。原因GitLab的多个组件有缓存。external_url修改后需要清理缓存。解决方案# 使用GitLab Rails控制台清理缓存 sudo gitlab-rails console # 在控制台中执行 Rails.cache.clear # 然后退出 exit此外还需要检查GitLab的gitlab.yml文件由reconfigure生成中的host和port设置是否正确但通常reconfigure会处理好。最根本的还是要确保external_url正确。6.3 进阶配置HSTSHTTP严格传输安全HSTS是一个安全特性它告诉浏览器“在接下来的一段时间里对于这个域名只允许使用HTTPS连接”。即使用户手动输入http://浏览器也会强制转成https://。这能有效防止SSL剥离攻击。 在/etc/gitlab/gitlab.rb中启用nginx[hsts_max_age] 31536000 # 有效期单位秒一年 nginx[hsts_include_subdomains] true # 是否包含子域名警告一旦启用并部署在有效期内你的域名将无法通过HTTP访问。请确保你的HTTPS配置100%稳定后再开启此选项。6.4 方案二关键点外部Nginx反向代理如果你选择使用外部Nginx核心思路是在/etc/gitlab/gitlab.rb中禁用内置Nginx并让GitLab工作进程Puma监听一个本地Socket或端口。nginx[enable] false puma[listen] 127.0.0.1:8080 # 例如监听在本地8080端口独立安装Nginx并编写一个Server配置块。关键配置如下server { listen 443 ssl http2; server_name gitlab.your-company.com; ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/privkey.pem; # ... 其他SSL优化配置 ... location / { proxy_pass http://127.0.0.1:8080; # 指向GitLab Puma proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 这行至关重要 proxy_http_version 1.1; } }其中proxy_set_header X-Forwarded-Proto $scheme;是灵魂所在它告诉后端的GitLab“这个请求最初是HTTPS过来的”。没有这个头GitLab会认为所有请求都是HTTP从而生成错误的URL。7. 配置后的维护与监控HTTPS配置不是一劳永逸的尤其是使用Let‘s Encrypt证书时。7.1 证书自动续期Let‘s Encrypt证书只有90天有效期。你需要设置一个自动续期的任务Cron Job。# 编辑root用户的crontab sudo crontab -e # 添加一行例如每周日凌晨2点检查并续期续期后重启GitLab Nginx 0 2 * * 0 /usr/bin/certbot renew --quiet /usr/bin/systemctl reload nginx # 注意如果你用的是GitLab内置Nginx重载命令是 sudo gitlab-ctl hup nginx 0 2 * * 0 /usr/bin/certbot renew --quiet /usr/sbin/gitlab-ctl hup nginxcertbot renew命令会检查所有已管理证书如果有效期不足30天则自动续期。reload或hup命令能让Nginx重新加载配置和证书而不中断现有连接。7.2 定期安全检查每隔一段时间比如每季度你应该检查一下SSL配置的安全性。使用SSL Labs测试访问https://www.ssllabs.com/ssltest/输入你的GitLab域名进行免费扫描。它会从协议、加密套件、密钥强度等多个维度打分A为最佳并给出详细的改进建议。检查证书有效期可以将证书过期监控纳入你的运维监控系统如Zabbix, Prometheus或者在日历上设置提醒。关注安全公告关注Nginx和OpenSSL的安全公告及时更新系统包修复可能存在的漏洞。给GitLab配置HTTPS从安全角度看是零妥协的底线操作。整个过程像是一次对服务网络层的小型手术步骤清晰但要求细致。我的经验是第一次配置时最好在一个测试环境上完整走一遍流程记录下所有命令和可能报错的信息。这样当你在生产环境操作时就能心中有数手到擒来。毕竟没有什么比看到浏览器里那个绿色的锁以及git clone时流畅的安全连接更让人安心了。