使用 GitHub Webhook 执行自动化 Hugo 部署

众所周知,我搭了个静态部落格,那每次我都要手动生成网站也太麻烦了,于是我就想方设法搞自动部署出来。

首先写一个 PHP 页面,用来接收 WebHook 。为什么要用 PHP 呢,用别的不行吗?当然可以,只是我因为跑了 Chevereto 本身就要跑一个 php-fpm 所以我不如干脆也用 PHP 来写接收好了。

<?php
    if (isset($_GET) && isset($_GET["token"]) && $_GET["token"] === "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") {
        if (isset($_SERVER["X-GitHub-Event"]) && $_SERVER["X-GitHub-Event"] === "push") {
            echo "{\"status\": 200, \"result\": ".json_encode(shell_exec("export XDG_RUNTIME_DIR=/run/user/$(id -u user) && sudo -u user /usr/bin/systemctl --user start pull-blog.service && sudo -u user /usr/bin/journalctl --user -u pull-blog.service -n 20 --no-pager"))."}";

        } else {
                echo "{\"status\": 200}";
        }
    } else {
        http_response_code(403);
    }
?>

那我们怎么把部落格的内容重新拉下来呢?很简单,用一个 service 到时候去用 systemctl 呼叫就行了。

首先创建一个 pull-blog.service 文件在 ~/.config/systemd/user 中 (本例中个人用户名为 user)

[Unit]
Description=Blog Deploy Service

[Service]
Type=oneshot
ExecStart=/usr/bin/git pull
ExecStart=/usr/bin/git submodule update --init
ExecStart=/usr/bin/rm -rf $WEBROOT/public
ExecStart=/opt/hugo/hugo -d $WEBROOT/public
WorkingDirectory=/home/user/blog

接着使用 systemctl --user daemon-reload 重新载入用户自定义的服务

然后找到 php-fpm 所使用的用户,本例为 http

使用 sudo visudo 将以下几行添加到 sudoers 文件中 man

Defaults:http env_keep=XDG_RUNTIME_DIR
http ALL= (user) NOPASSWD: /usr/bin/systemctl --user start pull-blog.service, \
    /usr/bin/journalctl --user -u pull-blog.service -n 20 --no-pager

这样 php-fpm 就有权限使用如上的命令了,同时也会回报命令的执行情况给 WebHook 。

Tips

使用如下命令可以绕过 /usr/sbin/nologin 1

su -s /bin/bash -c '/path/to/your/script' testuser