搭建你的私有 Gitea 部署指南

本指南适用于在 Ubuntu 22.04 服务器上部署 Gitea 服务。整个部署基于 Docker 和 Docker Compose,无需担心 Nginx 配置文件的位置问题,因为我们使用的是容器化部署。

关于 Nginx 配置

在本部署方案中,Nginx 配置文件位于 ./nginx/conf.d/default.conf,通过 Docker 卷挂载映射到容器内的 /etc/nginx/conf.d/default.conf。这与 Ubuntu 系统默认的 Nginx 配置位置 (/etc/nginx/sites-available/default) 无关,因为我们使用的是 Docker 容器内部的 Nginx,不是宿主机上的 Nginx。

项目结构

├── docker-compose.yml        # Docker Compose配置文件
├── nginx/                    # Nginx配置目录
│   ├── conf.d/               # Nginx配置文件
│   │   └── default.conf      # 主配置文件
│   ├── html/                 # 静态HTML文件
│   │   └── index.html        # 欢迎页面
│   ├── logs/                 # 日志目录
│   └── ssl/                  # SSL证书目录(未来使用)
├── gitea-data/               # Gitea数据目录(自动创建)
└── postgres-data/            # PostgreSQL数据目录(自动创建)

部署步骤

1. 准备环境

在 Ubuntu 22.04 服务器上安装 Docker 和 Docker Compose:

# 更新软件包
sudo apt update
sudo apt upgrade -y

# 安装必要的依赖
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release

# 方法一:使用阿里云镜像安装Docker(推荐中国大陆服务器使用)
# 添加阿里云Docker GPG密钥
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -

# 添加阿里云Docker仓库
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"

# 更新软件包索引
sudo apt update

# 安装Docker
sudo apt install -y docker-ce docker-ce-cli containerd.io

# 方法二:直接使用apt安装Docker(简单方法)
# 如果上述方法不成功,可以尝试这种简单的方法
# sudo apt install -y docker.io docker-compose

# 启动Docker并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker

# 安装Docker Compose(本地下载后上传到服务器)

# 方法1:在本地计算机下载Docker Compose二进制文件,然后上传到服务器(推荐)

## 步骤A:在本地计算机上下载正确版本的Docker Compose

# 重要:无论您的本地系统是什么,都必须下载Linux版本的Docker Compose,因为服务器是Linux系统
# 在浏览器中访问:https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64

# 或使用对应系统的命令行下载:

# 在macOS终端下载Linux版本:
# curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64" -o docker-compose-linux

# 在Windows PowerShell下载Linux版本:
# Invoke-WebRequest -Uri "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64" -OutFile "docker-compose-linux"

# 在Linux终端下载:
# wget https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-linux-x86_64 -O docker-compose-linux

## 步骤B:将下载的文件上传到服务器并重命名
# 使用SCP将文件从本地上传到服务器并重命名为docker-compose
# 示例(本地终端执行):

# 如果您从macOS上传:
# scp docker-compose-linux root@{你的云服务IP或域名}:/usr/local/bin/docker-compose

# 如果您从Windows上传(使用PowerShell):
# scp docker-compose-linux root@{你的云服务IP或域名}:/usr/local/bin/docker-compose

# 注意:必须重命名为"docker-compose"(无平台后缀),否则系统无法正确识别

## 步骤C:在服务器上设置权限
# 登录到服务器后执行:
sudo chmod +x /usr/local/bin/docker-compose

# 方法2:在服务器上安装基础版本(如果上述方法不可行)
# sudo apt install -y docker-compose
# 这个版本较旧(1.29.2),但能满足基本需求

# 方法3:使用Docker插件方式(如果您能在本地下载插件文件)
# 在本地下载docker-compose插件文件后上传到服务器:
# 创建插件目录
sudo mkdir -p /usr/local/lib/docker/cli-plugins
# 上传后移动到插件目录
# sudo mv /path/to/uploaded/docker-compose /usr/local/lib/docker/cli-plugins/docker-compose
# sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

# 验证安装
docker --version
docker-compose --version

# 将当前用户添加到docker组(避免每次都需要sudo)
sudo usermod -aG docker $USER
# 需要重新登录使上述更改生效

