I have a MERN stack website which i use nginx to serve. My backend server is running on port 5000 over http. SSL works fine for my frontend, but i cant make https requests to my express server. How can i solve this issue? Should i use another SSL for my backend?
This is how my express server.js looks like:
const express = require("express");
const dotenv = require("dotenv");
const routers = require("./routers/index");
const connectDatabase = require("./helpers/database/connectDatabase");
const path = require("path");
const cors = require("cors");
// Environment Variables
dotenv.config({
path: "./config/env/config.env",
});
// MongoDb Conenction
connectDatabase();
const app = express();
// Express - Body Json
app.use(express.json());
const PORT = process.env.PORT;
// CORS
app.use(cors());
// Router Middleware
app.use("/api", routers);
app.listen(PORT, () => {
console.log(
`App Started on PORT: ${process.env.PORT} : ${process.env.NODE_ENV}`
);
});
and this is how nginx/sites-avaliable/my-site.com looks like:
server {
root /var/www/my-site.com/html;
index index.html index.htm index.nginx-debian.html;
server_name my-site.com www.my-site.com;
location / {
try_files $uri /index.html;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/my-site.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/my-site.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = www.my-site.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
if ($host = my-site.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
listen [::]:80;
server_name my-site.com www.my-site.com;
return 404; # managed by Certbot
}
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 ?
I have a problem with my server developed in EXPRESS and hosted on NGINX.
I use passport.js for user authentication, even if I don't think this is the problem, and when I try to login from localhost I get an error while if I run it by uploading it to my domain I don't get it wrong and it works correctly, so I think it's a CORS problem blocking localhost requests.
NGINX default
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name api.mysite.com www.api.mysite.com;
location / {
proxy_pass https://localhost:3007; #whatever port your app runs on
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;
if ($http_origin ~* (^https?://([^/]+\.)*(mysite)\.com$)) {
set $cors "true";
}
if ($http_origin ~* (^http?://([^/]+\.)*(localhost:3006))) {
set $cors "true";
}
if ($http_origin ~* (^https?://([^/]+\.)*(192.168.1.21:3006))) {
set $cors "true";
}
# Nginx doesn't support nested If statements. This is where things get slightly nasty.
# Determine the HTTP request method used
if ($request_method = 'OPTIONS') {
set $cors "${cors}options";
}
if ($request_method = 'GET') {
set $cors "${cors}get";
}
if ($request_method = 'POST') {
set $cors "${cors}post";
}
if ($cors = "true") {
# Catch all incase there's a request method we're not dealing with properly
add_header 'Access-Control-Allow-Origin' "$http_origin";
}
if ($cors = "trueget") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($cors = "trueoptions") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
#
# Om nom nom cookies
#
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($cors = "truepost") {
add_header 'Access-Control-Allow-Origin' "$http_origin";
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/mysite.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/mysite.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
serverDev.js
const sessionParser = session({
saveUninitialized: false,
secret: 'secret',
resave: false,
cookie: {expires: 43200000, secure: false }
})
var privateKey = fs.readFileSync('ssl-cert/privkey.pem', 'utf8');
var certificate = fs.readFileSync('ssl-cert/fullchain.pem', 'utf8');
var credentials = { key: privateKey, cert: certificate };
var httpsServer = https.createServer(credentials,app);
routes.js
app.post('/Login', passport.authenticate('local-login', {
successRedirect : '/Profile',
failureRedirect : '/Login',
failureFlash : false
}),
function(req, res) {
if (req.body.remember) {
req.session.cookie.maxAge = 1000 * 60 * 3;
} else {
req.session.cookie.expires = false;
}
res.redirect('/Login');
});
app.get('/Profile', isLoggedIn, todoList.profile);
function isLoggedIn(req, res, next) {
console.log("isLoggedIn",req.isAuthenticated()) <--- THIS IS THE PROBLEM IN LOCALHOST RETURN ALWAYS FALSE
if (req.isAuthenticated())
return next();
res.redirect('/Login');
}
passport.js
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("use `Users`");
connection.query("SELECT * FROM Accounts WHERE id = ? ",[id], function(err, rows){
if (err){
return done(err);
}
var user = rows[0];
done(err, user);
});
});
If anyone else had this problem I solved it by configuring the 'express-session' in this way
var session = require('express-session');
const sessionParser = session({
secret: 'your-secret',
resave: false,
saveUninitialized: true,
cookie: {
secure: true,
httpOnly: true,
sameSite: 'none',
maxAge: 1000 * 60 * 60 * 12 // milliseconds * seconds * minutes * hours
}
})
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}`));
With the following config and code, if I goto https://domain.co/api/yo
it looks for a '/api/yo' route in the express app rather than just '/yo'
how do I config NGINX so that express sees https://domain.co/api/yo as '/yo'?
server {
listen 443 default_server;
listen [::]:443 default_server;
root /var/www/domain.co;
index index.html;
server_name domain.co www.domain.co;
ssl on;
ssl_certificate /etc/letsencrypt/live/domain.co/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain.co/privkey.pem;
location / {
try_files $uri /index.html;
}
location /api {
proxy_pass http://127.0.0.1:8080;
}
}
app.js
const express = require('express')
const app = express()
app.get('/yo', (req, res) => res.send('Hello World!'))
app.listen(8080, () => console.log('Example app listening on port 8080!'))
The Nginx and Express route had to match for me
nginx:
location /api
express:
app.get('/api', ...)