Использование Socket.IO с Apache, Node.js, SSL и CloudFlare (HTTP 500) - PullRequest
0 голосов
/ 02 августа 2020

Я создаю веб-сайт, который будет подключаться к Node.js Socket.IO WebSocket. Этот сервер узла работает на порту 4923, а узел Socket.IO настроен на конечной точке /socket. Я хочу подключаться не через https://domain1.com:4932/socket, а через https://domain1.com/socket.io, который указывает на мой Apache Сервер. Брандмауэр блокирует порт 4932, чтобы заблокировать https://domain1.com:4932/socket.

Сервер Apache должен проксировать все соединения от https://domain1.com/socket.io до https://localhost:4932/socket SSL. Сертификат SSL - это сертификат от Let's Encrypt.

Когда создается новое соединение, квитирование SSL между серверами Apache и Node.JS не выполняется.

трафик моего веб-сайта c идет через Cloudflare с активированным полным универсальным SSL.

На виртуальном хосте apache у меня следующая конфигурация:

<VirtualHost  *:443>
        ...

        SSLEngine On
        SSLProxyEngine On

        SSLCertificateFile /etc/letsencrypt/live/domain1.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/domain1.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf      

        # Handle wss proxy connections
        RewriteEngine On
        RewriteCond %{REQUEST_URI}  ^/socket.io             [NC]
        RewriteCond %{QUERY_STRING} transport=websocket     [NC]
        RewriteRule /(.*)           ws://localhost:4923/$1 [P,L]

        # Autogenerated ProxyPass
        ProxyPass        /socket.io http://localhost:4923/socket
        ProxyPassReverse /socket.io http://localhost:4923/socket
        
        ...
</VirtualHost>

Мой node.js сервер через HTTPS:

const port = 4923;

const fs = require('fs');

var options = {
    key: fs.readFileSync('/etc/letsencrypt/live/domain1.com/privkey.pem'),
    cert: fs.readFileSync('/etc/letsencrypt/live/domain1.com/fullchain.pem'),
};

var app = require('https').createServer(options);
var io = require('socket.io')(app, {
    path: '/socket',
    serveClient: false,
    pingInterval: 10000,
    pingTimeout: 5000,
    cookie: false
});

app.listen(port);

io.httpServer.on('listening', function () {
    console.log("Listening on", port);
});

io.on('connect', (socket) => {
    console.log("Socket connected: " + socket.id);
    socket.on('disconnect', () => {
        console.log("Socket disconnected: " + socket.id);
    });
    socket.on('download-request', (id) => {
        onDownloadRequest(socket, id);
    });
});

function onDownloadRequest(socket, id) {
    console.log("Request from " + socket.id + " and video id: " + id);
}

Между тем, на стороне клиента я создаю новое соединение WebSocket при загрузке окна, а затем отправляю сообщение, когда нажимается кнопка.

...
const websocketOptions = {
        server : {
                protocol : 'https://',
                host     : 'domain1.com',
                port     : 443,
                endpoint : '/socket.io'
        }
};

function requestDownload() {
        if (isAnySelected() || socket !== null) {
                console.log(document.getElementsByClassName("download-input-box")[0].value);
                socket.emit('download-request', {id: document.getElementsByClassName("download-input-box")[0].value});
        }
}

function createConnection() {
        console.log("Creating websocket connection!");
        socket = io.connect(websocketOptions.server.protocol
                        + websocketOptions.server.host
                        + ':'
                        + websocketOptions.server.port
                        + websocketOptions.server.endpoint,
                        {transport: 'websocket'});
}

function onWindowLoad() {
        createConnection();
}

window.onload = onWindowLoad;

В результате получается код ответа 500 и это сообщение об ошибке в журнале ошибок apache:

AH00898: Error during SSL Handshake with remote server returned by /socket.io/, referer: https://domain1.com/

Что я делаю не так? Любая помощь приветствуется.

РЕДАКТИРОВАТЬ:

Теперь, когда проблема установления связи SSL была решена, со мной возникла новая проблема. Посмотреть его можно здесь .

1 Ответ

1 голос
/ 04 августа 2020

Вы не можете использовать SSL «localhost», поэтому есть три варианта:

  • Использовать один домен, для которого вы можете запросить SSL

  • Используйте «localhost» с HTTP (не s)

  • Используйте «localhost» с SSL, но отключив «SSLProxyCheckPeerName» в конфигурации Apache2. (См. эту ссылку)

    SSLProxyCheckPeerName off

...