# 配置Docker国内镜像加速(可选但推荐)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": [
    "https://registry.docker-cn.com",
    "https://mirror.baidubce.com",
    "https://hub-mirror.c.163.com"
  ]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2. 创建项目目录结构

# 创建项目目录
mkdir -p ~/gitea-deploy
cd ~/gitea-deploy

# 创建所需子目录
mkdir -p nginx/conf.d nginx/html nginx/logs nginx/ssl

3. 将配置文件复制到服务器

有两种方式将配置文件传输到服务器,本地创建、写入内容后再上传,或者直接在远程服务器上编辑。

实际都需要这3个文件的内容:docker-compose.yml、default.conf、index.html 其内容可在文件内容参考本文档末尾的部分查看。

注意它们分别所对应的目录,相信你能够正确处理。

方式一:从本地复制到服务器

使用 scp 命令在本地计算机上执行:

# 在本地执行以下命令将文件上传到服务器
scp -r docker-compose.yml nginx/conf.d/default.conf nginx/html/index.html root@{你的云服务IP或域名}:~/gitea-deploy/

方式二:直接在服务器上创建文件

也可以在服务器上使用文本编辑器(如 nano 或 vim)直接创建这些文件:

# 示例:使用 nano 创建 docker-compose.yml
nano ~/gitea-deploy/docker-compose.yml
# 粘贴内容后,按 Ctrl+O 保存,Ctrl+X 退出

# 示例:使用 nano 创建 nginx 配置文件
nano ~/gitea-deploy/nginx/conf.d/default.conf
# 粘贴内容后,按 Ctrl+O 保存,Ctrl+X 退出

# 示例:使用 nano 创建 HTML 文件
nano ~/gitea-deploy/nginx/html/index.html
# 粘贴内容后,按 Ctrl+O 保存,Ctrl+X 退出

4. 启动服务

# 进入项目目录
cd ~/gitea-deploy

# 启动服务(后台运行)
docker-compose up -d

# 查看容器状态
docker-compose ps

# 查看日志(如有问题)
docker-compose logs

5. 初始配置 Gitea

首次访问 http://{你的云服务IP或域名}/ 会进入 Gitea 的初始化界面,按照以下建议配置:

  1. 数据库设置
    • 数据库类型: PostgreSQL
    • 主机: db:5432
    • 用户名: gitea
    • 密码: for_gitea_password
    • 数据库名: gitea
  2. 应用基本设置
    • 站点名称: {你的网站名称}
    • 网站根URL: http://{你的云服务IP或域名}/
  3. 管理员账号设置
    • 创建管理员账号,设置安全的用户名和密码
  4. 服务器和其他设置
    • 根据需要自定义其他设置

6. 维护和管理

查看日志

# 查看Nginx日志
docker-compose exec nginx cat /var/log/nginx/gitea_access.log
docker-compose exec nginx cat /var/log/nginx/gitea_error.log

# 查看Gitea日志
docker-compose logs gitea

备份数据

# 备份Gitea数据和PostgreSQL数据
tar -czvf gitea-backup-$(date +%Y%m%d).tar.gz gitea-data postgres-data

重启服务

docker-compose restart

7. 升级到 HTTPS(域名备案后)

当您获得域名并完成备案后,可以按照以下详细步骤升级到 HTTPS:

7.1 准备工作

  1. 确保您有一个已完成备案的域名,并已配置正确的DNS记录指向服务器IP。
  2. 创建证书验证目录
    # 在宿主机上创建用于证书验证的目录
    mkdir -p ~/gitea-deploy/nginx/html/.well-known/acme-challenge
  3. 修改Nginx配置,支持证书验证(在80端口server块内添加):
    # 编辑Nginx配置文件
    nano ~/gitea-deploy/nginx/conf.d/default.conf
    
    # 在80端口server块内添加以下location块
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }
  4. 应用Nginx配置更改
    docker-compose restart nginx

7.2 获取SSL证书

使用Let's Encrypt获取免费的SSL证书:

# 安装certbot
sudo apt install certbot python3-certbot-nginx

