Instead of running a single global Redis server, I prefer to use multiple isolated instances. This allows me to precisely limit resources like memory (maxmemory) and apply specific tuning per instance. This approach is fundamental to reliable operation in a shared environment. I used systemd templates to manage this, creating an instance for Amavisd-new as a practical example.
The Standard Approach: Systemd Unit Templates
My initial thought was to build this template manually. However, as I later learned (and document here for transparency), modern distributions often provide this functionality out-of-box.
Lesson Learned (Update 2024-04-15): The file /usr/lib/systemd/system/redis-server@.service often exists and provides this exact functionality, complete with helpful comments. While the manual method described below still works, it’s generally better practice to use the unit file provided by your distribution for easier maintenance.
For reference, here is the robust template I built for Debian Bullseye to manage multi-instance Redis servers using systemd.
Configuring the systemd Unit Template
A unit template is created by adding a file called redis@.service in a systemd path like /usr/local/lib/systemd/system. This template allows you to start services like redis@amavis.service without needing a dedicated file for each.
Unit Section (Security and Dependency)
The [Unit] section establishes dependencies and security preconditions. The AssertPathExists directive is key: it uses the instance name (%i) to ensure the corresponding configuration file exists before attempting to start the service.
[Unit]
Description=Multi-Instance Redis - a fast key value store
Documentation=https://redis.io/documentation man:redis-server(1)
Conflicts=redis-server.service
AssertPathExists=/etc/redis/redis-%i.confService Section (Sandboxing and Resource Isolation)
This service definition is adapted from the Debian default but hardened for multi-instance use. Note the use of %i placeholders for the config and PID files, and the critical sandboxing directives for security. This ensures that each instance is managed individually and reproducibly, a key requirement for resilient service deployment.
[Service]
# Service taken from default debian systemd redis-server.service
# and modified for %i usage
Type=notify
ExecStart=/usr/bin/redis-server /etc/redis/redis-%i.conf --supervised systemd --daemonize no
PIDFile=/run/redis/redis-%i.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=2755
UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWritePaths=-/var/lib/redis
ReadWritePaths=-/var/log/redis
ReadWritePaths=-/var/run/redis
NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".
ProtectSystem=true
ReadWriteDirectories=-/etc/redisInstall Section
The installation definition remains straightforward, ensuring the unit can be enabled by the system target.
[Install]
WantedBy=multi-user.target
Alias=redis.servicePolicy: Per-Instance Configuration
The power of this approach lies in the instance configuration files. We simply include the default settings and override only the parameters necessary for resource management and isolation.
redis-amavis.conf (Amavis Example)
This configuration approach was inspired by the Rspamd documentation, specifically their tutorial detailing Redis replication for Bayesian statistics and fuzzy storage.
include /etc/redis/redis.conf
port 6377
pidfile /run/redis/redis-amavis.pid
logfile /var/log/redis/redis-amavis.log
dbfilename amavis.rdb
dir /var/lib/redis
maxmemory 300MTo add the service to your system, ensure the primary Redis service is disabled to prevent conflicts:
systemctl stop redis
systemctl disable redis
systemctl enable redis@amavis
systemctl start redis@amavisAdding More Instances
Adding new instances (e.g., for SpamAssassin) is now a simple, repeatable task. This ensures quick, reproducible scaling, which is fundamental for reliable operational standards.
Another example, instancename: spamassassin
Don’t forget to change the port in the configuration file.
root@mail:/etc/redis# cp redis-amavis.conf redis-spamassassin.conf
# 1. Edit the new file to change the port and file names
root@mail:/etc/redis# vim redis-spamassassin.conf
# 2. Enable and start the new instance
root@mail:# systemctl enable redis@spamassassin
root@mail:# systemctl start redis@spamassassinFinal Step: Log Rotation
Don’t forget log rotation! You must adjust the logrotate configuration to handle the multiple log files generated by your instances.
root@mail:/etc/logrotate.d# cat redis-server
/var/log/redis/redis-server*.log {
weekly
missingok
rotate 12
compress
notifempty
}See Also
- Rspamd. Bayesian statistics and fuzzy storage replication with multi-instance Redis backend.
https://rspamd.com/doc/tutorials/redis_replication.html - Redis Labs. Redis persistence explained.
https://redis.io/topics/persistence/ - Freedesktop.org. systemd.exec — Execution environment configuration (man page).
https://www.freedesktop.org/software/systemd/man/systemd.exec.html - Freedesktop.org. systemd.unit — Unit configuration (man page).
https://www.freedesktop.org/software/systemd/man/systemd.unit.html - Ales Nosek. Controlling a Multi-Service Application with systemd.
https://alesnosek.com/blog/2016/12/04/controlling-a-multi-service-application-with-systemd/
One thing. You need to daemon-reload systemctl before it works.
Beside that… amazing tutorial… thanks.