atagen

vineyard

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/vineyard.git

Blame: nix/module.nix

25d14e49ab68atagen2026-09-24 11:07 UTC1
self: { config, lib, pkgs, ... }:
25d14e49ab68atagen2026-09-24 11:07 UTC2
let
25d14e49ab68atagen2026-09-24 11:07 UTC3
  cfg = config.services.vineyard;
25d14e49ab68atagen2026-09-24 11:07 UTC4
  toml = pkgs.formats.toml { };
25d14e49ab68atagen2026-09-24 11:07 UTC5
  peerToml = peer: {
25d14e49ab68atagen2026-09-24 11:07 UTC6
    url = peer.url;
25d14e49ab68atagen2026-09-24 11:07 UTC7
    query_limit = peer.queryLimit;
25d14e49ab68atagen2026-09-24 11:07 UTC8
  } // lib.optionalAttrs (peer.rescanFrom != null) {
25d14e49ab68atagen2026-09-24 11:07 UTC9
    rescan_from = peer.rescanFrom;
25d14e49ab68atagen2026-09-24 11:07 UTC10
  };
25d14e49ab68atagen2026-09-24 11:07 UTC11
  configFile = toml.generate "vineyard.toml" {
25d14e49ab68atagen2026-09-24 11:07 UTC12
    listen = cfg.listen;
25d14e49ab68atagen2026-09-24 11:07 UTC13
    public_url = cfg.publicUrl;
25d14e49ab68atagen2026-09-24 11:07 UTC14
    database = "/var/lib/vineyard/events.sqlite";
25d14e49ab68atagen2026-09-24 11:07 UTC15
    forge_pubkeys = cfg.forgePubkeys;
25d14e49ab68atagen2026-09-24 11:07 UTC16
    peers = map peerToml cfg.peers;
25d14e49ab68atagen2026-09-24 11:07 UTC17
    allow_private_discovery = cfg.allowPrivateDiscovery;
25d14e49ab68atagen2026-09-24 11:07 UTC18
    limits = cfg.limits;
25d14e49ab68atagen2026-09-24 11:07 UTC19
  };
25d14e49ab68atagen2026-09-24 11:07 UTC20
  port = lib.strings.toIntBase10 (lib.last (lib.splitString ":" cfg.listen));
25d14e49ab68atagen2026-09-24 11:07 UTC21
in
25d14e49ab68atagen2026-09-24 11:07 UTC22
{
25d14e49ab68atagen2026-09-24 11:07 UTC23
  options.services.vineyard = {
25d14e49ab68atagen2026-09-24 11:07 UTC24
    enable = lib.mkEnableOption "vineyard";
25d14e49ab68atagen2026-09-24 11:07 UTC25
    package = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC26
      type = lib.types.package;
25d14e49ab68atagen2026-09-24 11:07 UTC27
      default = self.packages.${pkgs.stdenv.hostPlatform.system}.default;
25d14e49ab68atagen2026-09-24 11:07 UTC28
      description = "vineyard package to run";
25d14e49ab68atagen2026-09-24 11:07 UTC29
    };
25d14e49ab68atagen2026-09-24 11:07 UTC30
    listen = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC31
      type = lib.types.str;
25d14e49ab68atagen2026-09-24 11:07 UTC32
      default = "127.0.0.1:7777";
25d14e49ab68atagen2026-09-24 11:07 UTC33
      description = "address and port for vineyard to listen on";
25d14e49ab68atagen2026-09-24 11:07 UTC34
    };
25d14e49ab68atagen2026-09-24 11:07 UTC35
    publicUrl = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC36
      type = lib.types.str;
25d14e49ab68atagen2026-09-24 11:07 UTC37
      default = "";
25d14e49ab68atagen2026-09-24 11:07 UTC38
      description = "public websocket url for vineyard";
25d14e49ab68atagen2026-09-24 11:07 UTC39
    };
25d14e49ab68atagen2026-09-24 11:07 UTC40
    forgePubkeys = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC41
      type = lib.types.listOf lib.types.str;
