0. 前言

Hello, world!
也许是心血来潮,也许是不知好歹,这个博客还是折腾起来了,在互联网上开出自己的一亩三分田的想法终于实现。尽管自己还是大半个小白,“拿来主义”地参照网上的教程和文档摸索出了一套网站,实打实的技术几乎没有。虽然如此,还是想将大致操作和踩过的坑记录于此,以备来日。若能再给各位有所启发,更是有幸。

1. 基础设施

1.1 域名

虽然域名这方面之前交了些学费,真到自己成了“终端”想建站时,手上的几个域名还是不堪大用,就照着这个网名再注册了一个中规中矩的域名。过去几年随着域名市场的退潮,小众(有人戏称为非主流)后缀域名的火热时代已经过去了。

1.2 服务器

博客建站的硬件准备不外乎静态页面托管、虚拟主机空间、云服务器,成本升高,性能和自由度也随之增加。相比美元计价、价格不菲的大牌国外云服务商,国内云服务商大多有新购服务器优惠活动,但全靠吓死人的续费价格衬托。无奈,咬咬牙租三年,到期大不了迁移跑路。考虑到将来需能面向全球,也为免除备案之扰,最终选择了国内某云服务器厂商境外机房。起步配置则不需太高,独享的云服务器,单核(1C)2G内存便足矣,若是国内机房还有低价学生机可供试水。云服务器选择预装CentOS或Debian,接近开箱即用。然而,之前从未接触过Linux,面对黑漆漆的命令行不免心生迷茫,只能从零学起。

那些花里胡哨的Linux技巧可以不谈,一些基本的运维安全措施还是很有必要的。

  • 修改SSH默认监听的22端口,可规避大部分端口扫描。
  • SSH设置复杂密码或使用SSH密钥登录,限制单次密码尝试次数防止爆破。
  • 创建标准账户,禁止root账户远程登录。
  • 配置服务器后台的上游安全策略和本机防火墙。对于只有web服务的博客,可以封锁所有端口,只放通需要的80和443等端口。
  • 部分厂商对于云服务器的 SELinux 默认关闭 SELINUX=disabled,可视情况开启。
  • 关注异常的高CPU负载、内存用量、网络流量,可设置阙值报警。
  • 及时备份数据,定期下载到本地。

2. 框架与软件

2.1 Docker

起初也不知道什么DevOps、应用虚拟化的高深道理,只是贪图Docker部署可以直接套用现成的镜像,跑在上面的应用配置错了直接删容器也不要紧。在不打算自己编Dockerfile写镜像的前提下,能在Docker部署的有Hexo、Ghost、Wordpress和Halo这几个博客系统,但像Hexo这类静态博客系统,由于没有后端写作不太方便,就都排除了。

Linux环境下,Docker CE(社区版)使用官方安装脚本自动安装几乎一键完成

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

或通过yum手动安装。

2.2 Nginx + Mysql + PHP + Wordpress

原本打算用Nginx + Mysql + PHP + Wordpress (NMPW)的组合,上手后发现新东西越学越多,还是奈何不得它们几位复杂的相互作用,最终自己掉到Docker的虚拟卷和虚拟网卡的坑里去了。如此辗转于各类教程文章和官方文档之间,折腾数周,好歹把Nginx、Mysql、PHP一个个配置完成了,安装Wordpress却无奈于bug频出的后台管理页和主题。加之自己对PHP还是一窍不通,只好及时止损,转投Halo。

2.3 Nginx + Halo

有了之前配置Nginx的经验,使用 Docker 部署 Halo,再按照文档配置一下application.yaml即可。

本着能省则省的原则,没有使用Docker Composer,先在文本文档中写好run命令,再输入控制台。少量参数解释:
-v 从主机挂载卷,作为配置文件方便设置;
:ro 设置主机文件对容器为只读;
-p 映射容器端口到主机端口,这里是Halo的8090端口、Nginx的80和443端口;
-d 后台运行容器,并返回容器ID;
-i 以交互模式运行容器;
-t 为容器重新分配一个伪输入终端,通常与-i同时使用;
其他与网上教程大同小异。
Nginx run

sudo docker run --name nginx -p 80:80 -p 443:443 \
-v ~/nginx/nginx.conf:/etc/nginx/nginx.conf:ro \
-v ~/nginx/conf.d:/etc/nginx/conf.d:ro \
-v ~/nginx/html:/usr/share/nginx/html:ro \
-v ~/nginx/logs:/var/log/nginx \
-v ~/acme.sh:/etc/nginx/acme.sh:ro \
-d --restart=unless-stopped nginx

