at master 8.1 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 cfg = config.services.monero; 10 11 listToConf = option: list: lib.concatMapStrings (value: "${option}=${value}\n") list; 12 13 login = (cfg.rpc.user != null && cfg.rpc.password != null); 14 15 configFile = 16 with cfg; 17 pkgs.writeText "monero.conf" '' 18 log-file=/dev/stdout 19 data-dir=${dataDir} 20 21 ${lib.optionalString mining.enable '' 22 start-mining=${mining.address} 23 mining-threads=${toString mining.threads} 24 ''} 25 26 rpc-bind-ip=${rpc.address} 27 rpc-bind-port=${toString rpc.port} 28 ${lib.optionalString login '' 29 rpc-login=${rpc.user}:${rpc.password} 30 ''} 31 ${lib.optionalString rpc.restricted '' 32 restricted-rpc=1 33 ''} 34 35 ${lib.optionalString (banlist != null) '' 36 ban-list=${banlist} 37 ''} 38 39 limit-rate-up=${toString limits.upload} 40 limit-rate-down=${toString limits.download} 41 max-concurrency=${toString limits.threads} 42 block-sync-size=${toString limits.syncSize} 43 44 ${listToConf "add-peer" extraNodes} 45 ${listToConf "add-priority-node" priorityNodes} 46 ${listToConf "add-exclusive-node" exclusiveNodes} 47 48 ${lib.optionalString prune '' 49 prune-blockchain=1 50 sync-pruned-blocks=1 51 ''} 52 53 ${extraConfig} 54 ''; 55 56in 57 58{ 59 60 ###### interface 61 62 options = { 63 64 services.monero = { 65 66 enable = lib.mkEnableOption "Monero node daemon"; 67 68 dataDir = lib.mkOption { 69 type = lib.types.str; 70 default = "/var/lib/monero"; 71 description = '' 72 The directory where Monero stores its data files. 73 ''; 74 }; 75 76 banlist = lib.mkOption { 77 type = lib.types.nullOr lib.types.path; 78 default = null; 79 description = '' 80 Path to a text file containing IPs to block. 81 Useful to prevent DDoS/deanonymization attacks. 82 83 <https://github.com/monero-project/meta/issues/1124> 84 ''; 85 example = lib.literalExpression '' 86 builtins.fetchurl { 87 url = "https://raw.githubusercontent.com/rblaine95/monero-banlist/c6eb9413ddc777e7072d822f49923df0b2a94d88/block.txt"; 88 hash = ""; 89 }; 90 ''; 91 }; 92 93 mining.enable = lib.mkOption { 94 type = lib.types.bool; 95 default = false; 96 description = '' 97 Whether to mine monero. 98 ''; 99 }; 100 101 mining.address = lib.mkOption { 102 type = lib.types.str; 103 default = ""; 104 description = '' 105 Monero address where to send mining rewards. 106 ''; 107 }; 108 109 mining.threads = lib.mkOption { 110 type = lib.types.ints.unsigned; 111 default = 0; 112 description = '' 113 Number of threads used for mining. 114 Set to `0` to use all available. 115 ''; 116 }; 117 118 rpc.user = lib.mkOption { 119 type = lib.types.nullOr lib.types.str; 120 default = null; 121 description = '' 122 User name for RPC connections. 123 ''; 124 }; 125 126 rpc.password = lib.mkOption { 127 type = lib.types.nullOr lib.types.str; 128 default = null; 129 description = '' 130 Password for RPC connections. 131 ''; 132 }; 133 134 rpc.address = lib.mkOption { 135 type = lib.types.str; 136 default = "127.0.0.1"; 137 description = '' 138 IP address the RPC server will bind to. 139 ''; 140 }; 141 142 rpc.port = lib.mkOption { 143 type = lib.types.port; 144 default = 18081; 145 description = '' 146 Port the RPC server will bind to. 147 ''; 148 }; 149 150 rpc.restricted = lib.mkOption { 151 type = lib.types.bool; 152 default = false; 153 description = '' 154 Whether to restrict RPC to view only commands. 155 ''; 156 }; 157 158 limits.upload = lib.mkOption { 159 type = lib.types.addCheck lib.types.int (x: x >= -1); 160 default = -1; 161 description = '' 162 Limit of the upload rate in kB/s. 163 Set to `-1` to leave unlimited. 164 ''; 165 }; 166 167 limits.download = lib.mkOption { 168 type = lib.types.addCheck lib.types.int (x: x >= -1); 169 default = -1; 170 description = '' 171 Limit of the download rate in kB/s. 172 Set to `-1` to leave unlimited. 173 ''; 174 }; 175 176 limits.threads = lib.mkOption { 177 type = lib.types.ints.unsigned; 178 default = 0; 179 description = '' 180 Maximum number of threads used for a parallel job. 181 Set to `0` to leave unlimited. 182 ''; 183 }; 184 185 limits.syncSize = lib.mkOption { 186 type = lib.types.ints.unsigned; 187 default = 0; 188 description = '' 189 Maximum number of blocks to sync at once. 190 Set to `0` for adaptive. 191 ''; 192 }; 193 194 extraNodes = lib.mkOption { 195 type = lib.types.listOf lib.types.str; 196 default = [ ]; 197 description = '' 198 List of additional peer IP addresses to add to the local list. 199 ''; 200 }; 201 202 priorityNodes = lib.mkOption { 203 type = lib.types.listOf lib.types.str; 204 default = [ ]; 205 description = '' 206 List of peer IP addresses to connect to and 207 attempt to keep the connection open. 208 ''; 209 }; 210 211 exclusiveNodes = lib.mkOption { 212 type = lib.types.listOf lib.types.str; 213 default = [ ]; 214 description = '' 215 List of peer IP addresses to connect to *only*. 216 If given the other peer options will be ignored. 217 ''; 218 }; 219 220 prune = lib.mkOption { 221 type = lib.types.bool; 222 default = false; 223 description = '' 224 Whether to prune the blockchain. 225 <https://www.getmonero.org/resources/moneropedia/pruning.html> 226 ''; 227 }; 228 229 environmentFile = lib.mkOption { 230 type = lib.types.nullOr lib.types.path; 231 default = null; 232 example = "/var/lib/monero/monerod.env"; 233 description = '' 234 Path to an EnvironmentFile for the monero service as defined in {manpage}`systemd.exec(5)`. 235 236 Secrets may be passed to the service by specifying placeholder variables in the Nix config 237 and setting values in the environment file. 238 239 Example: 240 241 ``` 242 # In environment file: 243 MINING_ADDRESS=888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H 244 ``` 245 246 ``` 247 # Service config 248 services.monero.mining.address = "$MINING_ADDRESS"; 249 ``` 250 ''; 251 }; 252 253 extraConfig = lib.mkOption { 254 type = lib.types.lines; 255 default = ""; 256 description = '' 257 Extra lines to be added verbatim to monerod configuration. 258 ''; 259 }; 260 261 }; 262 263 }; 264 265 ###### implementation 266 267 config = lib.mkIf cfg.enable { 268 269 users.users.monero = { 270 isSystemUser = true; 271 group = "monero"; 272 description = "Monero daemon user"; 273 home = cfg.dataDir; 274 createHome = true; 275 }; 276 277 users.groups.monero = { }; 278 279 systemd.services.monero = { 280 description = "monero daemon"; 281 after = [ "network.target" ]; 282 wantedBy = [ "multi-user.target" ]; 283 284 preStart = '' 285 umask 077 286 ${pkgs.envsubst}/bin/envsubst \ 287 -i ${configFile} \ 288 -o ${cfg.dataDir}/monerod.conf 289 ''; 290 291 serviceConfig = { 292 User = "monero"; 293 Group = "monero"; 294 EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; 295 ExecStart = "${lib.getExe' pkgs.monero-cli "monerod"} --config-file=${cfg.dataDir}/monerod.conf --non-interactive"; 296 Restart = "always"; 297 SuccessExitStatus = [ 298 0 299 1 300 ]; 301 }; 302 }; 303 304 assertions = lib.singleton { 305 assertion = cfg.mining.enable -> cfg.mining.address != ""; 306 message = '' 307 You need a Monero address to receive mining rewards: 308 specify one using option monero.mining.address. 309 ''; 310 }; 311 312 }; 313 314 meta.maintainers = with lib.maintainers; [ rnhmjoj ]; 315 316}