我基于 Incus OS 的自托管基础设施

Lobsters Hottest 新闻

摘要

Solène 详细介绍其基于 Incus OS 重建的家庭自托管基础设施架构,涵盖可丢弃系统容器、默认拒绝网络、密钥管理、自动更新、备份、监控与安全设计,思路源自 SecNumCloud 与 ISO 27001 原则。

<p><a href="https://lobste.rs/s/q0wobg/my_self_hosted_infrastructure_with_incus">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/10/16 04:29

# Solene'% : 我基于 Incus OS 的自托管基础设施 来源: https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html 作者 *Solène*,发布于 2026年10月15日。标签: \#selfhosting (https://dataswamp.org/~solene/tag-selfhosting.html) \#security (https://dataswamp.org/~solene/tag-security.html) \#linux (https://dataswamp.org/~solene/tag-linux.html) \#containers (https://dataswamp.org/~solene/tag-containers.html) ## 目录 - 1\. 引言 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Introduction) - 2\. 整体架构 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_The_big_picture) - 3\. Incus OS (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Incus_OS) - 4\. 一次性系统容器 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Disposable_system_containers) - 5\. 默认拒绝的网络策略 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Network_denied_by_default)- 5\. 1\. 出站流量 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Outgoing_traffic) - 5\. 2\. 入站公网流量 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Incoming_public_traffic) - 5\. 3\. 通过 VPN 的私有访问 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Private_access_through_the_VPN) - 6\. 密钥管理 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Secrets_management) - 7\. 自动更新 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Automatic_updates) - 8\. 备份 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Backups) - 9\. 监控与日志 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Monitoring_and_logs) - 10\. 安全性 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Security)- 10\. 1\. 机密性 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Confidentiality) - 10\. 2\. 完整性 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Integrity) - 10\. 3\. 可用性 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Availability) - 11\. 挑战 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Challenges) - 12\. 结论 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Conclusion) - 13\. 延伸阅读 (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Going_further) ## 1\. 引言§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Introduction) 在过去的七个月里,我把自己(很少的)空闲时间很大一部分投入到了在家重建自托管基础设施上。我想要一套安全、完全自动化、能够自我更新的系统,并且在出现问题时可以从零开始重新构建。大部分思路来源于我在工作中参与的遵循 SecNumCloud(法国针对云服务提供商的安全标准)的基础设施项目,以及在较小程度上参考 ISO 27001,我想看看在家能将同样的原则应用到什么程度。 在这篇博客文章中,我会解释我的个人基础设施是如何运作的、各个部分如何协同工作,以及我认为每层安全措施为何有价值。这不是一份循序渐进的指南,我不会深入代码细节,目标是展示架构及其背后的原因。 在继续之前,我需要坦诚:这是一套运行在家里单台机器上的个人基础设施,对大多数人来说可能完全过度设计了。如果你只是想为家人搭建一个 Nextcloud,下面的很多内容都是不必要的。但在这个过程中我学到了很多,尤其是在容器和 cloud\-init 方面,我对结果非常满意 :) 托管服务器没有什么特别的,就是一台普通笔记本电脑,16 GB 内存、一块 NVMe SSD 和一块网卡,放在我的运营商光猫旁边。 ## 2\. 整体架构§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_The_big_picture) 所有东西都运行在这台笔记本上。操作系统是 Incus OS,一个小巧的不可变系统,只运行 Incus——一个系统容器和虚拟机的管理器(它类似 Proxmox,但更侧重容器)。 Incus OS 官方网站 (https://linuxcontainers.org/incus-os/) 在此之上,大约有二十个 Ubuntu 系统容器,每个服务一个,另外还有两个虚拟机用于更敏感的部分。在每个系统容器内部,应用程序本身以 podman 容器的形式运行,通过 "quadlet" 文件描述,即 systemd 会将其转换为服务的文件。所以存在两层容器:Incus 实例,以及其内部的 podman 容器。 我目前托管着以下服务: - Nextcloud - Forgejo,附带一个 CI runner - Immich,用于存放智能手机拍摄的照片/视频 - PeerTube,用于视频 - Vaultwarden,用于密码管理 - Kanboard - Uptime Kuma 和 SmokePing,用于网络监控 - 一个静态网站 - 一套监控栈:Prometheus、Grafana、Loki、Alertmanager - CrowdSec - 用于备份的 restic 没有任何东西是手工配置的。所有内容都从一个 git 仓库中声明,使用 OpenTofu(Terraform 的开源分支)和 cloud\-init(在云系统首次启动时进行配置的工具)。 系统容器是非特权的,这意味着容器内的 root 用户在宿主机上并不是 root。与为每个服务运行一个虚拟机相比,这非常高效:内存和磁盘占用都低得多,而且一切运行得相当快。 下面是整体架构的示意图: 架构示意图架构示意图 (https://dataswamp.org/~solene/static/selfhosting-infrastructure-incus-os.svg) ## 3\. Incus OS§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Incus_OS) Incus OS 是整个体系的基石,我选择它是因为它尽可能地被锁定。它自带: - 启用 Secure Boot - A/B 分区启动:更新写入另一个分区,如果需要可以回退到之前的系统 - 无本地访问:没有 shell、没有 SSH、没有包管理器,通过本地接入笔记本什么也做不了 - 使用 TPM 进行磁盘加密(这允许无需输入密码短语即可自动重启,但如果有人偷走了笔记本,它仍然可以启动,攻击者可以像在我局域网中一样对系统进行本地攻击) 它不对互联网开放,我从局域网内通过 Incus API 进行管理,使用证书进行身份验证。 一个意想不到的副作用是,我不再使用 SSH 来管理基础设施了。不需要管理 SSH 密钥,不需要加固 SSH 端点,也不再有 TERM 变量的问题。当需要查看某个实例内部时,我可以用 `incus exec` 运行命令,或用 `incus shell` 打开一个 shell,全部通过 Incus API 完成。整个设置中唯一的 SSH 是 Forgejo 提供的 git over SSH 访问,那是一个应用功能。 ## 4\. 一次性系统容器§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Disposable_system_containers) 这可能是我最喜欢的部分。每个实例都是从全新的 Ubuntu 云镜像创建的,cloud\-init 在首次启动时完成一切工作:升级系统、安装 podman、写入 quadlet 文件、解密密钥、启动服务。我的灵感来自于使用 Qubes OS 的经验。 当我更改实例上的任何内容(配置文件、容器、命令、命令顺序)时,OpenTofu 会销毁该实例并从零开始重新创建它。不存在配置漂移,运行的就是 git 中的内容。如果有人设法进入某个容器并留下了一些东西,下次重建时它就会消失。 只有数据是持久化的,存放在专用的 Incus 卷中: - 一个用于 podman 存储的卷,应用程序的命名卷都存放在这里 - 一个用于实例密钥(其解密密钥)的卷 - 一个 apt 包的本地缓存,用于加速重建 由于系统部分是完全一次性的,我甚至可以在没有太大麻烦的情况下用另一个发行版替换 Ubuntu,反正应用程序都是在 podman 容器中运行的。 这种做法的代价是:在变更过程中,该组件会有一到两分钟不可用,等待它重建完成。但换来的是,每次我做出更改时,我都确定它在下次启动时仍然有效,而且我知道如有需要可以重建整个系统。 ## 5\. 默认拒绝的网络策略§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Network_denied_by_default) 所有实例都连接到一个内部网桥上,并使用 Incus ACL 在两个方向上默认拒绝一切流量,包括实例之间的通信。每一条被允许的网络连接都在 OpenTofu 代码中声明,并附上其存在的原因说明。例如,反向代理可以访问每个后端的确切端口,Prometheus 可以访问指标导出器,每个实例都可以将日志发送到 Loki,但 Nextcloud 无法与 Vaultwarden 通信。 这样做的目的是让系统之间相互保护。如果某个服务被攻破,攻击者不应该能轻易跳转到其他服务。 对于最敏感的部分,有两个虚拟机: - haproxy 虚拟机,它是唯一连接到物理网络的机器,接收来自互联网的流量(DMZ) - CI runner,因为 CI 任务会运行任意代码,它还具备 Docker in Docker 功能以运行嵌套容器,这需要一些特权 容器的隔离性比虚拟机稍弱一些,但对我的威胁模型来说是可以接受的。对于最容易受到不可信输入的部分,我倾向于使用管理程序级别的安全性。 ## 5\.1\. 出站流量§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Outgoing_traffic) 大多数实例无法直接访问互联网。一个专用实例充当唯一的出口点,提供: - 一个带有允许域名列表的 HTTP 代理,其他一切都被拒绝(该域名列表由所有消费者共享,这在当前场景下是可以接受的) - 一个 apt 包的缓存代理(apt\-cacher\-ng) - 我所使用的容器镜像仓库的本地镜像(直通缓存):Docker Hub、GitHub 和 Codeberg 所有实例都使用这些来获取其软件包和容器镜像,少数需要访问互联网的应用程序通过过滤代理进行。少数无法通过代理的例外(例如公共反向代理的 ACME 证书、CI runner、Uptime Kuma 的探测请求或到 S3 的备份)都有明确的 ACL 规则并记录在案。 这样做的好处是,即使某个服务被入侵,也很难从任意服务器外泄数据或下载第二阶段的载荷。重建二十个实例不会对上游镜像造成负载,也不会浪费网络带宽。 ## 5\.2\. 入站公网流量§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Incoming_public_traffic) 公网流量要经过好几层。 `` Internet | v haproxy VM (CrowdSec bouncer with nftables) | raw TCP + PROXY protocol v caddy (public) --> public services `` haproxy 虚拟机只转发原始 TCP,它永远看不到明文流量,也不持有任何证书或私钥。它使用 PROXY 协议,这是在连接开头添加的一个小头部,携带原始客户端 IP,这样即使中间有 NAT 和容器,caddy 也知道真正的连接者是谁。 在同一台虚拟机上,CrowdSec 防火墙 bouncer 在 nftables 层面直接丢弃信誉不佳的 IP 的连接,甚至在 haproxy 接受连接之前就完成了。CrowdSec 从 Loki 读取 caddy、Forgejo 和 Nextcloud 的日志来检测恶意行为,同时也使用社区封锁列表。这些之所以有效,就是因为真实客户端 IP 全程都是已知的。 然后,caddy 终止 TLS 并将请求转发给各个服务。 我是在这个项目中发现 caddy 的,我觉得它是一款非常出色的软件。文档非常好,总是包含我需要的功能,配置也很容易理解。 ## 5\.3\. 通过 VPN 的私有访问§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Private_access_through_the_VPN) 有两个独立的 caddy 实例:一个用于公共网站,另一个只用于通过我的 VPN 才能访问的站点。这样,即使公共 caddy 被攻破,VPN 上的服务也不会受到影响。 VPN 的 caddy 只监听主机的 Tailscale 地址,并且还会检查客户端 IP 是否在 VPN 网段内。管理工具(Alertmanager、Uptime Kuma、Kanboard……)完全没有公网端点。 有些工具暴露在互联网上,但它们的管理界面或管理 API 只能通过 VPN 访问。即使管理 API 存在漏洞,也无法被利用。例如,Nextcloud 既可以在公网访问,也可以通过 VPN 访问,但它的管理 API 只能通过 VPN 访问。 Immich——我用来存储照片和视频的工具(今年我写过关于它的文章)——走得更远。在公网上,它只响应分享链接,这样我就可以与外部的人分享内容。其他一切功能,比如浏览媒体库或上传照片和视频,都通过 VPN 进行。这是一项安全措施,完整应用不会暴露在互联网上。 对于 VPN 站点,我希望使用真正的 TLS 证书而不是"自签名"的。我运行了自己的证书颁发机构(CA),通过 ACME(Let's Encrypt 使用的同一协议)颁发证书。它的根证书安装在所有实例和设备(手机、电脑、平板)上,因此每个知道该根 CA 的组件都能识别这些证书。再也不用 `curl \-k` 了! ## 6\. 密钥管理§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Secrets_management) 没有任何明文密钥被提交到仓库中。密钥使用 sops 和 age 加密,并存储在 git 中的服务文件旁边。 sops GitHub 页面 (https://github.com/getsops/sops) 每个实例都有自己独立的 age 私钥,生成一次后存储在 `secrets` 卷中,永远不会离开服务器。某个服务的密钥只会使用该实例的密钥和我的工作站密钥进行加密。这意味着只有需要知道某个密钥的人或机器才能读取它:一个被攻破的 Nextcloud 无法读取 Vaultwarden 的密钥,即使它拥有仓库的完整副本。 在启动时,密钥在一次性根磁盘上解密,因此每次重建都会重新生成。还有一个运行 gitleaks 的 git pre\-commit 钩子,以防万一,如果在历史记录中发现密钥,会阻止提交。 ## 7\. 自动更新§ (https://dataswamp.org/~solene/2026-10-15-selfhosting-infrastructure-incus-os.html#_Automatic_updates) 整个技术栈都能自我更新: - Incus OS 作为不可变镜像自我更新 - Ubuntu 实例使用 unattended\-upgrades,并且在实例创建时执行一次完整升级,以确保它从最新的软件包开始(我仍需要弄清楚如何升级整个基础镜像,而不是就地升级) - podman 容器通过 `podman auto\-update`(作为服务运行)进行更新,它会为配置的标签拉取新镜像,如果新容器启动失败则回滚 我选择的标签跟随主版本号(例如 `postgres:18\-alpine`),所以主版本升级是一次深思熟虑的单行更改。到目前为止,在容器更新后我从未遇到过任何问题。

相似文章

从 Proxmox 迁移到 NixOS 和 Incus

Hacker News Top

作者描述了将其家庭实验室从 Proxmox 迁移到使用 Incus 的 NixOS 的过程,强调了声明式配置和可重现性相对于命令式系统的优势。

我的自托管实践 | 理想中的自托管指南

Lobsters Hottest

作者分享了自己的自托管经验:为何从流媒体转向 Jellyfin,如何通过 VPN/CGNAT 限制服务暴露于公网,偏好原生运行与 Podman/systemd 而非 Docker,并介绍了所用的 Beelink Mini PC 硬件配置。

@CycleDecoded: Olares(来自 beclab 团队),一个专为“全天候 7x24 小时在线 AI Agent”设计的开源个人云操作系统。基于 Kubernetes 底层,把你家里淘汰的旧电脑、N1 盒子或者 NAS 闲置算力,直接改造成属于你自己的“…

X AI KOLs Timeline

Olares 是一个来自 beclab 团队的开源个人云操作系统,基于 Kubernetes,专为全天候 7x24 小时在线的 AI Agent 设计,可将旧电脑或 NAS 改装成自托管 AI 平台,支持本地数据存储和自然语言操作。

@vincemask: https://x.com/vincemask/status/2064581609928699973

X AI KOLs Timeline

本文介绍了Claude Code的五层安全护栏配置,包括OS沙箱、原生权限规则、PreToolUse Hook、工程规则和远程门禁,并提供了deny/ask/allow配置与命令分级清单,以确保Agent在安全边界内自主执行。