ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker部署Gitea教程:轻量级私有代码托管平台搭建与维护

2026/10/8 14:44:55 拓冰建站 浏览量
Docker部署Gitea教程:轻量级私有代码托管平台搭建与维护 最近给团队内部搭了一套代码托管平台用的就是 Docker 部署 Gitea。这事其实立项挺快因为大家早就被 GitHub 私有仓库的成员数限制和 GitLab 的资源占用搞得有点烦。用 Docker 装 Gitea一套下来顺手得就像装个普通 Web 应用资源占用低、管理方便后来陆陆续续帮几个朋友也部署过踩过的坑基本都摸清了。这篇就把从环境准备到日常维护的完整过程拆开讲清楚顺带把新手最容易卡住的几个问题一次说透。Gitea 是一个开源的轻量级代码托管方案GitHub、GitLab 能做的核心事情它基本都能做代码仓库托管、Issue 跟踪、Pull Request、Webhook、CI/CD 对接这些通通都有。Docker 又是现在部署服务最普遍的方式把它俩结合一台 1 核 2G 的机器就能带起一个小团队的日常开发。这篇文章适合谁看想在公司内网搭私有代码仓库的运维/后端同学想搞个人代码备份库的独立开发者还有那些被 GitLab 内存占用逼疯、正在找替代方案的朋友。不管你是第一次碰 Docker 还是已经玩了很久这篇都值得你花几分钟过一遍。1. 为什么选 Gitea Docker而不是其他方案1.1 相比于 GitLab 和 GiteeGitea 的差异在哪先聊选型。市面上自建代码仓库无外乎 GitLab、Gitea、Gogs 这几个再加上直接用 Gitee/GitHub 托管。我的结论很明确中小型团队自建选 Gitea要极致的轻量选 Gogs公司合规性要求高或者需要重度 CI/CD 集成选 GitLab至于 Gitee/GitHub私有仓库不是不好用而是仓库数量、成员数、大小限制多了以后非常难受代码资产也不在自己手里。Gitea 是用 Go 写的单二进制文件就能跑内存占用在 Docker 容器里通常在 200MB 到 500MB 之间。对比一下GitLab 官方推荐的机器配置是 4 核 4G 起步实际跑起来 8G 都不算宽裕。同样是自建Gitea 的资源需求只有 GitLab 的十分之一。功能上我之前专门列过一张对比表维度GiteaGitLab CE直接用 Gitee/GitHub内存占用Docker300MB 左右2GB 起步不需要代码托管核心能力完整完整完整CI/CD 集成有可对接 Drone/Jenkins内置强大 CI平台自带但有限制私有仓库无数量限制无数量限制付费或限量安装复杂度极简较复杂零部署代码资产归属自己手里自己手里第三方平台所以如果你的团队规模在几十人以内对 CI/CD 的需求可以接受外挂 Jenkins、Drone 这类工具Gitea 几乎就是最优解。我就是看重这一点才最终敲定用它。1.2 Docker 部署带来的实际收益为什么偏要用 Docker 装而不是直接下载二进制包跑我也干过裸机部署。两种方式各有利弊但 Docker 的优势在实际维护中很快体现出来。先说隔离性。Gitea 需要 SQLite 或 MySQL/PostgreSQL 做存储如果你直接装在宿主机上就得自己维护一套数据库环境。装了 Redis 可能还会想给 Gitea 的缓存用这些东西一旦在宿主机上铺开以后每次系统升级、依赖冲突都够你喝一壶。用 Docker 以后Gitea 和数据库各自跑在容器里宿主机只需要装一个 Docker其他东西一概不用管。哪天不想要了docker compose down 然后删掉数据目录系统恢复洁净这点非常香。再说可迁移性。Docker 容器可以把配置、数据卷直接打包迁到另一台机器只要把 Gitea 数据目录和 docker-compose.yml 拷过去新机器直接 docker compose up -d 就能恢复服务。我后来帮朋友把服务从一台腾讯云迁移到阿里云整个流程半小时搞定换作裸机安装数据库导来导去SSH 端口、systemd 脚本全部要重配一小时打底。还有版本升级。Gitea 大概一个月发一个小版本Docker 部署升级就是两条命令docker compose pull docker compose up -d容器自动重建。裸机升级得下载新二进制、备份旧文件、改 systemd 脚本一不留神还会把数据目录搞乱。用久了你会觉得Docker 这东西不是可选项是必选项。2. 环境准备Docker 装好且能跑起来后面才不踩坑2.1 Linux 下安装 DockerUbuntu 和 CentOS 都给你过一遍Gitea 部署在 Linux 服务器上是绝对主流。Ubuntu/Debian 系我一般建议用官方脚本命令是curl -fsSL https://get.docker.com | sh装完以后启动服务并设置开机自启systemctl enable --now dockerCentOS 7 和 CentOS 8 有些旧版本的内核和 Docker 存在兼容问题CentOS 7 尤其要注意。如果遇到 docker 服务启动失败先检查内核版本是不是 3.10。很多教程直接让用官方脚本但 CentOS 7 官方脚本装出来的 Docker 版本可能和系统旧内核不匹配建议先更新内核或者用 docker-ce.repo 安装yum install -y yum-utils yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo yum install -y docker-ce docker-ce-cli containerd.io systemctl start docker systemctl enable docker内核太旧的问题在 CentOS 7 上特别典型装完 docker 以后运行 docker info 如果提示 kernel version 或者 iptables 相关的错误多半就是内核版本导致的。如果公司服务器不允许随便升内核我建议直接上 Docker 20.10 版本配合 CentOS 7 的 3.10 内核勉强能跑但稳定性打折扣能升还是升。2.2 Windows/Mac 上的 Docker Desktop 注意事项本地开发调试用 Windows 或 Mac 的同学一般会装 Docker Desktop。这个工具本身做得不错但启动失败是最常见的问题错误提示经常是Docker Desktop failed to start because virtualisation support wasnt detected。这问题说白了就是虚拟化没打开。Windows 上你需要开机进 BIOS 开启 Intel VT-x 或 AMD-V启用 Windows 的 Hyper-V 和“适用于 Linux 的 Windows 子系统”功能确保没有把 Hyper-V 和第三方虚拟机软件弄冲突我自己实测过VMware 和 Docker Desktop 一起用的时候Hyper-V 冲突的概率非常高两个都想要就得用 WSL2 模式跑 Docker。在 Docker Desktop 设置里勾选 Use the WSL 2 based engine然后装一个 WSL2 内核更新包这个方法在 Win10 和 Win11 上都稳定。Mac 上问题少一些主要是 Intel 芯片的老机器开启虚拟化后 Docker Desktop 会吃不少内存建议在 Settings - Resources 里把内存配额调到 4GB 以上不然跑 Gitea MySQL 容易卡。2.3 装完 Docker 必做的三件小事Docker 装好只是开始有三件事我强烈建议你立刻做掉不然后面大概率要返工。第一件事配置 Docker 镜像加速。原因很简单默认拉取 Docker Hub 镜像的速度在国内环境下经常慢到让人怀疑人生Gitea 的镜像倒不算大但 MySQL 镜像、后续想装的 Runner 镜像都挺大的不配加速就是给自己找罪受。各云厂商的控制台里一般都能找到专属加速地址Docker 配置文件 /etc/docker/daemon.json 里加上 registry-mirrors 一项重启 docker 服务即可。这一步对部署体验的提升非常明显几乎是必做项。第二件事把当前用户加入 docker 组从而避免每次执行 docker 命令都要 sudosudo usermod -aG docker $USER newgrp docker我自己遇到过很多次 permission denied while trying to connect to the docker api 这个报错用户不在 docker 组里是最常见原因加了组以后问题立刻消失比去改 socket 权限省心得多。第三件事规划好端口占用。Gitea 默认要用 3000 端口做 HTTP22 端口做 SSH。但服务器上 22 一般已经给系统 SSH 占用了Gitea 的 SSH 端口肯定要改。我建议提前想好端口规划比如 HTTP 用 3000SSH 用 2222避免装到一半发现冲突再做迁移。顺便说一句docker 装 mysql 失败、装其他容器端口映射报错这些八成都是端口占用和防火墙没放行的问题跟 docker 本身关系不大。3. Gitea 容器化安装全流程从拉镜像到仓库可用3.1 目录规划数据、配置、日志分离是首要原则在动手 docker run 之前先想好目录布局。Gitea 的官方镜像把数据放在 /data 目录下里面又分了 git 仓库存储、数据库文件、配置目录和日志。我建议把整个 /data 挂载到宿主机的一个独立目录。也就是说容器内部的数据目录和宿主机目录一一对应。我常用的目录规划长这样mkdir -p /srv/gitea cd /srv/gitea然后整个 Gitea 的数据都存放在 /srv/gitea 下后续备份只需要打包这一个目录极其清爽。有些教程喜欢把 config、data、logs 分开挂多个卷原则上没问题但备份时要挂多个目录打包还要处理文件权限差异反而更麻烦。对于 Gitea 这个体量的应用单一数据目录是最顺手的选择。3.2 使用 docker-compose.yml 定义服务而不是一串 docker run我强烈建议使用 docker-compose而不是敲一长串 docker run 参数。原因很简单——可读性强、易于版本管理、服务依赖关系明确。下面给出一个我实际在用的 docker-compose.yml数据库选的 PostgreSQLWeb 端口映射的 3000SSH 端口映射的 2222version: 3 services: gitea: image: gitea/gitea:latest container_name: gitea environment: - USER_UID1000 - USER_GID1000 - GITEA__database__DB_TYPEpostgres - GITEA__database__HOSTdb:5432 - GITEA__database__NAMEgitea - GITEA__database__USERgitea - GITEA__database__PASSWDgitea123 restart: always volumes: - /srv/gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - 3000:3000 - 2222:22 depends_on: - db db: image: postgres:16 container_name: gitea-db environment: - POSTGRES_USERgitea - POSTGRES_PASSWORDgitea123 - POSTGRES_DBgitea restart: always volumes: - /srv/gitea-db:/var/lib/postgresql/data看到这里你可能会发现一个关键点Gitea 容器映射的是容器内部的 22 端口到宿主机的 2222 端口而不是直接映射宿主机的 22。这样做的好处非常明显——你系统的 sshd 继续占用 22Gitea 的 SSH 功能走 2222两边互不干扰。关于数据库选择官方支持 SQLite、MySQL、PostgreSQL。SQLite 适合个人使用或仓库数量很少的场景零维护团队多人并发写或者仓库数量上来了建议直接用 PostgreSQL。MySQL 也能用但我个人遇到过一次 Gitea MySQL 的字符集配置问题折腾了半小时换成 PostgreSQL 后世界清净了。小团队选 PostgreSQL 是稳妥路线。3.3 启动容器并完成初始化配置配置文件写好后启动服务docker compose up -d首次启动会自动拉取 gitea/gitea 和 postgres 镜像。然后访问 http://服务器IP:3000 就能看到 Gitea 的安装引导页面。安装页面有几个字段需要仔细填数据库设置数据库类型选 PostgreSQL主机地址填 db:5432这里 db 是 docker-compose 里定义的服务名在容器网络内部可以直接用服务名互相访问。如果你填 localhost 或者 127.0.0.1容器内部解析到的是 gitea 容器自己而不是数据库容器会连接失败。这是新手最容易踩的坑。站点名称和基础 URL站点名称随意基础 URL 建议直接填将来对外访问的域名比如 http://git.example.com如果暂时没有域名先填 http://IP:3000后面也可以在配置文件里改。SSH 服务器端口这里要填 2222因为 Gitea 容器内 SSH 监听的是 22映射到宿主机是 2222所以给用户展示的克隆地址里 SSH 端口应该是 2222。服务器域名的配置同理。页面填完点击安装几秒钟后就会跳到登录页。用第一个管理员账号登录后台就能正常使用了。3.4 给 Gitea 配置域名和反向代理HTTPS 可选但推荐如果只是内网 IP 访问到 3.3 步已经够用。但如果想用域名访问、想上 HTTPS就需要在前面加一层 Nginx 反向代理。我一般是在宿主机装一个 Nginx或者再用一个 Docker 起 nginx-proxy然后配置 server 块代理到 3000 端口。一个实际可用的 Nginx 配置片段server { listen 80; server_name git.example.com; client_max_body_size 512m; location / { proxy_pass http://127.0.0.1:3000; 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; } }关键点有两个。一是 client_max_body_size 一定要调大不然推送大文件或者 LFS 时会直接 413默认 1m 肯定不够用。二是要配置 X-Forwarded-Proto 等头Gitea 会用这个判断请求协议否则即使 HTTPS 反代了Gitea 页面里生成的克隆地址仍然会是 http导致克隆报错。HTTPS 证书我一般直接用 ACME 自动申请配上自动续期后基本可以做到一劳永逸。这个环节属于锦上添花但对体验提升是质变级的。4. 安装完成后的配置与日常维护4.1 管理员账号、组织和权限模型Gitea 第一次启动时创建的第一个账号会变成管理员。但我建议你在安装页面先创建一个普通管理员账号后面再按需创建普通成员而不是所有人都混在一个大账号里。具体规划时我通常这样做创建一个组织命名为 team-name团队名组织下建项目仓库按项目维度建私有仓库给成员分角色Owner、Collaborator、Read 等Gitea 的权限模型没有 GitLab 那么细但在中小团队里足够用了。有一点要说清楚Gitea 的仓库阅读权限是私有仓库默认只有显式添加的成员能看这一点比 GitHub 的免费版要友好得多——GitHub 免费版私有仓库其实也可以邀请协作者但 Gitea 完全无限制这一点对自建场景来说太关键了。我实际使用中都会在设置里开启“注册邀请制”让普通用户不能自己注册只能由管理员添加。毕竟自建仓库面向的是团队内部放开注册等于向全网开放了一个可能存在敏感代码的入口这一条务必注意。4.2 备份与恢复策略把整个数据目录打包Docker 部署最大的优势之一是备份非常简单。Gitea 的全部数据包含配置、仓库、数据库、SSH 密钥、LFS 文件都存放在挂载的 /data 目录下。结合 PostgreSQL 的数据卷 /srv/gitea-db我把备份策略定为每天凌晨用 cron 执行备份脚本用 tar 压缩 /srv/gitea 和 /srv/gitea-db 两个目录压缩包保留最近 7 天有条件的话异地备份或对象存储同步一个简单的备份脚本长这样#!/bin/bash BACKUP_DIR/backup/gitea DATE$(date %Y%m%d%H%M) mkdir -p $BACKUP_DIR tar czf $BACKUP_DIR/gitea-$DATE.tar.gz /srv/gitea tar czf $BACKUP_DIR/gitea-db-$DATE.tar.gz /srv/gitea-db find $BACKUP_DIR -name *.tar.gz -mtime 7 -delete有人可能会问直接用 docker compose down 再打包会不会更好理论上数据库文件在服务运行中打包可能出现不一致但 PostgreSQL 的 WAL 机制会让文件即使在运行中也处于相对安全的状态。保守起见备份前先执行 docker compose exec db pg_dump 导出一份 SQL双保险。恢复流程就是把压缩包解压回原目录然后 docker compose up -d数据直接回来非常省事。这套方案我实测恢复过两次一次是误删仓库一次是机房迁移都是半小时内搞定。4.3 给 Gitea 加 CI/CD 能力Drone 或 Gitea ActionsGitea 本身不附带 CI 功能但可以非常优雅地集成外部 CI。两个主流路线一是 Drone CI用 docker-compose 一把梭Drone 服务 Runner 一个容器搞定跟 Gitea 的集成非常顺滑。二是 Gitea Actions这个和 GitHub Actions 的语法几乎一致1.19 版本之后内置支持配置 .gitea/workflows/*.yml 就能跑。对于熟悉 GitHub Actions 的人来说上手几乎零成本。我用的是 Gitea Actions原因很简单少一个外部服务跟 GitHub 生态无缝衔接。在仓库里建一个 .gitea/workflows/build.yml用 Go 项目举个例子name: build on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - uses: actions/setup-gov4 with: go-version: 1.21 - run: go buildRunner 在宿主机上起一个 Docker 容器就能用配置也简单。这个能力加上以后整个代码仓库才真正变成完整的 DevOps 基础设施。这里不是必须但值得一试。4.4 升级 Gitea 到新版注意数据备份放第一Gitea 的小版本更新很频繁。Docker 部署升级就是两行命令docker compose pull docker compose up -d但升级前务必先备份尤其是跨大版本升级比如从 1.x 升到 2.x数据库结构可能有变更回滚起来没那么简单。我的习惯是先备份再升级然后检查首页、仓库列表、Issue、PR 这些核心功能是否正常。如果发现异常立刻 docker compose down恢复备份再排查原因避免在坏数据上继续操作。Gitea 官方文档也建议升级前先查看 release notes这个习惯值得养成。另外注意一点gitea/gitea:latest 标签虽然方便但升级的确定性就差一些。生产环境我更推荐固定版本号比如用的 gitea/gitea:1.21.5每次升级都是显式改标签可控性高很多。这个思路和 docker 部署其他服务也一致固定版本号永远是更稳的选择。5. 常见问题排查实录踩过的坑全在这里5.1 permission denied while trying to connect to the docker api这个报错基本可以判定是权限问题最常见的就是用户不在 docker 组里。我排查顺序如下groups $USER如果输出里没有 docker那就执行 usermod 加入组。如果已经在组里还报错大概率是 shell 会话没有刷新组信息登出重进或者用 newgrp docker 就能解决。另一种情况是 Docker 服务本身没起来。用 systemctl status docker 查看如果服务是 dead 状态journalctl -u docker 看日志。我遇到过好几次 Docker 服务启动失败都是因为防火墙规则或者 iptables 配置被改过导致 docker 无法初始化网络。解决办法是先停掉 firewalld 再启动 docker成功后再把 firewalld 拉起来观察 docker network 是否正常创建。如果你用 Ubuntuufw status 也需要确认没挡掉 docker 的网段。5.2 镜像下载慢或直接超时这个放在 docker 部署的任何服务上都是第一痛点。Gitea 镜像本身七十多兆PostgreSQL 镜像两百多兆在网速不给力的环境里光拉镜像就能耗掉你二十分钟。除了配镜像加速我还有一个经验是——不要在高峰期拉镜像尽量在低峰期或首次部署前就把镜像 pull 好。比如docker pull gitea/gitea:latest docker pull postgres:16提前拉好后面 docker compose up -d 就会非常快。如果已经配了加速还是慢试试用 docker pull 指定 tag比如具体的小版本号有些时候 latest 标签体积反而比指定版本大。再有一个骚操作是给 registry 配置 HTTP/HTTPS 代理但大多数场景下镜像加速就够用了。5.3 容器网络不通连不上数据库这个问题我在 3.3 节已经提过主机地址写 localhost 导致连不上数据库。在 docker-compose 网络里容器之间互相访问必须用服务名而不是 localhost。检查方法很简单docker exec -it gitea bash ping db如果 ping 不通说明 gitea 容器和 db 容器不在同一个网络里。docker compose 默认会创建一个项目名命名的网络只要两个服务都定义在同一个 compose 文件里默认就在一个网络下。如果你手贱加了 network_mode: host 或者其他自定义网络配置这个错误就会冒出来写完 compose 文件后记得 docker compose config 检查一下。访问宿主机上的数据库是另一种场景。比如你想让 Gitea 连接宿主机上已经跑着的 MySQL而不用起容器数据库那 Gitea 容器里访问宿主机就不能用 127.0.0.1而要用 host.docker.internalMac/Windows或者宿主机的内网 IPLinux。有次我图省事直接在 compose 里写了 127.0.0.1:3306结果 Gitea 一直报连接拒绝排查了十几分钟才反应过来。把 host 改成宿主机内网 IP 后立刻恢复。5.4 端口冲突尤其是 3000 和 sshGitea 的 Web 端口 3000 和系统的 sshd 端口 22 都是高占用端口。如果 3000 被别的服务占了docker compose up 会直接报 bind: address already in use。处理方式要么改 Gitea 的宿主机映射端口比如 3000 改成 13000要么找出占用进程干掉它。但我一般不会去杀进程因为那个进程可能也是个重要服务。我的建议是Gitea 的映射端口调整到不冲突的端口比如 3000 和 2222这两个端口在大多数服务器上不太容易被占用。如果你想要严谨一点改完端口后记得改防火墙放行规则。5.5 容器重启后数据丢失这个坑可以说是新手最容易犯的。比如 docker run 的时候忘了挂数据卷或者 compose 文件里写错了 volumes容器一删数据全没了。我在第一台测试机上就吃过这个亏当时图方便直接 docker run 没挂卷后来想升级版本容器一删仓库数据全没了。万幸是测试机没有正式数据从那以后凡是涉及有状态服务我第一件事就是把 volumes 写好先想清楚数据放哪再考虑怎么跑起来。还有一点Gitea 容器里的 /data 目录是整个应用的根数据目录如果你把 /data 挂载到了宿主机目录那么配置文件、仓库存储、LFS 文件全都在里面。恢复时只用恢复这个目录即可。另外如果遇到容器启动了但 Gitea 无法打开网页大概率是挂载目录权限不对容器内进程以 uid 1000 运行宿主机目录的所有者也要对应调整为 1000 权限。5.6 Docker Desktop 的 Windows 特有问题Windows 上启动 Docker Desktop 失败十有八九就是虚拟化没开。排查路径任务管理器 - 性能 - CPU看虚拟化是否显示“已启用”如果没启用进 BIOS 把 Intel VT-x / AMD-V 打开如果 BIOS 已经打开仍然检测不到多半是 Hyper-V 功能没启用Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-All装完 Hyper-V 后重启再试 Docker Desktop。再加上 WSL2 内核更新这套组合拳基本能解决 90% 的 Windows Docker 启动问题。如果还不行去事件查看器看 Docker 服务相关的错误日志会比到处搜教程高效得多。6. 实战后的几点体会整套部署流程讲完最后分享一些我的个人体会。Gitea Docker 这套组合对我来说是那种“没有惊艳但用起来非常踏实”的东西。它不像 GitLab 那样功能多到让人焦虑也不像 Gitee 那样时不时冒出条款限制。它就像你办公室角落里的饮水机平时不怎么注意但每个人都离不开。对于个人开发者一个 Docker 容器就把代码仓库放在自己的服务器上配合自动备份脚本整个代码资产的管理效率比散落在网盘里高出不止一个数量级。我在实际部署中发现最有价值的一件事不是安装本身而是把 Gitea 的备份和升级流程跑顺这决定了这个系统能不能长期稳定用下去。很多人装完就丢在一边出了事故才想起来根本没备份。建议你把备份脚本写进 cron 的第一天就做掉别等丢了再说。最后分享一个小技巧Gitea 的配置文件在 /data/gitea/conf/app.ini。装完以后如果不小心把端口、域名填错了不用重新跑安装流程直接改这个文件然后 docker compose restart gitea 就能生效。Linux 环境下用起来非常顺手。这套东西的扩展空间也很大。前文提到的 Gitea Actions、Drone CI、镜像仓库集成甚至配合一些自动化脚本做依赖管理、版本发布都可以逐步加进来。先把 Gitea 跑起来让代码进仓库后续的 DevOps 能力都建立在“有个稳定可控的代码仓库”这个基础之上。如果你正在为代码管理的事犯愁照着这篇装一套大概率能帮你省下不少事。