HanyanOS 部署手记
1. The Problem
HanyanOS runs on a dual-node topology. The Singapore Lightsail VPS (52.220.247.252) serves as the public edge, while the Brisbane N100 home server (192.168.1.18) hosts all real services — but it lives behind a carrier-grade NAT with no public IP and no possibility of port forwarding. The N100 is completely invisible to the internet.
The naive approach — SSH reverse tunnels — works for a handful of ports but becomes brittle and unscalable beyond two or three services. With seven subdomains, a mail system, and a growing agent ecosystem, we needed a dedicated, encrypted, production-grade tunnel. Enter FRP (Fast Reverse Proxy).
2. Architecture Overview
1 | ┌─────────────────────────────────┐ ┌─────────────────────────────────┐ |
Data Flow (Example: HTTPS Blog Request)
1 | Client → blog.chenyun.org → DNS A → VPS:443 |
Every request traverses two reverse proxy layers (VPS Nginx + N100 Nginx) and one encrypted FRP tunnel — yet latency remains sub-50ms for most requests.
3. Configuration
FRPS (VPS Server)
1 | # /etc/frp/frps.ini |
Minimal configuration. The server listens on port 7443 for control connections and uses a shared token for authentication. tcp_mux = true multiplexes multiple service streams over a single TCP connection, reducing overhead.
FRPC (N100 Client)
1 | # /etc/frp/frpc.ini |
The client initiates outbound connections from the NAT’d N100 to the VPS, establishing persistent tunnels. login_fail_exit = false ensures the client retries on connection loss rather than crashing.
Systemd Services
Both sides run as systemd services with auto-restart:
1 | # /etc/systemd/system/frpc.service |
4. Complete Port Mapping Table
| VPS FRP Port | Direction | N100 Port | Service |
|---|---|---|---|
| 7443 | ← | — | Control channel (bidirectional) |
| 7444 | → | :80 | Web services (HTTP, all subdomains) |
| 7446 | → | :25 | SMTP inbound |
| 7447 | → | :465 | SMTP Submission (TLS) |
| 7448 | → | :993 | IMAPS |
| 7449 | → | :8091 | SnappyMail webmail |
| 7450 | → | :5678 | n8n webhook receiver |
Note port 7445 is reserved for the AI API direct access. The gap between 7444 and 7446 is intentional — port 7445 was originally for the API tunnel but later consolidated through the web proxy layer.
5. Security Considerations
FRP alone is not enough. The tunnel is protected at multiple layers:
Token Authentication: The shared token (
chenyun-frp-2026) prevents unauthorized clients from joining the tunnel. In production, this should be rotated periodically.UFW Firewall (VPS): Only ports 22, 80, 443, 25, 465, 587, 993, 8443, and 7443 are open. The FRP data ports (7444–7450) are bound to
127.0.0.1on the VPS side — they are not exposed to the public internet. Only Nginx on the VPS can reach them.N100 Isolation: The home server initiates all outbound connections. No inbound ports are open on the N100’s router. Even if an attacker compromises the VPS, they cannot directly reach the N100 without also compromising the FRP token.
Fail2ban: Rate-limiting on SSHD and Nginx auth endpoints provides a second layer against brute-force attacks on any exposed management interfaces.
1 | Internet → [UFW] → VPS:443/25/465/993 only |
6. Problems Encountered & Solutions
Problem 1: Port Mapping Drift
Early on, FRP ports were changed multiple times as services were added and removed. The Nginx stream and proxy configurations were not always updated in sync, causing mysterious routing failures.
Solution: A version-controlled port mapping table was created in HanyanOS/memory/infrastructure/network/README.md. Any change to FRP configuration now requires a corresponding update to Nginx configs and a documented test of all affected subdomains.
Problem 2: Connection Drops Under Low Traffic
FRP’s default keepalive settings caused tunnel disconnections during idle periods (e.g., 3 AM when no one accesses the blog).
Solution: Added tcp_mux = true and systemd Restart=always with RestartSec=5. The client reconnects automatically within seconds of any disruption. With login_fail_exit = false, transient network issues on the N100’s ISP connection are handled gracefully.
Problem 3: Initial Port Binding Conflict
Port 7444 was initially used for both the AI API and WordPress before the routing was separated. Both services tried to bind to the same FRP remote port.
Solution: Separated services onto dedicated ports. The web traffic consolidation (all HTTP services through a single Nginx instance on N100:80) reduced the port count from 7+ to 3 main data ports plus the control channel.
Problem 4: Debugging Tunnel Connectivity
When a service goes down, it’s not immediately obvious whether the issue is at the FRP tunnel level or the service level.
Solution: Added ICMP monitoring via the HanyanOS patrol cron job, which checks FRPC process status and connection state every 15 minutes. Logs are written to structured error files for analysis.
7. Comparison: FRP vs SSH Reverse Tunnel
| Aspect | FRP | SSH Reverse Tunnel |
|---|---|---|
| Connection persistence | Excellent (auto-reconnect) | Good (autossh needed) |
| Multi-port support | Native (any number of proxies) | Manual (-R per port) |
| Encryption | TCP-level (optional TLS) | SSH channel encryption |
| Resource usage | ~15MB per binary | SSH daemon overhead |
| Configuration | Declarative INI file | CLI flags |
| TCP Multiplexing | Built-in (tcp_mux) |
Not natively supported |
FRP was chosen over SSH tunnels for its superior multi-port management and declarative configuration. Two SSH reverse tunnels are retained as a backup control plane (:2222 → :22 for SSH access, :8090 → :8090 for API emergency access), but all production traffic flows through FRP.
8. Conclusion
FRP provides the backbone of HanyanOS’s dual-node architecture, securely bridging the public VPS edge with the private N100 compute cluster. The setup handles six production services plus a control channel on a single outbound connection, with automatic reconnection, TCP multiplexing, and a security posture that keeps the home server completely invisible to the internet.
For any homelab running behind NAT with multiple services to expose, FRP is a battle-tested, lightweight, and reliable choice — especially when paired with a hardened edge VPS.
Next in series: Stalwart Mail System — Building a Self-Hosted Email Server on N100