Skip to content

Commit

Permalink
Add support for Fly.io deployments
Browse files Browse the repository at this point in the history
  • Loading branch information
mickel8 committed Sep 21, 2024
1 parent f310ba0 commit 2e4979c
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 21 deletions.
15 changes: 10 additions & 5 deletions guides/advanced/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ The visual aspects may not knock you off your feet, but the page provides a lot
to learn more about what's in the WebRTC Internals, or simply explore the tool and see what you find useful.

> #### Other browsers {: .info}
>
> Chromium's WebRTC Internals is arguably the best tool of this kind. Firefox provides `about:webrtc` page, but it's not nearly as featureful as `chrome://webrtc-internals`.
> Safari does not have an equivalent, but it allows you to enable verbose logging of WebRTC-related stuff.
Expand Down Expand Up @@ -54,7 +55,7 @@ open up Wireshark and capture the RTP traffic directly. Unfortunately, WebRTC by
you can obtain from packets captured live is highly limited. There are two solutions:

- run Chromium with `--disable-webrtc-encryption` flag. In this case, the other WebRTC peer also needs to somehow bypass encryption, which (as of now) is
impossible in Elixir WebRTC.
impossible in Elixir WebRTC.

- make Chromium dump received RTP packets after they were decrypted.

Expand All @@ -79,6 +80,7 @@ text2pcap -D -u 5443,62132 -t %H:%M:%S.%f rtp-dump.txt rtp-dump.pcap
Now, you should be able to open the `rtp-dump.pcap` file with Wireshark and inspect the packets!

