Can a webapp connect to mosquitto? - nginx

I have a mosquitto_sub running on background on serverA, let's say with topic "TEST", port 1883.
I followed this to use nginx as a stream proxy to mosquitto, on ServerB.
Testing the setup sending a message to ServerB, using mosquitto_pub, the message is received and displayed correctly on serverA.
Now I'd like that a webapp running on serverC could receive the mqtt messages I send using a websocket, as far as I understand that nginx setup is made exactly for this purpose because browser can't use directly mqtt protocol.
I did two tests:
pointing the websocket to ServerB stream (wss://serverB:1883)
pointing the websocket to nginx reverse proxy with this config:
.
...
server {
listen 443 ssl;
...
location /webapp/websocket {
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass_request_headers on;
proxy_pass http://serverB:1883/;
proxy_http_version 1.0;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_read_timeout 1800s;
}
}
With both the websocket doesn't work, with error 502 Bad Gateway.
My questions are, did I understand wrong and can it be done?
Does it say error 502 just because the webapp must be programmed to specify the topic to listen?

The Mosquitto broker supports MQTT over WebSockets, but it has to be on a separate port to native MQTT over TCP.
So if Mosquitto is normally listening on port 1883, you need to pick a different port to run the MQTT over WebSockets listener. e.g.
listener 1883
listener 8083
protocol websockets
You would then need to update the port in the proxy_pass entry to match.

Related

SignalR in ASP.NET Core behind Nginx

I have a server with ubuntu 16.04, kestrel and nginx as a proxy server that redirects to localhost where my app is. And my app is on Asp.Net Core 2. I'm trying to add push notifications and using SignalR core. On localhost everything is working well, and on a free hosting with iis and windows as well. But when I deploy my app on the linux server I have an error:
signalr-clientES5-1.0.0-alpha2-final.min.js?v=kyX7znyB8Ce8zvId4sE1UkSsjqo9gtcsZb9yeE7Ha10:1
WebSocket connection to
'ws://devportal.vrweartek.com/chat?id=210fc7b3-e880-4d0e-b2d1-a37a9a982c33'
failed: Error during WebSocket handshake: Unexpected response code:
204
But this error occurs only if I request my site from different machine via my site name. And when I request the site from the server via localhost:port everything is fine. So I think there is a problem in nginx. I read that I need to configure it for working with websockets which are used in signalr for establishing connection but I wasn't succeed. May be there is just some dumb mistake?
I was able to solve this by using $http_connection instead of keep-alive or upgrade
server {
server_name example.com;
location / {
proxy_pass http://localhost:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $http_connection;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
I did this because SignalR was also trying to use POST and GET requests to my hubs, so doing just an Upgrade to the connection in a separate server configuration wasn't enough.
The problem is the nginx configuration file. If you are using the default settings of the ASP.NET Core deployment guide then the problem is the one of the proxy headers. WebSocket requires Connection header as "upgrade".
You have to set a new path for SignalR Hub on nginx configuration file.
such as
location /api/chat {
proxy_pass http://localhost:5000;
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;
}
You can read my full blog post
https://medium.com/#alm.ozdmr/deployment-of-signalr-with-nginx-daf392cf2b93
For SignalR in my case, besides the "proxy_set_header" settings, there is another critical setting "proxy_buffering off;".
So, a full example is now like,
http {
map $http_upgrade $connection_upgrade {
default Upgrade;
'' close;
}
server {
server_name some_name;
listen 80 default_server;
root /path/to/wwwroot;
# Configure the SignalR Endpoint
location /hubroute {
proxy_pass http://localhost:5000;
# Configure WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache_bypass $http_upgrade;
# Configure ServerSentEvents
proxy_buffering off;
# Configure LongPolling
proxy_read_timeout 100s;
proxy_set_header Host $host;
}
}
}
See reference: Document reverse proxy usage with SignalR

NGINX - Connecting the webSocket to the same initial http connection

I have a scenario that i'm trying to configure in nginx where I have a number of processes each listening from ports 8000,8001... Upon establishing a http connection to one of these ports I then get the client (within javascript) to establish a WebSocket connection. All the listening processes have the same /SS websocket endpoint. However if a http connection initially makes a connection to 8000 it needs to also establish the websocket connection to 8000 too. I have the following nginx configuration:
upstream backends {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
include /etc/nginx/conf.d/*.conf;
server {
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://backends;
}
location /SS {
proxy_set_header Host $host;
proxy_pass http://backends;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
However this doesn't route the the websocket to the same place as the initial connection.
I thought of a way to do this where I setup different endpoints for each process and pass this through the initial http request. I would get the client to then use this endpoint for the WebSocket connection. This would however need me to configure all the different endpoints in nginx. I was wondering if there's a better way to solve this just within the nginx configuration?

Use nginx as proxy for websocket connection

How do I use nginx as proxy for a websocket ?
If I need to connect to socketSite.com:port from clientSite.com( javascript)
And I won't to show user's link "socketSite.com:port "
Can I use nginx proxy for redirecting requests from/to websocket server ?
Absolutely, you can! Use the following configuration:
location /myHandler{
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header HOST $host;
proxy_set_header X_Forwarded_For $remote_addr;
proxy_pass http://localhost:8880;
proxy_redirect default;
client_max_body_size 1000m;
}
I use spring websocket. /myHandler is my URL to create the websocket connection, http://localhost:8880; is my Tomcat server address. Nginx server and Tomcat are running on the same machine.

Nginx Proxy timeout correct configuration

My request to the upstream are timing out after 60 seconds.
I have configured the below proxy details.
location /myapp/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://aws-elb:80/myapp/;
proxy_read_timeout 300s;
}
Is there any other way to increase timeout or wait till I get response from my upstream
To configure the connection timeout you can change proxy_connect_timeout, which is 60 seconds by default.
This most likely won't solve your problem, however - have you confirmed that you receive a response if you curl your backend service?
Is your ELB successfully forwarding requests to your application? Your application would have to be listening on a port defined under your load balancers listeners.

Websockets on ElasticBeanstalk giving 404

I'm trying to deploy a websocket server to Elastic Beanstalk.
I have a Docker container that contains both nginx and a jar server, with nginx just doing forwarding. The nginx.conf is like this:
listen 80;
location /ws/ { # <-- this part only works locally
proxy_pass http://127.0.0.1:8090/; # jar handles websockets on port 8090
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / { # <-- this part works locally and on ElasticBeanstalk
proxy_pass http://127.0.0.1:8080/; # jar handles http requests on port 8080
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
I can run this docker locally and everything works fine - http requests are served, and I can connect websockets using ws://localhost:80/ws/ However, when I deploy to Elastic Beanstalk, http requests are still ok, but trying to connect websockets on ws://myjunk.elasticbeanstalk.com:80/ws/ gives a 404 error. Do I need something else to allow websockets on Elastic Beanstalk?
Ok, got it working. I needed the ElasticBeanstalk load balancer to use TCP instead of HTTP.
To do this from the AWS console (as it's laid out on 5/16/2015), go to your ElasticBeanstalk environment, choose "Configuration" on the left menu, under "Network Tier" there's a "Load Balancing" pane. Click its cog wheel, then you can change the load balancer protocol from http to tcp.

Resources