--- type: backend project: 通用 status: doing module: 后端文档 tags: - backend - 后端文档 created: 2026-06-09 updated: 2026-06-09 sensitive: false --- ## 如何使用 Gogs 设置 Git 钩子(Git Hooks)来实现项目的自动化部署 **使用 Webhooks**:这是 Gogs 官方推荐的、更现代、更灵活的方式。它通过 HTTP 请求通知你的服务器进行部署。这种方法的核心思想是:当 Gogs 收到 `git push` 时,它会向你配置的一个 URL 发送一个带有提交信息的 POST 请求。你的 Web 服务器上需要有一个小的应用一直监听这个 URL,收到请求后执行部署脚本。 ### 步骤 1: 准备部署脚本 (deploy.sh) 首先,确保你已经有一个可以正常工作的部署脚本,就像上一个回答中提到的那样。我们假设它位于 `/home/myuser/deploy.sh`。 ```sh #!/bin/bash # /home/myuser/deploy.sh set -e PROJECT_DIR="/usr/local/nginx/html/huahuibao" GIT_BRANCH="dev" echo "======== [Webhook GO] 部署开始 `date` ========" cd $PROJECT_DIR unset GIT_DIR /usr/local/git/bin/git reset --hard /usr/local/git/bin/git pull origin $GIT_BRANCH cd # ... 其他构建或重启命令 ... # 例如: # echo "正在重启服务..." # sudo systemctl restart my-app echo "======== [Webhook dev分支] 部署成功 `date` ========" ``` ### 步骤 2: Go 语言 Webhook 监听服务代码 此代码放在测试服 /root/Code/go/gogs-webhook-listener 目录下 创建一个名为 `gogs-webhook-listener` 的文件夹,并在其中创建一个 `main.go` 文件。 ```Go package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "io" "log" "net/http" "os" "os/exec" ) // --- 配置项 --- // 这些值可以硬编码,也可以通过环境变量或配置文件传入 const ( // Webhook 监听地址和端口 listenAddr = "0.0.0.0:8000" // Gogs Webhook 中设置的密钥,!!务必修改为你的密钥!! gogsSecret = "gogs_secret_key-xhb*2025" // 要执行的部署脚本路径 deployScriptPath = "/root/sh/gogs_deploy.sh" // 只对这个分支的 push 事件做出反应 targetBranch = "refs/heads/dev" // Webhook 访问路径 webhookPath = "/webhook" ) // GogsPushPayload 定义了我们关心的 Gogs push 事件的 JSON 结构体字段 type GogsPushPayload struct { Ref string `json:"ref"` // The full git ref that was pushed. Example: "refs/heads/master". } func main() { http.HandleFunc(webhookPath, handleWebhook) log.Printf("Gogs Webhook 监听服务已启动,地址: http://%s%s\n", listenAddr, webhookPath) if err := http.ListenAndServe(listenAddr, nil); err != nil { log.Fatalf("启动 HTTP 服务失败: %v", err) } } // handleWebhook 是处理所有进入 webhookPath 的请求的函数 func handleWebhook(w http.ResponseWriter, r *http.Request) { // 1. 检查请求方法是否为 POST if r.Method != http.MethodPost { log.Printf("无效的请求方法: %s", r.Method) http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) return } // 2. 读取请求体 body, err := io.ReadAll(r.Body) if err != nil { log.Printf("读取请求体失败: %v", err) http.Error(w, "Internal server error", http.StatusInternalServerError) return } defer r.Body.Close() // 3. 验证签名 (关键安全步骤) gogsSignature := r.Header.Get("X-Gogs-Signature") if !isValidSignature(body, gogsSecret, gogsSignature) { log.Println("签名验证失败!请求来源可疑。") http.Error(w, "Invalid signature", http.StatusUnauthorized) return } // 4. 检查是否为 'push' 事件 if r.Header.Get("X-Gogs-Event") != "push" { log.Println("接收到非 push 事件,已忽略。") w.WriteHeader(http.StatusOK) fmt.Fprint(w, "Not a push event, ignored.") return } // 5. 解析 JSON 并检查分支 var payload GogsPushPayload if err := json.Unmarshal(body, &payload); err != nil { log.Printf("解析 JSON payload 失败: %v", err) http.Error(w, "Invalid payload", http.StatusBadRequest) return } if payload.Ref != targetBranch { log.Printf("接收到对分支 '%s' 的 push,已忽略。目标分支为 '%s'。", payload.Ref, targetBranch) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "Push to branch %s ignored.", payload.Ref) return } // 6. 执行部署脚本 log.Printf("验证通过,开始执行部署脚本: %s", deployScriptPath) cmd := exec.Command("sh", deployScriptPath) // 将脚本的标准输出和标准错误输出重定向到 Go 程序的日志 cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Printf("执行部署脚本失败: %v", err) http.Error(w, "Deployment script execution failed", http.StatusInternalServerError) return } log.Println("部署脚本执行成功。") w.WriteHeader(http.StatusOK) fmt.Fprint(w, "Deployment triggered successfully.") } // isValidSignature 验证 Gogs 的 HMAC-SHA256 签名 func isValidSignature(body []byte, secret, signature string) bool { if signature == "" { return false } mac := hmac.New(sha256.New, []byte(secret)) mac.Write(body) expectedMAC := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(signature), []byte(expectedMAC)) } ``` ### 步骤 3: 编译和运行 代码放在测试服 /root 目录下 1. **初始化 Go Module** (如果你还没有的话) 在 `gogs-webhook-listener` 目录下执行: ```Bash go mod init gogs-webhook-listener ``` 2. **构建二进制文件** 这个命令会生成一个名为 `gogs-webhook-listener` 的可执行文件。 ```Bash go build . ``` 3. **运行服务** 可以直接在前台运行进行测试: ```Bash ./gogs-webhook-listener ``` 你应该会看到日志输出: `Gogs Webhook 监听服务已启动,地址: http://0.0.0.0:8000/webhook` ### 步骤 4: 设置为后台服务 (推荐使用 Systemd) 为了让这个服务在服务器上长期稳定地运行,并能开机自启,最好将它配置成一个 `systemd` 服务。 1. 创建 service 文件: ``` vim /etc/systemd/system/gogs-webhook.service ``` 2. 写入以下内容。注意修改 `User` 和 `ExecStart` 的路径。 ``` [Unit] Description=Gogs Webhook Listener for Auto Deployment After=network.target [Service] Type=simple # 建议创建一个专门的用户来运行此服务 User=root # ExecStart 指向你编译好的二进制文件的绝对路径 ExecStart=/root/Code/go/gogs-webhook-listener/gogs-webhook-listener Restart=on-failure RestartSec=5s [Install] WantedBy=multi-user.target ``` 3. 重载 `systemd` 并启动服务: ``` systemctl daemon-reload systemctl start gogs-webhook.service ``` 4. 检查服务状态: ``` systemctl status gogs-webhook.service ``` 如果一切正常,它应该显示 `active (running)`。 5. 设置开机自启: ``` systemctl enable gogs-webhook.service ```