commit 88f08dcc4d8b34ca612c4a4074f148a7bd72f4a7 Author: Mars Date: Fri Mar 14 10:32:43 2025 +0800 初始化GiteaDocker项目,包含自动安装脚本和配置文件 diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1e3868 --- /dev/null +++ b/README.md @@ -0,0 +1,360 @@ +# Gitea Docker 部署项目 + +本项目用于在已有DNMP环境中部署Gitea服务。 + +## 项目背景 + +- 服务器环境:Debian 12 +- 已部署服务:DNMP (Docker + Nginx + MySQL + PHP) +- 目标:部署Gitea服务 +- 域名:gitea.mzh.one (已完成DNS解析) +- 证书:使用已安装的certbot申请和自动更新SSL证书 + +## DNMP环境配置 + +- DNMP目录:/opt/dnmp +- DNMP的www目录:/opt/dnmp/www +- DNMP的Nginx配置目录:/opt/dnmp/services/nginx/conf.d +- SSL证书目录:/opt/dnmp/services/nginx/ssl/gitea.mzh.one +- Nginx配置文件名:gitea.mzh.one.conf + +## 容器路径映射 + +本项目会自动检测DNMP环境中的容器路径映射,适应不同的DNMP配置: + +- Nginx容器中的路径映射: + - 主机上的 `/opt/dnmp/www` 通常映射到容器内的 `/www` + - 主机上的 `/opt/dnmp/services/nginx/ssl` 通常映射到容器内的 `/ssl` + - 主机上的 `/opt/dnmp/services/nginx/conf.d` 通常映射到容器内的 `/etc/nginx/conf.d` + +安装脚本会自动检测这些映射,并相应地调整配置文件。 + +## 容器自动检测 + +本项目的脚本会自动检测环境中的容器: + +- 自动检测MySQL容器:脚本会自动查找运行中的MySQL或MariaDB容器 +- 自动检测Nginx容器:脚本会自动查找运行中的Nginx容器 +- 自动检测Docker网络:如果没有找到dnmp_default网络,会使用默认的bridge网络 + +这使得本项目可以适应不同的Docker环境配置,无需手动修改脚本中的容器名称。 + +## 项目结构 + +``` +. +├── README.md # 项目说明文档 +├── docker-compose.yml # Docker Compose配置文件 +├── deploy.sh # 部署脚本 +├── install.sh # 一键安装脚本 +├── uninstall.sh # 卸载脚本 +├── backup.sh # 备份脚本 +├── conf # 配置文件目录 +│ ├── nginx # Nginx配置文件目录 +│ │ └── conf.d # Nginx站点配置目录 +│ │ └── gitea.mzh.one.conf # Gitea站点配置 +│ └── gitea # Gitea配置文件目录 +│ └── app.ini # Gitea主配置文件 +└── data # 数据存储目录 + ├── gitea # Gitea数据目录 + └── mysql # MySQL数据目录(如需单独使用) +``` + +## 快速开始 + +### 一键安装 + +使用一键安装脚本可以快速部署Gitea: + +```bash +# 下载安装脚本 +wget https://raw.githubusercontent.com/yourusername/gitea-docker/main/install.sh +# 添加执行权限 +chmod +x install.sh +# 执行安装脚本 +sudo ./install.sh +``` + +安装脚本会自动完成以下操作: +1. 检查必要的依赖 +2. 自动检测MySQL和Nginx容器 +3. 自动检测容器的路径映射 +4. 创建项目目录结构 +5. 创建MySQL数据库和用户 +6. 申请SSL证书 +7. 配置Nginx反向代理 +8. 启动Gitea服务 + +### 一键卸载 + +如需卸载Gitea,可以使用卸载脚本: + +```bash +# 下载卸载脚本 +wget https://raw.githubusercontent.com/yourusername/gitea-docker/main/uninstall.sh +# 添加执行权限 +chmod +x uninstall.sh +# 执行卸载脚本 +sudo ./uninstall.sh +``` + +卸载脚本会执行以下操作: +1. 停止并删除Gitea容器 +2. 删除Nginx配置 +3. 可选:删除Gitea数据库 +4. 可选:删除SSL证书 +5. 可选:删除安装目录 + +### 自动备份 + +使用备份脚本可以定期备份Gitea数据: + +```bash +# 下载备份脚本 +wget https://raw.githubusercontent.com/yourusername/gitea-docker/main/backup.sh +# 添加执行权限 +chmod +x backup.sh +# 执行备份脚本 +sudo ./backup.sh +``` + +备份脚本支持以下选项: +- `-d <目录>`: 指定备份目录(默认:/opt/gitea-backups) +- `-g <目录>`: 指定Gitea安装目录(默认:/opt/gitea) +- `-m <容器名>`: 指定MySQL容器名(默认:自动检测) +- `-u <用户名>`: 指定MySQL用户名(默认:gitea) +- `-p <密码>`: 指定MySQL密码(默认:gitea_password) +- `-k <天数>`: 指定保留备份的天数(默认:7) + +设置定时备份: +```bash +# 编辑crontab +sudo crontab -e + +# 添加以下行,每天凌晨2点执行备份 +0 2 * * * /opt/gitea/backup.sh > /var/log/gitea-backup.log 2>&1 +``` + +## 详细部署步骤 + +### 1. 准备工作 + +1. 确保服务器上已安装Docker和Docker Compose +2. 确保MySQL和Nginx容器已正常运行 +3. 确保域名gitea.mzh.one已正确解析到服务器IP +4. 确保服务器上已安装certbot + +### 2. 克隆项目 + +```bash +git clone https://github.com/yourusername/gitea-docker.git +cd gitea-docker +``` + +或者手动创建项目结构和文件。 + +### 3. 准备MySQL数据库 + +创建Gitea所需的数据库和用户: + +```bash +# 创建SQL脚本 +cat < create_db.sql +CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER IF NOT EXISTS 'gitea'@'%' IDENTIFIED BY 'gitea_password'; +GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'%'; +FLUSH PRIVILEGES; +EOF + +# 执行SQL脚本(脚本会自动检测MySQL容器) +docker exec -i $(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $1}') mysql -uroot -p < create_db.sql +``` + +### 4. 申请SSL证书 + +使用certbot申请SSL证书: + +```bash +# 确保DNMP的www目录存在 +sudo mkdir -p /opt/dnmp/www/.well-known/acme-challenge + +# 申请证书 +sudo certbot certonly --webroot -w /opt/dnmp/www -d gitea.mzh.one + +# 创建SSL证书目录 +sudo mkdir -p /opt/dnmp/services/nginx/ssl/gitea.mzh.one + +# 复制证书到DNMP的SSL目录 +sudo cp /etc/letsencrypt/live/gitea.mzh.one/fullchain.pem /opt/dnmp/services/nginx/ssl/gitea.mzh.one/gitea.mzh.one.pem +sudo cp /etc/letsencrypt/live/gitea.mzh.one/privkey.pem /opt/dnmp/services/nginx/ssl/gitea.mzh.one/gitea.mzh.one.key +``` + +### 5. 配置Nginx + +将项目中的Nginx配置文件复制到DNMP的Nginx配置目录: + +```bash +# 复制Nginx配置文件 +sudo cp conf/nginx/conf.d/gitea.mzh.one.conf /opt/dnmp/services/nginx/conf.d/ + +# 重新加载Nginx配置(脚本会自动检测Nginx容器) +docker exec -it $(docker ps | grep nginx | head -1 | awk '{print $1}') nginx -s reload +``` + +### 6. 启动Gitea服务 + +```bash +# 启动服务 +docker-compose up -d +``` + +### 7. 完成初始化设置 + +访问 https://gitea.mzh.one 完成Gitea的初始化设置。 + +初始化时,请使用以下数据库设置: +- 数据库类型:MySQL +- 主机:[MySQL容器名]:3306(脚本会自动检测并显示) +- 用户名:gitea +- 密码:gitea_password +- 数据库名:gitea + +## 使用方法 + +### 1. 启动服务 + +```bash +docker-compose up -d +``` + +### 2. 停止服务 + +```bash +docker-compose down +``` + +### 3. 查看日志 + +```bash +docker-compose logs -f gitea +``` + +### 4. 备份数据 + +备份Gitea数据有两种方式: + +#### 手动备份 + +```bash +# 备份数据目录 +tar -czvf gitea-data-backup.tar.gz data/gitea + +# 备份MySQL数据库(脚本会自动检测MySQL容器) +MYSQL_CONTAINER=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $NF}') +docker exec $MYSQL_CONTAINER mysqldump -u gitea -pgitea_password gitea > gitea-db-backup.sql +``` + +#### 自动备份 + +使用提供的备份脚本: + +```bash +# 执行备份 +./backup.sh + +# 查看备份帮助 +./backup.sh -h +``` + +## 注意事项 + +- 确保MySQL服务已正常运行 +- 确保80和443端口未被占用 +- 确保域名已正确解析到服务器IP +- 修改app.ini中的密钥和令牌(SECRET_KEY, INTERNAL_TOKEN, LFS_JWT_SECRET) +- 默认SSH端口为222,如需修改,请同时更新docker-compose.yml和app.ini +- 默认数据库密码为gitea_password,建议在生产环境中修改为更强的密码 +- 确保没有其他配置文件使用相同的域名,以避免Nginx配置冲突 + +## 故障排除 + +- 如果无法访问Gitea,请检查Nginx配置和容器运行状态 + ```bash + docker ps | grep gitea + docker logs gitea + ``` + +- 如果数据库连接失败,请检查MySQL服务状态和连接配置 + ```bash + # 自动检测MySQL容器并查询 + MYSQL_CONTAINER=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $NF}') + docker exec -it $MYSQL_CONTAINER mysql -u gitea -pgitea_password -e "SHOW DATABASES;" + ``` + +- 如果SSL证书问题,请检查证书路径和权限 + ```bash + ls -la /opt/dnmp/services/nginx/ssl/gitea.mzh.one/ + ``` + +- 如果Nginx配置冲突,请检查是否有多个配置文件使用相同的域名 + ```bash + grep -r "server_name gitea.mzh.one" /opt/dnmp/services/nginx/conf.d/ + ``` + +## 安全建议 + +1. 修改默认的数据库密码 +2. 启用Gitea的二次验证功能 +3. 定期备份数据 +4. 定期更新Gitea版本 +5. 限制SSH访问权限 + +## 维护指南 + +### 更新Gitea + +更新Gitea到最新版本: + +```bash +# 拉取最新镜像 +docker pull gitea/gitea:latest + +# 重启服务 +docker-compose down +docker-compose up -d +``` + +### 数据迁移 + +如需迁移Gitea到新服务器: + +1. 在旧服务器上执行备份 + ```bash + ./backup.sh + ``` + +2. 将备份文件复制到新服务器 + ```bash + scp -r /opt/gitea-backups user@new-server:/tmp/ + ``` + +3. 在新服务器上安装Gitea + ```bash + ./install.sh + ``` + +4. 恢复备份 + ```bash + # 停止Gitea服务 + docker-compose down + + # 恢复数据 + tar -xzf /tmp/gitea-data-*.tar.gz -C /opt/gitea/ + + # 自动检测MySQL容器并恢复数据库 + MYSQL_CONTAINER=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $NF}') + gunzip -c /tmp/gitea-db-*.sql.gz | docker exec -i $MYSQL_CONTAINER mysql -u gitea -pgitea_password gitea + + # 启动服务 + docker-compose up -d + ``` \ No newline at end of file diff --git a/backup.sh b/backup.sh new file mode 100644 index 0000000..123b8a1 --- /dev/null +++ b/backup.sh @@ -0,0 +1,157 @@ +#!/bin/bash + +# Gitea备份脚本 +# 作者:AI助手 +# 日期:2025-03-13 + +set -e + +echo "===== Gitea备份脚本 =====" + +# 设置变量 +BACKUP_DIR="/opt/gitea-backups" +GITEA_DIR="/opt/gitea" +MYSQL_CONTAINER="mysql" # 默认MySQL容器名 +MYSQL_USER="gitea" +MYSQL_PASSWORD="gitea_password" +MYSQL_DATABASE="gitea" +DATE=$(date +%Y%m%d-%H%M%S) +KEEP_DAYS=7 +DOMAIN="gitea.mzh.one" + +# 检查Nginx容器 +NGINX_CONTAINER=$(docker ps | grep nginx | head -1 | awk '{print $1}') +if [ -z "$NGINX_CONTAINER" ]; then + echo "警告: Nginx容器未找到,无法备份Nginx配置" 1>&2 +else + NGINX_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $NGINX_CONTAINER | sed 's/\///') + echo "找到Nginx容器: $NGINX_CONTAINER_NAME" + + # 检查Nginx容器的挂载点 + SSL_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/ssl"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + CONF_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/etc/nginx/conf.d"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + + if [ -z "$SSL_MOUNT" ]; then + echo "警告: 未找到Nginx容器的SSL挂载点,将使用默认路径" + SSL_MOUNT="/opt/dnmp/services/nginx/ssl" + else + echo "找到Nginx SSL挂载点: $SSL_MOUNT" + fi + + if [ -z "$CONF_MOUNT" ]; then + echo "警告: 未找到Nginx容器的配置挂载点,将使用默认路径" + CONF_MOUNT="/opt/dnmp/services/nginx/conf.d" + else + echo "找到Nginx配置挂载点: $CONF_MOUNT" + fi +fi + +NGINX_CONF_DIR="${CONF_MOUNT:-/opt/dnmp/services/nginx/conf.d}" +SSL_DIR="${SSL_MOUNT:-/opt/dnmp/services/nginx/ssl}/$DOMAIN" + +# 自动检测MySQL容器 +AUTO_DETECT_MYSQL=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $1}') +if [ ! -z "$AUTO_DETECT_MYSQL" ]; then + DETECTED_MYSQL_NAME=$(docker inspect --format='{{.Name}}' $AUTO_DETECT_MYSQL | sed 's/\///') + MYSQL_CONTAINER=$DETECTED_MYSQL_NAME + echo "自动检测到MySQL容器: $MYSQL_CONTAINER" +fi + +# 检查参数 +while getopts "d:g:m:u:p:k:" opt; do + case $opt in + d) BACKUP_DIR="$OPTARG" ;; + g) GITEA_DIR="$OPTARG" ;; + m) MYSQL_CONTAINER="$OPTARG" ;; + u) MYSQL_USER="$OPTARG" ;; + p) MYSQL_PASSWORD="$OPTARG" ;; + k) KEEP_DAYS="$OPTARG" ;; + \?) echo "无效的选项: -$OPTARG" >&2; exit 1 ;; + esac +done + +# 显示配置信息 +echo "备份配置:" +echo " 备份目录: $BACKUP_DIR" +echo " Gitea目录: $GITEA_DIR" +echo " MySQL容器: $MYSQL_CONTAINER" +echo " 保留天数: $KEEP_DAYS" +echo " 域名: $DOMAIN" +echo " Nginx配置目录: $NGINX_CONF_DIR" +echo " SSL证书目录: $SSL_DIR" + +# 创建备份目录 +mkdir -p "$BACKUP_DIR" + +# 备份Gitea数据 +echo "备份Gitea数据..." +if [ -d "$GITEA_DIR/data/gitea" ]; then + tar -czf "$BACKUP_DIR/gitea-data-$DATE.tar.gz" -C "$GITEA_DIR" data/gitea + echo "Gitea数据备份完成: $BACKUP_DIR/gitea-data-$DATE.tar.gz" +else + echo "警告: Gitea数据目录不存在: $GITEA_DIR/data/gitea" +fi + +# 备份MySQL数据库 +echo "备份MySQL数据库..." +if docker ps | grep -q "$MYSQL_CONTAINER"; then + docker exec "$MYSQL_CONTAINER" mysqldump -u "$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" > "$BACKUP_DIR/gitea-db-$DATE.sql" + echo "MySQL数据库备份完成: $BACKUP_DIR/gitea-db-$DATE.sql" +else + echo "警告: MySQL容器不存在或未运行: $MYSQL_CONTAINER" +fi + +# 备份Nginx配置和SSL证书 +echo "备份Nginx配置和SSL证书..." +if [ -f "$NGINX_CONF_DIR/$DOMAIN.conf" ]; then + mkdir -p "$BACKUP_DIR/nginx-$DATE/conf.d" + cp "$NGINX_CONF_DIR/$DOMAIN.conf" "$BACKUP_DIR/nginx-$DATE/conf.d/" + echo "Nginx配置备份完成: $BACKUP_DIR/nginx-$DATE/conf.d/$DOMAIN.conf" +fi + +if [ -d "$SSL_DIR" ]; then + mkdir -p "$BACKUP_DIR/nginx-$DATE/ssl" + cp -r "$SSL_DIR" "$BACKUP_DIR/nginx-$DATE/ssl/" + echo "SSL证书备份完成: $BACKUP_DIR/nginx-$DATE/ssl/$DOMAIN" +fi + +# 压缩Nginx备份 +if [ -d "$BACKUP_DIR/nginx-$DATE" ]; then + tar -czf "$BACKUP_DIR/nginx-$DATE.tar.gz" -C "$BACKUP_DIR" "nginx-$DATE" + rm -rf "$BACKUP_DIR/nginx-$DATE" + echo "Nginx备份已压缩: $BACKUP_DIR/nginx-$DATE.tar.gz" +fi + +# 压缩数据库备份 +if [ -f "$BACKUP_DIR/gitea-db-$DATE.sql" ]; then + gzip "$BACKUP_DIR/gitea-db-$DATE.sql" + echo "MySQL数据库备份已压缩: $BACKUP_DIR/gitea-db-$DATE.sql.gz" +fi + +# 删除旧备份 +echo "删除$KEEP_DAYS天前的备份..." +find "$BACKUP_DIR" -name "gitea-data-*.tar.gz" -mtime +$KEEP_DAYS -delete +find "$BACKUP_DIR" -name "gitea-db-*.sql.gz" -mtime +$KEEP_DAYS -delete +find "$BACKUP_DIR" -name "nginx-*.tar.gz" -mtime +$KEEP_DAYS -delete + +echo "===== 备份完成 =====" +echo "备份文件保存在: $BACKUP_DIR" + +# 显示备份统计信息 +echo "备份统计:" +echo " 数据备份数量: $(find "$BACKUP_DIR" -name "gitea-data-*.tar.gz" | wc -l)" +echo " 数据库备份数量: $(find "$BACKUP_DIR" -name "gitea-db-*.sql.gz" | wc -l)" +echo " Nginx备份数量: $(find "$BACKUP_DIR" -name "nginx-*.tar.gz" | wc -l)" +echo " 总备份大小: $(du -sh "$BACKUP_DIR" | cut -f1)" + +# 使用说明 +echo "" +echo "使用说明:" +echo " 1. 手动运行备份: ./backup.sh" +echo " 2. 自定义备份目录: ./backup.sh -d /path/to/backup" +echo " 3. 自定义Gitea目录: ./backup.sh -g /path/to/gitea" +echo " 4. 自定义MySQL容器: ./backup.sh -m container_name" +echo " 5. 自定义保留天数: ./backup.sh -k 14" +echo "" +echo "添加到crontab定时运行:" +echo " 0 2 * * * /opt/gitea/backup.sh > /var/log/gitea-backup.log 2>&1" \ No newline at end of file diff --git a/conf/gitea/app.ini b/conf/gitea/app.ini new file mode 100644 index 0000000..99b47a3 --- /dev/null +++ b/conf/gitea/app.ini @@ -0,0 +1,83 @@ +APP_NAME = Gitea: Git with a cup of tea +RUN_USER = git +RUN_MODE = prod + +[repository] +ROOT = /data/git/repositories + +[repository.local] +LOCAL_COPY_PATH = /data/gitea/tmp/local-repo + +[repository.upload] +TEMP_PATH = /data/gitea/uploads + +[server] +APP_DATA_PATH = /data/gitea +DOMAIN = gitea.mzh.one +SSH_DOMAIN = gitea.mzh.one +HTTP_PORT = 3000 +ROOT_URL = https://gitea.mzh.one/ +DISABLE_SSH = false +SSH_PORT = 22 +SSH_LISTEN_PORT = 22 +LFS_START_SERVER = true +LFS_CONTENT_PATH = /data/git/lfs +LFS_JWT_SECRET = _YourSecretKey_ +OFFLINE_MODE = false + +[database] +PATH = /data/gitea/gitea.db +DB_TYPE = mysql +HOST = mysql:3306 +NAME = gitea +USER = gitea +PASSWD = gitea_password +SSL_MODE = disable +CHARSET = utf8mb4 + +[indexer] +ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve + +[session] +PROVIDER_CONFIG = /data/gitea/sessions +PROVIDER = file + +[picture] +AVATAR_UPLOAD_PATH = /data/gitea/avatars +REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars + +[attachment] +PATH = /data/gitea/attachments + +[log] +MODE = console +LEVEL = info +ROOT_PATH = /data/gitea/log + +[security] +INSTALL_LOCK = false +SECRET_KEY = _YourSecretKey_ +INTERNAL_TOKEN = _YourInternalToken_ + +[service] +DISABLE_REGISTRATION = false +REQUIRE_SIGNIN_VIEW = false +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true +DEFAULT_ENABLE_TIMETRACKING = true +NO_REPLY_ADDRESS = noreply.gitea.mzh.one + +[mailer] +ENABLED = false + +[openid] +ENABLE_OPENID_SIGNIN = true +ENABLE_OPENID_SIGNUP = true + +[ui] +DEFAULT_THEME = auto +THEMES = auto,gitea,arc-green \ No newline at end of file diff --git a/conf/nginx/conf.d/gitea.mzh.one.conf b/conf/nginx/conf.d/gitea.mzh.one.conf new file mode 100644 index 0000000..b79d9b4 --- /dev/null +++ b/conf/nginx/conf.d/gitea.mzh.one.conf @@ -0,0 +1,60 @@ +server { + listen 80; + server_name gitea.mzh.one; + + # 将HTTP请求重定向到HTTPS + location / { + return 301 https://$host$request_uri; + } + + # Let's Encrypt验证路径 + location /.well-known/acme-challenge/ { + root /www; + } +} + +server { + listen 443 ssl; + http2 on; + server_name gitea.mzh.one; + + # SSL证书配置 + ssl_certificate /ssl/gitea.mzh.one/gitea.mzh.one.pem; + ssl_certificate_key /ssl/gitea.mzh.one/gitea.mzh.one.key; + ssl_session_timeout 5m; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + # 反向代理到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"; + + # 超时设置 + proxy_read_timeout 600s; + proxy_connect_timeout 600s; + proxy_send_timeout 600s; + + # 缓冲设置 + proxy_buffer_size 128k; + proxy_buffers 4 256k; + proxy_busy_buffers_size 256k; + } + + # 大文件上传设置 + client_max_body_size 512M; + + # 错误页面 + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } +} \ No newline at end of file diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..b56d18a --- /dev/null +++ b/deploy.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +# 部署Gitea的脚本 +# 作者:AI助手 +# 日期:2025-03-13 + +set -e + +echo "===== 开始部署Gitea =====" + +# 设置变量 +DOMAIN="gitea.mzh.one" +DNMP_DIR="/opt/dnmp" +NGINX_CONF_DIR="$DNMP_DIR/services/nginx/conf.d" +SSL_DIR="$DNMP_DIR/services/nginx/ssl/$DOMAIN" +WWW_DIR="$DNMP_DIR/www" + +# 自动检测MySQL容器 +MYSQL_CONTAINER="mysql" # 默认MySQL容器名 +AUTO_DETECT_MYSQL=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $1}') +if [ ! -z "$AUTO_DETECT_MYSQL" ]; then + DETECTED_MYSQL_NAME=$(docker inspect --format='{{.Name}}' $AUTO_DETECT_MYSQL | sed 's/\///') + MYSQL_CONTAINER=$DETECTED_MYSQL_NAME + echo "自动检测到MySQL容器: $MYSQL_CONTAINER" +fi + +# 自动检测Nginx容器 +NGINX_CONTAINER="nginx" # 默认Nginx容器名 +AUTO_DETECT_NGINX=$(docker ps | grep nginx | head -1 | awk '{print $1}') +if [ ! -z "$AUTO_DETECT_NGINX" ]; then + DETECTED_NGINX_NAME=$(docker inspect --format='{{.Name}}' $AUTO_DETECT_NGINX | sed 's/\///') + NGINX_CONTAINER=$DETECTED_NGINX_NAME + echo "自动检测到Nginx容器: $NGINX_CONTAINER" +fi + +# 1. 创建必要的目录 +echo "1. 创建必要的目录..." +mkdir -p conf/nginx/conf.d conf/gitea data/gitea data/mysql +mkdir -p $SSL_DIR +mkdir -p $WWW_DIR + +# 2. 确保MySQL数据库已准备好 +echo "2. 准备MySQL数据库..." +# 假设MySQL已经在DNMP环境中运行 +# 创建gitea数据库和用户 +cat < create_db.sql +CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER IF NOT EXISTS 'gitea'@'%' IDENTIFIED BY 'gitea_password'; +GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'%'; +FLUSH PRIVILEGES; +EOF + +echo "请手动执行以下命令创建数据库(如果尚未创建):" +echo "docker exec -i $MYSQL_CONTAINER mysql -uroot -p < create_db.sql" + +# 3. 申请SSL证书 +echo "3. 申请SSL证书..." +echo "请确保域名$DOMAIN已正确解析到服务器IP" +echo "请手动执行以下命令申请证书:" +echo "certbot certonly --webroot -w $WWW_DIR -d $DOMAIN" +echo "然后复制证书到指定目录:" +echo "cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $SSL_DIR/$DOMAIN.pem" +echo "cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $SSL_DIR/$DOMAIN.key" + +# 4. 启动Gitea服务 +echo "4. 启动Gitea服务..." +docker-compose up -d + +echo "5. 配置Nginx..." +# 假设Nginx配置文件已经创建好 +echo "请确保Nginx配置文件已正确加载" +echo "请将gitea.conf复制到DNMP的nginx配置目录:" +echo "cp conf/nginx/conf.d/$DOMAIN.conf $NGINX_CONF_DIR/" +echo "然后重启Nginx:docker exec -it $NGINX_CONTAINER nginx -s reload" + +echo "===== Gitea部署完成 =====" +echo "请访问 https://$DOMAIN 完成初始化设置" +echo "初始化时,请使用以下数据库设置:" +echo "数据库类型:MySQL" +echo "主机:$MYSQL_CONTAINER:3306" +echo "用户名:gitea" +echo "密码:gitea_password" +echo "数据库名:gitea" + +echo "注意:首次访问时,您将被引导完成Gitea的初始化设置,包括创建管理员账户" \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..0bbe00b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,34 @@ +version: '3' + +services: + gitea: + image: gitea/gitea:latest + container_name: gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + - GITEA__database__DB_TYPE=mysql + - GITEA__database__HOST=mysql:3306 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD=gitea_password + - GITEA__server__DOMAIN=gitea.mzh.one + - GITEA__server__ROOT_URL=https://gitea.mzh.one/ + restart: always + volumes: + - ./data/gitea:/data + - ./conf/gitea/app.ini:/data/gitea/conf/app.ini:ro + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "3000:3000" + - "222:22" + networks: + - gitea + - dnmp_default # 连接到已有的DNMP网络 + +networks: + gitea: + driver: bridge + dnmp_default: + external: true # 使用已有的DNMP网络 \ No newline at end of file diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..20bde96 --- /dev/null +++ b/install.sh @@ -0,0 +1,461 @@ +#!/bin/bash + +# Gitea一键安装脚本 +# 作者:AI助手 +# 日期:2025-03-13 + +set -e + +echo "===== Gitea一键安装脚本 =====" +echo "此脚本将在已有DNMP环境中部署Gitea服务" + +# 检查是否有root权限 +if [ "$(id -u)" != "0" ]; then + echo "此脚本需要root权限运行" 1>&2 + exit 1 +fi + +# 检查必要的命令 +for cmd in docker docker-compose certbot; do + if ! command -v $cmd &> /dev/null; then + echo "错误: $cmd 未安装" 1>&2 + exit 1 + fi +done + +# 检查DNMP环境 +DOCKER_NETWORK="dnmp_default" +if ! docker network ls | grep -q dnmp_default; then + # 如果没有找到dnmp_default网络,检查是否有其他Docker网络 + if [ $(docker network ls | wc -l) -le 2 ]; then + echo "错误: 未找到可用的Docker网络,请确保Docker环境已正常运行" 1>&2 + exit 1 + else + echo "警告: 未找到dnmp_default网络,将使用默认的bridge网络" + DOCKER_NETWORK="bridge" + fi +else + echo "找到Docker网络: $DOCKER_NETWORK" +fi + +# 检查MySQL容器 +MYSQL_CONTAINER=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $1}') +if [ -z "$MYSQL_CONTAINER" ]; then + echo "错误: MySQL容器未找到,请确保MySQL服务已正常运行" 1>&2 + exit 1 +else + MYSQL_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $MYSQL_CONTAINER | sed 's/\///') + echo "找到MySQL容器: $MYSQL_CONTAINER_NAME" +fi + +# 检查Nginx容器 +NGINX_CONTAINER=$(docker ps | grep nginx | head -1 | awk '{print $1}') +if [ -z "$NGINX_CONTAINER" ]; then + echo "错误: Nginx容器未找到,请确保Nginx服务已正常运行" 1>&2 + exit 1 +else + NGINX_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $NGINX_CONTAINER | sed 's/\///') + echo "找到Nginx容器: $NGINX_CONTAINER_NAME" + + # 检查Nginx容器的挂载点 + echo "检查Nginx容器的挂载点..." + SSL_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/ssl"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + WWW_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/www"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + CONF_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/etc/nginx/conf.d"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + + if [ -z "$SSL_MOUNT" ]; then + echo "警告: 未找到Nginx容器的SSL挂载点,将使用默认路径" + SSL_MOUNT="/opt/dnmp/services/nginx/ssl" + else + echo "找到Nginx SSL挂载点: $SSL_MOUNT" + fi + + if [ -z "$WWW_MOUNT" ]; then + echo "警告: 未找到Nginx容器的WWW挂载点,将使用默认路径" + WWW_MOUNT="/opt/dnmp/www" + else + echo "找到Nginx WWW挂载点: $WWW_MOUNT" + fi + + if [ -z "$CONF_MOUNT" ]; then + echo "警告: 未找到Nginx容器的配置挂载点,将使用默认路径" + CONF_MOUNT="/opt/dnmp/services/nginx/conf.d" + else + echo "找到Nginx配置挂载点: $CONF_MOUNT" + fi + + # 检查Nginx容器的网络 + NGINX_NETWORK=$(docker inspect -f '{{range $key, $value := .NetworkSettings.Networks}}{{$key}}{{end}}' $NGINX_CONTAINER) + if [ ! -z "$NGINX_NETWORK" ]; then + echo "找到Nginx容器的网络: $NGINX_NETWORK" + DOCKER_NETWORK=$NGINX_NETWORK + fi +fi + +# 设置变量 +DOMAIN="gitea.mzh.one" +MYSQL_ROOT_PASSWORD="" +GITEA_DB_PASSWORD="gitea_password" +INSTALL_DIR="/opt/gitea" +NGINX_CONF_DIR="$CONF_MOUNT" +SSL_DIR="$SSL_MOUNT/$DOMAIN" +WWW_DIR="$WWW_MOUNT" + +# 询问MySQL root密码 +read -sp "请输入MySQL root密码: " MYSQL_ROOT_PASSWORD +echo "" + +# 询问Gitea数据库密码 +read -sp "请输入Gitea数据库密码 [默认: gitea_password]: " INPUT_GITEA_DB_PASSWORD +echo "" +if [ ! -z "$INPUT_GITEA_DB_PASSWORD" ]; then + GITEA_DB_PASSWORD=$INPUT_GITEA_DB_PASSWORD +fi + +# 询问安装目录 +read -p "请输入安装目录 [默认: $INSTALL_DIR]: " INPUT_INSTALL_DIR +if [ ! -z "$INPUT_INSTALL_DIR" ]; then + INSTALL_DIR=$INPUT_INSTALL_DIR +fi + +# 创建安装目录 +echo "创建安装目录: $INSTALL_DIR" +mkdir -p $INSTALL_DIR +cd $INSTALL_DIR + +# 创建项目结构 +echo "创建项目结构..." +mkdir -p conf/nginx/conf.d conf/gitea data/gitea data/mysql + +# 创建docker-compose.yml +echo "创建docker-compose.yml..." +cat > docker-compose.yml < conf/nginx/conf.d/$DOMAIN.conf < conf/gitea/app.ini < create_db.sql <&2 + exit 1 +fi + +# 检查是否存在冲突的配置文件 +echo "检查是否存在冲突的配置文件..." +CONFLICT_FILES=$(grep -l "server_name $DOMAIN" $NGINX_CONF_DIR/*.conf 2>/dev/null || true) +if [ ! -z "$CONFLICT_FILES" ]; then + echo "警告: 发现可能与 $DOMAIN 冲突的配置文件:" + echo "$CONFLICT_FILES" + read -p "是否删除这些文件?[y/N]: " DELETE_CONFLICT + if [ "$DELETE_CONFLICT" == "y" ] || [ "$DELETE_CONFLICT" == "Y" ]; then + for file in $CONFLICT_FILES; do + if [ "$file" != "$NGINX_CONF_DIR/$DOMAIN.conf" ]; then + echo "删除冲突文件: $file" + rm -f "$file" + fi + done + else + echo "请手动解决配置文件冲突,否则可能导致Nginx配置错误" + fi +fi + +# 申请SSL证书 +echo "申请SSL证书..." +mkdir -p $WWW_DIR/.well-known/acme-challenge +chmod -R 755 $WWW_DIR + +# 创建一个测试文件,确保路径配置正确 +echo "test" > $WWW_DIR/.well-known/acme-challenge/test +echo "请访问 http://$DOMAIN/.well-known/acme-challenge/test 确认是否返回 'test'" +echo "如果无法访问,请检查Nginx配置和域名解析" +read -p "按回车键继续..." CONTINUE + +# 申请证书 +certbot certonly --webroot -w $WWW_DIR -d $DOMAIN +CERT_STATUS=$? + +# 创建SSL证书目录 +echo "创建SSL证书目录..." +mkdir -p $SSL_DIR + +if [ $CERT_STATUS -ne 0 ]; then + echo "警告: 申请SSL证书失败,将使用自签名证书" + + # 生成自签名证书 + echo "生成自签名证书..." + openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout $SSL_DIR/$DOMAIN.key \ + -out $SSL_DIR/$DOMAIN.pem \ + -subj "/CN=$DOMAIN" +else + # 复制SSL证书 + echo "复制SSL证书..." + cp /etc/letsencrypt/live/$DOMAIN/fullchain.pem $SSL_DIR/$DOMAIN.pem + cp /etc/letsencrypt/live/$DOMAIN/privkey.pem $SSL_DIR/$DOMAIN.key +fi + +# 设置证书权限 +chmod 644 $SSL_DIR/$DOMAIN.pem +chmod 600 $SSL_DIR/$DOMAIN.key + +# 复制Nginx配置到DNMP +echo "复制Nginx配置到DNMP..." +mkdir -p $NGINX_CONF_DIR +cp conf/nginx/conf.d/$DOMAIN.conf $NGINX_CONF_DIR/ + +# 启动Gitea服务 +echo "启动Gitea服务..." +docker-compose up -d + +# 等待Gitea容器启动 +echo "等待Gitea容器启动..." +sleep 5 + +# 获取Gitea容器IP地址 +GITEA_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' gitea) +if [ ! -z "$GITEA_IP" ]; then + echo "Gitea容器IP地址: $GITEA_IP" + + # 更新Nginx配置,使用IP地址而不是主机名 + sed -i "s/proxy_pass http:\/\/\\\$upstream:3000;/proxy_pass http:\/\/$GITEA_IP:3000;/" $NGINX_CONF_DIR/$DOMAIN.conf + sed -i "/resolver 127.0.0.11/d" $NGINX_CONF_DIR/$DOMAIN.conf + sed -i "/set \\\$upstream gitea;/d" $NGINX_CONF_DIR/$DOMAIN.conf +fi + +# 重新加载Nginx配置 +echo "重新加载Nginx配置..." +docker exec -it $NGINX_CONTAINER nginx -t && docker exec -it $NGINX_CONTAINER nginx -s reload +if [ $? -ne 0 ]; then + echo "警告: Nginx配置测试失败,请检查配置文件" + docker exec -it $NGINX_CONTAINER cat /var/log/nginx/error.log | tail -n 20 + + # 如果使用IP地址仍然失败,尝试添加hosts映射 + echo "尝试添加hosts映射..." + docker exec -it $NGINX_CONTAINER bash -c "echo '$GITEA_IP gitea' >> /etc/hosts" + + # 恢复使用主机名的配置 + sed -i "s/proxy_pass http:\/\/$GITEA_IP:3000;/proxy_pass http:\/\/gitea:3000;/" $NGINX_CONF_DIR/$DOMAIN.conf + + # 再次重新加载Nginx配置 + docker exec -it $NGINX_CONTAINER nginx -s reload + + if [ $? -ne 0 ]; then + echo "警告: Nginx配置仍然失败,请手动检查配置" + read -p "是否继续?[y/N]: " CONTINUE_NGINX + if [ "$CONTINUE_NGINX" != "y" ] && [ "$CONTINUE_NGINX" != "Y" ]; then + echo "安装已中断" + exit 1 + fi + fi +fi + +echo "===== Gitea安装完成 =====" +echo "请访问 https://$DOMAIN 完成初始化设置" +echo "初始化时,请使用以下数据库设置:" +echo "数据库类型:MySQL" +echo "主机:$MYSQL_CONTAINER_NAME:3306" +echo "用户名:gitea" +echo "密码:$GITEA_DB_PASSWORD" +echo "数据库名:gitea" + +echo "注意:首次访问时,您将被引导完成Gitea的初始化设置,包括创建管理员账户" \ No newline at end of file diff --git a/uninstall.sh b/uninstall.sh new file mode 100644 index 0000000..13e4c5d --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +# Gitea卸载脚本 +# 作者:AI助手 +# 日期:2025-03-13 + +set -e + +echo "===== Gitea卸载脚本 =====" +echo "此脚本将卸载Gitea服务及其相关配置" +echo "警告:此操作将删除Gitea的所有数据,请确保已备份重要数据" + +# 检查是否有root权限 +if [ "$(id -u)" != "0" ]; then + echo "此脚本需要root权限运行" 1>&2 + exit 1 +fi + +# 检查Nginx容器 +NGINX_CONTAINER=$(docker ps | grep nginx | head -1 | awk '{print $1}') +if [ -z "$NGINX_CONTAINER" ]; then + echo "警告: Nginx容器未找到,部分卸载步骤可能无法完成" 1>&2 +else + NGINX_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $NGINX_CONTAINER | sed 's/\///') + echo "找到Nginx容器: $NGINX_CONTAINER_NAME" + + # 检查Nginx容器的挂载点 + echo "检查Nginx容器的挂载点..." + SSL_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/ssl"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + CONF_MOUNT=$(docker inspect -f '{{range .Mounts}}{{if eq .Destination "/etc/nginx/conf.d"}}{{.Source}}{{end}}{{end}}' $NGINX_CONTAINER) + + if [ -z "$SSL_MOUNT" ]; then + echo "警告: 未找到Nginx容器的SSL挂载点,将使用默认路径" + SSL_MOUNT="/opt/dnmp/services/nginx/ssl" + else + echo "找到Nginx SSL挂载点: $SSL_MOUNT" + fi + + if [ -z "$CONF_MOUNT" ]; then + echo "警告: 未找到Nginx容器的配置挂载点,将使用默认路径" + CONF_MOUNT="/opt/dnmp/services/nginx/conf.d" + else + echo "找到Nginx配置挂载点: $CONF_MOUNT" + fi +fi + +# 设置变量 +DOMAIN="gitea.mzh.one" +NGINX_CONF_DIR="${CONF_MOUNT:-/opt/dnmp/services/nginx/conf.d}" +SSL_DIR="${SSL_MOUNT:-/opt/dnmp/services/nginx/ssl}/$DOMAIN" + +# 询问安装目录 +INSTALL_DIR="/opt/gitea" +read -p "请输入Gitea的安装目录 [默认: $INSTALL_DIR]: " INPUT_INSTALL_DIR +if [ ! -z "$INPUT_INSTALL_DIR" ]; then + INSTALL_DIR=$INPUT_INSTALL_DIR +fi + +# 检查安装目录是否存在 +if [ ! -d "$INSTALL_DIR" ]; then + echo "错误: 安装目录 $INSTALL_DIR 不存在" 1>&2 + exit 1 +fi + +# 确认卸载 +read -p "确定要卸载Gitea吗?此操作将删除所有数据 [y/N]: " CONFIRM +if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then + echo "卸载已取消" + exit 0 +fi + +# 停止并删除容器 +echo "停止并删除Gitea容器..." +cd $INSTALL_DIR +docker-compose down + +# 删除Nginx配置 +echo "删除Nginx配置..." +if [ -f "$NGINX_CONF_DIR/$DOMAIN.conf" ]; then + rm -f "$NGINX_CONF_DIR/$DOMAIN.conf" + + # 重新加载Nginx配置 + if [ ! -z "$NGINX_CONTAINER" ]; then + echo "重新加载Nginx配置..." + docker exec -it $NGINX_CONTAINER nginx -s reload + else + echo "警告: Nginx容器未找到,请手动重新加载Nginx配置" 1>&2 + fi +else + echo "警告: Nginx配置文件不存在: $NGINX_CONF_DIR/$DOMAIN.conf" +fi + +# 询问是否删除数据库 +read -p "是否删除Gitea数据库?[y/N]: " DELETE_DB +if [ "$DELETE_DB" == "y" ] || [ "$DELETE_DB" == "Y" ]; then + echo "删除Gitea数据库..." + MYSQL_CONTAINER=$(docker ps | grep -E 'mysql|mariadb' | head -1 | awk '{print $1}') + if [ ! -z "$MYSQL_CONTAINER" ]; then + MYSQL_CONTAINER_NAME=$(docker inspect --format='{{.Name}}' $MYSQL_CONTAINER | sed 's/\///') + echo "找到MySQL容器: $MYSQL_CONTAINER_NAME" + read -sp "请输入MySQL root密码: " MYSQL_ROOT_PASSWORD + echo "" + docker exec -i $MYSQL_CONTAINER mysql -uroot -p$MYSQL_ROOT_PASSWORD <&2 + fi +fi + +# 询问是否删除SSL证书 +read -p "是否删除SSL证书?[y/N]: " DELETE_CERT +if [ "$DELETE_CERT" == "y" ] || [ "$DELETE_CERT" == "Y" ]; then + echo "删除SSL证书..." + if [ -d "$SSL_DIR" ]; then + rm -rf "$SSL_DIR" + echo "SSL证书目录已删除: $SSL_DIR" + else + echo "警告: SSL证书目录不存在: $SSL_DIR" + fi + + # 询问是否删除Let's Encrypt证书 + read -p "是否同时删除Let's Encrypt证书?[y/N]: " DELETE_LE_CERT + if [ "$DELETE_LE_CERT" == "y" ] || [ "$DELETE_LE_CERT" == "Y" ]; then + certbot delete --cert-name $DOMAIN + fi +fi + +# 询问是否删除安装目录 +read -p "是否删除安装目录 $INSTALL_DIR?[y/N]: " DELETE_DIR +if [ "$DELETE_DIR" == "y" ] || [ "$DELETE_DIR" == "Y" ]; then + echo "删除安装目录..." + rm -rf $INSTALL_DIR +fi + +echo "===== Gitea卸载完成 =====" \ No newline at end of file