Как использовать самозаверяющий SSL с WebSockets между AngularJS и Raspberry?
У меня есть приложение AngularJS, которое работает на защищенном сервере SSL. Теперь я хочу связаться с RaspberryPI через веб-сокет, чтобы получить потоковые данные. Raspberry не имеет своего собственного веб-сервера (nginx/apache), поэтому я не могу использовать, например, letsencrypt, но только самозаверяющие сертификаты. Проблема в том, что это не работает, и я не смог найти работающее решение (после 6 часов чтения форумов). Вот мой код:
Я создал свой самозаверяющий сертификат через:
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 9999 -nodes
В AngularJS я делаю просто:
const ip = IPADDRESS:9030
connection = new WebSocket('wss://' + ip);
Узловой сервер работает на Raspberry. Это выглядит так:
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) {
...
}
При запуске сервера с node server.js
и запустить мое приложение AngularJS я получаю сообщение об ошибке:
WebSocket connection to 'wss://IPADDRESS:9030/' failed: Error in connection establishment: net::ERR_CERT_AUTHORITY_INVALID
Что я могу сделать, чтобы заставить его работать? Спасибо за вашу помощь!
1 ответ
Что ж, после многих игр и тестирования все выглядит так, что кажется невозможным работать с самозаверяющими сертификатами.
Окончательное решение, которое я использовал сейчас, - это использование Letsencrypt. Вот шаги. Я надеюсь, что кто-то найдет это полезным:
Прежде всего, ваш маршрутизатор должен быть доступен через Интернет. Поэтому HTTP-порт 80 и HTTPS-порт 443 должны быть открыты для перенаправления входящего TCP на Raspberry.
Шаг 1: подготовьте малину и установите nginx
сервер:
sudo apt-get install nginx
sudo /etc/init.d/nginx start
Шаг 2: Установите LETSENCRYPT:
cd ~
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto -d DDNSNAME_ROUTER --redirect -m EMAILADDRESS
В процессе установки вам будут заданы несколько вопросов. Пожалуйста, не забудьте ввести свое DNS-имя для [CN].
Шаг 3: Измените некоторые разрешения, потому что файлы не читаются по умолчанию:
sudu chmod -r 775 /etc/letsencrypt/live
sudu chmod -r 775 /etc/letsencrypt/archive
Шаг 4: Включить автообновление LETSENCRYPT:
./letsencrypt-auto renew
sudo crontab -e
0 0 1 * * /home/pi/letsencrypt/letsencrypt-auto renew
Это оно! Теперь вы можете использовать WebSocket wss://
из вашего приложения Angular/AngularJS.
Узел-сервер, который может обрабатывать запросы HTTP и HTTPS, теперь выглядит следующим образом (мой сервер прослушивает данные на портах 9030 и 9031. Поэтому, пожалуйста, измените их в соответствии с вашими потребностями. В config.json
сохраняются только некоторые переменные.):
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!');
})
})
}
...
Я надеюсь, что это поможет, и вы сэкономили часть своей жизни.
PS: пожалуйста, дайте мне знать, если кто-то нашел решение, чтобы заставить его работать без веб-сервера. Мне не очень нравится подход к установке веб-сервера только для сертификата.