云部署个人博客

准备与了解:

  • 本地部署 –>参考链接
  • Nginx反向代理
  • 域名解析
  • ssl证书配置

本地虚拟机部署

  • 准备一个虚拟机

参考:
nginx:Linux 软件包 — nginx: Linux packages
新手指南 — Beginner’s Guide

安装Nginx

1
apt install nginx

启动Nginx,正常启动不会有任何输出

1
nginx

查看配置

1
nginx -V

通过apt安装的nginx,其相关文件分布

1
2
3
全局conf: /etc/nginx/nignx.conf
默认conf: /etc/nginx/sites-available/default
prefix: /usr/share/nginx

建立软连接

1
2
3
4
ls -l /usr/share/nginx # 检查html是否有建立软连接
# 如果没有建立软连接
rm -rf ./html
ln -s /var/www/html html

安装nodejs,这里我使用的时node.js v18

1
2
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo bash -
sudo apt-get install -y nodejs

全局安装Hexo

1
npm install hexo -g

使用hexo初始化一个博客,并启动博客

1
2
3
4
hexo init blog_hexo
cd blog_hexo
npm install
npm s

打开<ip>:4000,即可看到博客初始欢迎页

将博客部署到nginx上

1
2
3
cd blog_hexo
hexo g
cp -r public/* /var/www/html/

打开网页,此时便是默认用80端口来访问博客

如果要用一键部署的话,需要安装Hexo插件hexo,然后修改_config.yml,使用命令hexo d即可。这里略过

SFTP部署博客

https://hexo.io/zh-cn/docs/one-command-deployment.html#SFTP

安装 hexo-deployer-sftp。 通过 SFTP 部署站点,允许使用 ssh-agent 进行无密码连接。

1
$ npm install hexo-deployer-sftp --save

可配置内容:

1
2
3
4
5
6
7
8
9
10
deploy:  
type: sftp
host: 192.168.10.110
user: halofu
pass: root
remotePath: /home/halofu/
port: 22
privateKey: [用户ssh私钥路径] # ssh 会自动读取
passphrase: [passphrase]
agent: [path/to/agent/socket]
选项 描述 默认值
host 远程主机的地址
port 端口 22
user 使用者名称
pass 密码
privateKey SSH 私钥的目录地址
passphrase 私钥的可选密码
agent ssh套接字的目录地址 $SSH_AUTH_SOCK
remotePath 远程主机的根目录 /
concurrency 同时处理的 SFTP 任务的最大数量 100

登录方式

方式1 :使用密码登录

方式2:免密登录

  1. 将本地公钥追加到服务器的~/.ssh/authorized_keys文件中
  2. 如果私钥的默认开头为OPENSSH(新版),需要使用旧版更兼容的私钥格式pem
1
2
3
cd C:/Users/<user>/.ssh
cp id_rsa id_rsa.pem
ssh-keygen -p -m pem -f id_rsa.pem

此时如果在初次密钥对生成的时候没有设置密码,就可以一路回车下去即可。

hexo的sftp免密配置如下

1
2
3
4
5
6
- type: sftp
  host: 192.168.10.110
  user: root
  privateKey: C:/Users/lxp13/.ssh/id_rsa.pem
  remotePath: /home/halofu/test
  port: 22

Rsync

版本:Rsync 3.0.0

对于频繁更新的人来说,使用rsync来同步可以更快。rsync时比较本地与远程的异同,只有出现不一致的时候才会同步该文件。默认同步时,如果远程有多余文件会自动删除

安装:

1
npm install hexo-deployer-rsync --save
1
2
3
4
5
6
7
8
9
10
11
12
13
14
deploy:
type: rsync
host: <host>
user: <user>
root: <root> # 上传的根目录
port: 22
delete: true # 默认删除远程旧文件
progress: [true|false] # 默认展示进程
args: [rsync args] # Rsync的参数(支持空格分隔字符串)
rsh: [指定要使用的远程shell]
key: [用户ssh私钥路径] # ssh 会自动读取
verbose: true # 显示调试信息
ignore_errors: [true|false] # Default is false
create_before_update: [true|false] # Default is false
  • ignore_errors:忽略错误
  • create_before_update:首先创建不存在的文件,然后更新现有文件

如果没有在本地用ssh生成过密钥对,可以先生成一遍:

1
2
3
ssh-keygen -t ed25519 -C "your_email@example.com"  # 推荐
# 或者用 RSA
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

密钥对默认放在~/.ssh下。Windows则为用户目录下的.ssh

将密钥对的公钥上传到服务器

1
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server.com

或者则追加公钥内容到服务器下目标用户目录的.ssh/authorized_keys

首次建立连接时,本地客户端会自动将服务器主机公钥写入到know_hosts

问题-缺少rsync

Windows下运行可能会报以下错误:

1
2
3
4
5
Error: Spawn failed  
at ChildProcess.<anonymous> (H:\VSCODE\Blog\node_modules\hexo-util\lib\spawn.js:51:21)
at ChildProcess.emit (node:events:513:28)
at cp.emit (H:\VSCODE\Blog\node_modules\cross-spawn\lib\enoent.js:34:29)
at ChildProcess._handle.onexit (node:internal/child_process:291:12)

这是由于Windows没有rsync导致的,下载一个客户端,解压后将bing目录添加系统环境变量PATH里,然后重开git,输入rsync --version有响应则安装成功

问题-rsync调用的ssh版本不一致

1
2
3
Error: dup() in/out/err failed
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(232) [sender=3.4.1]

原因: Windows的ssh 的版本和 rsync 的版本不匹配。

先看Windows的ssh 的版本

1
2
ssh -V
# 输出: OpenSSH_9.7p1, OpenSSL 3.2.1 30 Jan 2024

然后到手动安装的rsync的bin目录下

1
2
./ssh.exe -V
# 输出:OpenSSH_10.0p2, OpenSSL 3.0.16 11 Feb 2025

指定rsync使用自己的ssh:

1
rsync -a -e "D:/Software/rsync/bin/ssh.exe" test.txt root@192.168.10.110:/root/

但这样部署不方便,直接修改插件源码deployer.js

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
'use strict';

const color = require('picocolors');
const { spawn } = require('hexo-util');
const pathFn = require('path');

module.exports = function(args) {
  if (!args.host || !args.user || !args.root) {
    let help = '';
    help += 'You should configure deployment settings in _config.yml first!\n\n';
    help += 'Example:\n';
    help += '  deploy:\n';
    help += '    type: rsync\n';
    help += '    host: <host>\n';
    help += '    user: <user>\n';
    help += '    root: <root>\n';
    help += '    port: [port] # Default is 22\n';
    help += '    delete: [true|false] # Default is true\n';
    help += '    progress: [true|false] # Default is true\n';
    help += '    args: <rsync args>\n';
    help += '    rsh: <remote shell>\n';
    help += '    key: <key>\n';
    help += '    verbose: [true|false] # Default is true\n';
    help += '    ignore_errors: [true|false] # Default is false\n';
    help += '    create_before_update: [true|false] # Default is false\n';
    help += '    rsync_ssh_path: <rsync client ssh path> # Default false\n\n ';
    help += 'For more help, you can check the docs: ' + color.underline('https://hexo.io/docs/deployment.html');
    console.log(help);
    return;
  }

  if (!Object.prototype.hasOwnProperty.call(args, 'delete')) args.delete = true;
  if (!Object.prototype.hasOwnProperty.call(args, 'verbose')) args.verbose = true;
  if (!Object.prototype.hasOwnProperty.call(args, 'progress')) args.progress = true;
  if (!Object.prototype.hasOwnProperty.call(args, 'ignore_errors')) args.ignore_errors = false;
  if (!Object.prototype.hasOwnProperty.call(args, 'create_before_update')) args.create_before_update = false;
  if (!Object.prototype.hasOwnProperty.call(args, 'rsync_ssh_path')) args.rsync_ssh_path = false;

// const rsync_ssh_path = "D:/Software/cwrsync_6.4.2/bin/ssh.exe";
  const params = [
    '-az',
    args.rsync_ssh_path ?'-e'+args.rsync_ssh_path:'',
    process.platform === 'win32' ? pathFn.basename(this.public_dir) + '/' : this.public_dir,
    args.user + '@' + args.host + ':' + args.root
  ];

  if (args.port && args.port > 0 && args.port < 65536) {
    params.splice(params.length - 2, 0, '-e');
    if (args.rsh) {
      if (args.key) {
        params.splice(params.length - 2, 0, `'${args.rsh}' -i ${args.key} -p ${args.port}`);
      } else {
        params.splice(params.length - 2, 0, `'${args.rsh}' -p ${args.port}`);
      }
    } else if (args.key) {
      params.splice(params.length - 2, 0, 'ssh -i ' + args.key + ' -p ' + args.port);
    } else {
      params.splice(params.length - 2, 0, 'ssh -p ' + args.port);
    }
  }

  if (args.verbose) params.unshift('-v');
  if (args.ignore_errors) params.unshift('--ignore-errors');
  if (args.delete) params.unshift('--delete');
  if (args.progress) params.unshift('--progress');
  if (args.args) params.unshift(args.args);

  if (args.create_before_update) {
    // Create non-existing files before updating existing files.
    // New files may be large documents, images and media, and we want to upload them first before updating links to them in the existing pages.
    // Otherwise, the links may be updated first and temporarily point to new files that have not been uploaded yet.
    params.unshift('--ignore-existing');
    return spawn('rsync', params, {verbose: true}).then(() => {
      params.shift();
      return spawn('rsync', params, {verbose: true});
    });
  }
  return spawn('rsync', params, {verbose: true});
};

然后再_config.yml的配置中旧可以指定rsync的ssh了

1
2
3
4
5
6
deploy:
  type: rsync
  host: 192.168.10.110
  user: root
  root: /var/www/html/
  rsync_ssh_path: D:/Software/cwrsync_6.4.2/bin/ssh.exe

最后就可以hexo d一键部署了

补充

由于Windows下使用了独立的rsync客户端,自带有ssh,所以在使用rsync进行远程同步的时候,需要先通过服务器的认证。

1
2
cd <rsync客户端的bin目录>
./ssh.exe user@remote_serer

然后才可以在hexo的部署里使用上rsync。

这一个过程主要是为了获取服务器的主机ssh公钥,当然,如果用户目录下的ssh已经完成过一次认证,可以直接整个文件(known_hosts)复制过来替换rsync下ssh的known_hosts也是一样的。

Vercel

使用vercel 来部署是一个十分不错的选择,它帮我们免去了了服务器,并提供了域名,且随着仓库的版本更新会随之重新部署到站点

准备:

  • github仓库,要求这个仓库符合hexo的框架
  • 注册 Vercel
  • 国内已备案的域名(有则更好)

在Vercel注册好后,创建一个项目,项目使用自己github下的hexo框架仓库,然后在部署栏里填入hexo generate,在安装栏里填入npm install,之后点击部署便可以了。

如果不习惯操作,可以先用个demo来测试以下,在demo仓库里只需要放入一个写好index.html文件即可,然后部署栏和安装栏里都置空,直接部署,便可以在预览里看到index.html

hexoblog-tan-ten.vercel.app

虽然提供了域名和免费托管,但是在国内普通网络想要访问到还是很困难的,基本都会显示超时。倒是对可以访问到外网的设备来说挺友好的。
参考:https://blog.csdn.net/ShrCheng/article/details/138207592

多种模式同时部署

以 github page 和 云服务为例,则_config.yml的deploy配置为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
deploy:
- type: git
  repo: git@github.com:halofu/halofu.github.io.git
  branch: master
  # message: [message]
- type: git
  repo: git@gitee.com:halofu/halofu.gitee.io.git
  branch: master
  # message: [message]
- type: sftp
  host: 192.168.10.110
  user: root
pass: root
  remotePath: /var/www/html/
- type: rsync
  host: 192.168.10.110
  user: root
  root: /var/www/html/
  rsync_ssh_path: D:/Software/cwrsync_6.4.2/bin/ssh.exe

比如一个用于站点部署,一个用于备份


云部署个人博客
https://halofu.github.io/2025/04/18/云部署个人博客/
作者
风鸣迎雪
发布于
2025年4月18日
更新于
2025年4月19日
许可协议