hexo 搭建个人博客
- hexo-theme-matery
- README
- Hexo
BLOG 地址
iyuhp's blog
基本介绍
本 blog 使用 HEXO 搭建, MATERY 作为主题, nginx 作静态代理,搭配 HTTPS 使用。
搭建步骤
1. 安装 hexo-cli
安装之前,请确认本机已经有 node 环境,可选择安装 cnpm。
cnpm install -g hexo-cli
2. 初始化一个 project
hexo init blogcd blogcnpm i
此时,通过 tree . -L 1 命令查看
![5c6d6b75e4c388fbc2cc0083ced1d5c0.png](https://i-blog.csdnimg.cn/blog_migrate/28d3443f01de1a1da49fdfaa738f687e.jpeg)
- _config.yml: 网站的配置信息, 绝大部分的配置,都在这里修改,这里的配置是你自己的配置
- scaffolds: 模板文件夹,新建文章时, 根据其中的模板进行填充相关内容,可以在 _config.yml 中配置选择使用哪种模板
- source:用户存放资源的地方。 除 _posts 文件夹之外,开头命名为 _ (下划线)的文件、文件夹和隐藏的文件将会被忽略。Markdown 和 HTML 文件会被解析并放到 public 文件夹,而其他文件会被拷贝过去
- themes:主题文件夹, hexo 根据主题来生成静态页面,主题目中也会有一个 _config.yml 配置文件,是关于主题的配置
3. 使用主题
关于 matery 主题的使用,可以参考 这里 。
我们把下载下来的稳定版本 copy 到 themes 目录下,然后在 _config.yml 中指定主题为 hexo-theme-matery , 同时参考 matery 文档,完成其他配置后,执行 hexo s 本地启动后,查看效果。
使用主题的方式有:
- 直接下载后添加
- 或者 git clone 到 theme 目录下
- 或者 通过 git submodule
git submodule add https://github.com/blinkfox/hexo-theme-matery.git themes/hexo-theme-matery
4. 新建文章
在 这里 可以查看到关于 hexo 的各种命令。
使用 hexo new --path folder/article "Oh Beautiful" ,会在当前 source/_post 目录下(这里根据你配置里的 default_layout,会在对应的目录下新建)新建一个 folder 目录,folder 目录中新建 article.md 文件, title 为 Oh Beautiful 。 这个命相比较于直接 new , 好处是能把文章按照目录进行分类。
这里贴一份我的 scaffold 里 post.md 的 layout:
---title: {{ title }}date: {{ date }}author: peifengimg: {{ zhankeng }}top: truecover: truecoverImg: {{ zhankeng }}password: passwordpasswordpasswordtoc: truemathjax: falsesummary: {{ zhankeng }}categories: Markdowntags: - Typora - Markdown---
官网关于 new 命令的介绍
更多配置说明请参考 这里
![32cbba6092dda5bdac724ccd9085c5f1.png](https://i-blog.csdnimg.cn/blog_migrate/fc2fc73824118b5df9be1addd4a42e85.jpeg)
5. 使用评论插件
hexo 的评论插件有很多种,比如 gitalk,gitment,disqus(国内基本可以不考虑),valine 等,我看了各种效果, valine 和 gitalk 比较满意。
valine 需要先到 LeanCloud 上注册账号,它会提供给开发者一个 1G 的免费存储空间( 计价方案),超出部分 0.10 元 / GB / 天。 个人 blog,感觉肯定是够用的(这里不得不感叹,果然是能薅羊毛,就薅羊毛啊,啊哈哈哈),因为其实不会有多少人来评论的!!!
不过我对于 valine 的权限控制有点不满意。因为我本身有后台服务支撑,后续打算对 valine 做点改动,所有评论由我自己递交给 leancloud,这样就不用暴露 leancloud 的 ak 和 sk 了。当然,这是静态 blog 的通病,木的办法。
而 gitalk,则是基于 github issue 做的实现,所有的评论,其实都是 github 上一个 repo 的 issue。这样的话,我其实不用关心这个 repo 的最终结局会怎样,大不了我删了重建一个新 repo 呗。
当然,gitalk 有两个问题
- 网络问题,经常性出现 Network Error 之类的问题
- 权限问题,用户留言时,gitalk 会要求用户给与十分大的权限,如果这个 blog 博主拿到权限后,做了一些乱七八糟的事情,可就不太好了。。。我就碰到自动 fork 博主项目的
关于 gitalk 的使用:
gitalk 文档
- 在 New Oauth 上新建一个授权应用
![72074bd11c572311fb2b29bb10d55a6d.png](https://i-blog.csdnimg.cn/blog_migrate/cb67e9ba209217efa607556e870ec05b.jpeg)
callback URL, 这里说下,根据 oauth2 协议,这个 callback URL 就是完成授权后的回调地址,这里可以填写自己网站的首页。
- 完成后会拿到 client id 和 client secret,填入到 theme 下的 _config.yml 即可。
![09509410060d5bf23cd8732dcf8deacb.png](https://i-blog.csdnimg.cn/blog_migrate/4b92d94e998d7768a2d792c674cf8a17.jpeg)
- repo: 即你的评论提交的地方,一个 github repo
- owner: 你 repo 所属的组织或者个人
- admin: 对这个 repo 有写权限的人
然后你就能愉快的使用评论功能了
![1c98289140382fbdf2a402bdda151d99.png](https://i-blog.csdnimg.cn/blog_migrate/06bc039f5bcb4f5298c4ba3f05427124.jpeg)
6. 其他优化
6.1 图片懒加载
6.2 代码压缩
6.3 SEO 优化
参考 hexo 优化
6.4 CDN 加速
关于 CDN 加速,也是通过 github + jsDelivr 完成。具体操作就是,在发布代码的时候,如果本身就托管在 github 上,那最方便,直接在 theme 主题下的 _config.yml 中配置 jsDelivr.url 即可,形如:
# 如你的 repo 地址: https://github.com/A/B# 则这里的地址就这样填写https://cdn.jsdelivr.net/gh/A/B
再次访问的时候, 就会去这里访问静态资源了。 我个人只把一部分如 css/js/libs 放到了 github 上,其他的,放在自己的 ecs 上。 关于 SEO 优化, 上面的文章也写的很详细了, 我个人只配置了 google 的, baidu 要做各种认证,就懒得配了,啊哈哈哈。
7. 百度统计
百度统计 可以用来分析网站各个维度的信息,比如访问人数, pv, uv 等。 用起来也很简单, 先在 这里 注册一个账号,创建一个应用,获取 id, 然后到 theme 下的 baiduAnalytics 那开启并配置 id ,即可看到一些统计信息了。
8. end
至此,在本地就能很方便的访问了
域名
在 域名注册 这里可以挑选一个合适的域名, 我当时买的时候,.top 后缀三年,好像才几十块钱。注册完成后,看你自己选择,要不要备案。如果选择备案,需要打印一张表格,填完后拍照上传,之后到阿里云备案,阿里云会免费邮寄一张蓝色的幕布(就是一张蓝色的纸...),然后你需要拍照上传。整个过程大约一个礼拜左右能搞定。不需要花钱。
服务器
但是阿里云搞活动,我选购了一台, 很便宜了。现在不知道是什么情况
SSL 证书
免费的 SSL 证书,提供商也很多,我这里选择的是 FreeSSL , 选择 Let's Encrypt V2 , 可以搞泛域名证书,这个还是很开心的。
如果你不需要泛域名, 只是单域名,那完全可以直接到阿里云/腾讯云等各个平台免费申请,都是一年的免费申请。还很方便。
在 freeSSL 上申请证书的时候,他会给你几个 TXT 类型的 DNS 解析,这个需要配置到你的 DNS 服务商那里。
阿里云的话, 在 这里 应该能找到配置
![0ece92f920a6db2039d2c85e87301b46.png](https://i-blog.csdnimg.cn/blog_migrate/7459aa7e0cbc9d9d441453996001ed0f.jpeg)
新添加后,基本都是立即生效的。(虽然说的是 10 分钟生效,还是相当谦虚的)
不过申请的 SSL 有效期,只有三个月 !!!注意需要定期更换
Nginx 配置 (1.14.1)
在这一部分, 需要一个(备案的)域名,一台服务器(ecs),以及 ssl 证书
Linux 下安装 nginx,这里不再赘述,centos 8 可以直接通过 sudo dnf install nginx -y 安装
这里多说一句, dnf 相比较于 yum,要更好用,按照历史规矩, yum 在将来,应该会被 dnf 取代。
再多说一句, centos 8 ,终于不再依赖 python2.7 了,vim 的基础版本也是 8.0,对于想要安装 YCM 的童鞋来说,也算是一个不错的好消息。
![68c3eec5ac585142d710aa68811717ff.png](https://i-blog.csdnimg.cn/blog_migrate/c26d4f7fd1f8bbc71d90514ecf7bade5.jpeg)
我的 nginx 目录长这样。
在 nginx.conf 中, include conf.d 目录下所有的 *.conf 的配置文件,这算很常见的配置方案,对于多应用来说,可以各自维护各自的 conf 文件。
我们在 这里 能找到一份不错的 nginx 配置,由 mozilla 推荐的配置
这是 nginx.conf 的完整配置以及 https 优化。
# ...# 加载 nginx 模块include /usr/share/nginx/modules/*.conf;http { # ... sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; # 全局 ssl 证书配置 ssl_certificate /etc/pki/nginx/server_ssl.crt; ssl_certificate_key /etc/pki/nginx/private/server_ssl.key; ssl_certificate /etc/pki/nginx/ssl_ecc.crt; ssl_certificate_key /etc/pki/nginx/private/ssl_ecc.key; # session 配置 ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # 协议配置 ssl_ciphers 仅作示例,具体配置下文有说明 ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers off; ssl_ciphers CDHE-ECDSA-AES128-GCM-SHA256: # TODO 开启 oscp # ssl_stapling on; # ssl_stapling_verify on; # ssl_trusted_certificate ospc_file_path # common header 证书有效期问题,这里设置 7776000 add_header Strict-Transport-Security "max-age=7776000;" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Xss-Protection "1; mode=block" always; add_header X-Content-Type-Options "nosniff" always; brotli on; brotli_static on; brotli_min_length 100; # 大于或等于 50 字节时才会进行压缩 brotli_comp_level 6; # 压缩等级 默认 6 越高 cpu 用的越多 brotli_buffers 16 8k; # 请求缓冲区的数量和大小 brotli_types text/plain text/css text/javascript application/javascript text/xml application/xml image/svg+xml application/json; include /etc/nginx/conf.d/*.conf;}
1. 全局 ssl 证书配置
这里采用的是双证书模式,RSA 和 ECC 两种加密方式的证书。如果各自的 conf 有新证书,直接在各自的 conf 中配置,会覆盖掉全局的配置
2. session 配置
一般开启服务端 session 缓存,1M 大约能缓存 4000 个 session,这里配置了 10M
3. 协议优化
TLSv1.1, TLSv1.2,TLSv1.3, TLSv1.3 相较于前者, 做到了更安全和更快, 如果你不需要向前兼容,直接选择 TLSv1.3 就好了。我本来也如此,后来对接 gitee 的 push hooks 的时候,发现握手一直挂,无奈,又配上了 TLSv1.2
关于 ssl_prefer_server_ciphers off 这个选项的更多解释:GITHUB ISSUE
4. add_header
是一些列的安全配置和 hsts 配置
5. brotli 压缩
一种压缩算法,比常用 gzip 要更给力。目前几乎所有主流浏览器都支持了 br ,但不免有漏网之鱼,所以可以选择同时支持 br 和 gzip 。
在使用 br 之前,需要先给 nginx 加上 brotli 模块。在 centos 8 下,操作如下:
5.1 下载 nginx
具体哪个版本,视你安装的 nginx 版本而定,可通过 nginx -V 查看, 我这里使用的是 nginx/1.14.1
# 这之前, 你可能需要安装一些基础工具包sudo dnf install -y curl wget unzip socat bash-completion epel-release && sudo dnf groupinstall "Development Tools"sudo dnf install -y pcre pcre-devel zlib zlib-devel openssl openssl-develwget https://nginx.org/download/nginx-1.14.1.tar.gz && tar zxvf nginx-1.14.1.tar.gz
5.2 下载 brotli
git clone https://github.com/google/ngx_brotli.gitcd ngx_brotli && git submodule update --init
5.3 编译
这里要十分的注意,我们需要编译的 .so 文件,最终是我们已经安装的 nginx 去执行,所以我们在 make 的时候,所有的环境配置需要和已安装的 nginx 一致。
我最开始的时候没有注意到这一点,踩了坑,最后 restart nginx 的时候,一致报 is not binary compatible 之类的错误
# 1. 获取当前运行 nginx 的环境配置sudo nginx -V# 进入下载的 nginx 源码目录操作# 上一步会输出 configure arguments,我们设为 A, 把他们全部加入其中# --add-dynamic-module=../ngx_brotli 这里的路径根据你下载 brotli 的位置而定./configure A --add-dynamic-module=../ngx_brotli
这一步执行的时候,可能还会报错,一般都是缺少依赖。如:
# This is perl 5, version 26, subversion 3 (v5.26.3) built for x86_64-linux-thread-multi# Can't locate ExtUtils/Embed.pm in @INC (you may need to install the ExtUtils::Embed module).......# 此时执行:sudo dnf -y install perl-devel perl-ExtUtils-Embed# the HTTP image filter module requires the GD library# 执行sudo dnf -y install gd gd-devel
5.4 cp .so 文件
上一步执行完成后, 会在 nginx 下的 objs 目中中生成
ngx_http_brotli_filter_module.so 和 ngx_http_brotli_static_module.so
目标文件,我们把他们移动到原 nginx 的 mudule 中。
先在 nginx.conf 中看 modules.conf 在哪里:
include /usr/share/nginx/modules/*.conf; 说明所有的 module 配置文件都在这个目录下。
然后去这个目录,随便 cat 一个配置文件, 会输出:
load_module "/usr/lib64/nginx/modules/ngx_http_brotli_filter_module.so";
此时能看到,所有 module 的 .so 文件,都在这个地方,我们把这两个 .so 也 cp 这个目录
当然, 你也可以放入任何你想放的位置,然后在编写 .conf 的时候,指定路径就好了。
5.5 编写 .conf 文件
移动完成后,同样的,我们在 modules 目录下,创建两个文件:
mod-http-brotli-filter.conf 和 mod-http-brotli-static.conf
内容分别为:
load_module "/usr/lib64/nginx/modules/ngx_http_brotli_filter_module.so";
和
load_module "/usr/lib64/nginx/modules/ngx_http_brotli_static_module.so";
当然,以上所有的路径,都以你实际的目录为准
5.6 重启和验证
sudo nginx -t 输出 ok 后 sudo systemctl restart nginx
这时通过页面访问,能看到 br 即说明 ok
![dc9e15b407e2fd0a6cf874f75c844fda.png](https://i-blog.csdnimg.cn/blog_migrate/ab910326af34f6136bffa93813a84b2f.jpeg)
6. blog conf 配置[启用 http2]
server { listen 80; server_name iyuhp.top; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; return 301 https://$host$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name iyuhp.top; try_files $uri /index.html; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; location / { root /usr/share/nginx/html/growing-blog/public; index index.html index.htm; } location = /favicon.png { expires 30d; access_log off; root /usr/share/nginx/html; } location ~* ^.*.(gif|jpg|jpeg|png|bmp|swf)$ { expires 15d; access_log off; root /usr/share/nginx/html/growing-blog/public; } # js/css 等,我们已经托管到 jsDelivr ,这里就不用再配置了 access_log /var/log/nginx/growing-blog/access.log main;}
我们在 listen 的时候,如上图配置 http2 即可,无需 ssl on
剩下都是常规配置, 没什么好说的, 无非是给一些静态文件添加缓存,这个根据实际情况配置就好。
我们打开控制台,能看到 Protocol 一栏,都显示为 h2 ,说明配置生效
![eb3799d4b24b6c9066179cfe1cdac61a.png](https://i-blog.csdnimg.cn/blog_migrate/d69495bbf0153386bf92ded7cecd350d.jpeg)
7. 限流 + Deny
在 blog 跑了几天之后,我无事之时,看了眼 nginx 的日志,发现网络世界还是凶险啊。
![be28d0475349a6272edc03482508ca40.png](https://i-blog.csdnimg.cn/blog_migrate/50da766d5f93bc9070cefc6907f38247.jpeg)
针对各式各样乱七八糟的爬虫,还有一些端口扫描工具,我们可以简单的通过 user-agent 来做过滤,比如在你的 server 层(因为包含 if 语句,所以 http 层是放不了的),加一个 ua-deny.conf 之类的文件
#禁止Scrapy等工具的抓取if ($http_user_agent ~* (Scrapy|Curl|HttpClient)) { return 444;}#禁止指定UA及UA为空的访问if ($http_user_agent ~* "tbox|Go http|FeedDemon|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|CoolpadWebkit|Java|Feedly|UniversalFeedParser|ApacheBench|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|EasouSpider|Gather Analyze Provide|Ezooms|zgrab|^$" ) { return 444;}
这样就可以根据 ua 进行过滤。
同时,也可以分析日志,查找异常的 ip, 然后直接 deny 掉。
awk '{print $1}' ./access.log | sort | uniq -c| sort -n
把恶意 ip 写入到如 ip_deny 文件中,然后在 http 层,或者 server 层, include ip_deny; ,即可拒绝这些 ip。
我们还可以限定单个 ip,或者 单个 server 的访问
# 限流# 限制单个 ip 每秒十次访问# 这里以 binary_remote_addr 作为 key,进行单 ip 限流limit_req_zone $binary_remote_addr zone=one:1m rate=2r/s;limit_req zone=one burst=3 nodelay; # 每秒两次请求,会缓存 3 次,超过的请求即被丢弃limit_req_status 403;limit_conn_zone $binary_remote_addr zone=addr:1m;limit_conn addr 3;limit_conn_status 403;
示例中,对 ip 进行限流,我们同时可以针对 server 进行限流,使用 $host 作为 key 即可。
limit_req 和 limit_conn 分别针对访问次数和访问连接数做限制。上述配置即:
单 ip 最多有 3 个连接,单 ip 每秒最多允许 2 次请求,超过的次数,会先缓存到 burst 中,会缓存 3 次,若还有请求,则被丢弃,返回 403。
8. 开启 OSCP
# TODO 开启 oscpssl_stapling on;ssl_stapling_verify on;ssl_trusted_certificate ospc_file_path
有兴趣的童鞋可以开启试下, 这里注意下,你要先生成 trusted certificate file , 这个 file 有过期时间,所以你需要一个 cronjob 来定时更新它,反正我没有开启它。。。
图床
使用七牛云作为图床, 七牛云注册后,会送 10G 的免费 OSS,作为一些图片的存放点,十分合适(是的,我就是这样薅羊毛的!)
- Uploader 链接
- Gitee 仓库
实现概览:
- 使用 golang 搭建一个简单的 web server,主要负责登录验证和分发七牛云 OSS 的上传 Token
- 前端使用 Dropzone js 组件来实现上传
- 使用七牛云的 Http Upload 方式上传图片,token 从 web sever 拿,上传不经过 web server
嗯, 今天突然发现了一个功能完备的上传工具 PicGO ,不过我肯定还是用我自己的这个了,啊哈哈哈
CICD
如果不是和我一样,搞了很多乱七八糟的,无论是 github , 还是 gitee,都提供了基于 hexo 的 cicd,只需要在自己的 _config.yml 中配置下 deploy (可能需要添加一个 .travis.yml)
我个人基于 Golang ,自己定制了一个 cicd 流程。
通过 gitee 的 push hooks event, 拉取最新代码,然后执行 blog 中 build.sh 脚本,脚本主要做了这几件事情
- 打印 hexo 版本
- 执行 npm i
- 执行 gulp default , 进行编译压缩静态文件
- 移动文件到指定目录
执行完后, cicd 会检测是否需要提交到 github,如果需要,会执行 git add git commit git push 一系列命令,执行完毕后,整个流程就结束。
对于我的 uploader , cicd 首先会拉取代码,打包镜像,之后会通过 docker ps 查看是否有进程,有的话会杀死,是的,就是这么霸道,完全没有那么一丝丝的平滑,杀死后,会把新的镜像拉起来,整个流程结束。 本来准备打算加个通知功能,不过暂时没有时间做。
还有,十分重要的就是, 所有的操作都在同一个目录,cicd 每一次执行,都会开一个协程,这必然会产生写文件冲突,考虑到只有我一个人用,并不打算改这里。
改进也很简单,就是每次 cicd 的时候,都产生一个新目录,只拉取最新代码,然后在各自的目录中去做事就好了。完事儿把目录删掉!
可是考虑到我那 1C1G 50G 的可怜资源,哎,算了,咱不折腾!!!
写文章
windows 下,实际体验下来,还是用 Typora + PicGo 来的舒服
前面刚说完
不过我肯定是用我自己的这个了
嗯, 真香......
所以我自己的,就平时用来存存图片啥的好了,反正都撸出来了不是!
TODO
1. bing 爬虫(done)
通过爬虫爬取 bing 首页图片,放到 banner 中
其实 bing 已经给了我们链接,我们稍微解析下就好了,链接在 这里
我取了列表前 5 张图,然后加上我自己的一张,设置权重,然后随机。每次刷新后,就会去后台随机拿一张图的链接。
2. 撸一个简单的 devops(done)
本地提交代码到 gitee 后, ecs 来去代码打包部署
3. 七牛云图床(done)
搞一个上传界面,用来存储图片,同时获取图片路径
ISSUE
Q1 打开的文章页面,都变成了下载页面...
A:在 _config.yml 中 permalink , 一定要注意结尾加上斜杠(/) !!! like this: :title/
Q2 Local hexo not found in xxx
ERROR Local hexo not found in xxxERROR Try running: 'npm install hexo --save'
A: 开玩笑, 明明已经跑了命令 sudo npm install -g hexo-cli , 你还给我提示这个?
对我而言, 我是因为新 clone 下来的文件, 还没执行 npm i , 执行后, 就 ok 了。
但是搜解决方案的时候,有人说是因为 node_modules 的问题,要删了重新 npm i ,可以一试。