Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion nixos/doc/manual/release-notes/rl-2605.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.

- [udp-over-tcp](https://github.com/mullvad/udp-over-tcp), a tunnel for proxying UDP traffic over a TCP stream. Available as `services.udp-over-tcp`.
Expand All @@ -24,4 +28,4 @@

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

- `services.openssh` now supports generating host SSH keys by setting `services.openssh.generateHostKeys = true` while leaving `services.openssh.enable` disabled. This is particularly useful for systems that have no need of an SSH daemon but want SSH host keys for other purposes such as using agenix or sops-nix.
- `services.openssh` now supports generating host SSH keys by setting `services.openssh.generateHostKeys = true` while leaving `services.openssh.enable` disabled. This is particularly useful for systems that have no need of an SSH daemon but want SSH host keys for other purposes such as using agenix or sops-nix.
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,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
Expand Down
57 changes: 57 additions & 0 deletions nixos/modules/services/networking/meshtastic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# 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 changes: 124 additions & 0 deletions nixos/modules/services/networking/meshtasticd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
{
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 change: 1 addition & 0 deletions nixos/tests/all-tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -938,6 +938,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;
Expand Down
45 changes: 45 additions & 0 deletions nixos/tests/networking/meshtasticd.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
lib,
pkgs,
...
}:
let
mainPort = 9445;
webPort = 9446;
in
{
name = "meshtasticd";
meta.maintainers = [ lib.maintainers.drupol ];

nodes.machine = {
services.meshtasticd = {
enable = true;
port = mainPort;

settings = {
Lora = {
Module = "sim";
DIO2_AS_RF_SWITCH = false;
spiSpeed = "2000000";
};
Webserver = {
Port = webPort;
RootPath = pkgs.meshtastic-web;
};
General = {
MaxNodes = 200;
MaxMessageQueue = 100;
MACAddressSource = "eth0";
};
};
};
};

testScript = ''
with subtest("Test meshtasticd service"):
machine.wait_for_unit("meshtasticd.service")
machine.wait_for_open_port(${builtins.toString mainPort})
machine.wait_for_open_port(${builtins.toString webPort})
machine.succeed("curl -fvvv -Ls http://localhost:${builtins.toString webPort} | grep -q 'Meshtastic Web Client'")
'';
}
Loading