Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel + Redis Cache via SSL?

I am trying to connect to Redis with predis 1.1 and SSL, using information https://github.com/nrk/predis, where in the example the following configuration is used:

// Named array of connection parameters:
$client = new Predis\Client([
  'scheme' => 'tls',
  'ssl'    => ['cafile' => 'private.pem', 'verify_peer' => true],
]);

My Laravel configuration looks like below:

'redis' => [
        'client' => 'predis',
        'cluster' => env('REDIS_CLUSTER', false),

        'default' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'options' => [
            'cluster' => 'redis',
            'parameters' => ['password' => env('REDIS_PASSWORD', null)],
            'scheme' => 'tls',
        ],
    ],

Unfortunately I am getting the following error:

ConnectionException in AbstractConnection.php line 155:
Error while reading line from the server. [tcp://MY_REDIS_SERVER_URL:6380]

Suggestions are appreciated :)

like image 278
Lech Migdal Avatar asked Jan 20 '17 11:01

Lech Migdal


People also ask

How does Redis Cache work laravel?

Laravel supports the use of Redis, which uses caches for temporary data storage to speed up the process of performing database queries and getting feedback, which will, in turn, reduce the amount of time spent pulling up data.

How does Redis integrate with laravel?

Redis in Laravel In order to use Redis with Laravel, firstly yo will have to install the predis/predis package. You can install it via composer. Just run this command and you're done. Apart from this, you can also install php redis, a php extension via PECL.

Does Redis support TLS?

By default, Redis uses mutual TLS and requires clients to authenticate with a valid certificate (authenticated against trusted root CAs specified by ca-cert-file or ca-cert-dir ). You may use tls-auth-clients no to disable client authentication.


1 Answers

I was able to get it to work!

You need to move 'scheme' from 'options' to 'default':

My working config:

'redis' => [
    'client' => 'predis',
    'cluster' => env('REDIS_CLUSTER', false),

    'default' => [
        'scheme' => 'tls',
        'host' => env('REDIS_HOST', 'localhost'),
        'password' => env('REDIS_PASSWORD', null),
        'port' => env('REDIS_PORT', 6379),
        'database' => 0,
    ],

    'options' => [
        'parameters' => ['password' => env('REDIS_PASSWORD', null)],
    ],
],

Note: I had also removed the 'cluster' option from 'options', but I don't suspect this to be the make-or-break with this problem.

In my final-final config, I changed it to: 'scheme' => env('REDIS_SCHEME', 'tcp'), and then defined REDIS_SCHEME=tls in my env file instead.

Tested with AWS ElastiCache with TLS enabled.

Edit: The above config only works with single-node redis. If you happen to enable clustering and TLS then you'll need a different config entirely.

'redis' => [
        'client' => 'predis',
        'cluster' => env('REDIS_CLUSTER', false),

        // Note! for single redis nodes, the default is defined here.
        // keeping it here for clusters will actually prevent the cluster config
        // from being used, it'll assume single node only.
        //'default' => [
        //    ...
        //],

        // #pro-tip, you can use the Cluster config even for single instances!
        'clusters' => [
            'default' => [
                [
                    'scheme'   => env('REDIS_SCHEME', 'tcp'),
                    'host'     => env('REDIS_HOST', 'localhost'),
                    'password' => env('REDIS_PASSWORD', null),
                    'port'     => env('REDIS_PORT', 6379),
                    'database' => env('REDIS_DATABASE', 0),
                ],
            ],
            'options' => [ // Clustering specific options
                'cluster' => 'redis', // This tells Redis Client lib to follow redirects (from cluster)
            ]
        ],
        'options' => [
            'parameters' => [ // Parameters provide defaults for the Connection Factory
                'password' => env('REDIS_PASSWORD', null), // Redirects need PW for the other nodes
                'scheme'   => env('REDIS_SCHEME', 'tcp'),  // Redirects also must match scheme
            ],
        ]
    ]

Explaining the above:

  • 'client' => 'predis': This specifies the PHP Library Redis driver to use (predis).
  • 'cluster' => 'redis': This tells Predis to assume server-side clustering. Which just means "follow redirects" (e.g. -MOVED responses). When running with a cluster, a node will respond with a -MOVED to the node that you must ask for a specific key.
  • If you don't have this enabled with Redis Clusters, Laravel will throw a -MOVED exception 1/n times, n being the number of nodes in Redis cluster (it'll get lucky and ask the right node every once in awhile)
  • 'clusters' => [...] : Specifies a list of nodes, but setting just a 'default' and pointing it to the AWS 'Configuration endpoint' will let it find any/all other nodes dynamically (recommended for Elasticache, because you don't know when nodes are comin' or goin').
  • 'options': For Laravel, can be specified at the top-level, cluster-level, and node option. (they get combined in Illuminate before being passed off to Predis)
  • 'parameters': These 'override' the default connection settings/assumptions that Predis uses for new connections. Since we set them explicitly for the 'default' connection, these aren't used. But for a cluster setup, they are critical. A 'master' node may send back a redirect (-MOVED) and unless the parameters are set for password and scheme it'll assume defaults, and that new connection to the new node will fail.
like image 73
CenterOrbit Avatar answered Sep 20 '22 14:09

CenterOrbit