treewide: init flakes

This commit is contained in:
Lu Wang 2024-11-28 01:14:34 +08:00
commit 79aceaa648
Signed by: rebmit
SSH key fingerprint: SHA256:3px8QV1zEerIrEWHaqtH5rR9kjetyRST5EipOPrd+bU
146 changed files with 6698 additions and 0 deletions

4
.envrc Normal file
View file

@ -0,0 +1,4 @@
use flake
if has sops; then
export TF_ENCRYPTION=$(sops --extract '["tofu"]' -d infra/secrets.yaml)
fi

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
result*
.direnv
.pre-commit-config.yaml

29
.sops.yaml Normal file
View file

@ -0,0 +1,29 @@
keys:
age:
- &marisa age1sfnct03u4cvfj98x4yjrcrrnu5gg8qgxrwk4uqq8w4e6wveeaedq97rn44
- &flandre age166kxtrcx99fxlgtvz5mvyt5ctvk3dt09f42gvm94ngnkyztmmelsyzdn77
- &reisen age1uf2h3hlv373ppdstjlngyuu7q5mee3u3ww3674lsj9rlt9ax7vqsv7wpe8
creation_rules:
- path_regex: infra/.*
key_groups:
- age:
- *marisa
- path_regex: secrets/local.*
key_groups:
- age:
- *marisa
- *flandre
- path_regex: secrets/hosts/(opentofu/)?marisa-.*
key_groups:
- age:
- *marisa
- path_regex: secrets/hosts/(opentofu/)?flandre-.*
key_groups:
- age:
- *marisa
- *flandre
- path_regex: secrets/hosts/(opentofu/)?reisen-.*
key_groups:
- age:
- *marisa
- *reisen

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 rebmit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

552
flake.lock Normal file
View file

