Host Angular application on raspberry pi using nginx, socket.io and nodejs - node.js

I can't find a configuration to make this work. I want to host an angular app (a board game) and a nodejs server (which communicates with the board game) on a raspberry pi via nginx (also already tried apache).
I start to get the feeling it's not a problem with the nginx configuration, but something fundamental I am missing.
Working:
Running the Angular app (via ng serve) and the nodejs server (via
ts-node ./src/app.ts) locally
Running the Angular app (via ng serve) local and the nodejs server on the raspberry
Not working
hosting angular app via nginx (putting the content of dist folder (generated by ng build --prod) into var/www/html) and running nodejs server on raspberry --> resulting in Error during WebSocket handshake: Unexpected response code: 400
Code
Nodejs Server
const Express = require('express')();
const Http = require('http').Server(Express);
const Socketio = require('socket.io')(Http);
Http.listen(3333, () => {
console.log('Listening at :3333...');
});
Angular App Client
import { SocketIoConfig, SocketIoModule } from 'ngx-socket-io';
const config: SocketIoConfig = { url: 'http://192.xxx.xxx.xx:3333', options: { transports: ['websocket'] } };
#NgModule({
imports: [CommonModule, SocketIoModule.forRoot(config)],
exports: [SocketIoModule]
})
export class DataAccessModule {}
nginx config
server {
location ~* \.io {
proxy_pass http://localhost:3333;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
add_header X-location contains-io always;
}
}
EDIT: If I remove my nginx config additions I get the same results. Is there a way to test if the config is used?
Some other weird thing I discovered is, that I only see a blank page and not a single console.log when running the angular app via ng serve on the raspberry and go to localhost:4200

You better use ng build instead of ng serve, and direct your Nginx to your dest folder, like this:
location / {
root /var/www/angular-deploy; // move your dest into here
index index.html index.htm;
}
You can read this for more details, hope it will help

Turns out the only thing I needed was a dyndns, instead of localhost or a static ip.
So the client code looks like this:
private socketUrl = 'http://example.ddns.net';
// also switched to the plain socket.io-client package instead of ngx-socket-io, but I don't think this is necessary
socket: SocketIOClient.Socket = io(this.socketUrl);
and the nginx conf:
server {
listen 80;
server_name example.ddns.net;
root /var/www/app;
location ^~ /socket.io/ {
proxy_pass http://127.0.0.1:3333;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location / {
try_files $uri $uri/ /index.html;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
index index.html index.htm;
}
}

Related

Node.js api not working when deploying to AWS

I have one Node.js app and the frontend is using React. When I develope it on my local, I put the project under http://localhost/app subdirectory and api is under /api, the port I use is 5000. It's all working. Here is the way I set:
For Node.js, I use this to set the Frontend directory and router:
const indexRouter = require('./routers')
app.use('/api', indexRouter) //to set API path
app.use('/app', express.static('public'))
the server is listen on 5000.
For React, I update the package.json to:
"homepage": "/app",
"proxy": "http://localhost:5000/"
and with the Axios request, I add the base varible at the beginning of the request path and set it to '/api'
This is all good on my localhost. However, when I deploy it to AWS with Nginx, I couldn't make the API request success.
With Nginx, I update the original location block from
location / {
try_files $uri $uri/ = 404;
}
to
location /app {
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;
}
When I go to /root/app, I can see the homepage of the React (I copied the React build files into the Node js public folder). However, it cannot get the request success. I can see on my localhost, the request path is http://localhost:3050/api/login, but the live sever request path is http://domain_name/login, I don't know why the server cannot go to /api for request.
I hope someone can help me for this.
Since you built the React app using yarn build, you would not be able to use the proxy that you were using in the development. That method is for testing in development only, and not in production. You can read more about it here.

Socket.io not working with nginx and https

