Exporting keycloak realms

I want to backup my keycloak realms.
I installed keycloak using the keycloak.nix module.
To export my keycloak realms, I thought I could launch keycloak with the following options:

-Dkeycloak.migration.action=export
-Dkeycloak.migration.provider=singleFile
-Dkeycloak.migration.file=/tmp/kcdump.json

However, (1) when I do it from the command line as follows:

sudo systemctl stop keycloak
nix-shell -p keycloak
sudo kc.sh start -Dkeycloak.migration.action=export -Dkeycloak.migration.provider=singleFile -Dkeycloak.migration.file=/tmp/kcdump.json

I get the following error:


ERROR: The 'providers' directory does not exist or is not a valid directory.

And (2), when I try to do it via the configuration.nix file as follows:

  services.keycloak = {
    enable = true;
    settings = {
      hostname = "keycloak.myhost.name";
      http-host = "127.0.0.1";
      http-port = 3002;
      http-relative-path = "/";
      proxy = "edge";
      http-enabled = true;
      hostname-strict-backchannel = true;
      keycloak.migration.action = "export";
      keycloak.migration.provider = "singleFile";
      keycloak.migration.file = "/tmp/kcdump.json";
    };

I get the following error when I nixos-rebuild switch:

error: A definition for option `services.keycloak.settings.keycloak.migration' is not of type `path'. Definition values:

Does it ring a bell?

Hi there, I was able to export the realms last week using following systemd service. Export could only be done when keycloak is stopped. Your export result would be under /var/lib/keycloak

      systemd.services.keycloakExportRealms =
        let p = config.systemd.services.keycloak;
        in mkIf config.services.keycloak.enable {
              after = p.after;
              before = [ "keycloak.service" ];
              wantedBy = [ "multi-user.target" ];
              environment = mkForce p.environment;
              serviceConfig =  let origin = p.serviceConfig; in {
                  Type = "oneshot";
                  RemainAfterExit = true;
                  User = origin.User;
                  Group = origin.Group;
                  LoadCredential = origin.LoadCredential;
                  DynamicUser =  origin.DynamicUser;
                  RuntimeDirectory = origin.RuntimeDirectory;
                  RuntimeDirectoryMode = origin.RuntimeDirectoryMode;
                  AmbientCapabilities = origin.AmbientCapabilities;
                  StateDirectory = "keycloak";
                  StateDirectoryMode = "0750";
              };
              script = ''
                    ${strings.removeSuffix "kc.sh start --optimized\n" config.systemd.services.keycloak.script}
                     EDIR="/var/lib/keycloak"
                     EDIRT="$EDIR/$(date '+%Y/%m/%d/%H:%M:%S')"
                     mkdir -p $EDIRT
                     kc.sh export --optimized --dir=$EDIRT
                '';
      };
1 Like

Thanks anpin!

Super cool! I was able to backup then restore a realm :slight_smile:

I have a couple of questions:

  • What is the purpose of the EDIR variable? Does it specify the current directory for the execution of the kc.sh script? Is it what fixed the problem with the ‘providers’ directory?
  • Why do you set RemainAfterExit = true?
  • I inserted your code in my configuration.nix (even though I use flakes). Is that the correct place? I had to replace e.g. mkIfwith lib.mkIf, is that OK?
  • Is the following the correct way to trigger a backup?
    • sudo systemctl stop keycloak
    • sudo systemctl start keycloakExportRealms
    • sudo systemctl start keycloak
  • When i execute nixos-rebuild switch, I get the following error (which occurs only if keycloak has been started). How can I fix that? (As a workaround, I simply stop keycloak before nixos-rebuilding.)
warning: the following units failed: keycloakExportRealms.service

× keycloakExportRealms.service
     Loaded: loaded (/etc/systemd/system/keycloakExportRealms.service; enabled; preset: enabled)
     Active: failed (Result: exit-code) since Sun 2023-12-31 11:51:12 CET; 1s ago
    Process: 28024 ExecStart=/nix/store/wanc8fj6j6hax7vyhn5rf0953c3rh107-unit-script-keycloakExportRealms-start/bin/keycloakExportRealms-start (code=exited, status=1/FAILURE)
   Main PID: 28024 (code=exited, status=1/FAILURE)
         IP: 0B in, 0B out
        CPU: 6ms

déc. 31 11:51:12 killy systemd[1]: Starting keycloakExportRealms.service...
déc. 31 11:51:12 killy keycloakExportRealms-start[28035]: ln: failed to create symbolic link '/run/keycloak/themes/kv1khfgvvp8avp3r8q9jac5rlrjh0f0y-keycloak-themes': Read-only file system
déc. 31 11:51:12 killy systemd[1]: keycloakExportRealms.service: Main process exited, code=exited, status=1/FAILURE
déc. 31 11:51:12 killy systemd[1]: keycloakExportRealms.service: Failed with result 'exit-code'.
déc. 31 11:51:12 killy systemd[1]: Failed to start keycloakExportRealms.service.
warning: error(s) occurred while switching to the new configuration

Glad you found it helpful as this was a result of multiple hours of research into how keycloak works and how it is packaged for nixos. Later I faced some issues and decided to abandon any further attempts to use it, so it is good to feel that my efforts were not wasted :slight_smile:

  • EDIR simply points to the StateDirectory of the export service. Providers are symlinked in the systemd.services.keycloak.script from the nix store to the keycloak service runtime dir, so changing the original script to call export instead of start fixed it.

Just so I can find it in the systemctl after it finishes the export

Depends on how you use your configuration.nix file. This code was a part of flake too and likely had with lib; defined somewhere at the top in order to use mkIf without referencing the full path.

keycloak has to be stopped in order for you to run export or import commands. This service is exporting all the realms every time keycloak starts, which was only useful in my experiment. For proper export I’d modify the service to stop running instance via systemd Conflicts and then start it over via ExecStopPost. (I’m no expert in systemd services, so there could be a better approach)

I was deploying my flake onto VM via deploy-rs and haven’t seen such an issue. As the export service shares RuntimeDirectory with the main service it might cause this issue, but I’m not really sure, you would have to investigate for yourself.