network · verified 2026-08-31 ✓ Verified

frp

Verified2026-08-31: frps/frpc tunnel + hot reload verified; status/reload requires the webServer (admin) enabled.

Expose LAN services without a public IP via frps/frpc; SSH home, HTTP serving, remote debugging.

Category: network Complete entry Security: Security reviewed Domain: other Verified 2026-08-31 v0.52.0~0.71.0 Conflicts: none Source: Trove (independent adaptation, unofficial)

Install: curl -L -o /tmp/frp.tar.gz https://ghfast.top/https://github.com/fatedier/frp/releases/download/v0.71.0/frp_0.71.0_linux_amd64.tar.gz && tar xzf /tmp/frp.tar.gz -C /tmp && sudo mv /tmp/frp_0.71.0_linux_amd64/frps /tmp/frp_0.71.0_linux_amd64/frpc /usr/local/bin/

What you are dealing with

You run a service on a LAN / campus network (home NAS, lab dev machine, a web service inside WSL) and want to reach it from outside, but you have no public IP. ISPs do not hand them out, router config is painful, campus networks have no inbound access at all - this is the "access a service without a public IP" problem. frp solves it: one server with a public IP (a cheap cloud VM is enough) acts as the relay; the LAN machine connects out and keeps a tunnel; anyone hitting the server port reaches your LAN service. Use it when: you need SSH back into a machine without a public IP; you want to temporarily expose a local dev service (remote debugging, demos, webhook/callback testing); you want to serve an internal web service on a public domain/port (HTTP vhost). Do not use it for: plain local/LAN access (no tunneling needed); long-running high-throughput production proxying (use a mature gateway instead).

Path: Quick fix (one command, local tunnel demo) → Step by step (real deployment on a public server) → How to confirm it works → FAQ (connection troubleshooting).

Why it works this way

frp is a reverse tunnel: instead of punching inbound holes, the LAN machine connects out and holds a long-lived connection to the public server. When an external user hits "server IP:port", frps forwards that traffic through the tunnel to frpc on the LAN machine, which forwards it to the real local service.

  • frps (server): runs on the machine with a public IP; listens on ports, receives traffic, forwards through the tunnel;
  • frpc (client): runs on the LAN machine; connects out to frps, registers proxies, and delivers forwarded traffic to local services;
  • proxy: one mapping rule in frpc.toml (e.g. "server port 6000 → local port 22").

What it touches: two standalone binaries (frps/frpc) + their config files; no package-manager changes, no global config writes; systemd autostart recommended.

Quick fix (no explanations, one command to run a local tunnel)

note: One combined command: download → extract → start frps → start frpc → verify through the tunnel, all isolated on 127.0.0.1 loopback (ports in the 27000 range); if it fails, split it up and follow "Step by step" below.
mkdir -p /tmp/frp-demo && cd /tmp/frp-demo && curl -L -o frp.tar.gz https://ghfast.top/https://github.com/fatedier/frp/releases/download/v0.71.0/frp_0.71.0_linux_amd64.tar.gz && tar xzf frp.tar.gz --strip-components=1 && printf 'frp tunnel demo page\n' > index.html && (python3 -m http.server 27081 --bind 127.0.0.1 >/dev/null 2>&1 &) && printf 'bindAddr = "127.0.0.1"\nbindPort = 27000\n' > frps.toml && ./frps -c frps.toml >/dev/null 2>&1 & sleep 1; printf 'serverAddr = "127.0.0.1"\nserverPort = 27000\n\n[[proxies]]\nname = "web-demo"\ntype = "tcp"\nlocalIP = "127.0.0.1"\nlocalPort = 27081\nremotePort = 27082\n' > frpc.toml && ./frpc -c frpc.toml >/dev/null 2>&1 & sleep 2; curl -s http://127.0.0.1:27082/index.html

预期输出: frp tunnel demo page (tunnel up); otherwise split it and follow "Step by step" below

Step by step

Step 1: Download and install (one copy per machine)

  • Server (public-IP cloud VM, Linux x86_64): download frps and put it in /usr/local/bin;
  • Client (LAN machine): download frpc and put it in /usr/local/bin.
note: In China prefer the ghfast.top mirror (verified working 2026-08-31, supports resuming); direct GitHub releases may be unreachable on some networks; Gitee mirrors the repo but does not host release assets
curl -L -o /tmp/frp.tar.gz https://ghfast.top/https://github.com/fatedier/frp/releases/download/v0.71.0/frp_0.71.0_linux_amd64.tar.gz
tar xzf /tmp/frp.tar.gz -C /tmp
sudo mv /tmp/frp_0.71.0_linux_amd64/frps /tmp/frp_0.71.0_linux_amd64/frpc /usr/local/bin/
frps --version && frpc --version

