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 25cb4fe
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 17 deletions.
2 changes: 1 addition & 1 deletion guides/advanced/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,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](../deploying/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
11 changes: 7 additions & 4 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ defmodule ExWebRTC.MixProject do
defp deps do
[
{:ex_sdp, "~> 1.0"},
{:ex_ice, "~> 0.8.0"},
{:ex_ice, github: "elixir-webrtc/ex_ice"},
{:ex_dtls, "~> 0.16.0"},
{:ex_libsrtp, "~> 0.7.1"},
{:ex_rtp, "~> 0.4.0"},
Expand All @@ -80,25 +80,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 25cb4fe

Please sign in to comment.