部署hexo到VPS

将 Hexo 部署到 GitHub Pages 上之后,发现访问速度较慢,并且有时侯GitHub 会被墙,访问不了,又折腾了一下将hexo部署到了vps,资料都是从网上查到的,这里做一下整理记录

准备工作

环境准备:

  • vps服务器一台,我这里使用的是Racknerd 最便宜的1c1g,14刀每年, 系统随便,我用的是CentOs7
  • 域名,我用的是 namesilo 也是因为便宜,并且不需要备案

网上部署方案有两种:

  • 将 Hexo 项目上传到 VPS 上面后执行 hexo server,之后配置 Nginx 反向代理,让域名指向 http://localhost:4000
  • 将 Hexo 在本地通过 hexo g 生成静态文件,在通过 hexo d 部署到 VPS 上面,使用 Nginx 直接做 Web 服务器。

相比第二种方式,第一种每次写博客与更新博客时候的操作会很繁琐。这里就只使用第二种方式进行部署,这样既可以将静态文件 deploy 到 VPS 上,也可以上传到 Github 上用作备份,操作性和安全性上都比第一种要高。

而对于第二种方式而言,常用的又有 git hookrsync 两种自动部署解决方案。

本文主要介绍 git hook 部署过程。

Git Hooks 自动部署

部署原理

我们在本地编辑文本,然后使用 Git 远程部署到 VPS 的 Git 仓库。hexo d 命令实际上只 deploy 了本地的 public 文件夹,Git Hooks 实际上就是当 Git 仓库收到最新的 push 时,将 Git 仓库接受到的内容复制到 VPS 上的网站目录内。相当于完成了手动将 public 文件夹复制到 VPS 的网站根目录里。

安装配置 Git

安装 Git

通过 SSH 连接 VPS,执行:yum install git,完成后通过 git --version 查看 Git 版本,若显示版本信息则说明安装成功。

创建 git 用户

执行:adduser git,根据提示设置密码。

赋予 git 用户 sudo 权限

执行:

1
2
chmod 740 /etc/sudoers
vim /etc/sudoers

找到以下内容:

1
2
# User privilege specification
root ALL=(ALL:ALL) ALL

root ALL=(ALL:ALL) ALL 这一行下面添加 git ALL=(ALL:ALL) ALL

保存退出后,修改回文件权限:

1
chmod 440 /etc/sudoers

关闭 git 用户 shell 权限

我们也可以通过:

1
ssh git@VPS IP

ssh 连接服务器,登录到服务器上,对服务器进行各种操作,这通常很不安全,也不合适,我们只需要能对仓库操作就可以了,不需要更大的权限。

因此我们关闭 git 用户 shell 权限,执行:

1
vim /etc/passwd

将最后一行的 git:x:1001:1001:,,,:/home/git:/bin/bash 修改为 git:x:1001:1001:,,,:/home/git:/usr/bin/git-shell

这样,git 用户可以正常通过 ssh 使用 git,但无法登录 shell,因为我们为 git 用户指定的 git-shell 每次一登录就自动退出

初始化 git 仓库

1
2
3
4
cd /home/git                //切换到git用户目录
mkdir blog.git //创建git仓库文件夹,以blog.git为例
cd blog.git //进入仓库目录
git init --bare //使用--bare参数初始化为裸仓库,这样创建的仓库不包含工作区

注意:裸仓库没有工作区,因为服务器上的 Git 仓库纯粹是为了共享,所以不让用户直接登录到服务器上去改工作区,并且服务器上的 Git 仓库通常都以.git 结尾。

创建网站目录

1
2
mkdir -p  /var/www/blog
cd /var/www/blog //创建网站目录,以blog为例

配置 SSH

1
2
3
4
cd /home/git                //切换到git用户目录
mkdir .ssh //创建.ssh目录
cd .ssh
vim authorized_keys

然后将本地的公钥复制到 authorized_keys 文件里 (公钥即本地执行 cat ~/.ssh/id_rsa.pub 查看的内容)。

注意:收集所有需要登录的用户的公钥,就是他们自己的 id_rsa.pub 文件,把所有公钥导入到 /home/git/.ssh/authorized_keys 文件里,一行一个。

用户组管理

1
2
ll /home/git/
ll /var/www/

确保 blog.git.sshblog 目录的用户组权限为 git:git,若不是,执行下列命令:

修改用户权限的命令:

1
chown -R 用户名.组名 /目录
1
2
3
chown -R git.git /home/git/blog.git/
chown -R git.git /home/git/.ssh/
chown -R git.git /var/www/blog/

安装配置 nginx

安装 nginx

执行:yum install nginx,若输入 nginx -V 可以看到 nginx 版本信息,则安装成功。

配置 nginx

https参考配置文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 443 ssl http2;
listen [::]:443 http2;
ssl_certificate /data/xxx.crt;//换成自己的
ssl_certificate_key /data/xxx.key;//换成自己的
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers xxxx;//换成自己的
server_name www.xxxxx.com; //换成自己的域名
index index.html index.htm;
root /var/www/blog;
error_page 400 = /400.html;
error_page 404 = /404.html;

# Config for 0-RTT in TLSv1.3
ssl_early_data on;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=31536000";
}

保存退出后,启动 nginx:

1
systemctl start nginx

设置开机自动启动:

1
systemctl enable nginx

查看运行状态:

1
systemctl status nginx

显示 running 表示成功运行。

配置 Git Hooks

创建 post-receive 文件

git 用户下执行(这里我用 root 用户执行上述命令,然后更改了文件所有者为 git.git):

1
2
cd /home/git/blog.git/hooks     //切换到hooks目录下
vim post-receive //创建文件

复制下面的内容到 post-receive 文件中:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash
echo "post-receive hook is running..."

GIT_REPO=/home/git/blog.git
TMP_GIT_CLONE=/tmp/blog
PUBLIC_WWW=/var/www/blog

rm -rf ${TMP_GIT_CLONE}
git clone $GIT_REPO $TMP_GIT_CLONE
rm -rf ${PUBLIC_WWW}/*
cp -rf ${TMP_GIT_CLONE}/* ${PUBLIC_WWW}

为什么不直接将裸仓库克隆到 Web 根目录下呢?我之前也一直被这个问题困扰,感觉先克隆到 tmp 目录再拷贝到 Web 根目录是多此一举。后来我觉得可能是出于项目安全的考虑,在执行 cp 命令的时候,.git 作为隐藏目录不会被拷贝到 Web 根目录下,也就避免了将整个仓库历史暴露在 Web 服务中。

赋予可执行权限:

1
chmod +x post-receive

本地操作

尝试连接

在本地打开 Git Bash:

1
ssh git@VPS的ip

若默认端口不是 22,则需要在后面加上 -p 端口号

或者在.ssh 文件夹下创建一个 config 文件,内容如下:

1
2
3
4
5
Host 服务器IP
HostName 服务器IP
User git
Port 端口号
IdentityFile ~/.ssh/id_rsa

这里可能会出现以下错误:

1
2
3
4
5
6
7
8
9
10
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:NgaCW7iTlWetUGGkX1uHepNs88G/pCYa9zrDouTQvhM.
Please contact your system administrator.
Add correct host key in /c/Users/dta05/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /c/Users/dta05/.ssh/known_hosts:6
ECDSA host key for [167.xxx.xxx.xxx]:2022 has changed and you have requested strict checking.
Host key verification failed.

原因分析:

It is also possible that a host key has just been changed.

我之前对 ssh 服务器重装了系统,导致所有与原系统建立过 ssh 连接的系统都无法再建立连接,因为在于原系统建立首次连接时,双方相互记录了对方的公钥(ssh 基于非对称密钥技术),在 ssh 服务主机重装系统后,公钥改变了,任以旧版本公钥的主机自然是无法与新系统连接的。

网上还有分析为 ssh 主机被人黑了,并在消除入侵记录时对 known_hosts 文件做了改动。

解决方案:

删除 ~/.ssh/known_hosts 文件,或者如果你可以判断出 known_hosts 中原 ssh 服务器的公钥,删去那部分,

然后再次建立新的连接,即可获得新的公钥。

配置 Hexo

打开本地博客根目录下的_config.yml 文件,找到最后的 deploy 配置,修改为:

1
2
3
4
5
6
7
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
# repo: git@VPS IP:/~/blog.git # 默认端口生效使用
# repo: ssh://git@VPS IP:端口/~/blog.git # 默认端口不生效使用,设置端口
branch: master

hexo 建站就全部配置部署完毕了