博客在 Ubuntu 16.04 上运行了 10 年,我将其迁移到了 FreeBSD
摘要
作者将其博客从一个使用了 10 年的 Ubuntu 16.04 VPS 迁移到了更具成本效益的 FreeBSD VPS,详细介绍了迁移动机、设置过程以及使用 Bastille 的 FreeBSD Jails 入门。
暂无内容
查看缓存全文
缓存时间: 2026/05/21 21:15
# 这篇博客在 Ubuntu 16.04 上跑了 10 年,我把它迁移到了 FreeBSD
原文链接:https://crocidb.com/post/this-blog-ran-on-ubuntu-16-04-for-10-years-i-migrated-it-to-freebsd/
这篇博客在 Digital Ocean 的 VPS 上跑了超过十年。一台位于纽约市的机器,运行着 **Ubuntu 16.04 LTS**。一个已经至少五年不再受支持的 LTS 版本。是时候该换了。经过一番考虑,我迁移到了一台 Hetzner 虚拟机上,它比我那台旧的 Ubuntu 机器好得多,价格还不到之前的一半,而且就在我所在的同一个国家。不仅如此,我还接受了挑战,把我的技术栈搬到了 **FreeBSD** 上。这会是一篇长文,但请耐心看下去,我会介绍 *FreeBSD Jails* 配合 *Bastille* 的酷炫用法,还有一些有趣的站点负载基准测试。
## 动机
如果你了解 Ubuntu 的发布机制(我自己也不太熟),一旦一个版本停止支持,apt 软件包仓库就会被移除,你就再也无法从中获取任何更新了。运行这样一个过时系统会带来多种风险,最明显的就是你的服务器不再那么安全。可能有很多机器人在四处寻找有漏洞的节点,往里面注入恶意内容。幸运的是(我想是吧),什么都没发生。话说回来,里面也没什么重要的东西可偷。但我记得很久以前,我有一个 WordPress 博客,也跑在一台旧 VPS 上,突然就被随机插入了大量指向赌场和赌博网站的非常可疑的链接,散布在文章的文字里。
我当时已经在用一台 Hetzner VPS 作为远程开发机器,可以从任何地方 SSH 进去,而且这个价格的 VPS 一直很可靠。所以我决定先比较一下规格。这是我那台运行博客和其他网站的 droplet:
我的旧 Digital Ocean 服务器
我的旧 Digital Ocean 服务器
它有 2GB 内存、1 个 vCPU、50GB 磁盘、2TB 月流量,运行 Ubuntu 16.04 x64。托管在纽约市的数据中心。这可能就是它这么贵的原因,我每月要付 13 美元。
Hetzner 是一家成熟的欧洲 IT 公司,在我居住的德国有大型数据中心。我能买到的最便宜的 Hetzner 服务器,仅需 **3.56 欧元**,就已经比我的旧服务器好得多了:
一杯咖啡的价格
一杯咖啡的价格
内存和 CPU 翻倍,存储空间略少,但流量是之前的十倍。但我决定选择配置更强的方案,每月不到 6 欧元:
一杯更精致的咖啡的价格
一杯*更精致*的咖啡的价格
对我的站点来说可能有点过头了,但为何不呢?
## 旧设配置
我的旧配置除了这个博客,还服务着几个其他站点。都没有太高的访问量;这个博客,里面最火的站点,一个月也就几千次页面浏览。除非有几篇文章在 Hacker News 上火了一把,否则流量不大。说到底,这台机器基本就只是服务静态站点,没有花哨的 CGI 或自定义代码运行。技术栈很简单。所有内容都由 **nginx/1.10.3** 静态服务。我基本上就是在 `/etc/nginx/sites-available` 里为每个站点放几个配置文件。额外需要的程序像静态站点生成器和 LaTeX 套件(例如:这个博客是由 **Hugo** 生成的),要么通过 `apt` 安装,要么通过 `snap` 安装。实际上,我更新博客的流程是:
- 在本地写文章
- 提交并推送到仓库
- ssh 到服务器
- 拉取仓库更新
- 运行 `hugo`
在使用这台 VPS 的头几年,我还用它来跑一些测试和做点编程。所以它塞满了各种不再使用的过时软件。但它一直运行着,而且运行得还不错。
是的,它跑的是 Linux 4.4!
是的,它跑的是 Linux 4.4!
事实上,它运行得如此之好,以至于在我关掉它的时候,它的运行时间达到了 1491 天!这差不多是连续运行了 4 年!
## 为什么选择 FreeBSD
不瞒你说,我的主要动机之一就是想捣鼓点不一样的东西。我一直在阅读和观看很多关于 BSD 的内容,之前还有一段短暂的 FreeBSD 使用经验,所以我觉得这是一个在实际环境中测试它的好机会。FreeBSD 通常因其稳定性而受到称赞,这得益于其一体化设计、安全性以及 **Jails**。我们很快就会讲到这个。
我不想说得好像我很清楚自己在做什么,但当我读到关于 **Jails** 的内容时,我立刻就知道自己想做什么了。**Jails** 是 FreeBSD 内置的一种虚拟化/容器化形式,已经存在超过 25 年了,比 Docker 出现的时间早得多。乍一看,它能做到你对 Docker 容器期待的一切:它在其中沙盒化一个“迷你系统”,这样你就可以运行那些无法访问宿主机系统的程序。我认为主要的区别在于,Docker 和其他容器解决方案更适合“打包程序”。它们是短暂的、不可变的。它们对来自容器外部的数据进行操作,但在容器内部,一切始终相同。而 Jails 实际上是子系统,几乎像迷你虚拟机,但实际上共享同一个内核。
除此之外,它的文件系统 **ZFS** 对于服务器来说真的很好用。如果你来自 Linux 世界,你可能听说过 **Btrfs**,这是近年来越来越多发行版采用的新文件系统。它与 ZFS 有一些相似之处:数据完整性和快照。只不过 **ZFS** 可能比 Btrfs 成熟得多。如果我对系统进行频繁快照,就不需要依赖 VPS 提供商的快照或备份系统了,那还要额外付费。
我的想法是,为每个站点创建一个 Jail,里面放上构建所需的所有工具(比如博客用的 **Hugo**),以及一个 nginx 实例来服务它。再有一个 Jail 作为主 Web 服务器,通过反向代理将所有站点与世界连接起来。这样一来,如果某个 Jail 被攻破,我就可以直接销毁它并创建一个新的。稍后我会更详细地介绍如何设置它们。
## Hetzner VPS
这里提供更多细节,给各位 `fetch` 爱好者:
不知道为什么 fastfetch 总是报告比实际值更多的已用内存。我在 btop 里看这台服务器从未见过超过 3GiB 的使用量
不知道为什么 fastfetch 总是报告比实际值更多的已用内存。我在 btop 里看这台服务器从未见过超过 3GiB 的使用量
## 配置过程
我会快速介绍我是如何设置这台服务器的,以及最重要的几个点。我通常会写开发日志,所以过程中一直在记录。不过,你不应该把这个当作教程,因为我可能漏掉了一些步骤。这里更多是让你体验一下在 Hetzner 上设置 FreeBSD Web 服务器的感觉。
### 安装 FreeBSD
Hetzner 在创建虚拟机时提供一些镜像,但选择非常有限:
没有 BSD
没有 BSD
但我看到一份指南,介绍了如何从官方的 FreeBSD YouTube 频道(https://www.youtube.com/watch?v=8RGbstrTWUo)在 Hetzner 上安装。顺便说一下,强烈推荐这个频道。
实际上 Hetzner 确实提供了 FreeBSD 镜像,只是藏得比较深,要多几步操作。它作为一个 ISO 镜像提供。所以,当创建过程中提示选择操作系统镜像时,你只需要随便选一个,因为之后你会把它全部清掉。创建完虚拟机后,你只需要进入控制台的 **ISO Images** 选项卡,挂载你想要的镜像:
可用的 FreeBSD ISO 镜像
可用的 FreeBSD ISO 镜像
我选了 **14.3**。然后重启。接着我基本上就跟着安装向导走。我不记得对标准选项做过什么修改,但我当时是跟着官方 FreeBSD 频道的安装视频操作的。很快,系统就安装并运行起来了。
### Bastille
我已经多次提到 Jails 了。但我不仅使用 Jails,还用了 **Bastille(https://github.com/BastilleBSD/bastille)**,这是一个帮助管理 Jails 的系统。实际上,手动创建 Jails 比我想要复杂一些。有几个不同的步骤需要单独处理,而且每创建一个新 Jail 都要做一遍。Bastille 简化了这一切,通过 `bastille` 命令就能搞定所有需求。比如 `bastille list` 显示系统中的所有 jails,`bastille create` 创建一个新的,`bastille console` 在 jail 中打开一个 shell,等等。
安装并启用它(几乎)和描述的一样简单(https://bastillebsd.org/getting-started/):
``
pkg install bastille
sysrc bastille_enable="YES"
``
还有其他 Jail 管理器,我只是选了名字最酷的那个。
## 技术栈
整个构想是:一个 Jail 运行 **Caddy** 来服务所有站点,处理域名和它们的 SSL 证书。然后每个站点有自己的 Jail,里面放置构建和服务所需的一切。服务器 Jail 会将所有流量反向代理到相应的 Jail。所以首先要做的就是在内部配置一个虚拟网络适配器。我们可以把这个技术栈想象成网络中的一组虚拟机。
要设置一个虚拟网络接口:
``
sudo sysrc cloned_interfaces+="lo1"
sudo sysrc ifconfig_lo1_name="bastille0"
sudo service netif cloneup
sudo sysrc ifconfig_bastille0="inet 10.0.0.1 netmask 255.255.255.0"
``
这基本上创建了一个环回接口的克隆,命名为 “bastille0”,并分配了网络参数。Jails 将只在这个网络接口上工作。Caddy jail 需要能够访问外部世界,因为它将监听请求。为此,我们需要使用 PF(Packet Filter),即 FreeBSD 的防火墙,创建一些互联网访问规则。
我们需要编辑 `/etc/pf.conf`:
``
# 主接口 `vtnet0` 和我们创建的虚拟接口 `bastille0`
ext_if = "vtnet0"
int_if = "bastille0"
vpn_if = "tailscale1"
# 跳过内部流量
set skip on $int_if
set skip on $vpn_if
# 允许从 jails 向互联网的出站访问
nat on $ext_if from 10.0.0.0/24 to any -> ($ext_if)
# 将来自 Web 的 HTTP/HTTPS 流量重定向到服务器 jail (10.0.0.5)
rdr pass on $ext_if proto tcp from any to any port {80, 443} -> 10.0.0.5
# 阻止其余一切
block all
# 允许宿主机出站流量
pass out quick on $ext_if keep state
``
正如配置中的注释所说,它基本上是把所有内部流量限制在我们的 `bastille0` 和 `tailscale1` 网络上;然后为我们的 jails 和宿主机系统配置出站流量;最后将所有 `80` 或 `443`(HTTP 和 HTTPS)流量重定向到内部 IP `10.0.0.5`,那将是我们的 Caddy 服务器。
现在我们需要启用 PF:
``
sysrc pf_enable="YES"
service pf start
sysrc gateway_enable="YES"
``
网络栈的部分就这些。我们来创建 Caddy 服务器 jail。
### 创建第一个 Jail:Caddy 服务器
我的旧服务器运行的是老牌的 `nginx`。除了用过一点 `Apache`,我大部分时间都在用 nginx。但 nginx 有一个烦人的地方,而 `Caddy` 很巧妙地解决了:SSL 证书。在旧服务器上,我必须时不时运行 `certbot` 来续期域名 SSL 证书,而我错过续期的频率比我希望的要高。Caddy 会自动处理这个问题。
要创建一个新的 jail,首先我们需要用我们将使用的 FreeBSD 版本进行引导,我这里用的是 `14.3-RELEASE`:
``
bastille bootstrap 14.3-RELEASE
``
然后创建实际的 jail:
``
bastille create caddy 14.3-RELEASE 10.0.0.5 bastille0
bastille start caddy
``
我们创建了一个名为 `caddy` 的 jail,使用 `14.3-RELEASE`,IP 为 `10.0.0.5`,位于 `bastille0` 接口上。
要检查 jail 的状态:
``
# bastille list
JID Name Boot Prio State Type IP Address Published Ports Release Tags
3 caddy on 99 Up thin 10.0.0.5 - 14.3-RELEASE -
``
瞧,它已经在运行了!记住,jails 不像 Docker 容器那样是“短暂的”,你设置好整个容器配置,启动它,然后期望机器永远保持一致。我们这里几乎是在处理虚拟机。我们可以随时通过以下命令访问 shell:
``
# bastille console caddy
[caddy]:
root@caddy:~ #
``
#### 设置 Caddy 服务器
由于我们已经位于 `caddy` jail 中,只需要安装 Caddy:
``
pkg install caddy
sysrc caddy_enable="YES"
service caddy start
``
Caddy 的所有配置都在 jail 内的 `/usr/local/etc/caddy/Caddyfile` 中。如果我们想从宿主机系统访问那个配置文件,需要将宿主机上的一个目录挂载到 jail 中。我们甚至可以用只读模式挂载,这样 jail 就无法修改配置。类似于这样:
``
bastille mount caddy /usr/local/etc/my-caddy-config /usr/local/etc/caddy nullfs ro 0 0
``
好了,服务器几乎配置好了,但我们还没有站点。所以让我们创建一个站点 jail,然后再回来配置 Caddy。
## 第一个站点:*es.cro.to*
回顾疫情期间,巴西总统表现得好像新冠病毒只是小感冒,没有采取任何封锁的紧急政策。他经常说国家停摆不起,如果一些人必须死,那就死吧。完全无视科学,甚至常识。历史证明他是多么错误。由于不满于此,我想 “抗议” 一下。
于是我创建了一个小页面 `es.cro.to`,它在葡萄牙语中的字面意思是 “阴囊”,但常用来形容一个“卑鄙小人”、“混蛋”之类的人。我注册了域名 `cro.to`(事后看来,这个域名真的很酷,英语里听起来也不错),并添加了子域名 `es`。它按单词的精确音节划分,就像你在字典里看到的那样,所以我既添加了词的定义,也放了那个家伙的图片:
escroto
escroto
当然,它托管在我的旧服务器上,并在那段封锁期间获得了相当大的流量。我决定从它开始,毕竟它只是一个带有严重压缩照片的页面,而且现在也没那么重要了。
那个站点是一个 git 仓库(https://github.com/crocidb/escroto),就像我将运行的所有其他站点一样。所以我准备在宿主机系统上把所有站点放在 `/usr/local/www` 中,然后将特定站点的目录以只读方式挂载到它们各自的 jail 中。当我把这个站点放在 `/usr/local/www/escroto` 后,就用 bastille 创建 jail。这次,我将使用一个 bastille 模板用于 nginx:`www/nginx`。模板只是预安装一些软件的小脚本。我不一定非要用,但为何不呢?
``
bastille bootstrap https://github.com/bastillebsd/templates
bastille create escroto 14.3-RELEASE 10.0.0.11 bastille0
bastille template escroto www/nginx
``
我使用 IP `10.0.0.11` 创建了它。稍后我们会需要这个 IP。此时,那个 jail 的 nginx 已经在 nginx 的默认页面提供服务了。它位于 `/usr/local/www/nginx`(注意 FreeBSD 几乎把所有东西放在 `/usr/local` 里)。
然后我将宿主机的网站目录挂载到 jail:
``
bastille mount escroto /usr/local/www/escroto /usr/local/www/escroto nullfs ro 0 0
``
现在,从 jail 内部,我可以访问 `/usr/local/www/escroto` 中的站点。由于它是一个 git 仓库,包含一些不应被提供服务的文件(`.git`)。所以我写了一个 `deploy.sh` 脚本来将 `/usr/local/www/escroto/*` 的内容复制到 `/usr/local/www/nginx/*`,并删除 `.git` 目录:
``
rm -fr /usr/local/www/nginx/*
cp -R /usr/local/www/escroto/* /usr/local/www/nginx/
rm -fr /usr/local/www/nginx/.git
``
想法是,每次我需要部署那个站点的新版本时,我会登录到宿主机服务器,更新仓库,然后运行那个脚本:
``
cd /usr/local/www/escroto
git pull
bastille cmd escroto /root/deploy.sh
``
我
相似文章
我的新家庭服务器软件选择
一篇个人博客文章,详细描述了作者为新家庭服务器选择操作系统和服务管理软件的经历,比较了Synology、TrueNAS、Debian以及使用Runit的Void Linux。
FreeBSD 网站的新设计
FreeBSD 项目为其官方网站推出了新设计,突出了操作系统的特性,如 ZFS、虚拟化、Jails、网络、文档和社区。
评测:FreeBSD 上的 Sylve
对 Sylve 早期版本的评测,这是一款用于 FreeBSD 的开源 Web 管理工具,可简化 jails、虚拟机和 ZFS 数据集的管理。
FreeBSD 基金会执行董事尝试在笔记本电脑上日常使用 FreeBSD
FreeBSD 基金会执行董事 Deb Goodkin 成功在 Framework 笔记本电脑上日常使用 FreeBSD,克服了长期存在的硬件支持问题。
FreeBSD 的 AI 审计
一次 AI 辅助的安全审计揭示了 FreeBSD 内核中的 15 个漏洞,包括权限提升和虚拟机逃逸,并详细描述了与 FreeBSD 团队协作报告和修补漏洞的过程。