P2P (Peer-to-Peer)

P2P (Peer-to-Peer) is a type of network architecture in which all the nodes (typically computers) in the network are considered equal and can communicate directly with each other, sharing resources and data without the need for an intermediary server. This contrasts with the traditional client-server model, where clients request services from servers.

Frps configuration

Similarly as before, edit the frps.toml in the server end and add the following lines here. WebServer service and auth.token could be disabled as well, just follow your heart.

1
2
3
4
5
6
7
8
vim frps.toml

bindPort = 7000
auth.token = "sunhaoyang"
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin_password"

Then, Start frps on machine A.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > /etc/systemd/system/frps.service <<-'EOF'
[Unit]
Description=FRP Server Service
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/frp/frps -c /usr/local/bin/frp/frps.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@frp-server ~]# systemctl daemon-reload
[root@frp-server ~]# systemctl enable frps.service --now
Created symlink /etc/systemd/system/multi-user.target.wants/frps.service → /etc/systemd/system/frps.service.
[root@frp-server ~]# systemctl status frps.service
● frps.service - FRP Server Service
Loaded: loaded (/etc/systemd/system/frps.service; enabled; preset: disabled)
Active: active (running) since Fri 2025-04-25 16:06:45 CST; 4s ago
Main PID: 355286 (frps)
Tasks: 5 (limit: 12344)
Memory: 9.0M
CPU: 324ms
CGroup: /system.slice/frps.service
└─355286 /usr/local/bin/frp/frps -c /usr/local/bin/frp/frps.toml

Apr 25 16:06:45 frp-server systemd[1]: Started FRP Server Service.
Apr 25 16:06:45 frp-server frps[355286]: 2025-04-25 16:06:45.952 [I] [frps/root.go:105] frps uses config file: /usr/local/bin/frp/frps.toml
Apr 25 16:06:46 frp-server frps[355286]: 2025-04-25 16:06:46.270 [I] [server/service.go:237] frps tcp listen on 0.0.0.0:7000
Apr 25 16:06:46 frp-server frps[355286]: 2025-04-25 16:06:46.271 [I] [frps/root.go:114] frps started successfully
Apr 25 16:06:46 frp-server frps[355286]: 2025-04-25 16:06:46.271 [I] [server/service.go:351] dashboard listen on 0.0.0.0:7500

Frpc configuration

Proxy

Start frpc on machine B, and expose the SSH port. Note that the remotePort field is removed.

1
[root@VM-0-7-rockylinux ~]# mv frp_0.62.0_linux_amd64 /usr/local/bin/frp
1
2
3
4
5
6
7
8
9
10
11
12
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
# set up a new stun server if the default one is not available.
# natHoleStunServer = "xxx"

[[proxies]]
name = "p2p_ssh"
type = "xtcp"
secretKey = "abcdefg"
localIP = "127.0.0.1"
localPort = 22 # Here, I use ssh port as an example. Something else, such as 80(httpd) works as well.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > /etc/systemd/system/frpc.service <<-'EOF'
[Unit]
Description=FRP Client Service
After=network.target

[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/frp/frpc -c /usr/local/bin/frp/frpc.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@VM-0-7-rockylinux frp]# systemctl daemon-reload
[root@VM-0-7-rockylinux frp]# systemctl enable frpc.service --now
Created symlink /etc/systemd/system/multi-user.target.wants/frpc.service → /etc/systemd/system/frpc.service.
[root@VM-0-7-rockylinux frp]# systemctl status frpc.service
● frpc.service - FRP Client Service
Loaded: loaded (/etc/systemd/system/frpc.service; enabled; preset: disabled)
Active: active (running) since Sun 2025-04-27 00:57:13 CST; 3s ago
Main PID: 72540 (frpc)
Tasks: 4 (limit: 12140)
Memory: 5.0M
CPU: 6ms
CGroup: /system.slice/frpc.service
└─72540 /usr/local/bin/frp/frpc -c /usr/local/bin/frp/frpc.toml

