Search code examples
node.jsangularnginxsocket.ioraspberry-pi3

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


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


Solution

  • 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;
            }
        }