forked from clan/clan-core
Compare commits
407 Commits
docs/impro
...
main
Author | SHA1 | Date | |
---|---|---|---|
0027c46313 | |||
ca2001040b | |||
d6725100ac | |||
503ce29c84 | |||
87444cd2b8 | |||
31eca9e8bc | |||
822afe08b5 | |||
cfb78b0edb | |||
65fd7d3efe | |||
e8241fb7c9 | |||
259d51bdc8 | |||
f6fb52afbf | |||
8089b87bbb | |||
578162425d | |||
dbad63f155 | |||
da8a733899 | |||
8f58f1998d | |||
|
c43fe5187f | ||
0993fe45f6 | |||
ba86b49952 | |||
0b34c340fc | |||
d513f66170 | |||
320fb776ea | |||
1a39957dbb | |||
b5abe4025a | |||
55f4dcc460 | |||
ef4a83f739 | |||
133f2b705f | |||
83fe58e003 | |||
481f926b17 | |||
788eae432a | |||
b7936c4ed2 | |||
750c8df003 | |||
276c39aba4 | |||
90e25eeb76 | |||
56676701ae | |||
bcccf301f0 | |||
e343ba5635 | |||
66fe5ec4fd | |||
f2a884ec30 | |||
d31aa7cf88 | |||
9f19a8e605 | |||
23ef39a2d9 | |||
dda82c49b0 | |||
c91c90a2a6 | |||
5794cdf8fa | |||
01a4748d6b | |||
a8762522c8 | |||
adef52a938 | |||
c8fbf87fc8 | |||
f63e3618c2 | |||
b18d7bfeac | |||
076b98ff00 | |||
6999685bba | |||
f1c02bbd46 | |||
2caa837537 | |||
e1ddbf226a | |||
7cb8c114c2 | |||
5945630870 | |||
ccadac4bb3 | |||
15b77f6b8a | |||
9bf76037aa | |||
d0d973b797 | |||
c1e2bc9ea9 | |||
0eef21e2ef | |||
461aa579c2 | |||
da442c47f6 | |||
491d37ea67 | |||
7e087d18ee | |||
5c75a6490b | |||
750b6aec59 | |||
d138e29a53 | |||
a7febba9c8 | |||
f0f97baa65 | |||
c2dc94507e | |||
7c0aaab463 | |||
5dcac604d1 | |||
96746b7c98 | |||
2ae50b7398 | |||
3c905c5072 | |||
5b926f57cc | |||
b9788a5dba | |||
7078f09872 | |||
1aa7808c02 | |||
ba8a51101d | |||
de69c970aa | |||
fe5fa6a85d | |||
de74febf64 | |||
3b6483e819 | |||
dcd6ad0983 | |||
567d979243 | |||
c81a8681b0 | |||
31cde90819 | |||
a77bf5bf21 | |||
4befa80eb8 | |||
52584662a8 | |||
de147f63e9 | |||
96c33dec7a | |||
3c0b5f0867 | |||
c252f11c1f | |||
f1f040397d | |||
418e9937cb | |||
c34664429c | |||
6fe5928297 | |||
eee99730d1 | |||
9394760e3b | |||
a0b0e1a0ac | |||
dbaa26ccaa | |||
d1591d4485 | |||
c68a8306ba | |||
ec9f605004 | |||
e60efea1f7 | |||
efacb7f184 | |||
67275aac63 | |||
a704a05b15 | |||
01aafc520d | |||
c0a54f539a | |||
e2d7e6e86c | |||
1df4e361f7 | |||
e8bd5ad24b | |||
775f993ecc | |||
0e1478edcd | |||
bfc1203a8a | |||
2bd8b144b9 | |||
b52b2221b0 | |||
64adf17368 | |||
509d8c1dae | |||
295de17640 | |||
b158c2706f | |||
750979c988 | |||
6d7849a03c | |||
f46fd3ace6 | |||
6e9f1515d3 | |||
81e0700826 | |||
4daf036a3c | |||
4faab0a20f | |||
76622557c4 | |||
4c4c94c508 | |||
b0d5ef01ca | |||
ab656d5655 | |||
ed171f0264 | |||
270f9d54cb | |||
73f486fe13 | |||
7da6826344 | |||
f54c518fd7 | |||
522fd1bcaa | |||
be5c3accfe | |||
3998efac78 | |||
691ae9fb15 | |||
fc8a64ef49 | |||
c0f3810e01 | |||
39d8cf91cf | |||
233b973120 | |||
f3f2f6df69 | |||
ec824becc8 | |||
7fbb50fcc8 | |||
33695f7470 | |||
001ed3283a | |||
9ae7d4a24b | |||
e39911d99c | |||
9c3da78792 | |||
69ddda24c9 | |||
c6f078fafc | |||
4e3ed011da | |||
a71191486c | |||
d3e6276d04 | |||
a1e2d1017e | |||
114b0b02d0 | |||
de3e133981 | |||
083e30f468 | |||
d7ef88c67c | |||
055b17c01b | |||
4b07bf363b | |||
97928801f9 | |||
fdacfb8ecf | |||
508a26d68d | |||
8055c21984 | |||
9bb6ed313f | |||
8c36df77cc | |||
2284b060be | |||
491b5d28f2 | |||
bf212ce9c4 | |||
35be09feaa | |||
4ee90b4b9f | |||
cab69935ef | |||
54fcfda43e | |||
d137342243 | |||
3eba6e85cc | |||
d395e2abf3 | |||
b971156df1 | |||
c885a3fec8 | |||
ae7794dddd | |||
acaa69e2bf | |||
e37f7e2760 | |||
245b615209 | |||
a78f5b2bec | |||
396caeff39 | |||
d5a639104d | |||
fb1b428c12 | |||
bfe37c2457 | |||
39b34d9ff3 | |||
fd29ed4693 | |||
9db4e5cf2f | |||
e28a02ec73 | |||
c1e7e25641 | |||
21104a0465 | |||
0f53475499 | |||
7aa85d8aaf | |||
e9b0ce6a78 | |||
d174fbd445 | |||
8687801cee | |||
6ebfd29c87 | |||
c8456f7d68 | |||
6b03645f7a | |||
2cb7adb377 | |||
78ab7ebc7f | |||
|
82a4ecf82b | ||
43b56e21b2 | |||
a47c2f3e69 | |||
a34fa4f69b | |||
e13217b1c9 | |||
1e4a3a3eee | |||
e39d8cb909 | |||
7c48730bbb | |||
da5f363bee | |||
24ec74ae37 | |||
64a98281f0 | |||
5863ddca0e | |||
5de3ab88e9 | |||
4cfc335e2c | |||
e25bd69c68 | |||
fe17f9e1a1 | |||
7980f13bed | |||
fef16a84a9 | |||
97a1d8b52a | |||
f9b32cbd09 | |||
4d66f2a14c | |||
473c236214 | |||
eeaf1c84a9 | |||
f6efd11eae | |||
8762ee4420 | |||
0568608be6 | |||
a0194f34d2 | |||
b3297532ad | |||
cd915e171f | |||
1e94bf02da | |||
1c2781267b | |||
ac8162a08d | |||
1476619515 | |||
8288048682 | |||
fd41badbc6 | |||
d574faf253 | |||
81522c96e5 | |||
e668a7f536 | |||
3293ac0c14 | |||
be841cdec2 | |||
49e39ec505 | |||
c25f7934ba | |||
4f6d25160f | |||
0bf9a566eb | |||
148a0c90cc | |||
789bf3d0c8 | |||
59c558ffc6 | |||
c5e62074a6 | |||
9999379f81 | |||
dd1cfe3834 | |||
cd0b360b49 | |||
8c0fb90c1a | |||
86ae7cbbfb | |||
fdf63fd605 | |||
82fa89b57e | |||
cad492e830 | |||
2abd5bbe37 | |||
aad130166f | |||
3e9a1ea68f | |||
2acd06c9fa | |||
f45d3385c2 | |||
23c9291912 | |||
1893ebef19 | |||
fd00a941dc | |||
9ab5a9507d | |||
1a4c20e49e | |||
f138e59da8 | |||
ddd9318ea1 | |||
aee2fdcffa | |||
d1b810dfad | |||
4dede0ee5c | |||
3506d6ba0d | |||
f2a3415e2c | |||
2e821c4525 | |||
bbba7e9087 | |||
15dd4ea25f | |||
5a6eeda125 | |||
f8e08a610e | |||
fc7f544199 | |||
8aaa95737a | |||
7dedae9920 | |||
01e5b02633 | |||
f4de3ac83d | |||
9e65cf2b5b | |||
8134583641 | |||
5d8ee29ed4 | |||
d9ce211d1a | |||
9ec8b71765 | |||
4fef9c3652 | |||
393ed517e2 | |||
159198b81a | |||
|
83ea2312a1 | ||
022a55639f | |||
6f2430b191 | |||
6236defde6 | |||
9a8a5f4c00 | |||
6908527ebd | |||
d013ef20da | |||
570f04ecdc | |||
3a9a7eedf9 | |||
ee552d3020 | |||
b95d95554a | |||
a09e680fa0 | |||
853d8221c0 | |||
43c799c3d0 | |||
f231f1e0c7 | |||
a48df5b993 | |||
e08342a6f3 | |||
e0f56c3c6b | |||
64c5a81f74 | |||
56fad0fd4a | |||
3dce5d2f95 | |||
bfe4f2c8f4 | |||
1051367ca4 | |||
480bb396ed | |||
b5653c169b | |||
5606101ce8 | |||
3da4117702 | |||
f383c6f82d | |||
af86980192 | |||
c681cc0998 | |||
0804e5e415 | |||
95f93d8800 | |||
4602c06835 | |||
a3f6996d69 | |||
7f424c862b | |||
94449a02d5 | |||
ed14f3e827 | |||
152a908dc9 | |||
ac0cb620cf | |||
6a484fef66 | |||
fc1bf17b9c | |||
39d6edc673 | |||
4a66cdffaf | |||
216c560830 | |||
cf67de2f69 | |||
b702ca686e | |||
acdb0a9b27 | |||
70ed0757a3 | |||
9778c432c2 | |||
1da6a0c5a2 | |||
5f5155023c | |||
1366d0bcf6 | |||
351571a655 | |||
3c02453705 | |||
7a74c86c70 | |||
4ae5b24d24 | |||
05b510230f | |||
9cb23b807c | |||
0a1cc29abf | |||
1a87df646d | |||
4964415d34 | |||
9ac0839bd5 | |||
6becce81cb | |||
8b1eae8c27 | |||
5cfc9f7db4 | |||
2c96e467fa | |||
3db2ecece6 | |||
8d74983103 | |||
81f7237a41 | |||
3ebc2e8be9 | |||
a810e96a20 | |||
1a99e033eb | |||
6d2ec12cca | |||
e81a7415d8 | |||
d2dffe30a3 | |||
a2074bb82b | |||
f964304224 | |||
72811d0828 | |||
22b767466c | |||
9f808b1bdb | |||
ed9d65a91c | |||
87559613ed | |||
0bae84b1ae | |||
498d29cca1 | |||
a33a76ecd2 | |||
8658e1694a | |||
0dde758296 | |||
5e33a0b3b8 | |||
c57cc5204c | |||
9a3f27ea08 | |||
b7f5e98db0 | |||
1db0ace17b | |||
059e4efcdc | |||
581b48b518 | |||
f8b881c41e | |||
dcad0d0d79 | |||
a4b15d2ca2 | |||
f385e0e037 | |||
060e3baa08 | |||
2d42af3675 |
@ -5,11 +5,6 @@ on:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
checks:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: nix run --refresh github:Mic92/nix-fast-build -- --no-nom --eval-workers 10
|
||||
checks-impure:
|
||||
runs-on: nix
|
||||
steps:
|
||||
|
13
.gitea/workflows/deploy.yaml
Normal file
13
.gitea/workflows/deploy.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
name: deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy-docs:
|
||||
runs-on: nix
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: nix run .#deploy-docs
|
||||
env:
|
||||
SSH_HOMEPAGE_KEY: ${{ secrets.SSH_HOMEPAGE_KEY }}
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -13,6 +13,9 @@ nixos.qcow2
|
||||
**/*.glade~
|
||||
/docs/out
|
||||
|
||||
# dream2nix
|
||||
.dream2nix
|
||||
|
||||
# python
|
||||
__pycache__
|
||||
.coverage
|
||||
@ -28,3 +31,8 @@ build
|
||||
build-dir
|
||||
repo
|
||||
.env
|
||||
|
||||
# node
|
||||
node_modules
|
||||
dist
|
||||
.webui
|
@ -1,4 +1,4 @@
|
||||
# Contributing to cLAN
|
||||
# Contributing to Clan
|
||||
|
||||
## Live-reloading documentation
|
||||
|
||||
|
20
README.md
20
README.md
@ -1,6 +1,6 @@
|
||||
# cLAN Core Repository
|
||||
# Clan Core Repository
|
||||
|
||||
Welcome to the cLAN Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the cLAN project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
|
||||
Welcome to the Clan Core Repository, the heart of the [clan.lol](https://clan.lol/) project! This monorepo is the foundation of Clan, a revolutionary open-source project aimed at restoring fun, freedom, and functionality to computing. Here, you'll find all the essential packages, NixOS modules, CLI tools, and tests needed to contribute to and work with the Clan project. Clan leverages the Nix system to ensure reliability, security, and seamless management of digital environments, putting the power back into the hands of users.
|
||||
|
||||
## Why Clan?
|
||||
|
||||
@ -14,32 +14,32 @@ Our mission is simple: to democratize computing by providing tools that empower
|
||||
- **Robust Backup Management:** Long-term, self-hosted data preservation.
|
||||
- **Intuitive Secret Management:** Simplified encryption and password management processes.
|
||||
|
||||
## Getting Started with cLAN
|
||||
## Getting Started with Clan
|
||||
|
||||
If you're new to cLAN and eager to dive in, start with our quickstart guide and explore the core functionalities that Clan offers:
|
||||
If you're new to Clan and eager to dive in, start with our quickstart guide and explore the core functionalities that Clan offers:
|
||||
|
||||
- **Quickstart Guide**: Check out https://docs.clan.lol/#starting-with-a-new-clan-project<!-- [docs/site/index.md](docs/site/index.md) --> to get up and running with cLAN in no time.
|
||||
- **Quickstart Guide**: Check out [getting started](https://docs.clan.lol/#starting-with-a-new-clan-project)<!-- [docs/site/index.md](docs/site/index.md) --> to get up and running with Clan in no time.
|
||||
|
||||
### Managing Secrets
|
||||
|
||||
In the Clan ecosystem, security is paramount. Learn how to handle secrets effectively:
|
||||
|
||||
- **Secrets Management**: Securely manage secrets by consulting https://docs.clan.lol/getting-started/secrets/<!-- [secrets.md](docs/site/getting-started/secrets.md) -->.
|
||||
- **Secrets Management**: Securely manage secrets by consulting [secrets](https://docs.clan.lol/getting-started/secrets/)<!-- [secrets.md](docs/site/getting-started/secrets.md) -->.
|
||||
|
||||
### Contributing to cLAN
|
||||
### Contributing to Clan
|
||||
|
||||
The Clan project thrives on community contributions. We welcome everyone to contribute and collaborate:
|
||||
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in https://docs.clan.lol/contributing/contributing/<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
- **Contribution Guidelines**: Make a meaningful impact by following the steps in [contributing](https://docs.clan.lol/contributing/contributing/)<!-- [contributing.md](docs/CONTRIBUTING.md) -->.
|
||||
|
||||
## Join the Revolution
|
||||
|
||||
Clan is more than a tool; it's a movement towards a better digital future. By contributing to the cLAN project, you're part of changing technology for the better, together.
|
||||
Clan is more than a tool; it's a movement towards a better digital future. By contributing to the Clan project, you're part of changing technology for the better, together.
|
||||
|
||||
### Community and Support
|
||||
|
||||
Connect with us and the Clan community for support and discussion:
|
||||
|
||||
- [Matrix channel](https://matrix.to/#/!djzOHBBBHnwQkgNgdV:matrix.org?via=blog.clan.lol) for live discussions.
|
||||
- [Matrix channel](https://matrix.to/#/#clan:lassul.us) for live discussions.
|
||||
- IRC bridges (coming soon) for real-time chat support.
|
||||
|
||||
|
@ -145,14 +145,14 @@
|
||||
machine.succeed("echo testing > /var/test-backups/somefile")
|
||||
|
||||
# create
|
||||
machine.succeed("clan --debug --flake ${self} backups create test-backup")
|
||||
machine.succeed("clan backups create --debug --flake ${self} test-backup")
|
||||
machine.wait_until_succeeds("! systemctl is-active borgbackup-job-test-backup >&2")
|
||||
machine.succeed("test -f /run/mount-external-disk")
|
||||
machine.succeed("test -f /run/unmount-external-disk")
|
||||
|
||||
# list
|
||||
backup_id = json.loads(machine.succeed("borg-job-test-backup list --json"))["archives"][0]["archive"]
|
||||
out = machine.succeed("clan --debug --flake ${self} backups list test-backup").strip()
|
||||
out = machine.succeed("clan backups list --debug --flake ${self} test-backup").strip()
|
||||
print(out)
|
||||
assert backup_id in out, f"backup {backup_id} not found in {out}"
|
||||
localbackup_id = "hdd::/mnt/external-disk/snapshot.0"
|
||||
@ -160,14 +160,14 @@
|
||||
|
||||
## borgbackup restore
|
||||
machine.succeed("rm -f /var/test-backups/somefile")
|
||||
machine.succeed(f"clan --debug --flake ${self} backups restore test-backup borgbackup 'test-backup::borg@machine:.::{backup_id}' >&2")
|
||||
machine.succeed(f"clan backups restore --debug --flake ${self} test-backup borgbackup 'test-backup::borg@machine:.::{backup_id}' >&2")
|
||||
assert machine.succeed("cat /var/test-backups/somefile").strip() == "testing", "restore failed"
|
||||
machine.succeed("test -f /var/test-service/pre-restore-command")
|
||||
machine.succeed("test -f /var/test-service/post-restore-command")
|
||||
|
||||
## localbackup restore
|
||||
machine.succeed("rm -f /var/test-backups/somefile /var/test-service/{pre,post}-restore-command")
|
||||
machine.succeed(f"clan --debug --flake ${self} backups restore test-backup localbackup '{localbackup_id}' >&2")
|
||||
machine.succeed(f"clan backups restore --debug --flake ${self} test-backup localbackup '{localbackup_id}' >&2")
|
||||
assert machine.succeed("cat /var/test-backups/somefile").strip() == "testing", "restore failed"
|
||||
machine.succeed("test -f /var/test-service/pre-restore-command")
|
||||
machine.succeed("test -f /var/test-service/post-restore-command")
|
||||
|
@ -46,7 +46,6 @@
|
||||
syncthing = import ./syncthing nixosTestArgs;
|
||||
wayland-proxy-virtwl = import ./wayland-proxy-virtwl nixosTestArgs;
|
||||
};
|
||||
schemaTests = pkgs.callPackages ./schemas.nix { inherit self; };
|
||||
|
||||
flakeOutputs =
|
||||
lib.mapAttrs' (
|
||||
@ -58,7 +57,7 @@
|
||||
self'.legacyPackages.homeConfigurations or { }
|
||||
);
|
||||
in
|
||||
{ inherit renderClanOptions; } // nixosTests // schemaTests // flakeOutputs;
|
||||
{ inherit renderClanOptions; } // nixosTests // flakeOutputs;
|
||||
legacyPackages = {
|
||||
nixosTests =
|
||||
let
|
||||
|
@ -9,16 +9,16 @@
|
||||
}:
|
||||
let
|
||||
dependencies = [
|
||||
self
|
||||
pkgs.stdenv.drvPath
|
||||
pkgs.disko
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.toplevel
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.diskoScript
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.build.diskoScript.drvPath
|
||||
self.clanInternals.machines.${pkgs.hostPlatform.system}.test_install_machine.config.system.clan.deployment.file
|
||||
self.inputs.nixpkgs.legacyPackages.${pkgs.hostPlatform.system}.disko
|
||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||
in
|
||||
{
|
||||
# Currently disabled...
|
||||
checks = pkgs.lib.mkIf (pkgs.stdenv.isLinux) {
|
||||
flash = (import ../lib/test-base.nix) {
|
||||
name = "flash";
|
||||
@ -41,7 +41,8 @@
|
||||
};
|
||||
testScript = ''
|
||||
start_all()
|
||||
machine.succeed("clan --flake ${../..} flash --debug --yes --disk main /dev/vdb test_install_machine")
|
||||
|
||||
machine.succeed("clan flash --debug --flake ${../..} --yes --disk main /dev/vdb test_install_machine")
|
||||
'';
|
||||
} { inherit pkgs self; };
|
||||
};
|
||||
|
@ -7,6 +7,8 @@
|
||||
#!${pkgs.bash}/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
unset CLAN_DIR
|
||||
|
||||
export PATH="${
|
||||
lib.makeBinPath [
|
||||
pkgs.gitMinimal
|
||||
|
@ -2,8 +2,8 @@
|
||||
{
|
||||
clan.machines.test_install_machine = {
|
||||
clan.networking.targetHost = "test_install_machine";
|
||||
fileSystems."/".device = lib.mkDefault "/dev/null";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/null";
|
||||
fileSystems."/".device = lib.mkDefault "/dev/vdb";
|
||||
boot.loader.grub.device = lib.mkDefault "/dev/vdb";
|
||||
|
||||
imports = [ self.nixosModules.test_install_machine ];
|
||||
};
|
||||
@ -12,11 +12,11 @@
|
||||
{ lib, modulesPath, ... }:
|
||||
{
|
||||
imports = [
|
||||
self.clanModules.diskLayouts
|
||||
self.clanModules.disk-layouts
|
||||
(modulesPath + "/testing/test-instrumentation.nix") # we need these 2 modules always to be able to run the tests
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
clan.diskLayouts.singleDiskExt4.device = "/dev/vdb";
|
||||
clan.disk-layouts.singleDiskExt4.device = "/dev/vdb";
|
||||
|
||||
environment.etc."install-successful".text = "ok";
|
||||
|
||||
@ -63,7 +63,9 @@
|
||||
};
|
||||
};
|
||||
nodes.client = {
|
||||
environment.systemPackages = [ self.packages.${pkgs.system}.clan-cli ];
|
||||
environment.systemPackages = [
|
||||
self.packages.${pkgs.system}.clan-cli
|
||||
] ++ self.packages.${pkgs.system}.clan-cli.runtimeDependencies;
|
||||
environment.etc."install-closure".source = "${closureInfo}/store-paths";
|
||||
virtualisation.memorySize = 2048;
|
||||
nix.settings = {
|
||||
@ -96,7 +98,7 @@
|
||||
client.succeed("${pkgs.coreutils}/bin/install -Dm 600 ${../lib/ssh/privkey} /root/.ssh/id_ed25519")
|
||||
client.wait_until_succeeds("ssh -o StrictHostKeyChecking=accept-new -v root@target hostname")
|
||||
|
||||
client.succeed("clan --debug --flake ${../..} machines install --yes test_install_machine root@target >&2")
|
||||
client.succeed("clan machines install --debug --flake ${../..} --yes test_install_machine root@target >&2")
|
||||
try:
|
||||
target.shutdown()
|
||||
except BrokenPipeError:
|
||||
|
@ -10,6 +10,7 @@ in
|
||||
hostPkgs = pkgs;
|
||||
# speed-up evaluation
|
||||
defaults = {
|
||||
nix.package = pkgs.nixVersions.latest;
|
||||
documentation.enable = lib.mkDefault false;
|
||||
boot.isContainer = true;
|
||||
|
||||
|
@ -10,6 +10,7 @@ in
|
||||
defaults = {
|
||||
documentation.enable = lib.mkDefault false;
|
||||
nix.settings.min-free = 0;
|
||||
nix.package = pkgs.nixVersions.latest;
|
||||
};
|
||||
|
||||
# to accept external dependencies such as disko
|
||||
|
@ -1,48 +0,0 @@
|
||||
{
|
||||
self,
|
||||
runCommand,
|
||||
check-jsonschema,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clanModules.clanCore = self.nixosModules.clanCore;
|
||||
|
||||
baseModule = {
|
||||
imports = (import (pkgs.path + "/nixos/modules/module-list.nix")) ++ [
|
||||
{
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
clanCore.clanName = "dummy";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
optionsFromModule =
|
||||
module:
|
||||
let
|
||||
evaled = lib.evalModules {
|
||||
modules = [
|
||||
module
|
||||
baseModule
|
||||
];
|
||||
};
|
||||
in
|
||||
evaled.options.clan;
|
||||
|
||||
clanModuleSchemas = lib.mapAttrs (
|
||||
_: module: self.lib.jsonschema.parseOptions (optionsFromModule module)
|
||||
) clanModules;
|
||||
|
||||
mkTest =
|
||||
name: schema:
|
||||
runCommand "schema-${name}" { } ''
|
||||
${check-jsonschema}/bin/check-jsonschema \
|
||||
--check-metaschema ${builtins.toFile "schema-${name}" (builtins.toJSON schema)}
|
||||
touch $out
|
||||
'';
|
||||
in
|
||||
lib.mapAttrs' (name: schema: {
|
||||
name = "schema-${name}";
|
||||
value = mkTest name schema;
|
||||
}) clanModuleSchemas
|
@ -4,10 +4,11 @@
|
||||
nodes.machine =
|
||||
{ self, config, ... }:
|
||||
{
|
||||
environment.etc."privkey.age".source = ./key.age;
|
||||
imports = [ (self.nixosModules.clanCore) ];
|
||||
environment.etc."secret".source = config.sops.secrets.secret.path;
|
||||
environment.etc."group-secret".source = config.sops.secrets.group-secret.path;
|
||||
sops.age.keyFile = ./key.age;
|
||||
sops.age.keyFile = "/etc/privkey.age";
|
||||
|
||||
clanCore.clanDir = "${./.}";
|
||||
clanCore.machineName = "machine";
|
||||
|
2
clanModules/borgbackup/README.md
Normal file
2
clanModules/borgbackup/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Efficient, deduplicating backup program with optional compression and secure encryption.
|
||||
---
|
16
clanModules/deltachat/README.md
Normal file
16
clanModules/deltachat/README.md
Normal file
@ -0,0 +1,16 @@
|
||||
Email-based instant messaging for Desktop.
|
||||
---
|
||||
|
||||
!!! warning "Under construction"
|
||||
|
||||
!!! info
|
||||
This module will automatically configure an email server on the machine for handling the e-mail messaging seamlessly.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] **Email-based**: Uses any email account as its backend.
|
||||
- [x] **End-to-End Encryption**: Supports Autocrypt to automatically encrypt messages.
|
||||
- [x] **No Phone Number Required**: Uses your email address instead of a phone number.
|
||||
- [x] **Cross-Platform**: Available on desktop and mobile platforms.
|
||||
- [x] **Automatic Server Setup**: Includes your own DeltaChat server for enhanced control and privacy.
|
||||
- [ ] **Bake a cake**: This module cannot cake a bake.
|
2
clanModules/disk-layouts/README.md
Normal file
2
clanModules/disk-layouts/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Automatically format a disk drive on clan installation
|
||||
---
|
@ -1,6 +1,6 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
options.clan.diskLayouts.singleDiskExt4 = {
|
||||
options.clan.disk-layouts.singleDiskExt4 = {
|
||||
device = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "/dev/disk/by-id/ata-Samsung_SSD_850_EVO_250GB_S21PNXAGB12345";
|
||||
@ -13,13 +13,14 @@
|
||||
disk = {
|
||||
main = {
|
||||
type = "disk";
|
||||
device = config.clan.diskLayouts.singleDiskExt4.device;
|
||||
device = config.clan.disk-layouts.singleDiskExt4.device;
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
boot = {
|
||||
size = "1M";
|
||||
type = "EF02"; # for grub MBR
|
||||
priority = 1;
|
||||
};
|
||||
ESP = {
|
||||
size = "512M";
|
2
clanModules/ergochat/README.md
Normal file
2
clanModules/ergochat/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
A modern IRC server
|
||||
---
|
@ -1,29 +1,26 @@
|
||||
{ inputs, ... }:
|
||||
{ ... }:
|
||||
{
|
||||
flake.clanModules = {
|
||||
diskLayouts = {
|
||||
imports = [
|
||||
./diskLayouts.nix
|
||||
inputs.disko.nixosModules.default
|
||||
];
|
||||
disk-layouts = {
|
||||
imports = [ ./disk-layouts ];
|
||||
};
|
||||
borgbackup = ./borgbackup.nix;
|
||||
ergochat = ./ergochat.nix;
|
||||
deltachat = ./deltachat.nix;
|
||||
graphical = ./graphical.nix;
|
||||
localbackup = ./localbackup.nix;
|
||||
localsend = ./localsend.nix;
|
||||
matrix-synapse = ./matrix-synapse.nix;
|
||||
moonlight = ./moonlight.nix;
|
||||
sshd = ./sshd.nix;
|
||||
sunshine = ./sunshine.nix;
|
||||
syncthing = ./syncthing.nix;
|
||||
root-password = ./root-password.nix;
|
||||
thelounge = ./thelounge.nix;
|
||||
vm-user = ./vm-user.nix;
|
||||
waypipe = ./waypipe.nix;
|
||||
xfce = ./xfce.nix;
|
||||
xfce-vm = ./xfce-vm.nix;
|
||||
zt-tcp-relay = ./zt-tcp-relay.nix;
|
||||
borgbackup = ./borgbackup;
|
||||
deltachat = ./deltachat;
|
||||
ergochat = ./ergochat;
|
||||
localbackup = ./localbackup;
|
||||
localsend = ./localsend;
|
||||
matrix-synapse = ./matrix-synapse;
|
||||
moonlight = ./moonlight;
|
||||
root-password = ./root-password;
|
||||
sshd = ./sshd;
|
||||
sunshine = ./sunshine;
|
||||
static-hosts = ./static-hosts;
|
||||
syncthing = ./syncthing;
|
||||
thelounge = ./thelounge;
|
||||
trusted-nix-caches = ./trusted-nix-caches;
|
||||
user-password = ./user-password;
|
||||
xfce = ./xfce;
|
||||
zerotier-static-peers = ./zerotier-static-peers;
|
||||
zt-tcp-relay = ./zt-tcp-relay;
|
||||
};
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
_: { fonts.enableDefaultPackages = true; }
|
2
clanModules/localbackup/README.md
Normal file
2
clanModules/localbackup/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Automatically backups current machine to local directory.
|
||||
---
|
2
clanModules/localsend/README.md
Normal file
2
clanModules/localsend/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Securely sharing files and messages over a local network without internet connectivity.
|
||||
---
|
@ -9,7 +9,7 @@
|
||||
# - cli frontend: https://github.com/localsend/localsend/issues/11
|
||||
# - ipv6 support: https://github.com/localsend/localsend/issues/549
|
||||
options.clan.localsend = {
|
||||
enable = lib.mkEnableOption (lib.mdDoc "enable the localsend module");
|
||||
enable = lib.mkEnableOption "enable the localsend module";
|
||||
defaultLocation = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The default download location";
|
2
clanModules/matrix-synapse/README.md
Normal file
2
clanModules/matrix-synapse/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
A federated messaging server with end-to-end encryption.
|
||||
---
|
2
clanModules/moonlight/README.md
Normal file
2
clanModules/moonlight/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
A desktop streaming client optimized for remote gaming and synchronized movie viewing.
|
||||
---
|
11
clanModules/root-password/README.md
Normal file
11
clanModules/root-password/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
Automatically generates and configures a password for the root user.
|
||||
---
|
||||
|
||||
After the system was installed/deployed the following command can be used to display the root-password:
|
||||
|
||||
```bash
|
||||
clan secrets get {machine_name}-password
|
||||
```
|
||||
|
||||
|
||||
See also: [Facts / Secrets](../../getting-started/secrets.md)
|
2
clanModules/sshd/README.md
Normal file
2
clanModules/sshd/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Enables secure remote access to the machine over ssh
|
||||
---
|
@ -1,6 +1,7 @@
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
services.openssh.enable = true;
|
||||
services.openssh.settings.PasswordAuthentication = false;
|
||||
|
||||
services.openssh.hostKeys = [
|
||||
{
|
2
clanModules/static-hosts/README.md
Normal file
2
clanModules/static-hosts/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Statically configure the host names of machines based on their respective zerotier-ip.
|
||||
---
|
44
clanModules/static-hosts/default.nix
Normal file
44
clanModules/static-hosts/default.nix
Normal file
@ -0,0 +1,44 @@
|
||||
{ lib, config, ... }:
|
||||
{
|
||||
options.clan.static-hosts = {
|
||||
excludeHosts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default =
|
||||
if config.clan.static-hosts.topLevelDomain != "" then [ ] else [ config.clanCore.machineName ];
|
||||
description = "Hosts that should be excluded";
|
||||
};
|
||||
topLevelDomain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Top level domain to reach hosts";
|
||||
};
|
||||
};
|
||||
|
||||
config.networking.hosts =
|
||||
let
|
||||
clanDir = config.clanCore.clanDir;
|
||||
machineDir = clanDir + "/machines/";
|
||||
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
|
||||
machines = builtins.readDir machineDir;
|
||||
filteredMachines = lib.filterAttrs (
|
||||
name: _: !(lib.elem name config.clan.static-hosts.excludeHosts)
|
||||
) machines;
|
||||
in
|
||||
lib.filterAttrs (_: value: value != null) (
|
||||
lib.mapAttrs' (
|
||||
machine: _:
|
||||
let
|
||||
path = zerotierIpMachinePath machine;
|
||||
in
|
||||
if builtins.pathExists path then
|
||||
lib.nameValuePair (builtins.readFile path) (
|
||||
if (config.clan.static-hosts.topLevelDomain == "") then
|
||||
[ machine ]
|
||||
else
|
||||
[ "${machine}.${config.clan.static-hosts.topLevelDomain}" ]
|
||||
)
|
||||
else
|
||||
null
|
||||
) filteredMachines
|
||||
);
|
||||
}
|
2
clanModules/sunshine/README.md
Normal file
2
clanModules/sunshine/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
A desktop streaming server optimized for remote gaming and synchronized movie viewing.
|
||||
---
|
32
clanModules/syncthing/README.md
Normal file
32
clanModules/syncthing/README.md
Normal file
@ -0,0 +1,32 @@
|
||||
A secure, file synchronization app for devices over networks, offering a private alternative to cloud services.
|
||||
---
|
||||
## Usage
|
||||
|
||||
We recommend configuring this module as an sync-service through the provided options. Although it provides a Web GUI through which more usage scenarios are supported.
|
||||
|
||||
## Features
|
||||
|
||||
- **Private and Secure**: Syncthing uses TLS encryption to secure data transfer between devices, ensuring that only the intended devices can read your data.
|
||||
- **Decentralized**: No central server is involved in the data transfer. Each device communicates directly with others.
|
||||
- **Open Source**: The source code is openly available for audit and contribution, fostering trust and continuous improvement.
|
||||
- **Cross-Platform**: Syncthing supports multiple platforms including Windows, macOS, Linux, BSD, and Android.
|
||||
- **Real-time Synchronization**: Changes made to files are synchronized in real-time across all connected devices.
|
||||
- **Web GUI**: It includes a user-friendly web interface for managing devices and configurations. (`127.0.0.1:8384`)
|
||||
|
||||
## Configuration
|
||||
|
||||
- **Share Folders**: Select folders to share with connected devices and configure permissions and synchronization parameters.
|
||||
|
||||
!!! info
|
||||
Clan automatically discovers other devices. Automatic discovery requires one machine to be an [introducer](#clan.syncthing.introducer)
|
||||
|
||||
If that is not the case you can add the other device by its Device ID manually.
|
||||
You can find and share Device IDs under the "Add Device" button in the Web GUI. (`127.0.0.1:8384`)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Sync Conflicts**: Resolve synchronization conflicts manually by reviewing file versions and modification times in the Web GUI (`127.0.0.1:8384`).
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation**: Extensive documentation is available on the [Syncthing website](https://docs.syncthing.net/).
|
@ -34,6 +34,10 @@
|
||||
'';
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
example = [
|
||||
"folder1"
|
||||
"folder2"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
2
clanModules/thelounge/README.md
Normal file
2
clanModules/thelounge/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Modern web IRC client
|
||||
---
|
2
clanModules/trusted-nix-caches/README.md
Normal file
2
clanModules/trusted-nix-caches/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
This module sets the `clan.lol` and `nix-community` cache up as a trusted cache.
|
||||
----
|
10
clanModules/trusted-nix-caches/default.nix
Normal file
10
clanModules/trusted-nix-caches/default.nix
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
nix.settings.trusted-substituters = [
|
||||
"https://cache.clan.lol"
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
nix.settings.trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
"cache.clan.lol-1:3KztgSAB5R1M+Dz7vzkBGzXdodizbgLXGXKXlcQLA28="
|
||||
];
|
||||
}
|
18
clanModules/user-password/README.md
Normal file
18
clanModules/user-password/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
Automatically generates and configures a password for the specified user account.
|
||||
---
|
||||
|
||||
If setting the option prompt to true, the user will be prompted to type in their desired password.
|
||||
|
||||
!!! Note
|
||||
This module will set `mutableUsers` to `false`, meaning you can not manage user passwords through `passwd` anymore.
|
||||
|
||||
|
||||
After the system was installed/deployed the following command can be used to display the user-password:
|
||||
|
||||
```bash
|
||||
clan secrets get {machine_name}-user-password
|
||||
```
|
||||
|
||||
See also: [Facts / Secrets](../../getting-started/secrets.md)
|
||||
|
||||
To regenerate the password, delete the password files in the clan directory and redeploy the machine.
|
49
clanModules/user-password/default.nix
Normal file
49
clanModules/user-password/default.nix
Normal file
@ -0,0 +1,49 @@
|
||||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
options.clan.user-password = {
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
example = "alice";
|
||||
description = "The user the password should be generated for.";
|
||||
};
|
||||
prompt = lib.mkOption {
|
||||
type = lib.types.bool;
|
||||
default = true;
|
||||
example = false;
|
||||
description = "Whether the user should be prompted.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
users.mutableUsers = false;
|
||||
users.users.${config.clan.user-password.user}.hashedPasswordFile =
|
||||
config.clanCore.facts.services.user-password.secret.user-password-hash.path;
|
||||
sops.secrets."${config.clanCore.machineName}-user-password-hash".neededForUsers = true;
|
||||
clanCore.facts.services.user-password = {
|
||||
secret.user-password = { };
|
||||
secret.user-password-hash = { };
|
||||
generator.prompt = (
|
||||
lib.mkIf config.clan.user-password.prompt "Set the password for your $user: ${config.clan.user-password.user}.
|
||||
You can autogenerate a password, if you leave this prompt blank."
|
||||
);
|
||||
generator.path = with pkgs; [
|
||||
coreutils
|
||||
xkcdpass
|
||||
mkpasswd
|
||||
];
|
||||
generator.script = ''
|
||||
if [[ -n $prompt_value ]]; then
|
||||
echo $prompt_value > $secrets/user-password
|
||||
else
|
||||
xkcdpass --numwords 3 --delimiter - --count 1 > $secrets/user-password
|
||||
fi
|
||||
cat $secrets/user-password | mkpasswd -s -m sha-512 > $secrets/user-password-hash
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
{
|
||||
security = {
|
||||
sudo.wheelNeedsPassword = false;
|
||||
polkit.enable = true;
|
||||
rtkit.enable = true;
|
||||
};
|
||||
|
||||
users.users.user = {
|
||||
isNormalUser = true;
|
||||
createHome = true;
|
||||
uid = 1000;
|
||||
initialHashedPassword = "";
|
||||
extraGroups = [
|
||||
"wheel"
|
||||
"video"
|
||||
"render"
|
||||
];
|
||||
shell = "/run/current-system/sw/bin/bash";
|
||||
};
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./vm-user.nix
|
||||
./graphical.nix
|
||||
];
|
||||
|
||||
services.xserver = {
|
||||
enable = true;
|
||||
displayManager.autoLogin.enable = true;
|
||||
displayManager.autoLogin.user = "user";
|
||||
desktopManager.xfce.enable = true;
|
||||
desktopManager.xfce.enableScreensaver = false;
|
||||
xkb.layout = "us";
|
||||
};
|
||||
}
|
2
clanModules/xfce/README.md
Normal file
2
clanModules/xfce/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
A lightweight desktop manager
|
||||
---
|
5
clanModules/zerotier-static-peers/README.md
Normal file
5
clanModules/zerotier-static-peers/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
Statically configure the `zerotier` peers of a clan network.
|
||||
---
|
||||
Statically configure the `zerotier` peers of a clan network.
|
||||
|
||||
Requires a machine, that is the zerotier controller configured in the network.
|
71
clanModules/zerotier-static-peers/default.nix
Normal file
71
clanModules/zerotier-static-peers/default.nix
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
lib,
|
||||
config,
|
||||
pkgs,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
clanDir = config.clanCore.clanDir;
|
||||
machineDir = clanDir + "/machines/";
|
||||
machinesFileSet = builtins.readDir machineDir;
|
||||
machines = lib.mapAttrsToList (name: _: name) machinesFileSet;
|
||||
|
||||
zerotierNetworkIdPath = machines: machineDir + machines + "/facts/zerotier-network-id";
|
||||
networkIdsUnchecked = builtins.map (
|
||||
machine:
|
||||
let
|
||||
fullPath = zerotierNetworkIdPath machine;
|
||||
in
|
||||
if builtins.pathExists fullPath then builtins.readFile fullPath else null
|
||||
) machines;
|
||||
networkIds = lib.filter (machine: machine != null) networkIdsUnchecked;
|
||||
networkId = if builtins.length networkIds == 0 then null else builtins.elemAt networkIds 0;
|
||||
in
|
||||
#TODO:trace on multiple found network-ids
|
||||
#TODO:trace on no single found networkId
|
||||
{
|
||||
options.clan.zerotier-static-peers = {
|
||||
excludeHosts = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ config.clanCore.machineName ];
|
||||
description = "Hosts that should be excluded";
|
||||
};
|
||||
};
|
||||
|
||||
config.systemd.services.zerotier-static-peers-autoaccept =
|
||||
let
|
||||
machines = builtins.readDir machineDir;
|
||||
zerotierIpMachinePath = machines: machineDir + machines + "/facts/zerotier-ip";
|
||||
filteredMachines = lib.filterAttrs (
|
||||
name: _: !(lib.elem name config.clan.zerotier-static-peers.excludeHosts)
|
||||
) machines;
|
||||
hosts = lib.mapAttrsToList (host: _: host) (
|
||||
lib.mapAttrs' (
|
||||
machine: _:
|
||||
let
|
||||
fullPath = zerotierIpMachinePath machine;
|
||||
in
|
||||
if builtins.pathExists fullPath then
|
||||
lib.nameValuePair (builtins.readFile fullPath) [ machine ]
|
||||
else
|
||||
null
|
||||
) filteredMachines
|
||||
);
|
||||
in
|
||||
lib.mkIf (config.clan.networking.zerotier.controller.enable) {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "zerotierone.service" ];
|
||||
path = [ pkgs.zerotierone ];
|
||||
serviceConfig.ExecStart = pkgs.writeScript "static-zerotier-peers-autoaccept" ''
|
||||
#!/bin/sh
|
||||
${lib.concatMapStringsSep "\n" (host: ''
|
||||
${
|
||||
inputs.clan-core.packages.${pkgs.system}.zerotier-members
|
||||
}/bin/zerotier-members allow --member-ip ${host}
|
||||
'') hosts}
|
||||
'';
|
||||
};
|
||||
|
||||
config.clan.networking.zerotier.networkId = lib.mkDefault networkId;
|
||||
}
|
2
clanModules/zt-tcp-relay/README.md
Normal file
2
clanModules/zt-tcp-relay/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Enable ZeroTier VPN over TCP for networks where UDP is blocked.
|
||||
---
|
@ -20,7 +20,7 @@
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
ExecStart = "${
|
||||
pkgs.callPackage ../pkgs/zt-tcp-relay { }
|
||||
pkgs.callPackage ../../pkgs/zt-tcp-relay { }
|
||||
}/bin/zt-tcp-relay --listen [::]:${builtins.toString config.clan.zt-tcp-relay.port}";
|
||||
Restart = "always";
|
||||
RestartSec = "5";
|
@ -1,3 +1,4 @@
|
||||
{ ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
@ -26,7 +27,8 @@
|
||||
packages = [
|
||||
select-shell
|
||||
pkgs.tea
|
||||
pkgs.nix
|
||||
# Better error messages than nix 2.18
|
||||
pkgs.nixVersions.latest
|
||||
self'.packages.tea-create-pr
|
||||
self'.packages.merge-after-ci
|
||||
self'.packages.pending-reviews
|
||||
@ -34,9 +36,6 @@
|
||||
config.treefmt.build.wrapper
|
||||
];
|
||||
shellHook = ''
|
||||
# no longer used
|
||||
rm -f "$(git rev-parse --show-toplevel)/.git/hooks/pre-commit"
|
||||
|
||||
echo -e "${ansiEscapes.green}switch to another dev-shell using: select-shell${ansiEscapes.reset}"
|
||||
'';
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
source_up
|
||||
|
||||
watch_file nix/flake-module.nix nix/shell.nix nix/default.nix
|
||||
watch_file $(find ./nix -name "*.nix" -printf '%p ')
|
||||
|
||||
# Because we depend on nixpkgs sources, uploading to builders takes a long time
|
||||
use flake .#docs --builders ''
|
||||
|
3
docs/.gitignore
vendored
Normal file
3
docs/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/site/reference
|
||||
/site/static/Roboto-Regular.ttf
|
||||
/site/static/FiraCode-VF.ttf
|
@ -15,92 +15,124 @@ Let's get your development environment up and running:
|
||||
|
||||
1. **Install Nix Package Manager**:
|
||||
|
||||
- You can install the Nix package manager by either [downloading the Nix installer](https://github.com/DeterminateSystems/nix-installer/releases) or running this command:
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
- You can install the Nix package manager by either [downloading the Nix installer](https://github.com/DeterminateSystems/nix-installer/releases) or running this command:
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
|
||||
2. **Install direnv**:
|
||||
|
||||
- Download the direnv package from [here](https://direnv.net/docs/installation.html) or run the following command:
|
||||
```bash
|
||||
curl -sfL https://direnv.net/install.sh | bash
|
||||
```
|
||||
- To automatically setup a devshell on entering the directory
|
||||
```bash
|
||||
nix profile install nixpkgs#nix-direnv-flakes
|
||||
```
|
||||
|
||||
3. **Add direnv to your shell**:
|
||||
|
||||
- Direnv needs to [hook into your shell](https://direnv.net/docs/hook.html) to work.
|
||||
You can do this by executing following command. The example below will setup direnv for `zsh` and `bash`
|
||||
- Direnv needs to [hook into your shell](https://direnv.net/docs/hook.html) to work.
|
||||
You can do this by executing following command. The example below will setup direnv for `zsh` and `bash`
|
||||
|
||||
```bash
|
||||
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && eval "$SHELL"
|
||||
```
|
||||
|
||||
4. **Clone the Repository and Navigate**:
|
||||
|
||||
- Clone this repository and navigate to it.
|
||||
|
||||
5. **Allow .envrc**:
|
||||
|
||||
- When you enter the directory, you'll receive an error message like this:
|
||||
```bash
|
||||
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
|
||||
```
|
||||
- Execute `direnv allow` to automatically execute the shell script `.envrc` when entering the directory.
|
||||
|
||||
# Setting Up Your Git Workflow
|
||||
|
||||
Let's set up your Git workflow to collaborate effectively:
|
||||
|
||||
1. **Register Your Gitea Account Locally**:
|
||||
|
||||
- Execute the following command to add your Gitea account locally:
|
||||
```bash
|
||||
tea login add
|
||||
```
|
||||
- Fill out the prompt as follows:
|
||||
- URL of Gitea instance: `https://git.clan.lol`
|
||||
- Name of new Login [gitea.gchq.icu]: `gitea.gchq.icu:7171`
|
||||
- Do you have an access token? No
|
||||
- Username: YourUsername
|
||||
- Password: YourPassword
|
||||
- Set Optional settings: No
|
||||
|
||||
2. **Git Workflow**:
|
||||
|
||||
1. Add your changes to Git using `git add <file1> <file2>`.
|
||||
2. Run `nix fmt` to lint your files.
|
||||
3. Commit your changes with a descriptive message: `git commit -a -m "My descriptive commit message"`.
|
||||
4. Make sure your branch has the latest changes from upstream by executing:
|
||||
```bash
|
||||
git fetch && git rebase origin/main --autostash
|
||||
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc && echo 'eval "$(direnv hook bash)"' >> ~/.bashrc && eval "$SHELL"
|
||||
```
|
||||
5. Use `git status` to check for merge conflicts.
|
||||
6. If conflicts exist, resolve them. Here's a tutorial for resolving conflicts in [VSCode](https://code.visualstudio.com/docs/sourcecontrol/overview#_merge-conflicts).
|
||||
7. After resolving conflicts, execute `git merge --continue` and repeat step 5 until there are no conflicts.
|
||||
|
||||
3. **Create a Pull Request**:
|
||||
4. **Create a Gitea Account**:
|
||||
- Register an account on https://git.clan.lol
|
||||
- Fork the [clan-core](https://git.clan.lol/clan/clan-core) repository
|
||||
- Clone the repository and navigate to it
|
||||
- Add a new remote called upstream:
|
||||
```bash
|
||||
git remote add upstream gitea@git.clan.lol:clan/clan-core.git
|
||||
```
|
||||
|
||||
- To automatically open a pull request that gets merged if all tests pass, execute:
|
||||
```bash
|
||||
merge-after-ci
|
||||
```
|
||||
5. **Register Your Gitea Account Locally**:
|
||||
|
||||
4. **Review Your Pull Request**:
|
||||
- Execute the following command to add your Gitea account locally:
|
||||
```bash
|
||||
tea login add
|
||||
```
|
||||
- Fill out the prompt as follows:
|
||||
- URL of Gitea instance: `https://git.clan.lol`
|
||||
- Name of new Login [git.clan.lol]:
|
||||
- Do you have an access token? No
|
||||
- Username: YourUsername
|
||||
- Password: YourPassword
|
||||
- Set Optional settings: No
|
||||
|
||||
- Visit https://git.clan.lol and go to the project page. Check under "Pull Requests" for any issues with your pull request.
|
||||
|
||||
5. **Push Your Changes**:
|
||||
- If there are issues, fix them and redo step 2. Afterward, execute:
|
||||
```bash
|
||||
git push origin HEAD:YourUsername-main
|
||||
```
|
||||
- This will directly push to your open pull request.
|
||||
6. **Allow .envrc**:
|
||||
|
||||
- When you enter the directory, you'll receive an error message like this:
|
||||
```bash
|
||||
direnv: error .envrc is blocked. Run `direnv allow` to approve its content
|
||||
```
|
||||
- Execute `direnv allow` to automatically execute the shell script `.envrc` when entering the directory.
|
||||
|
||||
7. **(Optional) Install Git Hooks**:
|
||||
- To syntax check your code you can run:
|
||||
```bash
|
||||
nix fmt
|
||||
```
|
||||
- To make this automatic install the git hooks
|
||||
```bash
|
||||
./scripts/pre-commit
|
||||
```
|
||||
|
||||
8. **Open a Pull Request**:
|
||||
- To automatically open up a pull request you can use our tool called:
|
||||
```
|
||||
merge-after-ci --reviewers Mic92 Lassulus Qubasa
|
||||
```
|
||||
|
||||
# Debugging
|
||||
|
||||
Here are some methods for debugging and testing the clan-cli:
|
||||
|
||||
## See all possible packages and tests
|
||||
|
||||
To quickly show all possible packages and tests execute:
|
||||
|
||||
```bash
|
||||
nix flake show --system no-eval
|
||||
```
|
||||
|
||||
Under `checks` you will find all tests that are executed in our CI. Under `packages` you find all our projects.
|
||||
|
||||
```
|
||||
git+file:///home/lhebendanz/Projects/clan-core
|
||||
├───apps
|
||||
│ └───x86_64-linux
|
||||
│ ├───install-vm: app
|
||||
│ └───install-vm-nogui: app
|
||||
├───checks
|
||||
│ └───x86_64-linux
|
||||
│ ├───borgbackup omitted (use '--all-systems' to show)
|
||||
│ ├───check-for-breakpoints omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-age omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-bash omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-e2fsprogs omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-fakeroot omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-git omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-nix omitted (use '--all-systems' to show)
|
||||
│ ├───clan-dep-openssh omitted (use '--all-systems' to show)
|
||||
│ ├───"clan-dep-python3.11-mypy" omitted (use '--all-systems' to show)
|
||||
├───packages
|
||||
│ └───x86_64-linux
|
||||
│ ├───clan-cli omitted (use '--all-systems' to show)
|
||||
│ ├───clan-cli-docs omitted (use '--all-systems' to show)
|
||||
│ ├───clan-ts-api omitted (use '--all-systems' to show)
|
||||
│ ├───clan-vm-manager omitted (use '--all-systems' to show)
|
||||
│ ├───default omitted (use '--all-systems' to show)
|
||||
│ ├───deploy-docs omitted (use '--all-systems' to show)
|
||||
│ ├───docs omitted (use '--all-systems' to show)
|
||||
│ ├───editor omitted (use '--all-systems' to show)
|
||||
└───templates
|
||||
├───default: template: Initialize a new clan flake
|
||||
└───new-clan: template: Initialize a new clan flake
|
||||
```
|
||||
|
||||
You can execute every test separately by following the tree path `nix build .#checks.x86_64-linux.clan-pytest` for example.
|
||||
|
||||
## Test Locally in Devshell with Breakpoints
|
||||
|
||||
To test the cli locally in a development environment and set breakpoints for debugging, follow these steps:
|
||||
@ -150,12 +182,14 @@ If you need to inspect the Nix sandbox while running tests, follow these steps:
|
||||
2. Use `cntr` and `psgrep` to attach to the Nix sandbox. This allows you to interactively debug your code while it's paused. For example:
|
||||
|
||||
```bash
|
||||
cntr exec -w your_sandbox_name
|
||||
psgrep -a -x your_python_process_name
|
||||
cntr attach <container id, container name or process id>
|
||||
```
|
||||
|
||||
Or you can also use the [nix breakpoint hook](https://nixos.org/manual/nixpkgs/stable/#breakpointhook)
|
||||
|
||||
|
||||
# Standards
|
||||
|
||||
Every new module name should be in kebab-case.
|
||||
Every fact definition, where possible should be in kebab-case.
|
||||
- Every new module name should be in kebab-case.
|
||||
- Every fact definition, where possible should be in kebab-case.
|
||||
|
@ -20,11 +20,11 @@ There are several reasons for choosing to self-host. These can include:
|
||||
|
||||
Alice wants to self-host a mumble server for her family.
|
||||
|
||||
- She visits to the cLAN website, and follows the instructions on how to install cLAN-OS on her server.
|
||||
- Alice logs into a terminal on her server via SSH (alternatively uses cLAN GUI app)
|
||||
- Using the cLAN CLI or GUI tool, alice creates a new private network for her family (VPN)
|
||||
- Alice now browses a list of curated cLAN modules and finds a module for mumble.
|
||||
- She adds this module to her network using the cLAN tool.
|
||||
- She visits to the Clan website, and follows the instructions on how to install Clan-OS on her server.
|
||||
- Alice logs into a terminal on her server via SSH (alternatively uses Clan GUI app)
|
||||
- Using the Clan CLI or GUI tool, alice creates a new private network for her family (VPN)
|
||||
- Alice now browses a list of curated Clan modules and finds a module for mumble.
|
||||
- She adds this module to her network using the Clan tool.
|
||||
- After that, she uses the clan tool to invite her family members to her network
|
||||
- Other family members join the private network via the invitation.
|
||||
- By accepting the invitation, other members automatically install all required software to interact with the network on their machine.
|
||||
@ -33,7 +33,7 @@ Alice wants to self-host a mumble server for her family.
|
||||
|
||||
Alice wants to add a photos app to her private network
|
||||
|
||||
- She uses the clan CLI or GUI tool to manage her existing private cLAN family network
|
||||
- She uses the clan CLI or GUI tool to manage her existing private Clan family network
|
||||
- She discovers a module for photoprism, and adds it to her server using the tool
|
||||
- Other members who are already part of her network, will receive a notification that an update is required to their environment
|
||||
- After accepting, all new software and services to interact with the new photoprism service will be installed automatically.
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Joining a cLAN network
|
||||
# Joining a Clan network
|
||||
|
||||
## General Description
|
||||
|
||||
@ -8,13 +8,13 @@ Joining a self-hosted infrastructure involves connecting to a network, server, o
|
||||
|
||||
### Story 1: Joining a private network
|
||||
|
||||
Alice' son Bob has never heard of cLAN, but receives an invitation URL from Alice who already set up private cLAN network for her family.
|
||||
Alice' son Bob has never heard of Clan, but receives an invitation URL from Alice who already set up private Clan network for her family.
|
||||
|
||||
Bob opens the invitation link and lands on the cLAN website. He quickly learns about what cLAN is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
|
||||
Bob opens the invitation link and lands on the Clan website. He quickly learns about what Clan is and can see that the invitation is for a private network of his family that hosts a number of services, like a private voice chat and a photo sharing platform.
|
||||
|
||||
Bob decides to join the network and follows the instructions to install the cLAN tool on his computer.
|
||||
Bob decides to join the network and follows the instructions to install the Clan tool on his computer.
|
||||
|
||||
Feeding the invitation link to the cLAN tool, bob registers his machine with the network.
|
||||
Feeding the invitation link to the Clan tool, bob registers his machine with the network.
|
||||
|
||||
All programs required to interact with the network will be installed and configured automatically and securely.
|
||||
|
||||
@ -22,7 +22,7 @@ Optionally, bob can customize the configuration of these programs through a simp
|
||||
|
||||
### Story 2: Receiving breaking changes
|
||||
|
||||
The cLAN family network which Bob is part of received an update.
|
||||
The Clan family network which Bob is part of received an update.
|
||||
|
||||
The existing photo sharing service has been removed and replaced with another alternative service. The new photo sharing service requires a different client app to view and upload photos.
|
||||
|
||||
@ -30,7 +30,7 @@ Bob accepts the update. Now his environment will be updated. The old client soft
|
||||
|
||||
Because Bob has customized the previous photo viewing app, he is notified that this customization is no longer valid, as the software has been removed (deprecation message).l
|
||||
|
||||
Optionally, Bob can now customize the new photo viewing software through his cLAN configuration app or via a config file.
|
||||
Optionally, Bob can now customize the new photo viewing software through his Clan configuration app or via a config file.
|
||||
|
||||
## Challenges
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
# cLAN module maintaining
|
||||
# Clan module maintaining
|
||||
|
||||
## General Description
|
||||
|
||||
cLAN modules are pieces of software that can be used by admins to build a private or public infrastructure.
|
||||
Clan modules are pieces of software that can be used by admins to build a private or public infrastructure.
|
||||
|
||||
cLAN modules should have the following properties:
|
||||
Clan modules should have the following properties:
|
||||
|
||||
1. Documented: It should be clear what the module does and how to use it.
|
||||
1. Self contained: A module should be usable as is. If it requires any other software or settings, those should be delivered with the module itself.
|
||||
|
41
docs/main.py
Normal file
41
docs/main.py
Normal file
@ -0,0 +1,41 @@
|
||||
from typing import Any
|
||||
|
||||
|
||||
def define_env(env: Any) -> None:
|
||||
static_dir = "/static/"
|
||||
video_dir = "https://clan.lol/" + "videos/"
|
||||
asciinema_dir = static_dir + "asciinema-player/"
|
||||
|
||||
@env.macro
|
||||
def video(name: str) -> str:
|
||||
return f"""<video loop muted autoplay id="{name}">
|
||||
<source src={video_dir + name} type="video/webm">
|
||||
Your browser does not support the video tag.
|
||||
</video>"""
|
||||
|
||||
@env.macro
|
||||
def asciinema(name: str) -> str:
|
||||
return f"""<div id="{name}">
|
||||
<script>
|
||||
// Function to load the script and then create the Asciinema player
|
||||
function loadAsciinemaPlayer() {{
|
||||
var script = document.createElement('script');
|
||||
script.src = "{asciinema_dir}/asciinema-player.min.js";
|
||||
script.onload = function() {{
|
||||
AsciinemaPlayer.create('{video_dir + name}', document.getElementById("{name}"), {{
|
||||
loop: true,
|
||||
autoPlay: true,
|
||||
controls: false,
|
||||
speed: 1.5,
|
||||
theme: "solarized-light"
|
||||
}});
|
||||
}};
|
||||
document.head.appendChild(script);
|
||||
}}
|
||||
|
||||
// Load the Asciinema player script
|
||||
loadAsciinemaPlayer();
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="{asciinema_dir}/asciinema-player.css" />
|
||||
</div>"""
|
103
docs/mkdocs.yml
103
docs/mkdocs.yml
@ -1,4 +1,4 @@
|
||||
site_name: cLAN documentation
|
||||
site_name: Clan Documentation
|
||||
site_url: https://docs.clan.lol
|
||||
repo_url: https://git.clan.lol/clan/clan-core/
|
||||
repo_name: clan-core
|
||||
@ -10,17 +10,25 @@ validation:
|
||||
unrecognized_links: warn
|
||||
|
||||
markdown_extensions:
|
||||
- admonition
|
||||
- attr_list
|
||||
- footnotes
|
||||
- md_in_html
|
||||
- meta
|
||||
- plantuml_markdown
|
||||
- pymdownx.emoji:
|
||||
emoji_index: !!python/name:material.extensions.emoji.twemoji
|
||||
emoji_generator: !!python/name:material.extensions.emoji.to_svg
|
||||
- pymdownx.tasklist:
|
||||
custom_checkbox: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
- footnotes
|
||||
- meta
|
||||
- admonition
|
||||
- pymdownx.details
|
||||
- pymdownx.highlight:
|
||||
use_pygments: true
|
||||
anchor_linenums: true
|
||||
- pymdownx.keys
|
||||
- toc:
|
||||
title: On this page
|
||||
|
||||
@ -30,30 +38,75 @@ exclude_docs: |
|
||||
/drafts/
|
||||
|
||||
nav:
|
||||
- Blog:
|
||||
- blog/index.md
|
||||
- Getting started:
|
||||
- index.md
|
||||
- Configure: getting-started/configure.md
|
||||
- Deploy Machine: getting-started/machines.md
|
||||
- Installer: getting-started/installer.md
|
||||
- Setup Networking: getting-started/networking.md
|
||||
- Provision Secrets & Passwords: getting-started/secrets.md
|
||||
- Configure: getting-started/configure.md
|
||||
- Secrets & Facts: getting-started/secrets.md
|
||||
- Deploy Machine: getting-started/deploy.md
|
||||
- Mesh VPN: getting-started/mesh-vpn.md
|
||||
- Backup & Restore: getting-started/backups.md
|
||||
- Flake-parts: getting-started/flake-parts.md
|
||||
- Templates: templates/index.md
|
||||
- Modules:
|
||||
- Clan Modules:
|
||||
- reference/clanModules/borgbackup.md
|
||||
- reference/clanModules/deltachat.md
|
||||
- reference/clanModules/disk-layouts.md
|
||||
- reference/clanModules/ergochat.md
|
||||
- reference/clanModules/localbackup.md
|
||||
- reference/clanModules/localsend.md
|
||||
- reference/clanModules/matrix-synapse.md
|
||||
- reference/clanModules/moonlight.md
|
||||
- reference/clanModules/root-password.md
|
||||
- reference/clanModules/sshd.md
|
||||
- reference/clanModules/sunshine.md
|
||||
- reference/clanModules/syncthing.md
|
||||
- reference/clanModules/static-hosts.md
|
||||
- reference/clanModules/thelounge.md
|
||||
- reference/clanModules/trusted-nix-caches.md
|
||||
- reference/clanModules/user-password.md
|
||||
- reference/clanModules/xfce.md
|
||||
- reference/clanModules/zerotier-static-peers.md
|
||||
- reference/clanModules/zt-tcp-relay.md
|
||||
- CLI:
|
||||
- reference/cli/index.md
|
||||
- reference/cli/backups.md
|
||||
- reference/cli/config.md
|
||||
- reference/cli/facts.md
|
||||
- reference/cli/flakes.md
|
||||
- reference/cli/flash.md
|
||||
- reference/cli/history.md
|
||||
- reference/cli/machines.md
|
||||
- reference/cli/secrets.md
|
||||
- reference/cli/ssh.md
|
||||
- reference/cli/vms.md
|
||||
- Clan Core:
|
||||
- reference/clan-core/index.md
|
||||
- reference/clan-core/backups.md
|
||||
- reference/clan-core/facts.md
|
||||
- reference/clan-core/sops.md
|
||||
- reference/clan-core/state.md
|
||||
- Contributing: contributing/contributing.md
|
||||
|
||||
docs_dir: site
|
||||
site_dir: out
|
||||
|
||||
theme:
|
||||
logo: static/logo.png
|
||||
font: false
|
||||
logo: https://clan.lol/static/logo/clan-white.png
|
||||
favicon: https://clan.lol/static/dark-favicon/128x128.png
|
||||
name: material
|
||||
features:
|
||||
- navigation.instant
|
||||
- navigation.tabs
|
||||
- content.code.annotate
|
||||
- content.code.copy
|
||||
- content.tabs.link
|
||||
icon:
|
||||
repo: fontawesome/brands/git
|
||||
repo: fontawesome/brands/git-alt
|
||||
custom_dir: overrides
|
||||
|
||||
palette:
|
||||
# Palette toggle for light mode
|
||||
@ -74,5 +127,33 @@ theme:
|
||||
icon: material/weather-sunny
|
||||
name: Switch to light mode
|
||||
|
||||
extra_css:
|
||||
- static/extra.css
|
||||
|
||||
extra:
|
||||
social:
|
||||
- icon: fontawesome/regular/comment
|
||||
link: https://matrix.to/#/#clan:lassul.us
|
||||
- icon: fontawesome/brands/gitlab
|
||||
link: https://git.clan.lol/clan/clan-core
|
||||
- icon: fontawesome/brands/github
|
||||
link: https://github.com/clan-lol/clan-core
|
||||
- icon: fontawesome/solid/rss
|
||||
link: /feed_rss_created.xml
|
||||
|
||||
plugins:
|
||||
- search
|
||||
- blog
|
||||
- macros
|
||||
- rss:
|
||||
match_path: blog/posts/.*
|
||||
use_git: false
|
||||
date_from_meta:
|
||||
as_creation: "date"
|
||||
as_update: "date"
|
||||
datetime_format: "%Y-%m-%d %H:%M"
|
||||
default_timezone: Europe/Paris
|
||||
default_time: "17:18"
|
||||
categories:
|
||||
- categories
|
||||
- tags
|
||||
|
@ -1,72 +0,0 @@
|
||||
{
|
||||
self,
|
||||
lib,
|
||||
inputs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
imports = [ ./zola-pages.nix ];
|
||||
|
||||
perSystem =
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
|
||||
allNixosModules = (import "${inputs.nixpkgs}/nixos/modules/module-list.nix") ++ [
|
||||
"${inputs.nixpkgs}/nixos/modules/misc/assertions.nix"
|
||||
{ nixpkgs.hostPlatform = "x86_64-linux"; }
|
||||
];
|
||||
|
||||
clanCoreNixosModules = [
|
||||
self.nixosModules.clanCore
|
||||
{ clanCore.clanDir = ./.; }
|
||||
] ++ allNixosModules;
|
||||
|
||||
# TODO: optimally we would not have to evaluate all nixos modules for every page
|
||||
# but some of our module options secretly depend on nixos modules.
|
||||
# We would have to get rid of these implicit dependencies and make them explicit
|
||||
clanCoreNixos = pkgs.nixos { imports = clanCoreNixosModules; };
|
||||
|
||||
# using extendModules here instead of re-evaluating nixos every time
|
||||
# improves eval performance slightly (10%)
|
||||
options = modules: (clanCoreNixos.extendModules { inherit modules; }).options;
|
||||
|
||||
docs =
|
||||
options:
|
||||
pkgs.nixosOptionsDoc {
|
||||
options = options;
|
||||
warningsAreErrors = false;
|
||||
# transform each option so that the declaration link points to git.clan.lol
|
||||
# and not to the /nix/store
|
||||
transformOptions =
|
||||
opt:
|
||||
opt
|
||||
// {
|
||||
declarations = lib.forEach opt.declarations (
|
||||
decl:
|
||||
if lib.hasPrefix "${self}" decl then
|
||||
let
|
||||
subpath = lib.removePrefix "${self}" decl;
|
||||
in
|
||||
{
|
||||
url = "https://git.clan.lol/clan/clan-core/src/branch/main/" + subpath;
|
||||
name = subpath;
|
||||
}
|
||||
else
|
||||
decl
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
outputsFor = name: docs: { packages."docs-md-${name}" = docs.optionsCommonMark; };
|
||||
|
||||
clanModulesPages = lib.flip lib.mapAttrsToList self.clanModules (
|
||||
name: module: outputsFor "module-${name}" (docs ((options [ module ]).clan.${name} or { }))
|
||||
);
|
||||
in
|
||||
{
|
||||
imports = clanModulesPages ++ [
|
||||
# renders all clanCore options in a single page
|
||||
(outputsFor "core-options" (docs (options [ ]).clanCore))
|
||||
];
|
||||
};
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
self',
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
getMdPages =
|
||||
prefix:
|
||||
let
|
||||
mdDocs' = lib.filterAttrs (name: _: lib.hasPrefix prefix name) self'.packages;
|
||||
mdDocs = lib.mapAttrs' (name: pkg: lib.nameValuePair (lib.removePrefix prefix name) pkg) mdDocs';
|
||||
in
|
||||
if mdDocs != { } then
|
||||
mdDocs
|
||||
else
|
||||
throw ''
|
||||
Error: no markdown files found in clan-core.packages' with prefix "${prefix}"
|
||||
'';
|
||||
|
||||
makeZolaIndexMd =
|
||||
title: weight:
|
||||
pkgs.writeText "_index.md" ''
|
||||
+++
|
||||
title = "${title}"
|
||||
template = "docs/section.html"
|
||||
weight = ${toString weight}
|
||||
sort_by = "title"
|
||||
draft = false
|
||||
+++
|
||||
'';
|
||||
|
||||
makeZolaPages =
|
||||
{
|
||||
sectionTitle,
|
||||
files,
|
||||
makeIntro ? _name: "",
|
||||
weight ? 9999,
|
||||
}:
|
||||
pkgs.runCommand "zola-pages-clan-core" { } ''
|
||||
mkdir $out
|
||||
# create new section via _index.md
|
||||
cp ${makeZolaIndexMd sectionTitle weight} $out/_index.md
|
||||
# generate zola compatible md files for each nixos options md
|
||||
${lib.concatStringsSep "\n" (
|
||||
lib.flip lib.mapAttrsToList files (
|
||||
name: md: ''
|
||||
# generate header for zola with title, template, weight
|
||||
title="${name}"
|
||||
echo -e "+++\ntitle = \"$title\"\ntemplate = \"docs/page.html\"\n+++" > "$out/${name}.md"
|
||||
cat <<EOF >> "$out/${name}.md"
|
||||
${makeIntro name}
|
||||
EOF
|
||||
# append everything from the nixpkgs generated md file
|
||||
cat "${md}" >> "$out/${name}.md"
|
||||
''
|
||||
)
|
||||
)}
|
||||
'';
|
||||
in
|
||||
{
|
||||
packages.docs-zola-pages-core = makeZolaPages {
|
||||
sectionTitle = "cLAN Core Reference";
|
||||
files = getMdPages "docs-md-core-";
|
||||
weight = 20;
|
||||
};
|
||||
|
||||
packages.docs-zola-pages-modules = makeZolaPages {
|
||||
sectionTitle = "cLAN Modules Reference";
|
||||
files = getMdPages "docs-md-module-";
|
||||
weight = 25;
|
||||
makeIntro = name: ''
|
||||
To use this module, import it like this:
|
||||
|
||||
\`\`\`nix
|
||||
{config, lib, inputs, ...}: {
|
||||
imports = [inputs.clan-core.clanModules.${name}];
|
||||
# ...
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -1,15 +1,45 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
pkgs,
|
||||
module-docs,
|
||||
clan-cli-docs,
|
||||
asciinema-player-js,
|
||||
asciinema-player-css,
|
||||
roboto,
|
||||
fira-code,
|
||||
...
|
||||
}:
|
||||
let
|
||||
uml-c4 = pkgs.python3Packages.plantuml-markdown.override { plantuml = pkgs.plantuml-c4; };
|
||||
in
|
||||
pkgs.stdenv.mkDerivation {
|
||||
name = "clan-documentation";
|
||||
|
||||
src = ../.;
|
||||
|
||||
nativeBuildInputs =
|
||||
[ pkgs.python3 ]
|
||||
[
|
||||
pkgs.python3
|
||||
uml-c4
|
||||
]
|
||||
++ (with pkgs.python3Packages; [
|
||||
mkdocs
|
||||
mkdocs-material
|
||||
mkdocs-rss-plugin
|
||||
mkdocs-macros
|
||||
]);
|
||||
configurePhase = ''
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
|
||||
mkdir -p ./site/static/asciinema-player
|
||||
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
|
||||
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
|
||||
|
||||
# Link to fonts
|
||||
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
|
||||
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
mkdocs build --strict
|
||||
|
@ -8,7 +8,7 @@
|
||||
}:
|
||||
|
||||
writeShellScriptBin "deploy-docs" ''
|
||||
set -eux -o pipefail
|
||||
set -eu -o pipefail
|
||||
export PATH="${
|
||||
lib.makeBinPath [
|
||||
coreutils
|
||||
@ -17,13 +17,26 @@ writeShellScriptBin "deploy-docs" ''
|
||||
]
|
||||
}"
|
||||
|
||||
if [ -n "$SSH_HOMEPAGE_KEY" ]; then
|
||||
#########################################
|
||||
# #
|
||||
# DO NOT PRINT THE SSH KEY TO THE LOGS #
|
||||
# #
|
||||
#########################################
|
||||
set +x
|
||||
if [ -n "''${SSH_HOMEPAGE_KEY:-}" ]; then
|
||||
echo "$SSH_HOMEPAGE_KEY" > ./ssh_key
|
||||
chmod 600 ./ssh_key
|
||||
sshExtraArgs="-i ./ssh_key"
|
||||
else
|
||||
sshExtraArgs=
|
||||
fi
|
||||
set -x
|
||||
###########################
|
||||
# #
|
||||
# END OF DANGER ZONE #
|
||||
# #
|
||||
###########################
|
||||
|
||||
|
||||
rsync \
|
||||
-e "ssh -o StrictHostKeyChecking=no $sshExtraArgs" \
|
||||
|
@ -1,4 +1,4 @@
|
||||
{ inputs, ... }:
|
||||
{ inputs, self, ... }:
|
||||
{
|
||||
perSystem =
|
||||
{
|
||||
@ -7,11 +7,77 @@
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
# Simply evaluated options (JSON)
|
||||
# { clanCore = «derivation JSON»; clanModules = { ${name} = «derivation JSON» }; }
|
||||
jsonDocs = import ./get-module-docs.nix {
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit pkgs self;
|
||||
inherit (self.nixosModules) clanCore;
|
||||
inherit (self) clanModules;
|
||||
};
|
||||
|
||||
clanModulesFileInfo = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModules);
|
||||
clanModulesReadmes = pkgs.writeText "info.json" (builtins.toJSON jsonDocs.clanModulesReadmes);
|
||||
|
||||
# Simply evaluated options (JSON)
|
||||
renderOptions =
|
||||
pkgs.runCommand "renderOptions.py"
|
||||
{
|
||||
# TODO: ruff does not splice properly in nativeBuildInputs
|
||||
depsBuildBuild = [ pkgs.ruff ];
|
||||
nativeBuildInputs = [
|
||||
pkgs.python3
|
||||
pkgs.mypy
|
||||
];
|
||||
}
|
||||
''
|
||||
install ${./scripts/renderOptions.py} $out
|
||||
patchShebangs --build $out
|
||||
|
||||
ruff format --check --diff $out
|
||||
ruff --line-length 88 $out
|
||||
mypy --strict $out
|
||||
'';
|
||||
|
||||
asciinema-player-js = pkgs.fetchurl {
|
||||
url = "https://github.com/asciinema/asciinema-player/releases/download/v3.7.0/asciinema-player.min.js";
|
||||
sha256 = "sha256-Ymco/+FinDr5YOrV72ehclpp4amrczjo5EU3jfr/zxs=";
|
||||
};
|
||||
asciinema-player-css = pkgs.fetchurl {
|
||||
url = "https://github.com/asciinema/asciinema-player/releases/download/v3.7.0/asciinema-player.css";
|
||||
sha256 = "sha256-GZMeZFFGvP5GMqqh516mjJKfQaiJ6bL38bSYOXkaohc=";
|
||||
};
|
||||
|
||||
module-docs = pkgs.runCommand "rendered" { nativeBuildInputs = [ pkgs.python3 ]; } ''
|
||||
export CLAN_CORE=${jsonDocs.clanCore}/share/doc/nixos/options.json
|
||||
# A file that contains the links to all clanModule docs
|
||||
export CLAN_MODULES=${clanModulesFileInfo}
|
||||
export CLAN_MODULES_READMES=${clanModulesReadmes}
|
||||
|
||||
mkdir $out
|
||||
|
||||
# The python script will place mkDocs files in the output directory
|
||||
python3 ${renderOptions}
|
||||
'';
|
||||
in
|
||||
{
|
||||
devShells.docs = pkgs.callPackage ./shell.nix { inherit (self'.packages) docs; };
|
||||
devShells.docs = pkgs.callPackage ./shell.nix {
|
||||
inherit (self'.packages) docs clan-cli-docs;
|
||||
inherit module-docs;
|
||||
inherit asciinema-player-js;
|
||||
inherit asciinema-player-css;
|
||||
};
|
||||
packages = {
|
||||
docs = pkgs.python3.pkgs.callPackage ./default.nix { inherit (inputs) nixpkgs; };
|
||||
docs = pkgs.python3.pkgs.callPackage ./default.nix {
|
||||
inherit (self'.packages) clan-cli-docs;
|
||||
inherit (inputs) nixpkgs;
|
||||
inherit module-docs;
|
||||
inherit asciinema-player-js;
|
||||
inherit asciinema-player-css;
|
||||
};
|
||||
deploy-docs = pkgs.callPackage ./deploy-docs.nix { inherit (config.packages) docs; };
|
||||
inherit module-docs;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
51
docs/nix/get-module-docs.nix
Normal file
51
docs/nix/get-module-docs.nix
Normal file
@ -0,0 +1,51 @@
|
||||
{
|
||||
nixpkgs,
|
||||
pkgs,
|
||||
clanCore,
|
||||
clanModules,
|
||||
self,
|
||||
}:
|
||||
let
|
||||
allNixosModules = (import "${nixpkgs}/nixos/modules/module-list.nix") ++ [
|
||||
"${nixpkgs}/nixos/modules/misc/assertions.nix"
|
||||
{ nixpkgs.hostPlatform = "x86_64-linux"; }
|
||||
];
|
||||
|
||||
clanCoreNixosModules = [
|
||||
clanCore
|
||||
{ clanCore.clanDir = ./.; }
|
||||
] ++ allNixosModules;
|
||||
|
||||
# TODO: optimally we would not have to evaluate all nixos modules for every page
|
||||
# but some of our module options secretly depend on nixos modules.
|
||||
# We would have to get rid of these implicit dependencies and make them explicit
|
||||
clanCoreNixos = pkgs.nixos { imports = clanCoreNixosModules; };
|
||||
|
||||
# using extendModules here instead of re-evaluating nixos every time
|
||||
# improves eval performance slightly (10%)
|
||||
getOptions = modules: (clanCoreNixos.extendModules { inherit modules; }).options;
|
||||
|
||||
evalDocs =
|
||||
options:
|
||||
pkgs.nixosOptionsDoc {
|
||||
options = options;
|
||||
warningsAreErrors = false;
|
||||
};
|
||||
|
||||
# clanModules docs
|
||||
clanModulesDocs = builtins.mapAttrs (
|
||||
name: module: (evalDocs ((getOptions [ module ]).clan.${name} or { })).optionsJSON
|
||||
) clanModules;
|
||||
|
||||
clanModulesReadmes = builtins.mapAttrs (
|
||||
module_name: _module: self.lib.modules.getReadme module_name
|
||||
) clanModules;
|
||||
|
||||
# clanCore docs
|
||||
clanCoreDocs = (evalDocs (getOptions [ ]).clanCore).optionsJSON;
|
||||
in
|
||||
{
|
||||
inherit clanModulesReadmes;
|
||||
clanCore = clanCoreDocs;
|
||||
clanModules = clanModulesDocs;
|
||||
}
|
237
docs/nix/scripts/renderOptions.py
Normal file
237
docs/nix/scripts/renderOptions.py
Normal file
@ -0,0 +1,237 @@
|
||||
# Options are available in the following format:
|
||||
# https://github.com/nixos/nixpkgs/blob/master/nixos/lib/make-options-doc/default.nix
|
||||
#
|
||||
# ```json
|
||||
# {
|
||||
# ...
|
||||
# "fileSystems.<name>.options": {
|
||||
# "declarations": ["nixos/modules/tasks/filesystems.nix"],
|
||||
# "default": {
|
||||
# "_type": "literalExpression",
|
||||
# "text": "[\n \"defaults\"\n]"
|
||||
# },
|
||||
# "description": "Options used to mount the file system.",
|
||||
# "example": {
|
||||
# "_type": "literalExpression",
|
||||
# "text": "[\n \"data=journal\"\n]"
|
||||
# },
|
||||
# "loc": ["fileSystems", "<name>", "options"],
|
||||
# "readOnly": false,
|
||||
# "type": "non-empty (list of string (with check: non-empty))"
|
||||
# "relatedPackages": "- [`pkgs.tmux`](\n https://search.nixos.org/packages?show=tmux&sort=relevance&query=tmux\n )\n",
|
||||
# }
|
||||
# }
|
||||
# ```
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
# Get environment variables
|
||||
CLAN_CORE = os.getenv("CLAN_CORE")
|
||||
CLAN_MODULES = os.environ.get("CLAN_MODULES")
|
||||
CLAN_MODULES_READMES = os.environ.get("CLAN_MODULES_READMES")
|
||||
|
||||
OUT = os.environ.get("out")
|
||||
|
||||
|
||||
def sanitize(text: str) -> str:
|
||||
return text.replace(">", "\\>")
|
||||
|
||||
|
||||
def replace_store_path(text: str) -> tuple[str, str]:
|
||||
res = text
|
||||
if text.startswith("/nix/store/"):
|
||||
res = "https://git.clan.lol/clan/clan-core/src/branch/main/" + str(
|
||||
Path(*Path(text).parts[4:])
|
||||
)
|
||||
name = Path(res).name
|
||||
return (res, name)
|
||||
|
||||
|
||||
def render_option_header(name: str) -> str:
|
||||
return f"# {name}\n"
|
||||
|
||||
|
||||
def join_lines_with_indentation(lines: list[str], indent: int = 4) -> str:
|
||||
"""
|
||||
Joins multiple lines with a specified number of whitespace characters as indentation.
|
||||
|
||||
Args:
|
||||
lines (list of str): The lines of text to join.
|
||||
indent (int): The number of whitespace characters to use as indentation for each line.
|
||||
|
||||
Returns:
|
||||
str: The indented and concatenated string.
|
||||
"""
|
||||
# Create the indentation string (e.g., four spaces)
|
||||
indent_str = " " * indent
|
||||
# Join each line with the indentation added at the beginning
|
||||
return "\n".join(indent_str + line for line in lines)
|
||||
|
||||
|
||||
def render_option(name: str, option: dict[str, Any], level: int = 3) -> str:
|
||||
read_only = option.get("readOnly")
|
||||
|
||||
res = f"""
|
||||
{"#" * level} {sanitize(name)}
|
||||
{"Readonly" if read_only else ""}
|
||||
{option.get("description", "No description available.")}
|
||||
|
||||
**Type**: `{option["type"]}`
|
||||
|
||||
"""
|
||||
if option.get("default"):
|
||||
res += f"""
|
||||
**Default**:
|
||||
|
||||
```nix
|
||||
{option["default"]["text"] if option.get("default") else "No default set."}
|
||||
```
|
||||
"""
|
||||
example = option.get("example", {}).get("text")
|
||||
if example:
|
||||
example_indented = join_lines_with_indentation(example.split("\n"))
|
||||
res += f"""
|
||||
|
||||
???+ example
|
||||
|
||||
```nix
|
||||
{example_indented}
|
||||
```
|
||||
"""
|
||||
if option.get("relatedPackages"):
|
||||
res += f"""
|
||||
### Related Packages
|
||||
|
||||
{option["relatedPackages"]}
|
||||
"""
|
||||
|
||||
decls = option.get("declarations", [])
|
||||
source_path, name = replace_store_path(decls[0])
|
||||
print(source_path, name)
|
||||
res += f"""
|
||||
:simple-git: [{name}]({source_path})
|
||||
"""
|
||||
res += "\n"
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def module_header(module_name: str) -> str:
|
||||
return f"# {module_name}\n"
|
||||
|
||||
|
||||
def module_usage(module_name: str) -> str:
|
||||
return f"""## Usage
|
||||
|
||||
To use this module, import it like this:
|
||||
|
||||
```nix
|
||||
{{config, lib, inputs, ...}}: {{
|
||||
imports = [ inputs.clan-core.clanModules.{module_name} ];
|
||||
# ...
|
||||
}}
|
||||
```
|
||||
"""
|
||||
|
||||
|
||||
clan_core_descr = """ClanCore delivers all the essential features for every clan.
|
||||
It's always included in your setup, and you can customize your clan's behavior with the configuration [options](#module-options) provided below.
|
||||
|
||||
"""
|
||||
|
||||
options_head = "\n## Module Options\n"
|
||||
|
||||
|
||||
def produce_clan_core_docs() -> None:
|
||||
if not CLAN_CORE:
|
||||
raise ValueError(
|
||||
f"Environment variables are not set correctly: $CLAN_CORE={CLAN_CORE}"
|
||||
)
|
||||
|
||||
if not OUT:
|
||||
raise ValueError(f"Environment variables are not set correctly: $out={OUT}")
|
||||
|
||||
# A mapping of output file to content
|
||||
core_outputs: dict[str, str] = {}
|
||||
with open(CLAN_CORE) as f:
|
||||
options: dict[str, dict[str, Any]] = json.load(f)
|
||||
module_name = "clan-core"
|
||||
for option_name, info in options.items():
|
||||
outfile = f"{module_name}/index.md"
|
||||
|
||||
# Create separate files for nested options
|
||||
if len(option_name.split(".")) <= 2:
|
||||
# i.e. clan-core.clanDir
|
||||
output = core_outputs.get(
|
||||
outfile,
|
||||
module_header(module_name) + clan_core_descr + options_head,
|
||||
)
|
||||
output += render_option(option_name, info)
|
||||
# Update the content
|
||||
core_outputs[outfile] = output
|
||||
else:
|
||||
# Clan sub-options
|
||||
[_, sub] = option_name.split(".")[0:2]
|
||||
outfile = f"{module_name}/{sub}.md"
|
||||
# Get the content or write the header
|
||||
output = core_outputs.get(outfile, render_option_header(sub))
|
||||
output += render_option(option_name, info)
|
||||
# Update the content
|
||||
core_outputs[outfile] = output
|
||||
|
||||
for outfile, output in core_outputs.items():
|
||||
(Path(OUT) / outfile).parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(Path(OUT) / outfile, "w") as of:
|
||||
of.write(output)
|
||||
|
||||
|
||||
def produce_clan_modules_docs() -> None:
|
||||
if not CLAN_MODULES:
|
||||
raise ValueError(
|
||||
f"Environment variables are not set correctly: $CLAN_MODULES={CLAN_MODULES}"
|
||||
)
|
||||
if not CLAN_MODULES_READMES:
|
||||
raise ValueError(
|
||||
f"Environment variables are not set correctly: $CLAN_MODULES_READMES={CLAN_MODULES_READMES}"
|
||||
)
|
||||
|
||||
if not OUT:
|
||||
raise ValueError(f"Environment variables are not set correctly: $out={OUT}")
|
||||
|
||||
with open(CLAN_MODULES) as f:
|
||||
links: dict[str, str] = json.load(f)
|
||||
|
||||
with open(CLAN_MODULES_READMES) as readme:
|
||||
readme_map: dict[str, str] = json.load(readme)
|
||||
|
||||
# {'borgbackup': '/nix/store/hi17dwgy7963ddd4ijh81fv0c9sbh8sw-options.json', ... }
|
||||
for module_name, options_file in links.items():
|
||||
with open(Path(options_file) / "share/doc/nixos/options.json") as f:
|
||||
options: dict[str, dict[str, Any]] = json.load(f)
|
||||
print(f"Rendering options for {module_name}...")
|
||||
output = module_header(module_name)
|
||||
|
||||
if readme_map.get(module_name, None):
|
||||
output += f"{readme_map[module_name]}\n"
|
||||
|
||||
output += module_usage(module_name)
|
||||
|
||||
output += options_head if len(options.items()) else ""
|
||||
for option_name, info in options.items():
|
||||
output += render_option(option_name, info)
|
||||
|
||||
outfile = Path(OUT) / f"clanModules/{module_name}.md"
|
||||
outfile.parent.mkdir(
|
||||
parents=True,
|
||||
exist_ok=True,
|
||||
)
|
||||
with open(outfile, "w") as of:
|
||||
of.write(output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
produce_clan_core_docs()
|
||||
produce_clan_modules_docs()
|
@ -1 +1,31 @@
|
||||
{ docs, pkgs, ... }: pkgs.mkShell { inputsFrom = [ docs ]; }
|
||||
{
|
||||
docs,
|
||||
pkgs,
|
||||
module-docs,
|
||||
clan-cli-docs,
|
||||
asciinema-player-js,
|
||||
asciinema-player-css,
|
||||
roboto,
|
||||
fira-code,
|
||||
...
|
||||
}:
|
||||
pkgs.mkShell {
|
||||
inputsFrom = [ docs ];
|
||||
shellHook = ''
|
||||
mkdir -p ./site/reference/cli
|
||||
cp -af ${module-docs}/* ./site/reference/
|
||||
cp -af ${clan-cli-docs}/* ./site/reference/cli/
|
||||
chmod +w ./site/reference/*
|
||||
|
||||
echo "Generated API documentation in './site/reference/' "
|
||||
|
||||
mkdir -p ./site/static/asciinema-player
|
||||
|
||||
ln -snf ${asciinema-player-js} ./site/static/asciinema-player/asciinema-player.min.js
|
||||
ln -snf ${asciinema-player-css} ./site/static/asciinema-player/asciinema-player.css
|
||||
|
||||
# Link to fonts
|
||||
ln -snf ${roboto}/share/fonts/truetype/Roboto-Regular.ttf ./site/static/
|
||||
ln -snf ${fira-code}/share/fonts/truetype/FiraCode-VF.ttf ./site/static/
|
||||
'';
|
||||
}
|
||||
|
12
docs/overrides/main.html
Normal file
12
docs/overrides/main.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
<meta property="og:title" content="Clan - Documentation, Blog & Getting Started Guide" />
|
||||
<meta property="og:description" content="Documentation for Clan. The peer-to-peer machine deployment framework." />
|
||||
<meta property="og:image" content="https://clan.lol/static/dark-favicon/128x128.png" />
|
||||
<meta property="og:url" content="https://docs.clan.lol" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content="Clan" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
|
||||
{% endblock %}
|
26
docs/site/blog/.authors.yml
Normal file
26
docs/site/blog/.authors.yml
Normal file
@ -0,0 +1,26 @@
|
||||
authors:
|
||||
DavHau:
|
||||
name: "DavHau"
|
||||
description: "Core Developer"
|
||||
avatar: "https://clan.lol/static/profiles/davhau.jpg"
|
||||
url: "https://DavHau.com"
|
||||
Lassulus:
|
||||
name: "Lassulus"
|
||||
description: "Core Developer"
|
||||
avatar: "https://clan.lol/static/profiles/lassulus.jpg"
|
||||
url: "https://http://lassul.us/"
|
||||
Mic92:
|
||||
name: "Mic92"
|
||||
description: "Core Developer"
|
||||
avatar: "https://clan.lol/static/profiles/mic92.jpg"
|
||||
url: "https://thalheim.io"
|
||||
W:
|
||||
name: "W"
|
||||
description: "Founder of Clan"
|
||||
avatar: "https://clan.lol/static/profiles/w_profile.webp"
|
||||
url: ""
|
||||
Qubasa:
|
||||
name: "Qubasa"
|
||||
description: "Core Developer"
|
||||
avatar: "https://clan.lol/static/profiles/qubasa.png"
|
||||
url: "https://github.com/Qubasa"
|
2
docs/site/blog/index.md
Normal file
2
docs/site/blog/index.md
Normal file
@ -0,0 +1,2 @@
|
||||
# Blog
|
||||
|
72
docs/site/blog/posts/hello-world.md
Normal file
72
docs/site/blog/posts/hello-world.md
Normal file
@ -0,0 +1,72 @@
|
||||
---
|
||||
title: "Introducing Clan: Full-Stack Computing Redefined"
|
||||
description: "Introducing Clan, a new model for a decentralized network, designed to provide families, smaller groups, and small businesses a platform that’s private, secure, and user-friendly."
|
||||
authors:
|
||||
- W
|
||||
- Qubasa
|
||||
date: 2024-03-19
|
||||
---
|
||||
|
||||
|
||||
In a digital age where users are guided increasingly toward submission and dependence, Clan reclaims computing and networking from the ground up.
|
||||
|
||||
Clan enables users to build any system from a git repository, automate secret handling, and join devices in a secure darknet. This control extends beyond applications to communication protocols and the operating system itself, putting you fully in charge of your own digital environment.
|
||||
|
||||
## Why We're Building Clan
|
||||
|
||||
Our mission is simple: to restore fun, freedom, and functionality to computing as an open source project. We believe in building tools that empower users, foster innovation, and challenge the limitations imposed by outdated paradigms. Clan, in its essence, is an open source endeavor; it's our contribution to a future where technology serves humanity, not the other way around.
|
||||
|
||||
## How Clan Changes the Game
|
||||
Clan embodies a new philosophy in system, application, and network design. It enables seamless, secure communication across devices, simplifies software distribution and updates, and offers both public and private network configurations. Here are some of the ways it accomplishes this:
|
||||
|
||||
- **Nix as a Foundation:** Imagine a safety net for your computer's operating system, one that lets you make changes or updates without the fear of causing a crash or losing data. Nix simplifies the complexities of system design, ensuring that updates are safe and systems are more reliable.
|
||||
|
||||
- **Simplified System Deployment:** Building and managing a computer system, from the operating system to the software you use, often feels like putting together a complex puzzle. With Clan, the puzzle pieces are replaced by a set of building blocks. Leveraging the power of Nix and Clan's innovative toolkit, anyone from tech-savvy administrators to everyday users can create and maintain what we call "full-stack systems" (everything your computer needs to run smoothly).
|
||||
|
||||
- **A Leap in Connectivity:** Imagine if you could create private, secure pathways between your devices, bypassing the noisy and often insecure internet. Clan makes this possible through something called "overlay networks." These networks are like private tunnels, allowing your devices to talk to each other securely and directly. With Clan's built-in overlay networks and automatically configured services, connecting your devices becomes seamless, secure, and hassle-free.
|
||||
|
||||
- **Security Through Separation:** Clan employs sandboxing and virtual machines, a technology that runs code in isolated environments - so even if you explore new Clans, your system remains protected from potential threats.
|
||||
|
||||
- **Reliable:** With Clan, your data and services are preserved for the long haul. We focus on self-hosted backups and integration with the [Fediverse](https://de.wikipedia.org/wiki/Fediverse), a network of interconnected, independent online communities, so your digital life remains uninterrupted and under your control.
|
||||
|
||||
|
||||
## A Glimpse at Clan's Features
|
||||
|
||||
- **Social Scaling:** Choose between creating a private sanctuary for your closest contacts, a dynamic space for a self-contained community, or embracing the open web with public Clans anyone can join.
|
||||
|
||||
{{ video(name="show_join.webm")}}
|
||||
|
||||
- **Seamless VM Integration:** Applications running in virtual machines can appear and behave as if they're part of your main operating system — a blend of power and simplicity.
|
||||
|
||||
{{ video(name="show_run.webm")}}
|
||||
|
||||
- **Robust Backup Management:** Keep your data safe _forever_ - never worry about cloud services disappearing in 10 years.
|
||||
|
||||
{{ asciinema(name="backups.cast") }}
|
||||
|
||||
- **Intuitive Secret Management:** Clan simplifies digital security by automating the creation and management of encryption keys and passwords for your services.
|
||||
|
||||
{{ asciinema(name="secrets.cast") }}
|
||||
|
||||
- **Remote Install:** Set up and manage Clan systems anywhere in the world with just a QR scan or SSH access, making remote installations as easy as snapping a photo or sharing a link.
|
||||
|
||||
{{ asciinema(name="nixos-install.cast") }}
|
||||
|
||||
|
||||
## Who Stands to Benefit?
|
||||
|
||||
Clan is for anyone and everyone who believes in the power of open source technology to connect, empower, and protect. From system administrators to less tech-savvy individuals, small business owners to privacy-conscious users, Clan offers something for everyone — a way to reclaim control and redefine how we interact with technology.
|
||||
|
||||
## Join the Revolution
|
||||
|
||||
Ready to control your digital world? Clan is more than a tool—it's a movement. Secure your data, manage your systems easily, or connect with others how you like. Start with Clan for a better digital future.
|
||||
|
||||
Connect with us on our [Matrix channel at clan.lol](https://matrix.to/#/#clan:lassul.us) or through our IRC bridges (coming soon).
|
||||
|
||||
Want to see the code? Check it out [on our Gitea](https://git.clan.lol/clan/clan-core) or [on GitHub](https://github.com/clan-lol/clan-core).
|
||||
|
||||
Or follow our [RSS feed](https://docs.clan.lol/feed_rss_created.xml)!
|
||||
|
||||
Join us and be part of changing technology for the better, together.
|
||||
|
||||
|
194
docs/site/blog/posts/jsonschema.md
Normal file
194
docs/site/blog/posts/jsonschema.md
Normal file
@ -0,0 +1,194 @@
|
||||
---
|
||||
title: "Dev Report: Introducing the NixOS to JSON Schema Converter"
|
||||
description: "Discover our new library designed to extract JSON schema interfaces from NixOS modules, streamlining frontend development"
|
||||
authors:
|
||||
- DavHau
|
||||
date: 2024-05-25
|
||||
slug: jsonschema-converter
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
We’ve developed a new library designed to extract interfaces from NixOS modules and convert them into JSON schemas, paving the way for effortless GUI generation. This blog post outlines the motivations behind this development, demonstrates the capabilities of the library, and guides you through leveraging it to create GUIs seamlessly.
|
||||
|
||||
## Motivation
|
||||
|
||||
In recent months, our team has been exploring various graphical user interfaces (GUIs) to streamline NixOS machine configuration. While our opinionated Clan modules simplify NixOS configurations, there's a need to configure these modules from diverse frontends, such as:
|
||||
|
||||
- Command-line interfaces (CLIs)
|
||||
- Web-based UIs
|
||||
- Desktop applications
|
||||
- Mobile applications
|
||||
- Large Language Models (LLMs)
|
||||
|
||||
Given this need, a universal format like JSON is a natural choice. It is already possible as of now, to import json based NixOS configurations, as illustrated below:
|
||||
|
||||
`configuration.json`:
|
||||
```json
|
||||
{ "networking": { "hostName": "my-machine" } }
|
||||
```
|
||||
|
||||
This configuration can be then imported inside a classic NixOS config:
|
||||
```nix
|
||||
{config, lib, pkgs, ...}: {
|
||||
imports = [
|
||||
(lib.importJSON ./configuration.json)
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
This straightforward approach allows us to build a frontend that generates JSON, enabling the configuration of NixOS machines. But, two critical questions arise:
|
||||
|
||||
1. How does the frontend learn about existing configuration options?
|
||||
2. How can it verify user input without running Nix?
|
||||
|
||||
Introducing [JSON schema](https://json-schema.org/), a widely supported standard that defines interfaces in JSON and validates input against them.
|
||||
|
||||
Example schema for `networking.hostName`:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"networking": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"hostName": {
|
||||
"type": "string",
|
||||
"pattern": "^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Client-Side Input Validation
|
||||
|
||||
Validating input against JSON schemas is both efficient and well-supported across numerous programming languages. Using JSON schema validators, you can accurately check configurations like our `configuration.json`.
|
||||
|
||||
Validation example:
|
||||
|
||||
```shell
|
||||
$ nix-shell -p check-jsonschema
|
||||
$ jsonschema -o pretty ./schema.json -i ./configuration.json
|
||||
===[SUCCESS]===(./configuration.json)===
|
||||
```
|
||||
|
||||
In case of invalid input, schema validators provide explicit error messages:
|
||||
|
||||
```shell
|
||||
$ echo '{ "networking": { "hostName": "my/machine" } }' > configuration.json
|
||||
$ jsonschema -o pretty ./schema.json -i ./configuration.json
|
||||
===[ValidationError]===(./configuration.json)===
|
||||
|
||||
'my/machine' does not match '^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$'
|
||||
|
||||
Failed validating 'pattern' in schema['properties']['networking']['properties']['hostName']:
|
||||
{'pattern': '^$|^[a-z0-9]([a-z0-9_-]{0,61}[a-z0-9])?$',
|
||||
'type': 'string'}
|
||||
|
||||
On instance['networking']['hostName']:
|
||||
'my/machine'
|
||||
```
|
||||
|
||||
## Automatic GUI Generation
|
||||
|
||||
Certain libraries facilitate straightforward GUI generation from JSON schemas. For instance, the [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/) auto-generates a form for any given schema.
|
||||
|
||||
## NixOS Module to JSON Schema Converter
|
||||
|
||||
To enable the development of responsive frontends, our library allows the extraction of interfaces from NixOS modules to JSON schemas. Open-sourced for community collaboration, this library supports building sophisticated user interfaces for NixOS.
|
||||
|
||||
Here’s a preview of our library's functions exposed through the [clan-core](https://git.clan.lol/clan/clan-core) flake:
|
||||
|
||||
- `lib.jsonschema.parseModule` - Generates a schema for a NixOS module.
|
||||
- `lib.jsonschema.parseOption` - Generates a schema for a single NixOS option.
|
||||
- `lib.jsonschema.parseOptions` - Generates a schema from an attrset of NixOS options.
|
||||
|
||||
Example:
|
||||
`module.nix`:
|
||||
```nix
|
||||
{lib, config, pkgs, ...}: {
|
||||
# a simple service with two options
|
||||
options.services.example-web-service = {
|
||||
enable = lib.mkEnableOption "Example web service";
|
||||
port = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
description = "Port used to serve the content";
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Converted, using the `parseModule` function:
|
||||
```shell
|
||||
$ cd clan-core
|
||||
$ nix eval --json --impure --expr \
|
||||
'(import ./lib/jsonschema {}).parseModule ./module.nix' | jq | head
|
||||
{
|
||||
"properties": {
|
||||
"services": {
|
||||
"properties": {
|
||||
"example-web-service": {
|
||||
"properties": {
|
||||
"enable": {
|
||||
"default": false,
|
||||
"description": "Whether to enable Example web service.",
|
||||
"examples": [
|
||||
...
|
||||
```
|
||||
|
||||
This utility can also generate interfaces for existing NixOS modules or options.
|
||||
|
||||
## GUI for NGINX in Under a Minute
|
||||
|
||||
Creating a prototype GUI for the NGINX module using our library and [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/) can be done quickly:
|
||||
|
||||
1. Export all NGINX options into a JSON schema using a Nix expression:
|
||||
|
||||
```nix
|
||||
# export.nix
|
||||
let
|
||||
pkgs = import <nixpkgs> {};
|
||||
clan-core = builtins.getFlake "git+https://git.clan.lol/clan/clan-core";
|
||||
options = (pkgs.nixos {}).options.services.nginx;
|
||||
in
|
||||
clan-core.lib.jsonschema.parseOption options
|
||||
```
|
||||
|
||||
2. Write the schema into a file:
|
||||
```shell
|
||||
$ nix eval --json -f ./export.nix | jq > nginx.json
|
||||
```
|
||||
|
||||
3. Open the [react-jsonschema-form playground](https://rjsf-team.github.io/react-jsonschema-form/), select `Blank` and paste the `nginx.json` contents.
|
||||
|
||||
This provides a quick look at a potential GUI (screenshot is cropped).
|
||||
|
||||
![Image title](https://clan.lol/static/blog-post-jsonschema/nginx-gui.jpg)
|
||||
|
||||
## Limitations
|
||||
|
||||
### Laziness
|
||||
|
||||
JSON schema mandates the declaration of all required fields upfront, which might be configured implicitly or remain unused. For instance, `services.nginx.virtualHosts.<name>.sslCertificate` must be specified even if SSL isn’t enabled.
|
||||
|
||||
### Limited Types
|
||||
|
||||
Certain NixOS module types, like `types.functionTo` and `types.package`, do not map straightforwardly to JSON. For full compatibility, adjustments to NixOS modules might be necessary, such as substituting `listOf package` with `listOf str`.
|
||||
|
||||
### Parsing NixOS Modules
|
||||
|
||||
Currently, our converter relies on the `options` attribute of evaluated NixOS modules, extracting information from the `type.name` attribute, which is suboptimal. Enhanced introspection capabilities within the NixOS module system would be beneficial.
|
||||
|
||||
## Future Prospects
|
||||
|
||||
We hope these experiments inspire the community, encourage contributions and further development in this space. Share your ideas and contributions through our issue tracker or matrix channel!
|
||||
|
||||
## Links
|
||||
|
||||
- [Comments on NixOS Discourse](https://discourse.nixos.org/t/introducing-the-nixos-to-json-schema-converter/45948)
|
||||
- [Source Code of the JSON Schema Library](https://git.clan.lol/clan/clan-core/src/branch/main/lib/jsonschema)
|
||||
- [Our Issue Tracker](https://git.clan.lol/clan/clan-core/issues)
|
||||
- [Our Matrix Channel](https://matrix.to/#/#clan:lassul.us)
|
||||
- [react-jsonschema-form Playground](https://rjsf-team.github.io/react-jsonschema-form/)
|
13
docs/site/blog/posts/new-docs.md
Normal file
13
docs/site/blog/posts/new-docs.md
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
title: "New documentation site and weekly new meetup"
|
||||
authors:
|
||||
- Lassulus
|
||||
- Mic92
|
||||
date: 2024-04-16
|
||||
---
|
||||
|
||||
Last week, we added a new documentation hub for clan at [docs.clan.lol](https://docs.clan.lol).
|
||||
We are still working on improving the installation procedures, so stay tuned.
|
||||
We now have weekly office hours where people are invited to hangout and ask questions.
|
||||
They are every Wednesday 15:30 UTC (17:30 CEST) in our [jitsi](https://jitsi.lassul.us/clan.lol).
|
||||
Otherwise drop by in our [matrix channel](https://matrix.to/#/#clan:lassul.us).
|
63
docs/site/drafts/deployment-framework.md
Normal file
63
docs/site/drafts/deployment-framework.md
Normal file
@ -0,0 +1,63 @@
|
||||
---
|
||||
title: "Git Based Machine Deployment with Clan-Core"
|
||||
description: ""
|
||||
authors:
|
||||
- Qubasa
|
||||
date: 2024-05-25
|
||||
---
|
||||
## Revolutionizing Server Management
|
||||
|
||||
In the world of server management, countless tools claim to offer seamless deployment of multiple machines. Yet, many fall short, leaving server admins and self-hosting enthusiasts grappling with complexity. Enter the Clan-Core Framework—a groundbreaking all in one solution designed to transform decentralized self-hosting into an effortless and scalable endeavor.
|
||||
|
||||
### The Power of Clan-Core
|
||||
|
||||
Imagine having the power to manage your servers with unparalleled ease, scaling your IT infrastructure like never before. Clan-Core empowers you to do just that. At its core, Clan-Core leverages a single Git repository to define everything about your machines. This central repository utilizes Nix or JSON files to specify configurations, including disk formatting, ensuring a streamlined and unified approach.
|
||||
|
||||
### Simplified Deployment Process
|
||||
|
||||
With Clan-Core, the cumbersome task of bootstrapping a specific ISO is a thing of the past. All you need is SSH access to your Linux server. Clan-Core allows you to overwrite any existing Linux distribution live over SSH, eliminating time-consuming setup processes. This capability means you can deploy updates or new configurations swiftly and efficiently, maximizing uptime and minimizing hassle.
|
||||
|
||||
### Secure and Efficient Secret Management
|
||||
|
||||
Security is paramount in server management, and Clan-Core takes it seriously. Passwords and other sensitive information are encrypted within the Git repository, automatically decrypted during deployment. This not only ensures the safety of your secrets but also simplifies their management. Clan-Core supports sharing secrets with other admins, fostering collaboration and maintaining reproducibillity and security without sacrificing convenience.
|
||||
|
||||
### Services as Apps
|
||||
|
||||
Setting up a service can be quite difficult. Many server adjustments need to be made, from setting up a database to adjusting webserver configurations and generating the correct private keys. However, Clan-Core aims to make setting up a service as easy as installing an application. Through Clan-Core's Module system, everything down to secrets can be automatically set up. This transforms the often daunting task of service setup into a smooth, automated process, making it accessible to all.
|
||||
|
||||
### Decentralized Mesh VPN
|
||||
|
||||
Building on these features is a self-configuring decentralized mesh VPN that interconnects all your machines into a private darknet. This ensures that sensitive services, which might have too much attack surface to be hosted on the public internet, can still be made available privately without the need to worry about potential system compromise. By creating a secure, private network, Clan-Core offers an additional layer of protection for your most critical services.
|
||||
|
||||
### Decentralized Domain Name System
|
||||
|
||||
Current DNS implementations are distributed but not truly decentralized. For Clan-Core, we implemented our own truly decentralized DNS module. This module uses simple flooding and caching algorithms to discover available domains inside the darknet. This approach ensures that your internal domain name system is robust, reliable, and independent of external control, enhancing the resilience and security of your infrastructure.
|
||||
|
||||
|
||||
### A New Era of Decentralized Self-Hosting
|
||||
|
||||
Clan-Core is more than just a tool; it's a paradigm shift in server management. By consolidating machine definitions, secrets and network configuration, into a single, secure repository, it transforms how you manage and scale your infrastructure. Whether you're a seasoned server admin or a self-hosting enthusiast, Clan-Core offers a powerful, user-friendly solution to take your capabilities to the next level.
|
||||
|
||||
|
||||
### Key Features of Clan-Core:
|
||||
|
||||
- **Unified Git Repository**: All machine configurations and secrets stored in a single repository.
|
||||
- **Live Overwrites**: Deploy configurations over existing Linux distributions via SSH.
|
||||
- **Automated Service Setup**: Easily set up services with Clan-Core's Module system.
|
||||
- **Decentralized Mesh VPN**: Securely interconnect all machines into a private darknet.
|
||||
- **Decentralized DNS**: Robust, independent DNS using flooding and caching algorithms.
|
||||
- **Automated Secret Management**: Encrypted secrets that are automatically decrypted during deployment.
|
||||
- **Collaboration Support**: Share secrets securely with other admins.
|
||||
|
||||
|
||||
## Clan-Cores Future
|
||||
|
||||
Our vision for Clan-Core extends far beyond being just another deployment tool. Clan-Core is a framework we've developed to achieve something much greater. We want to put the "personal" back into "personal computing." Our goal is for everyday users to fully customize their phones or laptops and create truly private spaces for friends and family.
|
||||
|
||||
Our first major step is to develop a Graphical User Interface (GUI) that makes configuring all this possible. Initial tests have shown that AI can be leveraged as an alternative to traditional GUIs. This paves the way for a future where people can simply talk to their computers, and they will configure themselves according to the users' wishes.
|
||||
|
||||
By adopting Clan, you're not just embracing a tool—you're joining a movement towards a more efficient, secure, and scalable approach to server management. Join us and revolutionize your IT infrastructure today.
|
||||
|
||||
|
||||
|
||||
|
@ -6,13 +6,19 @@ For installations on physical hardware, create a NixOS installer image and trans
|
||||
|
||||
To create a bootable USB flash drive with the NixOS installer:
|
||||
|
||||
### Build the Installer Image
|
||||
### Download the install iso
|
||||
|
||||
```bash
|
||||
nix build git+https://git.clan.lol/clan/clan-core.git#install-iso
|
||||
Either with wget:
|
||||
|
||||
```shellSession
|
||||
wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso
|
||||
```
|
||||
|
||||
> Make sure you do this inside
|
||||
or with curl:
|
||||
|
||||
```shellSession
|
||||
curl -L https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso -o nixos-installer-x86_64-linux.iso
|
||||
```
|
||||
|
||||
### Prepare the USB Flash Drive
|
||||
|
||||
@ -20,8 +26,8 @@ nix build git+https://git.clan.lol/clan/clan-core.git#install-iso
|
||||
|
||||
2. Identify your flash drive with `lsblk`.
|
||||
|
||||
```bash
|
||||
$ lsblk
|
||||
```shellSession
|
||||
lsblk
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
sdb 8:0 1 117,2G 0 disk
|
||||
└─sdb1 8:1 1 117,2G 0 part /run/media/qubasa/INTENSO
|
||||
@ -35,7 +41,7 @@ nix build git+https://git.clan.lol/clan/clan-core.git#install-iso
|
||||
|
||||
3. Ensure all partitions on the drive are unmounted. Replace `sdX` in the command below with your device identifier (like `sdb`, etc.):
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
sudo umount /dev/sdb1
|
||||
```
|
||||
|
||||
@ -43,11 +49,11 @@ nix build git+https://git.clan.lol/clan/clan-core.git#install-iso
|
||||
|
||||
Use the `dd` utility to write the NixOS installer image to your USB drive:
|
||||
|
||||
```bash
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./result/stick.raw of=/dev/sd<X>
|
||||
```shellSession
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X>
|
||||
```
|
||||
|
||||
In case your USB device is `sdb` use `of=/dev/sdb`
|
||||
In this case, the USB device is `sdb` use `of=/dev/sdb`
|
||||
|
||||
### Boot and Connect
|
||||
|
||||
@ -85,14 +91,15 @@ After writing the installer to the USB drive, use it to boot the target machine.
|
||||
- **Apple**: Option (Alt) Key (Boot Menu for Mac)
|
||||
- If your hardware was not listed read the manufacturers instructions how to enter the boot Menu/BIOS Setup.
|
||||
|
||||
|
||||
5. Select `NixOS` to boot into the clan installer
|
||||
|
||||
6. The installer will display an IP address and a root password, which you can use to connect via SSH.
|
||||
Alternatively you can also use the displayed QR code.
|
||||
|
||||
7. Set your keyboard language. Important for writing passwords correctly.
|
||||
7. Set your keyboard language (i.e. `de` for German keyboards, default is English). Important for writing passwords correctly.
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
loadkeys de
|
||||
```
|
||||
|
||||
@ -100,31 +107,31 @@ After writing the installer to the USB drive, use it to boot the target machine.
|
||||
|
||||
1. Bring up the `iwd` shell
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
iwctl
|
||||
```
|
||||
|
||||
2. List available networks. Double press tab after station for device autocompletion. In this case `wlan0` is the only network wifi device.
|
||||
2. List available networks. Double press tab after station for autocompleting your wlan device. In this case `wlan0`
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
[iwd] station wlan0 get-networks
|
||||
```
|
||||
|
||||
3. Connect to a Wifi network. Replace `SSID` with the wlan network name.
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
[iwd] station wlan0 connect SSID
|
||||
```
|
||||
|
||||
9. Now that you have internet re-execute the init script by pressing `Ctrl+D` or by executing:
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
bash
|
||||
```
|
||||
|
||||
10. Connect to the machine over ssh
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
ssh-copy-id -o PreferredAuthentications=password root@<ip>
|
||||
```
|
||||
|
||||
|
324
docs/site/drafts/secret-cli.md
Normal file
324
docs/site/drafts/secret-cli.md
Normal file
@ -0,0 +1,324 @@
|
||||
## Secrets (CLI Reference)
|
||||
|
||||
#### Adding Secrets (set)
|
||||
|
||||
```bash
|
||||
clan secrets set mysecret
|
||||
> Paste your secret:
|
||||
```
|
||||
|
||||
!!! note
|
||||
As you type your secret won't be displayed. Press Enter to save the secret.
|
||||
|
||||
#### List all Secrets (list)
|
||||
|
||||
```bash
|
||||
clan secrets list
|
||||
```
|
||||
|
||||
#### Assigning Access (set)
|
||||
|
||||
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
|
||||
|
||||
```bash
|
||||
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
|
||||
#### Displaying Secrets (get)
|
||||
|
||||
```bash
|
||||
clan secrets get mysecret
|
||||
```
|
||||
|
||||
#### Rename
|
||||
|
||||
TODO
|
||||
|
||||
#### Remove
|
||||
|
||||
TODO
|
||||
|
||||
#### import-sops
|
||||
|
||||
TODO
|
||||
|
||||
### Users (Reference)
|
||||
|
||||
Learn how to manage users and allowing access to existing secrets.
|
||||
|
||||
#### list user
|
||||
|
||||
Lists all added users
|
||||
|
||||
```bash
|
||||
clan secrets user list
|
||||
```
|
||||
|
||||
``` {.console, title="Example output", .no-copy}
|
||||
jon
|
||||
sara
|
||||
```
|
||||
|
||||
!!! Question "Who can execute this command?"
|
||||
Everyone - completely public.
|
||||
|
||||
#### add user
|
||||
|
||||
add a user
|
||||
|
||||
```bash
|
||||
clan secrets users add {username} {public-key}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Changes can be trusted by maintainer review in version control.
|
||||
|
||||
#### get user
|
||||
|
||||
get a user public key
|
||||
|
||||
```bash
|
||||
clan secrets users get {username}
|
||||
```
|
||||
|
||||
``` {.console, title="Example output", .no-copy}
|
||||
age1zk8uzrte55wkg9lkqxu5x6twsj2ja4lehegks0cw4mkg6jv37d9qsjpt44
|
||||
```
|
||||
|
||||
#### remove user
|
||||
|
||||
remove a user
|
||||
|
||||
```bash
|
||||
clan secrets users remove {username}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Changes can be trusted by maintainer review in version control.
|
||||
|
||||
#### add-secret user
|
||||
|
||||
Grants the user (`username`) access to the secret (`secret_name`)
|
||||
|
||||
```bash
|
||||
clan secrets users add-secret {username} {secret_name}
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Requires the executor of the command to have access to the secret (`secret_name`).
|
||||
|
||||
#### remove-secret user
|
||||
|
||||
remove the user (`username`) from accessing the secret (`secret_name`)
|
||||
|
||||
!!! Danger "Make sure at least one person has access."
|
||||
It might still be possible for the machine to access the secret. (See [machines](#machines))
|
||||
|
||||
We highly recommend to use version control such as `git` which allows you to rollback secrets in case anything gets messed up.
|
||||
|
||||
```bash
|
||||
clan secrets users remove-secret {username} {secret_name}
|
||||
```
|
||||
|
||||
!!! Question "Who can execute this command?"
|
||||
Requires the executor of the command to have access to the secret (`secret_name`).
|
||||
|
||||
### Machines (Reference)
|
||||
|
||||
- [list](): list machines
|
||||
- [add](): add a machine
|
||||
- [get](): get a machine public key
|
||||
- [remove](): remove a machine
|
||||
- [add-secret](): allow a machine to access a secret
|
||||
- [remove-secret](): remove a machine's access to a secret
|
||||
|
||||
#### List machine
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
|
||||
```bash
|
||||
clan secrets machines list
|
||||
```
|
||||
|
||||
#### Add machine
|
||||
|
||||
For clan machines the machine key is generated automatically on demand if none exists.
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
If you already have a device key and want to add it manually, see: [How to obtain a remote key](#obtain-remote-keys-manually)
|
||||
|
||||
#### get machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove machine
|
||||
|
||||
TODO
|
||||
|
||||
#### add-secret machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove-secret machine
|
||||
|
||||
TODO
|
||||
|
||||
### Groups (Reference)
|
||||
|
||||
The Clan-CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
- [list](): list groups
|
||||
- [add-user](): add a user to group
|
||||
- [remove-user](): remove a user from group
|
||||
- [add-machine](): add a machine to group
|
||||
- [remove-machine](): remove a machine from group
|
||||
- [add-secret](): allow a user to access a secret
|
||||
- [remove-secret](): remove a group's access to a secret
|
||||
|
||||
#### List Groups
|
||||
|
||||
```bash
|
||||
clan secrets groups list
|
||||
```
|
||||
|
||||
#### add-user
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
clan secrets groups add-user admins <username>
|
||||
```
|
||||
|
||||
!!! info
|
||||
The group is created if no such group existed before.
|
||||
|
||||
The user must exist in beforehand (See: [users](#users-reference))
|
||||
|
||||
```{.console, .no-copy}
|
||||
.
|
||||
├── flake.nix
|
||||
. ...
|
||||
└── sops
|
||||
├── groups
|
||||
│ └── admins
|
||||
│ └── users
|
||||
│ └── <username> -> ../../../users/<username>
|
||||
```
|
||||
|
||||
#### remove-user
|
||||
|
||||
TODO
|
||||
|
||||
#### add-machine
|
||||
|
||||
TODO
|
||||
|
||||
#### remove-machine
|
||||
|
||||
TODO
|
||||
|
||||
#### add-secret
|
||||
|
||||
```bash
|
||||
clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
#### remove-secret
|
||||
|
||||
TODO
|
||||
|
||||
### Key (Reference)
|
||||
|
||||
- [generate]() generate age key
|
||||
- [show]() show age public key
|
||||
- [update]() re-encrypt all secrets with current keys (useful when changing keys)
|
||||
|
||||
#### generate
|
||||
|
||||
TODO
|
||||
|
||||
#### show
|
||||
|
||||
TODO
|
||||
|
||||
#### update
|
||||
|
||||
TODO
|
||||
|
||||
## Further
|
||||
|
||||
Secrets in the repository follow this structure:
|
||||
|
||||
```{.console, .no-copy}
|
||||
sops/
|
||||
├── secrets/
|
||||
│ └── <secret_name>/
|
||||
│ ├── secret
|
||||
│ └── users/
|
||||
│ └── <your_username>/
|
||||
```
|
||||
|
||||
The content of the secret is stored encrypted inside the `secret` file under `mysecret`.
|
||||
|
||||
By default, secrets are encrypted with your key to ensure readability.
|
||||
|
||||
### Obtain remote keys manually
|
||||
|
||||
To fetch a **SSH host key** from a preinstalled system:
|
||||
|
||||
```bash
|
||||
ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
!!! Success
|
||||
This command converts the SSH key into an age key on the fly. Since this is the format used by the clan secrets backend.
|
||||
|
||||
Once added the **SSH host key** enables seamless integration of existing machines with clan.
|
||||
|
||||
Then add the key by executing:
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
See also: [Machine reference](#machines-reference)
|
||||
|
||||
### NixOS integration
|
||||
|
||||
A NixOS machine will automatically import all secrets that are encrypted for the
|
||||
current machine. At runtime it will use the host key to decrypt all secrets into
|
||||
an in-memory, non-persistent filesystem using [sops-nix](https://github.com/Mic92/sops-nix).
|
||||
In your nixos configuration you can get a path to secrets like this `config.sops.secrets.<name>.path`. For example:
|
||||
|
||||
```nix
|
||||
{ config, ...}: {
|
||||
sops.secrets.my-password.neededForUsers = true;
|
||||
|
||||
users.users.mic92 = {
|
||||
isNormalUser = true;
|
||||
passwordFile = config.sops.secrets.my-password.path;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
|
||||
### Migration: Importing existing sops-based keys / sops-nix
|
||||
|
||||
`clan secrets` stores each secret in a single file, whereas [sops](https://github.com/Mic92/sops-nix) commonly allows to put all secrets in a yaml or json document.
|
||||
|
||||
If you already happened to use sops-nix, you can migrate by using the `clan secrets import-sops` command by importing these files:
|
||||
|
||||
```bash
|
||||
% clan secrets import-sops --prefix matchbox- --group admins --machine matchbox nixos/matchbox/secrets/secrets.yaml
|
||||
```
|
||||
|
||||
This will create secrets for each secret found in `nixos/matchbox/secrets/secrets.yaml` in a `./sops` folder of your repository.
|
||||
Each member of the group `admins` in this case will be able to decrypt the secrets with their respective key.
|
||||
|
||||
Since our clan secret module will auto-import secrets that are encrypted for a particular nixos machine,
|
||||
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
|
@ -5,28 +5,42 @@
|
||||
In the `flake.nix` file:
|
||||
|
||||
- [x] set a unique `clanName`.
|
||||
- [ ] set `clanIcon` (optional)
|
||||
- [ ] Set `machineIcon` per machine (optional)
|
||||
|
||||
These icons will be used by our future GUI.
|
||||
=== "**buildClan**"
|
||||
|
||||
```nix title="clan-core.lib.buildClan"
|
||||
buildClan {
|
||||
# Set a unique name
|
||||
clanName = "Lobsters";
|
||||
# Optional, a path to an image file
|
||||
clanIcon = ./path/to/file;
|
||||
```nix title="clan-core.lib.buildClan"
|
||||
buildClan {
|
||||
# Set a unique name
|
||||
clanName = "Lobsters";
|
||||
# Should usually point to the directory of flake.nix
|
||||
directory = ./.;
|
||||
|
||||
machines = {
|
||||
jon = {
|
||||
machines = {
|
||||
jon = {
|
||||
# ...
|
||||
};
|
||||
# ...
|
||||
# Optional, a path to an image file
|
||||
clanCore.machineIcon = ./path/to/file;
|
||||
};
|
||||
# ...
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
=== "**flakeParts**"
|
||||
|
||||
!!! info "See [Clan with flake-parts](./flake-parts.md) for help migrating to flake-parts."
|
||||
|
||||
```nix title="clan-core.flakeModules.default"
|
||||
clan = {
|
||||
# Set a unique name
|
||||
clanName = "Lobsters";
|
||||
|
||||
machines = {
|
||||
jon = {
|
||||
# ...
|
||||
};
|
||||
# ...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Machine configuration
|
||||
|
||||
@ -37,12 +51,15 @@ Adding or configuring a new machine requires two simple steps:
|
||||
1. Find the remote disk id by executing:
|
||||
|
||||
```bash title="setup computer"
|
||||
ssh root@<target-computer> lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
ssh root@flash-installer.local lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
```
|
||||
|
||||
!!! Note
|
||||
Replace `flash-installer.local` with the IP address of the machine if you don't have the avahi service running which resolves mDNS local domains.
|
||||
|
||||
Which should show something like:
|
||||
|
||||
```bash
|
||||
```{.shellSession hl_lines="6" .no-copy}
|
||||
NAME ID-LINK FSTYPE SIZE MOUNTPOINT
|
||||
sda usb-ST_16GB_AA6271026J1000000509-0:0 14.9G
|
||||
├─sda1 usb-ST_16GB_AA6271026J1000000509-0:0-part1 1M
|
||||
@ -56,41 +73,115 @@ Adding or configuring a new machine requires two simple steps:
|
||||
|
||||
1. Edit the following fields inside the `flake.nix`
|
||||
|
||||
```nix title="clan-core.lib.buildClan"
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
=== "**buildClan**"
|
||||
|
||||
```nix title="clan-core.lib.buildClan" hl_lines="18 23"
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
imports = [
|
||||
# ...
|
||||
./modules/disko.nix
|
||||
./machines/jon/configuration.nix
|
||||
];
|
||||
# ...
|
||||
|
||||
# Change this to the correct ip-address or hostname
|
||||
# The hostname is the machine name by default
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@<hostname>"
|
||||
# Change this to the correct ip-address or hostname
|
||||
# The hostname is the machine name by default
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"
|
||||
|
||||
# Change this to the ID-LINK of the desired disk shown by 'lsblk'
|
||||
clan.diskLayouts.singleDiskExt4 = {
|
||||
device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
}
|
||||
# Change this to the ID-LINK of the desired disk shown by 'lsblk'
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
}
|
||||
|
||||
# e.g. > cat ~/.ssh/id_ed25519.pub
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"<YOUR SSH_KEY>"
|
||||
];
|
||||
# ...
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
=== "**flakeParts**"
|
||||
|
||||
```nix title="clan-core.flakeModules.default" hl_lines="18 23"
|
||||
clan = {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
imports = [
|
||||
# ...
|
||||
./modules/disko.nix
|
||||
./machines/jon/configuration.nix
|
||||
];
|
||||
# ...
|
||||
|
||||
# Change this to the correct ip-address or hostname
|
||||
# The hostname is the machine name by default
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon"
|
||||
|
||||
# Change this to the ID-LINK of the desired disk shown by 'lsblk'
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/__CHANGE_ME__";
|
||||
}
|
||||
|
||||
# e.g. > cat ~/.ssh/id_ed25519.pub
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"__YOUR_SSH_KEY__"
|
||||
];
|
||||
# ...
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
### Step 2. Detect hardware specific drivers
|
||||
|
||||
1. Generate a `hardware-configuration.nix` for your target computer
|
||||
!!! Info "Replace `__CHANGE_ME__` with the appropriate identifier, such as `nvme-eui.e8238fa6bf530001001b448b4aec2929`"
|
||||
!!! Info "Replace `__YOUR_SSH_KEY__` with your personal key, like `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILoMI0NC5eT9pHlQExrvR5ASV3iW9+BXwhfchq0smXUJ jon@jon-desktop`"
|
||||
|
||||
```bash
|
||||
ssh root@<target-computer> nixos-generate-config --no-filesystems --show-hardware-config > hardware-configuration.nix
|
||||
```
|
||||
These steps will allow you to update your machine later.
|
||||
|
||||
1. Move the generated file to `machines/jon/hardware-configuration.nix`.
|
||||
### Step 2: Detect Drivers
|
||||
|
||||
### Initialize the facts
|
||||
Generate the `hardware-configuration.nix` file for your machine by executing the following command:
|
||||
|
||||
!!! Info
|
||||
**All facts are automatically initialized.**
|
||||
```bash
|
||||
ssh root@flash-installer.local nixos-generate-config --no-filesystems --show-hardware-config > machines/jon/hardware-configuration.nix
|
||||
```
|
||||
|
||||
If you need additional help see our [facts chapter](./secrets.md)
|
||||
This command connects to `flash-installer.local` as `root`, runs `nixos-generate-config` to detect hardware configurations (excluding filesystems), and writes them to `machines/jon/hardware-configuration.nix`.
|
||||
|
||||
### Step 3: Custom Disk Formatting
|
||||
|
||||
In `./modules/disko.nix`, a simple `ext4` disk partitioning scheme is defined for the Disko module. For more complex disk partitioning setups, refer to the [Disko examples](https://github.com/nix-community/disko/tree/master/example).
|
||||
|
||||
### Step 4: Custom Configuration
|
||||
|
||||
Modify `./machines/jon/configuration.nix` to personalize the system settings according to your requirements.
|
||||
|
||||
### Step 5: Check Configuration
|
||||
|
||||
Validate your configuration by running:
|
||||
|
||||
```bash
|
||||
nix flake check
|
||||
```
|
||||
|
||||
This command helps ensure that your system configuration is correct and free from errors.
|
||||
|
||||
!!! Note
|
||||
|
||||
Integrate this step into your [Continuous Integration](https://en.wikipedia.org/wiki/Continuous_integration) workflow to ensure that only valid Nix configurations are merged into your codebase. This practice helps maintain system stability and reduces integration issues.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Secrets & Facts](secrets.md): Setting up secrets with nix-sops
|
||||
|
||||
---
|
||||
|
231
docs/site/getting-started/deploy.md
Normal file
231
docs/site/getting-started/deploy.md
Normal file
@ -0,0 +1,231 @@
|
||||
# Deploy Machine
|
||||
|
||||
Integrating a new machine into your Clan environment is an easy yet flexible process, allowing for a straight forward management of multiple NixOS configurations.
|
||||
|
||||
We'll walk you through adding a new computer to your Clan.
|
||||
|
||||
## Installing a New Machine
|
||||
|
||||
Clan CLI, in conjunction with [nixos-anywhere](https://github.com/nix-community/nixos-anywhere), provides a seamless method for installing NixOS on various machines.
|
||||
|
||||
This process involves preparing a suitable hardware and disk partitioning configuration and ensuring the target machine is accessible via SSH.
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
=== "**Physical Hardware**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
- [x] **USB Flash Drive**: See [Clan Installer](installer.md)
|
||||
|
||||
!!! Steps
|
||||
|
||||
1. Create a NixOS installer image and transfer it to a bootable USB drive as described in the [installer](./installer.md).
|
||||
|
||||
2. Boot the target machine and connect it to a network that makes it reachable from your setup computer.
|
||||
|
||||
=== "**Remote Machines**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
|
||||
!!! Steps
|
||||
|
||||
- Any cloud machine if it is reachable via SSH and supports `kexec`.
|
||||
|
||||
|
||||
### Step 1. Deploy the machine
|
||||
|
||||
**Finally deployment time!** Use the following command to build and deploy the image via SSH onto your machine.
|
||||
|
||||
|
||||
=== "**Image Installer**"
|
||||
|
||||
This method makes use of the image installers of [nixos-images](https://github.com/nix-community/nixos-images).
|
||||
See how to prepare the installer for use [here](./installer.md).
|
||||
|
||||
The installer will randomly generate a password and local addresses on boot, then run ssh with these preconfigured.
|
||||
The installer shows it's deployment relevant information in two formats, a text form, as well as a QR code.
|
||||
|
||||
|
||||
This is an example of the booted installer.
|
||||
|
||||
```{ .bash .annotate .no-copy .nohighlight}
|
||||
┌─────────────────────────────────────────────────────────────────────────────────────┐
|
||||
│ ┌───────────────────────────┐ │
|
||||
│ │███████████████████████████│ # This is the QR Code (1) │
|
||||
│ │██ ▄▄▄▄▄ █▀▄█▀█▀▄█ ▄▄▄▄▄ ██│ │
|
||||
│ │██ █ █ █▀▄▄▄█ ▀█ █ █ ██│ │
|
||||
│ │██ █▄▄▄█ █▀▄ ▀▄▄▄█ █▄▄▄█ ██│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▀ ▀▄▀▄█▄▄▄▄▄▄▄██│ │
|
||||
│ │███▀▀▀ █▄▄█ ▀▄ ▄▀▄█ ███│ │
|
||||
│ │██▄██▄▄█▄▄▀▀██▄▀ ▄▄▄ ▄▀█▀██│ │
|
||||
│ │██ ▄▄▄▄▄ █▄▄▄▄ █ █▄█ █▀ ███│ │
|
||||
│ │██ █ █ █ █ █ ▄▄▄ ▄▀▀ ██│ │
|
||||
│ │██ █▄▄▄█ █ ▄ ▄ ▄ ▀█ ▄███│ │
|
||||
│ │██▄▄▄▄▄▄▄█▄▄▄▄▄▄█▄▄▄▄▄█▄███│ │
|
||||
│ │███████████████████████████│ │
|
||||
│ └───────────────────────────┘ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │Root password: cheesy-capital-unwell # password (2) │ │
|
||||
│ │Local network addresses: │ │
|
||||
│ │enp1s0 UP 192.168.178.169/24 metric 1024 fe80::21e:6ff:fe45:3c92/64 │ │
|
||||
│ │enp2s0 DOWN │ │
|
||||
│ │wlan0 DOWN # connect to wlan (3) │ │
|
||||
│ │Onion address: 6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion │ │
|
||||
│ │Multicast DNS: nixos-installer.local │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────────────────┘ │
|
||||
│ Press 'Ctrl-C' for console access │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
1. This is not an actual QR code, because it is displayed rather poorly on text sites.
|
||||
This would be the actual content of this specific QR code prettified:
|
||||
```json
|
||||
{
|
||||
"pass": "cheesy-capital-unwell",
|
||||
"tor": "6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion",
|
||||
"addrs": [
|
||||
"2001:9e8:347:ca00:21e:6ff:fe45:3c92"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
To generate the actual QR code, that would be displayed use:
|
||||
```shellSession
|
||||
echo '{"pass":"cheesy-capital-unwell","tor":"6evxy5yhzytwpnhc2vpscrbti3iktxdhpnf6yim6bbs25p4v6beemzyd.onion","addrs":["2001:9e8:347:ca00:21e:6ff:fe45:3c92"]}' | nix run nixpkgs#qrencode -- -s 2 -m 2 -t utf8
|
||||
```
|
||||
2. The root password for the installer medium.
|
||||
This password is autogenerated and meant to be easily typeable.
|
||||
3. See how to connect the installer medium to wlan [here](./installer.md#optional-connect-to-wifi).
|
||||
4. :man_raising_hand: I'm a code annotation! I can contain `code`, __formatted
|
||||
text__, images, ... basically anything that can be written in Markdown.
|
||||
|
||||
!!!tip
|
||||
For easy sharing of deployment information via QR code, we highly recommend using [KDE Connect](https://apps.kde.org/de/kdeconnect/).
|
||||
|
||||
There are two ways to deploy your machine:
|
||||
|
||||
1. **SSH with Password Authentication**
|
||||
Run the following command to install using SSH:
|
||||
```bash
|
||||
clan machines install [MACHINE] flash-installer.local
|
||||
```
|
||||
|
||||
2. **Scanning a QR Code for Installation Details**
|
||||
You can input the information by following one of these methods:
|
||||
- **Using a JSON String or File Path:**
|
||||
Provide the path to a JSON string or input the string directly:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --json [JSON]
|
||||
```
|
||||
- **Using an Image Containing the QR Code:**
|
||||
Provide the path to an image file containing the relevant QR code:
|
||||
```terminal
|
||||
clan machines install [MACHINE] --png [PATH]
|
||||
```
|
||||
|
||||
=== "**SSH access**"
|
||||
|
||||
Replace `<target_host>` with the **target computers' ip address**:
|
||||
|
||||
```bash
|
||||
clan machines install [MACHINE] <target_host>
|
||||
```
|
||||
|
||||
|
||||
If you are using our template `[MACHINE]` would be `jon`
|
||||
|
||||
|
||||
!!! success
|
||||
Your machine is all set up. 🎉 🚀
|
||||
|
||||
|
||||
## Update Your Machines
|
||||
|
||||
Clan CLI enables you to remotely update your machines over SSH. This requires setting up a target address for each target machine.
|
||||
|
||||
### Setting the Target Host
|
||||
|
||||
Replace `root@jon` with the actual hostname or IP address of your target machine:
|
||||
```{.nix hl_lines="9" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
# "jon" will be the hostname of the machine
|
||||
"jon" = {
|
||||
# Set this for clan commands use ssh i.e. `clan machines update`
|
||||
# If you change the hostname, you need to update this line to root@<new-hostname>
|
||||
# This only works however if you have avahi running on your admin machine else use IP
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
!!! warning
|
||||
The use of `root@` in the target address implies SSH access as the `root` user.
|
||||
Ensure that the root login is secured and only used when necessary.
|
||||
|
||||
### Updating Machine Configurations
|
||||
|
||||
Execute the following command to update the specified machine:
|
||||
|
||||
```bash
|
||||
clan machines update jon
|
||||
```
|
||||
|
||||
You can also update all configured machines simultaneously by omitting the machine name:
|
||||
|
||||
```bash
|
||||
clan machines update
|
||||
```
|
||||
|
||||
### Setting a Build Host
|
||||
|
||||
If the machine does not have enough resources to run the NixOS evaluation or build itself,
|
||||
it is also possible to specify a build host instead.
|
||||
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
|
||||
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
clan.networking.buildHost = "root@<host_or_ip>";
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
### Excluding a machine from `clan machine update`
|
||||
|
||||
To exclude machines from being updated when running `clan machines update` without any machines specified,
|
||||
one can set the `clan.deployment.requireExplicitUpdate` option to true:
|
||||
|
||||
```{.nix hl_lines="5" .no-copy}
|
||||
buildClan {
|
||||
# ...
|
||||
machines = {
|
||||
"jon" = {
|
||||
clan.deployment.requireExplicitUpdate = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
This is useful for machines that are not always online or are not part of the regular update cycle.
|
||||
|
||||
---
|
||||
|
||||
## What's next ?
|
||||
|
||||
- [**Mesh VPN**](./mesh-vpn.md): Configuring a secure mesh network.
|
||||
|
||||
---
|
||||
|
@ -35,6 +35,7 @@ After updating your flake inputs, the next step is to import the `clan-core` fla
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } (
|
||||
{
|
||||
#
|
||||
imports = [
|
||||
inputs.clan-core.flakeModules.default
|
||||
];
|
||||
@ -49,45 +50,48 @@ Configure your clan settings and define machine configurations.
|
||||
Below is a guide on how to structure this in your flake.nix:
|
||||
|
||||
```nix
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } (
|
||||
{
|
||||
imports = [
|
||||
inputs.clan-core.flakeModules.default
|
||||
];
|
||||
clan = {
|
||||
## Clan wide settings. (Required)
|
||||
clanName = "__CHANGE_ME__"; # Ensure to choose a unique name.
|
||||
directory = self; # Point this to the repository root.
|
||||
outputs = inputs@{ flake-parts, clan-core, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } ({self, pkgs, ...}: {
|
||||
# We define our own systems below. you can still use this to add system specific outputs to your flake.
|
||||
# See: https://flake.parts/getting-started
|
||||
systems = [];
|
||||
|
||||
specialArgs = { }; # Add arguments to every nix import in here
|
||||
# import clan-core modules
|
||||
imports = [
|
||||
clan-core.flakeModules.default
|
||||
];
|
||||
# Define your clan
|
||||
clan = {
|
||||
# Clan wide settings. (Required)
|
||||
clanName = ""; # Ensure to choose a unique name.
|
||||
|
||||
machines = {
|
||||
jons-desktop = {
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
imports = [
|
||||
clan-core.clanModules.sshd # Add openssh server for Clan management
|
||||
./configuration.nix
|
||||
];
|
||||
machines = {
|
||||
jon = {
|
||||
imports = [
|
||||
./machines/jon/configuration.nix
|
||||
./modules/disko.nix
|
||||
# ... more modules
|
||||
];
|
||||
nixpkgs.hostPlatform = "x86_64-linux";
|
||||
|
||||
# Set this for clan commands use ssh i.e. `clan machines update`
|
||||
clan.networking.targetHost = pkgs.lib.mkDefault "root@jon";
|
||||
|
||||
# remote> lsblk --output NAME,ID-LINK,FSTYPE,SIZE,MOUNTPOINT
|
||||
disko.devices.disk.main = {
|
||||
device = "/dev/disk/by-id/nvme-eui.e8238fa6bf530001001b448b4aec2929";
|
||||
};
|
||||
|
||||
# There needs to be exactly one controller per clan
|
||||
clan.networking.zerotier.controller.enable = true;
|
||||
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
For detailed information about configuring `flake-parts` and the available options within Clan,
|
||||
refer to the Clan module documentation located [here](https://git.clan.lol/clan/clan-core/src/branch/main/flakeModules/clan.nix).
|
||||
|
||||
### Next Steps
|
||||
|
||||
With your flake created, explore how to add new machines by reviewing the documentation provided [here](machines.md).
|
||||
|
||||
---
|
||||
|
||||
## TODO
|
||||
|
||||
* How do I use Clan machines install to setup my current machine?
|
||||
* I probably need the clan-core sshd module for that?
|
||||
* We need to tell them that configuration.nix of a machine NEEDS to be under the directory CLAN_ROOT/machines/<machine-name> I think?
|
||||
|
@ -1,57 +1,91 @@
|
||||
# Installer
|
||||
|
||||
We offer a dedicated installer to assist remote installations.
|
||||
Our installer image simplifies the process of performing remote installations.
|
||||
|
||||
In this tutorial we will guide you through building and flashing it to a bootable USB drive.
|
||||
Follow our step-by-step guide to create and transfer this image onto a bootable USB drive.
|
||||
|
||||
## Step 0. Prerequisites
|
||||
!!! info
|
||||
If you already have a NixOS machine you can ssh into (in the cloud for example) you can skip this chapter and go directly to [Configure Machines](configure.md).
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
- [x] A free USB Drive with at least 1.5GB (All data on it will be lost)
|
||||
- [x] Linux/NixOS Machine with Internet
|
||||
|
||||
## Step 1. Identify the USB Flash Drive
|
||||
### Step 1. Identify the USB Flash Drive
|
||||
|
||||
1. Insert your USB flash drive into your computer.
|
||||
|
||||
1. Identify your flash drive with `lsblk`:
|
||||
2. Identify your flash drive with `lsblk`:
|
||||
|
||||
```bash
|
||||
$ lsblk
|
||||
```
|
||||
```shellSession
|
||||
lsblk
|
||||
```
|
||||
|
||||
```{.console, .no-copy}
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
sdb 8:0 1 117,2G 0 disk
|
||||
└─sdb1 8:1 1 117,2G 0 part /run/media/qubasa/INTENSO
|
||||
nvme0n1 259:0 0 1,8T 0 disk
|
||||
├─nvme0n1p1 259:1 0 512M 0 part /boot
|
||||
└─nvme0n1p2 259:2 0 1,8T 0 part
|
||||
└─luks-f7600028-9d83-4967-84bc-dd2f498bc486 254:0 0 1,8T 0 crypt /nix/store /
|
||||
```
|
||||
```{.shellSession hl_lines="2" .no-copy}
|
||||
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
|
||||
sdb 8:0 1 117,2G 0 disk
|
||||
└─sdb1 8:1 1 117,2G 0 part /run/media/qubasa/INTENSO
|
||||
nvme0n1 259:0 0 1,8T 0 disk
|
||||
├─nvme0n1p1 259:1 0 512M 0 part /boot
|
||||
└─nvme0n1p2 259:2 0 1,8T 0 part
|
||||
└─luks-f7600028-9d83-4967-84bc-dd2f498bc486 254:0 0 1,8T 0 crypt /nix/store
|
||||
```
|
||||
|
||||
In this case it is `sdb`.
|
||||
!!! Info "In this case the USB device is `sdb`"
|
||||
|
||||
3. Ensure all partitions on the drive are unmounted. Replace `sdb1` in the command below with your device identifier (like `sdc1`, etc.):
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
sudo umount /dev/sdb1
|
||||
```
|
||||
=== "**Linux OS**"
|
||||
### Step 2. Flash Custom Installer
|
||||
|
||||
### Step 2. Build the Installer
|
||||
Using clan flash enables the inclusion of ssh public keys.
|
||||
It also allows to set language and keymap currently in the installer image.
|
||||
|
||||
```bash
|
||||
nix build git+https://git.clan.lol/clan/clan-core.git#install-iso
|
||||
```
|
||||
```bash
|
||||
clan flash --flake git+https://git.clan.lol/clan/clan-core \
|
||||
--ssh-pubkey $HOME/.ssh/id_ed25519.pub \
|
||||
--keymap en \
|
||||
--language en \
|
||||
--disk main /dev/sd<X> \
|
||||
flash-installer
|
||||
```
|
||||
|
||||
### Step 3. Flash the Installer to the USB Drive
|
||||
The `--ssh-pubkey`, `--language` and `--keymap` are optional.
|
||||
Replace `$HOME/.ssh/id_ed25519.pub` with a path to your SSH public key.
|
||||
If you do not have an ssh key yet, you can generate one with `ssh-keygen -t ed25519` command.
|
||||
|
||||
Use the `dd` utility to write the NixOS installer image to your USB drive:
|
||||
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
|
||||
|
||||
```bash
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./result of=/dev/sd<X>
|
||||
```
|
||||
The `clan flash` utility will erase the disk. Make sure to specify the correct device
|
||||
|
||||
If your USB device is `sdb` use `of=/dev/sdb`.
|
||||
|
||||
|
||||
=== "**Other OS**"
|
||||
### Step 2. Download Generic Installer
|
||||
|
||||
```shellSession
|
||||
wget https://github.com/nix-community/nixos-images/releases/download/nixos-unstable/nixos-installer-x86_64-linux.iso
|
||||
```
|
||||
|
||||
### Step 3. Flash the Installer to the USB Drive
|
||||
|
||||
!!! Danger "Specifying the wrong device can lead to unrecoverable data loss."
|
||||
|
||||
The `dd` utility will erase the disk. Make sure to specify the correct device (`of=...`)
|
||||
|
||||
For example if the USB device is `sdb` use `of=/dev/sdb`.
|
||||
|
||||
|
||||
|
||||
Use the `dd` utility to write the NixOS installer image to your USB drive:
|
||||
|
||||
```shellSession
|
||||
sudo dd bs=4M conv=fsync oflag=direct status=progress if=./nixos-installer-x86_64-linux.iso of=/dev/sd<X>
|
||||
```
|
||||
|
||||
### Step 4. Boot and Connect to your network
|
||||
|
||||
@ -73,8 +107,6 @@ After writing the installer to the USB drive, use it to boot the target machine.
|
||||
- **Apple**: Option (Alt) Key (Boot Menu for Mac)
|
||||
- If your hardware was not listed read the manufacturers instructions how to enter the boot Menu/BIOS Setup.
|
||||
|
||||
|
||||
|
||||
**During Boot**
|
||||
|
||||
Select `NixOS` to boot into the clan installer.
|
||||
@ -83,23 +115,12 @@ Select `NixOS` to boot into the clan installer.
|
||||
|
||||
For deploying your configuration the machine needs to be connected via LAN (recommended).
|
||||
|
||||
For connecting via Wifi, please consult the guide below.
|
||||
|
||||
---
|
||||
|
||||
### Whats next?
|
||||
|
||||
- [Configure Machines](configure.md): Customise machine configuration
|
||||
- [Deploying](machines.md): Deploying a Machine configuration
|
||||
- [WiFi](#optional-connect-to-wifi): Guide for connecting to Wifi.
|
||||
|
||||
---
|
||||
|
||||
### (Optional) Connect to Wifi
|
||||
## (Optional) Connect to Wifi
|
||||
|
||||
If you don't have access via LAN the Installer offers support for connecting via Wifi.
|
||||
|
||||
```bash
|
||||
```shellSession
|
||||
iwctl
|
||||
```
|
||||
|
||||
@ -111,10 +132,11 @@ This will enter `iwd`
|
||||
|
||||
Now run the following command to connect to your Wifi:
|
||||
|
||||
```bash
|
||||
```{.shellSession .no-copy}
|
||||
# Identify your network device.
|
||||
device list
|
||||
# Replace 'wlan0' with your device name
|
||||
|
||||
# Replace 'wlan0' with your wireless device name
|
||||
# Find your Wifi SSID.
|
||||
station wlan0 scan
|
||||
station wlan0 get-networks
|
||||
@ -135,6 +157,17 @@ Connected network FRITZ!Box (Your router device)
|
||||
IPv4 address 192.168.188.50 (Your new local ip)
|
||||
```
|
||||
|
||||
Press `ctrl-d` to exit `IWD`.
|
||||
Press ++ctrl+d++ to exit `IWD`.
|
||||
|
||||
Press `ctrl-d` **again** to update the displayed QR code and connection information.
|
||||
!!! Important
|
||||
Press ++ctrl+d++ **again** to update the displayed QR code and connection information.
|
||||
|
||||
You're all set up
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Configure Machines](configure.md): Customize machine configuration
|
||||
|
||||
---
|
||||
|
@ -1,127 +0,0 @@
|
||||
# Deploy Machine
|
||||
|
||||
Integrating a new machine into your Clan environment is an easy yet flexible process, allowing for a straight forward management of multiple NixOS configurations.
|
||||
|
||||
We'll walk you through adding a new computer to your Clan.
|
||||
|
||||
## Installing a New Machine
|
||||
|
||||
Clan CLI, in conjunction with [nixos-anywhere](https://github.com/nix-community/nixos-anywhere), provides a seamless method for installing NixOS on various machines.
|
||||
|
||||
This process involves preparing a suitable hardware and disk partitioning configuration and ensuring the target machine is accessible via SSH.
|
||||
|
||||
### Step 0. Prerequisites
|
||||
|
||||
=== "**Physical Hardware**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
- [x] **USB Flash Drive**: See [Clan Installer](installer.md)
|
||||
|
||||
!!! Steps
|
||||
|
||||
1. Create a NixOS installer image and transfer it to a bootable USB drive as described in the [installer](./installer.md).
|
||||
|
||||
2. Boot the target machine and connect it to a network that makes it reachable from your setup computer.
|
||||
|
||||
=== "**Cloud Machines**"
|
||||
|
||||
- [x] **Two Computers**: You need one computer that you're getting ready (we'll call this the Target Computer) and another one to set it up from (we'll call this the Setup Computer). Make sure both can talk to each other over the network using SSH.
|
||||
- [x] **Machine configuration**: See our basic [configuration guide](./configure.md)
|
||||
- [x] **Initialized secrets**: See [secrets](secrets.md) for how to initialize your secrets.
|
||||
|
||||
!!! Steps
|
||||
|
||||
- Any cloud machine if it is reachable via SSH and supports `kexec`.
|
||||
|
||||
Confirm the machine is reachable via SSH from your setup computer.
|
||||
|
||||
```bash
|
||||
ssh root@<your_target_machine_ip>
|
||||
```
|
||||
|
||||
### Step 1. Deploy the machine
|
||||
|
||||
**Finally deployment time!** Use the following command to build and deploy the image via SSH onto your machine.
|
||||
|
||||
Replace `<target_host>` with the **target computers' ip address**:
|
||||
|
||||
```bash
|
||||
clan machines install my-machine <target_host>
|
||||
```
|
||||
|
||||
> Note: This may take a while for building and for the file transfer.
|
||||
|
||||
!!! success
|
||||
|
||||
Your machine is all set up. 🎉 🚀
|
||||
|
||||
---
|
||||
|
||||
## What's next ?
|
||||
|
||||
- [**Update a Machine**](#update-your-machines): Learn how to update an existing machine?
|
||||
|
||||
Coming Soon:
|
||||
|
||||
- **Join Your Machines in a Private Network:**: Stay tuned for steps on linking all your machines into a secure mesh network with Clan.
|
||||
|
||||
---
|
||||
|
||||
## Update Your Machines
|
||||
|
||||
Clan CLI enables you to remotely update your machines over SSH. This requires setting up a target address for each target machine.
|
||||
|
||||
### Setting the Target Host
|
||||
|
||||
Replace `host_or_ip` with the actual hostname or IP address of your target machine:
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.networking.targetHost root@host_or_ip
|
||||
```
|
||||
|
||||
> Note: The use of `root@` in the target address implies SSH access as the `root` user.
|
||||
> Ensure that the root login is secured and only used when necessary.
|
||||
|
||||
### Updating Machine Configurations
|
||||
|
||||
Execute the following command to update the specified machine:
|
||||
|
||||
```bash
|
||||
clan machines update my-machine
|
||||
```
|
||||
|
||||
You can also update all configured machines simultaneously by omitting the machine name:
|
||||
|
||||
```bash
|
||||
clan machines update
|
||||
```
|
||||
|
||||
### Setting a Build Host
|
||||
|
||||
If the machine does not have enough resources to run the NixOS evaluation or build itself,
|
||||
it is also possible to specify a build host instead.
|
||||
During an update, the cli will ssh into the build host and run `nixos-rebuild` from there.
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.networking.buildHost root@host_or_ip
|
||||
```
|
||||
|
||||
### Excluding a machine from `clan machine update`
|
||||
|
||||
To exclude machines from being updated when running `clan machines update` without any machines specified,
|
||||
one can set the `clan.deployment.requireExplicitUpdate` option to true:
|
||||
|
||||
```bash
|
||||
clan config --machine my-machine clan.deployment.requireExplicitUpdate true
|
||||
```
|
||||
|
||||
This is useful for machines that are not always online or are not part of the regular update cycle.
|
||||
|
||||
---
|
||||
|
||||
# TODO:
|
||||
* TODO: How to join others people zerotier
|
||||
* `services.zerotier.joinNetworks = [ "network-id" ]`
|
||||
* Controller needs to approve over webinterface or cli
|
97
docs/site/getting-started/mesh-vpn.md
Normal file
97
docs/site/getting-started/mesh-vpn.md
Normal file
@ -0,0 +1,97 @@
|
||||
# Mesh VPN
|
||||
|
||||
This guide provides detailed instructions for configuring
|
||||
[ZeroTier VPN](https://zerotier.com) within Clan. Follow the
|
||||
outlined steps to set up a machine as a VPN controller (`<CONTROLLER>`) and to
|
||||
include a new machine into the VPN.
|
||||
|
||||
## Concept
|
||||
|
||||
By default all machines within one clan are connected via a chosen network technology.
|
||||
|
||||
```{.no-copy}
|
||||
Clan
|
||||
Node A
|
||||
<-> (zerotier / mycelium / ...)
|
||||
Node B
|
||||
```
|
||||
|
||||
If you select multiple network technologies at the same time. e.g. (zerotier + yggdrassil)
|
||||
You must choose one of them as primary network and the machines are always connected via the primary network.
|
||||
|
||||
## 1. Set-Up the VPN Controller
|
||||
|
||||
The VPN controller is initially essential for providing configuration to new
|
||||
peers. Once addresses are allocated, the controller's continuous operation is not essential.
|
||||
|
||||
1. **Designate a Machine**: Label a machine as the VPN controller in the clan,
|
||||
referred to as `<CONTROLLER>` henceforth in this guide.
|
||||
2. **Add Configuration**: Input the following configuration to the NixOS
|
||||
configuration of the controller machine:
|
||||
```nix
|
||||
clan.networking.zerotier.controller = {
|
||||
enable = true;
|
||||
public = true;
|
||||
};
|
||||
```
|
||||
3. **Update the Controller Machine**: Execute the following:
|
||||
```bash
|
||||
clan machines update <CONTROLLER>
|
||||
```
|
||||
Your machine is now operational as the VPN controller.
|
||||
|
||||
## 2. Add Machines to the VPN
|
||||
|
||||
To introduce a new machine to the VPN, adhere to the following steps:
|
||||
|
||||
1. **Update Configuration**: On the new machine, incorporate the following to its
|
||||
configuration, substituting `<CONTROLLER>` with the controller machine name:
|
||||
```nix
|
||||
{ config, ... }: {
|
||||
clan.networking.zerotier.networkId = builtins.readFile (config.clanCore.clanDir + "/machines/<CONTROLLER>/facts/zerotier-network-id");
|
||||
}
|
||||
```
|
||||
1. **Update the New Machine**: Execute:
|
||||
```bash
|
||||
$ clan machines update <NEW_MACHINE>
|
||||
```
|
||||
Replace `<NEW_MACHINE>` with the designated new machine name.
|
||||
|
||||
!!! Note "For Private Networks"
|
||||
1. **Retrieve the ZeroTier ID**: On the `new_machine`, execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
Example Output:
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 OFFLINE
|
||||
```
|
||||
, where `d2c71971db` is the ZeroTier ID.
|
||||
2. **Authorize the New Machine on the Controller**: On the controller machine,
|
||||
execute:
|
||||
```bash
|
||||
$ sudo zerotier-members allow <ID>
|
||||
```
|
||||
Substitute `<ID>` with the ZeroTier ID obtained previously.
|
||||
|
||||
2. **Verify Connection**: On the `new_machine`, re-execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
The status should now be "ONLINE":
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 ONLINE
|
||||
```
|
||||
|
||||
!!! success "Congratulations!"
|
||||
The new machine is now part of the VPN, and the ZeroTier
|
||||
configuration on NixOS within the Clan project is complete.
|
||||
|
||||
## Further
|
||||
|
||||
Currently you can only use **Zerotier** as networking technology because this is the first network stack we aim to support.
|
||||
In the future we plan to add additional network technologies like tinc, head/tailscale, yggdrassil and mycelium.
|
||||
|
||||
We chose zerotier because in our tests it was a straight forwards solution to bootstrap.
|
||||
It allows you to selfhost a controller and the controller doesn't need to be globally reachable.
|
||||
Which made it a good fit for starting the project.
|
@ -1,76 +0,0 @@
|
||||
# Overlay Networks
|
||||
|
||||
This guide provides detailed instructions for configuring
|
||||
[ZeroTier VPN](https://zerotier.com) within Clan. Follow the
|
||||
outlined steps to set up a machine as a VPN controller (`<CONTROLLER>`) and to
|
||||
include a new machine into the VPN.
|
||||
|
||||
## 1. Setting Up the VPN Controller
|
||||
|
||||
The VPN controller is initially essential for providing configuration to new
|
||||
peers. Once addresses are allocated, the controller's continuous operation is not essential.
|
||||
|
||||
### Instructions:
|
||||
|
||||
1. **Designate a Machine**: Label a machine as the VPN controller in the clan,
|
||||
referred to as `<CONTROLLER>` henceforth in this guide.
|
||||
1. **Add Configuration**: Input the following configuration to the NixOS
|
||||
configuration of the controller machine:
|
||||
```nix
|
||||
clan.networking.zerotier.controller = {
|
||||
enable = true;
|
||||
public = true;
|
||||
};
|
||||
```
|
||||
1. **Update the Controller Machine**: Execute the following:
|
||||
```bash
|
||||
$ clan machines update <CONTROLLER>
|
||||
```
|
||||
Your machine is now operational as the VPN controller.
|
||||
|
||||
## 2. Integrating a New Machine to the VPN
|
||||
|
||||
To introduce a new machine to the VPN, adhere to the following steps:
|
||||
|
||||
### Instructions:
|
||||
|
||||
1. **Update Configuration**: On the new machine, incorporate the following to its
|
||||
configuration, substituting `<CONTROLLER>` with the controller machine name:
|
||||
```nix
|
||||
{ config, ... }: {
|
||||
clan.networking.zerotier.networkId = builtins.readFile (config.clanCore.clanDir + "/machines/<CONTROLLER>/facts/zerotier-network-id");
|
||||
}
|
||||
```
|
||||
1. **Update the New Machine**: Execute:
|
||||
```bash
|
||||
$ clan machines update <NEW_MACHINE>
|
||||
```
|
||||
Replace `<NEW_MACHINE>` with the designated new machine name.
|
||||
1. **Retrieve the ZeroTier ID**: On the `new_machine`, execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
Example Output:
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 OFFLINE
|
||||
```
|
||||
, where `d2c71971db` is the ZeroTier ID.
|
||||
1. **Authorize the New Machine on the Controller**: On the controller machine,
|
||||
execute:
|
||||
```bash
|
||||
$ sudo zerotier-members allow <ID>
|
||||
```
|
||||
Substitute `<ID>` with the ZeroTier ID obtained previously.
|
||||
1. **Verify Connection**: On the `new_machine`, re-execute:
|
||||
```bash
|
||||
$ sudo zerotier-cli info
|
||||
```
|
||||
The status should now be "ONLINE":
|
||||
```{.console, .no-copy}
|
||||
200 info d2c71971db 1.12.1 ONLINE
|
||||
```
|
||||
|
||||
!!! success "Congratulations!"
|
||||
The new machine is now part of the VPN, and the ZeroTier
|
||||
configuration on NixOS within the Clan project is complete.
|
||||
|
@ -4,13 +4,15 @@ Clan enables encryption of secrets (such as passwords & keys) ensuring security
|
||||
|
||||
Clan utilizes the [sops](https://github.com/getsops/sops) format and integrates with [sops-nix](https://github.com/Mic92/sops-nix) on NixOS machines.
|
||||
|
||||
This documentation will guide you through managing secrets with the Clan CLI
|
||||
This guide will walk you through:
|
||||
|
||||
## 1. Initializing Secrets
|
||||
- **Creating a Keypair for Your User**: Learn how to generate a keypair for $USER to securely control all secrets.
|
||||
- **Creating Your First Secret**: Step-by-step instructions on creating your initial secret.
|
||||
- **Assigning Machine Access to the Secret**: Understand how to grant a machine access to the newly created secret.
|
||||
|
||||
### Create Your Master Keypair
|
||||
## Create Your Admin Keypair
|
||||
|
||||
To get started, you'll need to create **Your master keypair**.
|
||||
To get started, you'll need to create **Your admin keypair**.
|
||||
|
||||
!!! info
|
||||
Don't worry — if you've already made one before, this step won't change or overwrite it.
|
||||
@ -30,7 +32,7 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
|
||||
|
||||
!!! warning
|
||||
Make sure to keep a safe backup of the private key you've just created.
|
||||
If it's lost, you won't be able to get to your secrets anymore because they all need the master key to be unlocked.
|
||||
If it's lost, you won't be able to get to your secrets anymore because they all need the admin key to be unlocked.
|
||||
|
||||
!!! note
|
||||
It's safe to add any secrets created by the clan CLI and placed in your repository to version control systems like `git`.
|
||||
@ -38,11 +40,10 @@ Also add your age public key to the repository with 'clan secrets users add YOUR
|
||||
### Add Your Public Key
|
||||
|
||||
```bash
|
||||
clan secrets users add <your_username> <your_public_key>
|
||||
clan secrets users add $USER <your_public_key>
|
||||
```
|
||||
|
||||
!!! note
|
||||
Choose the same username as on your Setup/Source Machine that you use to control the deployment with.
|
||||
It's best to choose the same username as on your Setup/Admin Machine that you use to control the deployment with.
|
||||
|
||||
Once run this will create the following files:
|
||||
|
||||
@ -52,112 +53,39 @@ sops/
|
||||
└── <your_username>/
|
||||
└── key.json
|
||||
```
|
||||
If you followed the quickstart tutorial all necessary secrets are initialized at this point.
|
||||
|
||||
## 2. Adding Machine Keys
|
||||
---
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
## Whats next?
|
||||
|
||||
```bash
|
||||
$ clan secrets machines list
|
||||
```
|
||||
- [Deployment](deploy.md): How to remotely deploy your machine
|
||||
|
||||
For existing machines, add their keys:
|
||||
---
|
||||
|
||||
```bash
|
||||
$ clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
## More on Secrets
|
||||
|
||||
### Advanced
|
||||
If you want to know more about how to save and share passwords in your clan read further!
|
||||
|
||||
To fetch an age key from an SSH host key:
|
||||
### Adding a Secret
|
||||
|
||||
```bash
|
||||
$ ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
## 3. Assigning Access
|
||||
|
||||
By default, secrets are encrypted for your key. To specify which users and machines can access a secret:
|
||||
|
||||
```bash
|
||||
$ clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
|
||||
You can add machines/users to existing secrets without modifying the secret:
|
||||
|
||||
```bash
|
||||
$ clan secrets machines add-secret <machine_name> <secret_name>
|
||||
```
|
||||
|
||||
## 4. Adding Secrets
|
||||
|
||||
```bash
|
||||
$ clan secrets set mysecret
|
||||
```shellSession
|
||||
clan secrets set mysecret
|
||||
Paste your secret:
|
||||
```
|
||||
|
||||
!!! note
|
||||
As you type your secret won't be displayed. Press Enter to save the secret.
|
||||
|
||||
## 5. Retrieving Stored Secrets
|
||||
### Retrieving a Stored Secret
|
||||
|
||||
```bash
|
||||
$ clan secrets get mysecret
|
||||
clan secrets get mysecret
|
||||
```
|
||||
|
||||
### List all Secrets
|
||||
|
||||
```bash
|
||||
$ clan secrets list
|
||||
clan secrets list
|
||||
```
|
||||
|
||||
## 6. Groups
|
||||
|
||||
Clan CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
All users within a group inherit access to all secrets of the group.
|
||||
|
||||
This feature eases the process of handling permissions for multiple users.
|
||||
|
||||
Here's how to get started:
|
||||
|
||||
1. **Creating Groups**:
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups add admins <username>
|
||||
```
|
||||
|
||||
2. **Listing Groups**:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups list
|
||||
```
|
||||
|
||||
3. **Assigning Secrets to Groups**:
|
||||
|
||||
```bash
|
||||
$ clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
## Further
|
||||
|
||||
Secrets in the repository follow this structure:
|
||||
|
||||
```{.console, .no-copy}
|
||||
sops/
|
||||
├── secrets/
|
||||
│ └── <secret_name>/
|
||||
│ ├── secret
|
||||
│ └── users/
|
||||
│ └── <your_username>/
|
||||
```
|
||||
|
||||
The content of the secret is stored encrypted inside the `secret` file under `mysecret`.
|
||||
|
||||
By default, secrets are encrypted with your key to ensure readability.
|
||||
|
||||
### NixOS integration
|
||||
|
||||
A NixOS machine will automatically import all secrets that are encrypted for the
|
||||
@ -176,8 +104,75 @@ In your nixos configuration you can get a path to secrets like this `config.sops
|
||||
}
|
||||
```
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
### Assigning Access
|
||||
|
||||
When using `clan secrets set <secret>` without arguments, secrets are encrypted for the key of the user named like your current $USER.
|
||||
|
||||
To add machines/users to an existing secret use:
|
||||
|
||||
```bash
|
||||
clan secrets machines add-secret <machine_name> <secret_name>
|
||||
```
|
||||
|
||||
Alternatively specify users and machines while creating a secret:
|
||||
|
||||
```bash
|
||||
clan secrets set --machine <machine1> --machine <machine2> --user <user1> --user <user2> <secret_name>
|
||||
```
|
||||
|
||||
## Advanced
|
||||
|
||||
In this section we go into more advanced secret management topics.
|
||||
|
||||
### Groups
|
||||
|
||||
Clan CLI makes it easy to manage access by allowing you to create groups.
|
||||
|
||||
All users within a group inherit access to all secrets of the group.
|
||||
|
||||
This feature eases the process of handling permissions for multiple users.
|
||||
|
||||
Here's how to get started:
|
||||
|
||||
1. **Creating Groups**:
|
||||
|
||||
Assign users to a new group, e.g., `admins`:
|
||||
|
||||
```bash
|
||||
clan secrets groups add admins <username>
|
||||
```
|
||||
|
||||
2. **Listing Groups**:
|
||||
|
||||
```bash
|
||||
clan secrets groups list
|
||||
```
|
||||
|
||||
3. **Assigning Secrets to Groups**:
|
||||
|
||||
```bash
|
||||
clan secrets groups add-secret <group_name> <secret_name>
|
||||
```
|
||||
|
||||
### Adding Machine Keys
|
||||
|
||||
New machines in Clan come with age keys stored in `./sops/machines/<machine_name>`. To list these machines:
|
||||
|
||||
```bash
|
||||
clan secrets machines list
|
||||
```
|
||||
|
||||
For existing machines, add their keys:
|
||||
|
||||
```bash
|
||||
clan secrets machines add <machine_name> <age_key>
|
||||
```
|
||||
|
||||
To fetch an age key from an SSH host key:
|
||||
|
||||
```bash
|
||||
ssh-keyscan <domain_name> | nix shell nixpkgs#ssh-to-age -c ssh-to-age
|
||||
```
|
||||
|
||||
### Migration: Importing existing sops-based keys / sops-nix
|
||||
|
||||
@ -189,8 +184,141 @@ If you already happened to use sops-nix, you can migrate by using the `clan secr
|
||||
% clan secrets import-sops --prefix matchbox- --group admins --machine matchbox nixos/matchbox/secrets/secrets.yaml
|
||||
```
|
||||
|
||||
This will create secrets for each secret found in `nixos/matchbox/secrets/secrets.yaml` in a ./sops folder of your repository.
|
||||
This will create secrets for each secret found in `nixos/matchbox/secrets/secrets.yaml` in a `./sops` folder of your repository.
|
||||
Each member of the group `admins` in this case will be able to decrypt the secrets with their respective key.
|
||||
|
||||
Since our clan secret module will auto-import secrets that are encrypted for a particular nixos machine,
|
||||
you can now remove `sops.secrets.<secrets> = { };` unless you need to specify more options for the secret like owner/group of the secret file.
|
||||
|
||||
|
||||
## Indepth Explanation
|
||||
|
||||
|
||||
The secrets system conceptually knows two different entities:
|
||||
|
||||
- **Machine**: consumes secrets
|
||||
- **User**: manages access to secrets
|
||||
|
||||
**A Users** Can add or revoke machines' access to secrets.
|
||||
|
||||
**A machine** Can decrypt secrets that where encrypted specifically for that machine.
|
||||
|
||||
!!! Danger
|
||||
**Always make sure at least one _User_ has access to a secret**. Otherwise you could lock yourself out from accessing the secret.
|
||||
|
||||
### Inherited implications
|
||||
|
||||
By default clan uses [sops](https://github.com/getsops/sops) through [sops-nix](https://github.com/Mic92/sops-nix) for managing its secrets which inherits some implications that are important to understand:
|
||||
|
||||
- **Public/Private keys**: Entities are identified via their public keys. Each Entity can use their respective private key to decrypt a secret.
|
||||
- **Public keys are stored**: All Public keys are stored inside the repository
|
||||
- **Secrets are stored Encrypted**: secrets are stored inside the repository encrypted with the respective public keys
|
||||
- **Secrets are deployed encrypted**: Fully encrypted secrets are deployed to machines at deployment time.
|
||||
- **Secrets are decrypted by sops on-demand**: Each machine decrypts its secrets at runtime and stores them at an ephemeral location.
|
||||
- **Machine key-pairs are auto-generated**: When a machine is created **no user-interaction is required** to setup public/private key-pairs.
|
||||
- **secrets are re-encrypted**: In case machines, users or groups are modified secrets get re-encrypted on demand.
|
||||
|
||||
!!! Important
|
||||
After revoking access to a secret you should also change the underlying secret. i.e. change the API key, or the password.
|
||||
|
||||
---
|
||||
|
||||
### Machine and user keys
|
||||
|
||||
The following diagrams illustrates how a user can provide a secret (i.e. a Password).
|
||||
|
||||
- By using the **Clan CLI** a user encrypts the password with both the **User public-key** and the **machine's public-key**
|
||||
|
||||
- The *Machine* can decrypt the password with its private-key on demand.
|
||||
|
||||
- The *User* is able to decrypt the password to make changes to it.
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
|
||||
Person(user, "User", "Someone who manages secrets")
|
||||
ContainerDb(secret, "Secret")
|
||||
Container(machine, "Machine", "A Machine. i.e. Needs the Secret for a given Service." )
|
||||
|
||||
Rel_R(user, secret, "Encrypt", "", "Pubkeys: User, Machine")
|
||||
Rel_L(secret, user, "Decrypt", "", "user privkey")
|
||||
Rel_R(secret, machine, "Decrypt", "", "machine privkey" )
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
|
||||
#### User groups
|
||||
|
||||
Here we illustrate how machine groups work.
|
||||
|
||||
Common use cases:
|
||||
|
||||
- **Shared Management**: Access among multiple users. I.e. a subset of secrets/machines that have two admins
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
|
||||
System_Boundary(c1, "Group") {
|
||||
Person(user1, "User A", "has access")
|
||||
Person(user2, "User B", "has access")
|
||||
}
|
||||
|
||||
ContainerDb(secret, "Secret")
|
||||
Container(machine, "Machine", "A Machine. i.e. Needs the Secret for a given Service." )
|
||||
|
||||
Rel_R(c1, secret, "Encrypt", "", "Pubkeys: User A, User B, Machine")
|
||||
Rel_R(secret, machine, "Decrypt", "", "machine privkey" )
|
||||
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
<!-- TODO: See also [Groups Reference](#groups-reference) -->
|
||||
|
||||
---
|
||||
|
||||
#### Machine groups
|
||||
|
||||
Here we illustrate how machine groups work.
|
||||
|
||||
Common use cases:
|
||||
|
||||
- **Shared secrets**: Among multiple machines such as Wifi passwords
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
!include C4_Container.puml
|
||||
!include C4_Deployment.puml
|
||||
|
||||
Person(user, "User", "Someone who manages secrets")
|
||||
ContainerDb(secret, "Secret")
|
||||
System_Boundary(c1, "Group") {
|
||||
Container(machine1, "Machine A", "Both machines need the same secret" )
|
||||
Container(machine2, "Machine B", "Both machines need the same secret" )
|
||||
}
|
||||
|
||||
Rel_R(user, secret, "Encrypt", "", "Pubkeys: machine A, machine B, User")
|
||||
Rel(secret, c1, "Decrypt", "", "Both machine A or B can decrypt using their private key" )
|
||||
|
||||
|
||||
@enduml
|
||||
```
|
||||
|
||||
<!-- TODO: See also [Groups Reference](#groups-reference) -->
|
||||
|
||||
|
||||
|
||||
See the [readme](https://github.com/Mic92/sops-nix) of sops-nix for more
|
||||
examples.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Whats next?
|
||||
|
||||
- [Deployment](deploy.md): How to remotely deploy your machine
|
||||
|
||||
---
|
||||
|
@ -1,44 +1,31 @@
|
||||
# Getting Started
|
||||
# Setup
|
||||
|
||||
Welcome to your simple guide on starting a new Clan project.
|
||||
|
||||
## What's Inside
|
||||
|
||||
We've put together a straightforward guide to help you out:
|
||||
|
||||
- [**Starting with a New Clan Project**](#starting-with-a-new-clan-project): Create a new Clan from scratch.
|
||||
- [**Integrating Clan using Flake-Parts**](getting-started/flake-parts.md)
|
||||
|
||||
---
|
||||
|
||||
## **Starting with a New Clan Project**
|
||||
|
||||
Create your own clan with these initial steps.
|
||||
Create your own clan with these initial steps and manage a fleet of machines with one single testable git repository!
|
||||
|
||||
### Prerequisites
|
||||
|
||||
#### Linux
|
||||
=== "**Linux**"
|
||||
|
||||
Clan depends on nix installed on your system. Run the following command to install nix.
|
||||
Clan depends on nix installed on your system. Run the following command to install nix.
|
||||
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
```bash
|
||||
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install
|
||||
```
|
||||
|
||||
#### NixOS
|
||||
=== "**NixOS**"
|
||||
|
||||
If you run NixOS the `nix` binary is already installed.
|
||||
If you run NixOS the `nix` binary is already installed.
|
||||
|
||||
You will also need to enable the `flakes` and `nix-commands` experimental features.
|
||||
You will also need to enable the `flakes` and `nix-commands` experimental features.
|
||||
|
||||
```bash
|
||||
# /etc/nix/nix.conf or ~/.config/nix/nix.conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
```bash
|
||||
# /etc/nix/nix.conf or ~/.config/nix/nix.conf
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
#### Other
|
||||
=== "**Other**"
|
||||
|
||||
Clan doesn't offer dedicated support for other operating systems yet.
|
||||
Clan doesn't offer dedicated support for other operating systems yet.
|
||||
|
||||
### Step 1: Add Clan CLI to Your Shell
|
||||
|
||||
@ -48,6 +35,13 @@ Add the Clan CLI into your development workflow:
|
||||
nix shell git+https://git.clan.lol/clan/clan-core#clan-cli
|
||||
```
|
||||
|
||||
You can find reference documentation for the `clan` cli program [here](./reference/cli/index.md).
|
||||
|
||||
Alternatively you can check out the help pages directly:
|
||||
```terminalSession
|
||||
clan --help
|
||||
```
|
||||
|
||||
### Step 2: Initialize Your Project
|
||||
|
||||
Set the foundation of your Clan project by initializing it as follows:
|
||||
@ -57,12 +51,14 @@ clan flakes create my-clan
|
||||
```
|
||||
|
||||
This command creates the `flake.nix` and `.clan-flake` files for your project.
|
||||
It will also generate files from a default template, to help show general clan usage patterns.
|
||||
|
||||
### Step 3: Verify the Project Structure
|
||||
|
||||
Ensure that all project files exist by running:
|
||||
|
||||
```bash
|
||||
cd my-clan
|
||||
tree
|
||||
```
|
||||
|
||||
@ -101,12 +97,6 @@ sara
|
||||
|
||||
### What's Next?
|
||||
|
||||
- [**Machine Configuration**](getting-started/configure.md): Declare behavior and configuration of machines.
|
||||
|
||||
- [**Deploy Machines**](getting-started/machines.md): Learn how to deploy to any remote machine.
|
||||
|
||||
- [**Installer**](getting-started/installer.md): Setting up new computers remotely is easy with an USB stick.
|
||||
|
||||
- [**Check out our Templates**](templates/index.md)
|
||||
|
||||
---
|
||||
|
1
docs/site/static/asciinema-player/asciinema-player.css
Symbolic link
1
docs/site/static/asciinema-player/asciinema-player.css
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/8y5h98wk5p94mv1wyb2c4gkrr7bswd19-asciinema-player.css
|
1
docs/site/static/asciinema-player/asciinema-player.min.js
vendored
Symbolic link
1
docs/site/static/asciinema-player/asciinema-player.min.js
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
/nix/store/w0i3f9qzn9n6jmfnfgiw5wnab2f9ssdw-asciinema-player.min.js
|
13
docs/site/static/extra.css
Normal file
13
docs/site/static/extra.css
Normal file
@ -0,0 +1,13 @@
|
||||
@font-face {
|
||||
font-family: "Roboto";
|
||||
src: url(./Roboto-Regular.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Fira Code";
|
||||
src: url(./FiraCode-VF.ttf) format('truetype');
|
||||
}
|
||||
|
||||
:root {
|
||||
--md-text-font: "Roboto";
|
||||
--md-code-font: "Fira Code";
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
@ -1,24 +0,0 @@
|
||||
# Templates
|
||||
|
||||
We provide some starting templates you can easily use one of those via `nix flakes`.
|
||||
|
||||
They showcase best practices and guide you through setting up and using Clan's modules
|
||||
|
||||
I.e. To use the `new-clan` template run the following command:
|
||||
|
||||
```bash
|
||||
nix flake init -t git+https://git.clan.lol/clan/clan-core#new-clan
|
||||
```
|
||||
|
||||
## Available Templates
|
||||
|
||||
We offer the following templates:
|
||||
|
||||
To initialize a clan with one of those run:
|
||||
```bash
|
||||
nix flake init -t git+https://git.clan.lol/clan/clan-core#[TEMPLATE_NAME]
|
||||
```
|
||||
|
||||
Substitute `[TEMPLATE_NAME]` with the name of the template.
|
||||
|
||||
- **new-clan**: Perfect for beginners, this template shows you how to link two machines in a basic setup.
|
80
flake.lock
80
flake.lock
@ -7,11 +7,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712356478,
|
||||
"narHash": "sha256-kTcEtrQIRnexu5lAbLsmUcfR2CrmsACF1s3ZFw1NEVA=",
|
||||
"lastModified": 1717177033,
|
||||
"narHash": "sha256-G3CZJafCO8WDy3dyA2EhpUJEmzd5gMJ2IdItAg0Hijw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"rev": "0a17298c0d96190ef3be729d594ba202b9c53beb",
|
||||
"rev": "0274af4c92531ebfba4a5bd493251a143bc51f3c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -27,11 +27,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"lastModified": 1717285511,
|
||||
"narHash": "sha256-iKzJcpdXih14qYVcZ9QC9XuZYnPc6T8YImb6dX166kw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"rev": "2a55567fcf15b1b1c7ed712a2c6fadaec7412ea8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -42,11 +42,11 @@
|
||||
},
|
||||
"nixlib": {
|
||||
"locked": {
|
||||
"lastModified": 1711846064,
|
||||
"narHash": "sha256-cqfX0QJNEnge3a77VnytM0Q6QZZ0DziFXt6tSCV8ZSc=",
|
||||
"lastModified": 1712450863,
|
||||
"narHash": "sha256-K6IkdtMtq9xktmYPj0uaYc8NsIqHuaAoRBaMgu9Fvrw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixpkgs.lib",
|
||||
"rev": "90b1a963ff84dc532db92f678296ff2499a60a87",
|
||||
"rev": "3c62b6a12571c9a7f65ab037173ee153d539905f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -55,6 +55,22 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-2311": {
|
||||
"locked": {
|
||||
"lastModified": 1717017538,
|
||||
"narHash": "sha256-S5kltvDDfNQM3xx9XcvzKEOyN2qk8Sa+aSOLqZ+1Ujc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "64e468fd2652105710d86cd2ae3e65a5a6d58dec",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-generators": {
|
||||
"inputs": {
|
||||
"nixlib": "nixlib",
|
||||
@ -63,11 +79,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712191720,
|
||||
"narHash": "sha256-xXtSSnVHURHsxLQO30dzCKW5NJVGV/umdQPmFjPFMVA=",
|
||||
"lastModified": 1716210724,
|
||||
"narHash": "sha256-iqQa3omRcHGpWb1ds75jS9ruA5R39FTmAkeR3J+ve1w=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-generators",
|
||||
"rev": "0c15e76bed5432d7775a22e8d22059511f59d23a",
|
||||
"rev": "d14b286322c7f4f897ca4b1726ce38cb68596c94",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -76,13 +92,34 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixos-images": {
|
||||
"inputs": {
|
||||
"nixos-2311": "nixos-2311",
|
||||
"nixos-unstable": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1717040312,
|
||||
"narHash": "sha256-yI/en4IxuCEClIUpIs3QTyYCCtmSPLOhwLJclfNwdeg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-images",
|
||||
"rev": "47bfb55316e105390dd761e0b6e8e0be09462b67",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nixos-images",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1712468661,
|
||||
"narHash": "sha256-n2gVVBs+rV+HzPv/N3QQv5cdAXqSkjmaObvfeMqnw2c=",
|
||||
"lastModified": 1717298511,
|
||||
"narHash": "sha256-9sXuJn/nL+9ImeYtlspTvjt83z1wIgU+9AwfNbnq+tI=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "298edc8f1e0dfffce67f50375c9f5952e04a6d02",
|
||||
"rev": "6634a0509e9e81e980b129435fbbec518ab246d0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -97,6 +134,7 @@
|
||||
"disko": "disko",
|
||||
"flake-parts": "flake-parts",
|
||||
"nixos-generators": "nixos-generators",
|
||||
"nixos-images": "nixos-images",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"sops-nix": "sops-nix",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
@ -110,11 +148,11 @@
|
||||
"nixpkgs-stable": []
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712458908,
|
||||
"narHash": "sha256-DMgBS+jNHDg8z3g9GkwqL8xTKXCRQ/0FGsAyrniVonc=",
|
||||
"lastModified": 1717297459,
|
||||
"narHash": "sha256-cZC2f68w5UrJ1f+2NWGV9Gx0dEYmxwomWN2B0lx0QRA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "39191e8e6265b106c9a2ba0cfd3a4dafe98a31c6",
|
||||
"rev": "ab2a43b0d21d1d37d4d5726a892f714eaeb4b075",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -130,11 +168,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711963903,
|
||||
"narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=",
|
||||
"lastModified": 1717278143,
|
||||
"narHash": "sha256-u10aDdYrpiGOLoxzY/mJ9llST9yO8Q7K/UlROoNxzDw=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac",
|
||||
"rev": "3eb96ca1ae9edf792a8e0963cc92fddfa5a87706",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
|
||||
|
||||
disko.url = "github:nix-community/disko";
|
||||
disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||
sops-nix.url = "github:Mic92/sops-nix";
|
||||
@ -16,6 +15,8 @@
|
||||
sops-nix.inputs.nixpkgs-stable.follows = "";
|
||||
nixos-generators.url = "github:nix-community/nixos-generators";
|
||||
nixos-generators.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nixos-images.url = "github:nix-community/nixos-images";
|
||||
nixos-images.inputs.nixos-unstable.follows = "nixpkgs";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
flake-parts.inputs.nixpkgs-lib.follows = "nixpkgs";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
@ -23,10 +24,14 @@
|
||||
};
|
||||
|
||||
outputs =
|
||||
inputs@{ flake-parts, ... }:
|
||||
inputs@{ flake-parts, self, ... }:
|
||||
flake-parts.lib.mkFlake { inherit inputs; } (
|
||||
{ ... }:
|
||||
{
|
||||
clan = {
|
||||
# meta.name = "clan-core";
|
||||
directory = self;
|
||||
};
|
||||
systems = [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
@ -4,6 +4,7 @@ clan-core:
|
||||
lib,
|
||||
flake-parts-lib,
|
||||
inputs,
|
||||
self,
|
||||
...
|
||||
}:
|
||||
let
|
||||
@ -16,10 +17,38 @@ let
|
||||
cfg = config.clan;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
# TODO: figure out how to print the deprecation warning
|
||||
# "${inputs.nixpkgs}/nixos/modules/misc/assertions.nix"
|
||||
(lib.mkRenamedOptionModule
|
||||
[
|
||||
"clan"
|
||||
"clanName"
|
||||
]
|
||||
[
|
||||
"clan"
|
||||
"meta"
|
||||
"name"
|
||||
]
|
||||
)
|
||||
(lib.mkRenamedOptionModule
|
||||
[
|
||||
"clan"
|
||||
"clanIcon"
|
||||
]
|
||||
[
|
||||
"clan"
|
||||
"meta"
|
||||
"icon"
|
||||
]
|
||||
)
|
||||
];
|
||||
|
||||
options.clan = {
|
||||
directory = mkOption {
|
||||
type = types.path;
|
||||
description = "The directory containing the clan subdirectory";
|
||||
default = self; # default to the directory of the flake
|
||||
};
|
||||
specialArgs = mkOption {
|
||||
type = types.attrsOf types.raw;
|
||||
@ -31,15 +60,27 @@ in
|
||||
default = { };
|
||||
description = "Allows to include machine-specific modules i.e. machines.\${name} = { ... }";
|
||||
};
|
||||
clanName = mkOption {
|
||||
type = types.str;
|
||||
description = "Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.";
|
||||
};
|
||||
clanIcon = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = "A path to an icon to be used for the clan, should be the same for all machines";
|
||||
|
||||
# Checks are performed in 'buildClan'
|
||||
# Not everyone uses flake-parts
|
||||
meta = {
|
||||
name = lib.mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Needs to be (globally) unique, as this determines the folder name where the flake gets downloaded to.";
|
||||
};
|
||||
icon = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = "A path to an icon to be used for the clan in the GUI";
|
||||
};
|
||||
description = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "A short description of the clan";
|
||||
};
|
||||
};
|
||||
|
||||
pkgsForSystem = mkOption {
|
||||
type = types.functionTo types.raw;
|
||||
default = _system: null;
|
||||
@ -50,7 +91,8 @@ in
|
||||
clanInternals = lib.mkOption {
|
||||
type = lib.types.submodule {
|
||||
options = {
|
||||
all-machines-json = lib.mkOption { type = lib.types.attrsOf lib.types.str; };
|
||||
meta = lib.mkOption { type = lib.types.attrsOf lib.types.unspecified; };
|
||||
all-machines-json = lib.mkOption { type = lib.types.attrsOf lib.types.unspecified; };
|
||||
machines = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
|
||||
machinesFunc = lib.mkOption { type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); };
|
||||
};
|
||||
@ -63,9 +105,8 @@ in
|
||||
directory
|
||||
specialArgs
|
||||
machines
|
||||
clanName
|
||||
clanIcon
|
||||
pkgsForSystem
|
||||
meta
|
||||
;
|
||||
};
|
||||
};
|
||||
|
@ -11,7 +11,9 @@
|
||||
treefmt.programs.mypy.directories = {
|
||||
"pkgs/clan-cli".extraPythonPackages = self'.packages.clan-cli.testDependencies;
|
||||
"pkgs/clan-vm-manager".extraPythonPackages =
|
||||
self'.packages.clan-vm-manager.externalTestDeps ++ self'.packages.clan-cli.testDependencies;
|
||||
# clan-vm-manager currently only exists on linux
|
||||
(self'.packages.clan-vm-manager.externalTestDeps or [ ])
|
||||
++ self'.packages.clan-cli.testDependencies;
|
||||
};
|
||||
|
||||
treefmt.settings.formatter.nix = {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user