Não consigo fazer com que os websockets funcionem em um backend de nó usando um proxy do apache através de HTTPS para se conectar à instância do nó. Os Websockets estão funcionando corretamente se nenhum proxy HTTP (apache) for usado.
Minha configuração: Eu tenho um servidor apache com vários hosts virtuais. Eu tenho uma página da Web HTTPS para myserver.com e a API HTTPS com node / express / ws no subdomínio api.myserver.com através do proxy, que redireciona as solicitações para a instância node.js (várias instâncias no PM2) em execução na porta 3333 .
Este é o meu host virtual do apache para o subdomínio:
<VirtualHost *:443>
ServerName api.myserver.com
ServerAdmin [email protected]
DocumentRoot /var/www/html/myserver/api
Options -Indexes
SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM
SSLCertificateFile /etc/apache2/certs/STAR_myserver_co.crt
SSLCertificateKeyFile /etc/apache2/certs/myserver_private_key.pem
SSLCertificateChainFile /etc/apache2/certs/STAR_myserver_co.ca-bundle
SSLProxyEngine On
ProxyPreserveHost On
ProxyRequests Off
# This is for websocket requests
ProxyPass /wss/ wss://localhost:3333/
ProxyPassReverse /wss/ wss://localhost:3333/
# This is for normal requests
ProxyPass / https://localhost:3333/
ProxyPassReverse / https://localhost:3333/
</VirtualHost>
Isso funciona bem para redirecionar as conexões para o backend expresso do nó. Eu instalei o mod_proxy, mod_proxy_http e mod_proxy_wstunnel.
Este é o backend da API node.js: primeiro, inicializo express, sessões, etc.
// express, session and mongodb session storage
var express = require('express')
var session = require('express-session')
var MongoStore = require('connect-mongo')(session)
var app = express()
// configure sessionStore and sessions, mongodb, etc...
// Certificates and credentials for HTTPS server
var fs = require('fs')
var privateKey = fs.readFileSync(__dirname + '/certs/myserver_private_key.pem', 'utf8')
var certificate = fs.readFileSync(__dirname + '/certs/myserver_cert.pem', 'utf8')
var ca = fs.readFileSync(__dirname + '/certs/myserver_ca.pem', 'utf8')
var credentials = {key: privateKey, cert: certificate, ca: ca}
app.enable('trust proxy')
app.set("trust proxy", 1)
E então eu configuro o servidor HTTPS com segurança, usando os mesmos certificados do APACHE:
// Setup HTTPS server
var https = require('https')
var server = https.createServer(credentials, app)
server.listen(appPort, 'localhost', function () {
// Server up and running!
var host = server.address().address
var port = server.address().port
console.log('myserver listening at https://%s:%s', host, port)
})
Por último, configuro as conexões do websocket:
// setup Websockets
wss = new WebSocketServer({ server: server })
wss.on('connection', function connection(ws) {
var cookies = cookie.parse(ws.upgradeReq.headers.cookie)
var sid = cookieParser.signedCookie(cookies["connect.sid"], myserver_secret)
// extract user credentials and data from cookie/sid,
// get the session object
sessionStore.get(sid, function (err, ss) {
...
})
})
Então meus clientes tentam se conectar a websockets com segurança (porque, sendo um aplicativo HTTPS, não posso usar a conexão ws: // insecure websockets):
window.WebSocket = window.WebSocket || window.MozWebSocket
webSocket = new WebSocket('wss://' + location.host + '/wss')
E então recebo sempre o mesmo erro 302:
[Error] WebSocket connection to 'wss://api.myserver.com/wss' failed: Unexpected response code: 302
Se eu testar em um servidor local diretamente para a instância do nó link , ele está funcionando perfeitamente e os websockets funcionam como deveriam.
Alguma ideia de como resolver isso? Existe algum problema com os redirecionamentos do ws feitos pelos módulos proxy do Apache?