I have a React app communicating with a very simple node backend, it works perfectly fine in local and was working perfectly fine over http. For obvious reason, the app is now running in https but the socket is not connecting anymore. I have been looking to so many threads but couldn't find a way to fix it. Here are the socket parts of my code and nginx conf.
Client side:
const socket = io('wss://sub.domain.io', { path: '/my-path',});
Server side:
const server = require('http').createServer();
const io = require('socket.io')(server, {
path: '/my-path',
serveClient: false
});
server.listen(8080);
nginx proxy
server {
....website serving part...
location /my-path/ {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Error is: GET https://sub.domain.io/my-path/?EIO=3&transport=polling&t=MsCot3e net::ERR_CONNECTION_TIMED_OUT VM17:1 which looks like a timeout because it fails to connect.
So I found an answer after so many hours and it is pretty dumb and simple. My Nginx only handle the www website (DNS redirection is enough for the website), hence I needed www.sub.domain.io here:
const socket = io('wss://www.sub.domain.io', { path: '/my-path',});

Routing API requests to Node Server in MEAN app while deploying in server

I'm deploying my MEAN app in a subdomain https://app.example.com
Here is my app folder structure
app
- frontend (Angular Code)
- backend (NodeJS Code)
The server is running on NGINX, here are the config details:
server {
listen 80;
listen [::]:80;
server_name app.example.com;
root /var/www/app/frontend/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html?$query_string;
}
}
I'm running my NodeJS code in port 8080 in the same subdomain.
Log shows that the server is running on the port successfully.
But when my app makes API requests from the Angular App, the requests are getting timed out.
I guess it's because of the routing in the config file, how do I make the API requests route through my NodeJS code.
You have to forward requests from nginx to your app. Currently your server is doing nothing, except serving html files. Read nginx docs or look for tutorials regarding proxy_pass setting.
Currently you can just add this to your nginx and it will fire up
. . .
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;
}
}

502 Bad Gateway when connecting to Nodejs app running express through Nginx

I'm having issues connecting to my node app that is running on port 8081.
My setup is as follows (everything runs on a Raspberry Pi):
NGINX
events {
worker_connections 1024;
}
http {
server {
root /data/web;
location / {
}
location /pub {
proxy_pass http://localhost:8081;
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'm serving static files with the first location (which seems to be working fine), and I would like the second location to reroute to my node app. which is running on port 8081.
My node app looks like this:
app.get('/', function(req, res){
res.send("Hello World!");
});
var server = app.listen(8081, '192.168.0.178');
And I'm testing my connection using a simple wget from another pc in the LAN:
wget http://192.168.0.178/pub
The full error I get is this:
http://192.168.0.178/pub
Connecting to 192.168.0.178:80... connected.
HTTP request sent, awaiting response... 502 Bad Gateway
2018-01-14 15:42:27 ERROR 502: Bad Gateway.
SOLUTION
The accepted answer was indeed the problem I was having.
Another thing I added was a rewrite in my /pub location because '/pub' needs to be cut off from the url going to the Node app. So the final nginx conf looks like this:
http {
access_log /data/access_log.log;
error_log /data/error_log.log debug;
upstream backend {
server localhost:8081;
}
server {
root /data/web;
location / {
}
location /pub {
proxy_pass http://localhost:8081;
rewrite /pub(.*) /$1; break;
}
}
}
The problem seems related to the network interface you are exposing the nodejs app. You have setup the app to listen to port 8081 on the interface with ip 192.168.0.178, but the nginx is proxying trough the loopback interface, given the instruction
proxy_pass http://localhost:8081;
You can solve this issue exposing the nodejs app on the loopback interface:
var server = app.listen(8081, 'localhost');
The node app should be no more reachable directly on port 8081 from any other machine except the one the app is running

Unable to configure Nginx correctly for Node.js app

I am trying to install a react.js app and using pm2 package for running the server.
My /etc/nginx/sites-available/default file's contents are:
server {
listen 80;
server_name my.domain.name;
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';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
My react server is running on port 8080, since when I do curl localhost:8080 from the server, I get the appropriate response. Also, with curl localhost also I get the correct react server's response.
However, when I visit my.domain.name in the browser, I just get the default nginx page saying it's successfully installed.
What am I missing here?
Edit:
Added Reactjs app's server.js file:
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(8080, 'localhost', function (err, result) {
if (err) {
return console.log(err);
}
console.log('Listening at http://localhost:8080/');
});
Your site is available to nginx, but not enabled. So try moving or sym-linking your configuration, i.e. /etc/nginx/sites-available/default, to e.g. /etc/nginx/sites-enabled/your.domain.name and then running
/etc/init.d/nginx restart
Next, the following hint may help further with respect to issues internal to node.
Furthermore, you might benefit from adding the following to your config:
proxy_redirect http://localhost:8080 http://your.domain.name;
When put into sites-enabled my config on DigitalOcean is pretty much the same, but for https, which works just fine.

Resources