Node.js app in a Nginx subfolder with WSS connection to the same server - node.js

After many years managing my web projects on an Apache server, I had to move them to a new server using Nginx. I've succeeded in migrating all of them except the one that uses websockets.
The project is a web-based minesweeper using websockets to communicate with the game server. The game is accessible through https://www.my.domain.com/minesweeper . In its client.js file, the connection is established through the line const ws = new WebSocket('wss://www.my.domain.com:8081/').
The server uses the ws package, here's an extract of the server.js file, placed outside of the web folder :
const fs = require('fs')
const https = require('https')
const server = new https.createServer({
key: fs.readFileSync('/etc/letsencrypt/.../privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/.../fullchain.pem')
})
const wss = new WebSocket.Server({ server })
wss.on('connection', function (ws) {
ws.on('message', function (data) {
// ...
})
ws.on('close', function () {
// ...
})
})
server.listen(8081)
The game was working with this configuration on the previous server, but I can't remember if I had to edit the Apache conf file to make it work.
Now, on the new server, I've got the following configuration file :
server {
add_header Content-Security-Policy "default-src 'self' *.jquery.com wss: data: blob:;";
listen 443 ssl;
listen [::]:443 ssl;
root /var/www/mydomain;
index index.html index.htm index.nginx-debian.html index.php;
server_name www.my.domain.com;
charset utf-8;
source_charset utf-8;
location / {
rewrite ^/(.*).html$ /index.php?page=$1;
try_files $uri $uri/ /index.php$is_args$args;
}
location /minesweeper/ {}
location ~ /\.ht {
deny all;
}
ssl_certificate /etc/letsencrypt/.../fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/.../privkey.pem; # managed by Certbot
}
Without any additionnal configuration, when I try to access the game through its URL, the websocket request doesn't return the expected 101 response code. Firefox also triggers the "can't establish connection to wss://www.my.domain.com:8081" error.
Based on the official Nginx tutorial about websockets and other SO answers about similar problems, I've tried to edit my Nginx configuration with multiple combinations of proxy_* parameters without success.
But based on the fact that the websocket server and that the Nginx server are on the same IP, and that the websocket server is listening to the 8081 port, should the Nginx server also be listening to the 8081 server (if I edit the configuration to do so, Nginx refuses to restart because of the websocket server already listening on that port, and reciprocally) ? Is Nginx really the problem or am I missing another thing ?
Thanks in advance !

I confirm that I didn't have to edit my Nginx configuration. It had nothing to do with proxies : the problem was that firewall didn't allow 8081 port.
Here are the commands I've executed on my server, I saved my firewall settings before allowing the port (not sure if the process is the best, but it worked, connection is established and I've got my 101 response code) :
/etc/init.d/iptables save
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 8081 -j ACCEPT
/etc/init.d/iptables save
/etc/init.d/iptables restart

Related

Nginx Configuration for node Js application + Docker

I have a nodeJS application which is configured as a docker container.For making the application up and running, i was initially using 443 as the port - which gave a message 443 is a privileged port and updated the .yml with 8443 as the port.
Previously i used to give the url like - https://abc-acde.xyz , but now have to give https://abc-acde.xyz:8443 the port also along with domain name.
To resolve this i installed nginx to use it as a proxy to reroute the request.
The nginx config file is configured with the key , certs along with the server details - the configuration snippet of the conf file is below :
server {
listen 443 ssl;
server_name abc-acde.xyz;
ssl_certificate /opt/ssl/abc-acde.xyz/abc_acde_xyz.cer;
ssl_certificate_key /etc/ssl/ssl_signed_certs/abc-acde.xyz.key;
}
After this run the command - systemctl restart the nginx
Hope this configuration will help me to use the url as it was earlier - use without the port
Thanks in advance,
Rahul

Setting Up of Nginx reverse proxy

