教程

快速把 Hexo 博客部署到 VPS 教程指南

2026-10-16 #Debian#Hexo

虽然 Hexo 的博客可以部署到 GitHub 、Cloudflare Pages 等免费服务上,但是如果你有一台访问超快的 VPS,也可以选择直接部署到自己的 VPS 上。

将 Hexo 博客部署到自己的 VPS 上,核心原理是在服务器上创建一个Git 裸仓库(Bare Repository),并通过 Git 的 post-receive 钩子(Hook),在每次本地执行 hexo d 推送静态文件时,自动将最新代码检出(Checkout)到 Web 服务器的网站根目录下。

以下是完整的手动配置流程,文末附带一键自动化部署脚本。

一、 手动配置步骤

假设你的服务器系统为 Debian / Ubuntu,目标是将博客源码推送到 /var/repo/hexo.git,并将生成的静态网页自动同步到 /var/www/hexo。

1. 安装 Git 并创建专用用户

在 VPS 上执行,出于安全考虑,限制 git 用户通过 SSH 登录交互式 Shell。

首先确保服务器已安装 Git,然后创建一个名为 git 的系统用户,并将其默认 Shell 修改为 git-shell(仅允许执行 Git 推送/拉取操作,禁止常规命令行登录)。

1
2
3
4
5
6
7
8
# 1. 安装 Git
sudo apt update && sudo apt install -y git

# 2. 将 git-shell 加入系统合法 shell 列表
which git-shell | sudo tee -a /etc/shells

# 3. 创建 git 用户并指定 shell 为 git-shell
sudo adduser --disabled-password --gecos "" --shell "$(which git-shell)" git

2. 配置 SSH 公钥免密登录

避免每次 hexo d 都需要输入服务器密码

在本地电脑上获取你的 SSH 公钥(如果还没有,先在本地运行 ssh-keygen 生成):

1
cat ~/.ssh/id_ed25519.pub
生成 SSH 私钥命令
1
ssh-keygen -t ed25519 -C "hexo-deploy"

回到 VPS 服务器,将复制的公钥写入 git 用户的授权列表中,并严格设置目录权限(权限不对会导致 SSH 验证失败):

1
2
3
4
5
6
sudo -u git mkdir -p /home/git/.ssh
echo "粘贴你本地的公钥内容" | sudo -u git tee -a /home/git/.ssh/authorized_keys

# 严格限制权限
sudo chmod 700 /home/git/.ssh
sudo chmod 600 /home/git/.ssh/authorized_keys

3. 初始化 Git 裸仓库与网站目录

裸仓库只保存 Git 版本历史,不保存工作区源文件

创建用于存放 Git 仓库的目录 /var/repo 和存放网页文件的目录 /var/www/hexo,并将所有权交给 git 用户, 钩子脚本有权限写入文件。

1
2
3
4
5
6
7
8
# 1. 创建并初始化裸仓库
sudo mkdir -p /var/repo
sudo chown git:git /var/repo
sudo -u git git init --bare /var/repo/hexo.git

# 2. 创建静态网页部署目录
sudo mkdir -p /var/www/hexo
sudo chown git:git /var/www/hexo

4. 编写 post-receive 自动同步钩子

实现推送即部署的核心步骤

当本地向裸仓库推送代码完成后,Git 会自动触发 hooks/post-receive 脚本。我们利用它将文件强制部署到 /var/www/hexo。

1
2
3
4
5
6
7
8
# 创建并写入钩子内容
sudo -u git tee /var/repo/hexo.git/hooks/post-receive >/dev/null << 'EOF'
#!/bin/sh
git --work-tree=/var/www/hexo --git-dir=/var/repo/hexo.git checkout -f
EOF

# 赋予可执行权限(极其重要,否则钩子不会生效)
sudo chmod +x /var/repo/hexo.git/hooks/post-receive

5. 配置本地 Hexo 并推送测试

在你的本地电脑博客根目录下操作

首先确保本地安装了 Git 部署插件:

1
npm install hexo-deployer-git --save

打开本地 Hexo 根目录下的 _config.yml 文件,修改文末的 deploy 配置项:

1
2
3
4
deploy:
type: git
repo: git@你的服务器IP或域名:/var/repo/hexo.git
branch: master

保存后,在本地终端执行三连命令即可完成发布:

1
hexo clean && hexo g && hexo d

推送成功后,去服务器的 /var/www/hexo 目录下查看,你会发现静态网页文件已经全部自动生成好了。随后只需用 Nginx 或 Caddy 将网站根目录指向 /var/www/hexo 即可访问。

进阶:一键自动化部署脚本

如果你觉得上述手动步骤太繁琐,或者后续还想在同一台 VPS 上快速部署其他静态站点(如 VitePress、Hugo、纯静态主页等),可以直接在服务器上使用下面整理好的自动化脚本。

脚本亮点

  • 幂等性设计:可重复执行,已存在的用户、公钥或目录会自动跳过,方便随时新增第二个、第三个静态站点仓库。
  • 安全隔离:自动配置 git-shell 与严格的 .ssh 权限,无需手动切换用户调整 chown / chmod。
  • 灵活传参:既支持命令行直接传参(如 ./git-deploy-repo.sh hexo /var/www/hexo),也支持不带参数交互式运行。

