又是一个新的开始

Yicheng 于 2020-05-07 发布

说起来也是缘分,这台 DigitalOcean 的小机器跟了我整整5年了,一个月就5块钱,便宜得不行。但是吧,最近越来越感觉有点力不从心了,内存不够用,硬盘空间也紧张,索性一咬牙升级到了15块钱一个月的配置。既然都要折腾了,那干脆把所有服务都重新整理一遍,该扔的扔,该优化的优化。

至于旧博客的那些文章嘛…说实话,翻了一遍发现大部分都已经过时了,有些技术栈都已经淘汰了,留着也没啥意义,索性全扔了,轻装上阵。

为什么要折腾这一套

说白了吧,我就一个需求:不管在哪儿,只要有网,就能访问我的文件。

听起来简单对吧?但实际操作起来真的挺烦的。家里有两台群晖(一台916+一台更老的型号),还有一台 Ubuntu 工作站,平时在家用用还行,但是一旦出门在外想访问点东西,那就麻烦了。外网访问这个事儿,一直都是个让我头疼的问题。

之前的方案都有啥问题

一开始图省事,直接用了 LNMP 一键安装包。这玩意儿确实方便,当年装 WordPress 的时候一键搞定,nginx、MySQL、PHP 全给你配好了,HTTPS 证书也能自动申请,文档还挺全,基本上没碰到解决不了的问题。但是吧,后来不用 WordPress 了,改用静态博客了,MySQL 和 PHP 就成了摆设,每次还得更新、打补丁,感觉有点浪费资源。

然后是 frp 内网穿透这一套。原理很简单,就是把群晖的 5000 端口通过 frp 映射到 VPS 上的某个端口,然后再用 nginx 做个反向代理,包上 HTTPS,这样在外网就能访问了。用了挺长时间,整体还算稳定。

至于直连嘛…我也试过。但问题是,家里一边是 ATT 的光纤,公司或者外面一边可能是 Comcast 的电缆,这两家运营商之间的互联质量真的是…一言难尽。带宽忽高忽低,时不时还断线,用起来真的很烦。

OpenVPN 我也折腾过一阵子,想着能不能直接组个虚拟局域网,但实测下来速度还不如 frp + nginx 的组合。最后发现,虽然 frp 映射 + nginx 反代这套方案速度比不上直连,但胜在稳定,基本上不会断,延迟也能接受,就这么用下来了。

下面这张图大概展示了我当时的网络结构,各个节点之间的速度和延迟都标注在上面了:

网络结构示意图

旧方案踩过的那些坑

问题1:依赖地狱,真的是地狱

一开始用 apt 装各种软件,相安无事用了好一阵子,感觉挺好的。结果有一天突然想给群晖配个 WebDAV 服务,方便手机直接访问文件,这时候问题来了:LNMP 一键包里的 nginx 居然不支持 WebDAV 模块!

这就尴尬了。要么重新编译 nginx,要么就放弃这个功能。我寻思着都折腾到这份上了,那就编译吧。结果这一编译,各种依赖问题就来了,缺这个库缺那个库,编译参数也得研究半天,中间踩了一堆坑,折腾了大半天才搞定。那会儿就在想,要是有个更简单的方式就好了。

问题2:服务管理,一团乱麻

这个也挺让人头疼的。你看啊:

理论上是可以把这些都整合到一个统一的管理工具里,比如全都用 systemd 或者全都用 supervisor。但是吧,这又是一个新的维护点,得去写配置文件,得去调试,想想就觉得累。而且每次要改点什么,都得想一想”这个服务是用什么管理的来着?”,真的很烦。

解决方案:干脆全部 Docker 化算了

说到底,我就是懒。而且说实话,DigitalOcean 开的这个小机器,默认就是 root 登录,我平时也不在服务器上干啥别的事儿,就跑几个简单的服务。有点风险的服务呢,包一层 Docker 隔离一下,反正也没人会专门来搞我这个小破站,流量也不大,就自己用用。

所以我就想啊,既然都这样了,那还纠结啥性能啊、高可用啊这些东西,简单才是王道

Docker 这玩意儿的好处太明显了:

而且最重要的是,我不用再去管什么依赖冲突、系统环境污染这些破事儿了。每个服务都在自己的小盒子里,互不干扰,清清爽爽。

