Can nginx redirect instead of proxy - node.js

Suppose I have 1 nginx server and many Websocket servers:
server1.exmaple.com
server2.example.com
server3.example.com
When there is only a few concurrent connection Nginx can handle the traffic to and from the servers using upstream and proxy_pass.
Because users can send much more Websocket message than HTTP request in a given time, there is going to be a turning point when Nginx can't handle anymore message because it is out of network resources.
Adding more upstream servers won't help because the bottleneck is the server all users conenct to, the Nginx server.
If Nginx can do redirection when the Websocket handshake happens the browser can use that direct connection to each server and leave Nginx out of this.
If these servers can't handle the traffic I can just add more.
Is it possible to do redirection with Nginx instead of proxying, I can't find any demo or documentation about it?

Related

How to use Socket.io with Nginx load balancer?

I was going over this article: https://medium.com/#feritzcan/node-js-socket-io-1cde93315a7d, the section "CHAPTER 9 — NGINX Load Balancer", where it is said that:
Imagine you have 3 servers on ports 3000,3001,3002. An user connects to server through Nginx and its forwarded to server on port 3000. Then, socket connection between client and server:3000 is established. However, when client emit any event to server through Nginx, client is not guaranteed to be forwarded to the server:3000 again. Most of the time, it will be forwarded to server:3001 or server:3002 which doesn't recognize the client and will result in error.
In round-robin algorithm; requests are distributed sequentially among servers.
And then, below it is said that:
Ip hashing is a proxy algorithm like round-robin. The algorithm will always forward clients from the same ip to the same server. So, user will always connect the same server and be recognized.
Edit your config file again and set IP hashing this time
sudo nano /etc/nginx/sites-available/yourdomain.com
,upstream app_servers {
ip_hash;
server 142.93.111.111:3001;
server 142.93.111.111:3002;
server 142.93.111.111:3003;
….
…
…
After restarting Nginx, it will use IP hashing and will always forward clients to the same server that they were forwarded before.
Now my question here is: OK, I get it how the NGINX Load Balancer ensures that the same client will always be connected to the same server, but what about the frontend and the way the socket.io-client is created? For example, if we use server:3000 as the URL when creating the socket on the frontend side, does this means that every client will always be connected to the server:3000?
This somehow goes against the feature for distrusting the load between multiple servers, so I wonder If I am missing anything related.

How might one set up a reverse proxy that cannot decrypt traffic?

I'd like to have a reverse HTTPS proxy that CANNOT decrypt proxied traffic (ie an HTTPS passthrough/tunnel). The idea is to run this proxy on a VPS and point a domain to it, allowing for the IP address of the origin server to remain unexposed while maintaining end-to-end encryption.
Is this possible? I could probably proxy requests without difficulty since the destination address in that direction is fixed, but proxying responses seems problematic given that the proxy would be unable to read the client IP within an encrypted response.
A potential solution is to have the origin server package the encrypted response and destination address in a request made to the proxy, but I am unsure as to how I might generate the encrypted request without sending it (using node.js, which is the application running on the origin server).
From your question, I got that you want to listen to requests from your VPC server and pass the request to your other server which has to remain unexposed.
This can be configured with the web server which you are using for proxy ( considering AWS allows port forwarding from a VPN server to non-VPN server ).
I prefer doing this with Nginx as it is easy, open-source with less code and more functionality.
There is a concept of load balancing which does the same as you mentioned above.
steps :
Install Nginx and keep it active.
Create a new configuration file in /etc/nginx/sites-enabled
write the below code with modifications:
http {
upstream myapp1 {
server srv1.example.com;
server srv2.example.com;
server srv3.example.com;
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
}
and at the place of srv1.example.com and srv2.example.com add the domain to which you want to redirect requests
Save the file and restart the Nginx
Boom!! it should redirect all incoming requests to your application.

AWS Loadbalancer Proxy for Nodejs

I have configured the load balancer to route the request to two of Ec2 Instance running a NodeJs server. I need to direct the request coming from both http (port 80) and https (port 443) to http (port 80) of the EC2 instances in NodeJs. I have uploaded the ssl certificate to AWS and configured the load balancer to use ssl certificate. The problem is the request coming from http port doesn't automatically route to https. It has to be a server side script or snipped which I need to write in server.js which should be routing the http to https, i tried to do it and it run into endless redirection. So questions -
Is there any guide to do this from AWS ?
If not then how one can achieve this, any pointers or suggestions would be greatly appreciated.
On the server side you can check the X-Forwarded-Proto
(original request protocol) and if it's heaving value http you can send redirect (http 302) to a url with https protocol..
though with ALB (application load balancer you may specify a set of rules, maybe it's possible to do that there..)
I couldn't find a guide from AWS, but I will keep searching and update the answer in the case I find it.
Usually, when you write applications in Node.js, you specify which port should your app run at. It means that you will need two different servers listening. And when your app receives a request on port 80 (HTTP), it should redirect to your HTTPS server, like in this answer.
Another point that may be relevant to your question is that, in production environments, you don't usually bind a port to your Node.js server, since it's not production ready. You probably want to use a reverse proxy and load balancer like Nginx or HAProxy.
If you are using the AWS ALB (Application Load Balancer) they announced the http->https redirect today. Take a look: https://exampleloadbalancer.com/redirect_demo.html
Put your ELB behind the Cloudfront and in settings of your distribution select forward HTTP to HTTPS.
The following doc will be helpful
https://docs.aws.amazon.com/waf/latest/developerguide/tutorials-ddos-cross-service-ELB.html
This method has two benefit:
1-Your problem will be solve
2-You can use the benefit of the powerful CDN, for more information about Cloudfront read https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Introduction.html
Update:
You can forward traffic from HTTP to HTTPS by edit your Listeners setting in your ELB.

Socketio and cloudflare

So I've already done my research and figured out that socket.io only works with cloudflare if you use set ports found that here
So through that research I found that http and https can't use the same port. I'm coming here to as you guys how do you get a socketio server to listen on two ports? So it can support http and https with cloudflare
The common method is referred to as an SSL Termination Proxy (also called SSL off-loading). The proxy accepts incoming messages over HTTPS and passes the decrypted requests to another resource (another server, web service/API, etc.). This would allow your Node.js application utilizing socketio to handle all requests, no matter if the client made an HTTP or HTTPS request. Software like NGINX, Apache, and even Microsoft IIS are capable of providing this functionality.
Here are some links regarding this topic:
General Info: https://en.wikipedia.org/wiki/TLS_termination_proxy
NGINX: https://www.nginx.com/resources/admin-guide/nginx-ssl-termination/
NGINX: https://www.nginx.com/resources/admin-guide/nginx-tcp-ssl-termination/
HAProxy: https://www.digitalocean.com/community/tutorials/how-to-implement-ssl-termination-with-haproxy-on-ubuntu-14-04
IIS: https://blogs.iis.net/wonyoo/ssl-off-loading-in-application-request-routing

WebSocket over SSL: Cloudflare

I have a website behind cloudflare. I need to enable websockets over SSL without turning off cloudflare support. I have a PRO plan and hence won't get the new websocket support. I am using Nginx to proxy a SSL connection to a web socket running on a node server. Now, I read somewhere that cloudflare could work with approved ports would support websockets. Hence, I'm using 8443 for the Nginx port and another port for the node server. Using wscat it returns a 200 error.
$ wscat -c wss://xyz.com:8443
error: Error: unexpected server response (200)
I know that the websocket is expecting a 101 code. However, if I visit https://xyz.com:8443, I can see the page displayed by the node server telling me proxy is working. Also, once I turn off cloudflare support, the websocket starts working. Any clues to get this working. I know I can create a subdomain but I'd prefer running the websocket behind cloudflare.
If you're trying to access this through CloudFlare's network you'd need to explicitly have web sockets enabled on your domain before they will work -- regardless of the port. As in, even if the port can pass through our network, that won't automatically mean that web sockets will be enabled or accessible on your domain.
You can try contacting our support team to request an exception to see if they can enable it for your domain, but typically this is still only available at the business and enterprise levels.
Disclaimer: I work at CloudFlare.

Resources