> #### What about Firefox? {: .info}
>
> You can also do similar things in Firefox. Check out this [SO post](https://stackoverflow.com/questions/74399155/how-do-i-see-internal-webrtc-logs-in-firefox)
> to learn how to turn on WebRTC logs, and this [blog post](https://blog.mozilla.org/webrtc/debugging-encrypted-rtp-is-more-fun-than-it-used-to-be/)
> on how to dump RTP packets.
Expand Down Expand Up @@ -135,14 +137,17 @@ When using Simulcast in a browser, make sure that you allocate not too little ba
if the browser deems that there is too little bandwidth available, or that the CPU load is too big, it might decide to just stop sending one of the layers.

```js
mediaConstraints = {video: {width: { ideal: 1280 }, height: { ideal: 720 } }, audio: true};
mediaConstraints = {
video: { width: { ideal: 1280 }, height: { ideal: 720 } },
audio: true,
};
const localStream = await navigator.mediaDevices.getUserMedia(mediaConstraints);

const pc = new RTCPeerConnection();
pc.addTransceivers(localStream.getVideoTracks()[0], {
sendEncodings: [
{ rid: "h", maxBitrate: 1200 * 1024},
{ rid: "m", scaleResolutionDownBy: 2, maxBitrate: 600 * 1024},
{ rid: "h", maxBitrate: 1200 * 1024 },
{ rid: "m", scaleResolutionDownBy: 2, maxBitrate: 600 * 1024 },
{ rid: "l", scaleResolutionDownBy: 4, maxBitrate: 300 * 1024 },
],
});
Expand All @@ -162,4 +167,4 @@ You can also configure PeerConnection to use a specific port range by doing

Otherwise, the connection won't be established at all, or just in one direction.

Read more in our [Deploying tutorial](./deploying.md#allow-udp-traffic-in-your-firewall)!
Read more in our [Deploying tutorial](./bare.md#allow-udp-traffic-in-your-firewall)!
14 changes: 4 additions & 10 deletions guides/advanced/deploying.md → guides/deploying/bare.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Deploying
# Deploying on bare machines

Deploying WebRTC applications can be cumbersome.
Here are a few details you should keep in mind when trying to push your project into production.
Here are a few details you should keep in mind when trying to push your project into production on a bare machine.

## Allow UDP traffic in your firewall

Expand Down Expand Up @@ -37,12 +37,6 @@ docker run -p 50000-50010/udp myapp
Keep in mind that exporting a lot of ports might take a lot of time or even cause the Docker daemon to timeout.
That's why we recommend using host's network.

## Choose your cloud provider wisely

Many cloud providers do not offer good support for UDP traffic.
In such cases, deploying a WebRTC-based application might be impossible.
We recommend using bare machines that you can configure as you need.

## Enable HTTPS in your frontend

The server hosting your frontend site must have HTTPS enabled.
Expand All @@ -66,7 +60,7 @@ Read more [here](https://nginx.org/en/docs/http/websocket.html).

## Configure STUN servers

If you are deploying your application behind a NAT, you have to configure a STUN
If you are deploying your application behind a NAT, you have to configure a STUN
server that will allow it to discover its public IP address.
In Elixir WebRTC this will be:

Expand All @@ -86,6 +80,6 @@ And as a TURN server, you can always use our [Rel](https://github.com/elixir-web

If your application is deployed behind a very restrictive NAT, which should be very rare (e.g. a symmetric NAT),
you will need to configure a TURN server.
In most cases, TURN servers are needed on the client side as you don't have any control
In most cases, TURN servers are needed on the client side as you don't have any control
over a network your clients connect from.
For testing and experimental purposes, you can use our publicly available TURN called [Rel](https://github.com/elixir-webrtc/rel)!
50 changes: 50 additions & 0 deletions guides/deploying/fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Deploying on Fly.io

Elixir WebRTC-based apps can be easily deployed on [Fly.io](https://fly.io)!

There are just two things you need to do:

- configure a STUN server both on the client and server side
- use custom Fly.io IP filter on the server side

In theory, configuring a STUN server just on a one side should be enough but we recommend to do it on both sides.

In JavaScript code:

```js
pc = new RTCPeerConnection({
iceServers: [{ urls: "stun:stun.l.google.com:19302" }],
});
```

in Elixir code:

```elixir
ip_filter = Application.get_env(:your_app, :ice_ip_filter)

{:ok, pc} =
PeerConnection.start_link(
ice_ip_filter: ip_filter,
ice_servers: [%{urls: "stun:stun.l.google.com:19302"}]
)
```

in `runtime.exs`:

```elixir
if System.get_env("FLY_IO") do
config :your_app, ice_ip_filter: &ExWebRTC.ICE.FlyIpFilter.ip_filter/1
end
```

in fly.toml:

```toml
[env]
# add one additional env
FLY_IO = 'true'
```

That's it!
No special UDP port exports or dedicated IP address needed.
Just run `fly launch` and enjoy your deployment :)
22 changes: 22 additions & 0 deletions lib/ex_webrtc/ice/fly_ip_filter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule ExWebRTC.ICE.FlyIpFilter do
@moduledoc """
ICE IP filter for Fly.io deployments.
This module defines a single function, which filters out IP addresses,
which ICE Agent will use as its host candidates.
"""

@spec ip_filter(:inet.ip_address()) :: boolean()
def ip_filter(ip_address) do
case :inet.gethostbyname(~c"fly-global-services") do
# Assume that fly-global-services has to resolve
# to a single ipv4 address.
# In other case, don't even try to connect.
{:ok, {:hostent, _, _, :inet, 4, [addr]}} ->
addr == ip_address

_ ->
false
end
end
end
3 changes: 2 additions & 1 deletion lib/ex_webrtc/peer_connection/configuration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ defmodule ExWebRTC.PeerConnection.Configuration do

require Logger

alias ExICE.ICEAgent
alias ExWebRTC.{RTPCodecParameters, SDPUtils}
alias ExSDP.Attribute.{Extmap, FMTP, RTCPFeedback}

Expand Down Expand Up @@ -148,7 +149,7 @@ defmodule ExWebRTC.PeerConnection.Configuration do
controlling_process: Process.dest(),
ice_servers: [ice_server()],
ice_transport_policy: :relay | :all,
ice_ip_filter: (:inet.ip_address() -> boolean()),
ice_ip_filter: ICEAgent.ip_filter(),
ice_port_range: Enumerable.t(non_neg_integer()),
audio_codecs: [RTPCodecParameters.t()],
video_codecs: [RTPCodecParameters.t()],
Expand Down
12 changes: 8 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ defmodule ExWebRTC.MixProject do
defp deps do
[
{:ex_sdp, "~> 1.0"},
{:ex_ice, "~> 0.8.0"},
# {:ex_ice, "~> 0.8.0"},
{:ex_ice, github: "elixir-webrtc/ex_ice", override: true},
{:ex_dtls, "~> 0.16.0"},
{:ex_libsrtp, "~> 0.7.1"},
{:ex_rtp, "~> 0.4.0"},
Expand All @@ -80,25 +81,28 @@ defmodule ExWebRTC.MixProject do
"simulcast",
"modifying",
"mastering_transceivers",
"deploying",
"debugging"
]

deploying_guides = ["bare", "fly"]

[
main: "readme",
logo: "logo.svg",
extras:
["README.md"] ++
Enum.map(intro_guides, &"guides/introduction/#{&1}.md") ++
Enum.map(advanced_guides, &"guides/advanced/#{&1}.md"),
Enum.map(advanced_guides, &"guides/advanced/#{&1}.md") ++
Enum.map(deploying_guides, &"guides/deploying/#{&1}.md"),
assets: "guides/assets",
source_ref: "v#{@version}",
formatters: ["html"],
before_closing_body_tag: &before_closing_body_tag/1,
nest_modules_by_prefix: [ExWebRTC],
groups_for_extras: [
Introduction: Path.wildcard("guides/introduction/*.md"),
Advanced: Path.wildcard("guides/advanced/*.md")
Advanced: Path.wildcard("guides/advanced/*.md"),
Deploying: Path.wildcard("guides/deploying/*.md")
],
groups_for_modules: [
MEDIA: ~r"ExWebRTC\.Media\..*",
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"},
"ex_doc": {:hex, :ex_doc, "0.31.2", "8b06d0a5ac69e1a54df35519c951f1f44a7b7ca9a5bb7a260cd8a174d6322ece", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.1", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "317346c14febaba9ca40fd97b5b5919f7751fb85d399cc8e7e8872049f37e0af"},
"ex_dtls": {:hex, :ex_dtls, "0.16.0", "3ae38025ccc77f6db573e2e391602fa9bbc02253c137d8d2d59469a66cbe806b", [:mix], [{:bundlex, "~> 1.5.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:unifex, "~> 1.0", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "2a4e30d74c6ddf95cc5b796423293c06a0da295454c3823819808ff031b4b361"},
"ex_ice": {:hex, :ex_ice, "0.8.0", "f9bd181e8fd2f8ac9a808587ee8a47bf667143069d75f6e4892a62156d798aa7", [:mix], [{:elixir_uuid, "~> 1.0", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:ex_stun, "~> 0.2.0", [hex: :ex_stun, repo: "hexpm", optional: false]}, {:ex_turn, "~> 0.1.0", [hex: :ex_turn, repo: "hexpm", optional: false]}], "hexpm", "b0476f6b18986f6df48fda4cecb3be5022323572790d1bb49da10b177c936b4e"},
"ex_ice": {:git, "https://github.com/elixir-webrtc/ex_ice.git", "4c5190687e11b28a8209f2c930895647d0b2a64c", []},
"ex_libsrtp": {:hex, :ex_libsrtp, "0.7.2", "211bd89c08026943ce71f3e2c0231795b99cee748808ed3ae7b97cd8d2450b6b", [:mix], [{:bunch, "~> 1.6", [hex: :bunch, repo: "hexpm", optional: false]}, {:bundlex, "~> 1.3", [hex: :bundlex, repo: "hexpm", optional: false]}, {:membrane_precompiled_dependency_provider, "~> 0.1.0", [hex: :membrane_precompiled_dependency_provider, repo: "hexpm", optional: false]}, {:unifex, "~> 1.1", [hex: :unifex, repo: "hexpm", optional: false]}], "hexpm", "2e20645d0d739a4ecdcf8d4810a0c198120c8a2f617f2b75b2e2e704d59f492a"},
"ex_rtcp": {:hex, :ex_rtcp, "0.4.0", "f9e515462a9581798ff6413583a25174cfd2101c94a2ebee871cca7639886f0a", [:mix], [], "hexpm", "28956602cf210d692fcdaf3f60ca49681634e1deb28ace41246aee61ee22dc3b"},
"ex_rtp": {:hex, :ex_rtp, "0.4.0", "1f1b5c1440a904706011e3afbb41741f5da309ce251cb986690ce9fd82636658", [:mix], [], "hexpm", "0f72d80d5953a62057270040f0f1ee6f955c08eeae82ac659c038001d7d5a790"},
Expand Down

0 comments on commit 2e4979c

Please sign in to comment.