1. Nginx 容器化

直接用官方镜像,映射配置文件和 SSL 证书:

docker run --restart=on-failure:10 \
  -v $PWD/nginx/:/etc/nginx/ \
  -v $PWD/:/home/ \
  -v /root/.acme.sh/yicheng.ren/:/ssl/yicheng.ren/ \
  --network host \
  --name nginx-web nginx

2. frps 容器化

frp 是 Go 写的,一开始下载二进制文件用,每次更新都要手动替换,烦。

多阶段构建,镜像只有 10MB:

FROM golang:latest
COPY . /build/
WORKDIR /build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o frps ./cmd/frps

FROM scratch
COPY --from=0 /build/conf/frps.ini /
COPY --from=0 /build/frps /
ENTRYPOINT ["/frps","-c","/frps.ini"]

跑起来:

docker build -t frps:dev .
docker run --restart=unless-stopped -d \
  --network host \
  -v /root/docker/frps/frps.ini:/frps.ini \
  --name frps frps:dev

3. HTTPS 证书

继续用 acme.sh 申请 Let’s Encrypt 证书。

泛域名证书真香:一个 *.yicheng.ren 证书搞定所有子域名,不用像以前每加一个 vhost 就申请一次。

官方安装步骤

4. Nginx 配置

配置文件分离,结构清晰:

├── nginx.conf          # 主配置
└── vhost/
    ├── xbb.yicheng.ren.conf
    ├── yicheng.ren.conf
    └── ...others.conf

nginx.conf 里放通用配置:

http {
    gzip on;
    
    # HTTP 强制跳转 HTTPS
    server {
        listen 80 default_server;
        server_name _;
        return 301 https://$host$request_uri;
    }
    
    # HTTPS 默认配置
    server {
        listen 443 ssl http2 default_server;
        server_name _;
        index index.html;
        root /home/wwwroot/default;

        ssl_certificate /ssl/yicheng.ren/fullchain.cer;
        ssl_certificate_key /ssl/yicheng.ren/yicheng.ren.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256";
        ssl_session_cache builtin:1000 shared:SSL:10m;
        
        location ~ /\. {
            deny all;
        }
        
        access_log /home/wwwlogs/access.log;
    }
    
    include vhost/*.conf;
}

反代群晖就加个 proxy_pass

location / {
    proxy_pass http://127.0.0.1:20001;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_buffering off;
    add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
}

搞定。

博客重建:从 Org-mode 到 Markdown 的心路历程

说起来这个博客,也是一段历史了。以前我特别喜欢用 Emacs 的 Org-mode 写各种个人文档,笔记啊、待办事项啊、甚至代码片段都用 Org-mode 管理,所以当时建博客的时候,很自然地就选了 Nikola + Org-mode 这个组合。

能用吗?能用。有问题吗?也没啥大问题。但是吧,用的人真的太少了,基本上属于小众中的小众。

这就带来几个很现实的问题:

结果5年过去了,再看看现在的技术趋势,Markdown 已经彻底一统江湖了。公司内部文档全都迁移到 Markdown 了,各种协作工具也都支持 Markdown,写技术文档也基本上都是 Markdown 格式。而且 Org-mode 转 Markdown 的插件这几年也有了不少改进,虽然还是有些小毛病,但比以前好多了。

所以我就想,算了,不折腾了,直接跟随主流,用 Jekyll + Markdown 得了

然后就开始找主题,这次就顺利多了,毕竟 Jekyll 的生态太成熟了。最后找到了一个特别简洁的主题:TMaize Blog,看着挺顺眼的,功能也够用。

评论系统的话,我选了 Gitalk,这玩意儿挺有意思的,直接把 GitHub Issues 当后端,省得自己再去搭个评论服务器,而且对于技术博客来说,读者基本上都有 GitHub 账号,用起来也方便。

小测试

代码高亮效果:

#include <iostream>
using namespace std;

int main() {
    cout << "Hello World"; 
    return 0; 
}

完美。

总结一下这次折腾

回头看看这次迁移,其实核心思路就几个:

前前后后折腾了大概一天吧,总算是把所有服务都理顺了,测试了一下各个功能都正常,心里踏实多了。

接下来还想做点啥:

新的开始嘛,继续折腾呗。反正折腾这事儿,对我来说也是一种乐趣。