Compare commits
7 Commits
wireguard
...
push-tnkqq
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c7d885b6 | ||
|
|
6482094cb4 | ||
|
|
cbcfcd507d | ||
|
|
9b71f106f6 | ||
|
|
1482bd571c | ||
|
|
ec2537d088 | ||
|
|
41229af93e |
@@ -17,4 +17,4 @@ jobs:
|
|||||||
|
|
||||||
- name: Build clan-app for x86_64-darwin
|
- name: Build clan-app for x86_64-darwin
|
||||||
run: |
|
run: |
|
||||||
nix build .#packages.x86_64-darwin.clan-app --log-format bar-with-logs
|
nix build .#packages.x86_64-darwin.clan-app --system x86_64-darwin --log-format bar-with-logs
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright 2023-2025 Clan contributors
|
Copyright 2023-2024 Clan contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
this software and associated documentation files (the "Software"), to deal in
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
self,
|
self,
|
||||||
lib,
|
lib,
|
||||||
inputs,
|
inputs,
|
||||||
privateInputs ? { },
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
@@ -86,12 +85,11 @@ in
|
|||||||
|
|
||||||
# Container Tests
|
# Container Tests
|
||||||
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
nixos-test-container = self.clanLib.test.containerTest ./container nixosTestArgs;
|
||||||
nixos-systemd-abstraction = self.clanLib.test.containerTest ./systemd-abstraction nixosTestArgs;
|
|
||||||
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
|
nixos-test-user-firewall-iptables = self.clanLib.test.containerTest ./user-firewall/iptables.nix nixosTestArgs;
|
||||||
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
|
nixos-test-user-firewall-nftables = self.clanLib.test.containerTest ./user-firewall/nftables.nix nixosTestArgs;
|
||||||
nixos-test-extra-python-packages = self.clanLib.test.containerTest ./test-extra-python-packages nixosTestArgs;
|
|
||||||
|
|
||||||
service-dummy-test = import ./service-dummy-test nixosTestArgs;
|
service-dummy-test = import ./service-dummy-test nixosTestArgs;
|
||||||
|
wireguard = import ./wireguard nixosTestArgs;
|
||||||
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
|
service-dummy-test-from-flake = import ./service-dummy-test-from-flake nixosTestArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -130,7 +128,7 @@ in
|
|||||||
// flakeOutputs
|
// flakeOutputs
|
||||||
// {
|
// {
|
||||||
clan-core-for-checks = pkgs.runCommand "clan-core-for-checks" { } ''
|
clan-core-for-checks = pkgs.runCommand "clan-core-for-checks" { } ''
|
||||||
cp -r ${privateInputs.clan-core-for-checks} $out
|
cp -r ${self} $out
|
||||||
chmod -R +w $out
|
chmod -R +w $out
|
||||||
cp ${../flake.lock} $out/flake.lock
|
cp ${../flake.lock} $out/flake.lock
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
modules.new-service = {
|
modules.new-service = {
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "new-service";
|
manifest.name = "new-service";
|
||||||
manifest.readme = "Just a sample readme to not trigger the warning.";
|
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer that uses the new-service to generate some files.";
|
description = "A peer that uses the new-service to generate some files.";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ nixosLib.runTest (
|
|||||||
modules.new-service = {
|
modules.new-service = {
|
||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "new-service";
|
manifest.name = "new-service";
|
||||||
manifest.readme = "Just a sample readme to not trigger the warning.";
|
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer that uses the new-service to generate some files.";
|
description = "A peer that uses the new-service to generate some files.";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
{ self, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
|
|
||||||
cli = self.packages.${pkgs.hostPlatform.system}.clan-cli-full;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
name = "systemd-abstraction";
|
|
||||||
|
|
||||||
nodes = {
|
|
||||||
peer1 = {
|
|
||||||
|
|
||||||
users.users.text-user = {
|
|
||||||
isNormalUser = true;
|
|
||||||
linger = true;
|
|
||||||
uid = 1000;
|
|
||||||
extraGroups = [ "systemd-journal" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# Set environment variables for user systemd
|
|
||||||
environment.extraInit = ''
|
|
||||||
if [ "$(id -u)" = "1000" ]; then
|
|
||||||
export XDG_RUNTIME_DIR="/run/user/1000"
|
|
||||||
export DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
|
|
||||||
# Enable PAM for user systemd sessions
|
|
||||||
security.pam.services.systemd-user = {
|
|
||||||
startSession = true;
|
|
||||||
# Workaround for containers - use pam_permit to avoid helper binary issues
|
|
||||||
text = pkgs.lib.mkForce ''
|
|
||||||
account required pam_permit.so
|
|
||||||
session required pam_permit.so
|
|
||||||
session required pam_env.so conffile=/etc/pam/environment readenv=0
|
|
||||||
session required ${pkgs.systemd}/lib/security/pam_systemd.so
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = [
|
|
||||||
cli
|
|
||||||
(cli.pythonRuntime.withPackages (
|
|
||||||
ps: with ps; [
|
|
||||||
pytest
|
|
||||||
pytest-xdist
|
|
||||||
]
|
|
||||||
))
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript =
|
|
||||||
{ ... }:
|
|
||||||
''
|
|
||||||
start_all()
|
|
||||||
|
|
||||||
peer1.wait_for_unit("multi-user.target")
|
|
||||||
peer1.wait_for_unit("user@1000.service")
|
|
||||||
|
|
||||||
# Fix user journal permissions so text-user can read their own logs
|
|
||||||
peer1.succeed("chown text-user:systemd-journal /var/log/journal/*/user-1000.journal*")
|
|
||||||
peer1.succeed("chmod 640 /var/log/journal/*/user-1000.journal*")
|
|
||||||
|
|
||||||
# Run tests as text-user (environment variables are set automatically)
|
|
||||||
peer1.succeed("su - text-user -c 'pytest -s -n0 ${cli}/${cli.pythonRuntime.sitePackages}/clan_lib/service_runner'")
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
(
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
name = "test-extra-python-packages";
|
|
||||||
|
|
||||||
extraPythonPackages = ps: [ ps.numpy ];
|
|
||||||
|
|
||||||
nodes.machine =
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
networking.hostName = "machine";
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
start_all()
|
|
||||||
machine.wait_for_unit("multi-user.target")
|
|
||||||
|
|
||||||
# Test availability of numpy
|
|
||||||
arr = np.array([1, 2, 3])
|
|
||||||
print(f"Numpy array: {arr}")
|
|
||||||
assert len(arr) == 3
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
)
|
|
||||||
115
checks/wireguard/default.nix
Normal file
115
checks/wireguard/default.nix
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
nixosLib,
|
||||||
|
clan-core,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
nixosLib.runTest (
|
||||||
|
{ ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
machines = [
|
||||||
|
"controller1"
|
||||||
|
"controller2"
|
||||||
|
"peer1"
|
||||||
|
"peer2"
|
||||||
|
"peer3"
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
clan-core.modules.nixosTest.clanTest
|
||||||
|
];
|
||||||
|
|
||||||
|
hostPkgs = pkgs;
|
||||||
|
|
||||||
|
name = "wireguard";
|
||||||
|
|
||||||
|
clan = {
|
||||||
|
directory = ./.;
|
||||||
|
modules."@clan/wireguard" = import ../../clanServices/wireguard/default.nix;
|
||||||
|
inventory = {
|
||||||
|
|
||||||
|
machines = lib.genAttrs machines (_: { });
|
||||||
|
|
||||||
|
instances = {
|
||||||
|
|
||||||
|
/*
|
||||||
|
wg-test-one
|
||||||
|
┌───────────────────────────────┐
|
||||||
|
│ ◄───────────── │
|
||||||
|
│ controller2 controller1
|
||||||
|
│ ▲ ─────────────► ▲ ▲
|
||||||
|
│ │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ │ │ │ │ │
|
||||||
|
│ │ │ │ └───────────────┐ │ │ │ │
|
||||||
|
│ │ │ └──────────────┐ │ │ │ │ │
|
||||||
|
│ ▼ │ ▼ ▼ ▼
|
||||||
|
└─► peer2 │ peer1 peer3
|
||||||
|
│ ▲
|
||||||
|
└──────────┘
|
||||||
|
*/
|
||||||
|
|
||||||
|
wg-test-one = {
|
||||||
|
|
||||||
|
module.name = "@clan/wireguard";
|
||||||
|
module.input = "self";
|
||||||
|
|
||||||
|
roles.controller.machines."controller1".settings = {
|
||||||
|
endpoint = "192.168.1.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
roles.controller.machines."controller2".settings = {
|
||||||
|
endpoint = "192.168.1.2";
|
||||||
|
};
|
||||||
|
|
||||||
|
roles.peer.machines = {
|
||||||
|
peer1.settings.controller = "controller1";
|
||||||
|
peer2.settings.controller = "controller2";
|
||||||
|
peer3.settings.controller = "controller1";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: Will this actually work with conflicting ports? Can we re-use interfaces?
|
||||||
|
#wg-test-two = {
|
||||||
|
# module.name = "@clan/wireguard";
|
||||||
|
|
||||||
|
# roles.controller.machines."controller1".settings = {
|
||||||
|
# endpoint = "192.168.1.1";
|
||||||
|
# port = 51922;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# roles.peer.machines = {
|
||||||
|
# peer1 = { };
|
||||||
|
# };
|
||||||
|
#};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
testScript = ''
|
||||||
|
start_all()
|
||||||
|
|
||||||
|
# Show all addresses
|
||||||
|
machines = [peer1, peer2, peer3, controller1, controller2]
|
||||||
|
for m in machines:
|
||||||
|
m.systemctl("start network-online.target")
|
||||||
|
|
||||||
|
for m in machines:
|
||||||
|
m.wait_for_unit("network-online.target")
|
||||||
|
m.wait_for_unit("systemd-networkd.service")
|
||||||
|
|
||||||
|
print("\n\n" + "="*60)
|
||||||
|
print("STARTING PING TESTS")
|
||||||
|
print("="*60)
|
||||||
|
|
||||||
|
for m1 in machines:
|
||||||
|
for m2 in machines:
|
||||||
|
if m1 != m2:
|
||||||
|
print(f"\n--- Pinging from {m1.name} to {m2.name}.wg-test-one ---")
|
||||||
|
m1.wait_until_succeeds(f"ping -c1 {m2.name}.wg-test-one >&2")
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
The admin service aggregates components that allow an administrator to log in to and manage the machine.
|
|
||||||
|
|
||||||
The following configuration:
|
|
||||||
|
|
||||||
1. Enables OpenSSH with root login and adds an SSH public key named`myusersKey` to the machine's authorized_keys via the `allowedKeys` setting.
|
|
||||||
|
|
||||||
2. Automatically generates a password for the root user.
|
|
||||||
|
|
||||||
```nix
|
|
||||||
instances = {
|
|
||||||
admin = {
|
|
||||||
roles.default.tags = {
|
|
||||||
all = { };
|
|
||||||
};
|
|
||||||
roles.default.settings = {
|
|
||||||
allowedKeys = {
|
|
||||||
myusersKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFDNnynMbFWatSFdANzbJ8iiEKL7+9ZpDaMLrWRQjyH lhebendanz@wintux";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
manifest.name = "clan-core/admin";
|
manifest.name = "clan-core/admin";
|
||||||
manifest.description = "Adds a root user with ssh access";
|
manifest.description = "Adds a root user with ssh access";
|
||||||
manifest.categories = [ "Utility" ];
|
manifest.categories = [ "Utility" ];
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the admin service";
|
description = "Placeholder role to apply the admin service";
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ let
|
|||||||
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
public-key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII6zj7ubTg6z/aDwRNwvM/WlQdUocMprQ8E92NWxl6t+ test@test";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
name = "admin";
|
name = "service-admin";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "borgbackup";
|
name = "service-borgbackup";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -50,13 +50,13 @@
|
|||||||
dns =
|
dns =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.net-tools ];
|
environment.systemPackages = [ pkgs.nettools ];
|
||||||
};
|
};
|
||||||
|
|
||||||
client =
|
client =
|
||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.net-tools ];
|
environment.systemPackages = [ pkgs.nettools ];
|
||||||
};
|
};
|
||||||
|
|
||||||
server01 = {
|
server01 = {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ in
|
|||||||
perSystem =
|
perSystem =
|
||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
clan.nixosTests.data-mesher = {
|
clan.nixosTests.service-data-mesher = {
|
||||||
imports = [ ./tests/vm/default.nix ];
|
imports = [ ./tests/vm/default.nix ];
|
||||||
clan.modules."@clan/data-mesher" = module;
|
clan.modules."@clan/data-mesher" = module;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "data-mesher";
|
name = "service-data-mesher";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "dyndns";
|
name = "service-dyndns";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"publickey": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
|
||||||
"type": "age"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"data": "ENC[AES256_GCM,data:seLxbv590dO0KvMJmtN7WVvUcH27VYwAc3rmyD7q6ZmwCgswOKx55LFnh0stRDKSZa8K7Dq1x7D9adhZtPAMWX8tbJswBeNMPt8=,iv:G52eugxfTi0tTzH4EN4CWmpyv6feSL34++UVSjb0aAo=,tag:6r10/a7kD2hBAmae0nz2OQ==,type:str]",
|
|
||||||
"sops": {
|
|
||||||
"age": [
|
|
||||||
{
|
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHVC8wZUZJYUl5MXVNa2k5\ndGV1MnFWbUNLNVdxeEtCVUc3MTd0ck9aeFFBCnFhZW40amVYc3FlN1FPRTFSWTJR\nQzhNOERKbnRnSlJVeElNSEM5ZUJsZGsKLS0tIG1uNnlNN3MweHlYczNRTW9xSytu\neThzUmxKZTJBT2lCcTdiNUI4N3paTVEKgS9j2/GVt1KBoggUj9d6UK/mIlK4niLQ\nzVq2BHt3irxQpkpGUogXH2b86zSAOEJFzsL1Rk8HM1mogTG8jqf0qA==\n-----END AGE ENCRYPTED FILE-----\n"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lastmodified": "2025-10-19T12:49:11Z",
|
|
||||||
"mac": "ENC[AES256_GCM,data:T/2xw2mvUi8YALyxz78qG/g/xguoUTeHNzcZfXwwSyCXMg9ircsGGLO9SOVWy/QNkibnw3Yp80tXNJyr4oJH28PhFH7RrRp8jzNdopF49ZNJb2IqJ3C7xNYRZMHfjOCd/raka+ehZq8YGilEpXUWLRk1ere9lbBMh1ycL7jJS3c=,iv:FZbY/jTNPM+p4qD41FD0K7B9zoppGuvnUY5hL/EkmYM=,tag:IF5QTyUkHXWthlAGBn9R8w==,type:str]",
|
|
||||||
"version": "3.11.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../../../sops/machines/server
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
"data": "ENC[AES256_GCM,data:Zu+n+DDYP7rQRTS17PJ6Apo=,iv:5WOs81Pj+S85kdC1AlOXSyPMGDfwM5UD8x7nyRZtRYQ=,tag:2JYkGnLugAni49Upv43o2g==,type:str]",
|
|
||||||
"sops": {
|
|
||||||
"age": [
|
|
||||||
{
|
|
||||||
"recipient": "age164wrhlnake7f7duhzs936lq6w49dtg53hcdyxqwxj0agad6tqg2s2u4yta",
|
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlR3RGQ2ZLTkR3ZWxNVCsv\naXJHRjBiVUVYZVRIY2swY2xubGhmb3pLRkNvCldhQUV2WDlqYjZ4ZUFWYXkvUEEw\nZi9XRWw0Mi9mRENDcnI0aENDR2Z4MHcKLS0tIGFQU3Q4WEErbnBjOHpNR1BSR2cr\nRFg0anE1cHExT0sySmxuUks1R05nczAKZO3R6+f9co2+YGO8HPufoq1fLqqrdTWD\n4zqemMmG2BjMRDumxtcKp8CLaZWlJoP4e/+tonfdoe42qmNF5NJcFw==\n-----END AGE ENCRYPTED FILE-----\n"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"recipient": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzZWo4WGh1cWxKeDhDdlBm\nTVFjVFBIUU9xaGRkanNHaUVUUHN1czNRSUhNCkp5MmwzSGdycmsrZGhaRUhEbXBF\nNUhtdEF6bHZQOGJYUVhFVHlYc3FPODAKLS0tIDBRQ2VGT2IvU1F4MEVabzhYSFJq\nOWZmbGpkQmNSMnNKa0s4K2JXdGgwRlkKUQRREpG5H1mNHSc/cZrdMiSz0veJFR4N\n+W49XL/wQUZwajykwYj++G+dWDO7DQ+fpbB9w4mzbsAmCsXirseTLA==\n-----END AGE ENCRYPTED FILE-----\n"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"lastmodified": "2025-10-19T12:49:11Z",
|
|
||||||
"mac": "ENC[AES256_GCM,data:0msda7WbQQxXQ+juT7yErgT7NADgnzqEZLTQw+4JPuAE4xcqRIYwrrAALaA0GCCM2aIWlICzJigLCuzQUfSUbIzeP79tEHiKez+NOt/xgSM9ljz7GlsmLd0vzkxdt3WSxP+sHxy0S866N2sLMUkLqPGdqeTjB+Jji5ghGhzk9ys=,iv:8UU7iA4SdR6ZlVolm708l2Iea0sQYRT+5wPBBP5tpS0=,tag:VQXslAlqLqs1QEkwW6x6qg==,type:str]",
|
|
||||||
"version": "3.11.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
../../../../../sops/users/admin
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[Garage](https://garagehq.deuxfleurs.fr/) is an open-source, S3-compatible distributed object storage service for self-hosting.
|
|
||||||
|
|
||||||
This module provisions a single-instance S3 bucket. To customize its behavior, set `services.garage.settings` in your Nix configuration.
|
|
||||||
|
|
||||||
Example configuration:
|
|
||||||
```
|
|
||||||
instances = {
|
|
||||||
garage = {
|
|
||||||
roles.default.machines."server" = {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
manifest.name = "clan-core/garage";
|
manifest.name = "clan-core/garage";
|
||||||
manifest.description = "S3-compatible object store for small self-hosted geo-distributed deployments";
|
manifest.description = "S3-compatible object store for small self-hosted geo-distributed deployments";
|
||||||
manifest.categories = [ "System" ];
|
manifest.categories = [ "System" ];
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the garage service";
|
description = "Placeholder role to apply the garage service";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "garage";
|
name = "service-garage";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
This a test README just to appease the eval warnings if we don't have one
|
|
||||||
@@ -9,7 +9,6 @@
|
|||||||
_class = "clan.service";
|
_class = "clan.service";
|
||||||
manifest.name = "clan-core/hello-word";
|
manifest.name = "clan-core/hello-word";
|
||||||
manifest.description = "This is a test";
|
manifest.description = "This is a test";
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
# This service provides two roles: "morning" and "evening". Roles can be
|
# This service provides two roles: "morning" and "evening". Roles can be
|
||||||
# defined in this file directly (e.g. the "morning" role) or split up into a
|
# defined in this file directly (e.g. the "morning" role) or split up into a
|
||||||
@@ -35,13 +34,10 @@
|
|||||||
settings,
|
settings,
|
||||||
|
|
||||||
# The name of this instance of the service
|
# The name of this instance of the service
|
||||||
instanceName,
|
|
||||||
|
|
||||||
# The current machine
|
# The current machine
|
||||||
machine,
|
|
||||||
|
|
||||||
# All roles of this service, with their assigned machines
|
# All roles of this service, with their assigned machines
|
||||||
roles,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
name = "hello-service";
|
name = "service-hello-service";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
🚧🚧🚧 Experimental 🚧🚧🚧
|
|
||||||
|
|
||||||
Use at your own risk.
|
|
||||||
|
|
||||||
We are still refining its interfaces, instability and breakages are expected.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
This module is part of Clan's [networking interface](https://docs.clan.lol/guides/networking/networking/).
|
|
||||||
|
|
||||||
Clan's networking module automatically manages connections across available network transports and falls back intelligently. When you run `clan ssh` or `clan machines update`, Clan attempts each configured network in priority order until a connection succeeds.
|
|
||||||
|
|
||||||
The example below shows how to configure a domain so server1 is reachable over the clearnet. By default, the `internet` module has the highest priority among networks.
|
|
||||||
|
|
||||||
```nix
|
|
||||||
inventory.instances = {
|
|
||||||
# Direct SSH with fallback support
|
|
||||||
internet = {
|
|
||||||
roles.default.machines.server1 = {
|
|
||||||
settings.host = "server1.example.com";
|
|
||||||
};
|
|
||||||
roles.default.machines.server2 = {
|
|
||||||
settings.host = "192.168.1.100";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
];
|
];
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the internet service";
|
description = "Placeholder role to apply the internet service";
|
||||||
interface =
|
interface =
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
This module sets up the [KDE Plasma](https://kde.org) Desktop environment.
|
|
||||||
|
|
||||||
!!! Note "Customisation"
|
|
||||||
This service intentionally does not provide any settings or customisation
|
|
||||||
options, as desktop preferences are highly subjective. Clan currently
|
|
||||||
supports only this default desktop configuration. Any additional
|
|
||||||
customisation can be done via the `extraModules` option. Furthermore, if you
|
|
||||||
want to use a different desktop environment or compositor (e.g. Gnome or
|
|
||||||
sway), we encourage you to to build your own
|
|
||||||
[Clan Service](https://docs.clan.lol/guides/services/community/) or have a
|
|
||||||
look at the [Community Services](https://docs.clan.lol/services/community/).
|
|
||||||
|
|
||||||
## Example Usage
|
|
||||||
|
|
||||||
```nix
|
|
||||||
inventory = {
|
|
||||||
instances = {
|
|
||||||
kde = {
|
|
||||||
|
|
||||||
# Deploy on all machines
|
|
||||||
roles.default.tags.all = { };
|
|
||||||
|
|
||||||
# Or individual hosts
|
|
||||||
roles.default.machines.laptop = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
{
|
|
||||||
_class = "clan.service";
|
|
||||||
manifest.name = "clan-core/kde";
|
|
||||||
manifest.description = "Sets up a graphical desktop environment";
|
|
||||||
manifest.categories = [ "Desktop" ];
|
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
roles.default = {
|
|
||||||
description = "KDE/Plasma (wayland): Full-featured desktop environment with modern Qt-based interface";
|
|
||||||
perInstance.nixosModule = {
|
|
||||||
services = {
|
|
||||||
displayManager.sddm.enable = true;
|
|
||||||
displayManager.sddm.wayland.enable = true;
|
|
||||||
desktopManager.plasma6.enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
self,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
module = lib.modules.importApply ./default.nix {
|
|
||||||
inherit (self) packages;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
{
|
|
||||||
clan.modules = {
|
|
||||||
kde = module;
|
|
||||||
};
|
|
||||||
perSystem =
|
|
||||||
{ ... }:
|
|
||||||
{
|
|
||||||
clan.nixosTests.kde = {
|
|
||||||
imports = [ ./tests/vm/default.nix ];
|
|
||||||
|
|
||||||
clan.modules.kde = module;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
{
|
|
||||||
name = "kde";
|
|
||||||
|
|
||||||
clan = {
|
|
||||||
directory = ./.;
|
|
||||||
inventory = {
|
|
||||||
|
|
||||||
machines.client = { };
|
|
||||||
|
|
||||||
instances = {
|
|
||||||
kde = {
|
|
||||||
module.name = "kde";
|
|
||||||
module.input = "self";
|
|
||||||
roles.default.machines."client" = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
testScript = ''
|
|
||||||
start_all()
|
|
||||||
|
|
||||||
client.systemctl("start network-online.target")
|
|
||||||
client.wait_for_unit("network-online.target")
|
|
||||||
|
|
||||||
client.wait_for_unit("graphical.target")
|
|
||||||
client.wait_for_unit("display-manager.service")
|
|
||||||
client.succeed("systemctl status display-manager.service")
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
|
||||||
"type": "age"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{ ... }:
|
{ ... }:
|
||||||
{
|
{
|
||||||
name = "localbackup";
|
name = "service-localbackup";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
directory = ./.;
|
directory = ./.;
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"publickey": "age1qm0p4vf9jvcnn43s6l4prk8zn6cx0ep9gzvevxecv729xz540v8qa742eg",
|
|
||||||
"type": "age"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
This NixOS module installs and configures Synapse — a federated Matrix homeserver with end-to-end encryption — and optionally provides the Element web client.
|
|
||||||
|
|
||||||
The example below demonstrates a minimal setup that includes:
|
|
||||||
|
|
||||||
- Element web client.
|
|
||||||
- Synapse backed by PostgreSQL and nginx.
|
|
||||||
- An admin user and an additional regular user.
|
|
||||||
|
|
||||||
Example configuration:
|
|
||||||
|
|
||||||
```nix
|
|
||||||
instances = {
|
|
||||||
matrix-synapse = {
|
|
||||||
roles.default.machines."jon".settings = {
|
|
||||||
acmeEmail = "admins@clan.lol";
|
|
||||||
server_tld = "clan.test";
|
|
||||||
app_domain = "matrix.clan.test";
|
|
||||||
users.admin.admin = true;
|
|
||||||
users.someuser = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
manifest.name = "clan-core/matrix-synapese";
|
manifest.name = "clan-core/matrix-synapese";
|
||||||
manifest.description = "A federated messaging server with end-to-end encryption.";
|
manifest.description = "A federated messaging server with end-to-end encryption.";
|
||||||
manifest.categories = [ "Social" ];
|
manifest.categories = [ "Social" ];
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
roles.default = {
|
roles.default = {
|
||||||
description = "Placeholder role to apply the matrix-synapse service";
|
description = "Placeholder role to apply the matrix-synapse service";
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
[Mycelium](https://github.com/threefoldtech/mycelium) is an end-to-end encrypted IPv6 overlay network that spans the globe.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
- Locality-aware routing: finds the shortest path between nodes.
|
|
||||||
- All traffic is end-to-end encrypted.
|
|
||||||
- Can route traffic via friend nodes and is location-aware.
|
|
||||||
- Automatic rerouting if a physical link goes down.
|
|
||||||
- IPv6 addresses are derived from private keys.
|
|
||||||
- A simple, reliable message bus is implemented on top of Mycelium.
|
|
||||||
- Supports multiple transports (QUIC, TCP, …). Hole punching for QUIC is in progress to enable true P2P connectivity behind NATs.
|
|
||||||
- Designed for planetary-scale scalability; previous overlay networks reached practical limits, and Mycelium focuses on scaling.
|
|
||||||
- Can run without a TUN device and be used solely as a reliable message bus.
|
|
||||||
|
|
||||||
Example configuration below connects all your machines to the Mycelium network:
|
|
||||||
```nix
|
|
||||||
mycelium = {
|
|
||||||
roles.peer.tags.all = {};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
@@ -7,7 +7,6 @@
|
|||||||
"System"
|
"System"
|
||||||
"Network"
|
"Network"
|
||||||
];
|
];
|
||||||
manifest.readme = builtins.readFile ./README.md;
|
|
||||||
|
|
||||||
roles.peer = {
|
roles.peer = {
|
||||||
description = "A peer in the mycelium network";
|
description = "A peer in the mycelium network";
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
name = "mycelium";
|
name = "service-mycelium";
|
||||||
|
|
||||||
clan = {
|
clan = {
|
||||||
test.useContainers = false;
|
test.useContainers = false;
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
25.11
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
This service is meant to be consumed by the UI / API, and exposes a JSON serializable interface to add packages to a machine over the inventory.
|
|
||||||
|
|
||||||
The example below demonstrates installing the "cbonsai" application to a machine named "server.
|
|
||||||
|
|
||||||
```
|
|
||||||
instances.packages = {
|
|
||||||
roles.default.machines."server".settings = {
|
|
||||||
packages = [ "cbonsai" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
```
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user