docker-jitsi-meet icon indicating copy to clipboard operation
docker-jitsi-meet copied to clipboard

turn: add TURN server

Open netaskd opened this issue 4 years ago • 21 comments

adds TURN server to the infrastructure.

netaskd avatar Dec 11 '19 17:12 netaskd

Can I help here? I have free time...

jkroepke avatar Apr 21 '20 21:04 jkroepke

For information I finish a version that integrate a turn server into web container. Why insert coturn inside web container and not create a new one ? It's for use the same SSH certificate. https://github.com/sliard/docker-jitsi-meet/tree/upgrade_add_turn

It's not fair to create a new MR because it's base on this one at the begining. I have one last problem, it works only with network_mode host into docker compose.

sliard avatar Apr 22 '20 14:04 sliard

One thing that's currently missing is documentation: which ports one would need to open additionally. This should be added here:

https://github.com/jitsi/docker-jitsi-meet#external-ports

ccoenen avatar Apr 23 '20 15:04 ccoenen

One thing that's currently missing is documentation: which ports one would need to open additionally. This should be added here:

https://github.com/jitsi/docker-jitsi-meet#external-ports

added in 14d717c

netaskd avatar Apr 23 '20 16:04 netaskd

Hi, any news on this?

holtgrewe avatar May 11 '20 20:05 holtgrewe

Having this in will be great.

mihaiplesa avatar May 13 '20 06:05 mihaiplesa

ping?

holtgrewe avatar May 19 '20 07:05 holtgrewe

As I see we have only one unresolved conversation around it. So, if @saghul have a couple of minutes to take a look this, I beleive we will fastly resolve and merge it.

netaskd avatar May 25 '20 21:05 netaskd

@saghul could you have a look at this?

Only you can save mankind from Zoom meetings :)

holtgrewe avatar Jun 02 '20 07:06 holtgrewe

Hi! Although I'm not really versed on all needed to make this work on docker, I could test it in my on premises installation. Would it help? We are using docker, but setting up TURN without docker. Yes... Our JMS doesn't currently have a TURN server... :(

dsantos21 avatar Jun 17 '20 16:06 dsantos21

Thank you so much for this work! I look forward to see this! Jitsi community really rocks!

citosid avatar Jun 23 '20 18:06 citosid

Hi, is there anything that could be done here to move this forward?

holtgrewe avatar Jun 25 '20 07:06 holtgrewe

I've worked on this from the latest docker-jitsi-meet adding all the changes of the PR except for two:

  1. It does not contain the changes to the README of the original PR since that page content has been moved somewhere else
  2. It changes the name of the turn docker container (from jitsi/turn which wasn't found to instrumentisto/coturn).

I attach the patch which is mostly the same of the PR except for these two changes. I'd also be able to provide the terraform script that created the machines I'm testing in (in Digital Ocean). turn.diff

Problems

Jitsi works but I'm having some problems to test whether the turn server is working.

I can't block the port 10000/udp with ufw. I've tried to block ports with ufw but it doesn't seem to have any effect perhaps due to this?.

The other thing I've tried is to checking chrome://webrtc-internals (since I haven't been able to block 10000 this is not as useful as it could be). When I test with several participants I see in the some of the tabs "iceServers: [stun:meet-jit-si-turnrelay.jitsi.net:443]", but this is the same I see in a server where I have not applied the patch

@netaskd Any way I could go on from here in order to provide help to advance this pull request?

First option I can think of is to try other ways to block port 10000. Do other iptables management utilities have the same problem as ufw with respect to docker?, any advice on how to do block 10000/udp without stumbling on this problem?

nestorconde avatar Jun 28 '20 11:06 nestorconde

First option I can think of is to try other ways to block port 10000. Do other iptables management utilities have the same problem as ufw with respect to docker?, any advice on how to do block 10000/udp without stumbling on this problem?

Hi, does this help?

https://stackoverflow.com/questions/49549834/ufw-firewall-is-not-working-on-ubuntu-in-digitalocean/49563279#49563279

holtgrewe avatar Jun 29 '20 08:06 holtgrewe

Docker generally doesn't play well out-of-the-box with firewall configuration tools such as UFW, shorewall, etc. Such tools generate IPTABLES rules based on some "easier" configuration format, while Docker itself leverages IPTABLES to "magically" configure NAT for the containers. If both tools are not aware of each other, they will overwrite or shadow each-other's IPTABLE rules.

Both UFW and Shorwall have builtin support for Docker in their latest versions which is disabled by default. Enabling this feature will make UFW "docker-aware" and preserve Dockers IPTABLE rules when run.

However, it is still rather complicated to block incoming connections to Docker via IPTABLE rules, due to the fact that NAT is processed before the FILTER rules, meaning that packets to Docker-configured ports are redirected into the corresponding container before the packets run through the FILTER chain of the host - therefor never hitting the rule.

See: https://2.bp.blogspot.com/-skGmyfTzXGI/U84PI9EbjkI/AAAAAAAAD6Q/kjjfG17_yo8/s1600/Linux-Iptables-firewall-schema.png

Solution

The correct way to prevent access into a Docker container is to explicitly state 127.0.0.1 in the --port argument when running a container, such as

docker run --port 127.0.0.1:10000:10000 ...

This will only allow access to port 10000 when the connection is coming from the Docker host itself and will deny access when coming from elsewhere.

baccenfutter avatar Jun 29 '20 08:06 baccenfutter

I also need this. How can I help the development? What's still open?

parruc avatar Jun 30 '20 07:06 parruc

@baccenfutter What I did was modify the docker-compose.yml at the root of the project by changing

jvb
   ...
    ports:
-      '${JVB_PORT}:${JVB_PORT}/udp'
+      '127.0.0.1:${JVB_PORT}:${JVB_PORT}/udp'

Is that equivalent to what you suggested? (I don't know enough about docker and docker-compose to evaluate whether it is).

In any case after doing that I was having problems with the audio/video from the videoconference which only worked momentarily and then stopped working. Perhaps there's some unexpected side effect to that way of restricting the port?, if that's not the case then my patch is not working when 10000/udp is blocked.

@holtgrewe I did not try that because it seemed to me that I'd be changing more things than strictly needed (it would affect potentially other things). In order to evaluate whether the patch is working I need a test that isolates the changes so I wanted to only block 10000/udp and leave everything else the same.

@netaskd @saghul There's a lot of interest in this PR and some people would like to help but we don't have the information on how to do it. As far as I understand there's just this change pending review but the turncredentials code in netaskd branch have changed since the time the review was requested. Could you provide some guidance if helping is possible? If it isn't it would be useful to know that too ;)

nestorconde avatar Jun 30 '20 11:06 nestorconde

Read through all of this but didn't get it... will this also support adding an external TURN server without starting an additional coturn docker container which isn't needed in that case?

pandel avatar Aug 20 '20 20:08 pandel

What is the status of this PR, what discussion is still pending? I'm also working on integrating Jitsi, and we really need to support TURN for corporate VPNs.


The setup we are using is to split traffic with Envoy & also terminate TLS there. That way both Jitsi's NGINX/web container & CoTURN don't need to do TLS offloading. Example envoy.yaml configuration:

# docker run -v $PWD:/etc/ssl/private -v $PWD:/data envoyproxy/envoy:v1.14.4 /usr/local/bin/envoy -c /data/envoy.yaml --mode validate
#
admin:
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  # Main listener
  - address:
      socket_address: { address: 0.0.0.0, port_value: 4430 }
    # TLS Inspector parses the SNI & ALPN settings
    listener_filters:
    - name: "envoy.filters.listener.tls_inspector"
      typed_config: {}
    # One filter chain per SNI & ALPN
    filter_chains:
      # shard-1 HTTP
      - filter_chain_match: # shard-1 http
          server_names: ["shard-1.eu.example.org"]
          application_protocols: ["http/1.1", "h2"]
        transport_socket: &tmpl_transport_socket
          name: envoy.transport_sockets.tls
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
            common_tls_context:
              tls_certificates:
              - certificate_chain: { filename: "/etc/ssl/private/tls.crt" }
                private_key: { filename: "/etc/ssl/private/tls.key" }
        filters: &tmpl_http_filters
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                virtual_hosts:
                - name: default
                  domains: "*"
                  routes:
                  - match: { prefix: "/" }
                    route: { cluster: service_shard1_nginx }
              http_filters:
                - name: envoy.filters.http.router
      # shard-1 TURN
      - filter_chain_match:
          server_names: ["shard-1.eu.example.org"]
        transport_socket: *tmpl_transport_socket
        filters:
          - name: envoy.filters.network.tcp_proxy
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy
              stat_prefix: tcp
              cluster: service_shard1_turn
      # fallback HTTP (redirects to Application Level router)
      - filter_chain_match:
          server_names: ["*.example.org"]
        transport_socket: *tmpl_transport_socket
        filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: ingress_http
              route_config:
                virtual_hosts:
                - name: default
                  domains: "*"
                  routes:
                  - match: { prefix: "/" }
                    route: { cluster: service_fallback }
              http_filters:
                - name: envoy.filters.http.router
      # fallback for health check
      - filter_chain_match:
        transport_socket: *tmpl_transport_socket
        filters:
          - name: envoy.filters.network.http_connection_manager
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
              stat_prefix: direct_http
              route_config:
                virtual_hosts:
                - name: default
                  domains: "*"
                  routes:
                  - match: { prefix: "/" }
                    direct_response:
                      status: 200
                      body:
                        inline_string: "Fallback"
              http_filters:
                - name: envoy.filters.http.router
  clusters:
  - name: service_fallback
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: service_fallback
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: nginx-internal
                port_value: 80
  - name: service_shard1_nginx
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: service_shard1_nginx
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: nginx.shard-1.svc.cluster.local
                port_value: 80
  - name: service_shard1_turn
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: service_shard1_turn
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: turn.shard-1.svc.cluster.local
                port_value: 5349

I'm also working on an Envoy xDS API endpoint that serves this configuration dynamically. That would ease adding shards drastically in our Kubernetes setup.

hermanbanken avatar Sep 11 '20 18:09 hermanbanken

I've documented in the community my tests with a simple firewall and:

  1. The setup described in this PR
  2. Multiplexing (for turn to work when its ports are blocked by the firewall) based on the docs. My exact setup for multiplexing can be seen here

As far as I can see under with this setup for the videoconferences to work it's enough if the firewall allows 80, 443 (both outbound and inbound) and 10000 outbound.

I know this PR does not include the multiplexing bit but I think this contributes to the conversation and the multiplexing part is an interesting direction for turn in docker-jitsi-meet to pursue

nestorconde avatar Oct 02 '20 08:10 nestorconde

Hi Folks,

This PR is still alive or somebody working on it? What kind of job is left to do?

Also, I don't understand this PR. As I can see the main goal of this PR is to make it happen to configure an external TURN server for Jitsi and you have created a new image which will be a coTURN server for testing or if somebody wants to use it. Am I right? If it's true then I would like to help you to finish this, because from the commits and because of my lack of knowledge with the configuration I can't see another way to configure Jitsi containers to use TURN servers.

If we can configure Jitsi to use TURN server, then there is a way to somehow force the relay through TURN with p2p connections? Can I just put a zero or false value into an env variable and force it?

VidarHUN avatar Sep 27 '22 20:09 VidarHUN