预期输出: 0.71.0 (two lines)

If stuck: download timeout/failure → switch ghfast.top to your own proxy or direct GitHub release; version command reports command not found → check the mv paths and sudo permissions; other architectures/systems → pick the matching asset on the project release page (linux_arm64 / darwin / windows amd64, etc.).

Step 2: Configure frps (public server)

frps is the server side: it listens on one "control port" waiting for frpc to connect; also set a token for identity verification (TLS is on by default since v0.50.0).

sudo mkdir -p /etc/frp
sudo tee /etc/frp/frps.toml > /dev/null <<'TOML'
bindAddr = "0.0.0.0"
bindPort = 7000
auth.method = "token"
auth.token = "replace with your own long random string"
TOML
sudo /usr/local/bin/frps -c /etc/frp/frps.toml

预期输出: frps uses config file: /etc/frp/frps.toml frps tcp listen on 0.0.0.0:7000 frps started successfully

If stuck: address already in use → the port is taken, run ss -tlnp | grep 7000 to find the process and change the port; server will not start and logs are empty → check the TOML syntax (TOML since v0.52.0, INI is deprecated). On cloud VMs, remember to open bindPort (default 7000) and the remotePorts you map (e.g. 6000) in the security group.

Step 3: Configure frpc (LAN machine)

frpc is the client side: fill in the frps address and token, then declare one proxy rule - "server port 6000 → local port 22".

sudo tee /etc/frp/frpc.toml > /dev/null <<'TOML'
serverAddr = "your-server-public-IP"
serverPort = 7000
auth.method = "token"
auth.token = "same token as frps"
[[proxies]]
name = "ssh-home"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
TOML
sudo /usr/local/bin/frpc -c /etc/frp/frpc.toml

预期输出: login to server success proxy added: [ssh-home] [ssh-home] start proxy success

If stuck: login to server failed → first run ss -tlnp | grep 7000 to confirm frps is listening, serverAddr is the public IP, and the token matches on both sides; proxy registered but unreachable from outside → check that the security group allows remotePort.

Step 4: Autostart with systemd (example, not tested)

note: This environment did not run systemd (isolated container); the unit below is the standard pattern, adjust per distro; not tested
sudo tee /etc/systemd/system/frpc.service > /dev/null <<'UNIT'
[Unit]
Description=frp client
After=network.target
[Service]
ExecStart=/usr/local/bin/frpc -c /etc/frp/frpc.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
UNIT
sudo systemctl enable --now frpc
sudo systemctl status frpc --no-pager

预期输出: systemd status Active: active (running) (example, not tested)

If stuck: systemctl reports unit not found → run sudo systemctl daemon-reload first; Status shows failed → run journalctl -u frpc -n 30 for the exact error.

How to confirm it works

From outside (or another machine), connect to the server port: if it responds, the tunnel is working; then check proxy registration with frpc status.

curl -s http://your-server-public-IP:the-mapped-remotePort/ -o /dev/null -w '%{http_code}\n'
ssh -oPort=6000 your-user@your-server-public-IP 'echo tunnel-ok'
frpc status -c /etc/frp/frpc.toml

预期输出: HTTP 200; SSH echoes tunnel-ok; frpc status lists proxies web-demo/ssh-home as running (the equivalent local isolated verification is in Evidence: curl 127.0.0.1:27082 returns the same page as direct access)

Other environments

note: frp official releases provide multi-platform binaries; the following are honest notes for environments this guide did not test
EnvironmentBehaviorNotes
Windowsfrps/frpc have windows amd64 binaries, same CLI usage; open the ports in the firewallNot tested (this guide ran on WSL/Linux)
macOSdarwin amd64/arm64 binaries; Apple Silicon use the arm64 packageNot tested
Linux server (public)standard frps deployment scenario with systemd autostart; open bindPort/remotePort in the security groupConfig semantics cross-checked with the README; systemd not run in this environment
Router/embedded (OpenWrt etc.)community builds available, same usage as LinuxNot tested

Daily use

note: frpc status / frpc reload depend on frpc's admin server - the webServer block must be enabled, otherwise you get web server port should be set if you want to use this feature (verified in this guide's testing). Add to frpc.toml:
cat >> /etc/frp/frpc.toml <<'TOML'
webServer.addr = "127.0.0.1"
webServer.port = 7400
TOML

预期输出: (no output; restart frpc once so the admin server takes effect before using status/reload)

Check tunnel status

To confirm each proxy is up and the exposed port works, run frpc status:

frpc status -c /etc/frp/frpc.toml

预期输出: A Proxy Status... table with one row per proxy (verified on v0.71.0): Name Status LocalAddr Plugin RemoteAddr Error, e.g. web-demo running 127.0.0.1:27081 127.0.0.1:27082 (Status running = healthy)

