Problem Description
I wrote a simple game server in Phoenix that uses Channels to network positions of the players. The client is a JavaScript app—written in Node and bundled with WebPack—and it uses Phoenix.js to connect to the server.
Using Docker, the server was deployed to an EC2 instance. I made sure to use 0.0.0.0
as the IP, and in Docker, published the port 4000:
docker run -dp 4000:4000 --env-file .env phoenix-backend
When I make a GET request to the server, I get a 404 response—which makes sense, because I’ve removed all but Channels from the app. If I view the Docker logs, I can see it received the request and responded with a 404.
However, I cannot connect over WebSocket. The logs don’t even register that an attempt was made.
check_origin
is disabled and the EC2 instance is configured to receive all traffic from everywhere.
What Has Been Tried
I wanted to test connecting locally, but I wasn’t able to figure out how to run Phoenix.js on the EC2 instance. It doesn’t have a browser, and when I tried in Node, I got the following error:
/home/ec2-user/phoenix-client-test/node_modules/phoenix/priv/static/phoenix.cjs.js:764
this.transport = opts.transport || global.WebSocket || LongPoll;
^
TypeError: Cannot read properties of undefined (reading 'WebSocket')
at new Socket (/home/ec2-user/phoenix-client-test/node_modules/phoenix/priv/static/phoenix.cjs.js:764:47)
at Object.<anonymous> (/home/ec2-user/phoenix-client-test/index.js:3:16)
at Module._compile (node:internal/modules/cjs/loader:1099:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47
The code itself:
const phoenix = require("phoenix");
const socket = new phoenix.Socket("ws://localhost:4000/socket", {});
socket.connect();
This leads me to believe Phoenix.js cannot be run from a server. If so, I’m all out of ideas. I don’t even know what to test anymore.
The config/
code
prod.exs
import Config
config :al_jeem_backend, AlJeemBackendWeb.Endpoint,
http: [ip: {0, 0, 0, 0}, port: 4000],
url: [host: "localhost", port: 4000],
check_origin: false
config :logger, level: :info
I have tried, here and everywhere else, to change host
from localhost
to the instance’s public IPv4 DNS. The results stayed exactly the same.
config.exs
import Config
config :al_jeem_backend, AlJeemBackendWeb.Endpoint,
url: [host: "localhost"],
render_errors: [view: AlJeemBackendWeb.ErrorView, accepts: ~w(json), layout: false],
pubsub_server: AlJeemBackend.PubSub,
live_view: [signing_salt: "dunno if this is sensitive info, so I removed it"]
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
runtime.exs
import Config
# Start the phoenix server if environment is set and running in a release
if System.get_env("PHX_SERVER") && System.get_env("RELEASE_NAME") do
config :al_jeem_backend, AlJeemBackendWeb.Endpoint, server: true
end
if config_env() == :prod do
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise """
environment variable SECRET_KEY_BASE is missing.
You can generate one by calling: mix phx.gen.secret
"""
host = System.get_env("PHX_HOST") || "localhost"
port = String.to_integer(System.get_env("PORT") || "4000")
config :al_jeem_backend, AlJeemBackendWeb.Endpoint,
url: [host: host, port: port],
http: [
ip: {0, 0, 0, 0, 0, 0, 0, 0},
port: port
],
secret_key_base: secret_key_base
end