Configuring HTTPS for Express and Nginx - javascript

I am trying to configure my ExpressJS app for https connection. The Express server runs at localhost:8080 and the secure one localhost:8443.
Here is the server.js code related to https:
var app = express();
var https = require('https');
const options = {
cert: fs.readFileSync('/etc/letsencrypt/live/fire.mydomain.me/fullchain.pem'),
key: fs.readFileSync('/etc/letsencrypt/live/fire.mydomain.me/privkey.pem')
};
app.listen(8080, console.log("Server running"));
https.createServer(options, app).listen(8443, console.log("Secure server running on port 8443"));
And here is my Nginx configuration:
server {
listen 80;
listen [::]:80;
server_name fire.mydomain.me;
location / {
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;
}
}
server {
listen 443;
listen [::]:443;
server_name fire.mydomain.me;
location / {
proxy_pass https://localhost:8443;
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;
}
}
What I did :
Generating SSL certificate with Letsencrypt certonly tool for the domain fire.mydomain.me.
Configuring nginx.
Configuring the server.js node app.
Adding TCP rules for the 443 port in Ufw.
I tried
Commenting the not-ssl server line in server.js to force the connections to go through ssl configuration: this serve the page when I try to go to fire.mydomain.me:443 but not to "https:// fire.mydomain.me". In both cases, no SSL. Trying to go to https:// fire.mydomain.me generate this message "This website doensn't provide a secure connection" in Google Chrome.
I followed this tutorial in the first place to set my ssl node config :
https://medium.com/#yash.kulshrestha/using-lets-encrypt-with-express-e069c7abe625#.93jgjlgsc

You don't need to use HTTPS between your nginx reverse proxy and Node app running on the same host. You can proxy both HTTP requests to port 80 and HTTPS requests to port 443 to the same port in your Node app - 8080 in this case - and you don't need to configure TLS certificates in that case.
You can change your server.js file to:
var app = express();
app.listen(8080, console.log("Server running"));
and use an nginx config that has proxy_pass http://localhost:8080; for both HTTP on port 80 and HTTPS on port 443.
This is how it is usually done. Encrypting traffic on the loopback interface doesn't add any security because to sniff the traffic you need root access to the box and when you have it then you can read the certs and decrypt the traffic anyway. Considering the fact that most of the posts on https://nodejs.org/en/blog/vulnerability/ are related to OpenSSL, one could argue that using SSL in Node can make it less secure in that particular case of encrypting loopback interface traffic. See this discussion on the Node project on GitHub for more info.

Thanks to #rsp solution, here is the working Nginx configuration :
server {
listen 80;
listen 443 ssl;
server_name fire.mydomain.me;
ssl_certificate /etc/letsencrypt/live/fire.mydomain.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/fire.mydomain.me/privkey.pem;
location / {
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;
}
}

Related

NGINX Proxy with a domain, instead of a ip adress

