Using socket.io with ejs on Express/Nginx - express

I'm working on a app with socket.io, ejs, express & nginx on a Node JS server.
I have managed to get the socket.io working withthout use of ejs.
But when I try to implement it with ejs I get error 400 on client.js.
Here is my code for server.js :
var express = require('express');
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var ejs = require('ejs');
// WITHOUT EJS : WORKS FINE
app.get('/', function(req, res) {
res.sendFile(index.html');
});
// WITH EJS : GET HTTP ERR 400 IN CLIENT.JS CONSOLE
app.set('view engine', 'ejs');
app.get('/', function(req, res) {
res.render('pages/index');
});
io.on('connection', function(socket) {
console.log('a user connected');
socket.on('chat message', function(msg){
console.log('message: ' + msg);
});
});
server.listen(process.env.PORT || 8080, function(){
console.log('app running');
});
My nginx code looks like this :
# HTTP — redirect all traffic to HTTPS
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS — proxy all requests to the Node app
server {
# Enable HTTP/2
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com;
# Use the Let’s Encrypt certificates
ssl_certificate /.../;
ssl_certificate_key /.../;
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://example.com:8080;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Here is my client.js :
var socket = io();
socket.on('news', function (data) {
console.log(data);
socket.emit('my other event', { my: 'data' });
});
What could be the issue here ?

Related

Nginx upstream to express server - 502 error

Heyo, I have a nginx server on digital ocean. I used to host on AWS with PM2 but tweaked this to run it with nginx.
The problem is that it seems I get a 502. Something just isn't configured right. Originally I had the client just being served and that worked but when i switched to the server doing it 502's as well.
The client and server folders are in the same parent directory.
Here is my current var/nginx/sites-available/default
# Main Content Delivery Block (SSL)
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name quakeviz.app;
ssl on;
ssl_certificate /etc/ssl/certs/mpaccione_ssl.crt;
ssl_certificate_key /etc/ssl/private/mpaccione_ssl.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Content-Security-Policy upgrade-insecure-requests;
location / {
root /var/www/html/usgs_viz/server;
proxy_pass https://quakeviz.app:8080/;
proxy_ssl_session_reuse on;
#try_files $uri $uri/ /;
}
#location /bufferLength {
# root /var/www/html/usgs_viz/server;
# proxy_pass https://quakeviz.app:8080/;
# proxy_ssl_session_reuse on;
#}
#location /quakeData {
# root /var/www/html/usgs_viz/server;
# proxy_pass https://quakeviz.app:8080/;
# proxy_ssl_session_reuse on;
#}
}
# Redirect
#server {
# listen 80 default_server;
# listen [::]:80 default_server;
# listen 443 ssl;
# listen [::]:443 ssl;
#
# return 301 https://quakeviz.app$request_uri;
#}
Here is the index.js in the server folder. I get a 502 now (updated question) on the client and the api.
// Modules
const cors = require('cors'),
express = require('express'),
expressStaticGzip = require('express-static-gzip'),
fs = require('fs'),
path = require('path'),
app = express(),
// Globals
getDirectories = (source) => {
return fs
.readdirSync(source, { withFileTypes: true })
.filter((dir) => dir.isDirectory())
.map((dir) => dir.name)
}
// CORS for Local Testing
app.use(cors())
// Compression
app.use(
'/',
expressStaticGzip(path.join(__dirname, '../client/build'), {
enableBrotli: true,
orderPreference: ['br', 'gz'],
})
)
// Routes
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '../client/build', 'index.html'))
})
app.get('/.well-known(/*)?', function (req, res) {
res.sendFile(path.join(__dirname, '../.well-known', 'assetlinks.json'))
})
app.get('/privacy-policy', function (req, res) {
res.sendFile(path.join(__dirname, '../privacy_policy.html'))
})
// API
app.get('/bufferLength', function (req, res) {
const encoding = req.headers['accept-encoding'],
compArr = getDirectories(
path.join(__dirname, '/api-data/compressed/')
).sort(function sortNum(a, b) {
return b - a
})
if (compArr.length < 2) {
console.warn('ByteLength Not Available')
res.status(500).send(new Error('ByteLength Not Available'))
} else {
console.log('BUFFER LENGTH RES')
fs.readFile(
path.join(
__dirname,
`/api-data/compressed/${compArr[1]}/byteLength.json`
),
(err, data) => {
if (err) {
console.warn(err)
res.status(500).send(new Error(err))
} else {
console.log(data)
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(data)
}
}
)
}
})
app.get('/quakeData/:index', function (req, res) {
const encoding = req.headers['accept-encoding'],
index = req.params.index,
compArr = getDirectories(
path.join(__dirname, '/api-data/compressed/')
).sort(function sortNum(a, b) {
return a - b
})
// Send Second Newest Dataset as Latest May hvae Read/Writes
if (compArr.length <= 1) {
console.warn('Unsupported Content Encoding Headers')
res.status(500).send(new Error('Dataset Not Currently Available'))
} else {
if (encoding.includes('br')) {
console.log('BROTLI RES')
fs.readFile(
path.join(
__dirname,
`/api-data/compressed/${compArr[1]}/brotliData${index}.txt.br`
),
(err, data) => {
if (err) {
console.warn(err)
res
.status(500)
.send(new Error('Brotli Compression Data Read Error'))
} else {
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Encoding': 'br',
})
res.end(data)
}
}
)
} else if (encoding.includes('gzip')) {
console.log('GZIP RES')
fs.readFile(
path.join(
__dirname,
`/api-data/compressed/${compArr[1]}/gzipData${index}.txt.gz`
),
(err, data) => {
if (err) {
console.warn(err)
res.status(500).send(new Error('Gzip Compression Data Read Error'))
} else {
res.writeHead(200, {
'Content-Type': 'application/json',
'Content-Encoding': 'gzip',
})
res.end(data)
}
}
)
} else {
console.warn('Unsupported Content Encoding Headers')
res.status(415).send(new Error('Unsupported Requested Encoding Type'))
}
}
})
// Listen
app.listen(8080, () => console.log('API listening on 8080'))
Didn't understand why you are trying to proxy each to route of your service, why didn't you let your app route the request for you?
Example:
location / {
root /var/www/html/usgs_viz/server;
proxy_pass https://quakeviz.app:8080/;
proxy_ssl_session_reuse on;
}
other thing I notice was the https on the proxy_pass I don't think that would work, try replacing with http.
I changed things to this. I also ran the server with PM2.
I am starting to get more into the fullstack sysadmin bit and so I didn't actually know I needed to run this on PM2 as well as route it with Nginx. I had the notion that Nginx would run it if I pointed to it. Kind of a silly thing but I do think the nginx config here is better. See below.
# Main Content Delivery Block (SSL)
server {
listen 443 ssl;
server_name quakeviz.app;
ssl on;
ssl_certificate /etc/ssl/certs/mpaccione_ssl.crt;
ssl_certificate_key /etc/ssl/private/mpaccione_ssl.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
add_header Content-Security-Policy upgrade-insecure-requests;
location / {
root /var/www/html/usgs_viz/server;
proxy_pass http://localhost:8080;
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;
}
}

