NAT Penetration using FRP

NAT penetration is useful in many cases. For example, if your ISP uses Carrier Grade NAT (CGNAT) and does not have a public IP address, you will need it to expose local service to be accessible from the public Internet. FRP is one powerful and simple to use NAT penetration tool. FRP documentation has more information on using FRP.

To use frp, first download frp server and client (frps and frpc) binaries, and create a regular user for frps/frpc with useradd on the server and client for security reason.

Server configuration

FRP server binds a main port for the tunnel traffic, as well as allows clients to map other server ports back to client services. Then, client services can be accessed using server ip and the reqested port.

Server can specify a simple token or password to authenicate client. FRP also supports using OpenID for authenication.

The server also needs to open the TCP or UDP (if KCP is used) port in the firewall to allow incoming traffic.

1
2
3
4
5
6
[common]
bind_port = <main port>
kcp_bind_port = <main port>
allow_ports = <allowed mapping port region>
authentication_method = token
token = <token>

Also, you can create a systemd service to control the frps process. Client can configure systemd service in a similar way.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=<your description>
After=network.target

[Service]
Type=simple
User=frps
Group=frps
Restart=on-failure
RestartSec=5s
ExecStart=/usr/bin/frps -c /etc/frp/frps.ini

[Install]
WantedBy=multi-user.target

Client configuration

Client connects to server port and requests to map local service to one server port. You can optionally use KCP instead of usual TCP as transport protocol for tunnel traffic, because KCP is a UDP-based protocol and it can reduce service latency.

One client configuration file can contain multiple services and request one server port for each service. Also optionally enable or disable compression and encryption for each service.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[common]
server_addr = <server address>
server_port = <main port>
# protocol = kcp
authentication_method = token
token = <token>

[<service name>]
type = tcp/udp
local_ip = localhost
local_port = <local service port>
remote_port = <requested server port>
# use_encryption = true
# use_compression = true

Finally, enable and start both frps and frpc with systemd, and your local service should be accessible from the Internet!