加密一台 VPS 看起来就是一行命令——cryptsetup luksFormat,搞定——但随后就会悄悄地达不到人们以为自己买到的效果。在一台你租来的机器上,内核之下还跑着一层 hypervisor,所以威胁模型和全盘加密最初设计所针对的那个并不是同一个。这篇指南讲真话:LUKS 在 VPS 上真正能防住什么、防不住什么、两条可行的部署路径,以及如何通过 SSH 解锁一个加密的根文件系统,让你永远不会被锁在自己的服务器外面。
在租来的服务器上,加密到底能换来什么
全盘加密保护的是“静态数据”(data at rest)。这个说法承载了很多含义,在 VPS 上尤其值得把哪些时刻算“静态”、哪些不算说清楚——大多数落空的期望,正是出在这两者之间的落差上。
退役的硬件
硬盘会坏,会被更换,然后离开机架。对接下来接手这块盘的任何人来说,一个 LUKS 卷就是一整块噪声。加密能彻底解决这种情况。
被拆下或被复制的卷
如果一个卷在机器关机状态下被从你的实例中拆走、克隆或做成镜像,拿到的结果只是密文和一个头部信息——不是你的文件。
运行中的机器
一旦卷被打开,主密钥就常驻在内核内存里。Hypervisor 级别的访问权限原则上可以触及它。加密在这里只是提高了成本,并没有把门彻底关上。
你自己犯的错
未加密的 swap、明文备份,以及挂载之前就写下的日志,全都待在加密容器之外。加密服务器上大多数真实的泄露,都是从这里发生的,而不是密码算法本身被攻破。
把这个局限说明白,你才能据此规划:卷解锁期间,密钥就存在于一台不属于你的硬件的 RAM 里。在 VPS 上,LUKS 对离线访问是一个强有力的答案,对在线访问则只是部分答案。把它和一个你真正信得过的司法管辖区搭配使用——参见 /offshore-hosting——而不是拿它来替代对司法管辖区的选择。
先选定方案,再敲命令
四种方案几乎覆盖了所有真实需求。选错了就得重装一遍,所以现在就做决定,而不是做到一半才发现。
路径 A——为一台已经在运行的服务器加密一个数据卷
这是大多数人真正想要的版本:十分钟搞定,不需要重装,所有重要的东西最终都会落在加密容器里面。先挂载第二个卷——在 /storage 套餐上,那就是那块大容量硬盘;在标准的 /vps 上,你可以在部署时就加上一块。
- 1
确认目标设备
运行 lsblk,确认你即将格式化的设备就是那块空盘。luksFormat 会摧毁它上面原有的一切,而且没有撤销。
- 2
创建 LUKS2 容器
cryptsetup luksFormat --type luks2 /dev/vdb 会要求你输入大写的 YES,然后设置一个密码短语。选一个即使在没有历史记录、没有回显的控制台上,你也能准确重新输入的密码短语。
- 3
打开容器并建立文件系统
cryptsetup open /dev/vdb cryptdata 会创建出 /dev/mapper/cryptdata。接着执行 mkfs.ext4 /dev/mapper/cryptdata,再把它挂载到数据将要存放的位置,例如 /srv/data。
- 4
决定开机时如何解锁
要么每次重启后手动输入密码短语,要么用 cryptsetup luksAddKey 添加一个密钥文件,并存放在根分区上。密钥文件更方便,但安全性绝对更弱——想清楚自己在做怎样的取舍。
- 5
配置 crypttab 和 fstab
把映射关系用 UUID= 而不是设备名写进 /etc/crypttab,再通过 /etc/fstab 挂载,并加上 nofail,这样即使解锁失败也不会卡住整个启动过程。
如果密钥文件放在未加密的根分区上,要精确认识自己得到的是什么:这个卷能防住离开机架的硬盘,或从你的实例上被拆走的硬盘,但防不住整台虚拟机的副本——因为那份副本里连密钥也一起拷走了。想要更强的保护,密码短语就必须来自服务器之外。
路径 B——通过自定义 ISO 实现加密根分区
如果要求是机器关机时,机器上不存在任何可读的内容,那么根分区本身就必须放进 LUKS 里。这意味着要从控制台驱动一次全新安装,而且主机商得允许你启动自己的 ISO。
- 1
从控制台启动安装程序
把一个 Debian 或 Ubuntu 的 netinst ISO 作为自定义 ISO 挂载,通过 VNC 或串口来完成安装。这一步完全没法通过 SSH 完成——因为此时还没有系统可以连接。
- 2
使用带加密 LVM 的引导式分区
安装程序会留出一个小的明文 /boot 分区,因为总得有东西在卷被打开之前先运行起来,然后把 root 和 swap 都放进同一个 LUKS 容器里。
- 3
选一个你能盲打的密码短语
每次重启,你都要在没有回显、没有自动补全的 SSH 会话里重新输入一遍。这种场合下,一句五个单词的密码短语比一串符号乱码更好用。
- 4
在退出登录之前配置好远程解锁
一个刚加密好的根分区,下次重启后会永远停在密码提示符那里等着。要在同一个会话里就把远程解锁配置好,趁控制台此刻还在你眼前。
在 RAM 只有 1–2 GB 的套餐上,默认的 Argon2id 密钥派生可能会索取比 initramfs 所拥有的更多内存,导致即使密码短语完全正确,开机解锁依然会失败。可以在格式化时用 cryptsetup luksFormat --pbkdf-memory 262144 加以限制,或者用 cryptsetup luksDump 检查一个已有的头部信息,再决定是否放心让一台小实例无人值守地重启。
用 dropbear-initramfs 通过 SSH 实现远程解锁
加密的根分区,需要在操作系统存在之前就拿到密码短语。dropbear-initramfs 会在 initramfs 里放进一个体积极小的 SSH 服务,让你可以从任何地方把密码短语传进去——这是加密服务器和一块加密砖头之间的全部区别。
- 1
安装软件包
apt install dropbear-initramfs。它会挂接到 initramfs 的生成过程中,此后每一个新内核镜像都会自动把它重新构建进去。
- 2
只授权一把密钥,且只允许一条命令
把你的公钥放进 /etc/dropbear/initramfs/authorized_keys——在 Debian 11 及更早版本上,路径是 /etc/dropbear-initramfs/authorized_keys。在这一行前面加上 no-port-forwarding,no-agent-forwarding,no-x11-forwarding,command="cryptroot-unlock" 前缀,这样即使密钥被盗,拿到手的也只是一个提示符,别无他用。
- 3
给 initramfs 配上网络
如果主机商提供 DHCP,直接用就行;否则就在 GRUB_CMDLINE_LINUX 里添加一个静态的 ip=ADDRESS::GATEWAY:NETMASK::eth0:off 参数,再运行 update-grub。最后执行 update-initramfs -u -k all,让改动落实到镜像里。
- 4
在依赖它之前先完整测试一次重启
重启时在另一个窗口开着主机商的控制台,连接上去,输入密码短语,看着启动过程继续往下走。一条没有测试过的解锁路径不是一项功能,而是一次尚未发生的宕机。
initramfs 携带着它自己的 SSH 主机密钥,和启动完成后的系统所出示的那把不一样,所以你的客户端每次重启都会警告主机密钥发生了变化。可以通过 /etc/dropbear/initramfs/dropbear.conf 里的 DROPBEAR_OPTIONS,让 dropbear 监听一个独立的端口,或者用 ssh -o HostKeyAlias=box-initramfs 来连接,并把两把密钥的指纹都记录下来。
磁盘加密通常败在密钥管理上
密码算法从来都不是薄弱环节。每一场和 LUKS 有关、还能挽回的灾难,归根结底都出在密钥或头部信息上,所以要把这两者都当作基础设施来对待。
- 立刻备份头部信息——cryptsetup luksHeaderBackup /dev/vdb --header-backup-file luks-header.img——并存放在服务器之外。哪怕密码短语完全正确,一次不小心的 dd 损坏了头部,数据也会永久丢失。
- 使用两个密钥槽。LUKS2 给你 32 个:一个放你的密码短语,另一个放一串又长又随机的恢复密钥,保存在密码管理器里。只用一个槽位,等于自己给自己制造了一个单点故障。
- 在远程机器上按正确顺序轮换密钥——先用 luksAddKey 添加新密钥,验证它确实能打开这个卷,再用 luksKillSlot 移除旧密钥。顺序绝不能反过来。
- 把密码短语和服务器的连接信息分开存放。一份笔记一旦泄露,不应该同时交出地址和密钥。
加密在性能上的代价
这个开销是真实存在的,但通常感觉不到。用你实际拥有的这台机器去实测,而不是相信一份出自另一个年代的跑分。
人们常常忽略的部分
一个边缘不断泄出明文的加密卷,带来的只是一种虚假的安全感,而这比完全没有安全感更糟。把下面这五点都堵上,才能说这项工作真正完成了。
- Swap。一个未加密的 swap 分区,可能保留着任何曾经经过内存的东西的碎片。可以在 /etc/crypttab 里用一条 /dev/urandom 的条目,让它每次开机都用一把全新的随机密钥加密。
- 挂载之前写下的日志。加密卷还没打开时产生的任何日志,都会落在明文的根分区上。把应用和数据库的日志路径指向加密容器内部。
- 备份。把加密卷里的内容直接复制到明文的对象存储里,等于把之前所有的努力全部推翻。要用 restic、borg 或 age 对备份单独再加密一次,并把这些密钥保存在别处。
- 快照。主机商的快照捕获的是硬盘,不是你的 RAM,所以 LUKS 卷在快照里依然是密文——但留在未加密根分区上的一切,则会被原封不动地捕获下来。
- Discard。让 discard 标志穿透 LUKS 传递下去,能让 NVMe 的 trim 继续生效,但也会暴露出哪些块处于未使用状态,从而泄露文件系统的使用程度和大致形状。要有意识地做这个选择,而不是照抄一份配置了事。
主机商仍然举足轻重的地方
加密是你能控制的那一层:它决定了机器关机后,或者硬盘离开机房之后,读取你的数据要付出多大的代价。围绕在它周围的那一层——谁能强制获取硬件访问权限,又有哪些记录把服务器和你本人联系在一起——则属于主机商和它所在的司法管辖区。我们的十五个地区中,有六个属于隐私优先级司法管辖区;/locations 列出了它们,/offshore-hosting 讲清楚了这一点具体会带来什么不同。
主机商的三项能力,决定了上面这些方案是否可行:自定义 ISO 启动——没有它,路径 B 根本无从谈起;带外控制台访问——用来应对远程解锁失败后的那次重启;以及一套从一开始就没有把这台机器和你的法定身份绑在一起的注册流程。这里的每一个 /offshore-vps 和 /storage 套餐都支持启动自定义 ISO、都提供控制台访问,并且都是从一份免 KYC 的预付加密货币余额中扣费——这样一来,加密硬盘之下就不会垫着一份早已写明你身份的文件记录。/guides 里有一篇诚实的讲解,说明主机商能看到什么、看不到什么。
部署清单
- 先说清楚你要防的是什么威胁:退役硬盘、被拆走的卷,以及离线镜像,这些才是加密能够应对的;一个正在运行的 hypervisor 不在此列。
- 如果服务器已经在运行,就加密一个数据卷(路径 A);只有当根分区本身必须加密时,才需要从自定义 ISO 重装(路径 B)。
- 使用 LUKS2 搭配 aes-xts-plain64,并在 RAM 低于 2 GB 的套餐上限制 Argon2id 的内存用量。
- 密码短语放一个密钥槽,一串又长又随机的恢复密钥放另一个密钥槽,两者都存放在服务器之外。
- 在写入第一个字节的真实数据之前,先备份好 LUKS 头部信息。
- dropbear-initramfs 跑在非默认端口上,只允许密钥登录,并限制为只能执行 cryptroot-unlock 命令。
- 在主机商的控制台仍然开在旁边的情况下,完整测试一遍重启加解锁的流程。
- 做好异地加密备份,并至少演练一次恢复——一份没有验证过的备份,只是一种期望,算不上真正的备份。
磁盘加密能阻止主机商读取我的数据吗?
静态时可以:机器一旦关机,卷就是密文,而密码短语从没离开过你的脑子。但服务器运行、卷处于打开状态时,主密钥就存在于主机商所运营硬件的 RAM 里。加密封住了所有离线路径——退役硬盘、被拆走的卷、冷镜像——并提高了其余路径的成本。它是对一个可信司法管辖区的补充,而不是替代。
能不能在不重装的情况下加密一台已有的 VPS?
如果是单独的数据卷,可以,大约十分钟就能搞定——也就是上面的路径 A。根文件系统的话,现实地说不行。cryptsetup reencrypt 确实可以就地转换文件系统,但在一台远程机器上,转换过程中一旦断连或者遇上电源事件,留下的就是一台无法启动的服务器和一个漫长的不眠夜。从自定义 ISO 重装反而更快,也安全得多。
LUKS 会带来多大的性能损耗?
比大多数人预想的要小。有了 AES-NI,AES-XTS 在典型的混合负载下只损耗百分之几,在现代 EPYC 核心上运行 cryptsetup benchmark 能跑出几 GB/s 的速度。看得见影响的场景,是针对高速 NVMe 的单线程顺序 I/O,这时一颗核心可能会比硬盘更早跑满。实测你自己的实例,而不是靠猜。
如果忘记了密码短语会怎样?
数据就没了。没有恢复机制,主机商那边也没有主密钥,更没有哪张工单能挽回——这个特性正是设计初衷所在。想保护好自己,就用第二个密钥槽存放一串随机恢复密钥,并把 LUKS 头部备份存放在服务器之外的地方。
在 initramfs 里跑 SSH 有风险吗?
这是一处很小、也被充分理解的暴露面。dropbear 只在根文件系统存在之前的那几秒钟里运行,只接受公钥登录,还可以被限制成只能执行一条强制命令,而这条命令除了提示输入密码短语之外什么也做不了。只要用非默认端口,并把 initramfs 的主机密钥单独记录下来,相比没有它就必然被锁在外面的确定性风险,这点实际风险微乎其微。


