I'm starting to provide Chinese / English versions of some articles, switch with the Language menu above. 我开始提供部分文章的中文、英文翻译,请使用顶部语言菜单切换。

使用 GPP 预处理 Dockerfile,实现 #include、#if 等功能

由于我有多种架构的设备运行 Docker(包括 x86_64 的电脑和服务器,ARM32v7 的 Tinker Board 和 ARM64v8 的树莓派 3B),我的每个 Docker 镜像都要构建多种版本。最初我给每个架构单独写一份 Dockerfile,但是很明显这样难以统一管理,在软件更新修改 Dockerfile 时经常漏改文件。之后,我用的是 Docker 的构建参数功能,即 --build-arg 参数,根据参数来调用不同的基础镜像、下载不同文件。但是这样还是有很大的局限性。首先,不同项目对不同架构的称呼是不一样的。例如,我们平时说的 x86 32 位架构,i386,就被 Go 以及众多使用 Go 的项目叫做 386。类似的,ARM32v7 也可以叫做 ARMHF,而 ARM64v8 有三种写法(ARM64v8,ARM64,AARCH64)。之前,我就不得不用 bash 脚本转换出不同的称呼组合在不同的地方使用,但是这样做就需要设置很多的变量,非常麻烦。另外,有些镜像在特定架构下需要特殊处理。例如,nginx 镜像在 i386 和 ARM32v7 下不能使用 Cloudflare 优化的 zlib,只能使用原版;nginx 在 x86_64 环境下编译 i386 镜像时需要 setarch i386,否则会编译出 64 位的程序。再例如,...

在 DN42 中使用 Docker 建立 Anycast DNS 服务

2020-03-16 提示 ¶本文中的方案已有更新版本:参见《Docker 容器共享网络命名空间,集成 Bird 实现 Anycast 高可用》。建议阅读本文的概念介绍部分及 Bird 的大致配置,配合上文的 Docker 部署方案使用。什么是 Anycast ¶互联网上常用的路由协议 BGP 是这样工作的:我在 DN42 拥有 IP 段 172.22.76.104/29。我通过 BIRD 等 BGP 软件,“宣告” 这台服务器上可以访问到 172.22.76.104/29 这个 IP 段。与我有 Peering 的其它服务器记录下这一条消息:“通过某条路径,走 1 格可以访问到 172.22.76.104/29。” 其它服务器向与它们有 Peering 的服务器继续宣告:“这台服务器距离 172.22.76.104/29 只有 1 格距离。” 以此类推,其余服务器也通过类似的流程,宣布自己与 172.22.76.104/29 有 2 格,3 格,4 格距离…… 所有服务器也都通过距离最短的路径,将数据发送到我的服务器。在这种情况中,只有一台服务器宣布自己是 172.22.76.104/29 的 “源头”。这就是单播(Unicast)。而任播,即 Anycast,就是我在多台服务器(实际中往往在不同地理位置,比如中国香港、美国洛杉矶、法国巴黎等)上都宣告自己有 172.22.76....

Typecho 主题性能优化和缓存

为了实现 Lightbox、代码高亮等功能,我在我的博客主题中写了一些后处理代码,对 Typecho Markdown 输出后的 HTML 代码再进行一层处理。但是因为我的博客历史文章较多,我在不同时期也用了不同的编辑器(WordPress 编辑器,百度 UEditor 等等),为了尽可能保证历史文章也能正常显示,我的处理逻辑比较复杂。再加上我用的廉价 VPS 性能本就不怎么样,相应的网页加载时间也较长。我在 nginx 配置中添加了这样一行,以在 HTTP 头中输出网页在服务器端处理的用时:add_header LT-Latency $request_time;最初,这个值是 0.25 左右,代表着每个网页需要在服务器端处理 250ms 之久。于是,我在大概一年前(2018 年 3 月 11 日,《大幅优化了博客主题性能》)大改了一轮后处理逻辑,修改点大致如下:原先,为了对应历史文章代码,我使用多条正则表达式一条条进行匹配、替换。我在修改时将有些正则表达式整合成一条,并且直接在数据库中改了一些文章的原始 HTML 代码,减少渲染时不必要的工作。Typecho 的很多函数都是直接 echo,而非返回值。原先,为了获取它们的结果,我使用 ob_start 以及 ob_get_flush 函数来捕获对应函数的输出,但这样效率较低。研究 Typecho 代码之后发现,...
插图

Go 语言实现的 Bird-lg(Bird Looking Glass)

