How to enable tls for heroku redis node? - node.js

I cannot connect to Heroku Redis using TLS. I tried whats given in heroku docs and the answer on this post How to Connect Heroku Redis TLS Node? but nothing seems to work. My current redis options look like:
const Redis = require('ioredis');
const url = process.env.REDIS_URL;
const options = {
tls: {
rejectUnauthorized: false,
},
};
const opts = new Redis(url, options);
Error that I am getting is
[ioredis] Unhandled error event:Error: connect ETIMEDOUT
at TLSSocket.<anonymous
(/app/node_modules/ioredis/built/redis/index.js:310:37)
at Object.onceWrapper (events.js:421:28)
at TLSSocket.emit (events.js:315:20)
.....
Also what is the difference between REDIS_URL and REDIS_TLS_URL? Which one to use?

REDIS_TLS_URL will have an extra 's' in the scheme of the url -> rediss://password#host:port vs. the REDIS_URL (with a single 's' in it's scheme). The other difference is the port. The TLS port is usually +1 of the regular port. On Heroku Redis version 6, you need to use the REDIS_TLS_URL along with tls option you defined above.
const Redis = require('ioredis');
const url = process.env.REDIS_TLS_URL;
const options = {
tls: {
rejectUnauthorized: false,
},
};
const opts = new Redis(url, options);

Related

socket.io-redis-emitter unable to connect using a redis cluster

