海外云服务器搭建 GitLab CE 私有代码托管 + GitLab Runner CI/CD 自动化部署完整教程(2026最新版)

📅 · ChengziCloud - 一站式云端服务

Meta Description: 从零开始用海外云服务器搭建 GitLab CE 私有代码托管平台,并部署 GitLab Runner 跑通 CI/CD 自动化部署流水线。涵盖 Docker Compose 部署命令、initial_root_password 首次登录、Let's Encrypt 自动 HTTPS、Runner 注册(glrt- 令牌)、.gitlab-ci.yml 三段式流水线、rsync 自动发布、Puma/Sidekiq 内存优化、备份与恢复、fail2ban 加固,附服务器配置推荐表、服务商价格表、自建 vs SaaS 成本对比表与 8 条常见问题 FAQ。

> 关键词:GitLab 搭建教程、海外云服务器搭建 GitLab、GitLab CE 私有部署、GitLab Runner 安装、CI/CD 自动化部署、Docker 部署 GitLab、GitLab 内存优化、自建代码托管平台、GitLab 和 Gitea 区别、gitlab-ci.yml 教程

前言

代码托管平台放在别人家里,和数据库放在别人家里一样,是一种"用便利换控制权"的交易。GitHub、GitLab.com、Bitbucket 的免费额度对个人和小团队确实够用,但只要遇到下面任何一种情况,你就需要一个跑在自己服务器上的 GitLab:公司要求源码不出境;仓库里有客户数据,不能落在第三方的机器上;CI/CD 的构建机需要访问内网数据库;或者你被 SaaS 的并发构建时长和 Runner 分钟数卡得很难受。

GitLab CE(Community Edition)是这个需求下最完整的开源答案:它不只是一个 Git 仓库,而是一整套研发协作平台——代码托管、Merge Request(含代码审查)、Issue 看板、CI/CD 流水线、容器镜像仓库(Registry)、制品库、Wiki、Pages 一应俱全。而且它是"单体套件":一个 Docker 镜像里打包好了 PostgreSQL、Redis、Puma、Sidekiq、Nginx、Gitaly,装完即用,不需要你一个个把中间件拼起来。

代价是资源。 GitLab 不是轻量软件,官方明确建议小型团队也要 4 核 CPU 起步。这既是它的门槛,也决定了本文的重点:不只是"怎么装起来",更要讲清楚怎么在有限内存里让它跑稳、怎么把 CI/CD 流水线跑通、以及怎么把数据备份到你自己能找回的地方

本文给出可直接复制执行的完整命令,以 Ubuntu 22.04(Docker 方式)为主线,覆盖:买服务器 → 装 Docker → 写 compose 部署 GitLab CE → 首次登录与初始化 → 自动 HTTPS 证书 → 安装并注册 GitLab Runner → 写第一条 .gitlab-ci.yml 流水线 → rsync 自动发布到生产机 → 内存优化 → 备份与恢复 → 安全加固,最后附服务器配置推荐表、服务商价格参考表、自建与 SaaS 的成本对比表,以及 8 条常见问题。

> 🚀 还没有海外云服务器?通过 5.chengzicloud.cloud 选购阿里云/AWS/腾讯云国际版,享专属折扣和中文技术支持。

一、先想清楚:GitLab、Gitea、SaaS,到底该选哪个

在动手前先做一次选型,因为选错了不是多花点钱的问题,而是整篇文章的命令都不适用。本站已经有一篇 Gitea 自建 Git 服务器教程 和一篇 Coolify 一键部署平台教程,很多读者会问"这三个到底差在哪"。下面这张边界表一次说清,本文只负责 GitLab 这一层

| 既有 / 相邻主题 | 它解决的问题 | 与本文的关系 | |---|---|---| | Gitea 自建 Git 服务器 | 轻量代码托管,1核1G 就能跑,够用就好 | GitLab 是它的"重型上位替代":多出 CI/CD、代码审查、Registry、Issues 看板,但资源需求高一到两个量级 | | Coolify 一键部署平台 | 自建 Heroku/Vercel 式 PaaS,把镜像/仓库部署成应用 | 本文讲源码托管 + 流水线这一层;Coolify 讲部署执行这一层,两者可以组合(GitLab 构建、Coolify 托管) | | Docker + Portainer 容器管理 | 容器与编排的可视化管理底座 | 本文的部署底座,直接用,不重复 | | Kubernetes 单节点集群 | 集群级编排与自愈调度 | 本文是单机 GitLab;K8s 是更高阶的编排层,规模上百人再上 | | Nginx 反向代理 + Let's Encrypt SSL | 外部反向代理与证书签发 | 本文可用其替代 GitLab 自带 Nginx;也可直接用 GitLab 内置的证书自动化(第四节) |

