# 架构

本页面介绍 Rediacc 的内部工作原理：双工具架构、适配器检测、安全模型和配置结构。

## Full Stack Overview

Traffic flows from the internet through a reverse proxy, into isolated Docker daemons, each backed by encrypted storage:

![Full Stack Architecture](/img/arch-full-stack.svg)

Each repository gets its own Docker daemon, loopback IP subnet (/26 = 64 IPs), and LUKS-encrypted BTRFS volume. The route server discovers running containers across all daemons and feeds routing configuration to Traefik.

## 双工具架构

Rediacc 采用两个通过 SSH 协同工作的二进制文件：

![双工具架构](/img/arch-two-tool.svg)

- **rdc** 运行在您的工作站上（macOS、Linux 或 Windows）。它读取您的本地配置，通过 SSH 连接到远程机器，并调用 renet 命令。
- **renet** 以 root 权限运行在远程服务器上。它管理 LUKS 加密磁盘映像、隔离的 Docker 守护进程、服务编排和反向代理配置。

您在本地输入的每条命令都会转化为一个 SSH 调用，在远程机器上执行 renet。您无需手动 SSH 登录服务器。

如需以运维为中心的使用规则，请参阅 [rdc vs renet](/zh/docs/rdc-vs-renet)。您也可以使用 `rdc ops` 运行本地虚拟机集群进行测试, 请参阅[实验性虚拟机](/zh/docs/experimental-vms)。

## 配置

所有 CLI 状态存储在 `~/.config/rediacc/` 下的扁平 JSON 配置文件中。

### 本地适配器（默认）

自托管使用的默认选项。所有状态存储在工作站的配置文件中（例如 `~/.config/rediacc/rediacc.json`）。

- 直接通过 SSH 连接到机器
- 无需外部服务
- 单用户、单工作站
- 首次使用 CLI 时自动创建默认配置。命名配置通过 `rdc config init <name>` 创建

### 云适配器（实验性）

当配置中包含 `apiUrl` 和 `token` 字段时自动激活。使用 Rediacc API 进行状态管理和团队协作。

- 状态存储在云 API 中
- 支持基于角色的多用户团队访问
- Web 控制台提供可视化管理
- 使用 `rdc auth login` 设置

> **注意：**云适配器命令为实验性功能。设置 `REDIACC_EXPERIMENTAL=1` 来启用。

两种适配器使用相同的 CLI 命令。适配器仅影响状态的存储位置和认证方式。

## rediacc 用户

运行 `rdc config machine setup` 时，renet 会在远程服务器上创建一个名为 `rediacc` 的系统用户：

- **UID**：7111
- **Shell**：`/sbin/nologin`（无法通过 SSH 登录）
- **用途**：拥有仓库文件并运行 Rediaccfile 函数

`rediacc` 用户无法直接通过 SSH 访问。rdc 以您配置的 SSH 用户（例如 `deploy`）连接，renet 通过 `sudo -u rediacc /bin/sh -c '...'` 执行仓库操作。这意味着：

1. 您的 SSH 用户需要 `sudo` 权限
2. 所有仓库数据归 `rediacc` 用户所有，而非您的 SSH 用户
3. Rediaccfile 函数（`up()`、`down()`）以 `rediacc` 用户身份运行

这种分离确保仓库数据具有一致的所有权，不受管理它的 SSH 用户影响。

## Docker 隔离

每个仓库拥有自己的隔离 Docker 守护进程。当仓库被挂载时，renet 会启动一个专用的 `dockerd` 进程，使用唯一的套接字：

![Docker 隔离](/img/arch-docker-isolation.svg)

```
/var/run/rediacc/docker-{networkId}.sock
```

例如，网络 ID 为 `2816` 的仓库使用：
```
/var/run/rediacc/docker-2816.sock
```

这意味着：
- 不同仓库的容器彼此不可见
- 每个仓库拥有独立的镜像缓存、网络和卷
- 主机的 Docker 守护进程（如果有的话）完全独立

Rediaccfile 函数会自动设置 `DOCKER_HOST` 为正确的套接字。

## LUKS 加密

仓库是存储在服务器数据存储中（默认：`/mnt/rediacc`）的 LUKS 加密磁盘映像。每个仓库：

1. 拥有一个随机生成的加密密码短语（"凭据"）
2. 以文件形式存储：`{datastore}/repos/{guid}.img`
3. 访问时通过 `cryptsetup` 挂载

凭据存储在本地配置文件中，但**绝不**存储在服务器上。没有凭据，仓库数据将无法读取。启用开机自启时，会在服务器上存储一个辅助 LUKS 密钥文件，以便启动时自动挂载。

## 配置结构

每个配置是存储在 `~/.config/rediacc/` 中的扁平 JSON 文件。默认配置为 `rediacc.json`；命名配置使用名称作为文件名（例如 `production.json`）。以下是一个注释示例：

```json
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "version": 1,
  "ssh": {
    "privateKeyPath": "/home/you/.ssh/id_ed25519"
  },
  "machines": {
    "prod-1": {
      "ip": "203.0.113.50",
      "user": "deploy",
      "port": 22,
      "datastore": "/mnt/rediacc",
      "knownHosts": "203.0.113.50 ssh-ed25519 AAAA..."
    }
  },
  "storages": {
    "backblaze": {
      "provider": "b2",
      "vaultContent": { "...": "..." }
    }
  },
  "repositories": {
    "webapp": {
      "repositoryGuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "credential": "base64-encoded-random-passphrase",
      "networkId": 2816
    }
  },
  "nextNetworkId": 2880,
  "universalUser": "rediacc"
}
```

**关键字段：**

| 字段 | 描述 |
|-------|-------------|
| `id` | 此配置文件的唯一标识符 |
| `version` | 配置文件模式版本 |
| `ssh.privateKeyPath` | 用于所有机器连接的 SSH 私钥路径 |
| `machines.<name>.user` | 连接到机器的 SSH 用户名 |
| `machines.<name>.knownHosts` | 来自 `ssh-keyscan` 的 SSH 主机密钥 |
| `repositories.<name>.repositoryGuid` | 标识加密磁盘映像的 UUID |
| `repositories.<name>.credential` | LUKS 加密密码短语（**不存储在服务器上**） |
| `repositories.<name>.networkId` | 确定 IP 子网（2816 + n*64），自动分配 |
| `nextNetworkId` | 用于分配网络 ID 的全局计数器 |
| `universalUser` | 覆盖默认系统用户（`rediacc`） |

> 此文件包含敏感数据（SSH 密钥路径、LUKS 凭据）。它以 `0600` 权限存储（仅所有者可读写）。请勿共享或提交到版本控制系统。