- README 默认英文:README.en.md → README.md(英文为默认),中文移至 README.zh-CN.md,语言切换链接同步 - 恢复被删除的 docs/en/ 英文文档(git 历史 cc5e53c5^),删除 4 篇已废弃文件 - 英文导航 config.ts 对齐中文结构(新增 Deployment/Changelog 侧栏,同步 Guide/Design 条目) - 翻译 15 篇中文新增文档:guide 5 篇(certificates/pages-usage/proxy-config/uptime-kuma/zone-domain-migration)+ design 10 篇(zone-design/cloudflare-pointing/waf-orchestration/origin-error-page/edge-cache-design/pages-design/logstore/kuma-design/login-captcha/observability 三篇) - en 首页更新(新增 Pages 特性、tagline 同步);changelog 英文入口指向中文版 - vitepress 构建验证:43 个英文页面全部渲染 注意:29 篇旧英文文档为恢复版,部分内容(如 deployment/server、reference/configuration)可能落后于中文,需后续逐篇同步
14 KiB
Agent Design Document
You will learn: Agent design principles, core functional modules, interaction links with the Server, and how configuration applications are secured and made reliable through immutable version models and the three-stage disaster recovery rollback mechanism.
Requirements Analysis
In distributed reverse proxy and edge security gateway scenarios, the Agent plays a central role in connecting the control plane (Server) and the data plane (OpenResty). Since the Agent runs on the user's actual node server, its design must adhere to the following core security and high-availability requirements:
- Active Pull (Pull Model) instead of Push: The Server does not hold the SSH keys of the nodes, nor does it actively initiate inbound connections to the nodes. All control directives and configuration updates are actively pulled by the Agent via heartbeats or long-lived connections (WebSockets). This eliminates inbound firewall security risks on the node side and prevents control channels from being hijacked.
- Minimal Intrusiveness: The Agent runs as an independent Go binary process. It only interacts with the local OpenResty process through file-based configuration rewriting and signal notifications, without interfering with other system services on the node.
- Robust Disaster Recovery & Self-Healing: Since network jitter, disk exhaustion, or erroneous configurations can easily lead to configuration sync failures, the Agent must possess zero-dependency local rollback and self-healing capabilities, strictly preventing a single configuration error from causing a complete node outage.
- Pure Data and State Landing: The Agent is only responsible for executing file generation and control intentions rendered by the Server. It does not carry complex control plane duties like business logic validation or multi-tenant authorization, ensuring the node side remains highly efficient and lightweight.
Core Capabilities
The Agent is composed of the following core sub-modules, cooperating to manage its complete lifecycle:
| Module Name | Directory | Responsibilities |
|---|---|---|
| Config Sync | sync/ |
Pulls full configuration packages, writes files, triggers reloads, and records and reports sync statuses. |
| Heartbeat | heartbeat/ |
Periodically reports node health and resource metrics to the Server and retrieves the latest active version summary. |
| WebSocket | wsclient/ |
Maintains a persistent connection with the Server, providing sub-second real-time configuration pushes and commands. |
| OpenResty Control | nginx/ |
Executes Nginx config validation (openresty -t), rewrites, graceful reloads (reload), and process auto-start. |
| Local State Store | state/ |
Persistently records local applied versions, error logs, and buffers unsent observability metrics. |
| Self-Updater | updater/ |
Listens to Server self-update commands, securely pulls new binary versions, and completes in-place upgrades. |
| Observability | observability/ |
Collects host CPU/memory/disk and Nginx performance metrics, processes access logs, and uploads them. |
| GeoIP Maintenance | geoipdata/ geoipupdate/ |
Maintains and updates the local GeoIP database periodically to support WAF country-level filtering. |
Interaction Flows with Server
The Agent communicates with the control plane through Token-based Auto-Registration and a Dual-channel Heartbeat/WebSocket system during its lifecycle.
1. Auto-Registration Flow
If the Agent starts with an empty access_token in its local agent.json, but has a discovery_token configured, it triggers the auto-registration flow:
- The Agent sends a registration request to
/api/agent/register, carrying a local hardware fingerprint, IP, and hostname. - After validating the
discovery_token, the Server generates a uniqueNodeIDand a dedicatedAccessToken(i.e.,agent_token) in the database and returns them. - The Agent writes the dedicated Token to its local configuration file, clears the one-time
discovery_token, and uses theAccessTokenfor all subsequent authenticated communications.
2. Dual-Channel Heartbeat & Sync Mechanism
- HTTP Polling (Fallback and Detection): The Agent sends POST heartbeat packets at configured
heartbeat_intervalintervals by default. It reports health metrics while retrieving the currently active configuration version summary (Version & Checksum). - WebSocket Channel (Real-time Communication): Upon a successful HTTP heartbeat, the Agent automatically attempts to upgrade the connection to WebSocket (
/api/agent/ws).- Once the WS connection is established, heartbeats and metrics reporting shift entirely to the WS pipeline, reducing network overhead.
- When the Server publishes or activates a new version, it broadcasts a notification to the Agent via WS. The Agent triggers the synchronization flow immediately upon receiving the change event, achieving sub-second configuration deployment.
- If the WS connection drops due to network issues, the Agent automatically falls back to HTTP polling and uses an exponential backoff algorithm to attempt rebuilding the WS channel.
3. Interaction Sequence Diagram
sequenceDiagram
autonumber
participant Agent as OpenFlare Agent
participant OR as Local OpenResty
participant Server as OpenFlare Server
Note over Agent: First Startup (No AccessToken)
Agent->>Server: 1. Auto-registration request (carrying discovery_token)
Server-->>Agent: 2. Issue NodeID & dedicated AccessToken (agent_token)
Note over Agent: Store Token in local configuration file
rect rgb(240, 248, 255)
Note over Agent, Server: HTTP Fallback & WebSocket Upgrade
Agent->>Server: 3. Send HTTP Heartbeat (report system metrics & health)
Server-->>Agent: 4. Return ActiveConfig summary & AgentSettings
Agent->>Server: 5. Initiate WebSocket upgrade request (/api/agent/ws)
Server-->>Agent: 6. Upgrade successful (persistent bi-directional channel)
end
rect rgb(245, 245, 245)
Note over Agent, Server: Real-time Configuration Publication
Note over Server: Administrator clicks publish config in UI
Server->>Agent: 7. Broadcast active config summary via WS (WSMessageTypeActiveConfig)
Agent->>Server: 8. Request full configuration details (carrying target Version/Checksum)
Server-->>Agent: 9. Return complete configuration snapshot (Nginx configs, certs, WAF rules, etc.)
Note over Agent: Backup old files, write new config to local temp path
Agent->>OR: 10. Execute config syntax validation (openresty -t)
OR-->>Agent: 11. Return validation result (OK)
Agent->>OR: 12. Send graceful reload signal (openresty -s reload)
Agent->>Server: 13. Report application success status (Apply Log & ActiveVersion)
end
Control of OpenResty
The Agent implements end-to-end closed-loop control of the data plane OpenResty, including configuration rendering, syntax validation, graceful reloading, and exception state capturing:
1. Configuration Layout on Disk
Upon successful sync, the Agent writes configuration files to /etc/nginx/openflare-lua/ (or the configured LuaDir) according to a strict physical structure:
nginx.conf: Main configuration file (replaces absolute path placeholders, configures performance parameters, shared dictionaries, and global server blocks).routes.conf: Route configuration file (generated by the Agent, containing all website server blocks, certificate paths, cache settings, and rate limit directives).certs/: Certificate storage directory (files named as{cert_id}.crtand{cert_id}.key).waf/andpow/: Dedicated Lua runtime scripts required for WAF and CC mitigation.waf_config.jsonandwaf_ip_groups.json: Structured rules and IP databases required by the WAF filtering engine.
2. Refined Reload Operations
- Backup Current Config: Before writing new files, the Agent copies the existing configuration files to a
.backupdirectory, keeping a complete rollback snapshot. - Write and Replace Placeholders: Writes the pulled templates, automatically replacing absolute path placeholders (e.g.,
__OPENFLARE_LUA_DIR__) with actual local execution paths. - Syntax Validation: Calls
openresty -t -c <temp_nginx.conf>to run a strict syntax test. - Graceful Reload: If validation passes, the Agent moves the files to the official paths and executes
openresty -s reload. If OpenResty is not running, it launches the process. - Exception Capture: If validation or reload fails, the Agent intercepts the standard error output (stderr) and extracts the first 2000 characters of the detailed error log.
Publishing & Config Application Model
OpenFlare discards the fragile mechanism of dynamically patching node configurations, instead using an immutable configuration version publishing model.
Edit rules -> Preview / View diff -> Publish -> Generate full configuration version -> Activate version -> Agent pulls -> Local application -> Report result
1. Core Design Principles
- Complete Publication: Every publication compiles all enabled proxy routes, certificates, and global/custom WAF rules at once, generating a complete version package with a unique
checksum. - Version Format: Uses the
YYYYMMDD-NNNincremental format, ensuring version histories are intuitive and strictly monotonic. - Global Single Active Version: The system supports only one globally
activeconfiguration version at any given time. Rollbacks do not require reverse patching; they simply transition an older healthy version to theactivestate, and the Agent pulls and applies it.
2. Three-Stage Disaster Recovery & Rollback Mechanism
If the Agent fails to apply a configuration (or reload fails), it automatically triggers the following three-stage self-healing pipeline:
graph TD
A[Config Application Failed] --> B[Stage 1: Attempt Local Backup Recovery]
B -- Backup Exists --> C[Write Local Backup Files]
C --> D[Run openresty -t Validation]
D -- Validation OK --> E[Reload Old Configuration]
D -- Validation Failed --> F[Proceed to Stage 2]
B -- No Backup --> F[Stage 2: Write Built-in Safe Fallback Config]
F --> G[Write fallback nginx.conf: Listen on Port 80 Only]
G --> H[Enable stub_status health checks]
G --> I[Return 503 for all other routes & block errors]
G --> J[Attempt to launch OpenResty to maintain basic survival]
J --> K[Proceed to Stage 3]
E --> L[Report Apply Warning]
K --> M[Block Local Repeated Application of Failed Version]
M --> N[Report Apply Error with detailed logs]
- Stage 1: Local Backup Rollback
- The Agent attempts to restore the main configuration, routes, and certificates from the
.backupdirectory. - It runs
openresty -tvalidation on the restored backup. If successful, it reloads and reports aWarningto the Server (Warning: failed to apply new version, automatically rolled back to the previous healthy version).
- The Agent attempts to restore the main configuration, routes, and certificates from the
- Stage 2: Built-in Safe Fallback Runtime
- If no local backup exists (e.g., first deployment failed) or if the rollback validation fails, the Agent activates the ultimate self-healing mechanism: writing a built-in safe fallback configuration.
- Fallback Configuration Specification:
- Listens only on port
80, containing no real user reverse proxy routes. - The
/openflare/stub_statusendpoint returns a healthy response, while all other requests uniformly return a503 Service Unavailablestatus code with the fixed response bodyOpenFlare: No Valid Configuration. - It attempts to launch OpenResty with this minimal configuration. This keeps the Nginx process alive, preserving underlying health probes and metric endpoints, preventing containers/pods from being repeatedly killed and restarted by orchestration systems, while keeping sensitive routes secure.
- Listens only on port
- Stage 3: Local Configuration Blocking
- The Agent records the failing configuration's
version + checksumin its local state store blacklist. - Until the control plane activates a new configuration (resulting in a changed
checksum), the Agent's heartbeat blocks repeated synchronization pulls of this erroneous version, preventing nodes from entering an infinite loop of "heartbeat -> pull failing config -> crash rollback".
- The Agent records the failing configuration's
3. WAF IP Group Asynchronous Runtime Synchronization
To prevent highly volatile IP blacklists from triggering frequent full config publications and Nginx reloads (which still incur minor CPU and connection overhead), WAF IP groups are synchronized via an asynchronous differential sync design:
- Static Publication Snapshot: The
waf_config.jsongenerated upon publication only contains the group ID reference mapping (i.e.,ip_whitelist_group_ids/ip_blacklist_group_ids) and does not contain the actual list of IP addresses. - Heartbeat Differential Check: The Agent uploads its locally cached IP groups MD5 checksum map in its heartbeat.
- Differential Delivery: The Server compares checksums and only delivers missing or modified IP groups, which are written directly to
waf_ip_groups.jsonon the node without reload. - WebSocket Real-time Push: When an administrator updates an IP group, or a threat intelligence subscription successfully pulls, or a security rule triggers a temporary block, the Server immediately broadcasts the IP group update package via WebSocket. The Agent receives and applies it instantly without Nginx reloads.
Design Constraints
To protect the security boundary of the data and control plane, Agent development must strictly comply with the following engineering constraints:
- Zero-Privilege Command Execution: The Server is strictly prohibited from sending any arbitrary shell commands or scripts to the Agent (such as exec/eval). All system control operations (such as start, stop, reload, update) must be hardcoded inside the Agent binary.
- Strict Token Filtering and Prefix Validation: Agent requests to the Server must be prefixed with
/api/agent/and must carry theX-Agent-Tokenheader for signature or token verification. - Node Autonomy: The Agent must support complete offline capabilities. During disconnected periods, the local OpenResty must rely on local configuration copies to keep reverse proxy services running normally.