Use case · In-memory data store

Valkey server on bare metal: install, lock down, move Redis data across

A production Valkey server is the valkey-server package (Ubuntu 24.04 carries the 7.2 line, 26.04 the 9.0 line) or an official valkey-io release, held on the loopback address with protected mode on, the passwordless default user switched off in favour of ACL users, a maxmemory ceiling, and RDB snapshots plus an append-only file. Memory sizes the machine. Below: the licence, what carries over from Redis, a gated install, backups, restores and a replication cutover from Redis OSS 7.2 or older.

See the machines

Valkey and its licence

Valkey is a key-value data structure server forked from Redis OSS 7.2.4, and the project is backed by the Linux Foundation. Its README says the fork was taken right before Redis moved to source-available licences. The COPYING file in the valkey-io/valkey repository is the BSD 3-Clause License, with copyright lines for "Valkey contributors" (2024 onward) and Redis Ltd. (2006-2020).

Our general reading, not legal advice: BSD-3-Clause is permissive. Whoever passes copies on, as source or binaries, keeps the copyright notice, the three conditions and the disclaimer with them, and may not use the contributors' names to endorse a derived product. Nothing obliges anyone to publish source, modified or not. Our self-hosted Redis page covers how the Redis releases are licensed, and suits readers staying on Redis.

Valkey against Redis: what carries over

Valkey's migration guide treats a move from Redis OSS 2.x to 7.2.x as an upgrade. Redis Community Edition 7.4 and later is out: its data files cannot be read by Valkey, and the guide offers no path for it. For the OSS releases, this carries over:

AreaValkey and Redis OSS 7.2 or older
Wire protocolRESP2 and RESP3; existing client libraries connect without code changes
RDB and AOF filesRead and written by Valkey
ConfigurationRedis-style directives accepted, plus Valkey-only ones
CLIredis-cli works against Valkey, valkey-cli against Redis OSS
Version stringINFO reports redis_version:7.2.4; server_name and valkey_version give the truth
Lua and modulesthe redis namespace and the RedisModule_ API keep working

Monitoring that reads redis_version gets 7.2.4 back rather than the Valkey release: point it at valkey_version.

Sizing the machine and picking a line

Valkey holds the whole dataset in RAM, so memory comes first. The administration page (marked as under review) says to set maxmemory below what is free (8 or 9 GB on a box with 10 GB free) to leave room for overhead and fragmentation, and warns that a write-heavy instance can use up to twice its normal memory while it saves an RDB or rewrites the AOF. It also asks for vm.overcommit_memory = 1 and transparent huge pages off. The table gives our starting points by job.

Jobmaxmemory-policyPersistenceDisk matters?
Cache in front of a databaseallkeys-lru (the docs' pick when unsure)None: save "" and appendonly noBarely
Sessions, rate limitsvolatile-lru or noevictionRDB snapshotsSome
Queues, primary storenoevictionRDB plus AOF, fsync every secondYes: AOF writes all day

valkey.conf calls the server mostly single threaded. It says I/O threads can roughly double throughput, are worth enabling only under real CPU pressure on three or more cores with one left spare, and suggests 2 or 3 threads on four cores, 6 on eight.

Every line on the dedicated server range is a whole machine with root and an unmetered port. By RAM:

  • Xeon E3-1585L v5 cartridge (m710x): 4 cores at 3 GHz, 16-64 GB, NVMe. Clock suits the mostly single-threaded server. See the NVMe cartridges.
  • Xeon D-1587: 16 cores, 16-128 GB, a 1.92 TB NVMe SSD, for a persistent store with an AOF.
  • Dual-socket Xeon: up to 1 TB, once the dataset outgrows 128 GB; four-socket Xeon Gold: up to 2 TB in one machine.

Console access: each rack server or blade carries iLO, iDRAC or a Supermicro BMC; the m510 and m710x cartridges get a console as well, other cartridges just power control. Rule out the X-Gene ARM line, since its two images (Ubuntu 16.04, 18.04) predate Valkey. A racked machine is handed over in about 30 minutes once payment is approved; a build to order takes 4 to 24 hours.

Install and fence it in

As root on Ubuntu 24.04 (universe carries valkey-server 7.2.x). The block installs the package, stops unless the shipped config still binds 127.0.0.1 -::1 with protected-mode yes, applies the two kernel settings and turns ufw on with SSH only, for IPv4 and IPv6. Images for 24.04 and 26.04 are on the Linux server lines.

apt-get update && apt-get install -y valkey-server valkey-tools ufw \
&& systemctl is-active --quiet valkey-server \
&& [ "$(valkey-cli ping)" = PONG ] \
&& grep -qx 'bind 127.0.0.1 -::1' /etc/valkey/valkey.conf \
&& grep -qx 'protected-mode yes' /etc/valkey/valkey.conf \
&& printf 'vm.overcommit_memory = 1\n' > /etc/sysctl.d/60-valkey.conf \
&& sysctl -q -p /etc/sysctl.d/60-valkey.conf \
&& printf 'w /sys/kernel/mm/transparent_hugepage/enabled - - - - never\n' > /etc/tmpfiles.d/valkey-thp.conf \
&& systemd-tmpfiles --create /etc/tmpfiles.d/valkey-thp.conf \
&& grep -q '\[never\]' /sys/kernel/mm/transparent_hugepage/enabled \
&& sed -i 's/^IPV6=.*/IPV6=yes/' /etc/default/ufw \
&& ufw allow OpenSSH && ufw --force enable \
&& echo "STEP 1 OK" || echo "STOP - step 1 did not finish, read the output above"

The package runs Valkey as user valkey, config /etc/valkey/valkey.conf, data /var/lib/valkey. The tmpfiles line that keeps huge pages off across reboots is our addition; the docs give a one-off echo never. Port 6379 stays shut in ufw and Valkey listens on loopback only. Re-running the block is harmless.

ACL users, a memory ceiling and persistence

Protected mode refuses remote clients only while the default user has no password; any local process can still log in as it. The security page recommends ACL users over requirepass. This block switches default off, creates admin and app with random passwords stored as SHA-256 hashes (the # form of a password rule), sets a 12 GB ceiling with noeviction (our figure for a 32 GB machine, leaving room for the save fork) and enables the AOF. On other sizes, edit 12gb before pasting to roughly three-eighths of RAM, so 6gb for 16 GB or 24gb for 64 GB (our rule of thumb, not the docs'), and change the policy line in local.conf to the table's choice for your job. It refuses to run twice, so the passwords are never replaced by accident, and refuses an instance that already holds keys.

V=/etc/valkey
if [ -e $V/users.acl ] || [ -e /root/valkey-passwords ]; then echo "STOP - already ran"
elif [ "$(valkey-cli dbsize)" != 0 ]; then echo "STOP - instance holds keys or is not answering, see below"
else
  a=$(openssl rand -hex 32); b=$(openssl rand -hex 32)
  ha=$(printf %s "$a" | sha256sum | cut -d' ' -f1); hb=$(printf %s "$b" | sha256sum | cut -d' ' -f1)
  if [ ${#a}${#b}${#ha}${#hb} = 64646464 ]; then
    install -m 600 /dev/null /root/valkey-passwords \
    && printf 'admin %s\napp %s\n' "$a" "$b" > /root/valkey-passwords \
    && install -m 600 -o valkey -g valkey /dev/null $V/users.acl \
    && printf 'user default off\nuser admin on #%s ~* &* +@all\nuser app on #%s ~* &* +@all -@dangerous\n' "$ha" "$hb" > $V/users.acl \
    && install -m 640 -o valkey -g valkey /dev/null $V/local.conf \
    && printf '%s\n' "aclfile $V/users.acl" 'maxmemory 12gb' 'maxmemory-policy noeviction' 'appendonly yes' > $V/local.conf \
    && echo "include $V/local.conf" >> $V/valkey.conf \
    && systemctl restart valkey-server \
    && valkey-cli ping 2>&1 | grep -q NOAUTH \
    && REDISCLI_AUTH=$a valkey-cli --user admin ping | grep -qx PONG \
    && echo "LOCKDOWN OK" || echo "STOP - check journalctl -u valkey-server"
  else echo "STOP - password generation did not work, nothing written"; fi
  unset a b ha hb
fi

Plain passwords sit in /root/valkey-passwords (mode 600); hand the app one to the application's own secret store. -@dangerous denies the app user FLUSHALL, KEYS, CONFIG and the like; add back one command with +command if a library needs it. To start over after a half-run, delete users.acl, local.conf, /root/valkey-passwords and the include line at the end of valkey.conf, then restart. The empty-instance check is there because the persistence page warns that turning the AOF on by editing the file and restarting a populated server can lose data: load existing data after this block, with the steps further down. If a package upgrade asks about valkey.conf, keep your copy.

Backups of the snapshot

The persistence page says copying dump.rdb while the server runs is safe: a snapshot is written under a temporary name and renamed when complete. This hourly job copies it, checks it with valkey-check-rdb, archives /etc/valkey and the password file beside it, and prunes copies older than 48 hours only after a good one exists.

install -d -m 700 /var/backups/valkey && cat > /usr/local/sbin/valkey-backup.sh <<'EOF'
d=/var/backups/valkey; t=$(date +%F-%H%M%S); umask 077
cp /var/lib/valkey/dump.rdb "$d/dump-$t.part" \
 && valkey-check-rdb "$d/dump-$t.part" >/dev/null \
 && mv "$d/dump-$t.part" "$d/dump-$t.rdb" \
 && tar -czf "$d/etc-$t.tar.gz" -C / etc/valkey root/valkey-passwords \
 && tar -tzf "$d/etc-$t.tar.gz" >/dev/null \
 || { echo "STOP - valkey backup FAILED, see $d"; exit 1; }
find "$d" \( -name 'dump-*.rdb' -o -name 'etc-*.tar.gz' \) -mmin +2880 -delete
EOF
printf '%s\n' '17 * * * * root /bin/bash /usr/local/sbin/valkey-backup.sh >> /var/log/valkey-backup.log 2>&1' > /etc/cron.d/valkey-backup \
&& bash /usr/local/sbin/valkey-backup.sh && ls -l /var/backups/valkey

A copy is as fresh as the last save point (by default an hour after one change, five minutes after 100, a minute after 10,000); if the first run finds no dump.rdb, run BGSAVE as admin. Once a day, pull a copy to another machine with plain rsync -a (never --delete) and compare checksums, as the docs advise.

Loading an RDB: a restore or a Redis 7.2 dump

A restore and a file move from Redis OSS 7.2 or older are the same job. With the AOF on, Valkey loads the AOF and ignores a copied RDB, so the AOF goes off for one start. As root, first define the helper with vk() { REDISCLI_AUTH=$(sed -n 's/^admin //p' /root/valkey-passwords) valkey-cli --user admin "$@"; }

  1. Check the file with valkey-check-rdb /root/dump.rdb && echo ok, and stop unless it prints ok.
  2. Snapshot what is there now with bash /usr/local/sbin/valkey-backup.sh && echo ok, and stop unless it prints ok.
  3. Stop the service and turn the AOF off with systemctl stop valkey-server && sed -i 's/^appendonly yes$/appendonly no/' /etc/valkey/local.conf && grep -qx 'appendonly no' /etc/valkey/local.conf && echo ok.
  4. Set the current data aside with [ ! -e /var/lib/valkey.previous ] && mv /var/lib/valkey /var/lib/valkey.previous && install -d -m 750 -o valkey -g valkey /var/lib/valkey && echo ok. If /var/lib/valkey.previous exists from an earlier run, move it elsewhere first.
  5. Copy the file in and start with install -m 640 -o valkey -g valkey /root/dump.rdb /var/lib/valkey/dump.rdb && systemctl start valkey-server && vk INFO keyspace. The key count must match the source's INFO keyspace.
  6. Turn the AOF back on live with vk CONFIG SET appendonly yes, wait until vk INFO persistence shows aof_rewrite_in_progress:0, aof_rewrite_scheduled:0 and aof_last_bgrewrite_status:ok, then sed -i 's/^appendonly no$/appendonly yes/' /etc/valkey/local.conf.
  7. If the count is wrong, undo it with `cd /var/lib && [ ! -e valkey.failed ] && systemctl stop valkey-server && mv valkey valkey.failed && mv valkey.previous valkey && sed -i 's/^appendonly no$/appendonly yes/' /etc/valkey/local.conf && grep -qx 'appendonly yes' /etc/valkey/local.conf && systemctl start valkey-server && vk INFO keyspace; move an old valkey.failed` away first if one exists.

Once everything checks out, delete /var/lib/valkey.previous. Per the migration guide, make a Redis dump with SAVE after disconnecting every client. To move within one machine, run SAVE, copy /var/lib/redis/dump.rdb to /root, stop and disable redis-server (both want port 6379), then run the blocks above and these steps.

Moving a live Redis across with replication

For less downtime, make the new Valkey a replica of the running Redis, then promote it. First confirm redis-cli INFO server on the old box reports redis_version 7.2.x or older, and that maxmemory in local.conf is above the Redis used_memory. The link rides an SSH tunnel under your own login, so neither side opens 6379.

  1. On the Valkey box, open the tunnel with ssh -f -N -o ExitOnForwardFailure=yes -L 127.0.0.1:6380:127.0.0.1:6379 you@old-redis-host.
  2. If Redis has a password, add masterauth (and masteruser for an ACL user; newer valkey.conf files call them primaryauth and primaryuser) to /etc/valkey/local.conf and restart Valkey; the file is mode 640, unlike your shell history.
  3. With the vk helper defined above, run vk REPLICAOF 127.0.0.1 6380. This discards whatever the Valkey instance holds.
  4. Wait for vk INFO replication to show master_link_status:up and master_sync_in_progress:0.
  5. Stop writes in the application, compare INFO keyspace on both sides, then vk REPLICAOF NO ONE, point the application at Valkey with the app user, remove the masterauth lines and close the tunnel. Shut Redis down last.

Ubuntu also ships valkey-redis-compat, which replaces redis-server on the same machine, copies /etc/redis/redis.conf over valkey.conf and /var/lib/redis into Valkey's data directory, and holds the services until you delete /etc/valkey/REDIS_MIGRATION (Ubuntu's README.Debian and the package postinst). It skips the lockdown above, so the RDB route is the cleaner one here.

When one Valkey server is the wrong answer

  • It must outlive the machine. One box is one failure domain; Valkey Sentinel or Valkey Cluster across several machines is the answer.
  • Clients sit on other servers. Valkey traffic, AUTH included, is plain text unless TLS is on, and no private VLAN is sold here, so traffic between our servers crosses the public port. Keep the app on the same box or tunnel it (WireGuard, SSH); opening 6379 takes a bind address, a firewall rule per client IP and TLS together.
  • The data is on Redis CE 7.4 or later. Neither files nor replication cross over.

Questions

Can I run the Valkey server in Docker instead?

Yes: the official image is valkey/valkey on Docker Hub, tagged per release (for example 9.0.7). Its Dockerfile in valkey-io/valkey-container turns protected mode off at build time, so a plain -p 6379:6379 publishes an open server on every host address; on IPv4 published ports skip ufw, and on IPv6 too once Docker's own IPv6 networking is on. Publish -p 127.0.0.1:6379:6379 (local-only on Docker Engine 28+) and mount a config with ACL users.

How do I get Valkey 9 on Ubuntu 24.04?

Ubuntu 24.04's archive carries the 7.2 line. The valkey.io download page publishes x86_64 and arm64 tarballs built for Ubuntu 22.04 and 24.04, each with a SHA-256 checksum to verify, and the repository's utils/systemd-valkey_server.service is the starting point for a unit. You then own the updates. Ubuntu 26.04 packages the 9.0 line directly.

Does protected mode keep Valkey off the internet?

Only partly. It makes a server with no password and the default all-interface bind answer loopback clients only, and an administrator can switch it off. The real fences are the bind line, the firewall and ACL users with long passwords; the security page asks for all three.

Put Valkey on its own machine

Pick a line by memory, take root, and run the three blocks above. The range lists every line with its RAM ceiling, disks and cities.

See the machines

Related on Server Room

Other use cases