一、背景与目标

1. 项目背景

A. 业务场景

作者维护个人基础设施已超过十年,自托管服务包括邮件服务器、博客、IRC 服务器、图片托管、RSS 阅读器等。原有部署方式混乱,有的使用容器,有的直接使用 nginx 托管静态文件,有的则是从 Debian 包管理器安装的二进制文件,缺乏统一管理。

B. 痛点分析

  • 部署方式不一致,难以维护
  • 服务分散在各个位置,缺乏统一管理
  • 家庭网络 ISP 使用 NAT,难以直接暴露服务到公网

2. 设计目标

A. 功能目标

  • 在本地家庭网络托管个人基础设施和服务
  • 支持内部服务和面向互联网的服务
  • 统一容器化部署方案

B. 非功能目标

  • 易于部署和配置
  • 尽可能自托管,愿意牺牲部分便利性
  • 可靠性强,无需频繁维护

二、硬件资源

1. 设备清单

  • NAS 服务器:2×8 TB 磁盘,2012 年硬件
  • Intel NUC(byggmester):Intel i5-6260U,16 GB RAM,2015 年
  • AMD NUC(amd):AMD Ryzen 7 8745HS,64 GB RAM,购自 AliExpress
  • 路由器:OpenWRT One

2. 网络架构

家庭网络采用扁平化设计,所有设备在同一网段。

graph LR
    Internet[互联网] -->|WireGuard 隧道| VPS[VPS 服务器]
    VPS --> byggmester[Intel NUC<br/>byggmester]
    byggmester --> amd[AMD NUC<br/>amd]
    byggmester --> NAS[NAS 服务器]
    amd --> Router[OpenWRT One]
    Router --> Clients[客户端设备]

个人基础设施网络架构

三、容器化平台:Incus

1. Incus 简介

Incus(原 LXD)是一个容器管理器,支持 LXC 容器、QEMU 虚拟机和 OCI 容器。作者已使用多年,具有高度可靠性,版本间更新不会突然破坏功能。

2. 集群配置

Incus 集群包含两个节点:

3. 网络配置

两个节点都创建了名为 br0 的网桥设备,所有容器使用桥接网络获取本地 IP,路由器提供域名解析。

systemd-networkd 配置示例:

# /etc/systemd/network/20-wired.network
[Match]
Name=en*

[Network]
Bridge=br0

# /etc/systemd/network/50-br0.netdev
[NetDev]
Name=br0
Kind=bridge

# /etc/systemd/network/50-br0.network
[Match]
Name=br0

[Network]
Address=192.168.1.2/24
Gateway=192.168.1.1
DNS=192.168.1.1

Incus 默认配置:

# incus profile show default
description: Default Incus profile
devices:
  eth0:
    nictype: bridged
    parent: br0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: default

4. OCI 容器支持

Incus 支持从容器镜像仓库直接拉取 OCI 容器。例如启动 Valkey 容器:

incus remote add docker https://docker.io/ --protocol=oci --public
incus launch docker:valkey/valkey valkey

容器启动后可直接通过本地域名访问:

ping valkey.local
# PING valkey.local (192.168.1.148) 56(84) bytes of data.

四、基础设施即代码:OpenTofu

1. OpenTofu 简介

OpenTofu(Terraform 的开源替代品)通过声明式配置管理 Incus 资源,将所有持久化数据存储在 NAS 上,实现基础设施的可重现部署。

2. 项目管理

所有服务按项目分类,每个项目共享通用模板,包括权限、网络和默认配置。OpenTofu 模块结构:

  • project 模块:所有其他模块的基础模板
  • 各服务模块:从 project 模块派生

3. 项目列表

当前运行的项目:

项目名称描述容器数量
caCA 项目4
default默认项目48
dnsDNS 项目7
immichImmich 项目14
mediaserver媒体服务器项目18
minifluxMiniflux 项目6
syncthingSyncthing 项目3
test测试项目2
user-1000用户受限项目2

4. Immich 部署示例

Immich 项目包含 7 个容器:

  • auto-album-jpg
  • auto-album-raw
  • database
  • immich
  • immich-machine-learning
  • redis

OpenTofu 配置示例:

resource "incus_image" "redis" {
  project = incus_project.immich.name
  alias {
    name = "redis"
  }
  source_image = {
    remote = "docker"
    name   = "valkey/valkey:8-bookworm"
  }
}

resource "incus_instance" "immich_redis" {
  name    = "redis"
  image   = incus_image.redis.fingerprint
  project = incus_project.immich.name
  target  = "amd"

  config = {
    "boot.autorestart" = true
  }
}

五、网络暴露方案

1. WireGuard 反向隧道

由于家庭 ISP 使用 NAT,无法直接暴露服务到公网。解决方案是在具有静态 IPv4 和 IPv6 的 VPS 上建立 WireGuard 点对点 VPN 隧道。

sequenceDiagram
    participant Internet as 互联网用户
    participant VPS as VPS 服务器<br/>静态 IP
    participant WG as WireGuard 隧道
    participant byggmester as Intel NUC<br/>byggmester
    participant Incus as Incus 容器

    Internet->>VPS: HTTPS 请求
    VPS->>WG: 转发流量
    WG->>byggmester: 隧道传输
    byggmester->>Incus: 反向代理
    Incus->>byggmester: 返回内容
    byggmester->>WG: 隧道传输
    WG->>VPS: 转发响应
    VPS->>Internet: HTTPS 响应

服务暴露流程

2. Nginx 反向代理

在 byggmester 节点上运行 nginx,将需要对外暴露的服务反向代理到内部 Incus 容器。使用内部 DNS 服务器解析域名,避免在 nginx 配置中硬编码 IP。

nginx-acme 插件自动处理 TLS 证书,无需手动运行 certbot。

nginx 配置示例:

# /etc/nginx/nginx.d/10-acme.conf
acme_issuer letsencrypt {
    uri         https://acme-v02.api.letsencrypt.org/directory;
    contact     root@linderud.dev;
    state_path  /var/lib/nginx/acme;
    accept_terms_of_service;
}

acme_shared_zone zone=ngx_acme_shared:1M;

server {
    listen 80;
    location / {
        return 404;
    }
}

# /etc/nginx/snippets/acme.conf
acme_certificate      letsencrypt;
ssl_certificate       $acme_certificate;
ssl_certificate_key   $acme_certificate_key;
ssl_certificate_cache max=2;

# /etc/nginx/nginx.d/30-bilder.linderud.dev.conf
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name bilder.linderud.dev;

    access_log /var/log/nginx/bilder.linderud.dev/access.log;
    error_log /var/log/nginx/bilder.linderud.dev/error.log;

    include snippets/acme.conf;
    include snippets/sslsettings.conf;

    client_max_body_size 50000M;

    resolver 192.168.1.1 ipv6=off;

    location / {
        set $immich immich.local;
        proxy_pass http://$immich:2283;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_http_version 1.1;
        proxy_set_header   Upgrade    $http_upgrade;
        proxy_set_header   Connection "upgrade";
        proxy_redirect off;
    }
}

六、静态网站部署

1. Syncthing 同步方案

对于静态网站(如博客),作者使用 Syncthing 将构建后的文件同步到 Web 服务器,避免了复杂的 CI/CD 流程。

2. 部署流程

graph LR
    Local[本地计算机] -->|Hugo 构建| Build[构建输出]
    Build -->|Syncthing| Sync[同步目录]
    Sync -->|/srv/linderud.dev/blog| Web[Web 服务器]

静态网站部署流程

服务器目录结构:

/srv/linderud.dev/
├── blog      # 博客
├── coredns01 # DNS 服务器配置
└── pub       # 公共共享文件

部署命令:

hugo build -d /srv/linderud.dev/blog/

优点:

  • 无服务依赖
  • 无需 CI/CD 设置
  • 无需 GitHub Actions
  • 无需 Ansible Playbooks

七、网络管理:OpenWRT One

1. 硬件设备

OpenWRT One 是面向 OpenWRT 开发者的路由器,购自 AliExpress。

2. 配置管理

作者编写了 OpenTofu provider 管理路由器配置,实现了基础设施即代码的网络管理。

3. 未来规划

计划添加支持 OpenWRT 的交换机,实现 VLAN 网络分段。

八、运维工具

1. USB KVM

在 38C3 活动中购买的 USB KVM 设备,通过 HDMI 和 USB-C 线缆连接到各个小计算机,简化了多设备管理。

九、技术总结

1. 核心技术栈

  • 容器平台:Incus(LXC 容器 + QEMU 虚拟机 + OCI 容器)
  • 基础设施即代码:OpenTofu
  • 网络暴露:WireGuard + nginx
  • 文件同步:Syncthing
  • 路由器:OpenWRT One

2. 架构优势

  • 统一容器化部署
  • 声明式配置管理
  • 简化的网络暴露方案
  • 无依赖的静态网站部署

3. 设计理念

  • 简单性优于复杂性
  • 自托管优于云服务
  • 可靠性优于功能丰富

参考资料

  1. Personal infrastructure setup 2026
  2. Locally hosting an internet-connected server
最后修改:2026 年 01 月 24 日
如果觉得我的文章对你有用,请随意赞赏