Hexo-自定义部署 1. 多Page仓库部署 在 Hexo-初始化静态网站 中提到,GitHub 允许一个账号拥有 1 个 账号 Page 和多个 项目 Page ,因此可以利用多个项目 Page 达到分内容、分域名、冗余部署等。
开启项目 Page 的前提是已经开启了账号 Page,确保可用默认域名 [username].github.io
访问账号 Page。
1.1 开启项目Page 新建一个 GitHub 仓库用作项目 Page,GitHub 对项目 Page 的仓库名没有限制。
新建完成后需要初始化仓库以及提交一个初始 Commit,以一个简单的 HTML 源文件为例,在本地创建如下代码并上传到项目 Page 仓库的 main
分支中:
1 2 3 <html> <h1 > This is Project Page.</h1 > </html>
在项目 Page 仓库的 Settings - Pages
中的部署源选项 Source
选择 main
分支,则项目 Page 就已经建立好了,默认情况下这个项目 Page 的访问域名为:[username].github.io/DemoPage
。
1.2 自定义域名 GitHub Page 设置域名的方式是在 Page 仓库根目录下创建一个没有后缀的文件 CNAME
,并在文件中写入一行(且只能有一行)需要自定义的域名,例如:
然后在 DNS 添加一条 CName记录,让 xxx.com
指向 [username].github.io
即可。需要注意的是,CNAME
文件中指定的是纯域名,不携带任何协议网络(例如 http
、https
等)。
假设账号 Page 设置了自定义域名 xxx.com
、项目 Page 的仓库名为 DemoPage
。
默认情况下,项目 Page 的访问路径是作为账号 Page 的子路径访问的,则项目 Page 的访问路径会自动设置为 xxx.com/DemoPage
。
如果想要用自定义域名访问,只需要在 DemoPage 仓库根目录下创建 CNAME
文件,并在其中写入对应的域名。
作为子域名访问时,写入例如:demo.xxx.com
作为独立的顶级域名访问时,写入例如:yyy.com
然后在对应域名的 DNS 中添加一条 CName 记录,同样指向账号 Page 的默认域名 [username].github.io
,GitHub 会自动判断请求的域名是否指向了某个 Page,如果是则自动转发。
2. 云服务器部署 考虑到 GitHub Page 在国内访问不太稳定,受不同运营商、不同地域的影响差别很大,因此也希望能部署到云服务器上。
2.1 搭建云服务器 云服务器按照个人需求选择即可。
以腾讯云轻量应用服务器 + Ubuntu Server 18 LTS 为例。
2.1.1 准备部署环境
确保服务器已经可用,且具有公网 IP,允许公网访问。
确保本地已有可用 SSH 密钥。
服务器绑定 SSH 公钥,用于远端部署。
2.1.2 配置Ubuntu默认账号 腾讯云轻量应用服务器的默认账号为 ubuntu
,如果创建服务器实例时已经设置了该账号的密码则可以跳过。否则需要通过「重置密码」设置,注意设置时选择用户名 系统默认 ubuntu
。
2.1.3 登录服务器 腾讯云轻量应用服务器在选择 Ubuntu 镜像时,默认会创建一个用户 lighthouse
,并且腾讯云默认禁用了 root 用户,尽管可以通过配置开启,但远端登录时仍有许多问题。因此建议切换为标准的默认用户 ubuntu
,否则后续需要多次调整权限。
网页端控制台可以在登录后通过 su ubuntu
切换至 ubuntu
账号,远端登录时可以通过 SSH 连接直接指定登录用户:
1 2 3 // [username] 即为需要登录的用户,前提是该用户已创建。 // [server ip] 即为服务器的公网 IP,如果没有则需要购买公网 IP。 ssh [username]@[server ip]
(1)如果首次从本地远端登录,可能会提示密钥交换信息:
1 2 3 The authenticity of host 'XXX.XXX.XXX.XXX (XXX.XXX.XXX.XXX)' can't be established. RSA key fingerprint is XXXXXXXXXXXXXXXXXXXXXXXXXXXXX. Are you sure you want to continue connecting (yes/no/fingerprint)?
输入 yes
继续即可。
(2)如果曾经连接过,但是服务器重置了或者公网 IP 有变更,则远端登录时可能提示错误:
1 2 3 4 5 6 7 8 9 10 11 12 13 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 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 RSA key sent by the remote host is SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX. Please contact your system administrator. Add correct host key in ~/.ssh/known_hosts to get rid of this message. Offending RSA key in ~/.ssh/known_hosts:4 RSA host key for XXX.XXX.XXX.XXX has changed and you have requested strict checking. Host key verification failed.
根据提示编辑 ~/.ssh/known_hosts
文件,删除曾经保存的服务器 IP 对应的 Host 信息:
1 2 // 删除公网 IP 对应的这条 Host 记录并保存 XXX.XXX.XXX.XXX ecdsa-sha2-nistp256 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
然后再重新登录即可。
2.2 配置云服务器 配置云服务器有两种方式:
使用默认 ubuntu 用户 + sudo
操作,但某些脚本可能需要单独设置 root 权限。
使用 root 用户配置,但远端使用 SSH 鉴权 Push 时也需要指定为 root 用户,可能会有安全性问题,不推荐。
结合上述问题,本文以第 2 种方式为例,使用 root 用户配置服务器,但禁用远端登录 root 用户,配置完后再对远端 Push 涉及的目录设置为 ubuntu 用户权限。
2.2.1 开启Root用户 腾讯云轻量应用服务器默认禁用了 root 用户,需要先以普通用户(例如 ubuntu)登录后再手动开启:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 // 1. 设置 root 用户密码,可以与其他用户的相同: ubuntu@~$ sudo passwd root // 二次输入密码后提示设置成功: passwd: password updated successfully // 2. 编辑配置文件 Authentication 部分,开启 root 密码登录: ubuntu@~$ sudo vi /etc/ssh/sshd_config // 2.1 取消 PermitRootLogin 选项的注释, // 默认配置 prohibit-password,禁止 Root 用户使用密码登录: PermitRootLogin prohibit-password // 2.2 如果需要允许 Root 用户登录,则修改 PermitRootLogin: PermitRootLogin yes // 然后添加一条配置,允许使用密码认证: PasswordAuthentication yes // 3. 保存配置退出编辑模式后,重启 SSH 服务 ubuntu@~$ sudo service ssh restart
断开远端连接重新登录;如果允许直接通过密码远端登录 root 用户,则可以直接通过 ssh root@[server ip]
登录。本文为了安全性保持禁用 root 用户直接密码登录,因此仍需先以 ubuntu 用户登录,然后再切换至 root 用户:
1 2 3 4 5 6 7 8 // 从本地登录至远端 ubuntu 用户: [luis@~]# ssh ubuntu@XXX.XXX.XXX.XXX // 登录后切换至 root 用户,输入 root 密码: ubuntu@~$ su root // 切换成功后可以看到已经切换至 root 用户,且命令进入特权模式: root@/home/ubuntu#
2.2.2 安装环境 在云服务器部署静态网站,主要需要用到两个开发环境:
Nginx: 用于自动把公网请求映射到具体的静态网页资源。
Git: 用于从本地推送静态网站资源。
腾讯云轻量应用服务器的 Ubuntu 系统默认自带了 Git 环境,因此只需要安装 Nginx:
1 2 3 4 // 更新 apt: root@/home/ubuntu# apt-get update // 安装 nginx: root@/home/ubuntu# apt-get install git nginx -y
2.2.3 配置网站目录 采用 Nginx + Git 托管静态网站需要用到两个目录:
Nginx 最终代理和转发的网站资源文件目录。
Git 接收远端 Push 网站资源文件的 Git 仓库目录。通过配置 Git Hook 将收到的文件自动关联到 Ngnix 的资源文件目录。
由于本文最终远端 Push 时使用 ubuntu 用户,因此将在 ubuntu 的用户目录 /home/ubuntu/
下配置所有网站目录。
本文中创建了 /home/ubuntu/Projects/
目录并将 Nginx 和 Git 目录统一配置在 Projects 目录下,实际路径可自由设置。
(1)创建 Nginx 网站资源目录并授权;
1 2 3 root@~# cd /home/ubuntu/Projects root@/home/ubuntu/Projects# mkdir -p ./WebServer root@/home/ubuntu/Projects# chmod -R 755 ./WebServer
(2)创建 Git 接收裸仓库的目录并授权;
1 2 3 4 5 6 // 注意创建的是裸仓库,添加 --bare 参数 root@/home/ubuntu/Projects# git init --bare Web.git // 提示创建成功 Initialized empty Git repository in /home/ubuntu/Projects/LuisBlogWeb.git/ root@/home/ubuntu/Projects# chmod -R 755 ./Web.git
Git 裸仓库是指该仓库将只保存仓库的提交历史(.git
文件),而不会保存实际文件,但同样支持 Push 和 Pull,通常作为服务器存储仓库。
(3)配置 Nginx 代理和转发目录(注意备份);
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 root@/home/ubuntu/Projects# vim /etc/nginx/sites-available/default // 修改 server 部分 server { # HTTP configuration # ## 监听普通 HTTP 的 80 端口: listen 80 default_server; listen [::]:80 default_server; # SSL configuration # ## 监听 HTTPS 的 443 端口: listen 443 ssl default_server; listen [::]:443 ssl default_server; ## 设置代理和转发的目录: root /home/ubuntu/Projects/WebServer; ## 设置自定义域名: server_name XXX.YYY; } // 然后重启 Nginx 服务。 root@/home/ubuntu/Projects# service nginx restart
2.2.4 验证网站访问性 (1)在 WebServer
目录下创建一个测试网页:
1 2 3 4 5 6 root@/home/ubuntu/Projects# vim WebServer/index.html // 随便填充一个元素: <html> <h1>This is My Web.</h1> </html>
然后访问公网 IP,如果可以正常访问说明配置正确;如果网页报 404 错误,则需要查看 Nginx 错误日志。
(2)Nginx 日志存放目录配置在 Nginx 配置文件中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 root@/home/ubuntu/Projects# vim /etc/nginx/nginx.conf // 找到 http 部分的 Logging 设置: http { ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; } // 然后查看错误日志: root@/home/ubuntu/Projects# vim /var/log /nginx/error.log // 日志内容: yyyy/MM/dd hh:mm:ss [crit] 18205#18205: *1 stat() "/home/ubuntu/Projects/WebServer/" failed (13: Permission denied), client: XXX.XXX.XXX.XXX, server: XXX.YYY, request: "GET / HTTP/1.1", host: "XXX.XXX.XXX.XXX"
错误日志提示发生了 403 权限拒绝问题。
(3)查看 Nginx 的运行和启动用户:
1 2 3 4 root@/home/ubuntu/Projects# ps aux | grep "nginx: worker process" | awk '{print $1}' www-data root
发现 Nginx 启动用户是 root,但运行用户是 www-data,所以出现了用户权限被拒绝的情况。
(4)将 Nginx 的运行用户也修改为 root 用户:
1 2 3 4 5 6 7 root@/home/ubuntu/Projects# vim /etc/nginx/nginx.conf // 将 user 修改为 root 用户: user root; // 然后重启 Nginx 服务 root@/home/ubuntu/Projects# service nginx restart
再次访问云服务器的公网 IP,可以正确访问了。
2.2.5 创建Git-Hook 由于 Nginx 只能将网络请求代理和转发到 WebServer
目录下的网站资源文件,而本地的网站资源文件是通过 Git Push 到 Web.git
仓库下的,因此需要创建一个 Git-Hook,自动将 Web.git
下的资源文件关联到 WebServer
目录中:
1 2 3 4 5 6 7 8 // 创建一个 Hook 文件 post-receive root@/home/ubuntu/Projects# vim ./Web.git/hooks/post-receive // 在 post-receive 中写入一行: git --work-tree=/home/ubuntu/Projects/WebServer --git-dir=/home/ubuntu/Projects/Web.git checkout -f // 保存退出后,给 post-receive 文件添加执行权限: root@/home/ubuntu/Projects# chmod +x ./Web.git/hooks/post-receive
2.3 本地Push至云服务器 经过上述配置,服务器中的 Git 接收和 Nginx 代理转发已经配置好了,即可从本地将 Hexo 生成的静态网站 Push 至服务器。
(1)在 Hexo 站点配置文件中添加云服务器 Git 部署配置:
1 2 3 4 5 6 7 8 deploy: - type: git repository: git@github.com:[username]/[username].github.io.git branch: main - type: git repository: ubuntu@[server ip]:/home/ubuntu/Projects/Web.git
(2)本地执行 Hexo 命令部署:
1 2 3 4 5 6 7 8 [luis@WebLocal]# hexo clean && hexo g -d // 有可能报错 unable to create temporary object directory: error: remote unpack failed: unable to create temporary object directory error: failed to push some refs to 'ubuntu@43.129.198.91:/home/ubuntu/Projects/LuisBlogWeb.git' // 也有可能报错 Permission denied: error: unable to create file xxx: Permission denied
向云服务器 Push 时报错,如果原因都是类似于「无法创建 XXX」、「无法访问 XXX」、「Permission denied」等等,绝大多数是因为 Git Push 的用户没有目标路径的权限导致的,在本例中,/home/ubuntu/Projects
目录以及其内所有子文件都是 root 用户权限,而云服务器为了安全禁用了远端登录 root 用户,所以 Git 在以 ubuntu 用户 Push 时就会导致权限不足。
(3)将云服务器中 /home/ubuntu/Projects
目录以及其内的所有子文件都改为 ubuntu 用户权限:
1 2 3 4 5 6 7 8 9 10 11 12 13 // 先切换到 ubuntu 用户: root@/home/ubuntu/Projects# su ubuntu // 然后切换到 ubuntu 用户目录下: ubuntu@~/Projects$ cd // 将 Projects 和其内的所有子文件都修改为 ubuntu 用户的权限: ubuntu@~$ sudo chown -R $USER :$USER ./Projects // 查看文件权限,Projects 已经变成 ubuntu 用户: ubuntu@~$ ll drwxr-xr-x 4 ubuntu ubuntu 4096 Aug 1 hh:mm Projects/
再次从本地执行 Hexo 命令,即可成功部署。
2.4 云服务器配置SSL证书 为了访问安全性以及提升访问质量,可以给域名套上 SSL 证书。
如果使用自定义域名,需要确保自定义域名已经申请了 SSL 证书,并且认证通过绑定至域名。如果自定义二级域名访问,则需要分别为顶级域名和二级域名各申请一张 SSL 证书。
2.4.1 GitHub-Page开启HTTPS GitHub Page 只需要确保域名已绑定 SSL 证书,然后在 Page 仓库的 Settings - Pages
中勾选 Enforce HTTPS
即可。
2.4.2 云服务器开启HTTPS 由于云服务器采用 Nginx 转发请求,因此需要将 SSL 证书下载并配置到 Nginx 中。配置 SSL 需要切换至 root 用户。
(1)上传 SSL 证书至云服务器;
从域名注册商下载已绑定的 SSL 证书并解压,找到 Nginx 下的两个证书,例如:domain.crt
和 domain.key
,然后从本地上传到远端:
1 2 3 // 在本地终端执行以下代码: [luis@ssl]# scp ./domain.crt ubuntu@XXX.XXX.XXX.XXX:/home/ubuntu/domain.crt [luis@ssl]# scp ./domain.key ubuntu@XXX.XXX.XXX.XXX:/home/ubuntu/domain.key
注意,这一步命令可能会遇到报错 Permission denied (publickey)
,则检查以下配置:
(2)将证书文件复制到云服务器中 Nginx 的默认配置路径:
1 2 root@/home/ubuntu/Projects# cp domain.crt /etc/nginx/domain.crt root@/home/ubuntu/Projects# cp domain.key /etc/nginx/domain.key
(3)修改 Nginx SSL 配置(注意备份);
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 root@/home/ubuntu/Projects# vim /etc/nginx/nginx.conf // 参考以下配置修改: http { ## # Basic Settings ## sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## 开启访问错误拦截 proxy_intercept_errors on; ## # Server Settings ## ## 禁止 IP 直接访问 server { listen 80 default_server; listen [::]:80 default_server; listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; return 444; } ## 特定子域名单独转发(需要 DNS 解析) server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name AAA.xxx.yyy BBB.xxx.yyy; return 301 https://xxx.yyy$request_uri; } ## 其他子域名全部转发至顶级域名(需要 DNS 解析) server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name *.xxx.yyy; return 301 https://xxx.yyy$request_uri; } ## HTTP 自动转发至 HTTPS server { listen 80; listen [::]:80; server_name xxx.yyy; ## 自定义域名 return 301 https://$host$request_uri; } ## 默认只代理 HTTPS 请求 server { listen 443 ssl; listen [::]:443 ssl; server_name xxx.yyy; ## 自定义域名 root /home/ubuntu/Projects/WebServer; # autoindex on; index index.html index.htm index.nginx-debian.html; # 错误页面导航 error_page 404 500 502 503 504 https://xxx.yyy/404; } ## # SSL Settings ## ssl_certificate domain.crt; ## 下载的 SSL CRT 证书 ssl_certificate_key domain.key; ## 下载的 SSL Key 密钥 ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; }
(4)修改 Nginx 默认 Server 配置(注意备份):
1 2 3 4 5 6 7 8 9 root@/home/ubuntu/Projects# vim /etc/nginx/sites-available/default // 去除(注释掉)默认配置中 Server 的重复配置项: server { # listen 80 default_server; # listen [::]:80 default_server; # root /var/www/html; # server_name _; }
(5)验证 Nginx 配置;
执行 Nginx 测试命令,检查是否配置通过:
1 2 3 4 5 6 7 8 root@/home/ubuntu/Projects# sudo nginx -t // 如果输出如下,说明配置正确,否则根据 [warn] 或 [error] 的提示修改。 nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful // 测试通过后,重启 Nginx 服务: root@home/ubuntu/Projects# sudo nginx -s reload
2.5 验证网站访问
以 HTTP 协议访问云服务器公网 IP:报错 444.
以 HTTPS 协议访问云服务器公网 IP:报错 444。
以 HTTP 协议访问自定义域名:自动转发至 HTTPS。
以 HTTPS 协议访问自定义域名:正常访问。
如果以上均验证成功,则网站已经正常部署。
2.6 常见异常 如果访问服务器时报错 403,先按上文所述查看 Nginx 的报错日志:
1 ubuntu@~$ vim /var/log /nginx/error.log
(1)directory index of "..." is forbidden
1 yyyy/MM/dd hh:mm:ss [error] 28043
首先检查 Git Push 是否成功,Hexo 在 Deploy 时,一旦某个文件 Push 失败则 Git 会中断 Push 任务,但只要 Push 任务结束 Hexo 就会提示 INFO Deploy done: git
,所以看到这个提示并不一定代表 Push 是成功的,需要检查 Deploy 日志,确保没有提示任何文件写入失败。如果有,大概率是权限问题导致的,可参照上文配置;如果没有,则需要检查 Nginx 配置:
1 2 3 4 5 6 7 8 9 10 11 ubuntu@~$ vim /etc/nginx/nginx.conf http { ## 默认只代理 HTTPS 请求 server { // 在默认代理 server 内添加该配置: index index.html index.htm index.nginx-debian.html; // 如果不确定网站使用的默认页,则添加如下配置: autoindex on; } }
参考文献