How to read it: if Status is not running, look at the Error column (port taken, local service down, etc.); LocalAddr is the local service address, RemoteAddr is the public-facing port; rows are sorted by proxy name.

Add a proxy without restart (hot reload)

Scenario: expose one more port - no frpc restart, existing tunnels stay up:

frpc reload -c /etc/frp/frpc.toml

预期输出: reload success (verified: with 2 proxies running, reload added a 3rd; the new proxy was immediately running and the old ones were unaffected)

Steps: ① append the new proxy block to frpc.toml; ② run reload; ③ frpc status to confirm the new proxy; ④ hit the new remotePort from outside to verify. Note: reload only adds/removes/updates proxies; connection-level changes (serverAddr / serverPort / auth) still need a full restart.

Logs

  • systemd deployment: journalctl -u frpc -f;
  • Manual run: login to server success in the terminal = connected to frps; start proxy success = that proxy is ready;
  • Server-side dashboard: frps supports webServer.port (not tested; see project docs).

Uninstall

sudo systemctl disable --now frpc 2>/dev/null || true
sudo rm -f /usr/local/bin/frps /usr/local/bin/frpc
sudo rm -rf /etc/frp
pkill -f frpc; pkill -f frps 2>/dev/null

预期输出: (no output; /usr/local/bin and /etc/frp cleaned)

note: frp keeps no background data or global state; removing the binaries and config is a complete uninstall; also close the frp ports you opened in the cloud security group

Dependency warnings & conflicts

  • Ports: bindPort (default 7000) and remotePort must be free and opened in the cloud security group; pick different ports on conflict;
  • Security: a public frps must set auth.token; transport.useEncryption/useCompression are off by default (TLS on), enable for sensitive traffic;
  • Antivirus false positives: frpc is a reverse-proxy tool; some AVs flag and delete it (project docs issue 3637) - add an allowlist/exclusion;
  • WSL/dual-stack pitfall (found in this guide's testing): without bindAddr, frps listened on an IPv6 dual-stack socket and IPv4 loopback connections were refused; setting bindAddr = "127.0.0.1" (or 0.0.0.0 on servers) fixed it;
  • Other tools on this site: frp is a standalone binary with its own config; no shared write surface with the listed agent/CLI tools (all 25 matrix pairs possible-compatible, static judgement).

FAQ

Q0: frpc status / frpc reload report web server port should be set if you want to use this feature Those two commands depend on frpc's admin server; enable webServer.addr + webServer.port in frpc.toml (see Daily use) and restart frpc. Verified in this guide's testing: without webServer both commands fail with that error, while the tunnels themselves keep working. Q1: frpc reports login to server failed: dial tcp ... connect: connection refused Run ss -tlnp | grep <port> to confirm frps is listening and the port is right; then check the security group/firewall allows bindPort; then make sure serverAddr is the public IP, not 127.0.0.1. In WSL, if frps refuses IPv4 loopback connections, check the dual-stack pitfall above (set bindAddr explicitly). Q2: address already in use Port is taken. ss -tlnp | grep <port> finds the process; change bindPort/remotePort or stop the old process. Old frps/frpc processes that did not exit cleanly cause this on restart. Q3: frpc was deleted by antivirus Common false positive for reverse-proxy tools (project docs issue 3637). Add an allowlist/exclusion, or use the portable extracted build (this guide installs the portable build). Q4: outside can reach the server port but no data flows through the tunnel First verify the local service on localPort works locally (curl localhost:localPort); then check proxy state with frpc status; common causes: localIP points at another machine, or the service listens on IPv6 only.

Evidence

  • Daily-use test (2026-09-01, WSL Ubuntu x86_64, frps/frpc 0.71.0): local repro log 2026-09-01 - with webServer enabled, frpc status printed the proxy table; frpc reload hot-added a proxy (reload success), the new tunnel worked immediately and old proxies were unaffected; the without-webServer error for status/reload was reproduced;
  • Full-loop isolated loopback tunnel test (2026-08-31, WSL Ubuntu x86_64, frps/frpc 0.71.0): local repro log 2026-08-31 - local service on 27081 reachable directly → frps listening on 27000 → frpc registered the proxy → curl 127.0.0.1:27082 returned the same page as the direct connection;
  • Version & download: GitHub release v0.71.0 (published 2026-08-14, Apache-2.0); ghfast.top mirror verified with 206 range/resume support;
  • Config semantics: TOML config supported since v0.52.0 (INI deprecated); TLS on by default (since v0.50.0); token auth is the default method - cross-checked with the project README.

← Trove | evidence & precheck records kept locally; conclusions and sources published here