25d14e49ab68atagen2026-09-24 11:07 UTC42
      default = [ ];
25d14e49ab68atagen2026-09-24 11:07 UTC43
      description = "locally hosted forge public keys in hex";
25d14e49ab68atagen2026-09-24 11:07 UTC44
    };
25d14e49ab68atagen2026-09-24 11:07 UTC45
    peers = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC46
      type = lib.types.listOf (lib.types.submodule {
25d14e49ab68atagen2026-09-24 11:07 UTC47
        options = {
25d14e49ab68atagen2026-09-24 11:07 UTC48
          url = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC49
            type = lib.types.str;
25d14e49ab68atagen2026-09-24 11:07 UTC50
            description = "peer relay url";
25d14e49ab68atagen2026-09-24 11:07 UTC51
          };
25d14e49ab68atagen2026-09-24 11:07 UTC52
          queryLimit = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC53
            type = lib.types.ints.positive;
25d14e49ab68atagen2026-09-24 11:07 UTC54
            default = 500;
25d14e49ab68atagen2026-09-24 11:07 UTC55
            description = "peer query limit";
25d14e49ab68atagen2026-09-24 11:07 UTC56
          };
25d14e49ab68atagen2026-09-24 11:07 UTC57
          rescanFrom = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC58
            type = lib.types.nullOr lib.types.ints.unsigned;
25d14e49ab68atagen2026-09-24 11:07 UTC59
            default = null;
25d14e49ab68atagen2026-09-24 11:07 UTC60
            description = "peer rescan timestamp";
25d14e49ab68atagen2026-09-24 11:07 UTC61
          };
25d14e49ab68atagen2026-09-24 11:07 UTC62
        };
25d14e49ab68atagen2026-09-24 11:07 UTC63
      });
25d14e49ab68atagen2026-09-24 11:07 UTC64
      default = [ ];
25d14e49ab68atagen2026-09-24 11:07 UTC65
      description = "peer relays for event exchange";
25d14e49ab68atagen2026-09-24 11:07 UTC66
    };
25d14e49ab68atagen2026-09-24 11:07 UTC67
    allowPrivateDiscovery = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC68
      type = lib.types.bool;
25d14e49ab68atagen2026-09-24 11:07 UTC69
      default = false;
25d14e49ab68atagen2026-09-24 11:07 UTC70
      description = "allow discovered relays on private networks";
25d14e49ab68atagen2026-09-24 11:07 UTC71
    };
25d14e49ab68atagen2026-09-24 11:07 UTC72
    limits = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC73
      type = lib.types.attrsOf lib.types.int;
25d14e49ab68atagen2026-09-24 11:07 UTC74
      default = { };
25d14e49ab68atagen2026-09-24 11:07 UTC75
      description = "relay limit overrides";
25d14e49ab68atagen2026-09-24 11:07 UTC76
    };
25d14e49ab68atagen2026-09-24 11:07 UTC77
    openFirewall = lib.mkOption {
25d14e49ab68atagen2026-09-24 11:07 UTC78
      type = lib.types.bool;
25d14e49ab68atagen2026-09-24 11:07 UTC79
      default = false;
25d14e49ab68atagen2026-09-24 11:07 UTC80
      description = "open firewall for listen port";
25d14e49ab68atagen2026-09-24 11:07 UTC81
    };
25d14e49ab68atagen2026-09-24 11:07 UTC82
  };
25d14e49ab68atagen2026-09-24 11:07 UTC83
  config = lib.mkIf cfg.enable {
25d14e49ab68atagen2026-09-24 11:07 UTC84
    assertions = [
25d14e49ab68atagen2026-09-24 11:07 UTC85
      {
25d14e49ab68atagen2026-09-24 11:07 UTC86
        assertion = cfg.publicUrl != "";
25d14e49ab68atagen2026-09-24 11:07 UTC87
        message = "publicUrl must be set";
25d14e49ab68atagen2026-09-24 11:07 UTC88
      }
25d14e49ab68atagen2026-09-24 11:07 UTC89
      {
25d14e49ab68atagen2026-09-24 11:07 UTC90
        assertion = cfg.forgePubkeys != [ ];
25d14e49ab68atagen2026-09-24 11:07 UTC91
        message = "forgePubkeys must not be empty";
25d14e49ab68atagen2026-09-24 11:07 UTC92
      }
25d14e49ab68atagen2026-09-24 11:07 UTC93
    ];
25d14e49ab68atagen2026-09-24 11:07 UTC94
    networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ port ];
