Unverified Commit e9c4ec8d authored by Doron Behar's avatar Doron Behar Committed by GitHub
Browse files

meshtasticd: build from source, nixos/meshtastic: init (#466509)

parents 8fdad3b2 adf01438
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -10,6 +10,10 @@

<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

- [Meshtastic](https://meshtastic.org), an open-source, off-grid, decentralised mesh network
  designed to run on affordable, low-power devices. Available as [services.meshtasticd]
  (#opt-services.meshtasticd.enable).

- [knot-resolver](https://www.knot-resolver.cz/) in version 6. Available as `services.knot-resolver`. A module for knot-resolver 5 was already available as `services.kresd`.

- [ImmichFrame](https://immichframe.dev/), display your photos from Immich as a digital photo frame. Available as `services.immichframe`.
+1 −0
Original line number Diff line number Diff line
@@ -1248,6 +1248,7 @@
  ./services/networking/lxd-image-server.nix
  ./services/networking/magic-wormhole-mailbox-server.nix
  ./services/networking/matterbridge.nix
  ./services/networking/meshtasticd.nix
  ./services/networking/microsocks.nix
  ./services/networking/mihomo.nix
  ./services/networking/minidlna.nix
+57 −0
Original line number Diff line number Diff line
# Meshtasticd {#module-services-meshtasticd}

[Meshtasticd](https://meshtastic.org/) daemon.

Meshtastic is an open-source, off-grid, decentralised mesh network designed to
run on affordable, low-power devices.

Meshtastic is a project that enables you to use inexpensive LoRa radios as a
long range off-grid communication platform in areas without existing or reliable
communications infrastructure. This project is 100% community driven and open
source!

## Quickstart {#module-services-meshtasticd-quickstart}

A minimal configuration:

```nix
{
  services.meshtasticd = {
    enable = true;
    port = 4403;
    settings = {
      Lora = {
        Module = "auto";
      };
      Webserver = {
        Port = 9443;
        RootPath = pkgs.meshtastic-web;
      };
      General = {
        MaxNodes = 200;
        MaxMessageQueue = 100;
        MACAddressSource = "eth0";
      };
    };
  };
}
```

By default Meshtasticd listens on all network interfaces. The example above
binds the daemon to port `4403` and the web UI to `9443`. This module
intentionally does not configure an reverse proxy for you, keeping the module
focused on the Meshtastic service itself. If you need to restrict access, use
firewall rules or put the web UI behind a reverse proxy (e.g.: Caddy, Nginx)
that binds to `127.0.0.1` and exposes only the proxy. This approach leaves proxy
choice and TLS configuration to the operator while documenting how to securely
expose the web UI when required.

## Configuration {#module-services-meshtasticd-config}

All available configuration directives are documented in the
[standard Meshtastic configuration file](https://github.com/meshtastic/firmware/blob/develop/bin/config-dist.yaml).

The service uses a dedicated user and group account (`meshtasticd`) by default.
If you override the service user, ensure it is a member of the `spi` and `gpio`
groups so it can access the required hardware devices, as mandated by
Meshtastic’s default `udev` rules.
+124 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  cfg = config.services.meshtasticd;
  format = pkgs.formats.yaml { };
  configFile = format.generate "config.yaml" cfg.settings;
in
{
  options.services.meshtasticd = {
    enable = lib.mkEnableOption "Meshtastic daemon";
    package = lib.mkPackageOption pkgs "meshtasticd" { };

    user = lib.mkOption {
      default = "meshtasticd";
      description = "User meshtasticd runs as.";
      type = lib.types.str;
    };

    group = lib.mkOption {
      default = "meshtasticd";
      description = "Group meshtasticd runs as.";
      type = lib.types.str;
    };

    port = lib.mkOption {
      type = lib.types.port;
      default = 4403;
      description = "Port to listen on";
    };

    settings = lib.mkOption {
      type = format.type;
      example = lib.literalExpression ''
        Lora = {
          Module = "auto";
        };
        Webserver = {
          Port = 9443;
          RootPath = pkgs.meshtastic-web;
        };
        General = {
          MaxNodes = 200;
          MaxMessageQueue = 100;
          MACAddressSource = "eth0";
        };
      '';
      description = ''
        The Meshtastic configuration file.

        An example of configuration can be found at <https://github.com/meshtastic/firmware/blob/develop/bin/config-dist.yaml>
      '';
    };

    dataDir = lib.mkOption {
      default = "/var/lib/meshtasticd";
      type = lib.types.path;
      description = ''
        The data directory.
      '';
    };
  };

  config = lib.mkIf cfg.enable {
    # Creation of the `meshtasticd` privilege user.
    users = {
      users = lib.mkIf (cfg.user == "meshtasticd") {
        meshtasticd = {
          home = cfg.dataDir;
          description = "meshtasticd-daemon privilege user";
          group = cfg.group;
          isSystemUser = true;
          extraGroups = [
            "spi"
            "gpio"
          ];
        };
      };
      groups = lib.mkIf (cfg.group == "meshtasticd") {
        meshtasticd = { };
        # These groups are required for udev rules to work properly.
        spi = { };
        gpio = { };
      };
    };

    # The `meshtasticd` package provides udev rules.
    services.udev.packages = [
      cfg.package
    ];

    # Creation of the `meshtasticd` service.
    # Based on the official meshtasticd service file: https://github.com/meshtastic/firmware/blob/develop/bin/meshtasticd.service
    systemd.services.meshtasticd = {
      description = "Meshtastic Native Daemon";
      after = [
        "network-online.target"
        "network.target"
      ];
      wants = [
        "network-online.target"
        "network.target"
      ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig = {
        User = cfg.user;
        Group = cfg.group;
        Type = "simple";
        StateDirectory = "meshtasticd";
        AmbientCapabilities = [
          "CAP_NET_BIND_SERVICE"
        ];
        ExecStart = "${lib.getExe cfg.package} --port=${builtins.toString cfg.port} --fsdir=${cfg.dataDir} --config=${configFile} --verbose";
        Restart = "always";
        RestartSec = "3";
      };
    };
  };
}
+1 −0
Original line number Diff line number Diff line
@@ -941,6 +941,7 @@ in
  meilisearch = runTest ./meilisearch.nix;
  memcached = runTest ./memcached.nix;
  merecat = runTest ./merecat.nix;
  meshtasticd = runTest ./networking/meshtasticd.nix;
  metabase = runTest ./metabase.nix;
  mihomo = runTest ./mihomo.nix;
  mimir = runTest ./mimir.nix;
Loading