Halo run

sudo docker run --name halo -p 8090:8090 \
-v ~/.halo:/root/.halo \
-it -d --restart=unless-stopped halohub/halo

由于个人网站规模不大,也没有多余的服务器资源,仅需在一台服务器上的Nginx配置好反向代理和https,写入三个配置文件nginx.confdefault.conf以及分离出本站的tanhex.com.conf,并配置好重定向和静态资源缓存。

2.4 acme.sh

相比于许多年前SSL证书需要真金白银购买,现在既然有了免费的SSL证书,那么https自然要安排上,而acme.sh为脚本相比Certbot客户端更轻量化。即便没有很大必要,为了统一部署,acme.sh也一并放在Docker上,并注册个ZeroSSL账号申请泛域名证书(Let’s encrypt不再是默认证书CA)。

在这配置Nginx时直接将acme.sh输出的证书和密钥链文件夹挂载给了Docker中的Nginx以方便更新,尽管不太推荐这么做而是使用acme.sh的命令安装证书。

云服务器利用crontab设定每15天定时更新证书和重启Nginx容器。

55 4 */15 * * docker exec acme.sh --cron --force
55 5 */15 * * docker restart nginx

由于acme.sh本身也带有定时更新证书的维护功能(每60天自动更新),需使用--force参数令其立即运行。域名转移或切换DNS服务商时注意需要重新配置acme.sh以成功验证域名DNS续期。

在全站使用CDN后,从访问者到CDN服务器将使用CDN厂商的SSL证书,也不用担心网站证书过期的问题。

3. 客制化

3.1 Halo主题

历史悠久的Wordpress有着五花八门的主题,但可供选择Halo的主题较少,不少主题多年没有更新。尝试一批主题后,还没能找到适合需求的主题。
documentary-of-start.halo-themes

在本地搭建Halo开发环境后,自我感觉良好地觉得可以试一试从零开始做个主题,前端知识基本亦是从零开始,还需要学习CSS、FreeMarker和JS。然而并不打算朝着前端工程师的方向发展,自制主题未半,效果堪忧而已经觉得力有不逮。最终还是点到为止,选择这个较为朴素的NexT开源主题,打算修改美化后赶快投入使用。尽管NexT是知名老牌主题,但NexT在Halo的移植版本看起来早已停止更新。

简洁为先,在NexT提供的四个外观(Scheme)中选择了Mist。然后剥离其他三个外观,简单地照着F12调试工具删改文字,大改图标和颜色,加上黑暗模式,更新Prism代码高亮样式,加上友链页面和404页面,再考虑利用分类菜单实现伪国际化英语和中文文章分类,优化静态资源加载。一顿增删改查,得到这个不完美,但比较符合朴素审美的扁平化主题,暂且称之为Nextan。至于主题更多的功能、优化细节等,只能说前端开发真是个不小的坑,还得在今后逐渐更新。

3.2 Halo后台设置

主要将资料填上,写好分类页就行。后台设置大多可以保持默认,高级选项-固定链接中设置各种页面的链接格式,可以按个人喜好习惯设置,但设置好后最好不要随意更改,以免忘记或漏掉修改某些指向这些页面的链接造成死链。

若开启了评论插件(API)需注意,评论插件的默认Gravatar源由于众所周知的原因无法使用,且评论者头像不能彻底关闭,导致文章页加载极慢,更换Gravatar镜像源后正常,如//gravatar.loli.net/avatar/

documentary-of-start.gravatar1

但后来发现,也并没有完全正常,因为官方的评论模块js文件中硬编码了官方Gravatar源地址作为备用,而看起来其他源无法响应一个参数为?s=256&d=undefined的请求,而导致总会出现一个失败的请求,手动替换js文件中的源地址也无法解决问题,好在影响不大。

3.3 Mathjax公式插件

安装Mathjax比较简单,可在后台博客设置通过CDN加载Halo Documents - 数学公式,也可将Mathjax下载安装到主题中。然而Mathjax插件较为重量级,会拖累网页打开速度,最好根据文章内容按需开启。

在Halo直接使用documentary-of-start.Mathjax3输入数学公式Mathjax均无法正常渲染。经查Halo社区论坛-公式渲染bug,发现Halo后端在将控制字符$ { } \等转义后再输出导致前端Mathjax无法解析。此外,Mathjax中 $ ... $ 的标记默认关闭,若未修改配置则无法使用。