I have a frontend in angular which scrapes from other pages. Because of CORS, I created a proxy server, which also runs on my VPS. If I'm starting Angular in localhost and my proxy on my VPS, I can use my Proxy with the IP address:port of my VPS. That's all good, but I need to use HTTPS, because the whole page is running on HTTPS. Here comes nginx with my domain, which does not work. I set everything up, but it still won't work, seems like I'm having a misconfiguration?
My nginx configuration:
server {
server_name domain.com www.domain.com;
root /var/www/docs;
location / {
try_files $uri $uri/ /index.html =404;
}
location /api {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /proxy { //HERE COMES MY PASS TO MY PROXY
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
.... SSL CONFIGURATION
Probably is the proxy_pass here wrong?
This is my nodejs proxy:
require('dotenv').config();
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || 'domain.com';
// Listen on a specific port via t.he PORT environment variable
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: [], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
If I'm trying with '0.0.0.0' instead of my domain name, it works with http://ip:port/target, but it does not work with domain.com/proxy/target. Then I become an "invalid host" error
Fixed the problem myself.
Problem was a missing / behind my proxy_pass
Solution is: "proxy_pass http://localhost:8080/;" instead of "proxy_pass http://localhost:8080;"

Client unable to hit socket.io server

Project is hosted on Digital Ocean.
On the client side, its throwing a 404 error
GET http://134.209.147.204/socket.io/?EIO=3&transport=polling&t=NKKWF-X //404
Here is the nginx config file
server {
listen 80;
root /var/www/html;
location / {
proxy_pass http://127.0.0.1:5000; (where the frontend is running)
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /socket/ {
proxy_pass http://localhost:3001; (where the sockets.io server is running)
}
}
Frontend
socket = io('/socket/')
Both the frontend and backend runs without any errors and can be accessed from the browser.
After days of hacking, I was able to make it work!
nginx config
upstream websocket {
server 127.0.0.1:3001;
}
server {
listen 80;
root /var/www/html;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /ws/ {
proxy_pass http://websocket/socket.io/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
socket.io server
const app = require('express')();
const server = app.listen(3001);
const io = require('socket.io').listen(server);
socket.io client
socket = io.connect('http://yourdomain/', {path: '/ws/'})
I faced the same problem when trying to connect a sockets.io application to a nodejs server that is behind an Apache2 server. I access the nodejs using /video/. I read this answer and didn't get it. Dummy me! But just in case I'm not alone, I'll attempt to clarify it further here.
I ended up having to follow the code of sockets.io to understand what they mean in the documentation. I'm such a dummy. The documentation says:
A new Socket instance is returned for the namespace specified by the
pathname in the URL, defaulting to /. For example, if the url is
http://localhost/users, a transport connection will be established to
http://localhost and a Socket.IO connection will be established to
/users
After following the code, the meaning (in my dummy's mind) became clear. The socket connection is made with the "String" that I specify in socket=io("url/video/"), but that the transport connection will be attempted to just its "url" part. To change the transport connection path, you need to specify one of the options described in the documentations for the Manager class, which are the same as the options for the io class.
Here is a link to the pertinent documentation, you need to read the io and the Manager headings.

create-react-app code changes behind nginx reverse proxy not reloading in browser

Ive installed a new CRA template and Im unable to see file changes reflect in the browser. Im reverse proxying React app through nginx using unmodfied CRA installation (unmodified apart from setting .env VAR PORT corresponding to standard nginx websocket proxy config). Still I see persistent browser error:
webpackHotDevClient.js:60 WebSocket connection to 'wss://react.syntapse.co.uk/sockjs-node' failed: Error during WebSocket handshake: Unexpected response code: 301
.env file
PORT=3121
nginx configuration
server {
listen 80;
server_name react.syntapse.co.uk;
location /sockjs-node/ {
proxy_pass http://0.0.0.0:3121/sockjs-node/;
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 / {
proxy_pass http://0.0.0.0:3121/;
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;
}
}
I haven;t taken any specific steps to enable HMR or any form of hot reloading just expecting code changes to update in the browser. I'm trying out different platforms and ive got near identical nginx config for default angular and vue apps which just work with HMR out the box so I guess React config needs tweaking to work with through proxy but the documentation is a bit sparse.
Any help or insights into using React with nginx reverse proxy are much appreciated.
Thanks
Answer in plain sight the whole time! drop the end slash.
location /sockjs-node {
proxy_pass http://0.0.0.0:3121/sockjs-node;
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;
}

Websocket connection for nginx and parity?

I am running a dAPP on a cloud server and using nginx and parity client with wesocket enabled on it.
I installed a certbot certificate for the https domain.
Now i am having problem that while accessing my website using https it gives an error on chrome that..
web3-providers.umd.js:1269 Mixed Content: The page at 'https://www.
chain.com/' was loaded over HTTPS, but attempted to connect to the
insecure WebSocket endpoint 'ws://40.138.47.154:7546/'. This request has
been blocked; this endpoint must be available over WSS.
then i added the reverse proxy on nginx config file as
location / {
# switch off logging
access_log off;
proxy_pass http://localhost:7556; #Port for parity websocket
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# WebSocket
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
and then it is giving an error of
"WebSocket interface is active. Open WS connection to access RPC."
What is the problem here and what should i try?
Thanks
The https won't allow loading insecure content on the page.
One possible solution is to use the SSL/TLS terminator between the application server and the client.
From the official Nginx docs, the relevant part of the config file could be like this:
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream websocket {
server localhost:7546;
}
server {
listen 443;
location / {
proxy_pass http://websocket;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
}
ssl on;
# specify cert and key
}
Inside the dApp change 'ws://40.138.47.154:7546/' to wss://40.138.47.154.

Hosting two websites in one domain using nginx

I have an angularjs website (with a nodejs server.js file that hosts it on port 8100). I use Nginx to reverse proxy into that port.
I would like users who come to a separate path (say www.example.com/location1) to go to a completely different website (a different AngularJS folder with a different server.js file).
The Node.js files run on my server. But the front end throws an injection error when I try to run the two websites. Is it even possible to do this?
FYI: When I run a single website on the server, it works... but it doesn't work when I run both.
Edit: both the websites work on my localhost perfectly.
My Nginx sites-available/default file
server {
...
location / {
proxy_pass http://127.0.0.1:8100;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /location1/ {
proxy_pass http://127.0.0.1:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
My Server.js files (more or less the same for both files):
var express = require('express')
var app = express();
path = require('path');
app.use(express.static(path.join(__dirname,'pw')));
app.all('*',function(req,res,next){
res.sendFile('pw/index.html',{root:__dirname});
});
app.listen(8100); //This will be 8080 for the other server.js file (which has been renamed something else

Categories