[GH-ISSUE #3469] Not all of STUN servers are compatible with FRP #2773

Closed
opened 2026-05-05 13:47:17 -06:00 by gitea-mirror · 9 comments
Owner

Originally created by @Bellegar on GitHub (May 31, 2023).
Original GitHub issue: https://github.com/fatedier/frp/issues/3469

Originally assigned to: @fatedier on GitHub.

Bug Description

This behaviour similar to using config field for frpc 'nat_hole_stun_server' or using console test
frpc nathole discover --nat_hole_stun_server ***

Default server stun.easyvoip.com:3478 is working as expected, but some others do not work, with error:
discover error: wait response from stun server timeout

I test some servers from that list and that.
Some STUN servers, that correctly similarly behave on https://icetest.info/ or on https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ produces such timeout error:
stun.antisip.com:3478
stun.stochastix.de:3478
stun.beebeetle.com:3478

I host own coturn STUN server on linux with default configuration (checked enabling/disabling 'stun-only' config flag) on public IP, which is correctly work for check on sites above.
But FRP can't work with it.

I found several working servers
stun.voipstunt.com:3478
stun.cheapvoip.com:3478
stun.voipgain.com:3478

Good 'nathole discover' result prints this one:
STUN server: stun.easyvoip.com:3478
Your NAT type is: EasyNAT
Behavior is: BehaviorNoChange
External address is: [IP:port IP:port]
Local address is: 0.0.0.0:port
Public Network: false

frpc Version

0.49.0 (cceab7e)

frps Version

0.49.0 (cceab7e)

System Architecture

windows/amd64, mingw64, go 1.20

Configurations

No need config to test 'nathole discover'

Logs

No response

Steps to reproduce

  1. frpc nathole discover --nat_hole_stun_server stun.antisip.com:3478
  2. discover error: wait response from stun server timeout

Affected area

  • Docs
  • Installation
  • Performance and Scalability
  • Security
  • User Experience
  • Test and Release
  • Developer Infrastructure
  • Client Plugin
  • Server Plugin
  • Extensions
  • Others
Originally created by @Bellegar on GitHub (May 31, 2023). Original GitHub issue: https://github.com/fatedier/frp/issues/3469 Originally assigned to: @fatedier on GitHub. ### Bug Description This behaviour similar to using config field for frpc 'nat_hole_stun_server' or using console test `frpc nathole discover --nat_hole_stun_server ***` Default server stun.easyvoip.com:3478 is working as expected, but some others do not work, with error: `discover error: wait response from stun server timeout` I test some servers from [that list](https://gist.github.com/sagivo/3a4b2f2c7ac6e1b5267c2f1f59ac6c6b) and [that](https://raw.githubusercontent.com/pradt2/always-online-stun/master/valid_hosts.txt). Some STUN servers, that correctly similarly behave on https://icetest.info/ or on https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/ produces such timeout error: stun.antisip.com:3478 stun.stochastix.de:3478 stun.beebeetle.com:3478 I host own [coturn](https://github.com/coturn/coturn) STUN server on linux with default configuration (checked enabling/disabling 'stun-only' config flag) on public IP, which is correctly work for check on sites above. But FRP can't work with it. I found several working servers stun.voipstunt.com:3478 stun.cheapvoip.com:3478 stun.voipgain.com:3478 Good 'nathole discover' result prints this one: STUN server: stun.easyvoip.com:3478 Your NAT type is: EasyNAT Behavior is: BehaviorNoChange External address is: [*IP*:*port* *IP*:*port*] Local address is: 0.0.0.0:*port* Public Network: false ### frpc Version 0.49.0 (cceab7e) ### frps Version 0.49.0 (cceab7e) ### System Architecture windows/amd64, mingw64, go 1.20 ### Configurations No need config to test 'nathole discover' ### Logs _No response_ ### Steps to reproduce 1. frpc nathole discover --nat_hole_stun_server stun.antisip.com:3478 2. discover error: wait response from stun server timeout ### Affected area - [ ] Docs - [ ] Installation - [ ] Performance and Scalability - [ ] Security - [ ] User Experience - [ ] Test and Release - [ ] Developer Infrastructure - [ ] Client Plugin - [ ] Server Plugin - [ ] Extensions - [X] Others
Author
Owner

@fatedier commented on GitHub (Jun 1, 2023):

It looks like stun.antisip.com:3478 may not be fully functional because we need to use the second address provided by the stun server to access different external IPs. However, the second address for stun.antisip.com:3478 is stun.antisip.com:3479 and it is not available, so it will time out.

<!-- gh-comment-id:1572074003 --> @fatedier commented on GitHub (Jun 1, 2023): It looks like `stun.antisip.com:3478` may not be fully functional because we need to use the second address provided by the stun server to access different external IPs. However, the second address for `stun.antisip.com:3478` is `stun.antisip.com:3479` and it is not available, so it will time out.
Author
Owner

@Bellegar commented on GitHub (Jun 2, 2023):

3479 and it is not available, so it will time out

That is right, I opened 3479 port for my hosted coturn server, and 'nathole discover' became working, as also in configuration for xtcp.
But a little bit strange, that NUT hole punching realization using in FRP is hard depends on 3479 port, when STUN address points directly to 3478, and there is no mention anywhere, that 3479 must be opened for servers, used for 'nat_hole_stun_server '. Also other STUN test services do not need 3479 port for checking correct STUN server's status.
Just interested: Does 3479 port really necessary for frp, isn't it redundant?

<!-- gh-comment-id:1573561735 --> @Bellegar commented on GitHub (Jun 2, 2023): > `3479` and it is not available, so it will time out That is right, I opened 3479 port for my hosted coturn server, and 'nathole discover' became working, as also in configuration for xtcp. But a little bit strange, that NUT hole punching realization using in FRP is hard depends on 3479 port, when STUN address points directly to 3478, and there is no mention anywhere, that 3479 must be opened for servers, used for 'nat_hole_stun_server '. Also other STUN test services do not need 3479 port for checking correct STUN server's status. Just interested: Does 3479 port really necessary for frp, isn't it redundant?
Author
Owner

@fatedier commented on GitHub (Jun 2, 2023):

If you are interested, you can refer to the relevant RFC documents for further information: RFC 5780.

The response code 3479 is not explicitly defined by any specific source, but it is returned by the STUN server itself. This code indicates the address of the second request that the client needs to try after the first request. Typically, the IP address of this second address needs to be different from the first attempt to yield meaningful results, while changing the port number usually has minimal impact.

STUN servers that support this feature can assist in detecting NAT behavior, thereby significantly enhancing the success rate of penetration.

Even if this feature is not supported, it might still be possible to achieve success, but certain specific NAT environments may experience adverse effects. Therefore, utilizing a STUN server that supports this capability (which is the case with most STUN servers adhering to standard specifications) can provide a better experience.

<!-- gh-comment-id:1573582177 --> @fatedier commented on GitHub (Jun 2, 2023): If you are interested, you can refer to the relevant RFC documents for further information: [RFC 5780](https://www.rfc-editor.org/rfc/rfc5780.html#section-7.4). The response code 3479 is not explicitly defined by any specific source, but it is returned by the STUN server itself. This code indicates the address of the second request that the client needs to try after the first request. Typically, the IP address of this second address needs to be different from the first attempt to yield meaningful results, while changing the port number usually has minimal impact. STUN servers that support this feature can assist in detecting NAT behavior, thereby significantly enhancing the success rate of penetration. Even if this feature is not supported, it might still be possible to achieve success, but certain specific NAT environments may experience adverse effects. Therefore, utilizing a STUN server that supports this capability (which is the case with most STUN servers adhering to standard specifications) can provide a better experience.
Author
Owner

@hayden-pan commented on GitHub (Oct 11, 2024):

As mentioned by @fatedier, after search about the widely used STUN server coturn's configuration.

I found the vital configuration items to make coturn satisfy with FRP.

  • no-rfc5780: This item is enabled by default, because it increase the possibility of an amplification attack. But it should be disabled for compatible with FRP
  • external-ip: If your server is behind NAT like me, you should set this item to <public-ip>/<private-ip>

After setting up as above and restart coturn service, you will find coturn listening on both UDP and TCP ports on 3478 and 3479. So maybe the answer is also for #4321 , the STUN server is need to implement and enabled RFC5780 to work with FRP

<!-- gh-comment-id:2407152665 --> @hayden-pan commented on GitHub (Oct 11, 2024): As mentioned by @fatedier, after search about the widely used STUN server coturn's [configuration](https://github.com/coturn/coturn/blob/master/examples/etc/turnserver.conf). I found the vital configuration items to make coturn satisfy with FRP. - `no-rfc5780`: This item is enabled by default, because it increase the possibility of an amplification attack. But it should be disabled for compatible with FRP - `external-ip`: If your server is behind NAT like me, you should set this item to `<public-ip>/<private-ip>` After setting up as above and restart coturn service, you will find coturn listening on both UDP and TCP ports on 3478 and 3479. So maybe the answer is also for #4321 , the STUN server is need to implement and enabled RFC5780 to work with FRP
Author
Owner

@TwoBirdsOnTheTree commented on GitHub (Mar 11, 2025):

反复尝试在阿里云里搭建,失败已放弃
turnserver.conf配置如下:

listening-port=3478
alt-listening-port=3479
external-ip=xxxxxxxx/10.0.0.169
#realm=coturn
verbose
stun-only
log-file=stdout
#no-rfc5780
#no-stun-backward-compatibility
#response-origin-only-with-rfc5780

尝试过程中发现:

  • 如果日志打印了error resolving ';; communications error to 208.67.222.222#53: timed out xxxxxxxxx' hostname: Name or service not known, 则3479端口监听成功:INFO: IPv4. UDP listener opened on: 10.0.0.169:3479
    • (出现概率低,偶发出现)
  • 反之则出现WARNING: STUN CHANGE_REQUEST not supported: only one IP address is provided,此时不会监听3479
<!-- gh-comment-id:2712638176 --> @TwoBirdsOnTheTree commented on GitHub (Mar 11, 2025): 反复尝试在阿里云里搭建,失败已放弃 turnserver.conf配置如下: ``` conf listening-port=3478 alt-listening-port=3479 external-ip=xxxxxxxx/10.0.0.169 #realm=coturn verbose stun-only log-file=stdout #no-rfc5780 #no-stun-backward-compatibility #response-origin-only-with-rfc5780 ``` 尝试过程中发现: - 如果日志打印了`error resolving ';; communications error to 208.67.222.222#53: timed out xxxxxxxxx' hostname: Name or service not known`, 则3479端口监听成功:`INFO: IPv4. UDP listener opened on: 10.0.0.169:3479` - (出现概率低,偶发出现) - 反之则出现`WARNING: STUN CHANGE_REQUEST not supported: only one IP address is provided`,此时不会监听3479
Author
Owner

@xsjmonk commented on GitHub (Dec 20, 2025):

Finally, a usable frp-compatible stun server can be done in this way:

  1. Prepare two public Ips
  2. Have ubuntu and install coturn as stun server
  3. Make this turnserver.conf. There are many pitfalls such as explicit listening-ip, etc. Make sure it fits your need and you know what you are doing
listening-ip=private_ip1
listening-ip=private_ip2
listening-port=3478
alt-listening-port=3479
no-auth
no-tls
no-dtls
no-tcp
no-sctp
fingerprint
simple-log
verbose
log-binding
rfc5780
external-ip=public_ip1/private_ip1
external-ip=public_ip2/private_ip2

Two public ips are the key, which enables the RFC5780 probe to succeed.

  • With only one public IP, coturn typically can’t provide a meaningful “change IP” target.
  • Many clients treat “missing OTHER-ADDRESS / change probe can’t be done” as NAT discovery failure.
<!-- gh-comment-id:3677773875 --> @xsjmonk commented on GitHub (Dec 20, 2025): Finally, a usable frp-compatible stun server can be done in this way: 1. Prepare two public Ips 2. Have ubuntu and install `coturn` as stun server 3. Make this `turnserver.conf`. There are many pitfalls such as explicit `listening-ip`, etc. Make sure it fits your need and you know what you are doing ``` listening-ip=private_ip1 listening-ip=private_ip2 listening-port=3478 alt-listening-port=3479 no-auth no-tls no-dtls no-tcp no-sctp fingerprint simple-log verbose log-binding rfc5780 external-ip=public_ip1/private_ip1 external-ip=public_ip2/private_ip2 ``` Two public ips are the key, which enables the RFC5780 probe to succeed. * With only one public IP, coturn typically can’t provide a meaningful “change IP” target. * Many clients treat “missing OTHER-ADDRESS / change probe can’t be done” as NAT discovery failure.
Author
Owner

@hayden-pan commented on GitHub (Dec 25, 2025):

Finally, a usable frp-compatible stun server can be done in this way:

  1. Prepare two public Ips
  2. Have ubuntu and install coturn as stun server
  3. Make this turnserver.conf. There are many pitfalls such as explicit listening-ip, etc. Make sure it fits your need and you know what you are doing
listening-ip=private_ip1
listening-ip=private_ip2
listening-port=3478
alt-listening-port=3479
no-auth
no-tls
no-dtls
no-tcp
no-sctp
fingerprint
simple-log
verbose
log-binding
rfc5780
external-ip=public_ip1/private_ip1
external-ip=public_ip2/private_ip2

Two public ips are the key, which enables the RFC5780 probe to succeed.

  • With only one public IP, coturn typically can’t provide a meaningful “change IP” target.
  • Many clients treat “missing OTHER-ADDRESS / change probe can’t be done” as NAT discovery failure.

Preparing two public IP addresses is too costly. Although I'm not an expert, I don't think such a protocol requirement should exist. I am using coturn with only one public IP address now

<!-- gh-comment-id:3691386811 --> @hayden-pan commented on GitHub (Dec 25, 2025): > Finally, a usable frp-compatible stun server can be done in this way: > 1. Prepare two public Ips > 2. Have ubuntu and install `coturn` as stun server > 3. Make this `turnserver.conf`. There are many pitfalls such as explicit `listening-ip`, etc. Make sure it fits your need and you know what you are doing > > ``` > listening-ip=private_ip1 > listening-ip=private_ip2 > listening-port=3478 > alt-listening-port=3479 > no-auth > no-tls > no-dtls > no-tcp > no-sctp > fingerprint > simple-log > verbose > log-binding > rfc5780 > external-ip=public_ip1/private_ip1 > external-ip=public_ip2/private_ip2 > ``` > > Two public ips are the key, which enables the RFC5780 probe to succeed. > * With only one public IP, coturn typically can’t provide a meaningful “change IP” target. > * Many clients treat “missing OTHER-ADDRESS / change probe can’t be done” as NAT discovery failure. > Preparing two public IP addresses is too costly. Although I'm not an expert, I don't think such a protocol requirement should exist. I am using coturn with only one public IP address now
Author
Owner

@bluedreamteng commented on GitHub (Feb 10, 2026):

I found a method for single public IP setup that's compatible with frp.
With a single network interface, you need to create a virtual IP, for example:
sudo ip addr add 172.26.208.185/24 dev eth0
Then the complete configuration is as follows:

listening-port=3478
alt-listening-port=3479
两个内网 IP
listening-ip=172.26.208.184
listening-ip=172.26.208.185
映射到同一个公网 IP
external-ip=47.120.26.60/172.26.208.184
external-ip=47.120.26.60/172.26.208.185
relay-ip=172.26.208.184
relay-ip=172.26.208.185
no-auth
verbose
log-file=/var/log/turnserver.log
<!-- gh-comment-id:3875025742 --> @bluedreamteng commented on GitHub (Feb 10, 2026): I found a method for single public IP setup that's compatible with frp. With a single network interface, you need to create a virtual IP, for example: `sudo ip addr add 172.26.208.185/24 dev eth0` Then the complete configuration is as follows: ``` listening-port=3478 alt-listening-port=3479 两个内网 IP listening-ip=172.26.208.184 listening-ip=172.26.208.185 映射到同一个公网 IP external-ip=47.120.26.60/172.26.208.184 external-ip=47.120.26.60/172.26.208.185 relay-ip=172.26.208.184 relay-ip=172.26.208.185 no-auth verbose log-file=/var/log/turnserver.log ```
Author
Owner

@Brown000 commented on GitHub (Apr 24, 2026):

I found a method for single public IP setup that's compatible with frp. With a single network interface, you need to create a virtual IP, for example: sudo ip addr add 172.26.208.185/24 dev eth0 Then the complete configuration is as follows:

listening-port=3478
alt-listening-port=3479
两个内网 IP
listening-ip=172.26.208.184
listening-ip=172.26.208.185
映射到同一个公网 IP
external-ip=47.120.26.60/172.26.208.184
external-ip=47.120.26.60/172.26.208.185
relay-ip=172.26.208.184
relay-ip=172.26.208.185
no-auth
verbose
log-file=/var/log/turnserver.log

This is a correct solution. When searching 'RFC 5780' in turnserver.conf, There are some comments like:

# Alternative listening port for UDP and TCP listeners;
# default (or zero) value means "listening port plus one". 
# This is needed for RFC 5780 support
# (STUN extension specs, NAT behavior discovery). The TURN Server 
# supports RFC 5780 only if it is started with more than one 
# listening IP address of the same family (IPv4 or IPv6).
# RFC 5780 is supported only by UDP protocol, other protocols
# are listening to that endpoint only for "symmetry".
#
#alt-listening-port=0

That means we need to listen on at least 2 IPs to support NAT behavior discovery which is required by frp.
So we can add another virtual private ip and listen on it, or just comment listening-ip config which make coturn listening on all system IPs from interfaces like lo/eth0/docker0.
This is remarked at turnserver.conf too:

# Listener IP address of relay server. Multiple listeners can be specified.
# If no IP(s) specified in the config file or in the command line options, 
# then all IPv4 and IPv6 system IPs will be used for listening.
#
#listening-ip=0.0.0.0
#listening-ip=10.207.21.238
#listening-ip=2607:f0d0:1002:51::4
<!-- gh-comment-id:4313181084 --> @Brown000 commented on GitHub (Apr 24, 2026): > I found a method for single public IP setup that's compatible with frp. With a single network interface, you need to create a virtual IP, for example: `sudo ip addr add 172.26.208.185/24 dev eth0` Then the complete configuration is as follows: > > ``` > listening-port=3478 > alt-listening-port=3479 > 两个内网 IP > listening-ip=172.26.208.184 > listening-ip=172.26.208.185 > 映射到同一个公网 IP > external-ip=47.120.26.60/172.26.208.184 > external-ip=47.120.26.60/172.26.208.185 > relay-ip=172.26.208.184 > relay-ip=172.26.208.185 > no-auth > verbose > log-file=/var/log/turnserver.log > ``` This is a correct solution. When searching 'RFC 5780' in **turnserver.conf**, There are some comments like: ```text # Alternative listening port for UDP and TCP listeners; # default (or zero) value means "listening port plus one". # This is needed for RFC 5780 support # (STUN extension specs, NAT behavior discovery). The TURN Server # supports RFC 5780 only if it is started with more than one # listening IP address of the same family (IPv4 or IPv6). # RFC 5780 is supported only by UDP protocol, other protocols # are listening to that endpoint only for "symmetry". # #alt-listening-port=0 ``` That means we need to listen on **at least 2 IPs** to support NAT behavior discovery which is required by **frp**. So we can add another virtual private ip and listen on it, or just comment **listening-ip** config which make **coturn** listening on all system IPs from interfaces like lo/eth0/docker0. This is remarked at **turnserver.conf** too: ```text # Listener IP address of relay server. Multiple listeners can be specified. # If no IP(s) specified in the config file or in the command line options, # then all IPv4 and IPv6 system IPs will be used for listening. # #listening-ip=0.0.0.0 #listening-ip=10.207.21.238 #listening-ip=2607:f0d0:1002:51::4 ```
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: github-starred/frp#2773
No description provided.