使用方法

  1. 登录 VPS,创建脚本文件 git-deploy-repo.sh:

    1
    vim git-deploy-repo.sh
  2. 将下方完整代码粘贴进去(注意将第 12 行的 PUBKEY 替换为你本地电脑的真实 SSH 公钥):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    #!/bin/bash

    # 用 git + post-receive hook 部署静态站点(如 Hexo)
    # 用法:git-deploy-repo.sh [repo 名] [部署目录]
    # 例:git-deploy-repo.sh hexo /var/www/hexo
    # 不带参数时交互输入。可重复执行,用于快速新增不同的 repo。

    set -u

    GIT_USER="git"
    REPO_ROOT="/var/repo"
    PUBKEY="PUBKEY"

    # ── sudo 包装:非 root 自动加 sudo ────────────────────────────────
    if [ "$(id -u)" -eq 0 ]; then
    SUDO=""
    else
    if command -v sudo >/dev/null 2>&1; then
    SUDO="sudo"
    else
    echo "需要 root 权限,但未找到 sudo。请以 root 身份执行。" >&2
    exit 1
    fi
    fi

    # 以 git 用户身份执行命令(root 下用 runuser,否则用 sudo -u)
    as_git() {
    if [ "$(id -u)" -eq 0 ]; then
    runuser -u "$GIT_USER" -- "$@"
    else
    sudo -u "$GIT_USER" "$@"
    fi
    }

    if ! command -v git >/dev/null 2>&1; then
    echo "未找到 git,正在安装..."
    $SUDO apt update && $SUDO apt install -y git || exit 1
    fi

    # ── 参数 ──────────────────────────────────────────────────────────
    REPO_NAME="${1:-}"
    if [ -z "$REPO_NAME" ]; then
    read -r -p "repo 名称(如 hexo): " REPO_NAME </dev/tty
    fi
    REPO_NAME="${REPO_NAME%.git}"
    if [ -z "$REPO_NAME" ]; then
    echo "repo 名称不能为空。" >&2
    exit 1
    fi

    WORK_TREE="${2:-}"
    if [ -z "$WORK_TREE" ]; then
    read -r -p "部署目录 [默认 /var/www/$REPO_NAME]: " WORK_TREE </dev/tty
    WORK_TREE="${WORK_TREE:-/var/www/$REPO_NAME}"
    fi

    REPO_DIR="$REPO_ROOT/$REPO_NAME.git"

    # ── 1. git 用户 ───────────────────────────────────────────────────
    GIT_SHELL="$(command -v git-shell)"
    if [ -z "$GIT_SHELL" ]; then
    echo "未找到 git-shell。" >&2
    exit 1
    fi
    if ! grep -qx "$GIT_SHELL" /etc/shells; then
    echo "$GIT_SHELL" | $SUDO tee -a /etc/shells >/dev/null
    fi

    if id "$GIT_USER" >/dev/null 2>&1; then
    echo "用户 $GIT_USER 已存在,跳过创建。"
    else
    $SUDO adduser --disabled-password --gecos "" --shell "$GIT_SHELL" "$GIT_USER" || exit 1
    echo "已创建用户 $GIT_USER。"
    fi

    if [ "$(getent passwd "$GIT_USER" | cut -d: -f7)" != "$GIT_SHELL" ]; then
    $SUDO usermod -s "$GIT_SHELL" "$GIT_USER"
    echo "已将 $GIT_USER 的 shell 设为 $GIT_SHELL。"
    fi

    # ── 2. SSH 公钥 ───────────────────────────────────────────────────
    GIT_HOME="$(getent passwd "$GIT_USER" | cut -d: -f6)"
    AUTH_KEYS="$GIT_HOME/.ssh/authorized_keys"

    as_git mkdir -p "$GIT_HOME/.ssh"
    as_git touch "$AUTH_KEYS"
    if $SUDO grep -qF "$PUBKEY" "$AUTH_KEYS"; then
    echo "公钥已存在,跳过。"
    else
    echo "$PUBKEY" | as_git tee -a "$AUTH_KEYS" >/dev/null || exit 1
    echo "已添加公钥。"
    fi
    $SUDO chmod 700 "$GIT_HOME/.ssh"
    $SUDO chmod 600 "$AUTH_KEYS"

    # ── 3. 裸仓库 ─────────────────────────────────────────────────────
    $SUDO mkdir -p "$REPO_ROOT"
    $SUDO chown "$GIT_USER:$GIT_USER" "$REPO_ROOT"

    if [ -d "$REPO_DIR" ]; then
    echo "仓库 $REPO_DIR 已存在,跳过 init。"
    else
    as_git git init --bare "$REPO_DIR" || exit 1
    fi

    # ── 4. 部署目录 ───────────────────────────────────────────────────
    $SUDO mkdir -p "$WORK_TREE"
    $SUDO chown "$GIT_USER:$GIT_USER" "$WORK_TREE"

    # ── 5. post-receive hook ──────────────────────────────────────────
    HOOK="$REPO_DIR/hooks/post-receive"
    as_git tee "$HOOK" >/dev/null << EOF
    #!/bin/sh
    git --work-tree="$WORK_TREE" --git-dir="$REPO_DIR" checkout -f
    EOF
    $SUDO chmod +x "$HOOK"

    echo
    echo "完成:"
    echo " 仓库:$REPO_DIR"
    echo " 部署:$WORK_TREE"
    echo " 远程地址:$GIT_USER@$(hostname -f 2>/dev/null || hostname):$REPO_DIR"
    echo " Hexo _config.yml 中 deploy.repo 填上面的远程地址即可。"
  3. 赋予执行权限并运行:

    1
    2
    chmod +x git-deploy-repo.sh
    ./git-deploy-repo.sh hexo /var/www/hexo
评论
分享

评论