I have a similar situation with a websocket.
WebSocket connection to 'wss://xxxx.zzz/socket.io/?EIO=4&transport=websocket' failed: Error during WebSocket handshake: 'Upgrade' header is missing
The project is based on the NuxtJS framework. The server is running on express.js
Nginx Conf
location / {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Connection "Upgrade";
proxy_set_header Upgrade $http_upgrade;
location ~* ^.+\.(jpeg|jpg|png|webp|gif|bmp|ico|svg|css|js)$ {
expires max;
fastcgi_hide_header "Set-Cookie";
}
}
The process on the server
const http = require("http").createServer(app);
let io = require("socket.io")(http, {
cors: { origin: "*" },
});
nuxt.config.js
io: {
// module options
sockets: [{
name: "home",
url: "https://xxxx.zzz/",
},],
},
I tried all the processes in Stackowerflow to no avail. The server is running via SSL.
Related
I am having the issue with my websocket. It works well locally on my computer, but when I run with my nginx server on chrome, I get the error
Do i have to configure my nodejs server with my ssl key? Here's what I have so far:
const app = express()
const httpServer = http.createServer(app)
const io = require('socket.io')(httpServer, {
cors: {
origin: '*',
methods: ['GET, POST'],
credentials: true,
allowedHeaders: ['custom-header'],
},
})
I got my ssl from godaddy, and it contains 3 files. How can i do this?
NGINX SERVER
server {
listen 80;
server_name mydomain + .com;
rewrite ^/(.*) https://mydomain + .com/$1 permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name mydomain + .com;
ssl_certificate /home/chained.crt;
ssl_certificate_key /home/mykey.key;
// React Setup
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
// NODEJS SETUP
location /api {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
// SOCKET.IO SETUP
location /socket.io/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy false;
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
This is where I set up the REACT SOCKET.IO CODE
useEffect(() => {
if (!socket.current) {
socket.current = io(process.env.REACT_APP_API)
console.log('SOCKET', socket.current)
}
if (socket.current) {
socket.current.emit('join', { userId: user._id })
socket.current.on('connectedUsers', ({ users }) => {
users.length > 0 &&
dispatch({
type: 'SET_CONNECTED_USERS',
payload: users,
})
// users.length > 0 && setConnectedUsers(users)
})
}
When I run my application on chrome, I get the error. Websocket doesn't work, but it works locally.
this is my nginx server setup. I have 2 server instances. I don't know if that is the problem. Anyone knows the best way to fix this??
server {
listen 80;
server_name mydomain + .com;
rewrite ^/(.*) https://mydomain + .com/$1 permanent;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name mydomain + .com;
ssl_certificate /home/chained.crt;
ssl_certificate_key /home/mykey.key;
// Frontend Setup
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
// API SETUP
location /api {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
// SOCKET.IO SETUP
location /socket.io/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy false;
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
this is my nodejs setup for backend.
const app = express()
const httpServer = https.createServer({}, app)
const io = require('socket.io')(httpServer, {
cors: {
origin: '*',
methods: ['GET, POST'],
credentials: true,
allowedHeaders: ['custom-header'],
},
})
httpServer.listen(port, () => {
console.log(`Server running on port ${port}`)
})
MY react setup looks like this
useEffect(() => {
if (!socket.current) {
socket.current = io(process.env.REACT_APP_API_APP)
console.log('SOCKET', socket.current)
}
if (socket.current) {
socket.current.emit('join', { userId: user._id })
socket.current.on('connectedUsers', ({ users }) => {
users.length > 0 &&
dispatch({
type: 'SET_CONNECTED_USERS',
payload: users,
})
// users.length > 0 && setConnectedUsers(users)
})
}
My application works locally. but on nginx, It doesn't work. I just get the error as shown in the image.
I am new to servers. Any help would be appreciated.
I have MERN app, the api build with express and the client build with reactjs.
In my local computer (windows), the client can connect to socket server. The onConnection event is triggered.
1. Local Computer (Windows)
Client Side:
socket.on('connect', () => {
console.log('connected to the socket server');
}) // triggered and i can see the console.log in broser console
Server Side:
io.on('connection', () => {
console.log('client connected to the socket server');
}) // triggered and i can see the console.log in terminal
2. VPS (Ubuntu 20, Nginx)
When i deploy the server and the client to vps, the socket can't connect. on connection event not triggered.
But the client is trigger connect_error event:
socket.on("connect_error", (error) => {
console.log('socket connection error:', error.message) // socket connection error: server error
}); // this event is triggered
This is my code:
Server side:
const server = app.listen(3000)
const io = socketio(server)
Client side:
const socket = io("http://103.150.60.132/api")
NGINX Config:
server {
listen 80;
location / {
root /var/www/bacotin/client; //reactjs build location
index index.html index.htm;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://103.150.60.132:3000; // express api
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location ~* \.io {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy false;
proxy_pass http://localhost:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
UPDATE: the problem is solve, now the socket client can connect to the socket server.
Just modify the client code:
From this:
const socket = io("http://103.150.60.132/api")
To this:
const socket = io("http://103.150.60.132")
But why?
I have a small angular app who comunicate with a node.js server. Both are deployed on aws and I use Nginx reverse proxy to acess the node.js server at the port 4000.
All end-points of the nodejs.server works fine, except the socket.io connection.
When I run both apps (front end app and the node.js server) in my machinine the socket.io connection works fine, but when I try to deploy it on aws I get this error in the front-end app:
Error: server error
at Socket.onPacket (socket.js:401)
at XHR.<anonymous> (socket.js:216)
at XHR.push.dMso.Emitter.emit (index.js:145)
at XHR.onPacket (transport.js:103)
at callback (polling.js:101)
at Array.forEach (<anonymous>)
at XHR.onData (polling.js:105)
at Request.<anonymous> (polling-xhr.js:94)
at Request.push.dMso.Emitter.emit (index.js:145)
at Request.onData (polling-xhr.js:236)
This is my Nginx configuration in /etc/nginx/sites-available/default:
server{
charset utf-8;
listen 80 default_server;
server_name 18.231.153.164;
# angular app & front-end files
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
root /opt/front-end/dist/admin;
try_files $uri /index.html;
}
# node api reverse proxy
location /api/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:4000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# node api reverse proxy
location /socket.io {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://localhost:4000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
As you can see, my node.js is running at port 4000, so everytime someone try to access the web site with the path /api/ it will be redirected to the node.js server.
Here is a piece of my node.js code:
const socketio = require('socket.io');
const express = require('express');
const app = express();
const port = 4000;
const httpServer = app.listen(port, () => {
console.log('Server listening on port ' + port);
});
let io = socketio(httpServer, {
cors: {
origin: "http://localhost:5200",
},
});
// auth moddleware
io.use((socket, next, err) => {
const jwtToken = socket.handshake.query.jwtToken;
// console.log('token --> ', jwtToken);
const user = socket.handshake.query.user;
if (!user) {return};
socket.user = JSON.parse(user);
next();
});
io.on('connection', (socket) => {
socket.emit('messageFromServer', {data: 'Welcome to server'});
})
Here is a piece of my front-end code:
import {io} from 'socket.io-client';
...
// Connect to server (When I am running locally I change '/api' to 'http://localhost:4000'
this.socket = io('/api', {secure: true, reconnection: true, rejectUnauthorized: false, query: {user: user, jwtToken: this.authService.authValue.jwtToken}});
// Listen to events
this.socket.on('usersOnline', (usersOnline) => {
console.log('Users online now:', usersOnline);
});
this.socket.on('connect_error', (err) => {
console.log('ERR::', err);
});
The version of socket.io in the server is "^4.0.0", and the version of the socket.io-client in front and is "^4.0.0".
I believe this issue is related with the reverse proxy and socket.io somehow. As I told before, the socket.io connection works fine in local envoriment.
Can someone please help me?
I found the solution.
I need to add proxy_redirect off; on the socket.io reverse proxy.
location /socket.io {
proxy_pass http://localhost:4000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
Then I had another problem, in the font end I start to get an error or invalid namespace.
So I change the client connection to / instead od /api:
this.socket = io('/', {query: {user: user, jwtToken: this.authService.authValue.jwtToken}});
Just check and install same version of socket.io and socket.io-client
I have a node app that is running in a dockerized environment just fine. It runs all fine over HTTP and locally. Only when I use Nginx reverse proxy, the socket.emit doesn't return anything.
My Nginx config:
location /verification/ {
proxy_pass http://127.0.0.1:3005/;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
my socket connection (client):
const socket = io(
'https://mywebsite.com',
{ path: + '/verification/socket.io/',
secure: true,
rejectUnauthorized: false
}, fn)
My server config:
const io = socket(http, {path: '/socket.io/'});
Actually I've come to a solution with this. I've implemented the room scenario myself and it's been working well. For so, I just implemented the following:
const clients = {};
io.to('/verification/').connection(function(){
clients[socket.id] = {room: null, id: socket.id};
socket.on('message', function(payload){
if(payload.intent === 'join'){
clients[socket.id] = {...clients[socket.id], room: payload.room};
}
});
//and to broadcast messages:
Object.values(clients)
.map(client => {
socket.to(client.id).emit('message', 'foo message')
})
})