Apr 27 00:57:13 VM-0-7-rockylinux systemd[1]: Started FRP Client Service.
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.009 [I] [sub/root.go:149] s>
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.009 [I] [client/service.go:>
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.042 [I] [client/service.go:>
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.042 [I] [proxy/proxy_manage>
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.052 [I] [client/control.go:>

Visitor

Start another frpc (typically on another machine C) with the configuration to connect to SSH using P2P mode.

1
2
3
4
[root@VM-48-7-rockylinux ~]# mv frp_0.62.0_linux_amd64 /usr/local/bin/frp
[root@VM-48-7-rockylinux ~]# cd /usr/local/bin/
[root@VM-48-7-rockylinux bin]# ls
frp scp sftp ssh ssh-add ssh-agent ssh-keygen ssh-keyscan
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
# set up a new stun server if the default one is not available.
# natHoleStunServer = "xxx"

[[visitors]]
name = "p2p_ssh_visitor"
type = "xtcp"
serverName = "p2p_ssh" # The serverName here and that one in Proxy must be set to the same.
secretKey = "abcdefg" # The secretKey here and that one in Proxy must be set to the same.
bindAddr = "127.0.0.1"
bindPort = 6000
# when automatic tunnel persistence is required, set it to true
# keepTunnelOpen = false # Comment this line

Connect

On machine C, connect to SSH on machine B, using this command.

Login Successfully

1
2
3
4
5
6
[root@VM-48-7-rockylinux frp_0.62.0_linux_amd64]# ssh -oPort=6000 127.0.0.1
root@127.0.0.1's password:
Activate the web console with: systemctl enable --now cockpit.socket

Last login: Sat Apr 26 21:30:24 2025 from 175.162.122.18
[root@VM-0-7-rockylinux ~]#

Check the log of frpc in machine B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@VM-0-7-rockylinux frp]# systemctl status frpc.service
● frpc.service - FRP Client Service
Loaded: loaded (/etc/systemd/system/frpc.service; enabled; preset: disabled)
Active: active (running) since Sun 2025-04-27 00:57:13 CST; 10min ago
Main PID: 72540 (frpc)
Tasks: 4 (limit: 12140)
Memory: 8.1M
CPU: 451ms
CGroup: /system.slice/frpc.service
└─72540 /usr/local/bin/frp/frpc -c /usr/local/bin/frp/frpc.toml

Apr 27 00:57:13 VM-0-7-rockylinux systemd[1]: Started FRP Client Service.
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.009 [I] [sub/root.go:149] start frpc service for config file [/usr/local/bin/frp/frpc.toml]
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.009 [I] [client/service.go:314] try to connect to server...
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.042 [I] [client/service.go:306] [5dbff11603bd8e75] login to server success, get run id [5dbff11603bd>
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.042 [I] [proxy/proxy_manager.go:177] [5dbff11603bd8e75] proxy added: [p2p_ssh]
Apr 27 00:57:13 VM-0-7-rockylinux frpc[72540]: 2025-04-27 00:57:13.052 [I] [client/control.go:172] [5dbff11603bd8e75] [p2p_ssh] start proxy success
Apr 27 01:07:43 VM-0-7-rockylinux frpc[72540]: 2025-04-27 01:07:43.686 [I] [proxy/xtcp.go:72] [5dbff11603bd8e75] [p2p_ssh] nathole prepare success, nat type: EasyNAT, >
Apr 27 01:07:44 VM-0-7-rockylinux frpc[72540]: 2025-04-27 01:07:44.696 [I] [proxy/xtcp.go:93] [5dbff11603bd8e75] [p2p_ssh] get natHoleRespMsg, sid [17456872631ee7cb59a>
Apr 27 01:07:44 VM-0-7-rockylinux frpc[72540]: 2025-04-27 01:07:44.734 [I] [proxy/xtcp.go:109] [5dbff11603bd8e75] [p2p_ssh] establishing nat hole connection successful>

It is obviously that the hole was punched.
E.g. nathole prepare success, nat type: EasyNAT, establishing nat hole connection successful.

Check the log of frps in machine A

1
2
3
4
5
2025-04-27 00:57:13.038 [I] [server/service.go:582] [5dbff11603bd8e75] client login info: ip [118.195.155.132:42178] version [0.62.0] hostname [] os [linux] arch [amd64]
2025-04-27 00:57:13.049 [I] [server/control.go:399] [5dbff11603bd8e75] new proxy [p2p_ssh] type [xtcp] success
2025-04-27 01:00:45.040 [I] [server/control.go:357] [607581f620a645ec] client exit success
2025-04-27 01:01:34.544 [I] [server/service.go:582] [fc60898a7eda2cb0] client login info: ip [101.43.210.253:57136] version [0.62.0] hostname [] os [linux] arch [amd64]
2025-04-27 01:07:44.741 [I] [nathole/controller.go:280] sid [17456872631ee7cb59a2e4b72a] report make hole success: true, mode 0, index 0

report make hole success represents the connection between machine B and machine C is successful as well.

Test

scp

Create a large file by dd command in machine C

1
2
3
4
[root@VM-0-7-rockylinux html]# dd if=/dev/zero of=testfile bs=1M count=5120
5120+0 records in
5120+0 records out
5368709120 bytes (5.4 GB, 5.0 GiB) copied, 25.0375 s, 214 MB/s

Use scp command in machine C and send the large file to machine B

1
2
3
[root@VM-48-7-rockylinux ~]# time scp -P 6000 testfile root@127.0.0.1:/root
root@127.0.0.1's password:
testfile 53% 2749MB 10.5MB/s 03:45 ETA^C

frps traffic monitor

Congratulations! This image is an evidence to proof that The traffic did not go through the frps server, but instead, machine B and machine C are directly connected.

wget

Install the httpd service in machine B

1
2
dnf provides httpd
dnf install httpd

Start and Enable the httpd service in machine B

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@VM-0-7-rockylinux ~]# systemctl enable httpd.service --now
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@VM-0-7-rockylinux ~]# systemctl status httpd.service
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
Active: active (running) since Sat 2025-04-26 22:11:58 CST; 1s ago
Docs: man:httpd.service(8)
Main PID: 21890 (httpd)
Status: "Started, listening on: port 80"
Tasks: 177 (limit: 12140)
Memory: 24.2M
CPU: 47ms
CGroup: /system.slice/httpd.service
├─21890 /usr/sbin/httpd -DFOREGROUND
├─21891 /usr/sbin/httpd -DFOREGROUND
├─21892 /usr/sbin/httpd -DFOREGROUND
├─21893 /usr/sbin/httpd -DFOREGROUND
└─21894 /usr/sbin/httpd -DFOREGROUND

Apr 26 22:11:58 VM-0-7-rockylinux systemd[1]: Starting The Apache HTTP Server...
Apr 26 22:11:58 VM-0-7-rockylinux httpd[21890]: Server configured, listening on: port 80
Apr 26 22:11:58 VM-0-7-rockylinux systemd[1]: Started The Apache HTTP Server.

Create a large file by dd command in machine B

1
2
3
4
[root@VM-0-7-rockylinux html]# dd if=/dev/zero of=testfile bs=1M count=5120
5120+0 records in
5120+0 records out
5368709120 bytes (5.4 GB, 5.0 GiB) copied, 25.0375 s, 214 MB/s

Move the large file to the httpd root directory in machine B

1
mv testfile /var/www/html

Use wget command in machine C and download the large file from machine B

1
2
3
4
5
6
7
[root@VM-48-7-rockylinux test_http]# wget http://127.0.0.1:6000/testfile
--2025-04-26 22:17:00-- http://127.0.0.1:6000/testfile
Connecting to 127.0.0.1:6000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 5368709120 (5.0G)
Saving to: ‘testfile.1’
testfile.1 10%[==> ] 529.66M 11.6MB/s eta 6m 47s ^C

frps traffic monitor

Congratulations! This image is an evidence to proof that The traffic did not go through the frps server, but instead, machine B and machine C are directly connected.