diff --git a/modules/services/korrosync/_derivation.nix b/modules/services/korrosync/_derivation.nix new file mode 100644 index 0000000..c58863f --- /dev/null +++ b/modules/services/korrosync/_derivation.nix @@ -0,0 +1,41 @@ +{ + lib, + fetchFromGitHub, + rustPlatform, + openssl, + pkg-config, + cacert, + ... +}: +rustPlatform.buildRustPackage (finalAttrs: { + pname = "korrosync"; + version = "0.4.0"; + + src = fetchFromGitHub { + owner = "szaffarano"; + repo = "korrosync"; + tag = "v${finalAttrs.version}"; + hash = "sha256-ubGOQ6JM9wo5428Yf1F1K+nllG9EDQBrBx4yr6PMPG0="; + }; + + buildInputs = [ + openssl + pkg-config + ]; + + nativeBuildInputs = [ + pkg-config + ]; + + #cargoHash = "sha256-3oMPREUWwKNEeaf8FdWHdjPMLU5xMSMzxKrmrhU+iko="; + cargoLock.lockFile = "${finalAttrs.src}/Cargo.lock"; + + SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; + NIX_SSL_CERT_FILE = "${cacert}/etc/ssl/certs/ca-bundle.crt"; + + meta = { + description = "KOReader Sync Server"; + license = lib.licenses.mit; + homepage = "https://github.com/szaffarano/korrosync"; + }; +}) diff --git a/modules/services/korrosync/korrosync-base.nix b/modules/services/korrosync/korrosync-base.nix new file mode 100644 index 0000000..acad5e6 --- /dev/null +++ b/modules/services/korrosync/korrosync-base.nix @@ -0,0 +1,162 @@ +{self, ...}: { + flake.overlays.korrosync = final: prev: { + korrosync = final.callPackage ./_derivation.nix {}; + }; + flake.nixosModules.korrosync-overlay = { + nixpkgs.overlays = [self.overlays.korrosync]; + }; + perSystem = {pkgs, ...}: { + packages.korrosync = pkgs.callPackage ./_derivation.nix {}; + }; + + flake.nixosModules.korrosync = { + config, + lib, + pkgs, + ... + }: let + cfg = config.services.korrosync; + in { + options.services.korrosync = { + enable = lib.mkEnableOption "Enable KOrrosync service"; + enable-service = lib.mkOption { + type = lib.types.bool; + description = "Enable korrosync service"; + example = true; + default = true; + }; + enable-configured-binary = lib.mkEnableOption "Put a korrosync binary into system-packges using the set configuration options."; + data-path = lib.mkOption { + type = lib.types.path; + description = "The path where korrosync saves it's data."; + example = "/var/lib/korrosync"; + default = "/var/lib/korrosync"; + }; + user = lib.mkOption { + type = lib.types.singleLineStr; + description = "The user under with korrosync runs."; + example = "korrosync"; + default = "korrosync"; + }; + group = lib.mkOption { + type = lib.types.singleLineStr; + description = "The group under with korrosync runs."; + example = "korrosync"; + default = "korrosync"; + }; + listen-address = lib.mkOption { + description = "The listen address of the korrosync server"; + type = lib.types.singleLineStr; + example = "0.0.0.0"; + default = "127.0.0.1"; + }; + listen-port = lib.mkOption { + description = "The listen port of the korrosync server"; + type = lib.types.int; + example = 3000; + default = 3000; + }; + rate-limit-per-second = lib.mkOption { + type = lib.types.int; + description = "Rate limit replenishment rate per second"; + example = 2; + default = 2; + }; + rate-limit-burst-size = lib.mkOption { + type = lib.types.int; + description = "Maximum burst size before rate limiting"; + example = 5; + default = 5; + }; + }; + + imports = [ + self.nixosModules.korrosync-overlay + ]; + + config = lib.mkIf cfg.enable { + # User setup + users.users = lib.mkIf (cfg.user == "korrosync") { + korrosync = { + description = "Korrosync service"; + useDefaultShell = true; + group = cfg.group; + isSystemUser = true; + }; + }; + users.groups = lib.mkIf (cfg.group == "korrosync") { + korrosync = {}; + }; + + # Pre-configured binary + environment.systemPackages = lib.mkIf cfg.enable-configured-binary [ + (let + envVars = config.systemd.services.korrosync.environment; + in + pkgs.writeShellScriptBin "korrosync" + '' + export KORROSYNC_DB_PATH="${envVars.KORROSYNC_DB_PATH}" + export KORROSYNC_SERVER_ADDRESS="${envVars.KORROSYNC_SERVER_ADDRESS}" + export KORROSYNC_USE_TLS="${envVars.KORROSYNC_USE_TLS}" + export KORROSYNC_RATE_LIMIT_PER_SECOND="${envVars.KORROSYNC_RATE_LIMIT_PER_SECOND}" + export KORROSYNC_RATE_LIMIT_BURST_SIZE="${envVars.KORROSYNC_RATE_LIMIT_BURST_SIZE}" + exec ${pkgs.korrosync}/bin/korrosync "$@" + '') + ]; + + # base service + systemd.services.korrosync = { + enable = cfg.enable-service; + description = "Korrosync - KOReader Sync Server"; + + after = ["network.target"]; + wantedBy = ["multi-user.target"]; + + environment = { + KORROSYNC_DB_PATH = "${cfg.data-path}/db.redb"; + KORROSYNC_SERVER_ADDRESS = "${cfg.listen-address}:${toString cfg.listen-port}"; + KORROSYNC_USE_TLS = "false"; + KORROSYNC_RATE_LIMIT_PER_SECOND = "${toString cfg.rate-limit-per-second}"; + KORROSYNC_RATE_LIMIT_BURST_SIZE = "${toString cfg.rate-limit-burst-size}"; + }; + + serviceConfig = { + Type = "simple"; + User = cfg.user; + Group = cfg.group; + ExecStart = "${pkgs.korrosync}/bin/korrosync serve"; + Restart = "on-failure"; + RestartSec = "5s"; + NoNewPrivileges = true; + PrivateTmp = true; + ProtectSystem = "strict"; + ProtectHome = true; + ReadWritePaths = cfg.data-path; + }; + }; + + # Initialize data directory + systemd.services.korrosync-init = { + description = "Initialize Korrosync databases"; + + wantedBy = ["korrosync.service"]; + before = ["korrosync.service"]; + + serviceConfig = { + Type = "oneshot"; + + ExecStart = pkgs.writeShellScript "korrosync-init" '' + if [ ! -d ${cfg.data-path} ]; then + echo "Creating Korrosync base directory \"${cfg.data-path}\"" + mkdir ${cfg.data-path} + chmod 770 ${cfg.data-path} + chown ${cfg.user}:${cfg.group} ${cfg.data-path} + fi + ''; + + RemainAfterExit = true; + }; + }; + }; + }; +} diff --git a/modules/services/korrosync/korrosync-hive.nix b/modules/services/korrosync/korrosync-hive.nix new file mode 100644 index 0000000..5bfef3a --- /dev/null +++ b/modules/services/korrosync/korrosync-hive.nix @@ -0,0 +1,64 @@ +{self, ...}: { + flake.nixosModules.korrosync-hive = { + config, + lib, + ... + }: let + cfg = config.hive.korrosync; + in { + options.hive.korrosync = { + enable = lib.mkEnableOption "Enable korrosync server"; + localPort = lib.mkOption { + type = lib.types.int; + example = 8080; + default = 45988; + description = "Specify the local port korrosync server uses."; + }; + instanceFQDN = lib.mkOption { + type = lib.types.singleLineStr; + example = "calibre.example.com"; + description = "Fully qualified domain name of the korrosync instance"; + }; + blockUserCreation = lib.mkOption { + type = lib.types.bool; + description = "Disallow /user/create endpoint via nginx"; + example = true; + default = true; + }; + }; + + imports = [ + self.nixosModules.korrosync + ]; + + config = lib.mkIf cfg.enable { + services.korrosync = { + enable = true; + listen-port = cfg.localPort; + listen-address = "127.0.0.1"; + data-path = "/srv/korrosync"; + }; + + # Fallback server with only 403 + services.nginx.virtualHosts.${config.networking.domain} = lib.mkDefault { + default = true; + locations."/".return = 403; + forceSSL = true; + enableACME = true; + }; + + # Virtual host for korrosync + services.nginx.virtualHosts."${cfg.instanceFQDN}" = + { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString cfg.localPort}"; + }; + } + // (lib.optionalAttrs cfg.blockUserCreation { + locations."/users/create".return = 403; + }); + }; + }; +}