0

I have an AngularJS application that is running on a SSL secured server. Now I want to contact a RaspberryPI via a websocket to get some stream data. The Raspberry doesn't have it's own webserver (nginx/apache) so i can't use e.g. letsencrypt but self signed certificates, only. The Problem is that it isn't working and I couldn't find a working solution (after spending 6h of reading forums). Here is my code:

I created my self signed certificate via:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 9999 -nodes

In AngularJS I do simple:

const ip = IPADDRESS:9030
connection = new WebSocket('wss://' + ip);

A node server is running on the Raspberry. It looks like this:

const net = require('net');
const fs = require('fs');
const https = require('https');

var options = {
    key:    fs.readFileSync('ssl/key.pem'),
    cert:   fs.readFileSync('ssl/cert.pem'),
    requestCert: false,
    rejectUnauthorized: false
};

//pass in your express app and credentials to create an https server
const httpsServer = https.createServer(options);
      httpsServer.listen(9030);

/**
 *  server
 */
let connections = {};
let WebSocketServer = require('ws').Server;
let wss = new WebSocketServer({server: httpsServer}),

wss.on('connection', function(ws) {
    ...
}

When starting the server with node server.js and start my AngularJS app I get the error message:

WebSocket connection to 'wss://IPADDRESS:9030/' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID

What can I do to get it to work? Thx for your help!

Lars
  • 920
  • 1
  • 14
  • 34

1 Answers1

0

Well, after playing and testing a lot it looks so that it seems to be not possible to work with self signed certificates.

The final solution I used now is using a Letsencrypt. Here are the steps. I hope that someone will find it useful:

First of all your router must have accessible via the internet. Therefore HTTP port 80 and HTTPS port 443 must be open have to forward incoming TCP to your Raspberry.

Step 1: Prepare your Raspberry and install a nginx server:

sudo apt-get install nginx
sudo /etc/init.d/nginx start

Step 2: Install LETSENCRYPT:

cd ~
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt

./letsencrypt-auto -d DDNSNAME_ROUTER --redirect -m EMAILADDRESS

During the installation process you will be asked some questions. Please keep in mind to enter your DNS name for [CN].

Step 3: Change some permissions because the files are not readable by default:

sudu chmod -r 775 /etc/letsencrypt/live
sudu chmod -r 775 /etc/letsencrypt/archive

Step 4: Enable LETSENCRYPT auto-update:

./letsencrypt-auto renew
sudo crontab -e

0 0 1 * * /home/pi/letsencrypt/letsencrypt-auto renew

That's it! Now you can make use of WebSocket wss:// from inside your Angular/AngularJS application.

A node-server that is able to handle HTTP and HTTPS requests looks now like this now (my server listens on port 9030 and 9031 for any data. So please change it to your needs. In config.json some variables are stored, only.):

const net = require('net');
const fs = require('fs');
const https = require('https');
const config = require('./server-config.json');

//
//  SSL SERVER
//
try {
    const privateKey = fs.readFileSync('/etc/letsencrypt/live/' + config.DNSROUTERNAME + '/privkey.pem', 'utf8');
    const certificate = fs.readFileSync('/etc/letsencrypt/live/' + config.DNSROUTERNAME + '/cert.pem', 'utf8');
    const ca = fs.readFileSync('/etc/letsencrypt/live/' + config.DNSROUTERNAME + '/chain.pem', 'utf8');

    const options = {
        key: privateKey,
        cert: certificate,
        ca: ca
    };  

    //pass in your express app and credentials to create an https server
    let httpsServer = https.createServer(options);
        httpsServer.listen(9031);
}
catch (e) {
    console.log("LETSENCRYPT certificates not found! HTTPS server not started!");
    console.log(e)
}

/**
 *
 *  server
 *
 */
let connections = {};
let WebSocketServer = require('ws').Server;

// start WS via HTTP
const wss1 = new WebSocketServer({port: 9030});

wss1.on('connection', function(ws) {
    console.log('connection via HTTP');

    ws.on('close', function () {
        console.log('close HTTP!');
    })
})


// start WS via HTTPS
if (typeof httpsServer !== 'undefined') {
    const wss2 = new WebSocketServer({server: httpsServer});

    wss2.on('connection', function(ws) {
        console.log('connection via HTTPS');

        ws.on('close', function () {
            console.log('close HTTPS!');
        })
    })
}

...

I hope that this will help and you saved some of your lifetime.

P.S.: please let me know if somebody has found a solution to get it to work without a webserver. I don't really like the approach to install a webserver for the certificate only.

Lars
  • 920
  • 1
  • 14
  • 34