25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 1 | self: { config, lib, pkgs, ... }: |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 2 | let |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 3 | cfg = config.services.vineyard; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 4 | toml = pkgs.formats.toml { }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 5 | peerToml = peer: { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 6 | url = peer.url; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 7 | query_limit = peer.queryLimit; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 8 | } // lib.optionalAttrs (peer.rescanFrom != null) { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 9 | rescan_from = peer.rescanFrom; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 10 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 11 | configFile = toml.generate "vineyard.toml" { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 12 | listen = cfg.listen; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 13 | public_url = cfg.publicUrl; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 14 | database = "/var/lib/vineyard/events.sqlite"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 15 | forge_pubkeys = cfg.forgePubkeys; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 16 | peers = map peerToml cfg.peers; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 17 | allow_private_discovery = cfg.allowPrivateDiscovery; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 18 | limits = cfg.limits; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 19 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 20 | port = lib.strings.toIntBase10 (lib.last (lib.splitString ":" cfg.listen)); |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 21 | in |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 22 | { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 23 | options.services.vineyard = { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 24 | enable = lib.mkEnableOption "vineyard"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 25 | package = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 26 | type = lib.types.package; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 27 | default = self.packages.${pkgs.stdenv.hostPlatform.system}.default; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 28 | description = "vineyard package to run"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 29 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 30 | listen = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 31 | type = lib.types.str; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 32 | default = "127.0.0.1:7777"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 33 | description = "address and port for vineyard to listen on"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 34 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 35 | publicUrl = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 36 | type = lib.types.str; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 37 | default = ""; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 38 | description = "public websocket url for vineyard"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 39 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 40 | forgePubkeys = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 41 | type = lib.types.listOf lib.types.str; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 42 | default = [ ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 43 | description = "locally hosted forge public keys in hex"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 44 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 45 | peers = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 46 | type = lib.types.listOf (lib.types.submodule { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 47 | options = { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 48 | url = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 49 | type = lib.types.str; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 50 | description = "peer relay url"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 51 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 52 | queryLimit = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 53 | type = lib.types.ints.positive; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 54 | default = 500; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 55 | description = "peer query limit"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 56 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 57 | rescanFrom = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 58 | type = lib.types.nullOr lib.types.ints.unsigned; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 59 | default = null; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 60 | description = "peer rescan timestamp"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 61 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 62 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 63 | }); |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 64 | default = [ ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 65 | description = "peer relays for event exchange"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 66 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 67 | allowPrivateDiscovery = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 68 | type = lib.types.bool; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 69 | default = false; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 70 | description = "allow discovered relays on private networks"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 71 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 72 | limits = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 73 | type = lib.types.attrsOf lib.types.int; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 74 | default = { }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 75 | description = "relay limit overrides"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 76 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 77 | openFirewall = lib.mkOption { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 78 | type = lib.types.bool; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 79 | default = false; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 80 | description = "open firewall for listen port"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 81 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 82 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 83 | config = lib.mkIf cfg.enable { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 84 | assertions = [ |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 85 | { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 86 | assertion = cfg.publicUrl != ""; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 87 | message = "publicUrl must be set"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 88 | } |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 89 | { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 90 | assertion = cfg.forgePubkeys != [ ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 91 | message = "forgePubkeys must not be empty"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 92 | } |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 93 | ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 94 | networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ port ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 95 | systemd.services.vineyard = { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 96 | description = "vineyard nostr relay"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 97 | wantedBy = [ "multi-user.target" ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 98 | after = [ "network-online.target" ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 99 | wants = [ "network-online.target" ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 100 | serviceConfig = { |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 101 | ExecStartPre = "${cfg.package}/bin/vineyard check-config --config ${configFile}"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 102 | ExecStart = "${cfg.package}/bin/vineyard serve --config ${configFile}"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 103 | DynamicUser = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 104 | StateDirectory = "vineyard"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 105 | StateDirectoryMode = "0700"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 106 | WorkingDirectory = "/var/lib/vineyard"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 107 | UMask = "0077"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 108 | Restart = "on-failure"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 109 | RestartSec = "5"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 110 | NoNewPrivileges = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 111 | ProtectSystem = "strict"; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 112 | ProtectHome = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 113 | PrivateTmp = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 114 | PrivateDevices = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 115 | ProtectKernelTunables = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 116 | ProtectKernelModules = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 117 | ProtectControlGroups = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 118 | RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ]; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 119 | RestrictNamespaces = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 120 | LockPersonality = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 121 | RestrictRealtime = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 122 | RestrictSUIDSGID = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 123 | RemoveIPC = true; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 124 | CapabilityBoundingSet = ""; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 125 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 126 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 127 | }; |
25d14e49ab68 | atagen | 2026-09-24 11:07 UTC | 128 | } |