FRP (Fast Reverse Proxy) solves a specific problem that comes up when you have services running on a local network that you want to reach from outside: your development machine, a home lab server, a printer, an IoT device. No port forwarding needed, no need for a static IP at home.
The architecture: FRP runs a server component (frps) on a cloud VPS with a public IP, and a client component (frpc) on the machine you want to expose. The client establishes a persistent connection to the server, and traffic to yoursubdomain.yourdomain.com gets tunneled to your local machine transparently.
I use it mainly for testing local development environments with real HTTPS URLs — useful for OAuth callbacks, webhooks from third-party services, and client demos.
The architecture: an FRP server (frps) runs on your cloud server with a public IP. FRP clients (frpc) run on devices behind NAT and connect outbound to the server. The server then routes incoming traffic from the internet to the appropriate client.
I run the FRP server component on Tencent Cloud Lighthouse. For intranet penetration, the relay server needs a stable static public IP and reliable uptime — Lighthouse provides both. The global data center options also matter: if your local machine and the people accessing your exposed services are in different regions, choosing a Lighthouse region between them reduces the round-trip latency for tunneled connections. The entry-level plan handles FRP comfortably — it's a lightweight proxy process.
- Key Takeaways
| Scenario | What you expose |
|---|---|
| Remote SSH to home server | SSH port via TCP proxy |
| Access home NAS from anywhere | NAS web UI via HTTP proxy |
| Share local dev server with clients | HTTP/HTTPS with custom domain |
| Expose IoT device management | Custom port via TCP/UDP |
| Access office network resources | Multiple TCP proxies |
| Mobile API backend testing | HTTP with webhook support |
| Requirement | Notes |
|---|---|
| Cloud server | Tencent Cloud Lighthouse with public IP |
| Local device | Any Linux/macOS/Windows machine behind NAT |
| FRP binary | Same version on both server and client |
ssh ubuntu@YOUR_SERVER_IP
Download the latest FRP release (check github.com/fatedier/frp/releases for current version):
FRP_VERSION="0.62.0"
wget https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz
tar -xzf frp_${FRP_VERSION}_linux_amd64.tar.gz
cd frp_${FRP_VERSION}_linux_amd64
# Install server binary
sudo cp frps /usr/local/bin/
sudo chmod +x /usr/local/bin/frps
Open required ports in the Lighthouse console firewall and UFW:
sudo ufw allow 7000/tcp # FRP server listen port (clients connect here)
sudo ufw allow 7500/tcp # FRP dashboard (optional)
sudo ufw allow 7080/tcp # HTTP virtual host port (optional)
sudo ufw allow 7443/tcp # HTTPS virtual host port (optional)
# Add custom ports as needed (e.g., 6022 for SSH proxy)
sudo ufw allow 6000:7000/tcp # Range for client-mapped ports
sudo mkdir -p /etc/frp
sudo nano /etc/frp/frps.toml
# frps server configuration
# FRP protocol listen port (clients connect here)
bindPort = 7000
# Web dashboard
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "choose_strong_dashboard_password"
# Authentication token — clients must present this to connect
auth.method = "token"
auth.token = "your_secret_auth_token_here"
# HTTP/HTTPS virtual hosting
vhostHTTPPort = 7080
vhostHTTPSPort = 7443
# Maximum ports a single client can open
maxPortsPerClient = 20
# Logging
log.to = "/var/log/frps.log"
log.level = "info"
log.maxDays = 7
Generate a strong auth token:
openssl rand -hex 32
# Copy the output — use it as auth.token
sudo nano /etc/systemd/system/frps.service
[Unit]
Description=FRP Server (frps)
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable frps
sudo systemctl start frps
sudo systemctl status frps
# Test the dashboard is accessible
curl http://localhost:7500
On the local device (the machine behind NAT):
# Download same FRP version as the server
FRP_VERSION="0.62.0"
# Choose the right build for your OS:
# Linux AMD64: frp_0.62.0_linux_amd64.tar.gz
# macOS ARM: frp_0.62.0_darwin_arm64.tar.gz
# Windows: frp_0.62.0_windows_amd64.zip
wget https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz
tar -xzf frp_${FRP_VERSION}_linux_amd64.tar.gz
cd frp_${FRP_VERSION}_linux_amd64
sudo cp frpc /usr/local/bin/
sudo chmod +x /usr/local/bin/frpc
Create client config:
sudo mkdir -p /etc/frp
sudo nano /etc/frp/frpc.toml
# frpc client configuration
serverAddr = "YOUR_SERVER_IP"
serverPort = 7000
# Must match server's auth.token
auth.method = "token"
auth.token = "your_secret_auth_token_here"
# Log
log.to = "/var/log/frpc.log"
log.level = "info"
Add these sections to /etc/frp/frpc.toml:
[[proxies]]
name = "ssh-home"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6022
Connect from anywhere:
ssh -p 6022 localuser@YOUR_SERVER_IP
[[proxies]]
name = "nas-ui"
type = "tcp"
localIP = "192.168.1.100" # NAS IP on local network
localPort = 5000 # Synology NAS management port
remotePort = 6500
[[proxies]]
name = "dev-server"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3000
remotePort = 6300
Access at: http://YOUR_SERVER_IP:6300
sudo nano /etc/systemd/system/frpc.service
[Unit]
Description=FRP Client (frpc)
After=network.target
[Service]
Type=simple
User=nobody
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
sudo systemctl enable frpc
sudo systemctl start frpc
sudo systemctl status frpc
FRP supports routing HTTP traffic by subdomain — you can map multiple local services to different subdomains via a single cloud server port.
Set up DNS: Add wildcard A record *.yourdomain.com → YOUR_SERVER_IP
Client config:
[[proxies]]
name = "local-blog"
type = "http"
localPort = 2368 # Local Ghost blog
customDomains = ["blog.yourdomain.com"]
[[proxies]]
name = "local-app"
type = "http"
localPort = 3000 # Local Node.js app
customDomains = ["app.yourdomain.com"]
Traffic to blog.yourdomain.com:7080 → forwarded to localhost:2368 on the client.
For HTTPS:
[[proxies]]
name = "local-https"
type = "https"
localPort = 443
customDomains = ["secure.yourdomain.com"]
Visit http://YOUR_SERVER_IP:7500 (or configure Nginx to proxy it with HTTPS).
The dashboard shows:
Restrict the dashboard to your IP only:
sudo ufw delete allow 7500/tcp
sudo ufw allow from YOUR_HOME_IP to any port 7500
Running frps without authentication means anyone can connect and create proxies through your server. This is a serious security issue — an attacker could use your server to tunnel traffic through it.
Always configure auth.token on the server and set the same token in every client config. If a client presents the wrong token, the connection is rejected.
Additionally, restrict the frps listen port (7000) using UFW if your clients have static IPs:
sudo ufw delete allow 7000/tcp
sudo ufw allow from CLIENT_IP to any port 7000
auth.token on server and all clientsmaxPortsPerClient = 20 limits abuse| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
How does FRP intranet penetration differ from a simple SSH tunnel?
SSH tunnels are connection-specific and not persistent without extra tools. FRP intranet penetration is a dedicated service that runs continuously, supports multiple protocols, and provides a more robust and manageable solution for ongoing tunnel needs.
Is the tunnel traffic encrypted?
Traffic through the Lighthouse server itself can be encrypted depending on the protocol used. For sensitive applications, use TLS/SSL on top of the tunnel for end-to-end encryption.
How do I make the tunnel persistent after server reboots?
Set up both the server and client components as systemd services with Restart=on-failure. They'll start automatically on boot and recover from crashes.
What is the performance overhead of using FRP intranet penetration?
Minimal for most use cases. Latency adds the round-trip time through the relay server. Throughput is limited by the Lighthouse server's bandwidth and network speed.
Set up your FRP server today:
👉 Tencent Cloud Lighthouse — Public IP relay server for FRP
👉 View current pricing and promotions
👉 Explore all active deals and offers