Pogocache instead of redis

Hi! Perhaps you have heard about new caching service pogocache, which has better performance, see GitHub - tidwall/pogocache: Fast caching software with a focus on low latency and cpu efficiency..

Looking at the benchmarks which show much better improvements I am thinking is it possible to replace redis with it? If yes, how to do it in a right way?

1 Like

Never heard of this before, but I thought why not test this on one of my test intstances. :slight_smile:

I only did a simple setup and didn’t do extensive testing because I don’t plan to use this on my production instance just yet. However, it seems to work as a drop-in replacement. Or, at least, Nextcloud did not return an internal server error, and notify_push, which depends on the Redis service, seems to work as well.

Here’s what I did:

I started the Docker container with the command from here: https://github.com/tidwall/pogocache#getting-started

docker run --net=host pogocache/pogocache

In config.php, I commented out the lines for Redis, and instead added two lines to connect to Pogocache, which by default listens on port 9401:

 'redis' => 
  array (
    'host' => '127.0.0.1',
    'port' => 9401,
//    'host' => '/var/run/redis/redis-server.sock',
//    'port' => 0,
//    'dbindex' => 1,
//    'timeout' => 0.5,
//    'password' => 'supersecretpassword',
  ),

Of course, you should probably dig deeper into how to run Pogocache securely — for example with a WebSocket connection and/or password protection — before putting it into production. It’s also a good idea to do some more extensive testing first, to avoid any unforeseen side effects with a 1.0 product, where there’s practically no real-world experience yet with how it behaves together with Nextcloud in a production envirement.

3 Likes

Hi! Many thanks for so prompt reply and mentioning security issues. I will test it as well, though mostly I prefer to use caching via sockets, not networks.

A socket can be enabled: https://pogocache.com/docs/configuration

I tested this briefly, and it works:

docker run -v /var/run/pogo:/var/run/pogo --name=pogocache -d pogocache/pogocache -p 0 -s /var/run/pogo/pogo-server.sock
  'redis' => 
  array (
    'host' => '/var/run/pogo/pogo-server.sock',
    'port' => 0,
  ),

and then:

chmod 777 /var/run/pogo/pogo-server.sock

Obviously you shouldn’t chmod 777 it on a production server, but for the sake of a quick test, I didn’t want to mess around with users/groups and permissions. :wink:

1 Like

Oh, nice. Meanwhile, have you found how to limit it to a specific user with a password? As far as I understand, that should be www-data user and the password should be stored in this config file?

How to set a password is in the docs I linked in my previous post. Just add --auth to the start parameters:

docker run \
  -v /var/run/pogo:/var/run/pogo \
  --name=pogocache -d pogocache/pogocache \
  -p 0 -s /var/run/pogo/pogo-server.sock --auth supersecretpassword

config.php:

  'redis' => 
  array (
    'host' => '/var/run/pogo/pogo-server.sock',
    'port' => 0,
    'password' => 'supersecretpassword'
  ),

Regarding the permissions, something like this on the host should work:

groupadd pogocache
usermod -aG pogocache www-data
chown root:pogocache /var/run/pogo/pogo-server.sock
chmod 660 /var/run/pogo/pogo-server.sock

But obviously this still isn’t ideal, because every time the container restarts you have to reapply the permissions to /var/run/pogo/pogo-server.sock.

That said, I should mention that I don’t run Nextcloud via Docker, and I’m not a Docker expert either. So I’m not sure what other (and better) ways there might be to expose the socket to a non-root user on the host, or in other containers, and whether that’s even possible without building a custom image. But this is probably something you could ask the Pogocache developer directly… https://github.com/tidwall/pogocache/issues

1 Like

Many thanks for your nice description. I’ve tested it myself, actually due to the lack of monitoring tools in pogo I cannot compare it with redis. What I understand the project is in the active phase of development and is not so ready for production.

During the test I’ve found that it is possible to use password to protect the caching server. That was not covered well in Nextcloud manuals. So, the question for you, do you use protection redis installations? If yes, then which ones and how?

You can set a password in the redis.conf file. On Debian/Ubuntu based systems it’s located in /etc/redis/:

Change the line…

# requirepass foobared

to

requirepass yoursupersecretpassword

Since Redis 6 they also have an ACL system where you can setup different users with different permissions, but that would be overkill for this usecase, where Redis is running on the same host Nextcloud, imho. :wink:

1 Like

Simply pass the verbose flag -vvv

Based on my tests with Pogocache and Nextcloud:

Pogocache implements basic Redis commands like GET, SET, and DEL, and it works for simple caching. However, it does not support advanced Redis features that Nextcloud relies on, such as Lua scripting (EVAL/EVALSHA), file locking, and certain atomic operations (e.g., UNLINK, DECRBY).

As a result, Pogocache cannot fully replace a production Redis server for Nextcloud, because critical features like file locking and distributed mutexes will fail. It can still be useful as a supplementary cache layer (for previews, sessions, or temporary data), but the main Redis instance must remain for core Nextcloud functionality.

h.t.h.


ernolf

4 Likes

Example log output:

. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/33f6652c3d66ce470d3b4ace0fe7fda4] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/33f6652c3d66ce470d3b4ace0fe7fda4] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/33f6652c3d66ce470d3b4ace0fe7fda4] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/33f6652c3d66ce470d3b4ace0fe7fda4] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/19fbabfc4fbc7f3d35cb1a11f2d86d93] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/19fbabfc4fbc7f3d35cb1a11f2d86d93] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/19fbabfc4fbc7f3d35cb1a11f2d86d93] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/19fbabfc4fbc7f3d35cb1a11f2d86d93] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/0ed3cc07138a30c208d9242ff78a590d] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/0ed3cc07138a30c208d9242ff78a590d] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/0ed3cc07138a30c208d9242ff78a590d] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/0ed3cc07138a30c208d9242ff78a590d] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/5f18aa1f148bc10c56278460cf1d63f0] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/5f18aa1f148bc10c56278460cf1d63f0] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/5f18aa1f148bc10c56278460cf1d63f0] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/5f18aa1f148bc10c56278460cf1d63f0] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/050e1035041896ae2edd2d07bafb1e95] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/050e1035041896ae2edd2d07bafb1e95] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/050e1035041896ae2edd2d07bafb1e95] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/050e1035041896ae2edd2d07bafb1e95] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/4b37a8e2847e0f3d2ec9079d31775fe5] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/4b37a8e2847e0f3d2ec9079d31775fe5] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/4b37a8e2847e0f3d2ec9079d31775fe5] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/4b37a8e2847e0f3d2ec9079d31775fe5] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [cf0e94b2e9ffc7e04395cf88f7583fc309985910] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/e6d65130645b735ac835199c9f81b247] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/e6d65130645b735ac835199c9f81b247] [1]
# Unknown command 'EVAL'
. . [EVALSHA] [720b40cb66cef1579f2ef16ec69b3da8c85510e9] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/e6d65130645b735ac835199c9f81b247] [1]
# Unknown command 'EVALSHA'
. . [EVAL] [if redis.call("exists", KEYS[1]) == 1 then return redis.call("decrby", KEYS[1], ARGV[1]) else return "NEX" end] [1] [dbd2bc3787d12a7c0af9ec31d6329153/lockfiles/e6d65130645b735ac835199c9f81b247] [1]
# Unknown command 'EVAL'

ernolf

1 Like

@ernolf Thanks for this overview. In my tests I haven’t covered lua scripting, that is important for me to certain extent… So, still not a case.

Thanks for your test.

My conclussion from this: Forgetting about it for now, and perhaps looking at it again at some point in the future. :wink:

Yeah, I’m not going down that rabbit hole, and I’ll just keep using APCu/Redis as recommended in the documentation. Still, looks like an interesting project, and who knows what the future holds. :slight_smile:

1 Like

When Redis switched to a more restrictive license in March 2024, it sent shockwaves through the FOSS world, as so many projects rely on it.

Naturally, a free fork → redict ← based on Redis®* OSS 7.2.4 was released immediately, hosted on codeberg. Anyone who cared about the license could simply switch to Redict. (And many did!)

But since May 2025, starting with Redis 8, a new product Redis Open Source licensed under the GNU Affero General Public License (AGPLv3) was launched:



So, switching to forks solely for licensing reasons should no longer be necessary.


ernolf

1 Like

The most well-established fork is probably Valkey, which is under the umbrella of the Linux Foundation and is now also available in the Debian repositories: https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=valkey.

Also, Valkey (and probably Redict as well) can be used as a drop-in replacement. Personally, I never switched and just kept using the Redis packages from the Debian 12 and Ubuntu 24.04 repos, which, as far as I know, still ship the versions from before they pulled that stunt. :wink:

Yes, they were probably afraid that others would eat their lunch, just as MariaDB did with MySQL. :wink: