1. 为什么你需要一个自己的私有Git仓库?

如果你写过代码,那你肯定用过Git。GitHub、GitLab这些平台大家都很熟悉,但它们都是“别人家”的。你有没有想过,自己动手搭一个完全属于自己、或者属于小团队的代码仓库?这听起来可能有点技术门槛,但今天我要告诉你,用Docker-Compose来部署Gitea,这件事简单得就像搭积木。

我自己最早也是把代码一股脑全扔在GitHub上。后来遇到几个挺实际的问题:有时候网络连接不稳定,提交个代码要等半天;有些项目涉及一些内部工具或者未成形的想法,暂时不想公开,但GitHub的私有仓库名额有限(虽然现在免费了,但早期可不是这样)。更重要的是,当你和几个小伙伴一起捣鼓一个项目,需要一个私密、稳定、完全可控的协作空间时,一个自建的私有仓库就成了刚需。

市面上能自建的开源Git服务不少,最出名的是GitLab。它功能确实强大,CI/CD、项目管理一套全齐,但它是典型的“重量级选手”。官方推荐的最低配置就要4核4G内存,对个人开发者或者小团队来说,为了一个代码仓库占用这么多资源,实在有点“杀鸡用牛刀”。而且它的界面和配置相对复杂,维护起来也需要不少精力。

这时候,轻量级的替代品就进入了视野,主要是Gogs和Gitea。它们俩都源自同一个想法:做一个足够用、又极其轻便的Git服务。Gogs出现得更早,以极简和易部署著称。而Gitea是从Gogs项目分叉(Fork)出来的,社区更活跃,发展更快,在功能迭代和安全性更新上更有优势。简单来说,你可以把Gitea看作是Gogs的一个更活跃、功能更现代的“社区增强版”。它用Go语言编写,打包成一个独立的二进制文件,对系统资源消耗极小,在树莓派上都能流畅运行,这正好切中了我们个人开发者“资源敏感”的痛点。

所以,当你需要的是一个私密、可控、部署简单、不吃资源的代码托管服务时,Gitea配合Docker-Compose,就成了一个近乎完美的解决方案。接下来,我就带你一步步亲手把它搭起来。

2. 部署前,你需要准备好这些“食材”

在开始“烹饪”我们的私有Git服务大餐之前,得先把厨房和食材准备好。整个过程其实就依赖两样核心工具:Docker和Docker-Compose。别被名字吓到,你可以把它们理解为一个超级高效的“应用打包和运行工具箱”。

Docker 就像是集装箱。以前运输货物,东西形状大小不一,装卸起来非常麻烦。集装箱出现后,把所有货物都打包进标准箱里,船、火车、卡车都只负责运输集装箱,效率大大提升。Docker做的也是类似的事,它把应用程序和它需要的所有环境(比如特定的系统库、依赖软件)一起打包成一个“镜像”。这个镜像在任何安装了Docker的机器上,都能以完全一致的方式运行起来,彻底解决了“在我电脑上好好的,怎么到你那就挂了”的千古难题。

Docker-Compose 则是管理多个集装箱的吊车和编排图。我们的Gitea服务不仅仅需要Gitea本身这个“集装箱”,还需要一个数据库(比如PostgreSQL)作为另一个“集装箱”来存储用户、仓库等数据。Docker-Compose允许我们用一个简单的配置文件(docker-compose.yml),一次性定义好这两个“集装箱”怎么启动、怎么连接、数据存哪里。之后一条命令,就能让整个服务栈井然有序地跑起来。

对于你的服务器环境,要求非常低:

  • 操作系统:任何主流的Linux发行版(如Ubuntu、CentOS、Debian)都可以,macOS和Windows也行,但生产环境建议用Linux。
  • 内存:1GB RAM就足以流畅运行,512MB也能启动,但体验会打折扣。
  • CPU:1核就够用。
  • 磁盘空间:至少预留10GB,用于存放Docker镜像、Gitea代码仓库和数据库数据。

我强烈建议你使用一台干净的Linux服务器(可以是云服务器,也可以是家里的旧电脑装的Linux),从头开始操作。接下来,我们首先安装Docker和Docker-Compose。

2.1 安装Docker引擎

我们以最常见的Ubuntu系统为例。打开你的终端(SSH连接到你的服务器),执行下面的命令。