一张表判断你该选谁:

| 你的情况 | 推荐方案 | |---|---| | 1~3 人,只想有个私有 Git 仓库,省钱省心 | Gitea(1核1G,月费 $4 级别) | | 团队 5~50 人,要 CI/CD、代码审查、镜像仓库 | GitLab CE 自建(本文,4核8G 起) | | 只是个人备份代码,不需要流水线,且能接受源码在境外 | GitHub 私有仓库(免费,零维护) | | 团队全球化、要 SLA、不想运维 | GitLab.com / GitHub Team(按席位付费,见第二节成本对比) |

一个必须提前说清的能力边界:自建 GitLab 不等于自建了高可用。本文部署的是单机单实例,服务器一挂,Git 仓库和流水线一起停。真正的高可用需要 Gitaly Cluster + 多节点 PostgreSQL + 外部 Redis + 负载均衡,那是另一个量级的工程(也是本站站7 企业级进阶系列的话题)。单机 GitLab 的正确期待是:用一份可控的成本换回数据主权和 CI/CD 自由度,同时把备份做到位——第六节的备份不是可选项。

二、服务器怎么选:GitLab 是"内存吃货",不是"CPU 吃货"

GitLab 的资源画像和 AdGuard Home、Gitea 这类轻量服务完全相反,选错了配置会一路卡到崩溃。

第一,内存是硬约束,且不可压缩。 一台装好 GitLab CE 的机器里,常驻进程至少有:Puma(Web 应用服务器,多 worker)、Sidekiq(后台任务队列)、PostgreSQL(数据库)、Redis(缓存与队列)、Gitaly(Git 仓库服务)、Nginx。即使零访问量,这些进程加起来常驻就在 3~4GB 量级。官方给 100 用户以内的小型部署建议最低 4GB,推荐 8GB;低于 4GB 不是"跑不动",而是 Docker 构件的构建任务一上来就被 OOM Killer 杀掉,表现为容器反复重启。

第二,CPU 在"有 CI 构建"时才吃紧。 纯代码托管、几个人推推代码,2 核完全够;但一旦 Runner 在同一台机器上跑 npm cidocker build、Maven 编译,构建会瞬间把 CPU 打满,连带 Web 界面卡死。经验法则:只要在同一台机器上跑 CI,就按"Web 资源 × 2"备配置,或者干脆把 Runner 拆到另一台机器。

第三,磁盘看仓库大小和流水线留存。 系统盘建议 40GB 起,并且流水线的构建产物(artifacts)和容器镜像会持续增长——这是所有自建 GitLab 最终磁盘爆掉的头号原因。第四节会给出留存策略。

第四,一定要加 Swap。 即使是 8GB 内存的机器,也建议配 2~4GB swap:内存瞬时峰值时先扛过去,比直接 OOM 杀掉 GitLab 好得多。这是成本最低、收益最高的一条。

服务器配置推荐(按使用规模)

| 使用场景 | 推荐配置 | 为什么够用 | |---|---|---| | 个人学习、1~2 人 | 2核 4G + 4G Swap | 关掉内置监控(第六节)后勉强够用,构建会慢 | | 小团队(10 人内,推荐) | 4核 8G + 2G Swap | 官方推荐档,Puma + Sidekiq + PostgreSQL + Redis 同时在线有余量 | | 中型团队(50 人内) | 4核 16G + SSD | 仓库和流水线并发上来,内存与 IO 都要留余量 | | 含高频 CI 构建 | 8核 16G 或"Web 4核8G + Runner 4核8G" | 把构建负载与 Web 分离,避免构建把界面拖死 | | Runner 专用机 | 4核 8G | 只跑构建,按并发数(concurrent)横向加机器 |

> ⚠️ 不要把 GitLab 和你正在跑的生产站塞在同一台小机器上。GitLab 的内存占用是"地板价"级的,它一起来,你的网站可能就连不上数据库了。

服务商价格参考

下面按"4核8G + 40GB SSD"这一推荐档整理公开官网参考区间(价格采集于 2026 年 9 月,仅为公开官网参考区间,请以官网实时价格为准):

