đź”’ Users broke your WebSockets

Launch was perfect until someone bookmarked the staging domain. Redirects fix what check_origin can’t.

Welcome to GigaElixir Gazette, your 5-minute digest of Elixir ecosystem news that actually matters đź‘‹.

. WEEKLY PICKS .

📊 State of Elixir 2025 Survey Results Released: Survey of 1,018 participants reveals 84% report improved productivity versus other languages, 71% ship faster, 67% see competitive advantage. Claude dominates AI coding at 84% adoption versus OpenAI's 32%. Top pain points: hiring difficulty and LSP instability. Community skews senior (median 13.5 years experience) working in small efficient teams. Elixir attracts veterans choosing deliberately, not juniors learning first language.

🚀 BullMQ Queue Library Launches for Elixir: Popular NodeJS Redis-based queue system now available for Elixir with identical Lua scripts enabling complete interoperability. Polyglot teams can share queue infrastructure between NodeJS and Elixir workers processing same queues. GenServer architecture provides BEAM concurrency advantages NodeJS version lacks while maintaining compatibility. Teams running mixed stacks get queue interoperability without reimplementing infrastructure while Elixir services benefit from superior process model. Job priorities, retries, rate limiting work identically across both runtimes.

🎓 Reddit Reveals Learning Elixir Path: Skip Ash, Master Phoenix First: Beginner attempts learning Elixir by jumping straight into Phoenix with Ash Framework hits wall of confusion and implicit magic. Community consensus: terrible approach for newcomers. Ash's DSL-heavy abstractions hide essential Elixir and Phoenix mechanics beginners need to understand. Recommended path: learn core Elixir first, build vanilla Phoenix apps, add LiveView, then consider Ash only when you understand what problems it solves. Multiple experienced developers confirm they needed several Phoenix projects before Ash benefits became clear versus feeling like magic.

🛡️ Server-Side Request Forgery Attacks Target Webhook Systems: Security tutorial demonstrates how SSRF vulnerabilities in webhook delivery systems let attackers access internal networks. Webhook debugging features showing response bodies become attack vectors when users control destination URLs. Attackers register internal IPs (10.x, 192.168.x) or cloud metadata endpoints (169.254.169.254) to extract credentials and private data. DNS rebinding attacks bypass initial validation by changing resolution between check and request. Solutions include SafeURL library for Elixir, dedicated proxy services like Smokescreen, and network segmentation with authentication for internal services.

đź’¬ GenServer State in Kubernetes Sparks Architecture Debate: Developer asks how to handle stateful GenServers when containers terminate unpredictably. Three camps emerge: externalize to Redis/Postgres, use ETS warm-up strategies, or embrace "let it crash" accepting state loss. Consensus: stateful GenServers should represent short-lived actions (game match, workflow) not long-lived identity. BEAM's "let it crash" philosophy versus orchestration's "terminate at will" creates tension some teams never resolve.

Your WebSockets Worked Until Users Bookmarked The Wrong Domain

Launch day: flawless. Two weeks later: logs exploded with Phoenix.Socket check_origin errors. Nothing broke in the deploy. Someone just bookmarked the staging domain.

Before launch, production lived on a temporary domain—hosting provider URL or custom staging address. Team updated DNS, configured the new domain in config/prod.exs, tested thoroughly. Ship it. Victory. A user who bookmarked the site during testing visits from that old domain. Their LiveView is completely broken. Phoenix rejects the WebSocket handshake because the origin header doesn't match the configured endpoint host.

The security mechanism doing its job becomes an operational problem. Phoenix checks the Origin header on WebSocket handshakes to prevent Cross-Site WebSocket Hijacking (CSWSH). An attacker could use client-side code on their own site to get your user's browser to create an authenticated WebSocket connection to your server and carry out operations without consent. When the origin matches your configured domain, Phoenix accepts the connection. When it doesn't match—like when someone visits from an old bookmark—Phoenix floods your logs with check_origin errors and kills their session.

Most teams add old domains to check_origin configuration, legitimizing wrong URLs forever. Smart teams redirect at the browser pipeline, forcing canonical domains before WebSocket handshakes happen. The error message suggests updating url: [host: ...] in config or adding specific origins to check_origin. Your config is already correct for the new domain. Adding the old domain to check_origin just makes the wrong URL permanent. Neither fixes the actual problem: visitors are using the wrong domain entirely.

Jason Pollentier at Revelry built a redirect plug that checks incoming requests against the configured endpoint host and redirects mismatches before they hit your application logic:

elixir

defmodule MyAppWeb.DomainRedirect do
  import Plug.Conn
  alias Phoenix.Controller
  alias MyAppWeb.Endpoint

  @default_opts %{active: Mix.env() == :prod}

  def init(opts), do: Map.merge(@default_opts, Map.new(opts))

  def call(%{method: "GET"} = conn, %{active: true}) do
    req_host = conn.host
    %{host: endpoint_host} = Endpoint.struct_url()

    if req_host == endpoint_host do
      conn
    else
      redirect_url = Endpoint.url() <> path(conn)
      conn |> Controller.redirect(external: redirect_url) |> halt()
    end
  end

  def call(conn, _), do: conn

  defp path(%{request_path: path, query_string: ""}), do: path
  defp path(%{request_path: path, query_string: query}), do: "#{path}?#{query}"
end

Add it to your browser pipeline and the redirect happens before LiveView mounts—origin never mismatches. Visitors get transparently redirected to the correct domain. Their WebSocket connections work because the origin now matches. Your logs stay clean. No more explaining to product managers why error counts spiked when nothing actually broke.

Multi-tenant apps with subdomains per customer need similar logic. Separate client-side applications connecting to Phoenix need more sophisticated origin validation. But for most teams deploying standard Phoenix apps, this simple redirect solves the recurring check_origin pain that hits every agency after every launch.

Remember, for production WebSocket stability:

  1. Redirect beats allowlist expansion – Adding old domains to check_origin legitimizes wrong URLs forever; redirecting forces correct domain usage from the start

  2. Deploy redirects at launch, not after – Catch staging URLs and hosting provider domains before users bookmark them during pre-launch testing

  3. Browser pipeline blocks before WebSocket attempts – Redirect happens before LiveView mounts, so origin header never mismatches in the first place

  4. Security doing its job looks like errors – check_origin protecting against CSWSH attacks floods logs when users visit from bookmarked staging URLs

. TIRED OF DEVOPS HEADACHES? .

Deploy your next Elixir app hassle-free with Gigalixir and focus more on coding, less on ops.

We're specifically designed to support all the features that make Elixir special, so you can keep building amazing things without becoming a DevOps expert.

See you next week,

Michael

P.S. Forward this to a friend who loves Elixir as much as you do đź’ś