I need to extend my socket.io server to multiple machines behind a load balancer (i do have sticky connections enabled on my load balancer, but once I have two machines or more running my client servers start throwing errors), it looks like one of the only ways to do it is with redis, my redis server runs in a cluster... in order to connect to redis as a cluster there is some nuance.
The socket.io/redis-emitter docs only give examples using the createClient connection with redis, while the redis library itself provides a cluster mode which I have included details of below
It looks like socket.io/redis-emitter and #socket.io/redis-adapter are both incompatible with using createCkuster in the redis library
I am getting the following error:
Error: Cluster is not connected
at RedisClusterSlots._RedisClusterSlots_getRandomClient (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/cluster/cluster-slots.js:193:15)
at RedisClusterSlots.getClient (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/cluster/cluster-slots.js:54:120)
at Commander._RedisCluster_execute (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/cluster/index.js:102:73)
at Commander.sendCommand (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/cluster/index.js:65:98)
at Commander.commandsExecutor (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/cluster/index.js:62:75)
at Commander.BaseClass.<computed> [as publish] (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#redis/client/dist/lib/commander.js:8:29)
at BroadcastOperator.emit (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/#socket.io/redis-emitter/dist/index.js:262:26)
at Socket.<anonymous> (/Users/aronlilland/Documents/dev/controlair/notifications/src/sockets/index.js:61:36)
at Socket.emit (node:events:527:28)
at Socket.emitUntyped (/Users/aronlilland/Documents/dev/controlair/notifications/node_modules/socket.io/dist/typed-events.js:69:22)
// mock example
const { createCluster } = require('redis')
const { Emitter } = require('#socket.io/redis-emitter')
const { Server } = require('socket.io')
const app = express()
const server = require('http').Server(app)
const log = require('../logger')('cache:client')
const rootNodes = [
{ url: `redis://${process.env.REDIS_HOST_1}` },
{ url: `redis://${process.env.REDIS_HOST_2}` },
{ url: `redis://${process.env.REDIS_HOST_3}` }
]
const client = createCluster({ rootNodes })
client.on('error', err => log.error(`Redis Cluster Error ${err}`))
const emitter = new Emitter(client)
// ...
const io = new Server(server)
io.on('connection', socket => {
socket.on('event', event => {
emitter.in('room1').emit('<some event>', event)
})
})
im using node v16.15.0
redis (running as a cluster) is v6.2.6
redis (node library) v4.1.0
socket.io/redis-emitter v4.1.1

Problems with migrating to Redis 4.x in Node

I am trying to migrate my google cloud app engine from Redis 3.x to 4.x. However, it appears that there have been some major changes in Redis 4.x. It appears that the client no longer autoconnect and there have been some chnages to the syntax. Here's what I have run
'use strict';
import {createClient} from 'redis';
// These are just values stored in environment variables.
const REDISHOST = process.env.REDIHOST;
const REDISPORT = process.env.REDIPORT;
const REDISAUTH = process.env.REDISAUTH;
const redisClient.createClient();
redisClient.host = REDISHOST;
redisClient.port = REDISPORT;
redisclient.auth = REDISAUTH;
redisClient.on('error', (err) => console.error(`##### REDIS ERR: ${err}.`));
await redisClient.connect();
I can tell that host, port, and auth is being set in redisClient, but when I connect, it tries to connect to localhost and fails. Any idea what I am missing here?
You need to pass the connection information in the call the createClient():
const redisClient = createClient({
socket: {
host: REDISHOST,
port: REDISPORT
},
password: REDISAUTH
})
There are lots of options for connecting. They are all detailed in the client configuration guide.

Redis Connection Error with Heroku Redis Instance: Redis connection to failed - read ECONNRESET heroku instance

I have a node js app. And I use Redis from Heroku Redis(with async-redis library).
Actually, I have two different Heroku accounts and two different Node.js apps hosted by Heroku. But except Redis credentials, both apps are the same code.
The interesting thing on my app I can connect to first Heroku Redis instance. But I can't connect to new Heroku Redis instance. Besides I deleted and created new instances, bu they don't work.
The error is:
Error: Redis connection to redis-123.compute.amazonaws.com:28680 failed - read ECONNRESET\n
at TCP.onStreamRead (internal/stream_base_commons.js:162:27)
My connection statement like this:
var redisPassword = 'password123';
var redisOptions = { host: 'redis-123.cloud.redislabs.com', port: '17371', auth_pass: redisPassword }
//var redisPassword = 'password123';
//var redisOptions = { host: 'redis-123.compute.amazonaws.com', port: '28680', auth_pass: redisPassword }
const client = redis.createClient(redisOptions);
client.on('connect', function () {
console.log('Redis client connected');
});
client.on('error', function (err) {
console.log('An error on Redis connection: ' + err);
});
As I can see there is the only thing that different on Heroku Redis instances. My first Redis instance hosts at cloud.redislabs.com but the second instance(that i can't connect) hosts at compute.amazonaws.com.
Any help will be much appreciated.
I encountered this situation and it turned out the with "Heroku Redis" connecting via TLS worked (the url that starts with rediss) once I adjusted my client code to connect following the example provided in the Heroku redis docs:
https://devcenter.heroku.com/articles/connecting-heroku-redis#ioredis-module
const Redis = require("ioredis");
const client = new Redis(process.env.REDIS_URL, {
tls: {
rejectUnauthorized: false
}
});
Where process.env.REDIS_URL is rediss://<details>
I couldn't find the root problem. But after comment of Chris, I checked again Heroku Redis addons I used.
Heroku Redis gives me an instance from amazonaws.com, and Redis Enterprise Cloud gives me an instance from redislabs.com. When I added and used Redis Enterprise Cloud, I could connect to it.
But Heroku Redis's connection problem still is a secret for me.

Redis Cloud and connect-redis: the client is closed

I currently build a website using Express and want to use redis cloud database to save userID in session. The redisClient is created in redisClient.js and after that i pass it to redisStore in session in app.js. Here is the code:
redisCLient.js
const redis = require("redis");
let redisClient = redis.createClient({
host: process.env.REDIS_HOSTNAME,
port: parseInt(process.env.REDIS_PORT),
password: process.env.REDIS_PASSWORD
});
redisClient.on('error', function(err) {
console.log('*Redis Client Error: ' + err.message);
});
redisClient.on('connect', function(){
console.log('Connected to redis instance');
});
(async () => {
await redisClient.auth(process.env.REDIS_PASSWORD)
.catch(err => {console.log('Redis auth error: ' + err.message)});
await redisClient.connect()
.catch(err => {console.log('Redis connect error: ' + err.message)});
})();
module.exports = redisClient;
app.js
const session = require("express-session");
const redisStore = require('connect-redis')(session);
const redisClient = require('./session-store/redisClient');
...
app.use(cookieParser());
app.use(session({
store: new redisStore({client: redisClient, ttl: 3600 * 24 * 30}),
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
resave: false
}));
The problem is: upon starting the server i got error messages log in console like this:
Redis auth error: The client is closed
*Redis Client Error: connect ECONNREFUSED 127.0.0.1:6379
*Redis Client Error: connect ECONNREFUSED 127.0.0.1:6379
*Redis Client Error: connect ECONNREFUSED 127.0.0.1:6379
*Redis Client Error: connect ECONNREFUSED 127.0.0.1:6379
...
I used this guide to set up redis cloud and assign dotenv variables (host, port and password). I have debugged and the dotenv is working fine and I have host, port and password variables correct.
But the problem still remains. I still get The client is closed and connect ECONNREFUSED 127.0.0.1:6379 error as in console log above. How can i fix this?
was stuck on same issue and found some luck. have used 'ioredis' module instead of redis which worked seamlessly.
const redis = require('ioredis');
const redisClient = redis.createClient({host:'your host address',port:your port,username:'',password:''});
redisClient.on('connect',() => {
console.log('connected to redis successfully!');
})
redisClient.on('error',(error) => {
console.log('Redis connection error :', error);
})
module.exports = redisClient;
When you create a client using redis.createClient, you need to use url instead of host, port.
refer to basic-example
it showing url format
redis[s]://[[username][:password]#][host][:port][/db-number]
in your case, it might be like this
var url = `redis://<YourUsername>:${process.env.REDIS_PASSWORD}#${process.env.REDIS_HOSTNAME}:${parseInt(process.env.REDIS_PORT)}`
redis.createClient({
url: url
});
Using host, port option must be the old version.
Option 1: switch the order of the calls to auth and connect
From the Node Redis client documentation:
When connecting to a Redis server that requires authentication, the AUTH command must be sent as the first command after connecting.
You should therefore switch the order of the calls to redisClient.auth and redisClient.connect.
Option 2: remove the call to auth
However, the documentation for the password property of createClient options states:
If set, client will run Redis auth command on connect.
As you are supplying password to createClient, you could alternatively just remove the explicit call to auth.
You must do await redisClient.connect() before you access the client. Try to move your redisClient.connect() just after you create it.
try this -->
var options = {
client: redis.createClient({
url : process.env.REDIS_URL,
legacyMode: true,
})};
you can make your url as 'redis://host:port'
import { createClient } from "redis";
const redisClient = createClient({
url: "redis://localhost:6379",
});
const start = async () => {
await redisClient.connect();
};
start();
export default redisClient;

How to make 2 nodejs servers connect with SSL websocket?

I am trying to make 2 servers communicate via socket.io library and SSL.
This used to work until an upgrade of socket.io package (can't tell you which).
I have managed to fix secure connection with a browser. I have also made it work between unsecure (http) servers. But the secure (https) servers refuse to connect between themselves. You may argue that socket.io is not made for server to server communications, but it would save me lots of work to fix it.
I am now running:
node: 7.5.0
express: 4.16.2
socket.io (and socket.io-client): 2.0.3
I cannot even make simple examples below work (removing all my middleware).
node server
// Use SSL certificate
const cert_path = "..";
const fs = require('fs');
const https_options = {
key: fs.readFileSync(cert_path+'/privkey.pem'),
cert: fs.readFileSync(cert_path+'/cert.pem')
};
const app = require('express')();
const https = require('https');
const server = https.createServer(https_options, app);
const io = require('socket.io')(server);
server.listen(8000);
io.on('connection', function (socket) {
console.log("connected");
});
node client
const io = require('socket.io-client');
const socket = io.connect(
'https://localhost:8000',
{secure: true}
);
socket.on("connect", function () {
console.log("connected");
});
Nothing happens, none of them connect. Any idea why?
EDIT: I'm getting both connect_error and reconnect_error that pop every 5s on client side:
{ Error: xhr poll error
at XHR.Transport.onError (../node_modules/engine.io-client/lib/transport.js:64:13)
at Request.<anonymous> (../node_modules/engine.io-client/lib/transports/polling-xhr.js:128:10)
at Request.Emitter.emit (../node_modules/component-emitter/index.js:133:20)
at Request.onError (../node_modules/engine.io-client/lib/transports/polling-xhr.js:310:8)
at Timeout._onTimeout (../node_modules/engine.io-client/lib/transports/polling-xhr.js:257:18)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5) type: 'TransportError', description: 503 }
Digging further in the errors, I see it may come from the certificate. But while I apply several workarounds of SO, I'm getting consecutively ECONNREFUSED, UNABLE_TO_VERIFY_LEAF_SIGNATURE, and finally DEPTH_ZERO_SELF_SIGNED_CERT...
After trying hard:
re-generate my Let's Encrypt certificate
re-generate my self-signed certificates (openssl) and use them by server+client
tinker with socket.io connect options (secure, rejectUnauthorized, ..)
tinker with nodejs global setup even (process.env['NODE_TLS_REJECT_UNAUTHORIZED'])
I finally stumbled on this page of github. It solved my issue and it's worth sharing it.
node client
const https = require('https');
https.globalAgent.options.rejectUnauthorized = false;
const io = require('socket.io-client');
const sockets = io.connect('https://localhost:8001', {agent: https.globalAgent});
Even if I would have preferred getting my connection authorized in the first place, this will work for me.

Resources