文章

自建云服务器历程

自建云服务器历程

前段时间,我突发奇想,想把实验室里一台闲置已久的电脑改造成自己的云服务器。它原来运行的是 Windows,我前后花了一两周、断断续续地清理和修复硬件,最后重新安装了 Ubuntu 24.04 LTS Server。这里的 Server 版本默认不带桌面环境,安装完成后看到的主要就是命令行界面;这并不意味着系统没有 DHCP,是否能自动获得 IP 地址,还取决于网卡是否启用、网络配置(Ubuntu 24.04 通常由 Netplan 配合 systemd-networkd 或 NetworkManager 管理)以及路由器是否提供 DHCP 服务。

安装系统时,我先尝试用 Ventoy 制作启动 U 盘。这个 U 盘已经用了接近十年,读写速度和兼容性都有些不稳定,Ventoy 制作的启动盘在这台旧电脑上出现了识别不完整、启动缓慢的问题。后来我改用把 Ubuntu ISO 镜像直接写入 U 盘的工具,启动过程才稳定下来。无论具体使用的是 Rufus 还是 balenaEtcher,这类工具的共同点都是将镜像完整写入设备,而不是只把 ISO 文件复制进去。

系统装好后,真正耗时的是联网。最初我想让主机通过无线网卡连接路由器,后来又尝试过手机热点,但无线接口始终没有正常获得地址。排查 ip addr(或 ip -br addr)的输出时,我发现有线接口其实处于关闭状态;Linux 中网卡名称通常是 eno1eno2enp3s0 这类可预测名称,而不是固定的“ECNO/ENCO”。启用正确的接口、接入网线后,主机仍然需要连接到提供 DHCP 的路由器,才能自动获得 IP、默认网关和 DNS。最初把网线直接插到另一台电脑上时,没有路由器或其他 DHCP 服务提供这些信息,所以链路即使接通,也不会自动联网;最后改接路由器并完成接口配置后,网络才真正恢复。

现在,这台 Ubuntu 服务器逐渐变成了一个固定的中枢。设备可以更换,工作流和数据不必跟着漂流。

Codex 作为工作台

网络打通后,最先体现出来的是远程工作的便携性。我在 Mac 上通过 Codex 发起远程连接,实际打开和操作的是 Ubuntu 服务器上的项目目录。Tailscale 在这里提供的是一层私有的组网通道:Mac 和服务器像处在同一个局域网里,但不需要把服务端口直接暴露到公网,也不需要每次都把文件复制到 Mac 上。

当前个人云和 Readest 这两套 Compose 服务的管理界面默认只绑定在服务器的回环地址 127.0.0.1,再通过 Tailscale 的私有入口访问;moontv服务则单独配置端口和网络。这样,代码、配置、笔记和运行中的服务都留在服务器上,我只需要带着 Mac 和 Codex,就能进入同一套工作环境。

文件同步

我平时会在 Mac、Windows、手机和平板之间来回切。论文附件在 Zotero 里,课程资料可能在某块硬盘上,随手记下的东西又在 Obsidian。以前每换一台设备,数据无法同步就很麻烦。

所以我没有一开始就给服务器列一长串软件清单。我只是把最常遇到的几件事一件件搬过去:文件和论文、笔记、书、新闻订阅、电影,还有博客。它们最后看起来像一套系统,但最初都只是为了解决一个很具体的小麻烦。

挂载硬盘

这台机器上有几块很老的机械硬盘。其中一块始终没能被系统识别,剩下的盘里,一块保留原来的 Windows 数据,另一块则被我重新格式化成 ext4,作为服务器的数据盘。

系统盘负责 Ubuntu 和 Docker 的运行,数据盘负责文件、书、媒体和之后的备份。 我现在还在慢慢整理旧盘里的东西,没有急着把所有文件一股脑迁过去。

文件、论文和笔记的同步方式

Nextcloud 是最先跑起来的服务之一。我主要用它放普通文件,也把 WebDAV 留给 Zotero 的附件。Zotero 的文献库本身还是按 Zotero 的方式同步,服务器只负责那些 PDF、补充材料和其他附件。这样要找一篇论文时,至少不用再猜它是在电脑、网盘还是移动硬盘里。

笔记的情况不太一样。Notion 用起来很顺手,但它更像一个在线工作台;有些本地文件、Markdown 和资料夹塞进去以后,总觉得隔着一层。后来我把日常笔记放到 Obsidian,服务器负责它的同步后端。这里最需要克制的一点是:同一个 Vault 只选一种同步方式。同步工具越多,不一定越安心,反而更容易在某一次冲突后不知道该信哪份文件。

阅读和 RSS

书原来散在各处:下载过的 EPUB、临时存下来的 PDF、看了一半就找不到的资料。现在我把它们慢慢导入 Readest。

Readest 背后其实有好几个容器:数据库、认证、对象存储和网页端各自运行。我不需要每天关心它们,只要在 Mac 上打开页面,接着昨天的地方读就行。书最后会放到服务器的数据盘,不过在确认备份可靠之前,我不会马上删掉本地副本。

FreshRSS 解决的是另一种“堆积”。新闻、博客和论文更新如果全靠算法推荐,很容易刷过去就没了;于是我单独部署了 FreshRSS,把真正想长期追踪的网站放进去。它大约每二十分钟更新一次订阅源。、

电影:Jellyfin 和 MoonTVPlus

Jellyfin 适合整理自己的媒体库。硬盘里那些我拥有或有权访问的文件,放进去以后有海报、分类、播放进度,看起来终于不像一串乱七八糟的文件名。

但我很快发现,自己并不想为了看一部电影就先把所有内容都下载到服务器里。后来我又折腾了 MoonTVPlus。它是另一套独立的部署,有自己的容器和 KVrocks 数据存储,不会和笔记、书库混在一起。

最难的是不同接口的格式不一样:有些是网页播放器能识别的,有些更像给电视盒子用的。为此我做了一个适配层,把它们变成 MoonTVPlus 能读的苹果流媒体标准格式。现在影片检索已经能用,直播源还在继续调。

Docker 不是魔法

这台机器上的服务大多用 Docker Compose 启动。它没有让维护消失,只是把端口、目录和依赖写进了文件里。以后服务出了问题,我至少可以回头看配置和日志,不用靠回忆猜自己当时点过哪些按钮。

博客终于不用在每台电脑上各装一遍

我之前已经有一个 GitHub Pages 博客,但为了在本地预览和写作,我在两台 Windows 和一台 Mac 上都装过 Docker。每次想写一篇文章,都得先确认那台电脑的环境还能不能跑起来,写作这件事反而被启动环境打断。

现在博客仓库放在服务器的工作目录里。我用 Codex 远程打开它,直接修改 Markdown,检查一下,再用 Git 推送到 GitHub。发布还是 GitHub Pages 的事,服务器没有替代 GitHub;

不过它已经开始融进日常:一篇论文的附件、一段读书标注、一条 RSS 更新,或者一篇刚改完的博客,都不再只属于某一台电脑。

这篇文章本身也是一次实验。我用麦克风把这几天想到的事说给 Codex,再让它帮我整理和润色,最后由我自己审核、修改和决定留下什么。所以文中或许仍有一些 AI 的痕迹,算是一份很小的复盘。

本文由作者按照 CC BY 4.0 进行授权