Phoenix and Fly.io and Websocket over TLS: WSS

This feels like a newbie question and I can find hints of things but getting fly.toml and phoenix runtime config into magic right combination has totall elluded me.

I want to use Secure Websockets. wss: The current (March 2022) phoenix example config for fly.io which is both in the phoenix doc and the maps the API to an internal port which if your try use with wss://site fails because of Cross Site protection.
I have HTTPS for a custom domain working for normal API calls and Serving the HTML but the WSS fails dismally in my many attempts.

The phoenix site is documented here:
https://hexdocs.pm/phoenix/using_ssl.html
There is a document on fly.io that mentions wss but it is for node and does not seem to be for wss.
WebSockets and Fly · Fly

Has anyone managed to make fly.io work for WSS or have a nice example they can point out to me.
Thanks,
Ric

Can you explain a little more what you have tried and what isn’t working? Are you using a custom domain? Fly is going to be terminating SSL for you, so you shouldn’t need to do much on the Phoenix configuration side. Your app.js out-of-the-box inherits the client’s protocol, so will work via ws or wss. Phoenix enable same origin in prod by default (check_origin: true), which means your websocket host must match the host configured in your endpoint’s :url. You can instead have it match the connection host by using check_origin: :conn, which is useful when paired with x-forwarded options for your custom domain(s):

config :my_app, MyAppWeb.Endpoint, 
  ...,
  check_origin: :conn,
  force_ssl: [rewrite_on: [:x_forwarded_proto], host: nil]
2 Likes

Thanks Chris for suggestion Chris. Its pretty epic to get help from you.

Check Origin did not like :conn.

[info] ** (ArgumentError) :check_origin expects a boolean, list of hosts, or MFA tuple, got: :conn

the relevant part of the config for phoenix currently is:

config :learnapi, LearnapiWeb.Endpoint,
server: true,
url: [host: “#{app_name}.fly.dev”, port: 80],
http: [
port: String.to_integer(System.get_env(“PORT”) || “4000”),
# IMPORTANT: support IPv6 addresses
transport_options: [socket_opts: [:inet6]],
],
# check_origin: :conn,
force_ssl: [rewrite_on: [:x_forwarded_proto], host: nil],
secret_key_base: secret_key_base

the relavent part of the fly.toml is:

[[services]]
internal_port = 4000
protocol = “tcp”
[services.concurrency]
hard_limit = 25
soft_limit = 20
[[services.ports]]
handlers = [“http”]
port = 80
[[services.ports]]
handlers = [“tls”, “http”]
port = 443
[[services.tcp_checks]]
grace_period = “30s” # allow some time for startup
interval = “15s”
restart_limit = 6
timeout = “2s”

This results in the error:

2022-03-01T21:32:47Z app[2f88901b] syd [info]21:32:47.459 [error] Could not check origin for Phoenix.Socket transport.
2022-03-01T21:32:47Z app[2f88901b] syd [info]Origin of the request: https://tick.tools
2022-03-01T21:32:47Z app[2f88901b] syd [info]This happens when you are attempting a socket connection to
2022-03-01T21:32:47Z app[2f88901b] syd [info]a different host than the one configured in your config/
2022-03-01T21:32:47Z app[2f88901b] syd [info]files. For example, in development the host is configured
2022-03-01T21:32:47Z app[2f88901b] syd [info]to “localhost” but you may be trying to access it from
2022-03-01T21:32:47Z app[2f88901b] syd [info]“127.0.0.1”. To fix this issue, you may either:
2022-03-01T21:32:47Z app[2f88901b] syd [info] 1. update [url: [host: …]] to your actual host in the
2022-03-01T21:32:47Z app[2f88901b] syd [info] config file for your current environment (recommended)
2022-03-01T21:32:47Z app[2f88901b] syd [info] 2. pass the :check_origin option when configuring your
2022-03-01T21:32:47Z app[2f88901b] syd [info] endpoint or when configuring the transport in your
2022-03-01T21:32:47Z app[2f88901b] syd [info] UserSocket module, explicitly outlining which origins
2022-03-01T21:32:47Z app[2f88901b] syd [info] are allowed:
2022-03-01T21:32:47Z app[2f88901b] syd [info] check_origin: [“https://example.com”,
2022-03-01T21:32:47Z app[2f88901b] syd [info] “//another.com:888”, “//other.com”]

And I made the obvious change suggested by the error and it worked. For those who come after me the key change is to make Phoenix check origin point to your site.

config :learnapi, LearnapiWeb.Endpoint,
server: true,
url: [host: “#{app_name}.fly.dev”, port: 80],
http: [
port: String.to_integer(System.get_env(“PORT”) || “4000”),
# IMPORTANT: support IPv6 addresses
transport_options: [socket_opts: [:inet6]],
],
check_origin: [“https://tick.tools”],
force_ssl: [rewrite_on: [:x_forwarded_proto], host: nil],
secret_key_base: secret_key_base

2 Likes