I have a node application running on an ec2 instance. Node is running on port 5000. I want to access the api from remote.
this is nginx configuration file.
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
client_max_body_size 20M;
listen 80;
listen [::]:80;
location / {
proxy_pass http://127.0.0.1:5000;
}
location /nginx_status {
# Turn on stats
stub_status on;
access_log off;
}
}
when I try to curl using curl localhost/nginx_status
it returns
Active connections: 1
server accepts handled requests
11 11 12
Reading: 0 Writing: 1 Waiting: 0
Also when I try to access the IP in browser, it shows
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and working. Further configuration is required.
For online documentation and support please refer to nginx.org.
Commercial support is available at nginx.com.
Thank you for using nginx.
But if I try to access the ip_address/nginx_status it shows 404 Error for example if I took IP address 123.456.789.098 in browser it shows the above mentioned message and if I took 123.456.789.098/nginx_status it will return 404 error. Even if I try curl ip_address/nginx_status it is also returning 404 error.
My question is, How can I access node application running on port 5000 from outside world?
unfortunately I only see part of your config, is there another server that listens to 80?
You don't use "default_server" for listen either, and without "server_name" I find it difficult to distinguish between them. So maybe another config with the server + port 80 as default_server takes effect. Check in your /etc/nginx/ folder which servers {..} all exist.
The proxy_pass looks correct, if the nodjs server is really listed there, check again whether it is really http or https scheme. For the correct protocol transmission of the proxy_pass.
But you should then add a control for the "stub_status" so that it is information that you do not entrust to everyone, for me it is the case that only one application has access to it internally and under another list what is not released on the internet:
server {
listen 127.0.0.1:10081 default_server;
location /flyingfish_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
I'm curious what you find out! :)

Nginx Proxy On Custom Port

I have a node process listening on port 11180, and would like to redirect all request from https:example.com:11179 to it. How can I accomplish this with nginx ?
I cannot use port 443, because it is forwarding to a different process. However I do have a certificate for the domain example.com
I have tried using this configuration
server {
listen 11179 ssl
location / {
proxy_pass http://127.0.0.1:11180
...
}
}
but the site just keeps loading, however the same configuration works if i listen on port 443
server {
listen 443 ssl
location / {
proxy_pass http://127.0.0.1:11180
...
}
}
Thanks a bunch for your help
Turns out it was a firewall problem :P

Cannot run multiple NodeJs server on one subdomain

I am trying to run multiple NodeJs server for (official) Kik Chatbots with different webhooks from one Subdomain on my webserver.
However, I am not able to do that. For one bot it works just fine. This is my setup for one working NodeJs server only:
Lets assume all webhooks are located at https://bots.mydomain.com
app.js:
'use strict';
let util = require('util');
let http = require('http');
let request = require('request');
let Bot = require('#kikinteractive/kik');
let bot = new Bot({
username: "foo",
apiKey: "bar",
baseUrl: "https://bots.mydomain.com"
});
bot.updateBotConfiguration();
// ... code ...
let server = http.createServer(bot.incoming()).listen(process.env.PORT || 8080);
So this Nodejs server is basically listening on port 8080. Therefore, my nginx config for the site https://bots.mydomain.com looks like this:
server {
root /var/www/bots.mydomain.com/public_html;
index index.php index.html index.htm;
server_name bots.mydomain.com;
location / { proxy_pass http://localhost:8080/; } # Port 8080
}
So far so good. This works perfectly fine! But here comes the issue:
If I try to run multiple NodeJs server, by making directories in the public_html folder, lets say /bot1 and /bot2 and adapt my nginx config like that:
server {
root /var/www/bots.mydomain.com/public_html;
index index.php index.html index.htm;
server_name bots.mydomain.com;
location /bot1 { proxy_pass http://localhost:8080/; } # Port 8080
location /bot2 { proxy_pass http://localhost:8090/; } # Port 8090
}
and finally setting the second server to listen on port 8090 instead of 8080 and of course setting the base URL to https://bots.mydomain.com/bot1 or https://bots.mydomain.com/bot2, nothing works anymore. And by that I mean the webhooks do no pass any data to the NodeJs server. They are, however running! I know this because if I navigate to (for example) https://bots.mydomain.com while the bot is offline, I obviously receive the error 502 Bad Gateway but if the bot is online I get a timeout (which means the server is indeed listening).
Am I missing something or does Nginx just not allow multiple webhooks or proxy_passes for directories?
A workaround would be to make a subdomain for each bot, which would work (I tried). But I'd like to use sub directories rather than subdomains for the bots.
EDIT:
I noticed a strange behavior: If I set a proxy_pass for /
like: location / { proxy_pass http://localhost:8080; }
to port 8080 and set the baseurl in the bot1 script to bots.mydomain.com/bot1, Bot-1 works.
But I obviously still can't get other bots to work aswell because I'm using the root (/).
Does that mean it's a problem with Kik-API's way of listening?
EDIT 2:
I checked the Nginx Log now and it seems like the Kik Wrapper tries to listen on a directory which doesn't exists. I did the following: Start the bot on port 8080 & message it. This is the log output:
https://pastebin.com/7G6TViHM
2017/04/13 09:07:05 [error] 15614#15614: *1 open() "/var/www/bots.mydomain.com/public_html/incoming" failed (2: No such file or directory), client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "POST /incoming HTTP/1.1", host: "bots.mydomain.com"
2017/04/13 09:07:13 [error] 15614#15614: *1 open() "/var/www/bots.mydomain.com/public_html/incoming" failed (2: No such file or directory), client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "POST /incoming HTTP/1.1", host: "bots.mydomain.com"
But I still don't know how to fix this. As a test I created the directory incoming in public_html. This returned the following in the log:
2017/04/13 09:32:41 [error] 15614#15614: *10 directory index of "/var/www/bots.mydomain.com/public_html/incoming/" is forbidden, client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "GET /incoming/ HTTP/1.1", host: "bots.mydomain.com"
Does anyone have an idea on how to fix it?
I think your issue lies with a trailing slash in proxy_pass, which removes the /bot1 and /bot2 prefixes once passed to upstream (replacing both with mere /), so, each bot in your nodejs code has a mismatched baseUrl setting as a result (as you mention that you did change those settings appropriately to match the external URL).
-location /bot1 { proxy_pass http://localhost:8080/; } # Port 8080
-location /bot2 { proxy_pass http://localhost:8090/; } # Port 8090
+location /bot1 { proxy_pass http://localhost:8080; } # Port 8080
+location /bot2 { proxy_pass http://localhost:8090; } # Port 8090
It probably doesn't wok because your target servers get the path that includes the /bot1 and /bot2 prefix, which they may not expect.
Maybe try:
location /bot1 {
rewrite ^/bot1/(.*)$ /$1 break;
proxy_pass http://localhost:8080/;
}
location /bot2 {
rewrite ^/bot2/(.*)$ /$1 break;
proxy_pass http://localhost:8090/;
}
In case anyone comes across this question:
It's just not possible by Kik's API design.
When you initialize your bot with
let bot = new Bot({
username: "foo",
apiKey: "bar",
baseUrl: "https://bots.mydomain.com"
});
this baseUrl is essentially a webhook and cannot be re-used. It has to be somewhat unique.
A possible work-around would be specifying a port directly in the base-url.

ExpressJS Server - respond to host header with shared port

Lets say I have corporatewebsite.com listening on port 80. Which is an appache / WordPress site.
I have a node application that I'd like to respond to sub.corporatewebsite.com
The node application is running Express currently. I can get it to listen to a separate port at the moment, but my service won't start if it's pointed to port 80 since it's already in use.
How can I have both apache and node listening to port 80, but having node responding to the subdomain?
You could use a reverse proxy like Nginx to route your subdomains.
Here is an example of nginx configuration, you might probaly have to complete according to your project and server :
server {
listen 80;
server_name corporatewebsite.com;
location / {
[ ... some parameters ... ]
include proxy_params; // Import global configuration for your routes
proxy_pass http://localhost:1234/; // One of your server that listens to 1234
}
}
server {
listen 80;
server_name sub.corporatewebsite.com;
location / {
[ ... some parameters ... ]
include proxy_params;
proxy_pass http://localhost:4567/; // The other server that listens to 4567
}
}
You have to configure, for example, apache2 listening to port 1234 while nodejs is listening to port 4567.
If you do like this, a good practice is to block direct access from the outside to your ports 1234 and 4567 (using iptables for example).
I think this post could be useful to you : Node.js + Nginx - What now?

Resources