# 获取证书
# 重要:将yourdomain.com替换为您的实际域名
# /root/gitea-deploy/nginx/html是宿主机上对应容器内/usr/share/nginx/html的路径
sudo certbot certonly --webroot -w /root/gitea-deploy/nginx/html -d yourdomain.com

注意-w参数必须指向宿主机上映射到Nginx容器内的HTML目录。这里是/root/gitea-deploy/nginx/html,您可能需要根据实际路径调整。

7.3 配置证书文件

# 创建SSL证书目录(如果不存在)
mkdir -p ~/gitea-deploy/nginx/ssl

# 复制证书文件
sudo cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem ~/gitea-deploy/nginx/ssl/cert.pem
sudo cp /etc/letsencrypt/live/yourdomain.com/privkey.pem ~/gitea-deploy/nginx/ssl/key.pem

# 设置权限
sudo chown -R $USER:$USER ~/gitea-deploy/nginx/ssl/

7.4 更新Nginx配置

nano ~/gitea-deploy/nginx/conf.d/default.conf

取消注释HTTPS部分,并修改为您的域名:

# 取消注释并修改以下部分
server {
    listen 80;
    server_name yourdomain.com;
    # HTTP重定向到HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
    
    # 保留此部分用于证书续期
    location /.well-known/acme-challenge/ {
        root /usr/share/nginx/html;
    }
}

server {
    listen 443 ssl;
    server_name yourdomain.com;

    # SSL证书配置
    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # 安全头部
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    add_header X-Content-Type-Options nosniff;
    add_header X-Frame-Options DENY;
    add_header X-XSS-Protection "1; mode=block";

    # 根据您的实际配置,可能需要修改以下路径
    # 如果您的Gitea路径是/yourgiteahome/
    location /yourgiteahome/ {
        proxy_pass http://gitea: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;
        
        # WebSocket支持
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
    
    # 静态网站根目录
    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

7.5 更新docker-compose.yml中的Gitea配置

nano ~/gitea-deploy/docker-compose.yml

更新Gitea的环境变量:

- GITEA__server__DOMAIN=yourdomain.com
- GITEA__server__ROOT_URL=https://yourdomain.com/yourgiteahome/
- GITEA__server__PROTOCOL=https

注意:如果您的Gitea安装在其他路径(如/git/或根路径/),请相应地调整ROOT_URL。

7.6 应用更改

# 重启服务
cd ~/gitea-deploy
docker-compose down
docker-compose up -d

# 验证服务状态
docker-compose ps

7.7 配置证书自动更新

Let's Encrypt证书有效期为90天,需要定期更新。设置自动更新:

# 测试证书续期(不实际执行)
sudo certbot renew --dry-run

# 添加定期任务
sudo crontab -e

添加以下行:

# 每月1日凌晨更新证书并重启Nginx
0 0 1 * * certbot renew --quiet && cp /etc/letsencrypt/live/yourdomain.com/fullchain.pem /root/gitea-deploy/nginx/ssl/cert.pem && cp /etc/letsencrypt/live/yourdomain.com/privkey.pem /root/gitea-deploy/nginx/ssl/key.pem && docker restart nginx-proxy

7.8 验证HTTPS配置

访问您的域名,确认:

  • HTTPS工作正常(浏览器显示安全锁图标)
  • HTTP请求重定向到HTTPS
  • Gitea在正确的路径下可访问
  • 备案信息页面正确显示

通过静态页面查看备案信息

我们配置了一个特殊路径 /welcome,可以通过 http://{你的云服务IP或域名}:3000/welcome 访问静态 HTML 页面,这个页面底部显示备案信息:京ICP-1234567890。

其他说明

  1. Gitea 使用 PostgreSQL 17(最新版本)数据库
  2. 所有数据持久化存储在宿主机上的对应目录中
  3. Nginx 配置了大文件上传支持(512MB)
  4. 系统配置了自动重启功能,服务器重启后 Docker 容器会自动启动

文件内容参考

如果需要手动创建文件,可以参考以下内容:

docker-compose.yml

version: '3'

services:
  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
      - "3000:3000"
    volumes:
      - ./nginx/conf.d:/etc/nginx/conf.d
      - ./nginx/html:/usr/share/nginx/html
      - ./nginx/logs:/var/log/nginx
      - ./nginx/ssl:/etc/nginx/ssl
    restart: always
    networks:
      - app-network

  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=for_gitea_password
      - GITEA__server__DOMAIN={你的云服务IP或域名}
      - GITEA__server__ROOT_URL=http://{你的云服务IP或域名}/
    restart: always
    volumes:
      - ./gitea-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    depends_on:
      - db
    networks:
      - app-network

  db:
    image: postgres:latest
    container_name: gitea-db
    restart: always
    environment:
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=for_gitea_password
      - POSTGRES_DB=gitea
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

nginx/conf.d/default.conf

# Gitea服务配置
server {
    listen 3000;
    server_name localhost {你的云服务IP或域名};

    access_log /var/log/nginx/gitea_access.log;
    error_log /var/log/nginx/gitea_error.log;

    client_max_body_size 512M;

    # 代理到Gitea
    location / {
        proxy_pass http://gitea: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;
        
        # WebSocket支持
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    # 静态页面可通过特定路径访问
    location /welcome {
        alias /usr/share/nginx/html;
        index index.html;
    }
}

# 80端口主入口
server {
    listen 80;
    server_name {你的云服务IP或域名};
    
    # 重定向到Gitea
    location / {
        proxy_pass http://gitea: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;
        
        # WebSocket支持
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

# 将来启用HTTPS时使用的配置(已注释)
# server {
#     listen 80;
#     server_name your-domain.com;
#     # HTTP重定向到HTTPS
#     location / {
#         return 301 https://$host$request_uri;
#     }
# }
#
# server {
#     listen 443 ssl;
#     server_name your-domain.com;
#
#     # SSL证书配置
#     ssl_certificate /etc/nginx/ssl/cert.pem;
#     ssl_certificate_key /etc/nginx/ssl/key.pem;
#     ssl_protocols TLSv1.2 TLSv1.3;
#     ssl_prefer_server_ciphers on;
#     ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305';
#     ssl_session_cache shared:SSL:10m;
#     ssl_session_timeout 1d;
#
#     # HSTS (启用HTTPS严格传输安全)
#     add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
#
#     # 其他安全头部
#     add_header X-Content-Type-Options nosniff;
#     add_header X-Frame-Options DENY;
#     add_header X-XSS-Protection "1; mode=block";
#
#     # 将请求代理到Gitea服务
#     location / {
#         proxy_pass http://gitea: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;
#         
#         # WebSocket支持
#         proxy_set_header Upgrade $http_upgrade;
#         proxy_set_header Connection "upgrade";
#     }
# }

nginx/html/index.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>你给网站取个名字</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            min-height: 100vh;
            color: #333;
        }
        header {
            background-color: #f8f9fa;
            padding: 2rem;
            text-align: center;
            border-bottom: 1px solid #e9ecef;
        }
        h1 {
            color: #333;
            margin: 0;
        }
        main {
            flex: 1;
            padding: 2rem;
            text-align: center;
            max-width: 800px;
            margin: 0 auto;
        }
        .services {
            margin-top: 2rem;
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
            gap: 1rem;
        }
        .service-card {
            border: 1px solid #e9ecef;
            border-radius: 5px;
            padding: 1.5rem;
            background-color: #f8f9fa;
            transition: transform 0.3s ease;
        }
        .service-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        }
        footer {
            background-color: #f8f9fa;
            padding: 1rem;
            text-align: center;
            color: #6c757d;
            border-top: 1px solid #e9ecef;
        }
    </style>
</head>
<body>
    <header>
        <h1>你给网站取个名字</h1>
    </header>
    <main>
        <p>欢迎访问之类按你需要去写。</p>
        
        <div class="services">
            <div class="service-card">
                <h3>小模块</h3>
                <p>描述文字之类。</p>
            </div>
            <div class="service-card">
                <h3>小模块</h3>
                <p>描述文字之类。</p>
            </div>
        </div>
    </main>
    <footer>
        <p>京ICP-1234567890</p>
    </footer>
</body>
</html>