什么是 BIRD?什么是 Bird-lg? ¶BIRD 是 Linux 上常用的一款 BGP 路由软件。我主要在 DN42 网络内使用 Bird,与其它用户建立连接。Bird-lg 是 GitHub 用户 sileht 开发的一款基于 Python 2 的程序。它提供了一个网页面板,可以显示各个服务器上的 BIRD 路由软件的状态,以及查询到指定 IP 的路由。为什么我要用 Go 语言重写? ¶Bird-lg 基于 Python 2 以及 Flask,因此占用内存较大(20-30 MB)。Bird-lgproxy 内存占用量也差不多 20 MB,并且每台服务器上都要运行一个。本站所在的 512 MB 内存的 VPS 已经出现过多次由于内存耗尽外加 SWAP 所在硬盘读写缓慢,导致 Docker、nginx、MySQL、PHP 轮流崩的情况,只能重启解决。Go 重写版本只消耗 6 MB 内存。Bird-lg 读取多个服务器的状态是按顺序进行的,而非并行进行。有时某台服务器网络状态不好,或者 ZeroTier One 抽风,会导致读取时卡较长时间。Go 重写版本使用 Goroutine 并行请求多台服务器,在服务器多、网络差的情况下成倍地加快页面加载速度。这也是我学 Go 语言的一个练手作。实现了什么功能? ¶对于 Bird-lgproxy,实现了以下功能:...
插图

BuyPass GO SSL 证书试用

BuyPass 是挪威的一家 CA,提供数字证书、安全认证产品等多种服务。最近 BuyPass 上线了基于 ACME 的自动签发证书服务,类似于 Let's Encrypt,这项服务称为 BuyPass GO。与 Let's Encrypt 主要的不同点在于他们的证书每次签发有效期是 180 天,比 Let's Encrypt 的长一倍。所以如果你需要给你的服务手动换证书,BuyPass 的证书会好一些。另外 BuyPass 暂不支持签发泛域名证书(俗称野卡?),只能将需要的域名一个个列出来。(不过我觉得如果需要手动换证书,还是申请 TrustAsia 之类的一年有效期的好一点)申请证书 ¶我使用 acme.sh 这个工具来申请证书。第一步是注册用户。与 Let's Encrypt 不同,BuyPass 要求在注册时提供一个有效的邮箱:cd /root/.acme.sh./acme.sh --server https://api.buypass.com/acme/directory --register-account --accountemail [你的邮件地址]如果你的域名有 CAA 记录,限制哪些 CA 能签发证书,那就添加一条 0 issue buypass.com,允许 BuyPass 给你签发证书。然后申请,我这里使用的是 DNS 验证,服务商是 CloudXNS:...
插图

使用 Docker 构建参数,多架构共享一份 Dockerfile

由于我有多种架构的设备运行 Docker(包括 x86 服务器,树莓派,Tinker Board),对于每个常用的软件,我需要为每种不同架构都构建一份镜像。之前,我采用的方式是每个架构都有一个独立的 Dockerfile,类似于这样:可以看到每份 Dockerfile 除了 FROM 调用的镜像不一样,其它几乎完全相同。用这种方式管理,好处是写构建脚本(travis.yml)的时候简单,直接一个个 docker build 过去即可,但是坏处也很明显,每次软件有版本更新,或者我决定添加或删除一个功能,我都要改好几份 Dockerfile。前两天我查资料时,发现了 Docker 的一个功能:构建参数(Build args),就是可以填入一些参数供构建过程使用。于是我就决定修改构建脚本,将不同架构的 Dockerfile 合并。使用构建参数 ¶Dockerfile 中使用 ARG 命令就可以定义一个构建参数,它可以像 ENV 定义出的环境变量一样使用:# 定义一个名为 THIS_ARCH 的参数ARG THIS_ARCH# 或者给它定义上默认值:ARG THIS_ARCH=amd64然后在构建时这样使用:docker build -t xddxdd/testimage --build-arg THIS_ARCH=amd64使用 ARG 有两个坑,...
插图

pfSense 配置 IPv6 多 WAN 自动切换

就在几天前,HE.NET Tunnelbroker 的法国服务器出了一次故障。因为我在配置 Kimsufi 服务器时,将 Kimsufi 原生的 IPv6 分给了 ESXi 单独使用(见这篇文章),pfSense 只具有原生 IPv4 并通过 Tunnelbroker 获取 IPv6 地址,所以这次服务器上的所有虚拟机都失去了 IPv6 连接。更严重的是,由于我在服务器上也参照这篇文章搭了个 NAT64 服务,为了优先使用 IPv6,我设置了 pfSense 的 DNS 解析优先使用 Google DNS 的 NAT64 解析服务器,就是 2001:4860:4860::64 和 2001:4860:4860::6464 这两个,只在这两个 DNS 全部失效后才去使用 IPv4 解析。由于 IPv6 不通了,而 pfSense DNS 服务器的超时又很长,内部的 DNS 解析几乎全部失败。为了防止 IPv6 出问题后再次引起连锁反应,我准备使用多个 Tunnelbroker 互相作为备份,并配置 pfSense 的 Multi-WAN Failover 功能,在一个 Tunnelbroker 断线后立即切换到其它 Tunnelbroker,保证 IPv6 对外连接不中断。...

