WebSocket (WSS) Connection Issues with Phoenix LiveView on Clever Cloud, Works Fine on HTTP

Hello everyone,

I’m facing an issue with establishing WebSocket (wss://) connections for Phoenix LiveView in a deployed application on Clever Cloud. The application works perfectly in HTTP, but as soon as I switch to HTTPS (which Clever Cloud handles with Let’s Encrypt), the WebSocket connection fails.

Environment:

  • Elixir version: 1.14
  • Phoenix version: 1.7.10
  • Phoenix LiveView version: 1.0
  • Clever Cloud: Hosting the application
  • LiveView version: 0.18.18
  • WebSocket protocol: WSS
  • Frontend: JavaScript (Phoenix LiveSocket)
  • Backend: Phoenix framework with LiveView and PubSub

Steps Taken:

  1. I’ve configured Phoenix to handle both HTTP and WebSocket connections using the correct URL and port configurations.
  2. The application works perfectly over HTTP (i.e., it uses ws:// for WebSockets), but as soon as I enable HTTPS on Clever Cloud (which uses Let’s Encrypt), the WebSocket connection switches to wss://, and it fails to connect.
  3. I’ve already checked that the domain and DNS configuration on Clever Cloud are correct. The application is accessible via https://www.felicien.cool and the certificate is valid.

Problem:

  • The WebSocket (wss://) connection repeatedly fails to connect.
  • I can see that the connection is being established in the server logs (Phoenix is logging “CONNECTED TO Phoenix.LiveView.Socket”).
  • On the frontend, I see an error in the browser’s developer console that says WebSocket connection to 'wss://www.felicien.cool/live/websocket' failed.
  • The app works as expected over HTTP (i.e., using ws:// for WebSocket).

Current Configuration:

config.exs:

elixir

Copy

config :wordly, WordlyWeb.Endpoint,
  # Port 80 pour HTTP
  url: [host: "www.felicien.cool", port: 443],
  render_errors: [
    formats: [html: WordlyWeb.ErrorHTML, json: WordlyWeb.ErrorJSON],
    layout: false
  ],
  pubsub_server: Wordly.PubSub,
  check_origin: ["https://felicien.cool", "https://www.felicien.cool"],
  live_view: [signing_salt: "xxxx"]

runtime.exs:

 host = System.get_env("PHX_HOST") || "www.felicien.cool"
  port = String.to_integer(System.get_env("PORT") || "4000")

  config :wordly, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")

  config :wordly, WordlyWeb.Endpoint,
    url: [host: host, port: 443, scheme: "https"],
    http: [
      # Enable IPv6 and bind on all interfaces.
      # Set it to  {0, 0, 0, 0, 0, 0, 0, 1} for local network only access.
      # See the documentation on https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html
      # for details about using IPv6 vs IPv4 and loopback vs public addresses.
      ip: {0, 0, 0, 0, 0, 0, 0, 0},
      port: port
    ],
    secret_key_base: secret_key_base

JavaScript (LiveSocket):

js

import { Socket } from "phoenix";
import { LiveSocket } from "phoenix_live_view";
import topbar from "../vendor/topbar";

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content");
let liveSocket = new LiveSocket("/live", Socket, { params: { _csrf_token: csrfToken } });

topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" });
window.addEventListener("phx:page-loading-start", () => topbar.show(300));
window.addEventListener("phx:page-loading-stop", () => topbar.hide());

liveSocket.connect();
window.liveSocket = liveSocket;

Troubleshooting Done:

  1. Verified that the WebSocket URL (wss://www.felicien.cool/live/websocket) is correct and accessible.
  2. Ensured the certificate is valid and the domain is correctly configured for SSL in Clever Cloud.
  3. Checked browser logs and network activity, where I see that the connection to the WebSocket URL fails.
  4. Confirmed that the issue only happens when switching to HTTPS; everything works in HTTP.

Questions:

  • Could there be a misconfiguration on my end that’s causing the WebSocket connection to fail when using wss://?
  • Is there anything specific in Clever Cloud’s configuration that I may need to check for WebSocket connections (like reverse proxy settings)?
  • Should I disable the https: configuration in Phoenix and let Clever Cloud handle everything, or is there a specific setting I need to adjust?
  • Could this be related to Clever Cloud’s load balancer, and if so, how can I ensure WebSocket connections are passed through correctly?

Any advice or insights on how to resolve this would be greatly appreciated!

Thank you in advance!