| 服务商 | 4核8G 月付 | 年付(折扣后) | 数据中心 | 优点 | |---|---|---|---|---| | 阿里云国际版 ECS | $48~$72 | 约 6~8 折 | 新加坡/香港/硅谷 | 中文面板、支持支付宝 | | AWS Lightsail | 约 $44(8GB 档) | 固定价 | 全球 20+ 区域 | 固定月费、含流量额度、开箱即用 | | 腾讯云国际版 CVM | $50~$70 | 约 6~8 折 | 香港/新加坡/东京 | 低延迟到国内、微信支付 | | Vultr | 约 $48(8GB 档) | 固定价 | 全球 32 个 | 按小时计费、随时销毁重建 | | DigitalOcean | 约 $48(8GB 档) | 固定价 | 全球 14 个 | 文档完善、社区教程多 |

> 💡 自建 GitLab 优先看香港、东京、新加坡:开发和推代码的 RTT 通常只有几十毫秒,git clonegit push 的手感接近内网。如果团队在欧美,就选法兰克福、弗吉尼亚。通过 5.chengzicloud.cloud 购买以上平台还可享额外折扣。

自建 vs SaaS:把成本摆到桌面上

"自建是不是更贵"这个问题,取决于团队人数。SaaS 是按席位线性涨价的,自建是一台固定机器成本,所以人越多、自建越划算。下面把两条路的真实成本摆在一起(SaaS 价格采集于 2026 年 9 月,仅为公开官网参考区间):

| 方案 | 10 人团队年成本 | 数据存放 | CI/CD 构建 | 维护责任 | |---|---|---|---|---| | GitLab CE 自建(本文,4核8G) | 服务器约 $500~$800/年 | 只在你的机器上 | 自备 Runner,无分钟数限制 | 你自己(备份、升级、加固) | | GitLab.com Free | $0 | 厂商 | 每月 400 分钟共享额度 | 厂商 | | GitLab.com Premium | 约 $29/人/月 × 10 × 12 ≈ $3,480/年 | 厂商 | 每月 10,000 分钟 | 厂商 | | GitHub Team | 约 $4/人/月 × 10 × 12 ≈ $480/年 | 厂商 | 每月 3,000 分钟 | 厂商 | | Gitea 自建(1核1G) | 服务器约 $50~$70/年 | 只在你的机器上 | 无内置,需自搭 Drone/Woodpecker | 你自己 |

> 声明:本文价格数据采集于 2026 年 9 月,仅为公开官网参考区间。云服务器价格随区域、计费方式和活动浮动,SaaS 的席位价与免费额度也会调整,请以各厂商官网实时价格为准。除特别标注外,金额单位均为美元(USD)。

一句话结论:如果你要的核心是 CI/CD 不限分钟 + 源码不出境,10 人以上团队自建 GitLab 一年就能省下一大截订阅费,还能顺手把镜像仓库和制品库一起拿下;如果只有 2~3 个人、也不介意源码在第三方,用 SaaS 免费版更省心——动手前先算清自己属于哪一类。

三、部署第一步:装 Docker 并用 Compose 拉起 GitLab CE

第一步:系统初始化(防火墙 + Docker)

以 Ubuntu 22.04 为例,先把系统更到最新,装好防火墙工具和 Docker。下面的命令可整段复制执行:

`bash apt update && apt upgrade -y apt install -y ufw curl ca-certificates gnupg curl -fsSL https://get.docker.com | sh systemctl enable --now docker docker --version docker compose version `

docker compose version 应输出 v2 版本号。Docker 官方安装脚本已经自带 Compose v2 插件,不需要再单独装 docker-compose(带连字符的旧版)

放行必要端口。GitLab 本体要 80、443,SSH 用 22,另外给 GitLab 的 Git-over-SSH 单独留一个 2224:

`bash ufw allow 22/tcp ufw allow 80/tcp ufw allow 443/tcp ufw allow 2224/tcp ufw --force enable ufw status `

> ⚠️ 云厂商的安全组是第二道门。 上面的 ufw 只管机器内部,阿里云/AWS/腾讯云控制台的安全组必须同步放行 22、80、443、2224。很多人的站点明明配了防火墙却还是打不开,就是漏了安全组。

第二步:规划目录

GitLab 官方镜像需要三个持久化目录:配置、日志、数据(含 PostgreSQL 数据与 Git 仓库)。全部放到 /srv/gitlab 下,方便整体备份:

`bash mkdir -p /srv/gitlab/config /srv/gitlab/logs /srv/gitlab/data `

