clanModules/mycelium: init mycelium

This adds a clanModule for `mycelium`.
`Mycelium` is an IPv6 overlay network written in Rust.
Each node that joins the overlay network will receive an overlay network IP in the 400::/7 range.

An example configuration might look like this in the inventory:

```nix
mycelium.default = {
  roles.peer.machines = [
    "berlin"
    "munich"
  ];
  config = {
    topLevelDomain = "m";
    openFirewall = true;
    addHostedPublicNodes = true;
  };
};
```

This will add the machines named `berlin` and `munich` to the `mycelium` vpn.
And will also set the toplevel domain of the mycelium vpn to `m`, meaning the
machines are now reachable via `berlin.m` and `munich.m`.
This commit is contained in:
a-kenji
2025-01-22 12:44:11 +01:00
committed by clan-bot
parent 7ff0058bd6
commit 42e0928b55
4 changed files with 130 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ in
matrix-synapse = ./matrix-synapse; matrix-synapse = ./matrix-synapse;
moonlight = ./moonlight; moonlight = ./moonlight;
mumble = ./mumble; mumble = ./mumble;
mycelium = ./mycelium;
nginx = ./nginx; nginx = ./nginx;
packages = ./packages; packages = ./packages;
postgresql = ./postgresql; postgresql = ./postgresql;

View File

@@ -0,0 +1,37 @@
---
description = "End-2-end encrypted IPv6 overlay network"
categories = ["System", "Network"]
features = [ "inventory" ]
---
Mycelium is an IPv6 overlay network written in Rust. Each node that joins the overlay network will receive an overlay network IP in the 400::/7 range.
Features:
- Mycelium, is locality aware, it will look for the shortest path between nodes
- All traffic between the nodes is end-2-end encrypted
- Traffic can be routed over nodes of friends, location aware
- If a physical link goes down Mycelium will automatically reroute your traffic
- The IP address is IPV6 and linked to private key
- A simple reliable messagebus is implemented on top of Mycelium
- Mycelium has multiple ways how to communicate quic, tcp, ... and we are working on holepunching for Quick which means P2P traffic without middlemen for NATted networks e.g. most homes
- Scalability is very important for us, we tried many overlay networks before and got stuck on all of them, we are trying to design a network which scales to a planetary level
- You can run mycelium without TUN and only use it as reliable message bus.
An example configuration might look like this in the inventory:
```nix
mycelium.default = {
roles.peer.machines = [
"berlin"
"munich"
];
config = {
topLevelDomain = "m";
openFirewall = true;
addHostedPublicNodes = true;
};
};
```
This will add the machines named `berlin` and `munich` to the `mycelium` vpn.
And will also set the toplevel domain of the mycelium vpn to `m`, meaning the
machines are now reachable via `berlin.m` and `munich.m`.

View File

@@ -0,0 +1,91 @@
{
pkgs,
config,
lib,
...
}:
let
flake = config.clan.core.settings.directory;
machineName = config.clan.core.settings.machine.name;
# Instances might be empty, if the module is not used via the inventory
#
# Type: { ${instanceName} :: { roles :: Roles } }
# Roles :: { ${role_name} :: { machines :: [string] } }
instances = config.clan.inventory.services.mycelium or { };
allPeers = lib.foldlAttrs (
acc: _instanceName: instanceConfig:
acc
++ (
if (builtins.elem machineName instanceConfig.roles.peer.machines) then
instanceConfig.roles.peer.machines
else
[ ]
)
) [ ] instances;
allPeerConfigurations = lib.filterAttrs (n: _: builtins.elem n allPeers) flake.nixosConfigurations;
allPeersWithIp =
builtins.mapAttrs
(_: x: lib.removeSuffix "\n" x.config.clan.core.vars.generators.mycelium.files.ip.value)
(
lib.filterAttrs (
_: x: (builtins.tryEval x.config.clan.core.vars.generators.mycelium.files.ip.value).success
) allPeerConfigurations
);
ips = lib.attrValues allPeersWithIp;
peers = lib.concatMap (ip: [
"tcp://[${ip}]:9651"
"quic://[${ip}]:9651"
]) ips;
in
{
options = {
clan.mycelium.topLevelDomain = lib.mkOption {
type = lib.types.str;
default = "";
description = "Top level domain to reach hosts";
};
clan.mycelium.openFirewall = lib.mkEnableOption "Open the firewall for mycelium";
clan.mycelium.addHostedPublicNodes = lib.mkEnableOption "Add hosted Public nodes";
clan.mycelium.addHosts = lib.mkOption {
default = true;
description = "Add mycelium ip's to the host file";
};
};
config.services.mycelium = {
enable = true;
addHostedPublicNodes = lib.mkDefault config.clan.mycelium.addHostedPublicNodes;
openFirewall = lib.mkDefault config.clan.mycelium.openFirewall;
keyFile = config.clan.core.vars.generators.mycelium.files.key.path;
inherit peers;
};
config.networking.hosts = lib.mkIf (config.clan.mycelium.addHosts) (
lib.mapAttrs' (
host: ip:
lib.nameValuePair ip (
if (config.clan.mycelium.topLevelDomain == "") then [ host ] else [ "${host}.m" ]
)
) allPeersWithIp
);
config.clan.core.vars.generators.mycelium = {
files."key" = { };
files."ip".secret = false;
files."pubkey".secret = false;
runtimeInputs = [
pkgs.mycelium
pkgs.coreutils
pkgs.jq
];
script = ''
timeout 5 mycelium --key-file "$out"/key || :
mycelium inspect --key-file "$out"/key --json | jq -r .publicKey > "$out"/pubkey
mycelium inspect --key-file "$out"/key --json | jq -r .address > "$out"/ip
'';
};
}

View File

@@ -92,6 +92,7 @@ nav:
- reference/clanModules/matrix-synapse.md - reference/clanModules/matrix-synapse.md
- reference/clanModules/moonlight.md - reference/clanModules/moonlight.md
- reference/clanModules/mumble.md - reference/clanModules/mumble.md
- reference/clanModules/mycelium.md
- reference/clanModules/nginx.md - reference/clanModules/nginx.md
- reference/clanModules/packages.md - reference/clanModules/packages.md
- reference/clanModules/postgresql.md - reference/clanModules/postgresql.md