Building a High-Availability Home Proxy: From Ngrok to FRP + Nginx Failover
Building a High-Availability Home Proxy: A Deep Dive into FRP and Nginx Stream Failover
In the world of personal networking and home labs, exposing local services securely or creating a stable proxy for family use is a common challenge. What started as a simple requirement—“I need a proxy for my family that uses my clean home IP”—evolved into a lesson in High Availability (HA) system design.
Here’s how I migrated from unreliable free-tier solutions to a robust, self-hosted architecture using FRP (Fast Reverse Proxy) and Nginx Stream, achieving zero-downtime failover between my Mac (Primary) and VPS (Backup).
⚠️ Disclaimer & Use Cases
The techniques discussed in this article are intended strictly for legitimate Home Network Remote Access and Network Stability Optimization.
Primary use cases include:
- Service Continuity (The Need for HA): Ensuring that critical services relying on this network channel (like remote monitoring or smart home controls) remain accessible even when the primary home server (Mac) is undergoing maintenance, sleeping, or experiencing ISP outages.
- Home Lab Access: Securely connecting to home NAS, Home Assistant, or git servers from external networks.
- Development Environment: Providing a static residential IP for mobile work devices to access IP-whitelisted services or debug in specific network conditions.
- Privacy Protection: Encrypting traffic on public Wi-Fi to prevent Man-in-the-Middle attacks.
🛑 The Problem: Quotas, Blocks, and instability
My initial setup relied on ngrok and later Cloudflare Tunnel. Both are excellent tools, but they hit walls in my specific use case:
- Ngrok: Great for quick tests, but the free tier has connection limits and dynamic domains. It’s not “production ready” for daily family use.
- Cloudflare Tunnel: Zero-trust is amazing, but it struggled with specific UDP traffic and non-standard ports in my restricted network environment.
- Local Only: Running a proxy solely on my Mac meant that if I closed my laptop or the network dropped, the internet went “down” for everyone else.
I needed a solution that was fast (using my home bandwidth/IP when available) but reliable (falling back to a VPS when my Mac was offline).
🛠 The Solution: Active-Passive High Availability
I designed a Primary-Backup architecture.
- Primary Node (Mac): Runs the proxy locally. Low latency, “clean” residential IP.
- Backup Node (VPS): A cheap cloud server. Always online, acts as a failsafe.
- The “Switch”: An Nginx load balancer running on the VPS.
graph TD
User["Client Devices"] -->|"Connect VPS:10086"| Nginx["Nginx Stream LB"]
subgraph VPS ["VPS Server (Cloud)"]
direction TB
Nginx
Backup["Backup Proxy (Port 10088)"]
FRPS["FRPS Server"]
end
subgraph Home ["Home Network"]
direction TB
FRPC["FRPC Client"]
Mac["Mac Primary Proxy (Port 10086)"]
end
Nginx -->|"Primary Path"| FRPS
FRPS <==>|"FRP Tunnel (:7000)"| FRPC
FRPC -->|"Forward"| Mac
Mac -->|"Internet"| Internet1
Nginx -.->|"Failover Path"| Backup
Backup -->|"Internet"| Internet2
Internet1(("Internet"))
Internet2(("Internet"))
style Mac fill:#a7f3d0,stroke:#047857,stroke-width:2px
style Backup fill:#fde68a,stroke:#d97706,stroke-width:2px
style Nginx fill:#bfdbfe,stroke:#1d4ed8
1. The Tunnel: Why FRP?
Since my Mac has no public IP, I needed a reverse tunnel. I chose FRP over others because:
- Protocol Support: It handles TCP/UDP perfectly, which is crucial for proxy traffic (unlike some HTTP-only tunnels).
- Self-Hosted: I control the server. No third-party rate limits.
- Lightweight:
frpc(Client) andfrps(Server) are single binaries.
The Config:
My Mac (frpc) connects to the VPS (frps) on port 7000, mapping its local proxy port (10086) to the VPS’s port 10087.
2. The Magic: Nginx Stream Module & Failover
This was the biggest technical learning point. Standard Nginx is famous for HTTP reverse proxying, but for a raw TCP proxy (like a secure custom tunnel), we need the Stream Module.
I used Nginx’s upstream module with the backup parameter to implement active-passive failover logic.
1 | stream { |
How it works:
- Clients connect to VPS:10086.
- Nginx attempts to forward traffic to 10087 (the FRP tunnel to Mac).
- Happy Path: Mac is online → Traffic flows through the tunnel → Mac -> Internet.
- Failure Path: Mac is sleeping/offline → 10087 connection refuses.
- Failover: Nginx detects the failure immediately and routes traffic to 10088 (the backup proxy running directly on the VPS).
- Recovery: Every 3 seconds (as defined by
fail_timeout), Nginx tentatively tries the Primary again. If the Mac wakes up, traffic automatically flows back.
3. The “StateLess” Client Experience
To make this seamless for the end-users (my family), I ensured that both the Mac Proxy and VPS Backup Proxy share the exact same UUID and encryption settings.
To the client (e.g., Shadowrocket), it just sees “Server A”. It has no idea that the underlying backend shifted from a Mac in Seattle to a VPS in LA.
🚀 Key Takeaways
1. Passive Health Checks > Active Probing
In simple TCP setups, you don’t always need complex active health checks (pinging endpoints). Nginx’s passive health check (monitoring the actual connection response) is incredibly efficient. It reacts instantly to connection refusals.
2. The Power of “Wait” (fail_timeout)
Tuning fail_timeout is an art. Set it too high, and you stay on the backup server too long after the primary recovers. Set it too low, and a flaky connection causes “flapping” (rapid switching). 3 seconds turned out to be the sweet spot for a home network environment.
3. Self-Hosting Gives You Control
By moving away from managed services like Cloudflare Tunnel for this specific use case, I regained control over the transport layer. I can see exactly where connections fail—whether it’s the FRP tunnel, the local proxy process, or the Nginx routing.
Conclusion
This project was more than just saving a few dollars on a paid proxy service. It was a practical exercise in Resiliency Engineering. We built a system that degrades gracefully rather than failing catastrophically.
For anyone looking to harden their home lab accessibility: Don’t just build a service; build a backup. And let Nginx handle the rest.
Tools used: FRP (v0.66.0), Nginx (1.26), Docker, X-UI