nginx 配置 LDAP 认证

我的各台服务器上安装了各种不同的服务,都有各自的用户名密码体系,难以统一管理。假设未来某天我的密码泄露了,一个个修改就会非常累人。因此,我希望用一个服务来专门管理用户名密码,其它服务都从它上面获取认证信息。LDAP 是常用的认证协议之一,不仅有许多软件原生支持它的认证(包括 Jenkins,pfSense 等),而且通过插件可以使得 nginx 支持它,为任何基于网页的服务加上统一管理的认证。添加插件 ¶如果你的 nginx 已经是源代码编译的,添加 nginx 的 LDAP 插件只需要三步:apk add openldap-devgit clone https://github.com/kvspb/nginx-auth-ldap.git./configure --add-module=/path/to/nginx-auth-ldap我依然使用 Docker 部署 nginx,Dockerfile 可以在 https://github.com/xddxdd/dockerfiles/blob/210f0f82c7bc1c0c3697d329b73ea31abea6b14a/nginx/Dockerfile 找到,其中的编译参数可以参考。配置认证 ¶安装插件后,先在 nginx.conf 的 http 配置块中添加 ldap_server 配置块。...

nginx:TLS 1.3 多版本草案和 HPACK

距离我之前给 nginx 启用 TLS 1.3 已经过了 11 个月了。快一年过后,许多与 nginx 相关的程序、补丁都有了很大的变化:OpenSSL 已经在发布 1.1.1 的测试版,写本文时最新版本是 1.1.1-pre8(也就是 Beta 6)。nginx 已经更新到 1.15.1。nginx 的 HPACK 补丁(HTTP 头压缩补丁)的 bug 已经有另外的补丁的补丁修复,使用原先的 HPACK 补丁会导致网站访问不正常,体现为每个网站只能打开一个页面,第二个页面开始就出现协议错误。有大佬发布了 OpenSSL 的补丁,可以让最新版 OpenSSL 同时支持 TLS 1.3 的 draft 23,26,28 三个版本。Lets Encrypt 证书已经自带 Certificate Transparency 信息了,不需要 nginx-ct 了。2018 年 7 月 1 日起,TLS 1.0 不再被建议使用。因此我重新调整了 nginx 的编译和运行配置,以适应 8102 年的需要。Dockerfile ¶我依然使用 Docker 部署 nginx。与之前的 Dockerfile 相比,新的 Dockerfile 只是改了下版本号,添加了几个补丁,整体并没有大的变化。为了节省篇幅,我将 Dockerfile 上传到了 https://github....
插图

Kimsufi 独服安装升级 ESXi 并设置软路由

Kimsufi 是法国 OVH 公司的一个廉价品牌,专门出租性价比极高的服务器。我自己租的是 KS-4C 型号,i5-2400 处理器,16GB 内存,2TB 硬盘,百兆带宽无限流量,只需要 13 欧元 / 月,性价比极高,非常适合开虚拟机做实验。VMware ESXi(现在也叫 vSphere Hypervisor)和 Proxmox VE 是两个非常流行的专门用来开虚拟机的操作系统,且两者都是免费的。最重要的是,Kimsufi 的控制面板中都有两款系统的一键安装。但我在使用过程中发现 Proxmox VE 在网络条件不佳的情况下远程控制虚拟机经常连接不上(VNC 黑屏)或者丢键(输密码时尤其要命),因此还是换装了 ESXi。这里又产生了一个问题:ESXi 不是完整的 Linux、FreeBSD 等系统,它不具有 Linux 等所有的 NAT 功能,也就是不能一个 IP 地址开好几台虚拟机然后做端口转发。不过,由于 Kimsufi 同时提供 IPv4 和 IPv6 地址,可以把 IPv4 给一台虚拟机用,让 ESXi 用 IPv6;再设置这台虚拟机做 NAT 就可以了。这就是本文中要做的事。为什么要写这篇文章 ¶因为我在配置的过程中遇到了一堆问题:ESXi 5.0 从命令行下在线升级的方法已经不能用了,会报错;ESXi 6 系列带的网页面板虽然平时管理虚拟机很好用,不需要装客户端,...