首先,更新系统软件包列表并安装一些必要的工具:

sudo apt update
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common

然后,添加Docker的官方GPG密钥和软件源:

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

再次更新,并安装Docker引擎:

sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io

安装完成后,启动Docker服务并设置开机自启:

sudo systemctl start docker
sudo systemctl enable docker

为了不用每次都输入sudo来执行docker命令(这涉及到用户组权限,是出于安全考虑),我们可以将当前用户加入docker用户组:

sudo usermod -aG docker $USER

注意:执行这条命令后,你需要完全退出当前终端会话(关闭窗口或输入exit命令),然后重新登录,这个改动才会生效。重新登录后,运行docker version命令,如果能看到Client和Server的版本信息,就说明安装成功了。

2.2 安装Docker-Compose

Docker-Compose现在通常作为一个独立的二进制文件提供,安装起来比Docker还简单。我们直接去GitHub下载最新稳定版。

首先,检查一下最新版本的编号。你可以访问 Docker Compose的GitHub发布页 查看,或者用下面的命令获取(以写作时的最新稳定版v2.24.5为例):

sudo curl -L "https://github.com/docker/compose/releases/download/v2.24.5/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

下载完成后,赋予它可执行权限:

sudo chmod +x /usr/local/bin/docker-compose

最后,验证安装是否成功:

docker-compose --version

如果输出了类似 Docker Compose version v2.24.5 的信息,那么恭喜你,所有“厨具”都已备齐。

3. 编写“食谱”:详解Docker-Compose配置文件

食材厨具都齐了,现在我们来写“食谱”,也就是docker-compose.yml文件。这个文件定义了整个Gitea服务栈的蓝图:用什么镜像、怎么配置、数据存哪、网络怎么连。我会逐行解释,让你不仅知其然,更知其所以然。

首先,我们创建一个专属的目录来存放所有相关文件,这样管理起来清晰:

mkdir -p /docker/gitea
cd /docker/gitea

在这个目录下,我们创建三个子目录,分别用于映射容器内的数据、配置和数据库文件。这样做的好处是,即使以后我们删除或重建容器,这些持久化的数据也不会丢失。

mkdir data config postgres

现在,创建并编辑核心的docker-compose.yml文件:

nano docker-compose.yml

(如果你习惯用vim,把nano换成vim即可。)

将以下内容复制进去,我会在关键位置加上注释:

version: "3.8" # 使用较新的Compose文件格式版本,兼容性更好

services:
  # 定义Gitea服务
  server:
    image: gitea/gitea:1.21.4-rootless # 使用rootless镜像,安全性更高
    container_name: gitea-server # 给容器起个名字,方便管理
    environment:
      - USER_UID=1000 # 容器内运行Gitea的用户UID,与宿主机用户对应可避免权限问题
      - USER_GID=1000 # 容器内运行Gitea的用户组GID
      - GITEA__database__DB_TYPE=postgres # 指定数据库类型为PostgreSQL
      - GITEA__database__HOST=db:5432 # 数据库地址,`db`是下面定义的数据库服务名,容器内会自动解析
      - GITEA__database__NAME=gitea # 数据库名称
      - GITEA__database__USER=gitea # 数据库用户名
      - GITEA__database__PASSWD=gitea # 数据库密码(生产环境请务必修改为强密码!)
    restart: unless-stopped # 容器退出时总是重启,除非手动停止
    volumes:
      - ./data:/var/lib/gitea # 将Gitea的数据目录(仓库、附件等)映射到宿主机的`./data`
      - ./config:/etc/gitea # 将Gitea的配置文件目录映射到宿主机的`./config`
      - /etc/timezone:/etc/timezone:ro # 同步宿主机时区,只读
      - /etc/localtime:/etc/localtime:ro # 同步宿主机本地时间,只读
    ports:
      - "3000:3000" # 将容器内的3000端口(Gitea的HTTP端口)映射到宿主机的3000端口
      - "2222:22"   # 将容器内的22端口(SSH端口)映射到宿主机的2222端口。注意容器内是22,映射出来是2222,避免与宿主机SSH冲突。
    depends_on:
      - db # 声明依赖,确保`db`服务先启动
    networks:
      - gitea-network # 将服务接入自定义网络,方便内部通信

  # 定义PostgreSQL数据库服务
  db:
    image: postgres:14-alpine # 使用Alpine版本的PostgreSQL,更轻量
    container_name: gitea-db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=gitea # 数据库超级用户(与上面Gitea配置对应)
      - POSTGRES_PASSWORD=gitea # 数据库超级用户密码(同上,务必修改!)
      - POSTGRES_DB=gitea # 初始创建的数据库名
    volumes:
      - ./postgres:/var/lib/postgresql/data # 将数据库数据文件映射到宿主机的`./postgres`
    networks:
      - gitea-network

# 定义一个自定义的Docker网络,让两个服务在独立的网络空间内通信
networks:
  gitea-network:
    driver: bridge

几个关键点解释和避坑指南:

  1. 镜像标签:我们使用了 :1.21.4-rootless 这个标签。rootless意味着容器内的进程不以root权限运行,提升了安全性。使用固定版本号(如1.21.4)而非latest,可以确保部署的一致性,避免因自动升级导致意外问题。
  2. 端口映射ports部分很重要。3000:3000意味着你通过浏览器访问服务器的3000端口就能打开Gitea网页。2222:22意味着Git的SSH克隆地址端口是2222。例如,如果你的服务器IP是192.168.1.100,那么克隆仓库的地址就是 ssh://git@192.168.1.100:2222/用户名/仓库名.git务必确保宿主机的3000和2222端口没有被其他程序占用
  3. 数据持久化volumes映射是数据的生命线。./data./config./postgres这三个目录就在我们刚才创建的/docker/gitea下面。所有用户代码、配置、数据库信息都保存在这里。定期备份这个/docker/gitea目录,就等于备份了你的整个Gitea服务。
  4. 环境变量:数据库密码等敏感信息直接写在文件里。对于更正式的环境,建议使用Docker的secrets功能或外部环境变量文件来管理。
  5. 权限问题:配置文件里我们通过USER_UIDUSER_GID指定了容器内运行用户的ID。你需要确认宿主机上/docker/gitea/data/docker/gitea/config目录的所属用户和组ID。通常,如果宿主机当前用户的UID是1000,那么直接运行sudo chown -R 1000:1000 /docker/gitea/data /docker/gitea/config来设置所有权。如果启动容器后遇到权限错误,可以查看容器日志 (docker-compose logs server) 来排查。

4. 一键启动与初始化配置

配置文件写好保存后,激动人心的时刻就到了:启动服务。整个过程简单得超乎想象。

确保你的终端当前位于/docker/gitea目录下,然后执行:

docker-compose up -d

这个-d参数代表“detached”,即让服务在后台运行。执行后,你会看到Docker开始拉取giteapostgres镜像,然后创建网络、启动容器。

稍等片刻,使用以下命令查看服务状态:

docker-compose ps

如果看到两个服务的状态都是 Up,那就说明启动成功了。如果状态是 Exit 或者一直在 Restarting,可以用 docker-compose logs(查看所有日志)或 docker-compose logs server(只看Gitea日志)来排查错误,最常见的就是端口冲突或目录权限问题。

启动成功后,打开你的浏览器,访问 http://你的服务器IP地址:3000。比如你的服务器内网IP是192.168.1.100,那就访问 http://192.168.1.100:3000

第一次访问,你会进入Gitea的安装引导页面。因为我们在docker-compose.yml里已经配置了数据库连接信息,所以页面上“数据库设置”部分应该是自动填好的,不需要改动。你需要重点关注的是下面这几项:

  • 站点名称:给你的Git服务起个名字,比如“小明的代码库”或“TeamDev”。
  • 服务器域名:填写你的服务器IP地址,或者你为它准备的域名(例如 git.yourcompany.com)。这里非常重要,它会影响仓库的克隆地址。如果你在内网用IP访问,就填IP(如192.168.1.100);如果有公网IP或域名,就填对应的地址。
  • 基础URL:这个会根据你上面填的“服务器域名”和端口自动生成,格式是 http://服务器域名:3000/。确保它正确无误。
  • 可选设置 - 管理员帐号设置强烈建议在这里设置一个管理员账号和密码。如果不设,第一个注册的普通用户会自动成为管理员。
  • 可选设置 - 电子邮件设置:如果你希望Gitea能发送注册确认、密码重置等邮件,需要在这里配置SMTP服务器信息。对于个人测试或内网使用,可以先跳过。

检查无误后,点击页面最下方的“安装Gitea”按钮。系统会进行初始化,这个过程大概十几秒到一分钟。完成后,页面会自动跳转到Gitea的登录页。

用你刚才设置的管理员账号登录,一个崭新的、完全由你掌控的私有Git服务就出现在眼前了!它的界面和操作逻辑与GitHub、GitLab非常相似,创建仓库、提交代码、发起Pull Request、管理组织,该有的功能一个不少,但运行在你自己的服务器上,数据完全私有。

5. 日常使用与管理进阶技巧

成功登录后,你就可以像使用GitHub一样使用Gitea了。点击右上角的“+”号可以创建新仓库,在仓库页面可以找到HTTP和SSH两种克隆地址。这里我分享几个在实际使用中非常实用的进阶技巧和配置。

5.1 配置SSH克隆(提升体验的关键)

在安装页面,我们把容器的22端口映射到了宿主机的2222端口。这意味着Git over SSH的地址会包含:2222。为了让git clone命令更简洁,我们可以配置本地的SSH客户端。

在你的本地电脑(不是服务器)上,编辑SSH配置文件 ~/.ssh/config(如果没有就创建一个):

Host your-gitea-server # 给服务器起个别名,比如 `mygit`
    HostName 192.168.1.100 # 你的Gitea服务器IP或域名
    Port 2222 # 映射的SSH端口
    User git # Gitea服务的固定SSH用户,永远是`git`

保存后,你就可以用非常简洁的方式克隆仓库了。假设你在Gitea上创建了一个叫 myproject 的仓库,克隆命令将是:

git clone mygit:yourusername/myproject.git

系统会自动使用你配置的HostNamePort,体验上和克隆GitHub仓库 (git clone git@github.com:...) 几乎无差。

5.2 修改Gitea的配置文件

Gitea的所有配置最终都保存在我们之前映射的 config 目录下的 app.ini 文件里。网页管理后台可以修改大部分常用设置,但更深入的定制需要直接编辑这个文件。

例如,你想关闭开放注册,只允许管理员创建用户:

  1. 用编辑器打开服务器上的 /docker/gitea/config/app.ini
  2. 找到 [service] 部分,将 DISABLE_REGISTRATION 的值改为 true
  3. 保存文件,然后回到/docker/gitea目录,重启Gitea服务使配置生效:
    docker-compose restart server
    

再比如,你觉得默认的3000端口不够“专业”,想改用80端口(HTTP默认端口):

  1. 首先,修改 docker-compose.yml 文件中 server 服务的端口映射,将 - "3000:3000" 改为 - "80:3000"注意:在Linux上,使用1024以下的端口(如80)需要root权限,Docker默认可能需要sudo,或者调整Docker守护进程的配置。更常见的做法是先用3000端口,然后用Nginx反向代理到80端口,这样更安全、灵活。
  2. 同时,修改 app.ini[server] 部分的 ROOT_URL,将 :3000 去掉,变成 http://你的域名/
  3. 保存两个文件,然后重启服务:docker-compose down 然后 docker-compose up -d

5.3 数据的备份与迁移

因为你所有的数据(代码仓库、数据库、配置)都保存在宿主机的 /docker/gitea 目录下,所以备份极其简单。

完整备份:直接打包整个目录即可。

tar -czvf gitea-backup-$(date +%Y%m%d).tar.gz /docker/gitea

这个压缩包包含了全部数据。要迁移到新服务器,只需要在新服务器上安装好Docker和Docker-Compose,解压这个包,然后运行 docker-compose up -d,服务就会原样恢复。

Gitea内置备份:Gitea也提供了命令行工具进行热备份,备份文件更小,且可以定时任务。 首先,进入Gitea容器内部:

docker-compose exec server bash

然后在容器内执行备份命令(假设备份到容器内的 /tmp):

su git -c "/usr/local/bin/gitea dump -c /etc/gitea/app.ini --file /tmp/gitea-dump.zip"

退出容器后,将备份文件复制到宿主机:

docker-compose cp server:/tmp/gitea-dump.zip ./

你可以写一个脚本,结合cron定时任务,定期执行这个备份流程,并将备份文件上传到云存储,实现自动化异地备份。

5.4 使用Nginx反向代理并配置HTTPS(让服务更专业)

直接通过IP:3000访问不够美观,也不安全。我们可以用Nginx作为反向代理,并配置SSL证书启用HTTPS。

首先,在宿主机上安装Nginx(假设是Ubuntu):

sudo apt install -y nginx

然后,为你的Gitea服务创建一个Nginx配置文件,例如 /etc/nginx/sites-available/gitea

server {
    listen 80;
    server_name git.yourdomain.com; # 你的域名

    # 将HTTP请求重定向到HTTPS(配置好SSL后启用)
    # return 301 https://$server_name$request_uri;

    location / {
        proxy_pass http://127.0.0.1:3000; # 指向Gitea服务
        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 100M; # 允许上传大文件
    }
}

创建一个符号链接启用该配置,并测试Nginx配置:

sudo ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

现在,你就可以通过 http://git.yourdomain.com 访问Gitea了。

配置HTTPS:强烈建议使用Let‘s Encrypt的免费证书。安装Certbot工具可以自动化完成证书申请和Nginx配置更新,命令类似 sudo certbot --nginx -d git.yourdomain.com。配置完成后,记得将上面Nginx配置中的HTTP重定向注释去掉,并修改Gitea的app.iniROOT_URLhttps://git.yourdomain.com

6. 故障排查与性能优化指南

即使按照步骤操作,也可能会遇到一些小问题。这里汇总几个我踩过的坑和解决方案。

问题一:访问页面显示“502 Bad Gateway”或连接被拒绝。

  • 可能原因1:容器没启动。 运行 docker-compose ps 检查状态。如果是Exit,运行 docker-compose logs server 查看具体错误日志。最常见的是端口冲突,换一个宿主机端口试试。
  • 可能原因2:目录权限错误。 查看日志中是否有“permission denied”字样。确保dataconfig目录的所属用户/组与容器内运行的UID/GID(默认为1000:1000)一致。用 ls -la /docker/gitea 查看,并用 sudo chown -R 1000:1000 /docker/gitea/data /docker/gitea/config 修正。

问题二:能打开页面,但注册或登录时提示数据库错误。

  • 可能原因:数据库服务启动失败或连接配置错误。 运行 docker-compose logs db 查看数据库日志。检查docker-compose.yml中数据库的环境变量(用户名、密码、数据库名)是否与app.ini或安装页面中的配置完全一致。确保depends_on设置正确,给数据库一点初始化时间。

问题三:Git克隆或推送速度慢。

  • 优化方向1:服务器资源。 确保服务器有足够的内存和CPU。对于超过100个仓库或活跃团队,考虑将数据库(PostgreSQL)单独部署到性能更好的机器上。
  • 优化方向2:Gitea配置。 编辑app.ini,在 [repository] 部分可以设置 DISABLE_HTTP_GIT = false 来强制使用HTTP协议进行Git操作(在某些网络环境下可能更快)。但SSH协议通常更安全高效。
  • 优化方向3:启用Gitea的缓存。app.ini中配置 [cache][session] 部分,使用Redis或memcached作为缓存后端,可以显著提升页面加载速度,特别是当用户和仓库数量增多时。这需要额外部署一个Redis容器并在配置中连接它。

问题四:如何升级Gitea版本? 升级非常简单,得益于Docker的封装。

  1. 备份! 执行前面提到的完整备份命令。
  2. 修改 docker-compose.yml 文件中 server 服务的 image 标签,指向新的版本号,例如 gitea/gitea:1.21.5-rootless
  3. /docker/gitea 目录下执行:
    docker-compose pull # 拉取新版本镜像
    docker-compose up -d # 重新创建并启动容器,数据卷会自动挂载
    
  4. 访问Web界面,Gitea通常会提示正在进行数据库迁移,等待其自动完成即可。

整个过程,从准备环境到完成部署,如果网络顺畅,半小时内绝对可以搞定。最关键的是,你收获的不仅仅是一个工具,而是一个完全受控、可定制、能随着你需求成长的开发基础设施。当你的项目代码在这个自己搭建的小天地里顺畅地流转时,那种成就感和掌控感,是使用任何第三方服务都无法替代的。

更多推荐