Sub paths in url returning an internal server error with nginx and express server using react router

So basically I have an express server running on port 4000 that Nginx is redirecting to with a proxy_pass. When I access the root of my domain in the browser (https://www.buildingblockscms.tech/) everything works fine. But when I refresh any sub-routes I've navigated to or try to access them directly (https://www.buildingblockscms.tech/dashboard) I get an internal server error.
The react app running on my express server works absolutely fine with react-router-dom when ran locally but something is up with my Nginx config.
I've been trying to solve this all day, any help is GREATLY appreciated.
This is my sites-available/default file in Nginx.
server {
root /var/www/index.html;
# Add index.php to the list if you are using PHP
index index.html index.htm index.nginx-debian.html;
server_name buildingblockscms.tech www.buildingblockscms.tech;
location / {
proxy_pass http://localhost:4000/; #whatever port your app runs$
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;
proxy_set_header X-Forwarded-Host $server_name;
proxy_redirect off;
}
And this is my server file running on port 4000:
const express = require('express');
const mongoose = require('mongoose');
const graphqlHTTP = require('express-graphql');
const auth = require('./middleware/auth');
const app = express();
const fileUpload = require('express-fileupload');
app.use(express.json());
// enable files upload
// app.use(
// fileUpload({
// createParentPath: true
// })
// );
// DB Config
const db = process.env.mongoURI || require('./config/keys').mongoURI;
// Connect to Mongo
mongoose
.connect(db, { useUnifiedTopology: true, useNewUrlParser: true })
.then(() => console.log('MongoDB connected...'))
.catch((err) => console.log(err));
// Use Routes
app.use('/api/content-types', require('./routes/api/content-types'));
app.use('/api/sites', require('./routes/api/sites'));
app.use('/api/users', require('./routes/api/users'));
app.use('/api/pages', require('./routes/api/pages'));
app.use('/api/auth', require('./routes/api/auth'));
// GraphQL Route
app.use(
'/graphiql',
auth,
graphqlHTTP({
schema: require('./routes/client-graphql/schema'),
graphiql: true,
})
);
// Serve static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
const port = process.env.PORT || 4000;
app.listen(port, () => console.log(`Server started on port ${port}`));

SocketIO over Nginx with SSL

I'm trying to setup socketio with ssl through nginx. The issue is that I can get the client to connect but then I'm not seeing the other events which I expect to come over the socket. (note: this does work locally just not on my production server)
the client code is here:
import openSocket from "socket.io-client";
const socket = openSocket(`${SOCKET}`);
function subscribeToTimer(callBack) {
socket.on("timer", timestamp => callBack(null, timestamp));
socket.emit("subscribeToTimer", 1000);
}
export class App extends Component {
constructor(props) {
super(props);
this.store = this.configureStore();
subscribeToTimer((err, action) => this.store.dispatch(action));
}
and the server:
const port = 8000
const io = require('socket.io')()
io.on("connection", (client) => {
console.log("a user connected")
client.on("subscribeToTimer", (interval) => {
console.log("a user is subscribing to timer with interval: ", interval)
setInterval(() => {
timestamp = new Date()
client.emit('timer', { type: 'SET_TIME', payload: timestamp });
}, interval);
});
})
io.listen(port)
console.log('listening on port ', port)
which is managed by nginx /etc/nginx/sites-enabled/default:
server {
<snip>
location /socket.io {
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;
}
}
When I start the server, I get:
listening on port 8000
a user connected
So, the client is connecting to the server but I'm not seeing the subscribeToTImer event.
Any insights here?
The issue is probably because of two reasons. One is using the Host headers and one is using localhost instead of 127.0.0.1
server {
<snip>
location /socket.io {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
}
I am not 100% sure of the root cause but I have seen removing Host and using 127.0.0.1 instead of localhost has helped in other issues with socket.io in past
The problem turned out to be in the proxy_pass line of the config. You need to create an upstream section with a named group of servers and then reference that in proxy_pass (not http://localhost... the way I had it).
The working config /etc/nginx/sites-enabled/default:
upstream socket_nodes {
ip_hash;
server 127.0.0.1:8000;
}
server {
<-- snip -->
location /socket.io {
proxy_pass http://socket_nodes;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
}
}

express and nginx - loads html file but can't serve assets

I'm trying to run an express server at port 3000. When I visit my server's IP, I'm able to get the html page to load, however it doesn't seem to be able to find the assets (have a .js and .css file that I link to - this is in the same directory as the index.html inside of public). Am I missing something in my configs?
express setup
const express = require('express');
const path = require('path');
const app = express();
const PORT = 3000;
app.use('*',
express.static(path.join(__dirname, '..', 'public', 'index.html')));
app.get('*', (req, res) => {
res.sendFile((path.join(__dirname, '..', 'public', 'index.html')));
});
app.listen(PORT, () => {
console.log(`Listening on http://localhost:${PORT}...`)
});
nginx setup
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/my_site/public;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ =404;
proxy_pass http://127.0.0.1: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;
}
}
In your nginx configuration,
try_files $uri $uri/ =404;
Means nginx will try to find a static resource in your root folder, then try it with a / at the end, if it hasn't found anything yet will give out a 404 (Not Found).
It never reaches the proxy_pass.
The proper way to configure it would be like this:
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/my_site/public;
index index.html index.htm index.nginx-debian.html;
server_name _;
location / {
try_files $uri $uri/ #nodejs;
}
location #nodejs {
proxy_pass http://127.0.0.1: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;
}
}
Now, it will look for static files in your root folder, then pass it on to the node server.

Unable to serve expressjs app from subfolder

I am new to express and nginx.
I have made a simple express app and configure nginx:
location /exapi {
proxy_pass http://localhost:8010;
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 expressjs app is:
var express = require('express')
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
app.listen(8010, function () {
console.log('Example app listening on port 8010!')
})
When I access my vps VPS_IP/exapi, I get response Cannot GET /exapi, but when I use http://VPS_IP:8010 it is working as expected.
How can I access my express app from VPS_IP/exapi?
Try rewrite in nginx:
location ~* ^/exapi {
rewrite ^/exapi/(.*) /$1 break;
subfilter /exapi /;
proxy_set_header Host $host;
proxy_redirect off;
proxy_pass http://localhost:8010;
}