Websocket 403 response in production

Hi everyone

I’m having an issue with getting channels to work in production. I’m running an Nginx reverse proxy on an EC2 instance.

I get this error: Error during WebSocket handshake: Unexpected response code: 403. I’m not sure what the issue is.

I’ve tried many different things, both on here and on Stack Overflow, but nothing seems to work.

Thanks in advance!

Here is my nginx config (redirects omitted for brevity)

upstream my_site {
  server localhost:4000;
}

map $http_upgrade $connection_upgrade {
  default upgrade;
  '' close;
}

server {
  listen 443 ssl http2; 
  server_name mysite.co.uk;

  include snippets/ssl-mysite.co.uk.conf;
  include snippets/ssl-params.conf;
 
  location /.well-known {
    alias /home/ubuntu/certbot/.well-known;
  }

  location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_redirect off;
    proxy_pass http://my_site;
    proxy_set_header Host $host;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }

}

prod.ex

use Mix.Config

config :app, AppWeb.Endpoint,
  url: [host: "localhost", port: 80],
  cache_static_manifest: "priv/static/cache_manifest.json",

config :logger, level: :info
import_config "prod.secret.exs"

So this block seems to fix it, not sure why exactly, but something to do with the Origin. If anyone has any explanation or alternative solutions, I’d like to hear about them

location /socket {
    proxy_pass http://my_site;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header Origin '';
  }
1 Like

In production, Phoenix is checking your WebSocket origin so that the connections can only be opened from your own site and not others. Since you have configured the url host to be “localhost”, it will check that the origin is “localhost”, which most likely is not true. You should configure it with the correct domain. You should also set the port to be 443 instead of 80 in the url so that you’ll generate correct links in your application if you use the router helpers.

3 Likes

Great, thanks for the explanation @Nicd