461 lines
13 KiB
Bash
461 lines
13 KiB
Bash
#!/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 <<EOF
|
||
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_CONTAINER_NAME:3306
|
||
- GITEA__database__NAME=gitea
|
||
- GITEA__database__USER=gitea
|
||
- GITEA__database__PASSWD=$GITEA_DB_PASSWORD
|
||
- GITEA__server__DOMAIN=$DOMAIN
|
||
- GITEA__server__ROOT_URL=https://$DOMAIN/
|
||
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:
|
||
- $DOCKER_NETWORK
|
||
|
||
networks:
|
||
$DOCKER_NETWORK:
|
||
external: true
|
||
EOF
|
||
|
||
# 创建Nginx配置
|
||
echo "创建Nginx配置..."
|
||
cat > conf/nginx/conf.d/$DOMAIN.conf <<EOF
|
||
server {
|
||
listen 80;
|
||
server_name $DOMAIN;
|
||
|
||
# 将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 $DOMAIN;
|
||
|
||
# SSL证书配置
|
||
ssl_certificate /ssl/$DOMAIN/$DOMAIN.pem;
|
||
ssl_certificate_key /ssl/$DOMAIN/$DOMAIN.key;
|
||
ssl_session_timeout 5m;
|
||
ssl_protocols TLSv1.2 TLSv1.3;
|
||
ssl_ciphers HIGH:!aNULL:!MD5;
|
||
ssl_prefer_server_ciphers on;
|
||
|
||
# 反向代理到Gitea服务
|
||
location / {
|
||
# 使用容器IP而不是主机名,避免DNS解析问题
|
||
resolver 127.0.0.11 valid=30s;
|
||
set \$upstream gitea;
|
||
proxy_pass http://\$upstream: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;
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# 创建Gitea配置
|
||
echo "创建Gitea配置..."
|
||
# 生成随机密钥
|
||
SECRET_KEY=$(openssl rand -hex 16)
|
||
INTERNAL_TOKEN=$(openssl rand -hex 16)
|
||
LFS_JWT_SECRET=$(openssl rand -hex 16)
|
||
|
||
cat > conf/gitea/app.ini <<EOF
|
||
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 = $DOMAIN
|
||
SSH_DOMAIN = $DOMAIN
|
||
HTTP_PORT = 3000
|
||
ROOT_URL = https://$DOMAIN/
|
||
DISABLE_SSH = false
|
||
SSH_PORT = 22
|
||
SSH_LISTEN_PORT = 22
|
||
LFS_START_SERVER = true
|
||
LFS_CONTENT_PATH = /data/git/lfs
|
||
LFS_JWT_SECRET = $LFS_JWT_SECRET
|
||
OFFLINE_MODE = false
|
||
|
||
[database]
|
||
PATH = /data/gitea/gitea.db
|
||
DB_TYPE = mysql
|
||
HOST = $MYSQL_CONTAINER_NAME:3306
|
||
NAME = gitea
|
||
USER = gitea
|
||
PASSWD = $GITEA_DB_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 = $SECRET_KEY
|
||
INTERNAL_TOKEN = $INTERNAL_TOKEN
|
||
|
||
[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.$DOMAIN
|
||
|
||
[mailer]
|
||
ENABLED = false
|
||
|
||
[openid]
|
||
ENABLE_OPENID_SIGNIN = true
|
||
ENABLE_OPENID_SIGNUP = true
|
||
|
||
[ui]
|
||
DEFAULT_THEME = auto
|
||
THEMES = auto,gitea,arc-green
|
||
EOF
|
||
|
||
# 创建数据库
|
||
echo "创建Gitea数据库..."
|
||
cat > create_db.sql <<EOF
|
||
CREATE DATABASE IF NOT EXISTS gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
CREATE USER IF NOT EXISTS 'gitea'@'%' IDENTIFIED BY '$GITEA_DB_PASSWORD';
|
||
GRANT ALL PRIVILEGES ON gitea.* TO 'gitea'@'%';
|
||
FLUSH PRIVILEGES;
|
||
EOF
|
||
|
||
docker exec -i $MYSQL_CONTAINER mysql -uroot -p$MYSQL_ROOT_PASSWORD < create_db.sql
|
||
if [ $? -ne 0 ]; then
|
||
echo "错误: 创建数据库失败,请检查MySQL root密码是否正确" 1>&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的初始化设置,包括创建管理员账户" |