Redis is an in-memory data structure store that is commonly used as a database, cache or a message broker. What makes Redis powerful is its optional ability to have data persistence. Therefore your dataset isn’t lost during restarts of the service.
The article below will discuss how to install, configure and provide basic security for Redis. From there, it will go into the basic use cases I use it for on a daily basis, session storing and general caching.
[[email protected] ~]# apt-get update [[email protected] ~]# apt-get install redis-server redis-tools
Redis listens on port 6379 by default and needs some additional configuration to ensure that it is secured. If you do not protect Redis with a firewall, authentication and have it listen only on a private network, there is a extremely high risk of leaking sensitive data.
First, set Redis to only listen on your private network. Redis does not have any type of encryption built in, it is important that the data is transferred only over private networks or secured tunnels. Set Redis to listen on the private interface by:
[[email protected] ~]# vim /etc/redis/redis.conf ... bind redis_servers_private_IP ...
If Redis is being installed on a stand alone web server and will not need to accept connections from other clients, then you can set Redis to listen on the local socket instead by commenting out the bind value and setting up a socket by:
[[email protected] ~]# mkdir /var/run/redis [[email protected] ~]# chown redis:redis /var/run/redis [[email protected] ~]# vim /etc/redis/redis.conf ... # bind 127.0.0.1 unixsocket /var/run/redis/redis.sock unixsocketperm 777
If you do not have a dedicated firewall, use your OS’s built in firewall to only allow in connections from trusted web servers using their internal IP’s. Some quick examples are below:
# iptables [[email protected] ~]# vim /etc/sysconfig/iptables ... -A INPUT -p tcp -m tcp --dport 6379 -s client_server_private_IP -m comment --comment "redis" -j ACCEPT [[email protected] ~]# service iptables restart # ufw [[email protected] ~]# ufw allow from client_server_private_IP/32 to any port 6379
To protect Redis further, setup authentication which is a built in security feature. This will force clients to authenticate before being granted access. Use a tool such as apg or pwgen to create a secure password. Set the password within Redis by:
[[email protected] ~]# vim /etc/redis/redis.conf ... requirepass your_secure_password_here ... [[email protected] ~]# systemctl restart redis
Then test to ensure the password works by:
# This should fail [[email protected] ~]# redis_cli 127.0.0.1:6379> set key1 10 (error) NOAUTH Authentication required. # This should work [[email protected] ~]# redis-cli 127.0.0.1:6379> auth your_secure_password_here 127.0.0.1:6379> set key1 10 OK 127.0.0.1:6379> get key1 "10"
Next, we need to secure the file permissions for Redis. The redis.conf contains the password for redis, so that file shouldn’t be readable by everyone. We also want to lock down the Redis data directory. Lock down the permissions on Redis by:
[[email protected] ~]# chmod 700 /var/lib/redis [[email protected] ~]# chown redis:redis /etc/redis/redis.conf [[email protected] ~]# chmod 600 /etc/redis/redis.conf [[email protected] ~]# systemctl restart redis
The Official Redis Administration Guide recommends to disable Transparent Huge Pages (THP). This can be performed live by:
[[email protected] ~]# echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled [[email protected]01 ~]# echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag
And disable Transparent Huge Pages (THP) at boot time by making a systemd unit file:
[[email protected] ~]# vim /etc/systemd/system/disable-thp.service [Unit] Description=Disable Transparent Huge Pages (THP) [Service] Type=simple ExecStart=/bin/sh -c "echo 'never' > /sys/kernel/mm/transparent_hugepage/enabled && echo 'never' > /sys/kernel/mm/transparent_hugepage/defrag" [Install] WantedBy=multi-user.target [[email protected] ~]# systemctl daemon-reload [[email protected] ~]# systemctl start disable-thp [[email protected] ~]# systemctl enable disable-thp
The Official Redis Administration Guide also recommends setting the following sysctl:
[[email protected] ~]# sysctl vm.overcommit_memory=1 [[email protected] ~]# vim /etc/sysctl.conf ... vm.overcommit_memory = 1 ...
Now that Redis is installed and secured, its time to tune it for your application’s needs. There are typically 2 types of Redis cache configurations I see:
Database cache or full page cache
The session cache allows for a single locations for your application to store sessions that would normally be stored by PHP on the local file system. It is important to ensure that the data is saved to disk so you don’t lose all the sessions between restarts of Redis. This is one of the primary advantages of using Redis over Memcached.
The full page cache is great for caching SQL queries or for serving as a full page cache for applications such as Magento or WordPress, caching images, videos, html, css or js. Generally this type of cache doesn’t need to be persistent across restarts of Redis.
Redis Configurations – Session store
When using Redis as a session store, you want to ensure that the Redis data persists between restarts of Redis. Otherwise your users could be left wondering why their shopping carts all of a sudden vanished. The example below will have disk persistence enabled with a memory limit of 1.5G (1536M).
These settings may or may not work for you! Adjust your settings to meet your environments requirements!
[[email protected] ~]# vim /etc/redis/redis.conf ... ## Ensure disk persistence is enabled save 900 1 save 300 10 save 60 10000 ... ## Set the max memory maxmemory 1536mb ... [[email protected] ~]# service redis restart
Redis Configurations – Database cache or full page cache
When using Redis for database caching or as a FPC for applications like WordPress or Magento, I disable disk persistence. This means the cache will only be stored in memory and lost whenever redis restart. I also set the memory limit to 1.5G (1536M) for starters and adjust accordingly from there. Since I am only storing cached data, I can avoid out of memory issues by allowing Redis to automatically remove the oldest cache entries using the maxmemory-policy allkeys-lru. Read up on the Redis supported eviction policies here.
These settings may or may not work for you! Adjust your settings to meet your environments requirements! Remember, this example assumes everything in Redis can be lost when the service restarts and the eviction policy will remove the least used keys out of all the data. I typically find this works for Magento and WordPress redis setups:
[[email protected] ~]# vim /etc/redis/redis.conf ... ## Disable disk persistence #save 900 1 #save 300 10 #save 60 10000 ... ## Set the max memory maxmemory 1536mb ... ## Update the eviction policy maxmemory-policy allkeys-lru ... [[email protected] ~]# systemctl restart redis
Multiple Redis Configurations
Redis has the ability to utilize multiple caching configurations with their own settings. The only requirement is that each instance of Redis listens on a unique port, has a unique pid, and of course has its own config and startup script. In the example below, we are going to have 2 redis instances running called redis-sessions and redis-cache. To avoid confusion, we will disable the original redis instance.
# Create 2 new configs and modify the values accordingly [[email protected] ~]# cp /etc/redis/redis.conf /etc/redis/redis-session.conf [[email protected] ~]# vim /etc/redis/redis-session.conf ... pidfile /var/run/redis-session.pid port 6379 logfile /var/log/redis/redis-session.log dir /var/lib/redis-session ... # If unixsocket is uncommented, then update to: unixsocket /var/run/redis/redis-session.sock unixsocketperm 777 ... [[email protected] ~]# cp /etc/redis/redis.conf /etc/redis/redis-cache.conf [[email protected] ~]# vim /etc/redis/redis-cache.conf ... pidfile /var/run/redis-cache.pid port 6380 logfile /var/log/redis/redis-cache.log dir /var/lib/redis-cache ... # If unixsocket is uncommented, then update to: unixsocket /var/run/redis/redis-cache.sock unixsocketperm 777 ... # Create directories and secure the permissions [[email protected] ~]# mkdir /var/lib/redis-session /var/lib/redis-cache [[email protected] ~]# chown redis:redis /var/lib/redis-session /var/lib/redis-cache /etc/redis/redis-session.conf /etc/redis/redis-cache.conf [[email protected] ~]# chmod 700 /var/lib/redis-session /var/lib/redis-cache [[email protected] ~]# chmod 600 /etc/redis/redis-session.conf /etc/redis/redis-cache.conf [[email protected] ~]# cd /etc/redis [[email protected] ~]# cp -Rp redis-server.post-down.d redis-session.post-down.d && cp -Rp redis-server.post-up.d redis-session.post-up.d && cp -Rp redis-server.pre-down.d redis-session.pre-down.d && cp -Rp redis-server.pre-up.d redis-session.pre-up.d [[email protected] ~]# cp -Rp redis-server.post-down.d redis-cache.post-down.d && cp -Rp redis-server.post-up.d redis-cache.post-up.d && cp -Rp redis-server.pre-down.d redis-cache.pre-down.d && cp -Rp redis-server.pre-up.d redis-cache.pre-up.d # Create startup files [[email protected] ~]# cp /etc/systemd/system/redis.service /etc/systemd/system/redis-session.service [[email protected] ~]# vim /etc/systemd/system/redis-session.service ... ExecStart=/usr/bin/redis-server /etc/redis/redis-session.conf PIDFile=/var/run/redis/redis-session.pid ExecStartPre=-/bin/run-parts --verbose /etc/redis/redis-session.pre-up.d ExecStartPost=-/bin/run-parts --verbose /etc/redis/redis-session.post-up.d ExecStop=-/bin/run-parts --verbose /etc/redis/redis-session.pre-down.d ExecStopPost=-/bin/run-parts --verbose /etc/redis/redis-session.post-down.d ReadWriteDirectories=-/var/lib/redis-session Alias=redis-session.service ... [[email protected] ~]# cp /etc/systemd/system/redis.service /etc/systemd/system/redis-cache.service [[email protected] ~]# vim /etc/systemd/system/redis-cache.service ... ExecStart=/usr/bin/redis-server /etc/redis/redis-cache.conf PIDFile=/var/run/redis/redis-cache.pid ExecStartPre=-/bin/run-parts --verbose /etc/redis/redis-cache.pre-up.d ExecStartPost=-/bin/run-parts --verbose /etc/redis/redis-cache.post-up.d ExecStop=-/bin/run-parts --verbose /etc/redis/redis-cache.pre-down.d ExecStopPost=-/bin/run-parts --verbose /etc/redis/redis-cache.post-down.d ReadWriteDirectories=-/var/lib/redis-cache Alias=redis-cache.service ... # Stop and disable old instance, start new instances. Error during 'systemctl enable' appears safe to ignore as service still starts on boot. But confirm for yourself! [[email protected] ~]# systemctl daemon-reload [[email protected] ~]# systemctl stop redis.service && systemctl disable redis.service [[email protected] ~]# systemctl enable redis-session.service && systemctl start redis-session.service [[email protected] ~]# systemctl enable redis-cache.service && systemctl start redis-cache.service # Finally, edit the /etc/redis/redis-session.conf and /etc/redis/redis-cache.conf using the instructions earlier in this article for configuring sessions and db cache.
The typical use cases I run into on a day to day basis are clients using Redis for their PHP application. Redis can be used to store cached content, or it can be used to centrally store sessions. Therefore these examples will be PHP focused.
Client setup – General data caching
For storing data, there is nothing that needs to be configured on the client side. The application code itself is what controls storing content within Redis.
Client setup – Storing sessions in Redis
To have Redis act as a central server for sessions, some additional configuration is needed on each client web server. Install php-memcache for your version of PHP. Assuming the default PHP version is installed from the package manager, you can install it by:
[[email protected] ~]# apt-get update [[email protected] ~]# apt-get install php-redis redis-tools [[email protected] ~]# service apache2 graceful [[email protected] ~]# php -m |grep redis
Then update the php.ini as follows:
session.save_handler = redis session.save_path = "tcp://127.0.0.1:6379?auth=your_secure_password_here"
Test to ensure sessions are now being stored in Redis:
[[email protected] ~]# vim /var/www/html/test-sessions.php <?php session_start(); ?> Created a session
Then run the following on the command line and confirm the returned numbers increment as shown below:
[[email protected] ~]# curl localhost/test-sessions.php && redis-cli -a your_secure_password_here keys '*' |grep SESSION | wc -l 10 Created a session 11
Confirm Redis is online:
[[email protected] ~]# redis-cli ping
How to connect using redis-cli when redis is running on a different server or using a different port:
[[email protected] ~]# redis-cli -h ip_of_redis_server -p port_number_here
Sometimes you may need to flush the Redis cache. Before doing this, make sure you are connecting to the right instance of Redis since there could be multiple instances running. An example is below:
[[email protected] ~]# redis-cli -h ip_of_redis_server -p port_number_here FLUSHALL
To get some useful stats on Redis, run:
[[email protected] ~]# redis-cli info
To get memory specific stats, run:
[[email protected] ~]# redis-cli info memory 127.0.0.1:6379> info memory # Memory used_memory:488315720 used_memory_human:465.69M used_memory_rss:499490816 used_memory_peak:505227288 used_memory_peak_human:481.82M used_memory_lua:36864 mem_fragmentation_ratio:1.02 mem_allocator:jemalloc-3.6.0
To increase the memory limit assigned to Redis without restarting the service, the example shown below will increase the memory allocated dynamically from 1G to 2G without a restart of the Redis:
[[email protected] ~]# redis-cli 127.0.0.1:6379> config get maxmemory 1) "maxmemory" 2) "1000000000" 127.0.0.1:6379> config set maxmemory 2g OK 127.0.0.1:6379> config get maxmemory 1) "maxmemory" 2) "2000000000"
Regarding performance issues with Redis, there are a number of factors that need to be account for, too many for this article. Redis published an excellent article that goes into various things that could cause latency with Redis at: