m1k1o / neko

A self hosted virtual browser that runs in docker and uses WebRTC.
https://neko.m1k1o.net/
Apache License 2.0
5.96k stars 449 forks source link

Possible without exposing public port #259

Closed bobobobosu closed 1 year ago

bobobobosu commented 1 year ago

Is it possible to leverage WebRTC nat traversal to allow for incoming connection without exposing port to public? I mean just like how chrome remote desktop does with stun and turn relay.

m1k1o commented 1 year ago

Yes, you can configure own ICE servers, that will be turn servers. In that case you do not need to expose any port.

bobobobosu commented 1 year ago

Is it possible without turn servers? I added turn server but it still does not work. This is what I get when accessing neko behind a reverse proxy with only the website port exposed. Neko works, however, if it is on the same lan as the client.

2:09AM WRN could not get server reflexive address udp6 stun:stun.l.google.com:19302: read udp6 [::]:59058: i/o timeout module=webrtc submodule=pion subsystem=ice
2:09AM INF sent all ICECandidates module=webrtc
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice
2:09AM WRN pingAllCandidates called with no candidate pairs. Connection is not possible yet. module=webrtc submodule=pion subsystem=ice

This is a screenshot from chrome://webrtc-internals

Screenshot 2023-03-16 at 10 14 43 PM

Neko is in school network with only ipv4, client is also in a school network. Does not work at home network with ipv6.

Setup log:

2:32AM INF preflight complete config=/root/neko/config-nvh264device0enc.yaml debug=false logging=false
2:32AM WRN you are using deprecated config setting 'NEKO_H264=true', use 'NEKO_VIDEO_CODEC=h264' instead
2:32AM INF starting neko server service=neko
2:32AM INF webrtc starting ephemeral_port_range=59000-59100 ice_lite=false ice_servers="[{URLs:[stun:stun.l.google.com:19302] Username: Credential:<nil> CredentialType:password}]" module=webrtc nat_ips=
2:32AM WRN http listening on 127.0.0.1:9999 module=http
2:32AM INF neko ready service=neko
2:32AM INF creating pipeline codec=opus module=capture src="pulsesrc device=auto_null.monitor ! audio/x-raw,channels=2 ! audioconvert ! opusenc inband-fec=true bitrate=128000 ! appsink name=appsink" submodule=stream-sink video_id=audio
2:32AM INF first listener, starting module=capture submodule=stream-sink video_id=audio
2:32AM INF creating pipeline codec=h264 module=capture src="ximagesrc display-name=:0 show-pointer=false use-damage=false ! video/x-raw,framerate=60/1 ! videoconvert ! queue max-size-buffers=1 leaky=downstream ! video/x-raw,format=NV12 ! nvh264device1enc bitrate=3000 max-bitrate=5000 aq-strength=15 preset=low-latency-hp qp-min=30 qp-max=51 temporal-aq=false aq-strength=15 zerolatency=true ! video/x-h264,stream-format=byte-stream ! appsink  name=appsink max-buffers=1 drop=True" submodule=stream-sink video_id=video
error: XDG_RUNTIME_DIR not set in the environment.
2:32AM INF first listener, starting module=capture submodule=stream-sink video_id=video
m1k1o commented 1 year ago

It looks like there is some error when gathering client's candidates. Its not needed when ports are exposed, so that might be why it was never actually discovered. Also proper ice tricke is missing on client side, to send candidates asynchronously.

m1k1o commented 1 year ago

With the latest changes it should be fixed. I was able to test connection with only private TURN and STUN servers.

'NEKO_ICESERVERS=[{"urls": ["turn:<ip>:3478", "stun:<ip>:3478"], "username": "<user>", "credential": "<pass>"}]'

@bobobobosu can you please check again if it fixes your issue?

bobobobosu commented 1 year ago

Works now!! This is awesome!