NHP-FRP integrates OpenNHP (Network infrastructure Hiding Protocol) with frp (fast reverse proxy) to provide zero-trust network access for reverse proxy tunnels.
Try NHP-FRP instantly with zero configuration -- just build and run:
# Build the client
make frpc # Linux/macOS
build.bat frpc # Windows
# Run it
./bin/nhp-frpc # Linux/macOS
bin\nhp-frpc.exe # WindowsOn startup, nhp-frpc will display your unique Machine ID and public URL:
_ _ _ _ ____ _____ ____ ____
| \ | | | | | _ \ | ___| _ \| _ \
| \| | |_| | |_) |_____| |_ | |_) | |_) |
| |\ | _ | __/______| _| | _ <| __/
|_| \_|_| |_|_| |_| |_| \_\_|
nhp-frp 0.1.0 (client)
Machine ID: 70a22f85
nhp agent started successfully
Config portal available at http://127.0.0.1:7400
Public URL: http://70a22f85.ac.opennhp.org:6060
Admin API: http://70a22f85-admin.ac.opennhp.org:6060 (user: admin, password: 70a22f85)
File server listening on :8888 (serving .../bin/public)
Open http://<your-machine-id>.ac.opennhp.org:6060/ in a browser -- you'll see the bin/public/index.html from your machine, served through the NHP-protected tunnel. Replace it with your own content to share files instantly.
Your Machine Demo Server (acdemo.opennhp.org) Browser
┌─────────────────┐ ┌─────────────────────────────────┐
│ │ 1. NHP Knock │ │
│ NHP Agent ─────│────── UDP ─────>│ NHP Server │
│ │ │ │ verify + open firewall │
│ │ 2. FRP Tunnel │ v │
│ FRP Client ────│──── TCP:7000 ──>│ nhp-frps (:7000) │
│ │ │ │ │ │
│ │ proxy │ │ │ vhost routing │
│ v │ │ v │
│ File Server │ │ :6060 │ ┌──────────┐
│ (:8888) │ │ <machine-id>.ac.opennhp.org │<────│ Browser │
│ │ │ │ │ │ │ requests │
│ v │ │ │ forward to client │ │ :6060 │
│ bin/public/ │<── HTTP ────────│────┘ │ └──────────┘
│ index.html │ via FRP tunnel │ │
│ │ │ │
│ Admin API ─────│── HTTP ────────>│ <machine-id>-admin │<─── Server
│ (:7400) │ via FRP tunnel │ (basic auth protected) │ management
└─────────────────┘ └─────────────────────────────────┘
Step 1: NHP Agent sends encrypted knock → server opens port for your IP only
Step 2: FRP client connects to server through the opened port
Step 3: Browser visits http://<machine-id>.ac.opennhp.org:6060
Step 4: Server routes request via FRP tunnel → your local file server (:8888)
Step 5: bin/public/index.html is returned to the browser
A config portal at http://127.0.0.1:7400 lets you monitor proxy status via the built-in web dashboard.
The client's admin API is exposed via the FRP tunnel, allowing the server to remotely manage clients. It is protected by HTTP Basic Auth (user: admin, password: the client's machine ID).
# Get client proxy status
curl -u admin:<machine-id> http://<machine-id>-admin.ac.opennhp.org:6060/api/status
# Get current client config
curl -u admin:<machine-id> http://<machine-id>-admin.ac.opennhp.org:6060/api/config
# Update client config remotely
curl -u admin:<machine-id> -X PUT \
-H "Content-Type: application/toml" \
-d @new-frpc.toml \
http://<machine-id>-admin.ac.opennhp.org:6060/api/config
# Reload client to apply new config
curl -u admin:<machine-id> -X PUT http://<machine-id>-admin.ac.opennhp.org:6060/api/reloadStandard frp exposes server ports to the public internet, making them visible to port scanners and vulnerable to attacks. NHP-FRP solves this by adding an NHP layer that hides server ports by default and only opens them to authenticated, authorized clients.
How it works:
- The NHP Agent (built into
nhp-frpc) sends a cryptographic "knock" to the NHP server before connecting - The NHP server verifies the client's identity and opens the frp server port only for that specific client IP
- The frp tunnel is established through the now-open port
- The port is hidden again after the session, invisible to all other traffic
This turns frp into a zero-trust reverse proxy -- services are completely invisible on the network until a verified client needs access.
With standard frp, the server port (e.g. 7000) is always open and visible to anyone on the internet:
Public Internet
┌──────────┐ ┌──────────────────────────┐
│ frpc │──── frp tunnel (TCP:7000) ────────>│ frps (:7000 OPEN) │
│ client │ │ │ │
└──────────┘ │ v │
│ Backend Services │
┌──────────┐ │ ┌─────────────────┐ │
│ Attacker │──── port scan / exploit ──────────>│ │ Web App :8080 │ │
│ │ :7000 is visible! │ │ SSH :22 │ │
└──────────┘ │ │ DB :3306 │ │
│ └─────────────────┘ │
└──────────────────────────┘
Private Network
Problem: Port 7000 is exposed to the entire internet. Attackers can discover it via port scanning, then attempt brute-force attacks, exploit vulnerabilities, or launch DDoS attacks.
NHP-FRP hides all server ports. They only open for verified clients, for a limited time:
Public Internet
┌──────────────────────────┐
1. NHP Knock (UDP) │ │
┌──────────┐ ─────────────────────────────────> │ NHP Server (nhp-door) │
│ nhp-frpc │ │ │ 2. Verify identity │
│ client │ 3. Port opened │ │ Open firewall │
│ (with │ (for this IP only) │ v │
│ NHP │ │ Firewall │
│ Agent) │ ── 4. frp tunnel (TCP:7000) ─────> │ [allow client IP:7000] │
└──────────┘ │ │ │
│ v │
│ nhp-frps (:7000) │
┌──────────┐ │ │ │
│ Attacker │──── port scan ─────────── X ──────>│ v │
│ │ :7000 is INVISIBLE! │ Backend Services │
└──────────┘ (all ports closed) │ ┌─────────────────┐ │
│ │ Web App :8080 │ │
│ │ SSH :22 │ │
│ │ DB :3306 │ │
│ └─────────────────┘ │
└──────────────────────────┘
Private Network
Step-by-step flow:
| Step | Action | Detail |
|---|---|---|
| 1 | NHP Knock | nhp-frpc sends an encrypted UDP knock packet to the NHP server |
| 2 | Verify & Open | NHP server verifies the client's cryptographic identity and instructs the firewall to open port 7000 only for this client's IP |
| 3 | Port Opened | The firewall now allows traffic from the client IP to port 7000. All other IPs still see the port as closed |
| 4 | FRP Tunnel | nhp-frpc establishes the frp tunnel through the now-accessible port |
| 5 | Service Access | Traffic flows through the frp tunnel to backend services in the private network |
Result: The server has zero exposed ports on the public internet. Even if an attacker knows the server's IP address, port scans return nothing. Services are only reachable by clients who can prove their identity through NHP's cryptographic knock.
| Binary | Description |
|---|---|
nhp-frpc |
frp client with built-in NHP Agent -- performs NHP knock before connecting |
nhp-frps |
frp server (thin wrapper, future NHP integration planned) |
nhp-agent.dll/.so/.dylib |
NHP SDK shared library used by nhp-frpc |
nhp-frp/
cmd/
frpc/ # nhp-frpc entry point (NHP Agent + frp client)
frps/ # nhp-frps entry point (frp server wrapper)
pkg/version/ # Version info (injected at build time)
web/frpc/ # Embedded admin dashboard (Vue.js)
hack/ # Build helper scripts
third_party/
opennhp/ # OpenNHP submodule (NHP SDK source)
bin/ # Build output + runtime directory
nhp-frpc(.exe)
nhp-frps(.exe)
etc/ # Configuration files (frpc.toml, frps.toml, nhp-frpc.toml)
public/ # Static files served by the built-in file server
logs/ # Runtime log files
sdk/ # NHP SDK shared libraries
build.bat # Windows build script
Makefile # Linux/macOS build script
This project is a thin wrapper around upstream frp -- it imports frp v0.67.0 as a Go module dependency rather than forking the source. Only NHP-specific code lives in this repository, making upstream upgrades simple (change the version in go.mod).
- Go 1.23+
- GCC (for building the NHP SDK shared library via CGO)
- Linux:
apt install gccor equivalent - macOS: Xcode Command Line Tools
- Windows: MSYS2 with
mingw-w64-x86_64-gcc
- Linux:
# Build everything (nhp-frps + nhp-frpc with SDK)
make
# Build individual targets
make frps
make frpc # includes SDK build
make build-sdk # SDK only:: Build everything
build.bat
:: Build individual targets
build.bat frps
build.bat frpc &:: includes SDK build
build.bat build-sdk &:: SDK only
:: Other commands
build.bat clean
build.bat helpNote (Windows): The SDK build requires MSYS2 MinGW-w64. The build script auto-detects MSYS2 at
C:\Program Files\msys2orC:\msys64. You may need to add Windows Defender exclusions for thebin\sdk\directory and your temp folder if the DLL build is blocked.
Config files live in bin/etc/ next to the binaries. NHP-FRP uses the same TOML format as frp, with template variables for dynamic values.
frps (server): bin/etc/frps.toml
bindPort = 7000
vhostHTTPPort = 6060
subDomainHost = "ac.opennhp.org"
log.to = "{{ .Envs.NHP_BIN_DIR }}/logs/nhp-frps.log"
log.level = "info"frpc (client): bin/etc/frpc.toml
serverAddr = "acdemo.opennhp.org"
serverPort = 7000
auth.method = "token"
auth.token = "opennhp-frp"
webServer.addr = "127.0.0.1"
webServer.port = 7400
webServer.user = "admin"
webServer.password = "{{ .Envs.NHP_MACHINE_ID }}"
[[proxies]]
name = "file-server"
type = "http"
localIP = "127.0.0.1"
localPort = 8888
subdomain = "{{ .Envs.NHP_MACHINE_ID }}"
[[proxies]]
name = "admin-api"
type = "http"
localIP = "127.0.0.1"
localPort = 7400
subdomain = "{{ .Envs.NHP_MACHINE_ID }}-admin"nhp-frpc.toml (NHP-specific settings, separate from frp config):
subDomainHost = "ac.opennhp.org"
vhostHTTPPort = 6060See bin/etc/ for full example configurations. For frp configuration details, refer to the frp documentation.
The NHP Agent is configured separately -- it reads its configuration from the same directory as the nhp-frpc binary. See OpenNHP documentation for NHP configuration details.
# Start the server
./bin/nhp-frps
# Start the client (NHP Agent starts automatically)
./bin/nhp-frpcBy default, both binaries read config from the etc/ subfolder next to the binary (e.g. bin/etc/frps.toml). You can override with -c:
./bin/nhp-frps -c /path/to/frps.toml
./bin/nhp-frpc -c /path/to/frpc.tomlWhen nhp-frpc starts, it first initializes the NHP Agent which performs the cryptographic knock sequence. Once the NHP handshake succeeds, the frp client connects to the server normally.
Apache License 2.0 -- see LICENSE for details.
This project builds upon frp by fatedier (Apache 2.0) and OpenNHP by the OpenNHP team.