第三步:写 docker-compose.yml

进入 /srv/gitlab 新建 docker-compose.yml注意:本站的 Markdown 渲染器会把行首的井号当作标题,所以本文所有配置文件代码块里都是"零注释"写法,说明一律写在正文或表格里。 文件内容如下:

`yaml version: '3.6' services: web: image: 'gitlab/gitlab-ce:latest' container_name: gitlab restart: always hostname: 'gitlab.example.com' environment: GITLAB_OMNIBUS_CONFIG: | external_url 'https://gitlab.example.com' gitlab_rails['gitlab_shell_ssh_port'] = 2224 gitlab_rails['time_zone'] = 'Asia/Shanghai' ports: - '80:80' - '443:443' - '2224:22' volumes: - '/srv/gitlab/config:/etc/gitlab' - '/srv/gitlab/logs:/var/log/gitlab' - '/srv/gitlab/data:/var/opt/gitlab' shm_size: '256m' `

这份配置里有几个关键决定,逐条说明:

| 配置项 | 作用 | 为什么这样写 | |---|---|---| | external_url | GitLab 对外访问地址 | 必须写成你的域名(含 https://);写错会导致 clone 地址、Webhook、Pages 全部生成错误链接 | | gitlab_shell_ssh_port | Git 的 SSH 端口 | 宿主机的 22 已给系统 SSH 用,所以把容器的 22 映射到主机 2224,并显式告诉 GitLab,clone 地址才会带正确的端口 | | time_zone | 时区 | 不设默认 UTC,中文团队看流水线日志时间会差 8 小时 | | 三个 volumes | 配置、日志、数据落盘 | 不挂卷的话容器重建后所有仓库和账号全丢,这是自建 GitLab 最惨的翻车方式 | | shm_size: 256m | 共享内存 | GitLab 官方推荐,默认 64MB 在并发操作时会报错 |

gitlab.example.com 替换成你自己的域名(本文统一用占位域名 gitlab.example.com,读者请自行替换)。

第四步:启动并等待首次初始化

`bash cd /srv/gitlab docker compose up -d docker compose logs -f --tail=100 `

这一步要有耐心:GitLab 首次启动会重建数据库、编译资源,根据机器性能通常需要 4~8 分钟。日志里出现 gitlab Reconfigured! 或你看到 curl 能返回登录页,才算真正就绪。判断就绪的可靠方法是轮询健康检查:

`bash until curl -sk -o /dev/null -w "%{http_code}" https://gitlab.example.com/users/sign_in | grep -q 200; do echo "等待 GitLab 就绪..."; sleep 15 done echo "GitLab 已就绪" `

四、首次登录、初始化与自动 HTTPS

第五步:拿到初始 root 密码

从 GitLab 14 起,首次启动会生成一个随机 root 密码,存在容器内的 /etc/gitlab/initial_root_password

`bash docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password `

> 🔴 这个文件只在首次 reconfigure 后的 24 小时内有效,之后会被自动删除。所以第一件事是登录后立刻改密码。如果不小心错过了 24 小时窗口,用下面这条命令直接重置:

`bash docker exec -it gitlab gitlab-rails runner "user = User.find_by_username('root'); user.password = 'YourNewStrongPassw0rd!'; user.password_confirmation = 'YourNewStrongPassw0rd!'; user.save!" `

用浏览器打开 https://gitlab.example.com,用户名 root + 上一步拿到的密码登录。第一件事:右上角头像 → Edit profile → Password 改掉初始密码

第六步:初始化必做的四件事

1. 关闭公开注册。 自建 GitLab 默认允许任何人注册账号,公网上非常危险。路径是 Admin Area → Settings → General → Sign-up restrictions,取消勾选 "Sign-up enabled",保存。团队账号一律由管理员手动创建,或走 LDAP/SSO。

2. 创建你的第一个用户和项目。 先建一个普通管理员账号给自己用,再建项目。不要长期用 root 做日常操作,root 只留给管理任务。

3. 设置代码推送协议偏好。Admin Area → Settings → General → Visibility and access controls 里可以把默认 clone 协议从 HTTPS 换成 SSH,团队用 SSH 免密会更顺手。

4. 配置邮件(可选但建议)。 没有邮件,用户收不到注册确认、密码重置、流水线失败通知。在 gitlab.rb 里配 SMTP(下面第六节的内存优化里会一起给出修改方式)。

第七步:让 HTTPS 自动化——两种方案

方案 A(推荐,最省事):用 GitLab 自带的 Let's Encrypt 自动化。 只要 external_url 写的是 https:// 且域名已解析到本机,GitLab Omnibus 就能自动申请并续期证书。编辑配置文件:

`bash docker exec -it gitlab vi /etc/gitlab/gitlab.rb `

在文件里加入下面几行(Ruby 语法,注意引号是英文单引号):

`ruby external_url 'https://gitlab.example.com' letsencrypt['enable'] = true letsencrypt['contact_emails'] = ['[email protected]'] letsencrypt['auto_renew'] = true letsencrypt['auto_renew_hour'] = 3 letsencrypt['auto_renew_minute'] = 30 `

保存后重新配置生效:

`bash docker exec -it gitlab gitlab-ctl reconfigure `

⚠️ 两个前提必须满足:域名 A 记录已经指向这台服务器;80 端口能从公网访问(Let's Encrypt 的 HTTP-01 校验需要)。

方案 B:用外部 Nginx 反代 + certbot 签证书。 如果你不想让 GitLab 自己管证书(例如同一台机器上还跑着别的站点),就把 compose 里的 443:443 去掉、只暴露 80,然后按本站 Nginx 反代 + Let's Encrypt 教程 配置反向代理到 127.0.0.1:80。这是更"标准"的做法,但多了一层要维护的配置。

验证 HTTPS 是否生效(证书签发后):

`bash curl -skI https://gitlab.example.com/users/sign_in | head -5 `

返回 HTTP/2 200 即成功。

五、装 GitLab Runner,把 CI/CD 流水线真正跑起来

装完 GitLab 你只完成了"代码托管"这一半。真正让自建平台值得的,是 GitLab Runner——它才是执行 .gitlab-ci.yml 里那些命令的"工人"。 没有 Runner,流水线只会一直显示 pending(挂起)。

第八步:安装 Runner(Docker 方式)

Runner 可以装在同一台机器,也可以单独一台(推荐,构建不占用 Web 资源)。用 Docker 拉起来最干净:

`bash docker run -d --name gitlab-runner --restart always \ -v /srv/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ gitlab/gitlab-runner:latest `

-v /var/run/docker.sock 是给 docker executor 用的:Runner 每次构建都会临时起一个容器跑你的脚本,所以要能操作宿主机的 Docker。

第九步:注册 Runner(GitLab 16+ 的 glrt- 令牌流程)

这里是最容易踩坑的地方:网上大量老教程让你去复制"注册令牌(registration token)",但从 GitLab 16 起这个流程已经废弃,改为在界面里创建"项目 Runner"并生成一个 glrt- 开头的认证令牌

操作路径:进入你的项目 → Settings → CI/CD → Runners → New project runner → 勾选 "Run untagged jobs"(可选)→ 创建后复制那个 glrt- 开头的令牌。然后在服务器上执行注册:

`bash docker exec -it gitlab-runner gitlab-runner register \ --non-interactive \ --url "https://gitlab.example.com" \ --token "glrt-把你的令牌粘到这里" \ --executor "docker" \ --docker-image "alpine:latest" \ --description "docker-runner-01" `

注册成功后回到项目的 CI/CD → Runners 页面,应该能看到一个绿色圆点的在线 Runner。如果显示灰色,先 docker logs gitlab-runner 看报错。

> ⚠️ 如果构建里要用 Docker-in-Docker(docker build),需要给 Runner 开特权模式。编辑 Runner 配置 /srv/gitlab-runner/config/config.toml,把 privileged 设为 true

`toml concurrent = 2 check_interval = 3

[[runners]] name = "docker-runner-01" url = "https://gitlab.example.com" executor = "docker" [runners.docker] tls_verify = false image = "alpine:latest" privileged = true volumes = ["/cache"] `

改完 docker restart gitlab-runner 生效。注意:特权模式等于把宿主机的 root 权限交给了构建脚本,只对可信仓库开启。

第十步:写第一条流水线(.gitlab-ci.yml)

在项目根目录新建 .gitlab-ci.yml。下面是一条构建 → 测试 → 部署三段式的完整流水线示例,构建产物用 artifacts 在阶段间传递:

`yaml stages: - build - test - deploy

build-job: stage: build image: node:20-alpine script: - npm ci - npm run build artifacts: paths: - dist/ expire_in: 1 week

test-job: stage: test image: node:20-alpine script: - npm ci - npm test

deploy-job: stage: deploy image: alpine:latest before_script: - apk add --no-cache openssh-client rsync - eval $(ssh-agent -s) - echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - - mkdir -p ~/.ssh - chmod 700 ~/.ssh - ssh-keyscan -H example.com >> ~/.ssh/known_hosts script: - rsync -avz --delete dist/ [email protected]:/var/www/app/ only: - main `

提交后,Build → Pipelines 里会立即出现一条流水线,三个阶段依次亮起。这份配置里三个设计点值得说明:

| 设计点 | 作用 | 为什么这样写 | |---|---|---| | artifacts.paths | 把 dist/ 传给后续阶段 | 不声明的话,每个 job 都是全新容器,上一个 job 的构建结果会消失 | | expire_in: 1 week | 构建产物 7 天后自动清理 | 这是控制磁盘增长最重要的一行,流水线产物会无上限堆积 | | only: main | 只对主分支部署 | 避免开发分支的提交误触发生产发布 | | SSH_PRIVATE_KEY | 部署密钥 | 在 Settings → CI/CD → Variables 里添加,务必勾选 "Masked" |

> 🔴 私钥千万不要写进 .gitlab-ci.yml 流水线文件是提交进仓库的,任何能看到仓库的人都能看到它。部署私钥、数据库密码、API Key 一律走 Settings → CI/CD → Variables,并勾选 Masked(日志里自动打码)和 Protected(只在受保护分支可用)。

六、内存优化、备份恢复与安全加固

第十一步:把内存占用压下来(2核4G 必需)

如果服务器只有 4GB 内存,第一件要做的事是关掉 GitLab 自带的整套监控组件——Prometheus、Grafana、Alertmanager、Exporter 在你没有专门用它们的时候纯属浪费,能省下 1GB 以上。编辑 gitlab.rb 并加入:

`ruby prometheus_monitoring['enable'] = false prometheus['enable'] = false grafana['enable'] = false alertmanager['enable'] = false node_exporter['enable'] = false redis_exporter['enable'] = false

puma['worker_processes'] = 2 puma['per_worker_max_memory_mb'] = 650

sidekiq['max_concurrency'] = 10 `

然后 docker exec -it gitlab gitlab-ctl reconfigure 生效。各项含义:prometheus_monitoring 系列关闭内置监控省内存;puma['worker_processes'] 把 Web worker 从默认(约为 CPU 核数)降到 2,是最有效的省内存手段;sidekiq['max_concurrency'] 限制后台任务并发。

再配一块 swap 兜底(4GB 内存以下强烈建议):

`bash fallocate -l 4G /swapfile chmod 600 /swapfile mkswap /swapfile swapon /swapfile echo '/swapfile none swap sw 0 0' >> /etc/fstab free -h `

> ⚠️ 一个反直觉的调优提醒:puma['worker_processes'] 不要设成 1 以下的比例值,也不要盲目设很大。设太小会让 Web 界面在高并发下排队,设太大在内存不足时会直接被 OOM Killer 杀掉——2~3 是 4核8G 以内的稳妥值。

第十二步:备份与恢复(自建 GitLab 的生命线)

备份必须做两件事,缺一不可:备份 GitLab 应用数据,以及备份配置文件与密钥。

`bash docker exec -t gitlab gitlab-backup create `

备份文件会落在 /srv/gitlab/data/backups/(容器内是 /var/opt/gitlab/backups/)。但这条命令不包含配置文件gitlab.rbgitlab-secrets.json(包含数据库加密密钥)需要单独备份:

`bash tar -czf /root/gitlab-config-$(date +%F).tar.gz -C /srv/gitlab config `

> 🔴 gitlab-secrets.json 丢了,备份就废了一半。 它保存着数据库里敏感字段的加密密钥,恢复时必须同时提供原来的 gitlab-secrets.json,否则 CI 变量、Runner 令牌等加密数据全部解不开。所以两样一起备份:数据备份 + config 目录。

恢复时的顺序(在全新机器上):

`bash docker exec -t gitlab gitlab-ctl stop puma docker exec -t gitlab gitlab-ctl stop sidekiq docker exec -t gitlab gitlab-backup restore BACKUP=你的备份文件名去掉_gitlab_backup.tar docker exec -t gitlab gitlab-ctl reconfigure docker exec -t gitlab gitlab-ctl restart `

再加一层异地保险:把 /srv/gitlab 下的备份和 config 每天 rsync 到另一台机器或对象存储。本站有 MinIO 自建对象存储教程数据备份与容灾恢复教程,可以直接照搬一套自动备份链路。

第十三步:安全加固清单

台面上的 GitLab 一旦暴露在公网,就是自动化扫描的重点目标。下面六条是上线前必须做的:

1. 强制 HTTPS + 关闭 HTTP。gitlab.rb 里用第四节的方案 A 配置好证书后,HTTP 会自动 301 跳转到 HTTPS。

2. 全站开启两步验证(2FA)。Admin Area → Settings → General → Sign-in restrictions 里可以强制所有用户必须开启 2FA,这一条能挡掉绝大多数撞库攻击。

3. 关闭公开项目与片段。Admin Area → Settings → General → Visibility and access controls 里,把默认项目可见性设为 Private、限制 Public 项目、关闭公开的 Snippets,避免敏感信息被搜索引擎收录。

4. 用 fail2ban 封禁暴力破解。 在服务器上安装 fail2ban,并针对 GitLab 的 Nginx 访问日志配一个 jail,监控登录失败并自动封 IP。因为 GitLab 跑在容器里,公网访问日志落盘在宿主机 /srv/gitlab/logs/nginx/gitlab_access.log,jail 的日志路径要指向它。

5. 限制 Runner 的攻击面。 上一节提到的特权模式只在必要时开;Runner 令牌属于高敏感凭据,泄露等于给了对方在构建机上执行命令的能力,发现泄露要立即在界面里吊销并重新注册。

6. 定期升级。 自建平台最常见的失守原因不是配置错误,而是版本长期不更新。GitLab 的升级有明确路径(不能跨大版本跳),官方建议按 当前版本 → 最新小版本 → 下一个大版本 逐级升;升级前必须做一次完整备份(见第十二步),这样才能在升级失败时回滚。

> 💡 想把这些加固一次做全,可以参考本站的 网站安全加固完整教程,里面 fail2ban + WAF + 安全响应头的做法同样适用于 GitLab 主机。

七、常见问题 FAQ

Q1:2核4G 的服务器能跑得动 GitLab 吗?会不会很卡?

能跑,但要接受两个前提:第一,按第十一步关掉 Prometheus/Grafana 等内置监控并把 Puma worker 降到 2,否则 4GB 内存会在启动阶段就被吃掉大半;第二,加至少 4GB swap,否则一有构建任务就可能被 OOM Killer 杀掉。在这个配置下,2~5 人推代码、跑轻量 CI 是可行的,但别指望流畅;如果团队超过 5 人或构建较频繁,直接上 4核8G,这是官方推荐档,也是最省心的分界线。

Q2:我的 80/443 端口已经被别的网站占用了,GitLab 还能装吗?

能。两种做法:做法一(推荐),把 compose 里的端口映射改成 '8080:80''8443:443',让 GitLab 跑在非标准端口上,再用外部 Nginx 反代到 127.0.0.1:8080(就是第四节的方案 B)。做法二,如果 GitLab 用了自带 Nginx 且你想要标准端口,就需要把原来占用 80/443 的服务挪走或改端口。关键原则:同一台机器的 80 端口只能有一个进程监听,别想着两个 Web 服务抢同一个端口。

Q3:初始 root 密码在哪?取的时候提示文件不存在怎么办?

密码在容器内 /etc/gitlab/initial_root_password,用 docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password 取。如果提示文件不存在,通常是因为首次 reconfigure 已超过 24 小时,文件被自动删除了。 这时直接用第四节的 gitlab-rails runner 命令重置即可,不需要重装。注意重置密码后建议把容器内的这个文件也手动删掉,避免密码明文长期留在磁盘上。

Q4:流水线一直显示 pending(挂起),永远不动,是什么原因?

99% 是"没有可用的 Runner"或"Runner 不匹配这个 job"。 排查顺序:① 到 Settings → CI/CD → Runners 看有没有绿色在线的 Runner,灰色说明 Runner 掉线了,用 docker logs gitlab-runner 看原因;② 看 Runner 有没有勾选 "Run untagged jobs"——你的 job 如果没写 tags,而 Runner 又只接受带标签的 job,就会一直 pending;③ 检查 Runner 的网络能否访问到 GitLab 的 external_url(自建时最容易出问题的是域名解析和证书)。记住:pending 不是"在排队等待",绝大多数情况是"根本没人在接单"。

Q5:GitLab 内存占用一直下不来,还有什么优化手段?

除了第十一步的关监控 + 降 Puma worker,还有几招:① 把 Runner 拆到另一台机器,构建进程是内存大户,拆走后 Web 端会明显轻松;② 限制流水线产物留存,用 expire_in 控制 artifacts 过期,并定期清理旧的 Pipeline;③ 关掉用不上的功能,比如 Registry、Pages、Mattermost(如果没在用);④ 检查是否有大量历史容器docker system prune 能回收不少磁盘;⑤ 如果内存还是长期高位,说明是规模问题不是配置问题,该升级配置就升级,别硬撑。

Q6:GitLab 和 Gitea 到底该怎么选?

一句话:要 CI/CD 和代码审查就选 GitLab,只想有个轻量私有仓库就选 Gitea。 Gitea 是 Go 写的单二进制,1核1G 就能跑得飞快,但它的 CI/CD 需要另配 Drone/Woodpecker,代码审查、镜像仓库这些能力也偏简。GitLab CE 功能完整、生态成熟,但资源要求高一个量级(4核8G 起)。本站另有一篇 Gitea 自建 Git 服务器完整教程,如果你发现自己并不需要流水线,那篇更省钱。

Q7:备份到底要备哪些?恢复时最常踩的坑是什么?

两样一起备:应用数据(gitlab-backup create)+ 配置目录(含 gitlab.rbgitlab-secrets.json)。 最大的坑就是只备了数据备份、没备 gitlab-secrets.json——它是数据库加密密钥,恢复时必须配套,否则 CI 变量、Runner 令牌等加密字段全部解不开,等于数据只恢复了一半。第二个坑是恢复版本必须与备份版本一致:跨大版本直接恢复会失败,正确做法是先装成与备份相同的版本、恢复、再按官方路径逐级升级。

Q8:GitLab 的邮件通知(注册确认、流水线失败)发不出去,怎么排查?

按这个顺序查:① gitlab.rb 里 SMTP 配了没有(没配的话默认发不出任何邮件);② 用 docker exec -it gitlab gitlab-rails console 进去手动测一封,看报错;③ 云厂商默认封锁 25 端口,绝大多数海外 VPS 都封 25,必须改用 465(SSL)或 587(STARTTLS)端口,这是最常见的原因;④ 发件域名要配 SPF/DKIM,否则邮件会进垃圾箱。本站的 自建邮箱服务器教程 里有 SMTP 发信与 SPF/DKIM 的完整配置。

八、总结

用海外云服务器搭建 GitLab CE,整条链路其实就是十三步:系统初始化并把端口收敛好、装 Docker、规划三个持久化目录、写 compose 拉起 GitLab、等首次初始化完成、取初始密码登录并改密、关掉公开注册、配置自动 HTTPS、部署并注册 Runner、写第一条 .gitlab-ci.yml、压内存、做备份、最后按清单加固。一台 4核8G 的海外 VPS、月费几十美元,你就拥有一套不限 CI 分钟数、源码完全自主的研发协作平台。

真正决定成败的是三个细节,而不是命令本身:第一,三个数据卷必须挂——不挂卷等于把仓库放在临时抽屉里,容器一重建全没了;第二,备份必须"数据 + config 密钥"两件套一起备,只备一半等于没备;第三,Runner 的令牌和部署私钥一律走 CI/CD Variables 并勾选 Masked,写进流水线文件等于把钥匙贴在门上。这三条踩了任何一条,都不是多花点钱能补回来的。

最后回到一个诚实的边界:本文部署的是单机单实例 GitLab,它给你的是数据主权和 CI/CD 自由度,不等于高可用——服务器一挂,仓库和流水线一起停。所以备份与异地容灾不是可选项。如果你要的是多节点高可用、企业级 SSO 与合规审计,那是另一个量级的工程(可参考站7 的企业级进阶系列)。把这台单机 GitLab 的边界和它该配的备份说清楚,是这篇文章最想留下的一句话。

延伸阅读: - Gitea 自建 Git 服务器完整教程:轻量代码托管首选 - Coolify 一键部署平台完整教程:自建 Vercel/Netlify/Heroku 替代 - Docker + Portainer 容器管理平台搭建完整教程 - Nginx 反向代理 + Let's Encrypt 免费 SSL 证书配置完整教程 - 数据备份与容灾恢复完整教程:快照 + 异地备份 + 恢复演练 - 网站安全加固完整教程:fail2ban + ModSecurity + 安全响应头

> 本文由 5.chengzicloud.cloud 提供,点击访问首页了解更多海外云服务器部署方案和专属优惠。