Persist the Cache, dammit

I’m trying to get a persistent cache working in a setup for one server with one keycloak instance. I’d like to enable restarts without messing up the users’ sessions.
Anyway, I tried a few things, for example the solution in Persist infinispan cache - #9 by Icatream, I mounted a volume where the ispn cache should get persisted, but nothing shows up there. I left out the jdbc-ping part because I don’t understand how that has anything to do with it.

Anyway I also get the ISPN000569: Unable to persist Infinispan internal caches as no global state enabled Error… Even though I have that global-state block in the /opt/cache-ispn.xml.

I can’t even verify keycloak is using my custom cache-ispn.xml. It doesn’t complain when I put nonsensical stuff in there. I made sure it is exactly in the same location as the default file, and that location is also mentioned in the documentation. My custom file is also not overwritten. It just doesn’t seem to be used, despite trying with and without --cache=ispn and --cache-config-file=/opt/keycloak/conf/cache-ispn.xml. It is highly frustrating…

So what may work as cache-ispn.xml, and this is not optimized or recommended:

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:11.0 http://www.infinispan.org/schemas/infinispan-config-11.0.xsd"
    xmlns="urn:infinispan:config:11.0">

    <cache-container name="keycloak">
        <transport lock-timeout="60000" stack="udp"/>
        <global-state>
            <persistent-location path="/ispn/" />
        </global-state>
        <local-cache name="realms">
            <encoding>
                <key media-type="application/x-java-object" />
                <value media-type="application/x-java-object" />
            </encoding>
            <memory max-count="10000" />
        </local-cache>
        <local-cache name="users">
            <encoding>
                <key media-type="application/x-java-object" />
                <value media-type="application/x-java-object" />
            </encoding>
            <memory max-count="10000" />
        </local-cache>
        <distributed-cache name="sessions" owners="2">
            <persistence>
                <file-store preload="true" fetch-state="true" />
            </persistence>
        </distributed-cache>
        <distributed-cache name="authenticationSessions" owners="2">
            <persistence>
                <file-store preload="true" fetch-state="true" />
            </persistence>
        </distributed-cache>
        <distributed-cache name="offlineSessions" owners="2">
            <persistence>
                <file-store preload="true" fetch-state="true" />
            </persistence>
        </distributed-cache>
        <distributed-cache name="clientSessions" owners="2">
            <persistence>
                <file-store preload="true" fetch-state="true" />
            </persistence>
        </distributed-cache>
        <distributed-cache name="offlineClientSessions" owners="2">
            <persistence>
                <file-store preload="true" fetch-state="true" />
            </persistence>
        </distributed-cache>
        <distributed-cache name="loginFailures" owners="2">
        </distributed-cache>
        <local-cache name="authorization">
            <encoding>
                <key media-type="application/x-java-object" />
                <value media-type="application/x-java-object" />
            </encoding>
            <memory max-count="10000" />
        </local-cache>
        <replicated-cache name="work">
        </replicated-cache>
        <local-cache name="keys">
            <encoding>
                <key media-type="application/x-java-object" />
                <value media-type="application/x-java-object" />
            </encoding>
            <expiration max-idle="3600000" />
            <memory max-count="1000" />
        </local-cache>
        <distributed-cache name="actionTokens" owners="2">
            <encoding>
                <key media-type="application/x-java-object" />
                <value media-type="application/x-java-object" />
            </encoding>
            <expiration max-idle="-1" lifespan="-1" interval="300000" />
            <memory max-count="-1" />
        </distributed-cache>
    </cache-container>
</infinispan>

If running in docker, remember to mount that path as a volume and set the correct privileges. The standard keycloak image sets the user id to ´1000´.