# Mozilla Autopush-rs 部署与配置全攻略


Autopush-rs 是 Mozilla 推送服务的 Rust 实现，采用典型的“生产者-消费者”架构，利用 Rust、Actix 以及键值数据存储。本文基于 `autopush-rs` 项目配置与 `Sunup` 客户端集成实践整理，涵盖核心原理、架构图示、详尽配置及部署指南。

<!--more-->

---

## 1. 架构原理与组件分工

Autopush-rs 采用双端解耦设计，通过 Redis 共享状态，实现从“公网推送请求”到“私有长连接下发”的回路。

### 1.1 服务组件分工

1.  **Autoconnect (WebSocket Server)**:
    *   **角色**: 面向客户端（如 Sunup Android 客户端）。
    *   **功能**: 建立并维护长连接，接收心跳，并将推送消息分发到设备。
    *   **默认端口**: `8080` (WebSocket), `8081` (内部路由端口)。

2.  **Autoendpoint (HTTP API)**:
    *   **角色**: 面向应用服务器（如 Mastodon/Matrix 等发送通知的服务）。
    *   **功能**: 接收标准 WebPush 请求，查询路由信息，并通知 `autoconnect` 进行推送。
    *   **默认端口**: `8000`。

3.  **Storage (Redis/Valkey)**:
    *   **功能**: 存储注册信息（Routers）和待发消息，并用于可靠性跟踪。

### 1.2 交互流程图 (Mermaid)

```mermaid
sequenceDiagram
    participant App as 应用服务器 (Sender)
    participant Endpoint as Autoendpoint (8000)
    participant Redis as Redis 数据库
    participant Conn as Autoconnect (8080/8081)
    participant Client as Sunup 客户端 (手机)

    Note over Client, Conn: 1. 建立长连接
    Client->>Conn: 建立 WebSocket (8080)
    Conn->>Redis: 注册 node_id (例如 http://autoconnect:8081)
    Conn-->>Client: 返回 pushEndpoint (指向 Autoendpoint)

    Note over App, Client: 2. 触发推送
    App->>Endpoint: 发送 POST WebPush 请求 (8000)
    Endpoint->>Redis: 查询用户的 node_id
    Redis-->>Endpoint: 返回 http://autoconnect:8081

    Note over Endpoint, Conn: 3. 内部下发
    Endpoint->>Conn: 内部通知 (8081 HTTP)
    Conn->>Client: 通过已有的 WS 连接下发消息
```

---

## 2. 详尽配置选项

配置选项既可以在配置文件中指定，也可以通过环境变量的形式指定。

### 2.1 Autoconnect 配置

| **选项** | **环境变量** | **类型** | **默认值** | **描述** |
|---|---|---|---|---|
| actix_max_connections | AUTOCONNECT__ACTIX_MAX_CONNECTIONS | 数字 | _无_ | Actix Web 服务器的最大并发连接数 |
| actix_workers | AUTOCONNECT__ACTIX_WORKERS | 数字 | _无_ | Actix Web 服务器每个绑定地址的工作线程数 |
| auto_ping_interval | AUTOCONNECT__AUTO_PING_INTERVAL | 数字 | 300 | 向客户端发送 ping 的时间间隔（秒） |
| auto_ping_timeout | AUTOCONNECT__AUTO_PING_TIMEOUT | 数字 | 4 | 等待客户端 ping 响应的时间（秒） |
| crypto_key | AUTOCONNECT__CRYPTO_KEY | 字符串 | _内部生成_ | 用于端点加密的加密密钥 (32 字节 Base64) |
| db_dsn | AUTOCONNECT__DB_DSN | 字符串 | _无_ | 后端数据库的数据源名称 |
| endpoint_hostname | AUTOCONNECT__ENDPOINT_HOSTNAME | 字符串 | "localhost" | 生成端点 URL 的公网主机名 |
| endpoint_port | AUTOCONNECT__ENDPOINT_PORT | 数字 | 8082 | 生成端点 URL 的公网端口覆盖值 |
| endpoint_scheme | AUTOCONNECT__ENDPOINT_SCHEME | 字符串 | "http" | 生成端点 URL 的方案 (http/https) |
| hostname | AUTOCONNECT__HOSTNAME | 字符串 | _无_ | 机器主机名，用于内部路由注册 |
| human_logs | AUTOCONNECT__HUMAN_LOGS | 布尔值 | false | 是否使用人类可读的日志格式 |
| msg_limit | AUTOCONNECT__MSG_LIMIT | 数字 | 1000 | 每个客户端存储的最大消息数 |
| port | AUTOCONNECT__PORT | 数字 | 8080 | 应用程序监听的 WS 端口 |
| router_port | AUTOCONNECT__ROUTER_PORT | 数字 | 8081 | 节点间通信的内部路由端口 |

### 2.2 Autoendpoint 配置

> **注意**：部分旧版文档中提到的 `AUTOENDPOINT__` 前缀在当前版本中应修改为 `AUTOEND__`。

| **选项** | **环境变量** | **类型** | **默认值** | **描述** |
|---|---|---|---|---|
| scheme | AUTOEND__SCHEME | 字符串 | "http" | 端点 URL 方案 |
| host | AUTOEND__HOST | 字符串 | "127.0.0.1" | 监听主机 |
| port | AUTOEND__PORT | 数字 | 8000 | 监听端口 |
| db_dsn | AUTOEND__DB_DSN | 字符串 | _无_ | 后端数据库数据源名称 |
| crypto_keys | AUTOEND__CRYPTO_KEYS | 字符串 | _内部生成_ | 加密密钥列表 (逗号分隔) |
| auth_keys | AUTOEND__AUTH_KEYS | 字符串 | _无_ | 身份验证密钥列表 (逗号分隔) |
| human_logs | AUTOEND__HUMAN_LOGS | 布尔值 | false | 是否使用人类可读日志 |
| max_notification_ttl | AUTOEND__MAX_NOTIFICATION_TTL | 数字 | 2592000 | 通知消息最大生存时间 (秒) |

---

## 3. 关键配置文件 (TOML 示例)

密钥可通过 `openssl rand -base64 32` 命令行生成。

### 3.1 `autoconnect.toml`
```toml
# --- 内部识别 (至关重要) ---
# 此 hostname 会存入 Redis。Autoendpoint 必须能通过此名称访问到本容器。
hostname = "autoconnect" 
port = 8080              
router_port = 8081       

# --- 推送地址生成 (给手机客户端看) ---
endpoint_scheme = "https"
endpoint_hostname = "push-api.example.com"
endpoint_port = 443      

# --- 存储与安全 ---
db_dsn = "redis://valkey:6379"
crypto_key = "[mqCGb8D-N7mqx6iWJov9wm70Us6kA9veeXdb8QUuzLQ=]"
```

### 3.2 `autoendpoint.toml`
```toml
host = "0.0.0.0"         
port = 8000              

db_dsn = "redis://valkey:6379"
# 必须与 autoconnect 的 crypto_key 保持一致
crypto_keys = "[mqCGb8D-N7mqx6iWJov9wm70Us6kA9veeXdb8QUuzLQ=]"

scheme = "http"
human_logs = true
```

---

## 4. 部署指南

### 4.1 Docker Compose 部署

```yaml
---
# https://github.com/orgs/forkdo/packages?repo_name=autopush-rs
services:
  autoendpoint:
    container_name: autoendpoint
    env_file:
      - path: ./.env
        required: false
    hostname: autoendpoint
    image: ghcr.io/forkdo/autoendpoint:latest
    ports:
      - 8000:8000
    restart: unless-stopped

  autoconnect:
    container_name: autoconnect
    env_file:
      - path: ./.env
        required: false
    hostname: autoconnect
    image: ghcr.io/forkdo/autoconnect:latest
    ports:
      - 8080:8080
    restart: unless-stopped
```

### 4.2 环境变量 (.env)

```dotenv
# CUSTOM
TZ=Asia/Shanghai

################################# autoendpoint 对应项 ###############
AUTOEND__HOST="autoendpoint"
AUTOEND__PORT=8000
AUTOEND__DB_DSN="redis://valkey:6379"

# 密钥需为随机 32 字节 Base64
# openssl rand -base64 32
AUTOEND__CRYPTO_KEYS="[CRYPTO_KEY]"
AUTOEND__AUTH_KEYS="[AUTH_KEY]"
AUTOEND__HUMAN_LOGS=true

########################## autoconnect 对应项 ############################
AUTOCONNECT__HOSTNAME="autoconnect"
AUTOCONNECT__PORT=8080
AUTOCONNECT__ROUTER_PORT=8081

# 外部应用可访问的配置
AUTOCONNECT__ENDPOINT_SCHEME="https"
AUTOCONNECT__ENDPOINT_HOSTNAME="push-api.example.com"
AUTOCONNECT__ENDPOINT_PORT=443

AUTOCONNECT__DB_DSN="redis://valkey:6379"
AUTOCONNECT__CRYPTO_KEY="[CRYPTO_KEY]"
AUTOCONNECT__HUMAN_LOGS=true

################################ Valkey ###################################
VALKEY_ARGS=--save 60 1000
```

### 4.3 Nginx 反向代理配置

```nginx
    location / {
        proxy_pass http://127.0.0.1:8000; # 指向 Autoendpoint (API) 或 Autoconnect (WS)
        proxy_http_version 1.1;

        proxy_set_header Host $http_host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;

        proxy_connect_timeout 3m;
        proxy_send_timeout 3m;
        proxy_read_timeout 3m;

        client_max_body_size 0; # Stream request body to backend
    }
```

---

## 5. 部署核心 Checklist

1.  **域名绑定分工**:
    *   **WebSocket 域名** (`push.domain.com`): 建议指向 `autoconnect` 的 `8080` 端口。
    *   **Push API 域名** (`push-api.domain.com`): 建议指向 `autoendpoint` 的 `8000` 端口。
2.  **Hostname 陷阱**:
    *   `autoconnect.toml` 里的 `hostname` **绝对不能**写 `127.0.0.1`。在 Docker 环境下应填写 `autoconnect` 容器服务名，否则 `autoendpoint` 无法通过网络回调。
3.  **密钥同步**:
    *   `crypto_key` (connect) 和 `crypto_keys` (endpoint) 必须完全相同，用于令牌的加密与验证。
4.  **生效触发**:
    *   修改配置并重启服务后，**客户端必须重新打开并建立一次连接**，以覆盖 Redis 中旧的路由信息。

---
相关链接：
* [Autopush-rs](https://github.com/mozilla-services/autopush-rs)
* [官方配置文档](https://mozilla-services.github.io/autopush-rs/)