Halo 1.5.0版本更新后优化了数学公式渲染,从而也导致输入方式无法沿用旧版。
对于Halo 1.5.x 和 Mathjax 3.x 版本,实测解决方案为在后端编辑器中Mathjax标签的符号前加\号转义。

如图所示,行内公式可用 documentary-of-start.Mathjax4

这是 \( \sqrt{a^{2} + b^{2}} \) 行内公式示例

行间公式可用
documentary-of-start.Mathjax5

这是
$$ \sqrt{a^{2} + b^{2}} $$
行间公式示例

以下数学输入方式仅适用于旧的 Halo 1.4.x 版本,示例在这个网页上可能显示异常。
对于Halo 1.4.x 和 Mathjax 3.x 版本,实测解决方案为使用`号行内代码块再外加$号,或使用行间代码块,分别包含对应的Mathjax标签。尽管这样的写法在Halo后端文章编辑器无法预览,但前端页面可以正常显示。

如图所示,行内公式可用documentary-of-start.Mathjax1

这是 `\(\sqrt{a^{2} + b^{2}}\)` 行内公式示例

行间公式可用
documentary-of-start.Mathjax2
这是

$$ \sqrt{a^{2} + b^{2} } $$

行间公式示例

3.4 网站访客统计

无论网站大小,访客流量的统计分析都很有必要——尽管像这样的个人网站并不为博人眼球、流量盈利。而由于众所周知的原因,国际标杆级的Google Analytics访问不便,国内大大小小的统计服务也有一些限制。就暂且选用了免费但不太有名的Clicky来统计网站流量,这个国外的产品足够简洁易用,重点宣传为Privacy-friendly的无Cookies统计。然而起初看来基本够用,但一段后时间发现,Clicky的统计分析功能还是寒酸,免费版基本上只有限量3000条记录的PV和UV统计功能。为了更详细的统计功能,尝试换用国内三大统计平台中的51LA,接近实时的网站统计,亦可监测搜索引擎和爬虫来访,目前看来还不错。

Halo将统计代码放在基础选项-其他设置-统计代码中的功能很方便,若想改用其他统计直接替换即可。

3.5 PicGo配合Github图床

众所周知,像这样的小水管带宽个人博客,如只是直接从网站服务器传输图片,图片数量和访问量稍大就可能吃不消。于是大多数博客和个人网站都会选择使用外部图床:一则可以让访问者同步加载静态图片资源和动态资源,提高打开速度;二则减少流量消耗,对按流量计费的一些云服务器和CDN大有好处。

虽说图床网上有一堆,也可以自己搭建,但限制少又能保证稳定的方案不多。大概有微博图床(已防盗链无法使用)、imgur、sm.ms图床、聚合图床、GitHub仓库等。

最终,使用背靠大树的GitHub作为图床,最大优点在于它可以使用jsdelivr作为CDN,且不担心倒闭跑路。仅有一点限制,单个文件大小限制在100M以内,超过50M提示警告,做图床已绰绰有余。

PicGo为免费图片上传工具,可用该工具将图片批量上传到各个平台上,方便管理图片和复制图片链接插入Markdown写文章。

更新:近期jsdelivr作为CDN的Github图床无法访问,改回使用本站附件配合Cloudflare CDN。

4. 后记

于此,历时小半年折腾的博客终于上线,往后就是最最艰巨的工程了——坚持写博客。
感谢大家以及浩瀚的互联网!
如果发现该网站任何错误(语法错误\页面错误\错别字\歧义混淆\失效链接等),或有其他建议,敬请指出。
主要参考资料如下,为免凌乱,还有许多零碎的资料和常见的工具网站不再写出。

(这里由主题通过css样式实现各种提示标志效果)

博客根本问题之一 - 知乎:自己拥有一台服务器可以做哪些很酷的事情?
博客根本问题之二 - 知乎:别再搞博客了,赶快写吧
一站式编程学习 - 菜鸟教程
Nginx入门 - 知乎:8分钟带你深入浅出搞懂Nginx
Halo官方文档 - 使用 Docker 部署 Halo
Halo博客系统社区
Https证书配置 - 简书:在Docker容器环境中用Let’s Encrypt部署HTTPS
Nginx的Https配置 - 简书:HTTPS配置优化及注意点
docker运行acme.sh 安装配置泛域名证书 - 一个人的孤独自白
Freemarker中文文档 - 什么是 FreeMarker?
Halo主题开发参考 - halo 博客深度定制与美化教程
CSS图标字体库 - Font Awesome 中文网站
MathJax官方网站 - Getting Started

EOF - 全文完