@ -0,0 +1,552 @@
{
"nodes": {
"crane": {
"inputs": {
"nixpkgs": [
"lanzaboote",
"nixpkgs"
]
},
"locked": {
"lastModified": 1717535930,
"narHash": "sha256-1hZ/txnbd/RmiBPNUs7i8UQw2N89uAK3UzrGAWdnFfU=",
"owner": "ipetkov",
"repo": "crane",
"rev": "55e7754ec31dac78980c8be45f8a28e80e370946",
"type": "github"
},
"original": {
"owner": "ipetkov",
"repo": "crane",
"type": "github"
}
},
"devshell": {
"inputs": {
"nixpkgs": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1728330715,
"narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=",
"owner": "numtide",
"repo": "devshell",
"rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "devshell",
"type": "github"
}
},
"disko": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1730135292,
"narHash": "sha256-CI27qHAbc3/tIe8sb37kiHNaeCqGxNimckCMj0lW5kg=",
"owner": "nix-community",
"repo": "disko",
"rev": "ab58501b2341bc5e0fc88f2f5983a679b075ddf5",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "v1.9.0",
"repo": "disko",
"type": "github"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1696426674,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730504689,
"narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "506278e768c2a08bec68eb62932193e341f55c90",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"git-hooks-nix": {
"inputs": {
"flake-compat": [
"rebmit",
"flake-compat"
],
"gitignore": [
"rebmit",
"gitignore-nix"
],
"nixpkgs": [
"rebmit",
"nixpkgs"
],
"nixpkgs-stable": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1731363552,
"narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore-nix": {
"inputs": {
"nixpkgs": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"haumea": {
"inputs": {
"nixpkgs": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1708375098,
"narHash": "sha256-DaFJp3wDHgOqx98U0SF57bXaH2Orp106c+jSdPCVu1E=",
"owner": "nix-community",
"repo": "haumea",
"rev": "ec6350fd9353e7f27ce0e85d31f82e3ed73e4d70",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "haumea",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1732303962,
"narHash": "sha256-5Umjb5AdtxV5jSJd5jxoCckh5mlg+FBQDsyAilu637g=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "8cf9cb2ee78aa129e5b8220135a511a2be254c0c",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"impermanence": {
"locked": {
"lastModified": 1731242966,
"narHash": "sha256-B3C3JLbGw0FtLSWCjBxU961gLNv+BOOBC6WvstKLYMw=",
"owner": "nix-community",
"repo": "impermanence",
"rev": "3ed3f0eaae9fcc0a8331e77e9319c8a4abd8a71a",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "impermanence",
"type": "github"
}
},
"lanzaboote": {
"inputs": {
"crane": "crane",
"flake-compat": [
"flake-compat"
],
"flake-parts": [
"flake-parts"
],
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
],
"pre-commit-hooks-nix": [
"git-hooks-nix"
],
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1718178907,
"narHash": "sha256-eSZyrQ9uoPB9iPQ8Y5H7gAmAgAvCw3InStmU3oEjqsE=",
"owner": "nix-community",
"repo": "lanzaboote",
"rev": "b627ccd97d0159214cee5c7db1412b75e4be6086",
"type": "github"
},
"original": {
"owner": "nix-community",
"ref": "v0.4.1",
"repo": "lanzaboote",
"type": "github"
}
},
"niri-flake": {
"inputs": {
"niri-stable": "niri-stable",
"niri-unstable": "niri-unstable",
"nixpkgs": [
"nixpkgs"
],
"nixpkgs-stable": [
"nixpkgs"
],
"xwayland-satellite-stable": "xwayland-satellite-stable",
"xwayland-satellite-unstable": "xwayland-satellite-unstable"
},
"locked": {
"lastModified": 1732261496,
"narHash": "sha256-GLPyY+OMmiTMPXUwwdFiM4GVwouOSh/hLoPg5D6X2bc=",
"owner": "sodiboo",
"repo": "niri-flake",
"rev": "d4b0bc42a58a4cee1deb19d7d8350384e9aa4240",
"type": "github"
},
"original": {
"owner": "sodiboo",
"repo": "niri-flake",
"type": "github"
}
},
"niri-stable": {
"flake": false,
"locked": {
"lastModified": 1731483594,
"narHash": "sha256-Qjf7alRbPPERfiZsM9EMKX+HwjESky1tieh5PJIkLwE=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "75c79116a7e40cbc0e110ce0cdd500e896458679",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"ref": "v0.1.10.1",
"repo": "niri",
"type": "github"
}
},
"niri-unstable": {
"flake": false,
"locked": {
"lastModified": 1732257446,
"narHash": "sha256-xTqbonT9ZJ1PkgDvftoyMYuDul8J4VJccOtsOeRorZM=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "c239937fac836f308311eff5f5d5fc5262c6eb55",
"type": "github"
},
"original": {
"owner": "YaLTeR",
"repo": "niri",
"type": "github"
}
},
"nixpkgs-unstable": {
"locked": {
"lastModified": 1731676054,
"narHash": "sha256-OZiZ3m8SCMfh3B6bfGC/Bm4x3qc1m2SVEAlkV6iY7Yg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "5e4fbfb6b3de1aa2872b76d49fafc942626e2add",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"ranet": {
"inputs": {
"flake-utils": [
"flake-utils"
],
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1728965628,
"narHash": "sha256-GB8FXnHzaM06MivfpYEFFIp4q0WfH3a7+jmoC3Tpwbs=",
"owner": "NickCao",
"repo": "ranet",
"rev": "964565690eddec2a660a887aea924c36f358f2a0",
"type": "github"
},
"original": {
"owner": "NickCao",
"repo": "ranet",
"type": "github"
}
},
"rebmit": {
"inputs": {
"devshell": "devshell",
"flake-compat": "flake-compat",
"flake-parts": "flake-parts",
"git-hooks-nix": "git-hooks-nix",
"gitignore-nix": "gitignore-nix",
"haumea": "haumea",
"nixpkgs": [
"rebmit",
"nixpkgs-unstable"
],
"nixpkgs-unstable": "nixpkgs-unstable",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1732721386,
"narHash": "sha256-UPjh8eXgssjDH7XjMtO9Q9ysWEo9rnwJiX2Gpmt4aJY=",
"owner": "rebmit",
"repo": "nix-exprs",
"rev": "a5973d50b8660c3a87224a58ffd38bedff9559bb",
"type": "github"
},
"original": {
"owner": "rebmit",
"repo": "nix-exprs",
"type": "github"
}
},
"root": {
"inputs": {
"devshell": [
"rebmit",
"devshell"
],
"disko": "disko",
"flake-compat": [
"rebmit",
"flake-compat"
],
"flake-parts": [
"rebmit",
"flake-parts"
],
"flake-utils": "flake-utils",
"git-hooks-nix": [
"rebmit",
"git-hooks-nix"
],
"home-manager": "home-manager",
"impermanence": "impermanence",
"lanzaboote": "lanzaboote",
"niri-flake": "niri-flake",
"nixpkgs": [
"rebmit",
"nixpkgs"
],
"nixpkgs-unstable": [
"rebmit",
"nixpkgs-unstable"
],
"ranet": "ranet",
"rebmit": "rebmit",
"sops-nix": "sops-nix",
"treefmt-nix": [
"rebmit",
"treefmt-nix"
]
}
},
"rust-overlay": {
"inputs": {
"flake-utils": [
"lanzaboote",
"flake-utils"
],
"nixpkgs": [
"lanzaboote",
"nixpkgs"
]
},
"locked": {
"lastModified": 1717813066,
"narHash": "sha256-wqbRwq3i7g5EHIui0bIi84mdqZ/It1AXBSLJ5tafD28=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "6dc3e45fe4aee36efeed24d64fc68b1f989d5465",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"sops-nix": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1732186149,
"narHash": "sha256-N9JGWe/T8BC0Tss2Cv30plvZUYoiRmykP7ZdY2on2b0=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "53c853fb1a7e4f25f68805ee25c83d5de18dc699",
"type": "github"
},
"original": {
"owner": "Mic92",
"repo": "sops-nix",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"rebmit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730321837,
"narHash": "sha256-vK+a09qq19QNu2MlLcvN4qcRctJbqWkX7ahgPZ/+maI=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "746901bb8dba96d154b66492a29f5db0693dbfcc",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"xwayland-satellite-stable": {
"flake": false,
"locked": {
"lastModified": 1730166465,
"narHash": "sha256-nq7bouXQXaaPPo/E+Jbq+wNHnatD4dY8OxSrRqzvy6s=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "a713cf46cb7db84a0d1b57c3a397c610cad3cf98",
"type": "github"
},
"original": {
"owner": "Supreeeme",
"ref": "v0.5",
"repo": "xwayland-satellite",
"type": "github"
}
},
"xwayland-satellite-unstable": {
"flake": false,
"locked": {
"lastModified": 1732233710,
"narHash": "sha256-gWf9dX6DVx0ssK2G3yrFG9yMT9UU0mDwyD51z/Q6FTA=",
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"rev": "02f30546264ff8407cbb39528b3a3cc3045e53c1",
"type": "github"
},
"original": {
"owner": "Supreeeme",
"repo": "xwayland-satellite",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

78
flake.nix Normal file
View file

@ -0,0 +1,78 @@
{
description = "a nixos configuration collection by rebmit";
outputs =
inputs@{ flake-parts, rebmit, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
inherit (rebmit.lib) systems;
imports = [
inputs.devshell.flakeModule
inputs.git-hooks-nix.flakeModule
inputs.treefmt-nix.flakeModule
inputs.rebmit.flakeModule
] ++ rebmit.lib.path.buildModuleList ./flake;
};
inputs = {
# flake-parts
flake-parts.follows = "rebmit/flake-parts";
# nixpkgs
nixpkgs.follows = "rebmit/nixpkgs";
nixpkgs-unstable.follows = "rebmit/nixpkgs-unstable";
# flake modules
devshell.follows = "rebmit/devshell";
git-hooks-nix.follows = "rebmit/git-hooks-nix";
treefmt-nix.follows = "rebmit/treefmt-nix";
# nixos modules
impermanence.url = "github:nix-community/impermanence";
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
disko = {
url = "github:nix-community/disko/v1.9.0";
inputs.nixpkgs.follows = "nixpkgs";
};
lanzaboote = {
url = "github:nix-community/lanzaboote/v0.4.1";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-parts.follows = "flake-parts";
inputs.flake-utils.follows = "flake-utils";
inputs.flake-compat.follows = "flake-compat";
inputs.pre-commit-hooks-nix.follows = "git-hooks-nix";
};
# programs
niri-flake = {
url = "github:sodiboo/niri-flake";
inputs.nixpkgs.follows = "nixpkgs";
inputs.nixpkgs-stable.follows = "nixpkgs";
};
ranet = {
url = "github:NickCao/ranet";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "flake-utils";
};
# libraries
rebmit.url = "github:rebmit/nix-exprs";
flake-utils.url = "github:numtide/flake-utils";
# misc
flake-compat.follows = "rebmit/flake-compat";
};
}

30
flake/devshell.nix Normal file
View file

@ -0,0 +1,30 @@
{
perSystem =
{
config,
pkgs,
lib,
...
}:
{
devshells.default = {
packages = with pkgs; [
just
sops
rage
(opentofu.withPlugins (
ps: with ps; [
sops
tls
]
))
];
env = [
(lib.nameValuePair "DEVSHELL_NO_MOTD" 1)
# https://github.com/opentofu/opentofu/issues/1478
(lib.nameValuePair "OPENTOFU_STATEFILE_PROVIDER_ADDRESS_TRANSLATION" 0)
];
devshell.startup.pre-commit-hook.text = config.pre-commit.installationScript;
};
};
}

73
flake/home-manager.nix Normal file
View file

@ -0,0 +1,73 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/b618b0fd16fb9c79ab7199ed51c4c0f98a392cea/flake/hosts.nix
{
inputs,
lib,
...
}:
let
inherit (inputs.rebmit.lib.path) buildModuleList rakeLeaves;
buildSuites = profiles: f: lib.mapAttrs (_: lib.flatten) (lib.fix (f profiles));
homeModules = buildModuleList ../home-manager/modules;
homeProfiles = rakeLeaves ../home-manager/profiles;
homeSuites = buildSuites homeProfiles (
profiles: suites: {
baseline = with profiles; [
# keep-sorted start
applications.base
fish
helix
tmux
yazi
# keep-sorted end
];
development = with profiles; [
# keep-sorted start
development
direnv
git
# keep-sorted end
];
workstation = suites.baseline ++ suites.development;
desktop-baseline =
suites.baseline
++ (with profiles; [
# keep-sorted start
applications.desktop
darkman
fcitx5
firefox
fontconfig
gtk
kitty
qt
theme.catppuccin
xdg-user-dirs
# keep-sorted end
]);
desktop-niri = with profiles; [
# keep-sorted start
cliphist
fuzzel
mako
niri
swaylock
swww
waybar.niri
# keep-sorted end
];
desktop-workstation = suites.workstation ++ suites.desktop-baseline ++ suites.desktop-niri;
}
);
in
{
passthru = {
inherit homeModules homeProfiles homeSuites;
};
}

152
flake/hosts.nix Normal file
View file

@ -0,0 +1,152 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/b618b0fd16fb9c79ab7199ed51c4c0f98a392cea/flake/hosts.nix
{
config,
inputs,
self,
lib,
getSystem,
...
}:
let
inherit (config.passthru)
nixosModules
nixosProfiles
nixosSuites
homeModules
homeProfiles
homeSuites
;
data = builtins.fromJSON (builtins.readFile ../zones/data.json);
mylib = inputs.rebmit.lib;
nixosSpecialArgs = name: {
inherit
inputs
self
data
mylib
;
profiles = nixosProfiles;
suites = nixosSuites;
hostData = data.hosts."${name}";
};
homeSpecialArgs = name: {
inherit
inputs
self
data
mylib
;
profiles = homeProfiles;
suites = homeSuites;
hostData = data.hosts."${name}";
};
commonNixosModules =
name:
nixosModules
++ [
inputs.impermanence.nixosModules.impermanence
inputs.home-manager.nixosModules.home-manager
inputs.sops-nix.nixosModules.sops
inputs.disko.nixosModules.disko
inputs.lanzaboote.nixosModules.lanzaboote
(
{ ... }:
{
home-manager = {
useGlobalPkgs = true;
useUserPackages = true;
sharedModules = commonHomeModules name;
extraSpecialArgs = homeSpecialArgs name;
};
}
)
];
commonHomeModules =
_name:
homeModules
++ [
inputs.niri-flake.homeModules.niri
(
{ osConfig, ... }:
{
home.stateVersion = osConfig.system.stateVersion;
}
)
];
mkHost =
{
name,
configurationName ? name,
nixpkgs ? inputs.nixpkgs,
system,
forceFlakeNixpkgs ? true,
}:
{
${name} = nixpkgs.lib.nixosSystem {
specialArgs = nixosSpecialArgs name;
modules =
(commonNixosModules name)
++ lib.optional (configurationName != null) ../nixos/hosts/${configurationName}
++ [
(
{ lib, ... }:
{
networking.hostName = lib.mkDefault name;
}
)
(
if forceFlakeNixpkgs then
{
imports = [ nixpkgs.nixosModules.readOnlyPkgs ];
nixpkgs = {
inherit ((getSystem system).allModuleArgs) pkgs;
};
}
else
{
nixpkgs = {
inherit ((getSystem system).nixpkgs) config overlays;
};
}
)
];
};
};
in
{
flake.nixosConfigurations = lib.mkMerge [
(mkHost {
name = "marisa-7d76";
system = "x86_64-linux";
})
(mkHost {
name = "marisa-a7s";
system = "x86_64-linux";
})
(mkHost {
name = "flandre-m5p";
system = "x86_64-linux";
})
(mkHost {
name = "reisen-sin0";
system = "x86_64-linux";
})
(mkHost {
name = "reisen-lax0";
system = "x86_64-linux";
})
];
}

67
flake/nixos.nix Normal file
View file

@ -0,0 +1,67 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/b618b0fd16fb9c79ab7199ed51c4c0f98a392cea/flake/hosts.nix
{
inputs,
lib,
...
}:
let
inherit (inputs.rebmit.lib.path) buildModuleList rakeLeaves;
buildSuites = profiles: f: lib.mapAttrs (_: lib.flatten) (lib.fix (f profiles));
nixosModules = buildModuleList ../nixos/modules;
nixosProfiles = rakeLeaves ../nixos/profiles;
nixosSuites = buildSuites nixosProfiles (
profiles: suites: {
baseline = with profiles; [
# keep-sorted start
programs.tools.common
security.polkit
services.dbus
services.journald
services.openssh
services.zram-generator
system.boot.kernel.latest
system.boot.systemd-initrd
system.common
system.global-persistence
system.nix.gc
system.nix.registry
system.nix.settings
system.nix.version
users.root
# keep-sorted end
];
network = with profiles; [
# keep-sorted start
programs.tools.network
services.firewall
services.networkd
services.resolved
system.boot.sysctl.tcp-bbr
# keep-sorted end
];
desktop = with profiles; [
# keep-sorted start
programs.dconf
programs.tools.system
security.rtkit
services.gnome-keyring
services.greetd
services.pipewire
# keep-sorted end
];
workstation = suites.baseline ++ suites.network ++ suites.desktop;
server = suites.baseline ++ suites.network;
}
);
in
{
passthru = {
inherit nixosModules nixosProfiles nixosSuites;
};
}

56
flake/nixpkgs.nix Normal file
View file

@ -0,0 +1,56 @@
{
inputs,
...
}:
let
overlays = [
inputs.ranet.overlays.default
(_final: prev: {
libadwaita = prev.libadwaita.overrideAttrs (old: {
patches = (old.patches or [ ]) ++ [
../patches/libadwaita-without-adwaita-theme.patch
];
doCheck = false;
});
})
];
in
{
perSystem =
{ config, lib, ... }:
{
nixpkgs = {
config = {
allowUnfree = false;
allowUnfreePredicate =
p:
builtins.elem (lib.getName p) [
# keep-sorted start
# keep-sorted end
];
allowNonSource = false;
allowNonSourcePredicate =
p:
builtins.elem (lib.getName p) [
# keep-sorted start
"ant"
"cargo-bootstrap"
"dotnet-sdk"
"go"
"libreoffice"
"rustc-bootstrap"
"rustc-bootstrap-wrapper"
"sof-firmware"
"temurin-bin"
"zotero"
# keep-sorted end
];
allowInsecurePredicate = p: (p.pname or null) == "olm";
};
inherit overlays;
};
};
}

7
flake/packages.nix Normal file
View file

@ -0,0 +1,7 @@
{
perSystem =
{ pkgs, ... }:
{
legacyPackages = pkgs;
};
}

36
flake/treefmt.nix Normal file
View file

@ -0,0 +1,36 @@
{
perSystem =
{
config,
lib,
...
}:
{
treefmt = {
projectRootFile = "flake.nix";
programs = {
nixfmt.enable = true;
deadnix.enable = true;
terraform.enable = true;
prettier.enable = true;
keep-sorted.enable = true;
};
settings.formatter = {
keep-sorted = {
includes = lib.mkForce [ "*.nix" ];
};
};
};
devshells.default.packages = lib.singleton config.treefmt.build.wrapper;
pre-commit.settings.hooks = {
treefmt = {
enable = true;
name = "treefmt";
entry = lib.getExe config.treefmt.build.wrapper;
pass_filenames = false;
};
};
};
}

View file

@ -0,0 +1,53 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/b618b0fd16fb9c79ab7199ed51c4c0f98a392cea/home-manager/modules/home/global-persistence.nix
{
config,
lib,
osConfig,
...
}:
with lib;
let
cfg = config.home.globalPersistence;
sysCfg = osConfig.environment.globalPersistence;
in
{
options.home.globalPersistence = {
enable = mkEnableOption "global presistence storage";
home = mkOption {
type = types.str;
description = ''
Home directory.
'';
};
directories = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
A list of directories in your home directory that you want to link to persistent storage.
'';
};
files = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
A list of files in your home directory you want to link to persistent storage.
'';
};
enabled = mkOption {
type = types.bool;
default = false;
description = ''
Is global home persistence storage enabled.
'';
};
};
config = mkIf (osConfig != null && sysCfg.enable) {
home.globalPersistence = {
inherit (sysCfg.user) directories;
inherit (sysCfg.user) files;
enabled = cfg.enable;
};
};
}

View file

@ -0,0 +1,68 @@
{ lib, ... }:
with lib;
let
themeOpts.options = {
iconTheme = mkOption {
type = types.str;
description = ''
The icon theme to use.
'';
};
gtkTheme = mkOption {
type = types.str;
description = ''
The GTK theme to use.
'';
};
wallpaper = mkOption {
type = types.str;
description = ''
The path to the wallpaper to use.
'';
};
kittyTheme = mkOption {
type = types.str;
description = ''
The path to the kitty theme to use.
'';
};
helixTheme = mkOption {
type = types.str;
description = ''
The path to the helix theme to use.
'';
};
base24Theme = mkOption { };
};
in
{
options.theme = {
cursorTheme = mkOption {
type = types.str;
description = ''
The cursor theme to use.
'';
};
cursorSize = mkOption {
type = types.int;
description = ''
The size of the cursor.
'';
};
light = mkOption {
type = types.submodule themeOpts;
default = { };
description = ''
The light theme configuration.
'';
};
dark = mkOption {
type = types.submodule themeOpts;
default = { };
description = ''
The dark theme configuration.
'';
};
};
}

View file

@ -0,0 +1,13 @@
{ pkgs, ... }:
{
home.packages = with pkgs; [
# keep-sorted start
fastfetch
fd
ffmpeg
fzf
numbat
ripgrep
# keep-sorted end
];
}

View file

@ -0,0 +1,29 @@
{ pkgs, ... }:
{
home.packages = with pkgs; [
# keep-sorted start
celluloid
foliate
libreoffice-fresh
loupe
nheko
papers
seahorse
tdesktop
thunderbird
zotero-beta
# keep-sorted end
];
home.globalPersistence.directories = [
".thunderbird"
".zotero"
".config/nheko"
".local/share/nheko"
".local/share/TelegramDesktop"
"Zotero"
];
}

View file

@ -0,0 +1,63 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/d40b75ca0955d2a999b36fa1bd0f8b3a6e061ef3/home-manager/profiles/niri/default.nix
{
config,
lib,
pkgs,
...
}:
let
cliphist = pkgs.cliphist;
in
lib.mkMerge [
{
home.packages = lib.singleton cliphist;
systemd.user.services.cliphist = {
Unit = {
Description = "Clipboard management daemon";
ConditionEnvironment = lib.singleton "WAYLAND_DISPLAY";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
Requisite = [ "graphical-session.target" ];
};
Install.WantedBy = [ "graphical-session.target" ];
Service = {
Type = "simple";
Restart = "on-failure";
ExecStart = "${pkgs.wl-clipboard}/bin/wl-paste --watch ${cliphist}/bin/cliphist store";
};
};
systemd.user.services.cliphist-images = {
Unit = {
Description = "Clipboard management daemon - images";
ConditionEnvironment = lib.singleton "WAYLAND_DISPLAY";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
Requisite = [ "graphical-session.target" ];
};
Install.WantedBy = [ "graphical-session.target" ];
Service = {
Type = "simple";
Restart = "on-failure";
ExecStart = "${pkgs.wl-clipboard}/bin/wl-paste --type image --watch ${cliphist}/bin/cliphist store";
};
};
}
(lib.mkIf config.programs.fuzzel.enable {
home.packages = with pkgs; [
(pkgs.writeShellApplication {
name = "cliphist-fuzzel";
runtimeInputs = with pkgs; [
wl-clipboard
config.programs.fuzzel.package
config.services.cliphist.package
];
text = ''
cliphist list | fuzzel -d | cliphist decode | wl-copy
'';
})
];
})
]

View file

@ -0,0 +1,35 @@
{
config,
pkgs,
lib,
...
}:
let
defaultMode = pkgs.writeText "darkman-default-mode" "light";
in
{
services.darkman.enable = true;
home.globalPersistence.directories = [ ".cache/darkman" ];
systemd.user.tmpfiles.rules = [
"C %h/.cache/darkman/mode.txt - - - - ${defaultMode}"
"z %h/.cache/darkman/mode.txt 644 - - -"
];
home.packages = with pkgs; [
(writeShellApplication {
name = "toggle-theme";
runtimeInputs = lib.singleton config.services.darkman.package;
text = ''
darkman toggle
'';
})
];
home.activation.restartDarkman = lib.hm.dag.entryAfter [ "writeBoundary" ] ''
if ${config.systemd.user.systemctlPath} --user is-active darkman; then
${config.systemd.user.systemctlPath} --user restart darkman
fi
'';
}

View file

@ -0,0 +1,8 @@
{ ... }:
{
home.globalPersistence.directories = [
"Projects"
".local/share/uv"
];
}

View file

@ -0,0 +1,9 @@
{ ... }:
{
programs.direnv = {
enable = true;
nix-direnv.enable = true;
};
home.globalPersistence.directories = [ ".local/share/direnv" ];
}

View file

@ -0,0 +1,5 @@
EnableFractionalScale=False
Font=Sans Serif 11
MenuFont=Sans Serif 11
TrayFont=Sans Serif 11

View file

@ -0,0 +1,2 @@
TriggerKey=

View file

@ -0,0 +1,2 @@
Toggle Key=

View file

@ -0,0 +1,2 @@
FirstRun=False

View file

@ -0,0 +1,26 @@
[Hotkey]
ActivateKeys=
AltTriggerKeys=
DeactivateKeys=
EnumerateBackwardKeys=
EnumerateForwardKeys=
EnumerateGroupBackwardKeys=
EnumerateGroupForwardKeys=
EnumerateSkipFirst=False
EnumerateWithTriggerKeys=True
TogglePreedit=
[Hotkey/NextCandidate]
0=Tab
[Hotkey/NextPage]
0=Down
[Hotkey/PrevCandidate]
0=Shift+Tab
[Hotkey/PrevPage]
0=Up
[Hotkey/TriggerKeys]
0=Super+space

View file

@ -0,0 +1,13 @@
[GroupOrder]
0=Default
[Groups/0]
Default Layout=us
DefaultIM=pinyin
Name=Default
[Groups/0/Items/0]
Name=keyboard-us
[Groups/0/Items/1]
Name=pinyin

View file

@ -0,0 +1,30 @@
{ pkgs, lib, ... }:
let
fcitx5Package = pkgs.qt6Packages.fcitx5-with-addons.override {
addons = with pkgs; [
qt6Packages.fcitx5-chinese-addons
fcitx5-pinyin-zhwiki
];
withConfigtool = false;
};
in
{
home.packages = lib.singleton fcitx5Package;
systemd.user.services.fcitx5-daemon = {
Unit = {
Description = "Fcitx5 input method editor";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
Requisite = [ "graphical-session.target" ];
};
Service.ExecStart = "${fcitx5Package}/bin/fcitx5";
Install.WantedBy = [ "graphical-session.target" ];
};
xdg.configFile."fcitx5" = {
source = ./_config;
force = true;
recursive = true;
};
}

View file

@ -0,0 +1,158 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/home.nix
# https://github.com/llakala/nixos/blob/b3c5fbde5a5f78c91ee658250f9b42418b73a7b7/apps/gui/firefox.nix
{
lib,
pkgs,
...
}:
{
programs.firefox.enable = true;
programs.firefox.policies = {
AutofillAddressEnabled = false;
AutofillCreditCardEnabled = false;
DisableAccounts = true;
DisableFirefoxAccounts = true;
DisableFirefoxStudies = true;
DisablePocket = true;
DisableTelemetry = true;
EnableTrackingProtection = {
Value = true;
Locked = true;
Cryptomining = true;
Fingerprinting = true;
EmailTracking = true;
};
FirefoxHome = {
Search = true;
TopSites = false;
SponsoredTopSites = false;
Highlights = false;
Pocket = false;
SponsoredPocket = false;
Snippets = false;
Locked = true;
};
FirefoxSuggest = {
WebSuggestions = false;
SponsoredSuggestions = false;
ImproveSuggest = false;
Locked = true;
};
PasswordManagerEnabled = false;
PostQuantumKeyAgreementEnabled = true;
SearchSuggestEnabled = false;
};
programs.firefox.policies.ExtensionSettings = {
"{446900e4-71c2-419f-a6a7-df9c091e268b}" = {
installation_mode = "force_installed";
install_url = "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi";
};
"uBlock0@raymondhill.net" = {
installation_mode = "force_installed";
install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi";
};
"addon@darkreader.org" = {
installation_mode = "force_installed";
install_url = "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi";
};
"@testpilot-containers" = {
installation_mode = "force_installed";
install_url = "https://addons.mozilla.org/firefox/downloads/latest/multi-account-containers/latest.xpi";
};
};
programs.firefox.policies.Preferences = {
"browser.urlbar.autoFill.adaptiveHistory.enabled" = true;
"browser.tabs.closeWindowWithLastTab" = false;
"browser.tabs.inTitlebar" = 0;
};
programs.firefox.policies.Preferences."browser.uiCustomization.state" = builtins.toJSON {
placements = {
widget-overflow-fixed-list = [ ];
nav-bar = [
"back-button"
"forward-button"
"stop-reload-button"
"sidebar-button"
"urlbar-container"
"downloads-button"
"unified-extensions-button"
"fxa-toolbar-menu-button"
];
toolbar-menubar = [ "menubar-items" ];
TabsToolbar = [ ];
vertical-tabs = [ "tabbrowser-tabs" ];
PersonalToolbar = [ "personal-bookmarks" ];
};
currentVersion = 20;
newElementCount = 0;
};
programs.firefox.profiles.default = {
isDefault = true;
search = {
force = true;
default = "Google";
};
containersForce = true;
containers = {
"Domestic" = {
id = 1;
color = "green";
icon = "fingerprint";
};
};
settings = {
"sidebar.revamp" = true;
"sidebar.verticalTabs" = true;
};
};
programs.firefox.profiles.default.search.engines = {
"Bing".metaData.hidden = true;
"eBay".metaData.hidden = true;
"Amazon.com".metaData.hidden = true;
"Wikipedia (en)".metaData.hidden = true;
"Nixpkgs" = {
urls = lib.singleton {
template = "https://search.nixos.org/packages";
params = lib.attrsToList {
"channel" = "unstable";
"query" = "{searchTerms}";
};
};
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@np" ];
};
"NixOS Options" = {
urls = lib.singleton {
template = "https://search.nixos.org/options";
params = lib.attrsToList {
"channel" = "unstable";
"query" = "{searchTerms}";
};
};
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = [ "@no" ];
};
"Home Manager Options" = {
urls = lib.singleton {
template = "https://home-manager-options.extranix.com";
params = lib.attrsToList {
"release" = "master";
"query" = "{searchTerms}";
};
};
iconUpdateURL = "https://home-manager-options.extranix.com/images/favicon.png";
definedAliases = [ "@ho" ];
};
};
home.globalPersistence.directories = [ ".mozilla" ];
programs.niri.browser = lib.mkDefault [ "firefox" ];
}

View file

@ -0,0 +1,43 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/home.nix
{ pkgs, ... }:
{
programs.fish = {
enable = true;
plugins = [
{
name = "tide";
src = pkgs.fishPlugins.tide.src;
}
{
name = "autopair";
src = pkgs.fishPlugins.autopair.src;
}
];
shellInit = ''
set fish_greeting
set fish_cursor_default block
set fish_cursor_insert line
set fish_cursor_replace_one underscore
set fish_cursor_replace underscore
set fish_cursor_external line
set fish_cursor_visual block
function fish_user_key_bindings
fish_vi_key_bindings
bind f accept-autosuggestion
end
string replace -r '^' 'set -g ' < ${pkgs.fishPlugins.tide.src}/functions/tide/configure/icons.fish | source
string replace -r '^' 'set -g ' < ${pkgs.fishPlugins.tide.src}/functions/tide/configure/configs/lean.fish | source
string replace -r '^' 'set -g ' < ${pkgs.fishPlugins.tide.src}/functions/tide/configure/configs/lean_16color.fish | source
set -g tide_prompt_add_newline_before false
fish_config theme choose fish\ default
set fish_color_autosuggestion white
'';
};
home.globalPersistence.directories = [ ".local/share/fish" ];
}

View file

@ -0,0 +1,15 @@
{ pkgs, ... }:
{
home.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-cjk-serif
noto-fonts-emoji
roboto-mono
(nerdfonts.override { fonts = [ "RobotoMono" ]; })
];
fonts.fontconfig.enable = true;
xdg.configFile."fontconfig/conf.d/30-default-fonts.conf".source = ./fonts.conf;
}

View file

@ -0,0 +1,174 @@
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<!-- https://catcat.cc/post/2021-03-07/ -->
<fontconfig>
<match target="pattern">
<test name="family">
<string>system-ui</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>sans-serif</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>sans-serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans</string>
<string>Noto Sans CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif</string>
<string>Noto Serif CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>monospace</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>RobotoMono Nerd Font Mono</string>
<string>Noto Sans Mono CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="family">
<string>emoji</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Color Emoji</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family" compare="contains">
<string>Noto Sans CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans CJK JP</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>ja</string>
</test>
<test name="family" compare="contains">
<string>Noto Serif CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif CJK JP</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family" compare="contains">
<string>Noto Sans CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans CJK KR</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>ko</string>
</test>
<test name="family" compare="contains">
<string>Noto Serif CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif CJK KR</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-CN</string>
</test>
<test name="family" compare="contains">
<string>Noto Sans</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-CN</string>
</test>
<test name="family" compare="contains">
<string>Noto Serif</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif CJK SC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-HK</string>
</test>
<test name="family" compare="contains">
<string>Noto Sans CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans CJK HK</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-HK</string>
</test>
<test name="family" compare="contains">
<string>Noto Serif CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif CJK HK</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-TW</string>
</test>
<test name="family" compare="contains">
<string>Noto Sans CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Sans CJK TC</string>
</edit>
</match>
<match target="pattern">
<test name="lang" compare="contains">
<string>zh-TW</string>
</test>
<test name="family" compare="contains">
<string>Noto Serif CJK SC</string>
</test>
<edit name="family" mode="prepend" binding="strong">
<string>Noto Serif CJK TC</string>
</edit>
</match>
</fontconfig>

View file

@ -0,0 +1,69 @@
{
config,
pkgs,
lib,
...
}:
let
mkTheme =
mode:
let
inherit (config.theme.${mode}.base24Theme)
base00
base04
base05
base08
base0D
;
in
(pkgs.formats.ini { }).generate "fuzzel-theme-${mode}.ini" {
colors = {
background = "${base00}dd";
text = "${base05}ff";
match = "${base08}ff";
selection = "${base04}ff";
selection-text = "${base05}ff";
selection-match = "${base08}ff";
border = "${base0D}ff";
};
};
in
{
programs.fuzzel = {
enable = true;
settings = {
main = {
fields = "filename,name,generic,exec,keywords";
font = "monospace:size=11";
dpi-aware = "no";
layer = "overlay";
};
border = {
width = "2";
radius = "0";
};
};
};
programs.fuzzel.settings.main.include = "~/.config/fuzzel/theme.ini";
systemd.user.tmpfiles.rules = [
"L %h/.config/fuzzel/theme.ini - - - - ${mkTheme "light"}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-fuzzel-${mode}";
text = ''
ln --force --symbolic --verbose "${mkTheme mode}" "$HOME/.config/fuzzel/theme.ini"
'';
};
in
{
lightModeScripts.fuzzel = "${lib.getExe (mkScript "light")}";
darkModeScripts.fuzzel = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,16 @@
{ lib, ... }:
{
programs.git = {
enable = true;
lfs.enable = true;
extraConfig = {
commit.gpgSign = true;
gpg.format = "ssh";
pull.rebase = true;
init.defaultBranch = "master";
fetch.prune = true;
};
};
programs.git.signing.key = lib.mkDefault "~/.ssh/id_ed25519";
}

View file

@ -0,0 +1,49 @@
{
config,
lib,
pkgs,
...
}:
{
gtk = {
enable = true;
gtk2.configLocation = "${config.xdg.configHome}/gtk-2.0/gtkrc";
cursorTheme = {
name = config.theme.cursorTheme;
size = config.theme.cursorSize;
};
};
# https://github.com/nix-community/home-manager/pull/5206
# https://github.com/nix-community/home-manager/commit/e9b9ecef4295a835ab073814f100498716b05a96
xdg.configFile."gtk-4.0/gtk.css" = lib.mkForce {
text = config.gtk.gtk4.extraCss;
};
services.darkman =
let
mkScript =
mode:
let
inherit (config.theme.${mode})
gtkTheme
iconTheme
;
in
pkgs.writeShellApplication {
name = "darkman-switch-gtk-${mode}";
runtimeInputs = with pkgs; [
dconf
];
text = ''
dconf write /org/gnome/desktop/interface/color-scheme "'prefer-${mode}'"
dconf write /org/gnome/desktop/interface/gtk-theme "'${gtkTheme}'"
dconf write /org/gnome/desktop/interface/icon-theme "'${iconTheme}'"
'';
};
in
{
lightModeScripts.gtk = "${lib.getExe (mkScript "light")}";
darkModeScripts.gtk = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,75 @@
{
config,
pkgs,
lib,
...
}:
{
programs.helix = {
enable = true;
defaultEditor = true;
settings = {
editor = {
line-number = "relative";
cursorline = true;
bufferline = "multiple";
color-modes = true;
lsp.display-messages = true;
cursor-shape = {
insert = "bar";
normal = "block";
select = "underline";
};
indent-guides.render = true;
};
keys = {
normal = {
esc = [
"keep_primary_selection"
"collapse_selection"
];
S = ":w";
Q = ":q";
J = lib.replicate 5 "move_visual_line_down";
K = lib.replicate 5 "move_visual_line_up";
H = lib.replicate 5 "move_char_left";
L = lib.replicate 5 "move_char_right";
};
select = {
J = lib.replicate 5 "extend_line_down";
K = lib.replicate 5 "extend_line_up";
H = lib.replicate 5 "extend_char_left";
L = lib.replicate 5 "extend_char_right";
};
};
};
};
programs.helix.settings.theme = "custom";
systemd.user.tmpfiles.rules = [
"L %h/.config/helix/themes/custom.toml - - - - ${config.theme.light.helixTheme}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-helix-${mode}";
runtimeInputs = with pkgs; [
procps
];
text = ''
ln --force --symbolic --verbose "${
config.theme.${mode}.helixTheme
}" "$HOME/.config/helix/themes/custom.toml"
pkill -USR1 -u "$USER" hx || true
'';
};
in
{
lightModeScripts.helix = "${lib.getExe (mkScript "light")}";
darkModeScripts.helix = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,55 @@
{
config,
lib,
pkgs,
...
}:
{
programs.kitty = {
enable = true;
font = {
name = "monospace";
size = 12.0;
};
settings = {
background_opacity = "0.95";
hide_window_decorations = "yes";
confirm_os_window_close = "0";
enable_audio_bell = "no";
map = "kitty_mod+t no_op";
};
extraConfig = ''
include theme.conf
'';
};
programs.fuzzel.settings.main.terminal = lib.mkDefault "kitty";
programs.niri.terminal = lib.mkDefault [ "kitty" ];
systemd.user.tmpfiles.rules = [
"L %h/.config/kitty/theme.conf - - - - ${config.theme.light.kittyTheme}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-kitty-${mode}";
runtimeInputs = with pkgs; [
procps
];
text = ''
ln --force --symbolic --verbose "${
config.theme.${mode}.kittyTheme
}" "$HOME/.config/kitty/theme.conf"
pkill -USR1 -u "$USER" kitty || true
'';
};
in
{
lightModeScripts.kitty = "${lib.getExe (mkScript "light")}";
darkModeScripts.kitty = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,56 @@
{
config,
pkgs,
lib,
...
}:
let
mkConfig =
mode:
let
inherit (config.theme.${mode}.base24Theme)
base00
base02
base05
base09
base0D
;
in
pkgs.writeText "mako-config-${mode}" ''
font=sans-serif 11
background-color=#${base00}
text-color=#${base05}
border-color=#${base0D}
progress-color=over #${base02}
border-size=3
border-radius=3
[urgency=high]
border-color=#${base09}
'';
mako = pkgs.mako;
in
{
home.packages = lib.singleton mako;
systemd.user.tmpfiles.rules = [
"L %h/.config/mako/config - - - - ${mkConfig "light"}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-mako-${mode}";
text = ''
ln --force --symbolic --verbose "${mkConfig mode}" "$HOME/.config/mako/config"
${mako}/bin/makoctl reload || true
'';
};
in
{
lightModeScripts.mako = "${lib.getExe (mkScript "light")}";
darkModeScripts.mako = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,305 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/d40b75ca0955d2a999b36fa1bd0f8b3a6e061ef3/home-manager/profiles/niri/default.nix
{
config,
lib,
pkgs,
...
}:
let
cfg = config.programs.niri;
in
{
options.programs.niri = {
browser = lib.mkOption {
type = with lib.types; listOf str;
description = ''
The command of the default browser.
'';
};
terminal = lib.mkOption {
type = with lib.types; listOf str;
description = ''
The command of the default terminal.
'';
};
xwayland = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable xwayland support.
'';
};
};
config = lib.mkMerge [
# niri
{
programs.niri = {
package = pkgs.niri;
settings = {
input = {
touchpad = {
tap = true;
natural-scroll = true;
dwt = true;
};
};
layout = {
gaps = 8;
center-focused-column = "never";
preset-column-widths = [
{ proportion = 1.0 / 3.0; }
{ proportion = 1.0 / 2.0; }
{ proportion = 2.0 / 3.0; }
];
default-column-width = {
proportion = 1.0 / 2.0;
};
focus-ring = {
enable = true;
width = 4;
active.color = "#7fc8ff";
inactive.color = "#505050";
};
border = {
enable = false;
width = 4;
active.color = "#ffc87f";
inactive.color = "#505050";
};
struts = { };
};
hotkey-overlay = {
skip-at-startup = true;
};
spawn-at-startup = [ ];
prefer-no-csd = true;
screenshot-path = "~/Pictures/Screenshots/Screenshot from %Y-%m-%d %H-%M-%S.png";
animations.enable = true;
window-rules = [
{
geometry-corner-radius =
let
radius = 12.0;
in
{
bottom-left = radius;
bottom-right = radius;
top-left = radius;
top-right = radius;
};
clip-to-geometry = true;
}
];
binds =
let
modMove = "Shift";
modMonitor = "Ctrl";
keyUp = "K";
keyDown = "J";
keyLeft = "H";
keyRight = "L";
directions = {
left = {
keys = [
keyLeft
"WheelScrollLeft"
];
windowTerm = "column";
};
down = {
keys = lib.singleton keyDown;
windowTerm = "window";
};
up = {
keys = lib.singleton keyUp;
windowTerm = "window";
};
right = {
keys = [
keyRight
"WheelScrollRight"
];
windowTerm = "column";
};
};
workspaceIndices = lib.range 1 9;
isWheelKey = lib.hasPrefix "Wheel";
wheelCooldownMs = 100;
windowBindings = lib.mkMerge (
lib.concatLists (
lib.mapAttrsToList (
direction: cfg:
(lib.lists.map (
key:
let
cooldown-ms = lib.mkIf (isWheelKey key) wheelCooldownMs;
in
{
"Mod+${key}" = {
action."focus-${cfg.windowTerm}-${direction}" = [ ];
inherit cooldown-ms;
};
"Mod+${modMove}+${key}" = {
action."move-${cfg.windowTerm}-${direction}" = [ ];
inherit cooldown-ms;
};
"Mod+${modMonitor}+${key}" = {
action."focus-monitor-${direction}" = [ ];
inherit cooldown-ms;
};
"Mod+${modMove}+${modMonitor}+${key}" = {
action."move-column-to-monitor-${direction}" = [ ];
inherit cooldown-ms;
};
}
) cfg.keys)
) directions
)
);
indexedWorkspaceBindings = lib.mkMerge (
map (index: {
"Mod+${toString index}" = {
action.focus-workspace = [ index ];
};
"Mod+${modMove}+${toString index}" = {
action.move-column-to-workspace = [ index ];
};
}) workspaceIndices
);
specialBindings = {
"Mod+W".action.spawn = cfg.browser;
"Mod+Return".action.spawn = cfg.terminal;
"Mod+D".action.spawn = [ "fuzzel" ];
"Mod+M".action.spawn = [ "swaylock" ];
"Mod+V".action.spawn = [ "cliphist-fuzzel" ];
"XF86AudioRaiseVolume" = {
allow-when-locked = true;
action.spawn = [
"${pkgs.pulsemixer}/bin/pulsemixer"
"--change-volume"
"+5"
];
};
"XF86AudioLowerVolume" = {
allow-when-locked = true;
action.spawn = [
"${pkgs.pulsemixer}/bin/pulsemixer"
"--change-volume"
"-5"
];
};
"XF86AudioMute" = {
allow-when-locked = true;
action.spawn = [
"${pkgs.pulsemixer}/bin/pulsemixer"
"--toggle-mute"
];
};
"Mod+P".action.spawn = [
"${pkgs.playerctl}/bin/playerctl"
"play-pause"
];
"Mod+I".action.spawn = [
"${pkgs.playerctl}/bin/playerctl"
"previous"
];
"Mod+O".action.spawn = [
"${pkgs.playerctl}/bin/playerctl"
"next"
];
"Mod+Shift+Q".action.close-window = [ ];
"Mod+Tab".action.focus-workspace-previous = [ ];
"Mod+C".action.center-column = [ ];
"Mod+Comma".action.consume-window-into-column = [ ];
"Mod+Period".action.expel-window-from-column = [ ];
"Mod+BracketLeft".action.consume-or-expel-window-left = [ ];
"Mod+BracketRight".action.consume-or-expel-window-right = [ ];
"Mod+R".action.switch-preset-column-width = [ ];
"Mod+Shift+R".action.reset-window-height = [ ];
"Mod+F".action.maximize-column = [ ];
"Mod+Shift+F".action.fullscreen-window = [ ];
"Mod+Minus".action.set-column-width = [ "-10%" ];
"Mod+Equal".action.set-column-width = [ "+10%" ];
"Mod+Shift+Minus".action.set-window-height = [ "-10%" ];
"Mod+Shift+Equal".action.set-window-height = [ "+10%" ];
"Mod+Shift+S".action.screenshot = [ ];
"Mod+Ctrl+S".action.screenshot-window = [ ];
"Mod+Shift+E".action.quit = [ ];
};
in
lib.mkMerge [
windowBindings
indexedWorkspaceBindings
specialBindings
];
cursor = {
theme = config.theme.cursorTheme;
size = config.theme.cursorSize;
};
};
};
home.packages = with pkgs; [
(hiPrio (writeShellApplication {
name = "wayland-session";
runtimeInputs = [ cfg.package ];
text = ''
niri-session
'';
}))
cfg.package
wl-clipboard
];
}
# xdg-desktop-portal
{
xdg.portal = {
enable = true;
extraPortals = with pkgs; [
xdg-desktop-portal-gtk
xdg-desktop-portal-gnome
];
config = {
common = {
"default" = [
"gnome"
"gtk"
];
"org.freedesktop.impl.portal.Secret" = [ "gnome-keyring" ];
};
};
};
home.packages = with pkgs; [
xdg-utils
];
}
# xwayland
(lib.mkIf cfg.xwayland {
systemd.user.services.xwayland-satellite = {
Unit = {
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
Requisite = [ "graphical-session.target" ];
};
Install.WantedBy = [ "graphical-session.target" ];
Service = {
Type = "simple";
ExecStart = "${lib.getExe pkgs.xwayland-satellite} :1";
NotifyAccess = "all";
StandardOutput = "journal";
Restart = "on-failure";
};
};
programs.niri.settings.environment = lib.singleton {
DISPLAY = ":1";
};
})
];
}

View file

@ -0,0 +1,5 @@
{
systemd.user.sessionVariables = {
QT_QPA_PLATFORMTHEME = "gtk3";
};
}

View file

@ -0,0 +1,46 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/home.nix
{
config,
pkgs,
lib,
...
}:
let
mkBlurredWallpaper =
mode:
pkgs.runCommand "wallpaper-blurred-${mode}" { nativeBuildInputs = with pkgs; [ imagemagick ]; } ''
magick convert -blur 14x5 ${config.theme.${mode}.wallpaper} $out
'';
in
{
programs.swaylock = {
enable = true;
settings = {
show-failed-attempts = true;
daemonize = true;
image = "~/.config/swaylock/image";
scaling = "fill";
};
};
systemd.user.tmpfiles.rules = [
"L %h/.config/swaylock/image - - - - ${mkBlurredWallpaper "light"}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-swaylock-${mode}";
text = ''
ln --force --symbolic --verbose "${mkBlurredWallpaper mode}" "$HOME/.config/swaylock/image"
'';
};
in
{
lightModeScripts.swaylock = "${lib.getExe (mkScript "light")}";
darkModeScripts.swaylock = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,54 @@
{
config,
pkgs,
lib,
...
}:
let
swww = pkgs.swww;
in
{
systemd.user.services.swww-daemon = {
Unit = {
Description = "A Solution to your Wayland Wallpaper Woes";
Documentation = "https://github.com/LGFae/swww";
PartOf = [ "graphical-session.target" ];
After = [ "graphical-session.target" ];
Requisite = [ "graphical-session.target" ];
};
Service = {
ExecStart = "${swww}/bin/swww-daemon --no-cache";
ExecStartPost = "${swww}/bin/swww img %h/.config/swww/wallpaper";
Restart = "on-failure";
KillMode = "mixed";
};
Install.WantedBy = [ "graphical-session.target" ];
};
systemd.user.tmpfiles.rules = [
"L %h/.config/swww/wallpaper - - - - ${config.theme.light.wallpaper}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-swww-${mode}";
text = ''
if ! ${config.systemd.user.systemctlPath} --user is-active swww-daemon; then
echo "swww-daemon is not active"
exit 1
fi
ln --force --symbolic --verbose "${config.theme.${mode}.wallpaper}" "$HOME/.config/swww/wallpaper"
${swww}/bin/swww img ~/.config/swww/wallpaper
'';
};
in
{
lightModeScripts.swww = "${lib.getExe (mkScript "light")}";
darkModeScripts.swww = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,6 @@
{ ... }:
{
services.syncthing.enable = true;
home.globalPersistence.directories = [ ".local/state/syncthing" ];
}

View file

@ -0,0 +1,31 @@
# This file is sourced from https://github.com/tinted-theming/schemes/tree/spec-0.11/base24
system = "base24"
name = "Catppuccin Frappe"
author = "https://github.com/catppuccin/catppuccin"
variant = "dark"
[palette]
base00 = "#303446"
base01 = "#292c3c"
base02 = "#414559"
base03 = "#51576d"
base04 = "#626880"
base05 = "#c6d0f5"
base06 = "#f2d5cf"
base07 = "#babbf1"
base08 = "#e78284"
base09 = "#ef9f76"
base0A = "#e5c890"
base0B = "#a6d189"
base0C = "#81c8be"
base0D = "#8caaee"
base0E = "#ca9ee6"
base0F = "#eebebe"
base10 = "#292c3c"
base11 = "#232634"
base12 = "#ea999c"
base13 = "#f2d5cf"
base14 = "#a6d189"
base15 = "#99d1db"
base16 = "#85c1dc"
base17 = "#f4b8e4"

View file

@ -0,0 +1,31 @@
# This file is sourced from https://github.com/tinted-theming/schemes/tree/spec-0.11/base24
system = "base24"
name = "Catppuccin Latte"
author = "https://github.com/catppuccin/catppuccin"
variant = "light"
[palette]
base00 = "#eff1f5"
base01 = "#e6e9ef"
base02 = "#ccd0da"
base03 = "#bcc0cc"
base04 = "#acb0be"
base05 = "#4c4f69"
base06 = "#dc8a78"
base07 = "#7287fd"
base08 = "#d20f39"
base09 = "#fe640b"
base0A = "#df8e1d"
base0B = "#40a02b"
base0C = "#179299"
base0D = "#1e66f5"
base0E = "#8839ef"
base0F = "#dd7878"
base10 = "#e6e9ef"
base11 = "#dce0e8"
base12 = "#e64553"
base13 = "#dc8a78"
base14 = "#40a02b"
base15 = "#04a5e5"
base16 = "#209fb5"
base17 = "#ea76cb"

View file

@ -0,0 +1,31 @@
# This file is sourced from https://github.com/tinted-theming/schemes/tree/spec-0.11/base24
system = "base24"
name = "Catppuccin Macchiato"
author = "https://github.com/catppuccin/catppuccin"
variant = "dark"
[palette]
base00 = "#24273a"
base01 = "#1e2030"
base02 = "#363a4f"
base03 = "#494d64"
base04 = "#5b6078"
base05 = "#cad3f5"
base06 = "#f4dbd6"
base07 = "#b7bdf8"
base08 = "#ed8796"
base09 = "#f5a97f"
base0A = "#eed49f"
base0B = "#a6da95"
base0C = "#8bd5ca"
base0D = "#8aadf4"
base0E = "#c6a0f6"
base0F = "#f0c6c6"
base10 = "#1e2030"
base11 = "#181926"
base12 = "#ee99a0"
base13 = "#f4dbd6"
base14 = "#a6da95"
base15 = "#91d7e3"
base16 = "#7dc4e4"
base17 = "#f5bde6"

View file

@ -0,0 +1,31 @@
# This file is sourced from https://github.com/tinted-theming/schemes/tree/spec-0.11/base24
system = "base24"
name = "Catppuccin Mocha"
author = "https://github.com/catppuccin/catppuccin"
variant = "dark"
[palette]
base00 = "#1e1e2e"
base01 = "#181825"
base02 = "#313244"
base03 = "#45475a"
base04 = "#585b70"
base05 = "#cdd6f4"
base06 = "#f5e0dc"
base07 = "#b4befe"
base08 = "#f38ba8"
base09 = "#fab387"
base0A = "#f9e2af"
base0B = "#a6e3a1"
base0C = "#94e2d5"
base0D = "#89b4fa"
base0E = "#cba6f7"
base0F = "#f2cdcd"
base10 = "#181825"
base11 = "#11111b"
base12 = "#eba0ac"
base13 = "#f5e0dc"
base14 = "#a6e3a1"
base15 = "#89dceb"
base16 = "#74c7ec"
base17 = "#f5c2e7"

View file

@ -0,0 +1,48 @@
{ pkgs, ... }:
let
importBase24Theme =
file:
let
inherit (builtins.fromTOML (builtins.readFile file)) palette;
in
builtins.mapAttrs (_name: value: builtins.substring 1 6 value) palette;
in
{
theme = {
cursorTheme = "capitaine-cursors-white";
cursorSize = 36;
light = {
iconTheme = "Papirus-Light";
gtkTheme = "catppuccin-latte-blue-compact";
wallpaper = "${pkgs.nixos-artwork.wallpapers.nineish}/share/backgrounds/nixos/nix-wallpaper-nineish.png";
kittyTheme = "${pkgs.kitty-themes}/share/kitty-themes/themes/Catppuccin-Latte.conf";
helixTheme = "${pkgs.helix}/lib/runtime/themes/catppuccin_latte.toml";
base24Theme = importBase24Theme ./catppuccin-latte.toml;
};
dark = {
iconTheme = "Papirus-Dark";
gtkTheme = "catppuccin-frappe-blue-compact";
wallpaper = "${pkgs.nixos-artwork.wallpapers.nineish-dark-gray}/share/backgrounds/nixos/nix-wallpaper-nineish-dark-gray.png";
kittyTheme = "${pkgs.kitty-themes}/share/kitty-themes/themes/Catppuccin-Frappe.conf";
helixTheme = "${pkgs.helix}/lib/runtime/themes/catppuccin_frappe.toml";
base24Theme = importBase24Theme ./catppuccin-frappe.toml;
};
};
home.packages = with pkgs; [
papirus-icon-theme
capitaine-cursors
(catppuccin-gtk.override {
accents = [ "blue" ];
size = "compact";
variant = "latte";
})
(catppuccin-gtk.override {
accents = [ "blue" ];
size = "compact";
variant = "frappe";
})
];
}

View file

@ -0,0 +1,73 @@
{ pkgs, lib, ... }:
{
programs.tmux = {
enable = true;
baseIndex = 1;
escapeTime = 10;
keyMode = "vi";
terminal = "tmux-256color";
historyLimit = 50000;
plugins = with pkgs.tmuxPlugins; [
yank
open
];
extraConfig = ''
set -g set-clipboard on
set -g mouse on
set -g status-right ""
set -g renumber-windows on
set -g bell-action none
# keybind
bind \; command-prompt
bind p paste-buffer
bind C-p choose-buffer
# pane
bind k select-pane -U
bind j select-pane -D
bind h select-pane -L
bind l select-pane -R
bind -r C-k resize-pane -U 5
bind -r C-j resize-pane -D 5
bind -r C-h resize-pane -L 5
bind -r C-l resize-pane -R 5
# copy mode
bind Escape copy-mode
bind -T copy-mode-vi k send -X cursor-up
bind -T copy-mode-vi K send -N 5 -X cursor-up
bind -T copy-mode-vi j send -X cursor-down
bind -T copy-mode-vi J send -N 5 -X cursor-down
bind -T copy-mode-vi h send -X cursor-left
bind -T copy-mode-vi H send -N 5 -X cursor-left
bind -T copy-mode-vi C-h send -X start-of-line
bind -T copy-mode-vi l send -X cursor-right
bind -T copy-mode-vi L send -N 5 -X cursor-right
bind -T copy-mode-vi C-l send -X end-of-line
bind -T copy-mode-vi v send -X begin-selection
# window
bind -r [ previous-window
bind -r ] next-window
bind -r C-[ swap-window -d -t -1
bind -r C-] swap-window -d -t +1
bind -r - split-window -h -c "#{pane_current_path}"
bind -r = split-window -v -c "#{pane_current_path}"
bind C-x kill-window
bind c new-window -c "#{pane_current_path}"
bind r command-prompt "rename-window %%"
# session
bind q confirm-before -p "kill-session #S? (y/n)" kill-session
bind R command-prompt "rename-session %%"
# image preview
set -g allow-passthrough on
set -ga update-environment TERM
set -ga update-environment TERM_PROGRAM
'';
};
programs.kitty.settings.shell = lib.mkDefault "tmux";
}

View file

@ -0,0 +1,57 @@
{
pkgs,
...
}:
{
height = 36;
layer = "top";
"niri/window" = {
format = "{}";
max-length = 80;
};
"wlr/taskbar" = {
all-outputs = false;
on-click = "activate";
on-click-middle = "close";
};
tray = {
icon-size = 18;
spacing = 10;
};
clock = {
format = "{:%a %b %d %H:%M}";
};
network = {
interval = 1;
format = "{ifname}";
format-wifi = "󰇚 {bandwidthDownBytes} 󰕒 {bandwidthUpBytes}";
format-ethernet = "󰇚 {bandwidthDownBytes} 󰕒 {bandwidthUpBytes}";
format-disconnected = "";
tooltip-format = "{ifname} via {gwaddr}";
tooltip-format-wifi = "{essid} {signalStrength}%";
tooltip-format-ethernet = "{ifname}";
tooltip-format-disconnected = "disconnected";
max-length = 40;
};
pulseaudio = {
format = "{icon} {volume}% {format_source}";
format-bluetooth = "󰂯 {volume}% {format_source}";
format-bluetooth-muted = "󰝟 {volume}% {format_source}";
format-icons = {
headphone = "󰋋";
default = [
"󰖀"
"󰕾"
];
};
format-muted = "󰝟 {volume}% {format_source}";
format-source = " {volume}%";
format-source-muted = " {volume}%";
on-click = "${pkgs.pavucontrol}/bin/pavucontrol";
};
"custom/nixos" = {
format = "";
interval = "once";
tooltip = false;
};
}

View file

@ -0,0 +1,49 @@
{
config,
pkgs,
lib,
...
}:
let
mkTheme =
mode:
let
inherit (config.theme.${mode}) base24Theme;
in
pkgs.writeText "waybar-style-${mode}.css" (import ./_style.nix base24Theme);
in
{
programs.waybar = {
enable = true;
systemd.enable = true;
};
systemd.user.services.waybar = {
Unit = {
ConditionEnvironment = lib.singleton "WAYLAND_DISPLAY";
Requisite = lib.singleton "graphical-session.target";
After = lib.singleton "graphical-session.target";
};
};
systemd.user.tmpfiles.rules = [
"L %h/.config/waybar/style.css - - - - ${mkTheme "light"}"
];
services.darkman =
let
mkScript =
mode:
pkgs.writeShellApplication {
name = "darkman-switch-waybar-${mode}";
text = ''
ln --force --symbolic --verbose "${mkTheme mode}" "$HOME/.config/waybar/style.css"
pkill -u "$USER" -USR2 waybar || true
'';
};
in
{
lightModeScripts.waybar = "${lib.getExe (mkScript "light")}";
darkModeScripts.waybar = "${lib.getExe (mkScript "dark")}";
};
}

View file

@ -0,0 +1,72 @@
{
base00,
base02,
base05,
base07,
base0A,
...
}:
''
* {
border: none;
border-radius: 0;
font-family: 'RobotoMono Nerd Font', 'sans';
font-size: 11pt;
font-weight: bold;
min-height: 0;
color: #${base05};
}
window#waybar {
padding: 0pt;
opacity: 0.95;
color: #${base05};
background: #${base00};
border-bottom: 2pt solid #${base02};
}
window#waybar.hidden {
opacity: 0.0;
}
#workspaces button {
padding: 0pt;
background: transparent;
color: #${base05};
border-bottom: 2pt solid transparent;
}
#workspaces button.focused,
#workspaces button.active {
background: #${base02};
border-bottom: 2pt solid #${base07};
}
#workspaces button.urgent {
background: #${base0A};
}
#custom-nixos {
padding-left: 12pt;
padding-right: 15pt;
}
#window {
padding: 0pt 8pt;
}
#clock,
#tray,
#network,
#pulseaudio {
margin: 0pt 0pt;
padding: 0pt 8pt;
}
#clock,
#tray,
#network,
#pulseaudio {
border-left: 2pt solid #${base02};
}
''

View file

@ -0,0 +1,32 @@
{
config,
pkgs,
lib,
...
}:
let
args = {
inherit config pkgs lib;
};
in
{
imports = lib.singleton ./_default.nix;
programs.waybar.settings = lib.singleton (
{
position = "top";
modules-left = [
"custom/nixos"
"niri/workspaces"
"niri/window"
];
modules-right = [
"network"
"pulseaudio"
"clock"
"tray"
];
}
// (import ./_common.nix args)
);
}

View file

@ -0,0 +1,23 @@
{ ... }:
{
xdg.userDirs = {
enable = true;
createDirectories = true;
desktop = "/var/empty";
documents = "$HOME/Documents";
download = "$HOME/Downloads";
music = "$HOME/Music";
pictures = "$HOME/Pictures";
publicShare = "/var/empty";
templates = "/var/empty";
videos = "$HOME/Videos";
};
home.globalPersistence.directories = [
"Documents"
"Downloads"
"Music"
"Pictures"
"Videos"
];
}

View file

@ -0,0 +1,116 @@
{ ... }:
{
programs.yazi = {
enable = true;
enableBashIntegration = true;
enableFishIntegration = true;
shellWrapperName = "ra";
settings = {
manager = {
sort_by = "natural";
linemode = "size";
};
preview = {
tab_size = 2;
max_width = 1000;
max_height = 1000;
};
open.rules = [
{
name = "*/";
use = [
"open"
"edit"
"reveal"
];
}
{
mime = "text/*";
use = [
"edit"
"reveal"
];
}
{
mime = "{image,audio,video}/*";
use = [
"open"
"reveal"
];
}
{
mime = "application/{,g}zip";
use = [
"extract"
"reveal"
];
}
{
mime = "application/x-{tar,bzip*,7z-compressed,xz,rar}";
use = [
"extract"
"reveal"
];
}
{
mime = "application/{json,x-ndjson}";
use = [
"edit"
"reveal"
];
}
{
mime = "*/javascript";
use = [
"edit"
"reveal"
];
}
{
mime = "inode/x-empty";
use = [
"edit"
"reveal"
];
}
{
name = "*";
use = [
"open"
"reveal"
];
}
];
};
keymap = {
manager.prepend_keymap = [
{
on = [ "J" ];
run = "arrow 5";
}
{
on = [ "K" ];
run = "arrow -5";
}
{
on = [ "<C-j>" ];
run = "seek 5";
}
{
on = [ "<C-k>" ];
run = "seek -5";
}
];
input.prepend_keymap = [
{
on = [ "H" ];
run = "move -5";
}
{
on = [ "L" ];
run = "move 5";
}
];
};
};
}

3
infra/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/.terraform
/terraform.tfstate.*
/.terraform.lock.hcl

14
infra/backend.tf Normal file
View file

@ -0,0 +1,14 @@
terraform {
backend "local" {
path = "terraform.tfstate"
}
encryption {
method "aes_gcm" "default" {
keys = key_provider.pbkdf2.default
}
state {
method = method.aes_gcm.default
enforced = true
}
}
}

27
infra/enthalpy.tf Normal file
View file

@ -0,0 +1,27 @@
locals {
enthalpy_network_prefix = "fde3:3be3:a244::/48"
enthalpy_organizations = {
core = "rebmit's core network"
edge = "rebmit's edge network"
}
}
resource "tls_private_key" "enthalpy" {
for_each = local.enthalpy_organizations
algorithm = "ED25519"
}
output "enthalpy_network_prefix" {
value = local.enthalpy_network_prefix
sensitive = false
}
output "enthalpy_organizations" {
value = local.enthalpy_organizations
sensitive = false
}
output "enthalpy_public_key_pem" {
value = { for k, v in tls_private_key.enthalpy : k => trimspace(v.public_key_pem) }
sensitive = false
}

63
infra/hosts.tf Normal file
View file

@ -0,0 +1,63 @@
locals {
hosts = {
"flandre-m5p" = {
endpoints_v4 = []
endpoints_v6 = []
enthalpy_node_id = parseint("a23", 16)
enthalpy_node_organization = "edge"
}
"marisa-7d76" = {
endpoints_v4 = []
endpoints_v6 = []
enthalpy_node_id = parseint("d79", 16)
enthalpy_node_organization = "edge"
}
"marisa-a7s" = {
endpoints_v4 = []
endpoints_v6 = []
enthalpy_node_id = parseint("572", 16)
enthalpy_node_organization = "edge"
}
"reisen-sin0" = {
endpoints_v4 = ["194.156.163.233"]
endpoints_v6 = ["2407:b9c0:e002:20b:26a3:f0ff:fe46:a4d0"]
enthalpy_node_id = parseint("267", 16)
enthalpy_node_organization = "core"
}
"reisen-lax0" = {
endpoints_v4 = ["38.175.109.149"]
endpoints_v6 = ["2a0e:6901:110:276:5054:ff:fe81:ec3b"]
enthalpy_node_id = null
enthalpy_node_organization = null
}
}
}
module "hosts" {
source = "./modules/host"
for_each = local.hosts
name = each.key
endpoints_v4 = each.value.endpoints_v4
endpoints_v6 = each.value.endpoints_v6
enthalpy_network_prefix = local.enthalpy_network_prefix
enthalpy_organizations = local.enthalpy_organizations
enthalpy_private_key = tls_private_key.enthalpy
enthalpy_node_id = each.value.enthalpy_node_id
enthalpy_node_organization = each.value.enthalpy_node_organization
}
output "hosts" {
value = module.hosts
sensitive = true
}
output "hosts_non_sensitive" {
value = {
for host, outputs in module.hosts :
host => {
for name, output in outputs :
name => output if !issensitive(output)
}
}
sensitive = false
}

View file

@ -0,0 +1,22 @@
variable "endpoints_v4" {
type = list(string)
}
variable "endpoints_v6" {
type = list(string)
}
output "endpoints" {
value = concat(var.endpoints_v4, var.endpoints_v6)
sensitive = false
}
output "endpoints_v4" {
value = var.endpoints_v4
sensitive = false
}
output "endpoints_v6" {
value = var.endpoints_v6
sensitive = false
}

View file

@ -0,0 +1,55 @@
variable "enthalpy_network_prefix" {
type = string
}
variable "enthalpy_organizations" {
type = map(string)
}
variable "enthalpy_private_key" {
type = map(object({
private_key_pem = string
}))
}
variable "enthalpy_node_id" {
type = number
}
variable "enthalpy_node_organization" {
type = string
}
locals {
enthalpy_network_prefix_length = tonumber(regex(".*/([[:digit:]]+)", var.enthalpy_network_prefix)[0])
enthalpy_node_enabled = var.enthalpy_node_id != null && var.enthalpy_node_organization != null
enthalpy_node_organization = local.enthalpy_node_enabled ? var.enthalpy_organizations[var.enthalpy_node_organization] : null
enthalpy_node_private_key_pem = local.enthalpy_node_enabled ? var.enthalpy_private_key[var.enthalpy_node_organization].private_key_pem : null
enthalpy_node_prefix = local.enthalpy_node_enabled ? cidrsubnet(var.enthalpy_network_prefix, 60 - local.enthalpy_network_prefix_length, var.enthalpy_node_id) : null
enthalpy_node_address = local.enthalpy_node_enabled ? cidrhost(local.enthalpy_node_prefix, 1) : null
}
output "enthalpy_node_id" {
value = var.enthalpy_node_id
sensitive = false
}
output "enthalpy_node_organization" {
value = local.enthalpy_node_organization
sensitive = false
}
output "enthalpy_node_private_key_pem" {
value = local.enthalpy_node_private_key_pem
sensitive = true
}
output "enthalpy_node_prefix" {
value = local.enthalpy_node_prefix
sensitive = false
}
output "enthalpy_node_address" {
value = local.enthalpy_node_address
sensitive = false
}

View file

@ -0,0 +1,3 @@
variable "name" {
type = string
}

View file

@ -0,0 +1,28 @@
resource "tls_private_key" "host_rsa" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "tls_private_key" "host_ed25519" {
algorithm = "ED25519"
}
output "ssh_host_rsa_key_pub" {
value = trimspace(tls_private_key.host_rsa.public_key_openssh)
sensitive = false
}
output "ssh_host_rsa_key" {
value = tls_private_key.host_rsa.private_key_openssh
sensitive = true
}
output "ssh_host_ed25519_key_pub" {
value = trimspace(tls_private_key.host_ed25519.public_key_openssh)
sensitive = false
}
output "ssh_host_ed25519_key" {
value = tls_private_key.host_ed25519.private_key_openssh
sensitive = true
}

View file

@ -0,0 +1,7 @@
terraform {
required_providers {
tls = {
source = "registry.terraform.io/hashicorp/tls"
}
}
}

10
infra/providers.tf Normal file
View file

@ -0,0 +1,10 @@
terraform {
required_providers {
sops = {
source = "registry.terraform.io/carlpett/sops"
}
tls = {
source = "registry.terraform.io/hashicorp/tls"
}
}
}

7
infra/secrets.tf Normal file
View file

@ -0,0 +1,7 @@
data "sops_file" "secrets" {
source_file = "secrets.yaml"
}
locals {
secrets = yamldecode(data.sops_file.secrets.raw)
}

21
infra/secrets.yaml Normal file
View file

@ -0,0 +1,21 @@
tofu: ENC[AES256_GCM,data:wv2zsYRcwM8boVYSaH4EtI4poL/modLixJ8gDoP1T7+JLDyCRyZQsu6WkMR9JPJrRsbMvQ2tFFrk8LPZU2hhh6BqqPX/ZlYUAmAQACuZa1JnUYeskc2TLVNkaL9Glz+cpfylyHQr0ARwEw5Q/cWdC1Xg55pnRFmVOQSY9Sf9asE6fxZ0JIAMPQeVTCe+CQ==,iv:O3smIEUNBPh4pAGUgbnKqLrqjCCK+ZRzVa9mnx9P4s0=,tag:Iv8UFwnUKTUgU+YFQ3gaqg==,type:str]
sops:
kms: []
gcp_kms: []
azure_kv: []
hc_vault: []
age:
- recipient: age1sfnct03u4cvfj98x4yjrcrrnu5gg8qgxrwk4uqq8w4e6wveeaedq97rn44
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArdnlvV09oUWNERmJyM0ZW
WStza2xMdm1JTVRzR0ZBcFlwOFdxamZQMmdZCkVIZG1HOVNla3RQbjRzNmlUUDRX
YitxTXQwUVUzb1JHbEI3NFlMbjI0MmMKLS0tIDRkdjhCcWRNYTkyYWJwUmZENjh3
Rk1mSHZicDNuVVFpL1NMcS9NS0NmRXcKT2GiNJ8L2ADuoJPm5XF1SrkNZtEzh/i5
8gGmswWnE+d7VM0BSnM64la/E4prcIhM4e4Ybyd8El6pwQN919gofQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2024-11-23T07:54:24Z"
mac: ENC[AES256_GCM,data:03Bina9HvdovMlUBceqa321L628AR89knW+6wB1Do6fPv3JgDjnSByqq7uewzLms+npVJY6Vj1VtWfwplgnd/UZvvoE0m9yu0Kmv+hOKy5eF5gI+G43j9YKoGzFnqIV+pCXZBF0gqBU+7qpGz3w3C82CG5uHbd6hEQyS0rqDnHA=,iv:lYvY105TcODa3wwmQTJbPxoN3eam6RDNR2ZTI3I3zXw=,tag:h6FNgpN1Kj7sM1gSKZKE0g==,type:str]
pgp: []
unencrypted_suffix: _unencrypted
version: 3.9.1

1
infra/terraform.tfstate Normal file

File diff suppressed because one or more lines are too long

51
justfile Normal file
View file

@ -0,0 +1,51 @@
set shell := ["bash", "-c"]
[linux]
[group('nix')]
remote name:
nixos-rebuild switch --flake .#{{name}} --target-host root@{{name}} --verbose --show-trace
[linux]
[group('nix')]
local name:
nixos-rebuild switch --use-remote-sudo --flake .#{{name}} --verbose --show-trace
[group('nix')]
up:
nix flake update
[group('nix')]
upp input:
nix flake lock --update-input {{input}}
[group('nix')]
history:
nix profile diff-closures --profile /nix/var/nix/profiles/system
[group('nix')]
repl:
nix repl -f flake:nixpkgs
[linux]
[group('infra')]
plan:
tofu -chdir="infra" plan
[linux]
[group('infra')]
apply:
tofu -chdir="infra" apply
[linux]
[group('infra')]
zone:
tofu -chdir="infra" output -json | jq -f zones/data.jq > zones/data.json
cat zones/data.json | jq -f zones/registry.jq > zones/registry.json
[linux]
[group('infra')]
secret name:
nix eval --raw .#nixosConfigurations.{{name}}.config.sops.opentofuTemplate > test.json
tofu -chdir="infra" output -json | jq -f test.json > secrets/hosts/opentofu/{{name}}.yaml
sops --input-type json --output-type yaml --in-place --encrypt secrets/hosts/opentofu/{{name}}.yaml
rm -i test.json

View file

@ -0,0 +1,10 @@
{
suites,
mylib,
...
}:
{
imports = suites.server ++ (mylib.path.scanPaths ./. "default.nix");
system.stateVersion = "24.05";
}

View file

@ -0,0 +1,84 @@
{
disko.devices = {
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"defaults"
"size=8G"
"mode=755"
"nosuid"
"nodev"
];
};
};
disk = {
main = {
type = "disk";
device = "/dev/disk/by-path/pci-0000:04:00.0-nvme-1";
content = {
type = "gpt";
partitions = {
esp = {
label = "ESP";
size = "2G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
cryptroot = {
label = "CRYPTROOT";
size = "100%";
content = {
type = "luks";
name = "cryptroot";
settings = {
allowDiscards = true;
bypassWorkqueues = true;
crypttabExtraOpts = [
"same-cpu-crypt"
"submit-from-crypt-cpus"
];
# unattended boot via usb
keyFile = "/dev/disk/by-id/usb-aigo_U330_80101016-0:0";
keyFileSize = 512 * 64;
};
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"/persist" = {
mountpoint = "/persist";
mountOptions = [ "compress=zstd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" ];
};
};
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = true;
environment.globalPersistence = {
enable = true;
root = "/persist";
};
services.btrfs.autoScrub = {
enable = true;
interval = "weekly";
fileSystems = [ "/persist" ];
};
}

View file

@ -0,0 +1,26 @@
{ ... }:
{
boot = {
initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"usbhid"
"usb_storage"
"sd_mod"
];
kernelModules = [ "kvm-amd" ];
loader = {
efi.canTouchEfiVariables = false;
systemd-boot.enable = true;
};
};
networking.wireless.iwd.enable = true;
hardware = {
amdgpu.initrd.enable = true;
cpu.amd.updateMicrocode = true;
enableRedistributableFirmware = true;
graphics.enable = true;
};
}

View file

@ -0,0 +1,67 @@
{ profiles, lib, ... }:
{
imports = with profiles; [
services.enthalpy
];
services.enthalpy.ipsec.interfaces = [ "enp2s0" ];
systemd.network = {
enable = true;
wait-online.anyInterface = true;
config = {
networkConfig = {
IPv4Forwarding = true;
IPv6Forwarding = true;
};
};
networks = {
"30-enp1s0" = {
matchConfig.Name = "enp1s0";
networkConfig = {
DHCPServer = "yes";
IPv6SendRA = "yes";
IPv6PrivacyExtensions = true;
IPv6AcceptRA = "no";
KeepConfiguration = true;
};
dhcpServerConfig = {
ServerAddress = "100.64.0.1/20";
EmitDNS = true;
};
ipv6Prefixes = lib.singleton {
Prefix = "fdce:2962:c3c1:130c::/64";
Assign = true;
};
};
"30-enp2s0" = {
matchConfig.Name = "enp2s0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = true;
KeepConfiguration = true;
};
dhcpV4Config.RouteMetric = 1024;
dhcpV6Config.RouteMetric = 1024;
ipv6AcceptRAConfig.RouteMetric = 1024;
};
};
};
networking.nftables.tables.nat = {
family = "inet";
content = ''
chain input {
type filter hook input priority mangle; policy accept;
iifname enp2s0 tcp dport { http, https } counter drop
iifname enp2s0 udp dport { http, https } counter drop
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname enp2s0 counter masquerade
}
'';
};
}

View file

@ -0,0 +1,31 @@
{
suites,
profiles,
mylib,
...
}:
{
imports =
suites.workstation
++ [
profiles.system.boot.binfmt
profiles.system.boot.secure-boot
profiles.users.rebmit
]
++ (mylib.path.scanPaths ./. "default.nix");
home-manager.users.rebmit =
{ suites, profiles, ... }:
{
imports = suites.desktop-workstation ++ [
profiles.syncthing
];
programs.niri.settings = {
input.tablet.map-to-output = "HDMI-A-1";
outputs."HDMI-A-1".scale = 1.75;
};
};
system.stateVersion = "24.05";
}

View file

@ -0,0 +1,81 @@
{
disko.devices = {
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"defaults"
"size=8G"
"mode=755"
"nosuid"
"nodev"
];
};
};
disk = {
main = {
type = "disk";
device = "/dev/disk/by-path/pci-0000:04:00.0-nvme-1";
content = {
type = "gpt";
partitions = {
esp = {
label = "ESP";
size = "2G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
cryptroot = {
label = "CRYPTROOT";
size = "100%";
content = {
type = "luks";
name = "cryptroot";
settings = {
allowDiscards = true;
bypassWorkqueues = true;
crypttabExtraOpts = [
"same-cpu-crypt"
"submit-from-crypt-cpus"
];
};
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"/persist" = {
mountpoint = "/persist";
mountOptions = [ "compress=zstd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" ];
};
};
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = true;
environment.globalPersistence = {
enable = true;
root = "/persist";
};
services.btrfs.autoScrub = {
enable = true;
interval = "weekly";
fileSystems = [ "/persist" ];
};
}

View file

@ -0,0 +1,34 @@
{ lib, ... }:
{
boot = {
initrd.availableKernelModules = [
"nvme"
"ahci"
"xhci_pci"
"usbhid"
"sd_mod"
];
kernelModules = [ "kvm-amd" ];
loader = {
efi.canTouchEfiVariables = true;
systemd-boot.enable = lib.mkDefault true;
};
};
networking.wireless.iwd.enable = true;
hardware = {
amdgpu.initrd.enable = true;
cpu.amd.updateMicrocode = true;
enableRedistributableFirmware = true;
graphics.enable = true;
};
services = {
udev.extraHwdb = ''
evdev:input:b*v046Dp4089*
KEYBOARD_KEY_70039=esc
KEYBOARD_KEY_70029=capslock
'';
};
}

View file

@ -0,0 +1,46 @@
{ profiles, lib, ... }:
{
imports = with profiles; [
services.enthalpy
];
services.enthalpy = {
ipsec.interfaces = [ "enp14s0" ];
sing-box = {
enable = true;
clat = {
enable = true;
segment = lib.singleton "fde3:3be3:a244:2676::2";
};
};
};
systemd.network = {
enable = true;
wait-online.anyInterface = true;
networks = {
"30-enp14s0" = {
matchConfig.Name = "enp14s0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = true;
};
dhcpV4Config.RouteMetric = 1024;
dhcpV6Config.RouteMetric = 1024;
ipv6AcceptRAConfig.RouteMetric = 1024;
};
"40-wlan0" = {
matchConfig.Name = "wlan0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = true;
};
dhcpV4Config.RouteMetric = 2048;
dhcpV6Config.RouteMetric = 2048;
ipv6AcceptRAConfig.RouteMetric = 2048;
};
};
};
}

View file

@ -0,0 +1,30 @@
{
suites,
profiles,
mylib,
...
}:
{
imports =
suites.workstation
++ [
profiles.users.rebmit
]
++ (mylib.path.scanPaths ./. "default.nix");
home-manager.users.rebmit =
{ suites, profiles, ... }:
{
imports = suites.desktop-workstation ++ [
profiles.syncthing
];
programs.niri.settings = {
outputs."eDP-1".scale = 1.2;
};
};
services.power-profiles-daemon.enable = true;
system.stateVersion = "24.05";
}

View file

@ -0,0 +1,81 @@
{
disko.devices = {
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"defaults"
"size=8G"
"mode=755"
"nosuid"
"nodev"
];
};
};
disk = {
main = {
type = "disk";
device = "/dev/disk/by-path/pci-0000:04:00.0-nvme-1";
content = {
type = "gpt";
partitions = {
esp = {
label = "ESP";
size = "2G";
type = "EF00";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
cryptroot = {
label = "CRYPTROOT";
size = "100%";
content = {
type = "luks";
name = "cryptroot";
settings = {
allowDiscards = true;
bypassWorkqueues = true;
crypttabExtraOpts = [
"same-cpu-crypt"
"submit-from-crypt-cpus"
];
};
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"/persist" = {
mountpoint = "/persist";
mountOptions = [ "compress=zstd" ];
};
"/nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" ];
};
};
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = true;
environment.globalPersistence = {
enable = true;
root = "/persist";
};
services.btrfs.autoScrub = {
enable = true;
interval = "weekly";
fileSystems = [ "/persist" ];
};
}

View file

@ -0,0 +1,36 @@
{ lib, ... }:
{
boot = {
initrd.availableKernelModules = [
"nvme"
"ahci"
"xhci_pci"
];
kernelModules = [ "kvm-amd" ];
loader = {
efi.canTouchEfiVariables = true;
systemd-boot.enable = lib.mkDefault true;
};
};
networking.wireless.iwd.enable = true;
hardware = {
amdgpu.initrd.enable = true;
cpu.amd.updateMicrocode = true;
enableRedistributableFirmware = true;
graphics.enable = true;
};
services = {
udev.extraHwdb = ''
evdev:input:b*v046Dp4089*
KEYBOARD_KEY_70039=esc
KEYBOARD_KEY_70029=capslock
evdev:atkbd:dmi:*
KEYBOARD_KEY_3a=esc
KEYBOARD_KEY_01=capslock
'';
};
}

View file

@ -0,0 +1,49 @@
{ profiles, lib, ... }:
{
imports = with profiles; [
services.enthalpy
];
services.enthalpy = {
ipsec = {
interfaces = [ "wlan0" ];
whitelist = [ "rebmit's edge network" ];
};
sing-box = {
enable = true;
clat = {
enable = true;
segment = lib.singleton "fde3:3be3:a244:2676::2";
};
};
};
systemd.network = {
enable = true;
wait-online.anyInterface = true;
networks = {
"30-enp3s0" = {
matchConfig.Name = "enp3s0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = true;
};
dhcpV4Config.RouteMetric = 1024;
dhcpV6Config.RouteMetric = 1024;
ipv6AcceptRAConfig.RouteMetric = 1024;
};
"40-wlan0" = {
matchConfig.Name = "wlan0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = true;
};
dhcpV4Config.RouteMetric = 2048;
dhcpV6Config.RouteMetric = 2048;
ipv6AcceptRAConfig.RouteMetric = 2048;
};
};
};
}

View file

@ -0,0 +1,20 @@
{
suites,
mylib,
...
}:
{
imports = suites.server ++ (mylib.path.scanPaths ./. "default.nix");
services.caddy = {
enable = true;
virtualHosts."rebmit.moe".extraConfig = ''
header /.well-known/matrix/* Content-Type application/json
header /.well-known/matrix/* Access-Control-Allow-Origin *
respond /.well-known/matrix/server `{"m.server": "matrix.rebmit.moe:443"}`
respond /.well-known/matrix/client `{"m.homeserver":{"base_url":"https://matrix.rebmit.moe"}}`
'';
};
system.stateVersion = "24.05";
}

View file

@ -0,0 +1,68 @@
{
disko.devices = {
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"defaults"
"size=2G"
"mode=755"
"nosuid"
"nodev"
];
};
};
disk = {
main = {
type = "disk";
device = "/dev/vda";
content = {
type = "gpt";
partitions = {
boot = {
type = "EF02";
label = "BOOT";
start = "0";
end = "+1M";
};
root = {
label = "ROOT";
end = "-0";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"boot" = {
mountpoint = "/boot";
mountOptions = [ "compress=zstd" ];
};
"nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" ];
};
"persist" = {
mountpoint = "/persist";
mountOptions = [ "compress=zstd" ];
};
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = true;
environment.globalPersistence = {
enable = true;
root = "/persist";
};
services.btrfs.autoScrub = {
enable = true;
interval = "weekly";
fileSystems = [ "/persist" ];
};
}

View file

@ -0,0 +1,15 @@
{ modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ahci"
"sym53c8xx"
"xhci_pci"
"virtio_pci"
"sr_mod"
"virtio_blk"
];
}

View file

@ -0,0 +1,185 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/hcloud/hio0/matrix.nix
{
config,
pkgs,
...
}:
let
conf = {
default_server_config = {
"m.homeserver" = {
base_url = config.services.matrix-synapse.settings.public_baseurl;
server_name = config.services.matrix-synapse.settings.server_name;
};
};
show_labs_settings = true;
};
in
{
services.postgresql = {
enable = true;
package = pkgs.postgresql_16;
};
services.postgresqlBackup = {
enable = true;
location = "/var/lib/backup/postgresql";
backupAll = true;
compression = "zstd";
};
sops.secrets."synapse/signing-key" = {
sopsFile = config.sops.secretFiles.get "hosts/reisen-lax0.yaml";
owner = config.systemd.services.matrix-synapse.serviceConfig.User;
};
sops.secrets."synapse/mautrix-telegram" = {
sopsFile = config.sops.secretFiles.get "hosts/reisen-lax0.yaml";
};
systemd.services.matrix-synapse.serviceConfig.LoadCredential = [
"telegram:/var/lib/mautrix-telegram/telegram-registration.yaml"
"irc:/var/lib/heisenbridge/registration.yml"
];
services.matrix-synapse = {
enable = true;
withJemalloc = true;
settings = {
server_name = "rebmit.moe";
public_baseurl = "https://matrix.rebmit.moe";
signing_key_path = config.sops.secrets."synapse/signing-key".path;
app_service_config_files = [
"/run/credentials/matrix-synapse.service/telegram"
"/run/credentials/matrix-synapse.service/irc"
];
enable_registration = true;
registration_requires_token = true;
listeners = [
{
bind_addresses = [ "127.0.0.1" ];
port = 8196;
tls = false;
type = "http";
x_forwarded = true;
resources = [
{
compress = true;
names = [
"client"
"federation"
];
}
];
}
];
media_retention = {
remote_media_lifetime = "14d";
};
experimental_features = {
# Room summary api
msc3266_enabled = true;
# Removing account data
msc3391_enabled = true;
# Thread notifications
msc3773_enabled = true;
# Remotely toggle push notifications for another client
msc3881_enabled = true;
# Remotely silence local notifications
msc3890_enabled = true;
};
};
};
systemd.services.mautrix-telegram.serviceConfig.RuntimeMaxSec = 86400;
services.mautrix-telegram = {
enable = true;
environmentFile = config.sops.secrets."synapse/mautrix-telegram".path;
serviceDependencies = [ "matrix-synapse.service" ];
settings = {
homeserver = {
address = "http://127.0.0.1:8196";
domain = config.services.matrix-synapse.settings.server_name;
};
appservice = {
address = "http://127.0.0.1:29317";
database = "postgres:///mautrix-telegram?host=/run/postgresql";
hostname = "127.0.0.1";
port = 29317;
provisioning.enabled = false;
};
bridge = {
displayname_template = "{displayname}";
public_portals = true;
delivery_error_reports = true;
incoming_bridge_error_reports = true;
bridge_matrix_leave = false;
relay_user_distinguishers = [ ];
create_group_on_invite = false;
encryption = {
allow = true;
default = true;
};
animated_sticker = {
target = "webp";
convert_from_webm = true;
};
state_event_formats = {
join = "";
leave = "";
name_change = "";
};
permissions = {
"*" = "relaybot";
"@i:rebmit.moe" = "admin";
};
relaybot = {
authless_portals = false;
};
};
telegram = {
device_info = {
app_version = "3.5.2";
};
};
logging = {
loggers = {
mau.level = "INFO";
telethon.level = "INFO";
};
};
};
};
services.heisenbridge = {
enable = true;
homeserver = "http://127.0.0.1:8196";
address = "127.0.0.1";
port = 9898;
owner = "@i:rebmit.moe";
};
services.caddy = {
virtualHosts."matrix.rebmit.moe".extraConfig = ''
reverse_proxy /_matrix/* 127.0.0.1:8196
reverse_proxy /_synapse/client/* 127.0.0.1:8196
header {
X-Frame-Options SAMEORIGIN
X-Content-Type-Options nosniff
X-XSS-Protection "1; mode=block"
Content-Security-Policy "frame-ancestors 'self'"
}
file_server
root * "${pkgs.element-web.override { inherit conf; }}"
'';
};
}

View file

@ -0,0 +1,21 @@
{ ... }:
{
systemd.network = {
enable = true;
wait-online.anyInterface = true;
networks = {
"30-enp3s0" = {
matchConfig.Name = "enp3s0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = false;
KeepConfiguration = true;
};
dhcpV4Config.RouteMetric = 1024;
dhcpV6Config.RouteMetric = 1024;
ipv6AcceptRAConfig.RouteMetric = 1024;
};
};
};
}

View file

@ -0,0 +1,10 @@
{
suites,
mylib,
...
}:
{
imports = suites.server ++ (mylib.path.scanPaths ./. "default.nix");
system.stateVersion = "24.05";
}

View file

@ -0,0 +1,68 @@
{
disko.devices = {
nodev = {
"/" = {
fsType = "tmpfs";
mountOptions = [
"defaults"
"size=1G"
"mode=755"
"nosuid"
"nodev"
];
};
};
disk = {
main = {
type = "disk";
device = "/dev/vda";
content = {
type = "gpt";
partitions = {
boot = {
type = "EF02";
label = "BOOT";
start = "0";
end = "+1M";
};
root = {
label = "ROOT";
end = "-0";
content = {
type = "btrfs";
extraArgs = [ "-f" ];
subvolumes = {
"boot" = {
mountpoint = "/boot";
mountOptions = [ "compress=zstd" ];
};
"nix" = {
mountpoint = "/nix";
mountOptions = [ "compress=zstd" ];
};
"persist" = {
mountpoint = "/persist";
mountOptions = [ "compress=zstd" ];
};
};
};
};
};
};
};
};
};
fileSystems."/persist".neededForBoot = true;
environment.globalPersistence = {
enable = true;
root = "/persist";
};
services.btrfs.autoScrub = {
enable = true;
interval = "weekly";
fileSystems = [ "/persist" ];
};
}

View file

@ -0,0 +1,15 @@
{ modulesPath, ... }:
{
imports = [
(modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [
"ahci"
"sym53c8xx"
"xhci_pci"
"virtio_pci"
"sr_mod"
"virtio_blk"
];
}

View file

@ -0,0 +1,51 @@
{ profiles, ... }:
{
imports = with profiles; [
services.enthalpy
];
services.enthalpy = {
ipsec.interfaces = [ "enp3s0" ];
exit = {
enable = true;
prefix = [ "::/0" ];
};
srv6.enable = true;
nat64.enable = true;
};
networking.nftables.tables.nat = {
family = "inet";
content = ''
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname enp3s0 counter masquerade
}
'';
};
systemd.network = {
enable = true;
wait-online.anyInterface = true;
config = {
networkConfig = {
IPv4Forwarding = true;
IPv6Forwarding = true;
};
};
networks = {
"30-enp3s0" = {
matchConfig.Name = "enp3s0";
networkConfig = {
DHCP = "yes";
IPv6AcceptRA = true;
IPv6PrivacyExtensions = false;
KeepConfiguration = true;
};
dhcpV4Config.RouteMetric = 1024;
dhcpV6Config.RouteMetric = 1024;
ipv6AcceptRAConfig.RouteMetric = 1024;
};
};
};
}

View file

@ -0,0 +1,31 @@
{ config, lib, ... }:
with lib;
let
cfg = config.networking.ports;
noCollision = l: length (unique l) == length l;
in
{
options.networking.ports = mkOption {
type = with types; attrsOf port;
default = {
http = 80;
https = 443;
ssh = 2222;
# enthalpy
sing-box = 1080;
enthalpy-ipsec = 13000;
};
readOnly = true;
description = ''
A mapping of network ports, each identified by a unique name.
'';
};
config = {
assertions = singleton {
assertion = noCollision (attrValues cfg);
message = "port collision";
};
};
}

View file

@ -0,0 +1,95 @@
{
config,
lib,
...
}:
with lib;
let
cfg = config.networking;
noCollision = l: length (unique l) == length l;
reservedTables = [
"local"
"main"
"default"
"unspec"
];
in
{
options.networking = {
routingTables = mkOption {
type = with types; attrsOf int;
default = {
# reserved
unspec = 0;
default = 253;
main = 254;
local = 255;
# enthalpy
localsid = 300;
nat64 = 301;
sing-box = 302;
};
readOnly = true;
description = ''
A mapping of routing tables, each identified by a unique name.
'';
};
routingMarks = mkOption {
type = with types; attrsOf int;
default = {
# enthalpy
sing-box = 1300;
};
readOnly = true;
description = ''
A mapping of routing marks, each identified by a unique name.
'';
};
routingPolicyPriorities = mkOption {
type = with types; attrsOf int;
default = {
# reserved
local = 0;
main = 32766;
default = 32767;
# enthalpy
localsid = 500;
sing-box = 13000;
};
readOnly = true;
description = ''
A set of priorities for routing policies.
'';
};
};
config = {
assertions = [
{
assertion = noCollision (attrValues cfg.routingTables);
message = "routing table id collision";
}
{
assertion = noCollision (attrValues cfg.routingMarks);
message = "routing mark id collision";
}
{
assertion = noCollision (attrValues cfg.routingPolicyPriorities);
message = "routing policy priority collision";
}
];
environment.etc."iproute2/rt_tables.d/routing_tables.conf" = {
mode = "0644";
text = ''
${concatStringsSep "\n" (
mapAttrsToList (name: table: "${toString table} ${name}") (
filterAttrs (name: _table: !(lib.elem name reservedTables)) cfg.routingTables
)
)}
'';
};
};
}

View file

@ -0,0 +1,127 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.enthalpy;
in
{
options.services.enthalpy.bird = {
enable = mkEnableOption "bird for site-scope connectivity";
socket = mkOption {
type = types.str;
default = "/run/enthalpy/bird.ctl";
description = ''
Path to the bird control socket.
'';
};
config = mkOption {
type = types.lines;
description = ''
Configuration file for bird.
'';
};
checkConfig = mkOption {
type = types.bool;
default = true;
description = ''
Whether to check the config at build time.
'';
};
routerId = mkOption {
type = types.int;
description = ''
Router ID for the bird instance.
'';
};
};
config = mkIf (cfg.enable && cfg.bird.enable) {
environment.etc."enthalpy/bird2.conf".source = pkgs.writeTextFile {
name = "bird2";
text = cfg.bird.config;
checkPhase = optionalString cfg.bird.checkConfig ''
ln -s $out bird2.conf
${pkgs.buildPackages.bird}/bin/bird -d -p -c bird2.conf
'';
};
systemd.services.enthalpy-bird2 = {
serviceConfig = {
NetworkNamespacePath = "/run/netns/${cfg.netns}";
Type = "forking";
Restart = "on-failure";
RestartSec = 5;
DynamicUser = true;
RuntimeDirectory = "enthalpy";
ExecStart = "${pkgs.bird}/bin/bird -s ${cfg.bird.socket} -c /etc/enthalpy/bird2.conf";
ExecReload = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} configure";
ExecStop = "${pkgs.bird}/bin/birdc -s ${cfg.bird.socket} down";
CapabilityBoundingSet = [
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
"CAP_NET_RAW"
];
AmbientCapabilities = [
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
"CAP_NET_RAW"
];
ProtectSystem = "full";
ProtectHome = "yes";
ProtectKernelTunables = true;
ProtectControlGroups = true;
PrivateTmp = true;
PrivateDevices = true;
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
MemoryDenyWriteExecute = "yes";
};
partOf = [ "enthalpy.service" ];
after = [ "enthalpy.service" ];
requires = [ "enthalpy.service" ];
requiredBy = [ "enthalpy.service" ];
wantedBy = [ "multi-user.target" ];
reloadTriggers = [ config.environment.etc."enthalpy/bird2.conf".source ];
};
services.enthalpy.bird.config = mkBefore ''
router id ${toString cfg.bird.routerId};
ipv6 sadr table sadr6;
protocol device {
scan time 5;
}
protocol kernel {
ipv6 sadr {
export all;
import none;
};
metric 512;
}
protocol static {
ipv6 sadr;
route ${cfg.prefix} from ::/0 unreachable;
route ${cfg.network} from ::/0 unreachable;
};
protocol babel {
ipv6 sadr {
export all;
import all;
};
randomize router id;
interface "enta*" {
type tunnel;
rxcost 32;
hello interval 20 s;
rtt cost 1024;
rtt max 1024 ms;
rx buffer 2000;
};
}
'';
};
}

View file

@ -0,0 +1,85 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/882da114b98389121d98d909f115d49d9af6613e/modules/gravity.nix
{
config,
lib,
pkgs,
mylib,
...
}:
with lib;
let
inherit (mylib.network) cidr;
cfg = config.services.enthalpy;
in
{
options.services.enthalpy = {
enable = mkEnableOption "enthalpy overlay network";
prefix = mkOption {
type = types.str;
description = ''
Prefix to be announced for the local node.
'';
};
netns = mkOption {
type = types.str;
default = "enthalpy";
description = ''
Name of the network namespace for interfaces.
'';
};
interface = mkOption {
type = types.str;
default = "enthalpy";
description = ''
Name of the interface to connect to the network namespace.
'';
};
network = mkOption {
type = types.str;
description = ''
Prefix of the enthalpy network.
'';
};
};
config = mkIf cfg.enable {
systemd.services.enthalpy = {
path = with pkgs; [
iproute2
coreutils
procps
];
script = ''
ip netns add ${cfg.netns}
ip link add ${cfg.interface} mtu 1400 address 02:00:00:00:00:01 type veth peer enthalpy mtu 1400 address 02:00:00:00:00:00 netns ${cfg.netns}
ip link set ${cfg.interface} up
ip -n ${cfg.netns} link set lo up
ip -n ${cfg.netns} link set enthalpy up
ip -n ${cfg.netns} addr add ${cidr.host 0 cfg.prefix}/127 dev enthalpy
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.default.forwarding=1
ip netns exec ${cfg.netns} sysctl -w net.ipv6.conf.all.forwarding=1
'';
preStop = ''
ip link del ${cfg.interface}
ip netns del ${cfg.netns}
'';
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
systemd.network.networks."50-enthalpy" = {
matchConfig.Name = cfg.interface;
networkConfig.Address = "${cidr.host 1 cfg.prefix}/127";
routes = singleton {
Destination = cfg.network;
Gateway = "fe80::ff:fe00:0";
};
};
};
}

View file

@ -0,0 +1,63 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
{
config,
lib,
pkgs,
mylib,
...
}:
with lib;
let
inherit (mylib.network) cidr;
cfg = config.services.enthalpy;
internalPrefix = filter (p: cidr.child p cfg.prefix) cfg.exit.prefix;
externalPrefix = subtractLists internalPrefix cfg.exit.prefix;
in
{
options.services.enthalpy.exit = {
enable = mkEnableOption "netns route leaking";
prefix = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
Prefixes to be announced from the default netns to the enthalpy network.
'';
};
};
config = mkIf (cfg.enable && cfg.exit.enable) {
services.enthalpy.bird.config = ''
protocol static {
ipv6 sadr;
${
concatMapStringsSep "\n" (p: ''
route ${p} from ${cfg.network} via fe80::ff:fe00:1 dev "enthalpy";
'') externalPrefix
}
}
'';
systemd.services.enthalpy-exit =
let
routes = map (p: "${p} via fe80::ff:fe00:1 dev enthalpy") internalPrefix;
in
mkIf (routes != [ ]) {
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = builtins.map (route: "${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r a ${route}") routes;
ExecStop = builtins.map (route: "${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r d ${route}") routes;
};
partOf = [ "enthalpy.service" ];
after = [
"enthalpy.service"
"network-online.target"
];
requires = [ "enthalpy.service" ];
requiredBy = [ "enthalpy.service" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
};
}

View file

@ -0,0 +1,204 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.enthalpy;
in
{
options.services.enthalpy.ipsec = {
enable = mkEnableOption "IPSec/IKEv2 for link-scope connectivity";
organization = mkOption {
type = types.str;
description = ''
Unique identifier of a keypair.
'';
};
commonName = mkOption {
type = types.str;
description = ''
Name of this node, should be unique within an organization.
'';
};
endpoints = mkOption {
type = types.listOf (
types.submodule {
options = {
serialNumber = mkOption { type = types.str; };
addressFamily = mkOption { type = types.str; };
address = mkOption {
type = types.nullOr types.str;
default = null;
};
};
}
);
description = ''
List of endpoints available on this node.
'';
};
port = mkOption {
type = types.port;
default = config.networking.ports.enthalpy-ipsec;
readOnly = true;
description = ''
UDP port used by IKEv2. NAT-T is enabled by default.
'';
};
interfaces = mkOption {
type = types.listOf types.str;
default = [ ];
description = ''
List of network interfaces that should be used by charon daemon.
'';
};
privateKeyPath = mkOption {
type = types.str;
description = ''
Path to the private key of this organization.
'';
};
registry = mkOption {
type = types.path;
description = ''
Path to the registry.
'';
};
blacklist = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
description = ''
A list of organizations that are blacklisted.
'';
};
whitelist = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
description = ''
A list of organizations that are whitelisted.
'';
};
};
config = mkIf (cfg.enable && cfg.ipsec.enable) {
assertions = [
{
assertion = builtins.all (lib.id) [
(cfg.ipsec.blacklist != null -> cfg.ipsec.whitelist == null)
(cfg.ipsec.whitelist != null -> cfg.ipsec.blacklist == null)
];
message = ''
Only one of `config.services.enthalpy.ipsec.blacklist` or
`config.services.enthalpy.ipsec.whitelist` can be defined at a time.
'';
}
];
environment.systemPackages = with pkgs; [ strongswan ];
environment.etc."ranet/config.json".source = (pkgs.formats.json { }).generate "config.json" {
organization = cfg.ipsec.organization;
common_name = cfg.ipsec.commonName;
endpoints = builtins.map (ep: {
serial_number = ep.serialNumber;
address_family = ep.addressFamily;
address = ep.address;
port = cfg.ipsec.port;
updown = pkgs.writeShellScript "updown" ''
LINK=enta$(printf '%08x\n' "$PLUTO_IF_ID_OUT")
case "$PLUTO_VERB" in
up-client)
ip link add "$LINK" type xfrm if_id "$PLUTO_IF_ID_OUT"
ip link set "$LINK" netns ${cfg.netns} multicast on mtu 1400 up
;;
down-client)
ip -n ${cfg.netns} link del "$LINK"
;;
esac
'';
}) cfg.ipsec.endpoints;
};
services.strongswan-swanctl = {
enable = true;
strongswan.extraConfig = ''
charon {
interfaces_use = ${strings.concatStringsSep "," cfg.ipsec.interfaces}
port = 0
port_nat_t = ${toString cfg.ipsec.port}
retransmit_base = 1
plugins {
socket-default {
set_source = yes
set_sourceif = yes
}
dhcp {
load = no
}
}
}
charon-systemd {
journal {
default = -1
ike = 0
}
}
'';
};
systemd.services.enthalpy-ipsec =
let
registry =
if cfg.ipsec.whitelist != null then
pkgs.runCommand "filtered-registry" { } ''
${pkgs.jq}/bin/jq "[.[] | select(.organization | IN(${
concatMapStringsSep "," (org: "\\\"${org}\\\"") cfg.ipsec.whitelist
}))]" ${cfg.ipsec.registry} > $out
''
else if cfg.ipsec.blacklist != null then
pkgs.runCommand "filtered-registry" { } ''
${pkgs.jq}/bin/jq "[.[] | select(.organization | IN(${
concatMapStringsSep "," (org: "\\\"${org}\\\"") cfg.ipsec.blacklist
}) | not)]" ${cfg.ipsec.registry} > $out
''
else
cfg.ipsec.registry;
command = "ranet -c /etc/ranet/config.json -r ${registry} -k ${cfg.ipsec.privateKeyPath}";
in
{
path = with pkgs; [
iproute2
ranet
];
script = "${command} up";
reload = "${command} up";
preStop = "${command} down";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
bindsTo = [
"strongswan-swanctl.service"
];
wants = [
"network-online.target"
"strongswan-swanctl.service"
];
requires = [
"enthalpy.service"
];
after = [
"network-online.target"
"strongswan-swanctl.service"
"enthalpy.service"
];
wantedBy = [ "multi-user.target" ];
reloadTriggers = [ config.environment.etc."ranet/config.json".source ];
};
};
}

View file

@ -0,0 +1,92 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.enthalpy;
in
{
options.services.enthalpy.nat64 = {
enable = mkEnableOption "NAT64";
table = mkOption {
type = types.int;
default = config.networking.routingTables.nat64;
readOnly = true;
description = ''
Routing table used for NAT64 entries.
'';
};
prefix = mkOption {
type = types.str;
default = "64:ff9b::/96";
description = ''
IPv6 prefix used for NAT64 translation in the network.
'';
};
dynamicPool = mkOption {
type = types.str;
default = "100.127.0.0/16";
description = ''
IPv4 address prefix allocated for dynamic IP assignment.
'';
};
};
config = mkIf (cfg.enable && cfg.nat64.enable) {
systemd.network.config = {
networkConfig = {
IPv6Forwarding = true;
ManageForeignRoutes = false;
};
};
systemd.network.networks."70-nat64" = {
matchConfig.Name = "nat64";
routes = [
{
Destination = cfg.nat64.prefix;
Table = cfg.nat64.table;
}
{ Destination = cfg.nat64.dynamicPool; }
];
networkConfig.LinkLocalAddressing = false;
linkConfig.RequiredForOnline = false;
};
systemd.services.enthalpy-nat64 = {
serviceConfig = {
ExecStart = "${pkgs.tayga}/bin/tayga -d --config ${pkgs.writeText "tayga.conf" ''
tun-device nat64
ipv6-addr fc00::
ipv4-addr 100.127.0.1
prefix ${cfg.nat64.prefix}
dynamic-pool ${cfg.nat64.dynamicPool}
''}";
};
partOf = [ "enthalpy.service" ];
after = [
"enthalpy.service"
"network.target"
];
requires = [ "enthalpy.service" ];
requiredBy = [ "enthalpy.service" ];
wantedBy = [ "multi-user.target" ];
};
networking.nftables.enable = true;
networking.nftables.tables.enthalpy4 = {
family = "ip";
content = ''
chain forward {
type filter hook forward priority 0;
tcp flags syn tcp option maxseg size set 1200
}
'';
};
};
}

View file

@ -0,0 +1,232 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/nixos/mainframe/gravity.nix
{
config,
lib,
pkgs,
mylib,
...
}:
with lib;
let
inherit (mylib.network) cidr;
cfg = config.services.enthalpy;
in
{
options.services.enthalpy.sing-box = {
enable = mkEnableOption "sing-box universal proxy platform";
tableName = mkOption {
type = types.str;
default = "sing-box";
readOnly = true;
description = ''
Routing table used for sing-box.
'';
};
table = mkOption {
type = types.int;
default = config.networking.routingTables."${cfg.sing-box.tableName}";
readOnly = true;
description = ''
Routing table ID associated with the sing-box routing table.
'';
};
priority = mkOption {
type = types.int;
default = config.networking.routingPolicyPriorities."${cfg.sing-box.tableName}";
readOnly = true;
description = ''
Routing priority assigned to the sing-box routing table.
'';
};
fwmark = mkOption {
type = types.int;
default = config.networking.routingMarks."${cfg.sing-box.tableName}";
readOnly = true;
description = ''
Firewall mark designated for the sing-box routing table.
'';
};
port = mkOption {
type = types.int;
default = config.networking.ports.sing-box;
readOnly = true;
description = ''
Port for the mixed proxy to listen on.
'';
};
clat = {
enable = mkEnableOption "464XLAT for IPv4 connectivity";
address = mkOption {
type = types.str;
default = cidr.host 2 cfg.prefix;
description = ''
IPv6 address used for 464XLAT as the mapped source address.
'';
};
segment = mkOption {
type = types.listOf types.str;
description = ''
SRv6 segments used for NAT64.
'';
};
};
};
config = mkIf (cfg.enable && cfg.sing-box.enable) (mkMerge [
# IPv6
{
systemd.network.networks."50-enthalpy" = {
routes = [
{
Destination = "::/0";
Gateway = "fe80::ff:fe00:0";
Table = cfg.sing-box.table;
Metric = 1024;
}
{
Destination = "::0/0";
Type = "blackhole";
Table = cfg.sing-box.table;
Metric = 4096;
}
];
routingPolicyRules = lib.singleton {
Family = "both";
FirewallMark = cfg.sing-box.fwmark;
Priority = cfg.sing-box.priority;
Table = cfg.sing-box.table;
};
};
services.sing-box = {
enable = true;
settings = {
log = {
level = "info";
};
dns = {
servers = [
{
tag = "cloudflare";
address = "https://[2606:4700:4700::1111]/dns-query";
strategy = "prefer_ipv6";
}
{
tag = "local";
address = "local";
strategy = "prefer_ipv4";
}
];
rules = [
{
geosite = [ "cn" ];
server = "local";
}
];
final = "cloudflare";
};
inbounds = [
{
type = "mixed";
tag = "inbound";
listen = "127.0.0.1";
listen_port = cfg.sing-box.port;
sniff = true;
sniff_override_destination = true;
}
];
outbounds = [
{
type = "direct";
tag = "enthalpy";
routing_mark = cfg.sing-box.fwmark;
domain_strategy = "prefer_ipv6";
}
{
type = "direct";
tag = "direct";
}
];
route = {
rules = [
{
geosite = [ "cn" ];
geoip = [ "cn" ];
ip_cidr = [ "10.0.0.0/8" ];
outbound = "direct";
}
];
final = "enthalpy";
};
};
};
environment.systemPackages = with pkgs; [ gg ];
environment.etc."ggconfig.toml".source = (pkgs.formats.toml { }).generate "ggconfig.toml" {
allow_insecure = false;
no_udp = false;
node = "socks5://127.0.0.1:${toString cfg.sing-box.port}";
proxy_private = false;
test_node_before_use = false;
};
}
# IPv4 (464XLAT)
(mkIf cfg.sing-box.clat.enable {
systemd.network.config = {
networkConfig = {
IPv6Forwarding = true;
ManageForeignRoutes = false;
};
};
systemd.network.networks."50-clat" = {
name = "clat";
linkConfig = {
MTUBytes = "1400";
RequiredForOnline = false;
};
addresses = singleton { Address = "192.0.0.2/32"; };
routes = [
{
Destination = "0.0.0.0/0";
Table = cfg.sing-box.table;
PreferredSource = "192.0.0.2";
Metric = 1024;
}
{ Destination = cfg.sing-box.clat.address; }
];
};
services.enthalpy.exit.enable = true;
services.enthalpy.exit.prefix = singleton "${cfg.sing-box.clat.address}/128";
systemd.services.enthalpy-clatd = {
path = with pkgs; [
iproute2
tayga
];
script = ''
ip r replace 64:ff9b::/96 from ${cfg.sing-box.clat.address} encap seg6 mode encap \
segs ${concatStringsSep "," cfg.sing-box.clat.segment} dev ${cfg.interface} mtu 1280
exec tayga -d --config ${pkgs.writeText "tayga.conf" ''
tun-device clat
prefix 64:ff9b::/96
ipv4-addr 192.0.0.1
map 192.0.0.2 ${cfg.sing-box.clat.address}
''}
'';
partOf = [ "enthalpy.service" ];
after = [
"enthalpy.service"
"network.target"
];
requires = [ "enthalpy.service" ];
requiredBy = [ "enthalpy.service" ];
wantedBy = [ "multi-user.target" ];
};
})
]);
}

View file

@ -0,0 +1,109 @@
# Portions of this file are sourced from
# https://github.com/NickCao/flakes/blob/3b03efb676ea602575c916b2b8bc9d9cd13b0d85/modules/gravity/default.nix
{
config,
lib,
pkgs,
mylib,
...
}:
with lib;
let
inherit (mylib.network) cidr;
cfg = config.services.enthalpy;
in
{
options.services.enthalpy.srv6 = {
enable = mkEnableOption "segment routing over IPv6";
tableName = mkOption {
type = types.str;
default = "localsid";
readOnly = true;
description = ''
Routing table designated for SRv6 SID.
'';
};
table = mkOption {
type = types.int;
default = config.networking.routingTables."${cfg.srv6.tableName}";
readOnly = true;
description = ''
Routing table ID associated with the localsid routing table.
'';
};
priority = mkOption {
type = types.int;
default = config.networking.routingPolicyPriorities."${cfg.srv6.tableName}";
readOnly = true;
description = ''
Routing priority assigned to the localsid routing table.
'';
};
prefix = mkOption {
type = types.str;
default = cidr.subnet 4 6 cfg.prefix;
description = ''
Prefix used for SRv6 actions.
'';
};
actions = mkOption {
type = types.listOf types.str;
default = [
"${cidr.host 1 cfg.srv6.prefix} encap seg6local action End.DT6 table main dev ${cfg.interface} table ${cfg.srv6.tableName}"
"${cidr.host 2 cfg.srv6.prefix} encap seg6local action End.DT6 table nat64 dev ${cfg.interface} table ${cfg.srv6.tableName}"
];
description = ''
List of SRv6 actions configured in the default network namespace.
'';
};
};
config = mkIf (cfg.enable && cfg.srv6.enable) {
systemd.network.config = {
networkConfig = {
IPv6Forwarding = true;
ManageForeignRoutes = false;
};
};
systemd.network.networks."50-enthalpy" = {
routes = singleton {
Destination = "::/0";
Type = "blackhole";
Table = cfg.srv6.table;
};
routingPolicyRules = singleton {
Priority = cfg.srv6.priority;
Family = "ipv6";
Table = cfg.srv6.table;
From = cfg.network;
To = cfg.srv6.prefix;
};
};
systemd.services.enthalpy-srv6 = {
path = with pkgs; [ iproute2 ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStartPre = [
"${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r a ${cfg.srv6.prefix} from ${cfg.network} via fe80::ff:fe00:1 dev enthalpy"
];
ExecStart = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 r a ${route}") cfg.srv6.actions;
ExecStop = builtins.map (route: "${pkgs.iproute2}/bin/ip -6 r d ${route}") cfg.srv6.actions;
ExecStopPost = [
"${pkgs.iproute2}/bin/ip -n ${cfg.netns} -6 r d ${cfg.srv6.prefix} from ${cfg.network} via fe80::ff:fe00:1 dev enthalpy"
];
};
partOf = [ "enthalpy.service" ];
after = [
"enthalpy.service"
"network-online.target"
];
requires = [ "enthalpy.service" ];
requiredBy = [ "enthalpy.service" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
};
};
}

View file

@ -0,0 +1,79 @@
# Portions of this file are sourced from
# https://github.com/linyinfeng/dotfiles/blob/b618b0fd16fb9c79ab7199ed51c4c0f98a392cea/nixos/modules/environment/global-persistence/default.nix
{
config,
lib,
...
}:
let
cfg = config.environment.globalPersistence;
userCfg =
name:
assert config.home-manager.users.${name}.home.globalPersistence.enabled;
{
inherit name;
value = {
inherit (config.home-manager.users.${name}.home.globalPersistence) home directories files;
};
};
usersCfg = lib.listToAttrs (map userCfg cfg.user.users);
in
with lib;
{
options.environment.globalPersistence = {
enable = mkEnableOption "global persistence storage";
root = mkOption {
type = types.str;
description = ''
The root of persistence storage.
'';
};
directories = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
Directories to bind mount to persistent storage.
'';
};
files = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
Files that should be stored in persistent storage.
'';
};
user = {
users = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
Persistence for users.
'';
};
directories = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
Directories to bind mount to persistent storage for users.
Paths should be relative to home of user.
'';
};
files = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
Files to link to persistent storage for users.
Paths should be relative to home of user.
'';
};
};
};
config = mkIf cfg.enable {
environment.persistence."${cfg.root}" = {
hideMounts = true;
inherit (cfg) directories files;
users = usersCfg;
};
};
}

Some files were not shown because too many files have changed in this diff Show more