mkv.nix (3861B)
1 { 2 config, 3 pkgs, 4 lib, 5 mkv, 6 ... 7 }: 8 9 let 10 cfg = config.services.local.mkv; 11 in 12 { 13 options.services.local.mkv = { 14 enable = lib.mkEnableOption "mkv distributed key-value store"; 15 16 package = lib.mkOption { 17 type = lib.types.package; 18 default = mkv.packages.${pkgs.stdenv.hostPlatform.system}.default; 19 description = "mkv package to use"; 20 }; 21 22 dbPath = lib.mkOption { 23 type = lib.types.str; 24 default = "/var/lib/mkv/index.db"; 25 description = "Path to the index database"; 26 }; 27 28 volumes = lib.mkOption { 29 type = lib.types.listOf lib.types.str; 30 default = []; 31 description = "List of volume server URLs"; 32 }; 33 34 replicas = lib.mkOption { 35 type = lib.types.int; 36 default = 2; 37 description = "Number of replicas"; 38 }; 39 40 port = lib.mkOption { 41 type = lib.types.port; 42 default = 3000; 43 description = "Port for the mkv service"; 44 }; 45 46 openFirewall = lib.mkOption { 47 type = lib.types.bool; 48 default = true; 49 description = "Open firewall port on wg0"; 50 }; 51 52 # Volume server options 53 volume = { 54 enable = lib.mkEnableOption "MKV volume WebDAV server"; 55 56 listenAddress = lib.mkOption { 57 type = lib.types.str; 58 description = "IP address to listen on (typically VPN address)"; 59 }; 60 61 port = lib.mkOption { 62 type = lib.types.port; 63 default = 8081; 64 description = "Port to listen on"; 65 }; 66 67 path = lib.mkOption { 68 type = lib.types.path; 69 default = "/var/lib/mkv/volume"; 70 description = "Path to the volume directory"; 71 }; 72 73 maxBodySize = lib.mkOption { 74 type = lib.types.str; 75 default = "256M"; 76 description = "Maximum upload size"; 77 }; 78 79 firewallInterface = lib.mkOption { 80 type = lib.types.str; 81 default = "wg0"; 82 description = "Interface to allow traffic on"; 83 }; 84 }; 85 }; 86 87 config = lib.mkMerge [ 88 # MKV server 89 (lib.mkIf cfg.enable { 90 systemd.services.mkv = { 91 description = "mkv distributed key-value store"; 92 wantedBy = [ "multi-user.target" ]; 93 after = [ 94 "network-online.target" 95 "wg-quick-wg0.service" 96 "nginx.service" 97 ]; 98 wants = [ "network-online.target" ]; 99 requires = [ "wg-quick-wg0.service" ]; 100 environment = { 101 MKV_DB = cfg.dbPath; 102 MKV_VOLUMES = lib.concatStringsSep "," cfg.volumes; 103 MKV_REPLICAS = toString cfg.replicas; 104 MKV_PORT = toString cfg.port; 105 }; 106 serviceConfig = { 107 Type = "simple"; 108 DynamicUser = true; 109 StateDirectory = "mkv"; 110 ExecStart = "${cfg.package}/bin/mkv serve"; 111 Restart = "on-failure"; 112 RestartSec = 5; 113 }; 114 }; 115 116 networking.firewall.interfaces.wg0.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ]; 117 }) 118 119 # Volume server (nginx WebDAV) 120 (lib.mkIf cfg.volume.enable { 121 services.nginx = { 122 enable = true; 123 virtualHosts."mkv-volume" = { 124 listen = [ 125 { addr = cfg.volume.listenAddress; port = cfg.volume.port; } 126 ]; 127 root = cfg.volume.path; 128 extraConfig = '' 129 autoindex on; 130 autoindex_format json; 131 dav_methods PUT DELETE; 132 create_full_put_path on; 133 client_max_body_size ${cfg.volume.maxBodySize}; 134 ''; 135 }; 136 }; 137 138 systemd.tmpfiles.rules = [ 139 "d ${cfg.volume.path} 0755 nginx nginx -" 140 ]; 141 142 networking.firewall.interfaces.${cfg.volume.firewallInterface}.allowedTCPPorts = [ cfg.volume.port ]; 143 144 systemd.services.nginx.serviceConfig = { 145 ReadWritePaths = [ cfg.volume.path ]; 146 ProtectSystem = lib.mkForce "full"; 147 }; 148 }) 149 ]; 150 }