{ config, lib, pkgs, masterDomain, securityTemplates, ... }: let cfg = config.os.srv.monero; banlist1 = pkgs.fetchurl { url = "https://gui.xmr.pm/files/block.txt"; hash = "sha256-0ik4d66js6wvrvciza0li6bsajj8dvxsqlf09hcz7hg610szdxcw"; }; banlist2 = pkgs.fetchurl { url = "https://raw.githubusercontent.com/Boog900/monero-ban-list/refs/heads/main/ban_list.txt"; hash = "sh256-01z4wm2mp4z1wq2wdkrm66j50gwk3r82m2ml4n0pwjcbajxkdc87"; }; combinedBanlist = pkgs.writeText "combined-monero-banlist.txt" '' ${builtins.readFile banlist1} ${builtins.readFile banlist2} ''; in { options.os.srv.monero = { wallet.enable = lib.mkEnableOption "enables the monero wallet"; service = { enable = lib.mkEnableOption "enables hosting a monero node"; public = lib.mkEnableOption "makes the RPC node public (disables authentication for general wallet syncing)"; tor.enable = lib.mkEnableOption "exposes monero RPC via Tor Onion Service"; i2p.enable = lib.mkEnableOption "exposes monero RPC via I2P Tunnel"; }; }; config = lib.mkMerge [ (lib.mkIf cfg.wallet.enable { environment.systemPackages = [ pkgs.monero-cli ]; }) (lib.mkIf cfg.service.enable { assertions = [ { assertion = if (!cfg.service.public) then config.os.srv.sops.enable else true; message = "sops must be enabled"; } { assertion = if cfg.service.tor.enable then config.os.srv.tor.enable else true; message = "tor must be enabled"; } { assertion = if cfg.service.i2p.enable then config.os.srv.i2p.enable else true; message = "i2p must be enabled"; } ]; sops.secrets."monero/rpc-password" = { owner = "monero"; restartUnits = [ "monero.service" ]; }; services.monero = { enable = true; prune = true; banlist = combinedBanlist; limits = { upload = 1250; download = 12500; threads = 8; }; rpc = { address = "0.0.0.0"; } // lib.optionalAttrs (!cfg.service.public) { restricted = true; user = "admin"; password = config.sops.secrets."monero/rpc-password".path; }; }; services.tor = lib.mkIf cfg.service.tor.enable { onionServices."xmr-rpc" = { to = [ { port = 18081; address = config.os.core.network.ips.vm9-relays; } ]; }; }; services.i2pd = lib.mkIf cfg.service.i2p.enable { tunnels.server."xmr-rpc" = { port = 18081; address = config.os.core.network.ips.vm9-relays; keys = "xmr-rpc-key.dat"; inbound.length = 3; outbound.length = 3; }; }; os.cluster.nginxProxies."xmr.${masterDomain}" = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://${config.os.core.network.ips.vm9-relays}:18081"; extraConfig = '' proxy_read_timeout 600s; proxy_send_timeout 600s; client_max_body_size 50m; ${securityTemplates.restrictToInternal} ''; }; }; # Left open for P2P syncing networking.firewall.allowedTCPPorts = [ 18080 ]; }) ]; }