1

Note** I was able to get things operational by taking cloudfront out of the picture for the server.com domain by just using route-53 and the elastic beanstalk environment. Still would be great to know why cloudfront was blocking this, but not an immediate concern for development **

I am serving a node.js static socket.io client form an s3 bucket using cloudfront and route 53. I am attempting to get this client to talk to a node.js web server using elastic beanstalk. The webserver is connected with amazon certificate manager generated ssl using a route 53 domain and cloudfront.

using an http client and directly connecting to the beanstalk environment I am seeing desired functionality. However, when I try to move to SSL/https with the client and server I am receiving:

(log from /var/log/nginx/error.log on elastic beanstalk instance)

"GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon CloudFront"

here is the client code that is running from the static s3 https domain:

import ioClient from "socket.io-client";

const ENDPOINT = "https://server.com";
export const socket = ioClient(ENDPOINT);

here is the server side. process.env.port is set to 8080, and I can verify the app is listening on 8080 through elastic beanstalk logs.

const express = require("express");
const http = require("http");
const socket_io = require("socket.io");

const index = require("./routes/index");
const app = express();
app.use(index);

const server = http.createServer(app);
const io = socket_io(server);

const port = process.env.port || 4001;
server.listen(port, () => console.log(`http server listing on port ${port}`));

Inside the ALB I have an https listener set up on port 443 with Amazon Certificate Manager (ACM) ssl certification. The listener has a process that maps the 443 https to 8080 on http, from where I think ngnix should be acting as a reverse proxy to my socket.io listener on 8080

Listeners & Processors

443 being forwarded to 8080

https ACM SSL

In the root of my node project folder I have a .ebextensions directory and inside that a file named 01_files.config with these contents:

files:
    "/etc/nginx/conf.d/websocketupgrade.conf" :
        mode: "000755"
        owner: root
        group: root
        content: |
             proxy_pass http://localhost:8080;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection "upgrade";
             proxy_http_version 1.1;
             proxy_set_header Host $host;

From the comments in this post : socket.io handshake return error "Transport unknown" I found the following socket.io error codes

engine.io message type:

open =0
close =1
ping =2
pong =3
message =4
upgrade =5
noop =6
socket.io message type:

connect = 0
disconnect = 1
event = 2
ack = 3
error = 4
binary_event = 5
binary_ack = 6

so, 400 51 could possibly mean "Bad request, upgrade-disconnect."

Here is the response body : {"code":0,"message":"Transport unknown"}

And here is the error on the client app in browser:

polling-xhr.js:268 GET https://server.com/socket.io/?EIO=3&transport=polling&t=NIgQkyr 400

which looks like a failed polling request on the xhr transport layer

Lucas Moskun
  • 172
  • 1
  • 13

1 Answers1

0

Received this solution from AWS support:

I have discussed your case with a CloudFront (CF) expert and I have some information for you.

After going through the CF setup with my colleague, we noticed that CF is not forwarding the HOST header to Elastic Beanstalk (EB). This means if the connection between CF and EB is established over HTTPS, it will fail. To fix this, we had to take a look at the CF policies. We noticed that you are making use of Cache Policies. In this policy there is a setting for Headers. Here I would recommend that you specify the HOST setting. This way, it secures the HTTPS connection against the Origins certificated.

If that does not work, there is something else I could suggest. The error you were seeing (GET /socket.io/ HTTP/1.1" 400 51 "-" "Amazon CloudFront" "(redacted IP, redacted IP") should have returned an "X-Amz-Cf-Id" ID along with a value (something like "X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd=="). Since it did not, I suspect something may have gone wrong with the websocket request parameters. For this I would recommend taking a look at our documentation and ensure that the correct request parameters required for CloudFront are being used. You can find a link to that documentation here: [1].

If all else fails, I would recommend making a request to your CF and record the key-value pair that is returned in the response header from CF. It should look something like "X-Amz-Cf-Id: jkahDAKJSHDAjhAKSJDHasd==" (the same ID and value I mentioned earlier). This value allows us as support engineers to pull the internal logs for CF using our tooling. This value will need to be recorded at the time of the request. Once you have this key-value pair, you can then open a support ticket with the CloudFront team, provide them with the error details as well as the key-value pair, and a CF engineer would be more than happy to assist you. Additionally, you could even reference this case (case ID = 7399701121) on the new case so that the engineer assisting you can have some more context.

To sum up, my first recommendation is that you forward the host header. Second is to use the request parameters required for CloudFront. And last, if you encounter another error after that, record the value from the HTTP response given by CloudFront for the error. Since I am not a CloudFront expert, I would suggest opening a new CloudFront case and providing that key-value pair in the message.

I hope you find this information useful. If you have any more questions or concerns, please feel free to reach out.

Lucas Moskun
  • 172
  • 1
  • 13
  • Hi Lucas, we are having a similar issue. we have our socket io in ec2 machine and s3 has our app which is trying to establish a connection. could you have a look here https://stackoverflow.com/questions/66205150/trying-to-connect-to-socket-io-punning-on-node-on-ec2-machine-from-react-app-hos – sumanth shetty Feb 15 '21 at 10:12