25d14e49ab68atagen2026-09-24 11:07 UTC95
    systemd.services.vineyard = {
25d14e49ab68atagen2026-09-24 11:07 UTC96
      description = "vineyard nostr relay";
25d14e49ab68atagen2026-09-24 11:07 UTC97
      wantedBy = [ "multi-user.target" ];
25d14e49ab68atagen2026-09-24 11:07 UTC98
      after = [ "network-online.target" ];
25d14e49ab68atagen2026-09-24 11:07 UTC99
      wants = [ "network-online.target" ];
25d14e49ab68atagen2026-09-24 11:07 UTC100
      serviceConfig = {
25d14e49ab68atagen2026-09-24 11:07 UTC101
        ExecStartPre = "${cfg.package}/bin/vineyard check-config --config ${configFile}";
25d14e49ab68atagen2026-09-24 11:07 UTC102
        ExecStart = "${cfg.package}/bin/vineyard serve --config ${configFile}";
25d14e49ab68atagen2026-09-24 11:07 UTC103
        DynamicUser = true;
25d14e49ab68atagen2026-09-24 11:07 UTC104
        StateDirectory = "vineyard";
25d14e49ab68atagen2026-09-24 11:07 UTC105
        StateDirectoryMode = "0700";
25d14e49ab68atagen2026-09-24 11:07 UTC106
        WorkingDirectory = "/var/lib/vineyard";
25d14e49ab68atagen2026-09-24 11:07 UTC107
        UMask = "0077";
25d14e49ab68atagen2026-09-24 11:07 UTC108
        Restart = "on-failure";
25d14e49ab68atagen2026-09-24 11:07 UTC109
        RestartSec = "5";
25d14e49ab68atagen2026-09-24 11:07 UTC110
        NoNewPrivileges = true;
25d14e49ab68atagen2026-09-24 11:07 UTC111
        ProtectSystem = "strict";
25d14e49ab68atagen2026-09-24 11:07 UTC112
        ProtectHome = true;
25d14e49ab68atagen2026-09-24 11:07 UTC113
        PrivateTmp = true;
25d14e49ab68atagen2026-09-24 11:07 UTC114
        PrivateDevices = true;
25d14e49ab68atagen2026-09-24 11:07 UTC115
        ProtectKernelTunables = true;
25d14e49ab68atagen2026-09-24 11:07 UTC116
        ProtectKernelModules = true;
25d14e49ab68atagen2026-09-24 11:07 UTC117
        ProtectControlGroups = true;
25d14e49ab68atagen2026-09-24 11:07 UTC118
        RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" ];
25d14e49ab68atagen2026-09-24 11:07 UTC119
        RestrictNamespaces = true;
25d14e49ab68atagen2026-09-24 11:07 UTC120
        LockPersonality = true;
25d14e49ab68atagen2026-09-24 11:07 UTC121
        RestrictRealtime = true;
25d14e49ab68atagen2026-09-24 11:07 UTC122
        RestrictSUIDSGID = true;
25d14e49ab68atagen2026-09-24 11:07 UTC123
        RemoveIPC = true;
25d14e49ab68atagen2026-09-24 11:07 UTC124
        CapabilityBoundingSet = "";
25d14e49ab68atagen2026-09-24 11:07 UTC125
      };
25d14e49ab68atagen2026-09-24 11:07 UTC126
    };
25d14e49ab68atagen2026-09-24 11:07 UTC127
  };
25d14e49ab68atagen2026-09-24 11:07 UTC128
}