Compare commits
1 Commits
master
...
1e66a99352
Author | SHA1 | Date | |
---|---|---|---|
1e66a99352 |
2
.envrc
2
.envrc
@@ -1,2 +1,2 @@
|
||||
watch_file devshell/{default,commands,install,vm-tasks}.nix
|
||||
nix_direnv_watch_file devshell/{default,commands,install,vm-tasks}.nix
|
||||
use flake
|
||||
|
@@ -6,11 +6,11 @@ on:
|
||||
|
||||
jobs:
|
||||
check:
|
||||
name: Check, build and cache nixfiles
|
||||
name: Check, build and cache Nix flake
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v27
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
# Gitea will supply a token in GITHUB_TOKEN, which this action will
|
||||
# try to pass to Nix when downloading from GitHub
|
||||
@@ -18,30 +18,22 @@ jobs:
|
||||
extra_nix_config: |
|
||||
# Make sure we're using sandbox
|
||||
sandbox-fallback = false
|
||||
# Big C++ projects fill up memory...
|
||||
cores = 6
|
||||
|
||||
extra-substituters = https://nix-cache.nul.ie
|
||||
extra-trusted-public-keys = nix-cache.nul.ie-1:BzH5yMfF4HbzY1C977XzOxoPhEc9Zbu39ftPkUbH+m4=
|
||||
extra-substituters = https://nix-cache.nul.ie/main
|
||||
extra-trusted-public-keys = main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8=
|
||||
- name: Set up attic
|
||||
run: |
|
||||
nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
|
||||
login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
|
||||
|
||||
- name: Check flake
|
||||
run: nix flake check --no-build
|
||||
|
||||
- name: Build (and cache) the world
|
||||
run: nix flake check
|
||||
- name: Build the world
|
||||
id: build
|
||||
env:
|
||||
HARMONIA_SSH_KEY: ${{ secrets.HARMONIA_SSH_KEY }}
|
||||
run: |
|
||||
nix eval --json --apply "builtins.attrNames" .#ci.x86_64-linux | jq -cr '.[]' | while read job; do
|
||||
echo "::group::Build $job"
|
||||
nix build --no-link .#ci.x86_64-linux."$job"
|
||||
echo "::endgroup::"
|
||||
|
||||
echo "::group::Cache $job"
|
||||
ci/push-to-cache.sh "$(nix eval --raw .#ci.x86_64-linux."$job")"
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
echo "Building and caching CI derivation"
|
||||
nix build --no-link .#ciDrv.x86_64-linux
|
||||
UPDATE_PROFILE=1 ci/push-to-cache.sh "$(nix eval --raw .#ciDrv.x86_64-linux)"
|
||||
path=$(nix build --no-link .#ci.x86_64-linux --json | jq -r .[0].outputs.out)
|
||||
echo "path=$path" >> "$GITHUB_OUTPUT"
|
||||
- name: Push to cache
|
||||
run: |
|
||||
nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
|
||||
push main ${{ steps.build.outputs.path }}
|
||||
|
@@ -14,36 +14,37 @@ jobs:
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
- uses: cachix/install-nix-action@v27
|
||||
- uses: cachix/install-nix-action@v23
|
||||
with:
|
||||
github_access_token: ${{ secrets.GH_PULL_TOKEN }}
|
||||
extra_nix_config: |
|
||||
# Make sure we're using sandbox
|
||||
sandbox-fallback = false
|
||||
|
||||
extra-substituters = https://nix-cache.nul.ie
|
||||
extra-trusted-public-keys = nix-cache.nul.ie-1:BzH5yMfF4HbzY1C977XzOxoPhEc9Zbu39ftPkUbH+m4=
|
||||
|
||||
- name: Set up vars
|
||||
extra-substituters = https://nix-cache.nul.ie/main
|
||||
extra-trusted-public-keys = main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8=
|
||||
- name: Set up attic
|
||||
id: setup
|
||||
run: |
|
||||
nix run .#nixpkgs.mine.x86_64-linux.attic-client -- \
|
||||
login --set-default colony https://nix-cache.nul.ie "${{ secrets.NIX_CACHE_TOKEN }}"
|
||||
echo "short_rev=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build installer ISO
|
||||
run: |
|
||||
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.iso
|
||||
ln -s "$(readlink result)"/iso/jackos-installer.iso \
|
||||
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
|
||||
ln -s "$(readlink result)"/iso/nixos-installer-devplayer0.iso \
|
||||
nixos-installer-devplayer0-${{ steps.setup.outputs.short_rev }}.iso
|
||||
- name: Build installer netboot archive
|
||||
run: |
|
||||
nix build .#nixfiles.config.nixos.systems.installer.configuration.config.my.buildAs.netbootArchive
|
||||
ln -s "$(readlink result)" \
|
||||
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar.zst
|
||||
nixos-installer-devplayer0-netboot-${{ steps.setup.outputs.short_rev }}.tar
|
||||
|
||||
- name: Create release
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
title: Latest installer
|
||||
api_key: '${{ secrets.RELEASE_TOKEN }}'
|
||||
files: |
|
||||
jackos-installer-${{ steps.setup.outputs.short_rev }}.iso
|
||||
jackos-installer-netboot-${{ steps.setup.outputs.short_rev }}.tar.zst
|
||||
nixos-installer-devplayer0-${{ steps.setup.outputs.short_rev }}.iso
|
||||
nixos-installer-devplayer0-netboot-${{ steps.setup.outputs.short_rev }}.tar
|
||||
|
@@ -1 +0,0 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKXRXkYnBf2opIjN+bXE7HmhUpa4hyXJUGmBT+MRccT4 harmonia
|
@@ -1 +0,0 @@
|
||||
object-ctr.ams1.int.nul.ie ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFdHbZErWLmTPO/aEWB1Fup/aGMf31Un5Wk66FJwTz/8
|
@@ -1,31 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
REMOTE_STORE=/var/lib/harmonia
|
||||
SSH_HOST="harmonia@object-ctr.ams1.int.nul.ie"
|
||||
SSH_KEY=/tmp/harmonia.key
|
||||
STORE_URI="ssh-ng://$SSH_HOST?ssh-key=$SSH_KEY&remote-store=$REMOTE_STORE"
|
||||
|
||||
remote_cmd() {
|
||||
ssh -i "$SSH_KEY" "$SSH_HOST" env HOME=/run/harmonia NIX_REMOTE="$REMOTE_STORE" "$@"
|
||||
}
|
||||
|
||||
umask_old=$(umask)
|
||||
umask 0066
|
||||
echo "$HARMONIA_SSH_KEY" | base64 -d > "$SSH_KEY"
|
||||
umask $umask_old
|
||||
|
||||
mkdir -p ~/.ssh
|
||||
cp ci/known_hosts ~/.ssh/
|
||||
path="$1"
|
||||
|
||||
echo "Pushing $path to cache..."
|
||||
nix copy --no-check-sigs --to "$STORE_URI" "$path"
|
||||
|
||||
if [ -n "$UPDATE_PROFILE" ]; then
|
||||
echo "Updating profile..."
|
||||
remote_cmd nix-env -p "$REMOTE_STORE"/nix/var/nix/profiles/nixfiles --set "$path"
|
||||
|
||||
echo "Collecting garbage..."
|
||||
remote_cmd nix-collect-garbage --delete-older-than 60d
|
||||
fi
|
@@ -20,7 +20,7 @@ in
|
||||
[ -e "${homeFlake}" ] && echo "${homeFlake} already exists" && exit 1
|
||||
|
||||
mkdir -p "$(dirname "${homeFlake}")"
|
||||
ln -sf "$(pwd)/flake.nix" "${homeFlake}"
|
||||
ln -s "$(pwd)/flake.nix" "${homeFlake}"
|
||||
echo "Installed link to $(pwd)/flake.nix at ${homeFlake}"
|
||||
'';
|
||||
}
|
||||
@@ -52,7 +52,7 @@ in
|
||||
name = "json2nix";
|
||||
category = "utilities";
|
||||
help = "Convert JSON to formatted Nix";
|
||||
command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt-rfc-style}/bin/nixfmt";
|
||||
command = "nix eval --impure --expr 'builtins.fromJSON (builtins.readFile /dev/stdin)' | ${pkgs.nixfmt}/bin/nixfmt";
|
||||
}
|
||||
|
||||
{
|
||||
@@ -77,12 +77,7 @@ in
|
||||
name = "build-n-switch";
|
||||
category = "tasks";
|
||||
help = "Shortcut to nixos-rebuild for this flake";
|
||||
command = ''
|
||||
# HACK: Upstream changes in Git + Nix makes this necessary
|
||||
# https://github.com/NixOS/nix/issues/10202
|
||||
doas git config --global --add safe.directory "$PWD"
|
||||
doas nixos-rebuild --flake . "$@"
|
||||
'';
|
||||
command = ''doas nixos-rebuild --flake . "$@"'';
|
||||
}
|
||||
{
|
||||
name = "run-vm";
|
||||
@@ -111,8 +106,8 @@ in
|
||||
{
|
||||
name = "build-netboot";
|
||||
category = "tasks";
|
||||
help = "Build NixOS configuration as netboot tree";
|
||||
command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.netbootTree"'';
|
||||
help = "Build NixOS configuration as netboot archive";
|
||||
command = ''nix build "''${@:2}" ".#nixfiles.config.nixos.systems.\"$1\".configuration.config.my.buildAs.netbootArchive"'';
|
||||
}
|
||||
{
|
||||
name = "build-home";
|
||||
@@ -120,17 +115,29 @@ in
|
||||
help = "Build home-manager configuration";
|
||||
command = ''nix build "''${@:2}" ".#homeConfigurations.\"$1\".activationPackage"'';
|
||||
}
|
||||
{
|
||||
name = "update-inputs";
|
||||
category = "tasks";
|
||||
help = "Update flake inputs";
|
||||
command = ''
|
||||
args=()
|
||||
for f in "$@"; do
|
||||
args+=(--update-input "$f")
|
||||
done
|
||||
nix flake lock "''${args[@]}"
|
||||
'';
|
||||
}
|
||||
{
|
||||
name = "update-nixpkgs";
|
||||
category = "tasks";
|
||||
help = "Update nixpkgs flake inputs";
|
||||
command = ''nix flake update nixpkgs-{unstable,stable,mine,mine-stable}'';
|
||||
command = ''update-inputs nixpkgs-{unstable,stable,mine,mine-stable}'';
|
||||
}
|
||||
{
|
||||
name = "update-home-manager";
|
||||
category = "tasks";
|
||||
help = "Update home-manager flake inputs";
|
||||
command = ''nix flake update home-manager-{unstable,stable}'';
|
||||
command = ''update-inputs home-manager-{unstable,stable}'';
|
||||
}
|
||||
{
|
||||
name = "update-installer";
|
||||
@@ -138,15 +145,5 @@ in
|
||||
help = "Update installer tag (to trigger new release)";
|
||||
command = ''git tag -f installer && git push -f origin installer'';
|
||||
}
|
||||
{
|
||||
name = "deploy-multi";
|
||||
category = "tasks";
|
||||
help = "Deploy multiple flakes at once";
|
||||
command = ''
|
||||
for f in $@; do
|
||||
deploy "$O" $f
|
||||
done
|
||||
'';
|
||||
}
|
||||
];
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@ in
|
||||
|
||||
NIX_USER_CONF_FILES = toString (pkgs.writeText "nix.conf"
|
||||
''
|
||||
experimental-features = nix-command flakes ca-derivations
|
||||
experimental-features = nix-command flakes ca-derivations repl-flake
|
||||
connect-timeout = 5
|
||||
fallback = true
|
||||
${lib.my.c.nix.cache.conf}
|
||||
@@ -24,10 +24,10 @@ in
|
||||
coreutils
|
||||
nixVersions.stable
|
||||
rage
|
||||
wireguard-tools
|
||||
(pkgs.writeShellScriptBin "deploy" ''
|
||||
exec ${deploy-rs.deploy-rs}/bin/deploy --skip-checks "$@"
|
||||
'')
|
||||
home-manager
|
||||
attic-client
|
||||
];
|
||||
}
|
||||
|
726
flake.lock
generated
726
flake.lock
generated
File diff suppressed because it is too large
Load Diff
55
flake.nix
55
flake.nix
@@ -3,27 +3,21 @@
|
||||
|
||||
inputs = {
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
# libnet.url = "github:reo101/nix-lib-net";
|
||||
libnetRepo = {
|
||||
url = "github:oddlama/nixos-extra-modules";
|
||||
flake = false;
|
||||
};
|
||||
devshell.url = "github:numtide/devshell";
|
||||
devshell.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
|
||||
nixpkgs-unstable.url = "nixpkgs/nixos-unstable";
|
||||
nixpkgs-stable.url = "nixpkgs/nixos-25.05";
|
||||
nixpkgs-stable.url = "nixpkgs/nixos-23.11";
|
||||
nixpkgs-mine.url = "github:devplayer0/nixpkgs/devplayer0";
|
||||
nixpkgs-mine-stable.url = "github:devplayer0/nixpkgs/devplayer0-stable";
|
||||
|
||||
home-manager-unstable.url = "home-manager";
|
||||
home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
home-manager-stable.url = "home-manager/release-25.05";
|
||||
home-manager-stable.url = "home-manager/release-23.11";
|
||||
home-manager-stable.inputs.nixpkgs.follows = "nixpkgs-stable";
|
||||
|
||||
# Stuff used by the flake for build / deployment
|
||||
# ragenix.url = "github:yaxitech/ragenix";
|
||||
ragenix.url = "github:devplayer0/ragenix/add-rekey-one-flag";
|
||||
ragenix.url = "github:yaxitech/ragenix";
|
||||
ragenix.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
deploy-rs.url = "github:serokell/deploy-rs";
|
||||
deploy-rs.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
@@ -32,17 +26,17 @@
|
||||
impermanence.url = "github:nix-community/impermanence";
|
||||
boardie.url = "github:devplayer0/boardie";
|
||||
boardie.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
nixGL.url = "github:nix-community/nixGL";
|
||||
nixGL.url = "github:guibou/nixGL";
|
||||
nixGL.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
|
||||
# Packages not in nixpkgs
|
||||
sharry.url = "github:eikek/sharry";
|
||||
sharry.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
borgthin.url = "github:devplayer0/borg";
|
||||
# TODO: Update borgthin so this works
|
||||
# borgthin.inputs.nixpkgs.follows = "nixpkgs-mine";
|
||||
copyparty.url = "github:9001/copyparty";
|
||||
copyparty.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
borgthin.inputs.nixpkgs.follows = "nixpkgs-mine";
|
||||
attic.url = "github:zhaofengli/attic";
|
||||
attic.inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
attic.inputs.nixpkgs-stable.follows = "nixpkgs-stable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
@@ -57,7 +51,7 @@
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (builtins) mapAttrs replaceStrings elem;
|
||||
inherit (builtins) mapAttrs replaceStrings;
|
||||
inherit (lib) mapAttrs' filterAttrs nameValuePair recurseIntoAttrs evalModules;
|
||||
inherit (lib.flake) flattenTree eachDefaultSystem;
|
||||
inherit (lib.my) mkDefaultSystemsPkgs flakePackageOverlay;
|
||||
@@ -65,11 +59,11 @@
|
||||
# Extend a lib with extras that _must not_ internally reference private nixpkgs. flake-utils doesn't, but many
|
||||
# other flakes (e.g. home-manager) probably do internally.
|
||||
libOverlay = final: prev: {
|
||||
my = import ./lib { inherit inputs; lib = final; };
|
||||
my = import ./lib { lib = final; };
|
||||
flake = flake-utils.lib;
|
||||
};
|
||||
pkgsLibOverlay = final: prev: { lib = prev.lib.extend libOverlay; };
|
||||
myPkgsOverlay = final: prev: import ./pkgs { lib = final.lib; pkgs = prev; };
|
||||
myPkgsOverlay = final: prev: import ./pkgs { lib = prev.lib; pkgs = prev; };
|
||||
|
||||
# Override the flake-level lib since we're going to use it for non-config specific stuff
|
||||
pkgsFlakes = mapAttrs (_: pkgsFlake: pkgsFlake // { lib = pkgsFlake.lib.extend libOverlay; }) {
|
||||
@@ -96,12 +90,12 @@
|
||||
(_: path: mkDefaultSystemsPkgs path (system: {
|
||||
overlays = [
|
||||
pkgsLibOverlay
|
||||
|
||||
myPkgsOverlay
|
||||
inputs.devshell.overlays.default
|
||||
inputs.ragenix.overlays.default
|
||||
inputs.deploy-rs.overlays.default
|
||||
inputs.deploy-rs.overlay
|
||||
(flakePackageOverlay inputs.home-manager-unstable system)
|
||||
inputs.attic.overlays.default
|
||||
];
|
||||
}))
|
||||
pkgsFlakes;
|
||||
@@ -111,19 +105,8 @@
|
||||
(_: path: mkDefaultSystemsPkgs path (_: {
|
||||
overlays = [
|
||||
pkgsLibOverlay
|
||||
|
||||
myPkgsOverlay
|
||||
];
|
||||
|
||||
config = {
|
||||
# RMS forgive me...
|
||||
# Normally this is set modularly, but sometimes we need to use other pkgs
|
||||
allowUnfreePredicate = p: elem (lib.getName p) [
|
||||
"widevine-cdm"
|
||||
"chromium-unwrapped"
|
||||
"chromium"
|
||||
];
|
||||
};
|
||||
}))
|
||||
pkgsFlakes;
|
||||
|
||||
@@ -132,11 +115,10 @@
|
||||
nixos/installer.nix
|
||||
nixos/boxes/colony
|
||||
nixos/boxes/tower
|
||||
nixos/boxes/castle
|
||||
nixos/boxes/home/stream.nix
|
||||
nixos/boxes/home/palace
|
||||
nixos/boxes/home/castle
|
||||
nixos/boxes/britway
|
||||
nixos/boxes/britnet.nix
|
||||
nixos/boxes/kelder
|
||||
|
||||
# Homes
|
||||
@@ -147,7 +129,7 @@
|
||||
modules = [
|
||||
{
|
||||
_module.args = {
|
||||
inherit lib pkgsFlakes hmFlakes self inputs;
|
||||
inherit lib pkgsFlakes hmFlakes inputs;
|
||||
pkgs' = configPkgs';
|
||||
};
|
||||
|
||||
@@ -167,7 +149,7 @@
|
||||
# Platform independent stuff
|
||||
{
|
||||
nixpkgs = pkgs';
|
||||
inherit inputs lib nixfiles;
|
||||
inherit lib nixfiles;
|
||||
|
||||
overlays.default = myPkgsOverlay;
|
||||
|
||||
@@ -215,9 +197,8 @@
|
||||
systems' = mapAttrs' (n: v: nameValuePair "system-${n}" v) systems;
|
||||
packages' = mapAttrs' (n: v: nameValuePair "package-${n}" v) packages;
|
||||
in
|
||||
homes' // systems' // packages' // {
|
||||
pkgs.linkFarm "ci" (homes' // systems' // packages' // {
|
||||
inherit shell;
|
||||
};
|
||||
ciDrv = pkgs.linkFarm "ci" ci;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
@@ -66,7 +66,7 @@ in
|
||||
|
||||
lsd = {
|
||||
enable = mkDefault true;
|
||||
enableFishIntegration = mkDefault true;
|
||||
enableAliases = mkDefault true;
|
||||
};
|
||||
|
||||
starship = {
|
||||
@@ -80,7 +80,6 @@ in
|
||||
|
||||
tmux = {
|
||||
enable = true;
|
||||
keyMode = "vi";
|
||||
};
|
||||
|
||||
bash = {
|
||||
@@ -132,8 +131,6 @@ in
|
||||
|
||||
ssh = {
|
||||
enable = mkDefault true;
|
||||
# TODO: Set after 25.11 releases
|
||||
# enableDefaultConfig = false;
|
||||
matchBlocks = {
|
||||
nix-dev-vm = {
|
||||
user = "dev";
|
||||
@@ -201,20 +198,17 @@ in
|
||||
file
|
||||
tree
|
||||
pwgen
|
||||
|
||||
minicom
|
||||
iperf3
|
||||
mosh
|
||||
wget
|
||||
hyx
|
||||
whois
|
||||
ldns
|
||||
minicom
|
||||
mtr
|
||||
|
||||
hyx
|
||||
ncdu
|
||||
jq
|
||||
yq-go
|
||||
nix-tree
|
||||
];
|
||||
|
||||
sessionVariables = {
|
||||
@@ -228,8 +222,6 @@ in
|
||||
# Note: If globalPkgs mode is on, then these will be overridden by the NixOS equivalents of these options
|
||||
nixpkgs = {
|
||||
overlays = [
|
||||
inputs.libnet.overlays.default
|
||||
|
||||
inputs.deploy-rs.overlay
|
||||
inputs.boardie.overlays.default
|
||||
inputs.nixGL.overlays.default
|
||||
|
@@ -1,28 +0,0 @@
|
||||
# XTerm's default colors
|
||||
|
||||
# Default colors
|
||||
[colors.primary]
|
||||
background = '#000000'
|
||||
foreground = '#ffffff'
|
||||
|
||||
# Normal colors
|
||||
[colors.normal]
|
||||
black = '#000000'
|
||||
red = '#cd0000'
|
||||
green = '#00cd00'
|
||||
yellow = '#cdcd00'
|
||||
blue = '#0000ee'
|
||||
magenta = '#cd00cd'
|
||||
cyan = '#00cdcd'
|
||||
white = '#e5e5e5'
|
||||
|
||||
# Bright colors
|
||||
[colors.bright]
|
||||
black = '#7f7f7f'
|
||||
red = '#ff0000'
|
||||
green = '#00ff00'
|
||||
yellow = '#ffff00'
|
||||
blue = '#5c5cff'
|
||||
magenta = '#ff00ff'
|
||||
cyan = '#00ffff'
|
||||
white = '#ffffff'
|
@@ -1,8 +1,7 @@
|
||||
{ lib, pkgs', pkgs, config, ... }:
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (lib) genAttrs mkIf mkMerge mkForce mapAttrs mkOptionDefault;
|
||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib) genAttrs mkIf mkMerge mkForce;
|
||||
inherit (lib.my) mkBoolOpt';
|
||||
|
||||
cfg = config.my.gui;
|
||||
|
||||
@@ -11,80 +10,33 @@ let
|
||||
name = "Monocraft";
|
||||
size = 10;
|
||||
};
|
||||
|
||||
doomWad = pkgs.fetchurl {
|
||||
url = "https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad";
|
||||
hash = "sha256-HX1DvlAeZ9kn5BXguPPinDvzMHXoWXIYFvZSpSbKx3E=";
|
||||
};
|
||||
subwaySurfers = pkgs.fetchurl {
|
||||
url = "https://p.${pubDomain}/video/subway-surfers-smol.mkv";
|
||||
hash = "sha256-fMe7TDRNTymRHIJOi7qG3trzu4GP8a3gCDz+FMkX1dY=";
|
||||
};
|
||||
minecraftParkour = pkgs.fetchurl {
|
||||
url = "https://p.${pubDomain}/video/minecraft-parkour-smol.mkv";
|
||||
hash = "sha256-723pRm4AsIjY/WFUyAHzTJp+JvH4Pn5hvzF9wHTnOPA=";
|
||||
};
|
||||
|
||||
genLipsum = pkgs.writeScript "lipsum" ''
|
||||
#!${pkgs.python3.withPackages (ps: [ ps.python-lorem ])}/bin/python
|
||||
import lorem
|
||||
print(lorem.get_paragraph(count=5, sep='\n\n'))
|
||||
'';
|
||||
doomsaver' = brainrotTextCommand: pkgs.runCommand "doomsaver" {
|
||||
inherit (pkgs) windowtolayer tmux terminaltexteffects;
|
||||
chocoDoom = pkgs.chocolate-doom2xx;
|
||||
ffmpeg = pkgs.ffmpeg-full;
|
||||
python = pkgs.python3.withPackages (ps: [ ps.filelock ]);
|
||||
|
||||
inherit doomWad;
|
||||
enojy = ./enojy.jpg;
|
||||
inherit brainrotTextCommand subwaySurfers minecraftParkour;
|
||||
} ''
|
||||
mkdir -p "$out"/bin
|
||||
substituteAll ${./screensaver.py} "$out"/bin/doomsaver
|
||||
chmod +x "$out"/bin/doomsaver
|
||||
'';
|
||||
doomsaver = doomsaver' cfg.screensaver.brainrotTextCommand;
|
||||
in
|
||||
{
|
||||
options.my.gui = with lib.types; {
|
||||
options.my.gui = {
|
||||
enable = mkBoolOpt' true "Enable settings and packages meant for graphical systems";
|
||||
manageGraphical = mkBoolOpt' false "Configure the graphical session";
|
||||
standalone = mkBoolOpt' false "Enable settings for fully Nix managed systems";
|
||||
screensaver.brainrotTextCommand = mkOpt' (either path str) genLipsum "Command to generate brainrot text.";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable (mkMerge [
|
||||
{
|
||||
home = {
|
||||
packages = with pkgs; [
|
||||
xdg-utils
|
||||
|
||||
font.package
|
||||
nerd-fonts.sauce-code-pro
|
||||
nerd-fonts.droid-sans-mono
|
||||
(nerdfonts.override {
|
||||
fonts = [ "DroidSansMono" "SourceCodePro" ];
|
||||
})
|
||||
noto-fonts-emoji
|
||||
|
||||
grim
|
||||
slurp
|
||||
swappy
|
||||
|
||||
python3Packages.python-lsp-server
|
||||
python310Packages.python-lsp-server
|
||||
nil # nix language server
|
||||
zls # zig language server
|
||||
rust-analyzer
|
||||
|
||||
cowsay
|
||||
fortune
|
||||
jp2a
|
||||
terminaltexteffects
|
||||
screenfetch
|
||||
neofetch
|
||||
cmatrix
|
||||
doomsaver
|
||||
|
||||
ffmpeg-full
|
||||
xournalpp
|
||||
];
|
||||
};
|
||||
|
||||
@@ -99,15 +51,7 @@ in
|
||||
alacritty = {
|
||||
enable = true;
|
||||
settings = {
|
||||
general.import = [ ./alacritty-xterm.toml ];
|
||||
|
||||
font = {
|
||||
size = font.size;
|
||||
normal = {
|
||||
family = font.name;
|
||||
style = "Regular";
|
||||
};
|
||||
};
|
||||
font.normal.family = font.name;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -115,29 +59,9 @@ in
|
||||
enable = true;
|
||||
inherit font;
|
||||
settings = {
|
||||
background_opacity = "0.65";
|
||||
background_opacity = "0.8";
|
||||
tab_bar_edge = "top";
|
||||
shell_integration = "no-sudo";
|
||||
font_features = "${font.name} -liga";
|
||||
};
|
||||
};
|
||||
|
||||
termite = {
|
||||
enable = true;
|
||||
font = "${font.name} ${toString font.size}";
|
||||
backgroundColor = "rgba(0, 0, 0, 0.8)";
|
||||
};
|
||||
|
||||
foot = {
|
||||
enable = true;
|
||||
settings = {
|
||||
main = {
|
||||
font = "${font.name}:size=${toString font.size}";
|
||||
};
|
||||
colors = {
|
||||
alpha = 0.8;
|
||||
background = "000000";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -184,19 +108,6 @@ in
|
||||
};
|
||||
Install.RequiredBy = [ "sway-session.target" ];
|
||||
};
|
||||
|
||||
activate-linux = {
|
||||
Unit = {
|
||||
Description = "Linux activation watermark";
|
||||
After = "graphical-session.target";
|
||||
PartOf = "graphical-session.target";
|
||||
};
|
||||
Service = {
|
||||
Type = "simple";
|
||||
ExecStart = "${pkgs.activate-linux}/bin/activate-linux";
|
||||
};
|
||||
Install.RequiredBy = [ "graphical-session.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -206,7 +117,6 @@ in
|
||||
wl-clipboard
|
||||
wev
|
||||
wdisplays
|
||||
swaysome
|
||||
|
||||
pavucontrol
|
||||
libsecret
|
||||
@@ -216,11 +126,10 @@ in
|
||||
];
|
||||
|
||||
pointerCursor = {
|
||||
package = pkgs.posy-cursors;
|
||||
name = "Posy_Cursor";
|
||||
size = 32;
|
||||
package = pkgs.vanilla-dmz;
|
||||
name = "Vanilla-DMZ";
|
||||
size = 16;
|
||||
gtk.enable = true;
|
||||
x11.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -229,36 +138,9 @@ in
|
||||
xsession.preferStatusNotifierItems = true;
|
||||
wayland = {
|
||||
windowManager = {
|
||||
sway =
|
||||
let
|
||||
cfg = config.wayland.windowManager.sway.config;
|
||||
mod = cfg.modifier;
|
||||
|
||||
renameWs = pkgs.writeShellScript "sway-rename-ws" ''
|
||||
focused_ws="$(swaymsg -t get_workspaces | jq ".[] | select(.focused)")"
|
||||
focused_num="$(jq -r ".num" <<< "$focused_ws")"
|
||||
focused_name="$(jq -r ".name" <<< "$focused_ws")"
|
||||
placeholder="$(sed -E 's/[0-9]+: //' <<< "$focused_name")"
|
||||
|
||||
name="$(rofi -dmenu -p "rename ws $focused_num" -theme+entry+placeholder "\"$placeholder\"")"
|
||||
if [ -n "$name" ]; then
|
||||
swaymsg rename workspace "$focused_name" to "$focused_num: $name"
|
||||
fi
|
||||
'';
|
||||
clearWsName = pkgs.writeShellScript "sway-clear-ws-name" ''
|
||||
focused_ws="$(swaymsg -t get_workspaces | jq ".[] | select(.focused)")"
|
||||
focused_num="$(jq -r ".num" <<< "$focused_ws")"
|
||||
focused_name="$(jq -r ".name" <<< "$focused_ws")"
|
||||
|
||||
swaymsg rename workspace "$focused_name" to "$focused_num"
|
||||
'';
|
||||
in
|
||||
{
|
||||
sway = {
|
||||
enable = true;
|
||||
xwayland = true;
|
||||
extraConfigEarly = ''
|
||||
set $mod ${mod}
|
||||
'';
|
||||
config = {
|
||||
input = {
|
||||
"type:touchpad" = {
|
||||
@@ -273,87 +155,23 @@ in
|
||||
|
||||
modifier = "Mod4";
|
||||
terminal = "kitty";
|
||||
keybindings = mapAttrs (k: mkOptionDefault) {
|
||||
"${mod}+Left" = "focus left";
|
||||
"${mod}+Down" = "focus down";
|
||||
"${mod}+Up" = "focus up";
|
||||
"${mod}+Right" = "focus right";
|
||||
|
||||
"${mod}+Shift+Left" = "move left";
|
||||
"${mod}+Shift+Down" = "move down";
|
||||
"${mod}+Shift+Up" = "move up";
|
||||
"${mod}+Shift+Right" = "move right";
|
||||
|
||||
"${mod}+b" = "splith";
|
||||
"${mod}+v" = "splitv";
|
||||
"${mod}+f" = "fullscreen toggle";
|
||||
"${mod}+a" = "focus parent";
|
||||
|
||||
"${mod}+s" = "layout stacking";
|
||||
"${mod}+w" = "layout tabbed";
|
||||
"${mod}+e" = "layout toggle split";
|
||||
|
||||
"${mod}+Shift+space" = "floating toggle";
|
||||
"${mod}+space" = "focus mode_toggle";
|
||||
|
||||
"${mod}+1" = "workspace number 1";
|
||||
"${mod}+2" = "workspace number 2";
|
||||
"${mod}+3" = "workspace number 3";
|
||||
"${mod}+4" = "workspace number 4";
|
||||
"${mod}+5" = "workspace number 5";
|
||||
"${mod}+6" = "workspace number 6";
|
||||
"${mod}+7" = "workspace number 7";
|
||||
"${mod}+8" = "workspace number 8";
|
||||
"${mod}+9" = "workspace number 9";
|
||||
"${mod}+0" = "workspace number 10";
|
||||
|
||||
"${mod}+Shift+1" =
|
||||
"move container to workspace number 1";
|
||||
"${mod}+Shift+2" =
|
||||
"move container to workspace number 2";
|
||||
"${mod}+Shift+3" =
|
||||
"move container to workspace number 3";
|
||||
"${mod}+Shift+4" =
|
||||
"move container to workspace number 4";
|
||||
"${mod}+Shift+5" =
|
||||
"move container to workspace number 5";
|
||||
"${mod}+Shift+6" =
|
||||
"move container to workspace number 6";
|
||||
"${mod}+Shift+7" =
|
||||
"move container to workspace number 7";
|
||||
"${mod}+Shift+8" =
|
||||
"move container to workspace number 8";
|
||||
"${mod}+Shift+9" =
|
||||
"move container to workspace number 9";
|
||||
"${mod}+Shift+0" =
|
||||
"move container to workspace number 10";
|
||||
|
||||
"${mod}+Shift+minus" = "move scratchpad";
|
||||
"${mod}+minus" = "scratchpad show";
|
||||
|
||||
"${mod}+Return" = "exec ${cfg.terminal}";
|
||||
"${mod}+r" = "mode resize";
|
||||
keybindings =
|
||||
let
|
||||
cfg = config.wayland.windowManager.sway.config;
|
||||
mod = cfg.modifier;
|
||||
in
|
||||
lib.mkOptionDefault {
|
||||
"${mod}+d" = null;
|
||||
"${mod}+l" = "exec ${doomsaver}/bin/doomsaver";
|
||||
"${mod}+q" = "kill";
|
||||
"${mod}+Shift+c" = "reload";
|
||||
"${mod}+Shift+q" = "exec swaynag -t warning -m 'bruh you really wanna kill sway?' -b 'ye' 'systemctl --user stop graphical-session.target && swaymsg exit'";
|
||||
|
||||
# rofi
|
||||
"${mod}+l" = "exec swaylock -i ${./lock.png} -s stretch";
|
||||
"${mod}+x" = "exec ${cfg.menu}";
|
||||
"${mod}+Shift+x" = "exec rofi -show drun";
|
||||
"${mod}+q" = "kill";
|
||||
"${mod}+Shift+q" = "exec swaynag -t warning -m 'bruh you really wanna kill sway?' -b 'ye' 'systemctl --user stop graphical-session.target && swaymsg exit'";
|
||||
"${mod}+Shift+d" = ''exec grim - | swappy -f -'';
|
||||
"${mod}+Shift+s" = ''exec grim -g "$(slurp)" - | swappy -f -'';
|
||||
"${mod}+Shift+e" = "exec rofi -show emoji";
|
||||
# Config for this doesn't seem to work :/
|
||||
"${mod}+c" = ''exec rofi -show calc -calc-command "echo -n '{result}' | ${pkgs.wl-clipboard}/bin/wl-copy"'';
|
||||
"${mod}+Shift+r" = "exec ${renameWs}";
|
||||
"${mod}+Shift+n" = "exec ${clearWsName}";
|
||||
|
||||
# Screenshots
|
||||
"${mod}+Shift+d" = ''exec grim - | swappy -f -'';
|
||||
"${mod}+Shift+s" = ''exec grim -g "$(slurp)" - | swappy -f -'';
|
||||
|
||||
"XF86MonBrightnessDown" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-";
|
||||
"XF86MonBrightnessUp" = "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%";
|
||||
|
||||
"XF86AudioRaiseVolume" = "exec ${pkgs.pamixer}/bin/pamixer -i 5";
|
||||
"XF86AudioLowerVolume" = "exec ${pkgs.pamixer}/bin/pamixer -d 5";
|
||||
@@ -370,9 +188,6 @@ in
|
||||
menu = "rofi -show run";
|
||||
bars = mkForce [ ];
|
||||
};
|
||||
extraConfig = ''
|
||||
include ${./swaysome.conf}
|
||||
'';
|
||||
|
||||
swaynag = {
|
||||
enable = true;
|
||||
@@ -395,10 +210,17 @@ in
|
||||
};
|
||||
qt = {
|
||||
enable = true;
|
||||
platformTheme.name = "gtk";
|
||||
platformTheme = "gtk";
|
||||
};
|
||||
|
||||
services = {
|
||||
swaync = {
|
||||
enable = true;
|
||||
settings = {
|
||||
widgets = [ "title" "dnd" "mpris" "notifications" ];
|
||||
};
|
||||
};
|
||||
|
||||
playerctld.enable = true;
|
||||
spotifyd = {
|
||||
enable = false;
|
||||
@@ -423,7 +245,6 @@ in
|
||||
diff-so-fancy.enable = true;
|
||||
userEmail = "jackos1998@gmail.com";
|
||||
userName = "Jack O'Sullivan";
|
||||
lfs.enable = true;
|
||||
extraConfig = {
|
||||
pull.rebase = true;
|
||||
};
|
||||
@@ -431,13 +252,11 @@ in
|
||||
|
||||
waybar = import ./waybar.nix { inherit lib pkgs config font; };
|
||||
rofi = {
|
||||
package = pkgs.rofi-wayland;
|
||||
enable = true;
|
||||
font = "${font.name} ${toString font.size}";
|
||||
plugins = with pkgs; (map (p: p.override { rofi-unwrapped = rofi-wayland-unwrapped; }) [
|
||||
plugins = with pkgs; [
|
||||
rofi-calc
|
||||
]) ++ [
|
||||
rofi-emoji-wayland
|
||||
rofi-emoji
|
||||
];
|
||||
extraConfig = {
|
||||
modes = "window,run,ssh,filebrowser,calc,emoji";
|
||||
@@ -452,7 +271,7 @@ in
|
||||
|
||||
chromium = {
|
||||
enable = true;
|
||||
package = (pkgs'.unstable.chromium.override { enableWideVine = true; }).overrideAttrs (old: {
|
||||
package = (pkgs.chromium.override { enableWideVine = true; }).overrideAttrs (old: {
|
||||
buildCommand = ''
|
||||
${old.buildCommand}
|
||||
|
||||
@@ -478,15 +297,6 @@ in
|
||||
] (_: "chromium-browser.desktop");
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
swaync = {
|
||||
enable = true;
|
||||
settings = {
|
||||
widgets = [ "title" "dnd" "mpris" "notifications" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
(mkIf (cfg.standalone && !pkgs.stdenv.isDarwin) {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 7.4 KiB |
@@ -1,257 +0,0 @@
|
||||
#!@python@/bin/python
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import filelock
|
||||
|
||||
class Screensaver:
|
||||
def __init__(self, cmd, env=None, weight=1):
|
||||
self.cmd = cmd
|
||||
self.weight = weight
|
||||
|
||||
if env is not None:
|
||||
self.env = os.environ.copy()
|
||||
for k, v in env.items():
|
||||
self.env[k] = v
|
||||
else:
|
||||
self.env = None
|
||||
self.proc = None
|
||||
|
||||
def start(self):
|
||||
assert self.proc is None
|
||||
self.proc = subprocess.Popen(self.cmd, env=self.env)
|
||||
|
||||
def wait(self):
|
||||
assert self.proc is not None
|
||||
self.proc.wait()
|
||||
|
||||
def stop(self, kill=False):
|
||||
assert self.proc is not None
|
||||
if kill:
|
||||
self.proc.kill()
|
||||
else:
|
||||
self.proc.terminate()
|
||||
|
||||
class DoomSaver(Screensaver):
|
||||
wad = '@doomWad@'
|
||||
|
||||
def __init__(self, demo_index, weight=1.5):
|
||||
super().__init__(
|
||||
['@chocoDoom@/bin/chocolate-doom',
|
||||
'-iwad', self.wad,
|
||||
'-demoloopi', str(demo_index)],
|
||||
env={
|
||||
'SDL_AUDIODRIVER': 'null',
|
||||
'SDL_VIDEODRIVER': 'caca',
|
||||
'CACA_DRIVER': 'ncurses',
|
||||
},
|
||||
weight=weight,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
super().stop(kill=True)
|
||||
|
||||
class TTESaver(Screensaver):
|
||||
effects = (
|
||||
'beams,binarypath,blackhole,bouncyballs,bubbles,burn,colorshift,crumble,'
|
||||
'decrypt,errorcorrect,expand,fireworks,middleout,orbittingvolley,overflow,'
|
||||
'pour,print,rain,randomsequence,rings,scattered,slice,slide,spotlights,'
|
||||
'spray,swarm,synthgrid,unstable,vhstape,waves,wipe'
|
||||
).split(',')
|
||||
|
||||
def __init__(self, cmd, env=None, weight=1):
|
||||
super().__init__(cmd, env=env, weight=weight)
|
||||
self.running = False
|
||||
|
||||
def start(self):
|
||||
self.running = True
|
||||
|
||||
def wait(self):
|
||||
while self.running:
|
||||
effect_cmd = ['@terminaltexteffects@/bin/tte', random.choice(self.effects)]
|
||||
print(f"$ {self.cmd} | {' '.join(effect_cmd)}")
|
||||
content = subprocess.check_output(self.cmd, shell=True, env=self.env, stderr=subprocess.DEVNULL)
|
||||
|
||||
self.proc = subprocess.Popen(effect_cmd, stdin=subprocess.PIPE)
|
||||
self.proc.stdin.write(content)
|
||||
self.proc.stdin.close()
|
||||
self.proc.wait()
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.proc.terminate()
|
||||
|
||||
class FFmpegCACASaver(Screensaver):
|
||||
@staticmethod
|
||||
def command(video, size):
|
||||
return ['@ffmpeg@/bin/ffmpeg', '-hide_banner', '-loglevel', 'error',
|
||||
'-stream_loop', '-1', '-i', video,
|
||||
'-pix_fmt', 'rgb24', '-window_size', f'{size}x{size}',
|
||||
'-f', 'caca', '-']
|
||||
|
||||
def __init__(self, video, weight=2):
|
||||
cols, lines = os.get_terminal_size()
|
||||
# IDK if it's reasonable to do this as "1:1"
|
||||
size = lines - 4
|
||||
super().__init__(
|
||||
self.command(video, size),
|
||||
env={'CACA_DRIVER': 'ncurses'},
|
||||
weight=weight,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
super().stop(kill=True)
|
||||
|
||||
class BrainrotStorySaver(Screensaver):
|
||||
def __init__(self, video, text_command, weight=2):
|
||||
cols, lines = os.get_terminal_size()
|
||||
video_size = lines - 1
|
||||
video_command = ' '.join(FFmpegCACASaver.command(video, video_size))
|
||||
text_command = (
|
||||
f'while true; do {text_command} | '
|
||||
f'@terminaltexteffects@/bin/tte --wrap-text --canvas-width=80 --canvas-height={video_size//2} --anchor-canvas=c '
|
||||
'print --final-gradient-stops=ffffff; clear; done' )
|
||||
self.tmux_session = f'screensaver-{os.urandom(4).hex()}'
|
||||
super().__init__(
|
||||
['@tmux@/bin/tmux', 'new-session', '-s', self.tmux_session, '-n', 'brainrot',
|
||||
text_command, ';', 'split-window', '-hbl', str(lines), video_command],
|
||||
# ['sh', '-c', text_command],
|
||||
env={
|
||||
'CACA_DRIVER': 'ncurses',
|
||||
'SHELL': '/bin/sh',
|
||||
},
|
||||
weight=weight,
|
||||
)
|
||||
|
||||
def stop(self):
|
||||
subprocess.check_call(['@tmux@/bin/tmux', 'kill-session', '-t', self.tmux_session])
|
||||
|
||||
class MultiSaver:
|
||||
savers = [
|
||||
DoomSaver(0),
|
||||
DoomSaver(1),
|
||||
DoomSaver(2),
|
||||
|
||||
Screensaver(['cmatrix']),
|
||||
|
||||
TTESaver('screenfetch -N'),
|
||||
TTESaver('fortune | cowsay'),
|
||||
TTESaver('top -bn1 | head -n50'),
|
||||
TTESaver('ss -nltu'),
|
||||
TTESaver('ss -ntu'),
|
||||
TTESaver('jp2a --width=100 @enojy@'),
|
||||
|
||||
BrainrotStorySaver('@subwaySurfers@', '@brainrotTextCommand@'),
|
||||
BrainrotStorySaver('@minecraftParkour@', '@brainrotTextCommand@'),
|
||||
]
|
||||
state_filename = 'screensaver.json'
|
||||
|
||||
def __init__(self, select=None):
|
||||
self.state_path = os.path.join(f'/run/user/{os.geteuid()}', self.state_filename)
|
||||
self.lock = filelock.FileLock(f'{self.state_path}.lock')
|
||||
|
||||
if select is not None:
|
||||
assert select >= 0 and select < len(self.savers), 'Invalid screensaver index'
|
||||
self.selected = self.savers[select]
|
||||
else:
|
||||
self.selected = None
|
||||
self.cleaned_up = False
|
||||
|
||||
def select(self):
|
||||
with self.lock:
|
||||
if not os.path.exists(self.state_path):
|
||||
state = {'instances': []}
|
||||
else:
|
||||
with open(self.state_path) as f:
|
||||
state = json.load(f)
|
||||
|
||||
if self.selected is None:
|
||||
available = set(range(len(self.savers)))
|
||||
new_instances = []
|
||||
for instance in state['instances']:
|
||||
if not os.path.exists(f"/proc/{instance['pid']}"):
|
||||
continue
|
||||
|
||||
new_instances.append(instance)
|
||||
i = instance['saver']
|
||||
assert i in available
|
||||
available.remove(i)
|
||||
assert available, 'No screensavers left'
|
||||
available = list(available)
|
||||
|
||||
weights = []
|
||||
for i in available:
|
||||
weights.append(self.savers[i].weight)
|
||||
selected_i = random.choices(available, weights=weights)[0]
|
||||
|
||||
new_instances.append({'pid': os.getpid(), 'saver': selected_i})
|
||||
state['instances'] = new_instances
|
||||
|
||||
# print(f'Selected saver {selected_i}')
|
||||
self.selected = self.savers[selected_i]
|
||||
|
||||
with open(self.state_path, 'w') as f:
|
||||
json.dump(state, f)
|
||||
|
||||
def cleanup(self):
|
||||
if self.cleaned_up:
|
||||
return
|
||||
self.cleaned_up = True
|
||||
|
||||
with self.lock:
|
||||
with open(self.state_path) as f:
|
||||
state = json.load(f)
|
||||
|
||||
for i, instance in enumerate(state['instances']):
|
||||
if instance['pid'] == os.getpid():
|
||||
del state['instances'][i]
|
||||
|
||||
with open(self.state_path, 'w') as f:
|
||||
json.dump(state, f)
|
||||
|
||||
def run(self):
|
||||
assert self.selected is not None
|
||||
self.selected.start()
|
||||
|
||||
signal.signal(signal.SIGINT, self._sighandler)
|
||||
signal.signal(signal.SIGTERM, self._sighandler)
|
||||
signal.signal(signal.SIGHUP, self._sighandler)
|
||||
self.selected.wait()
|
||||
self.cleanup()
|
||||
|
||||
def stop(self):
|
||||
assert self.selected is not None
|
||||
print('Shutting down')
|
||||
self.selected.stop()
|
||||
self.cleanup()
|
||||
def _sighandler(self, signum, frame):
|
||||
self.stop()
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Wayland terminal-based lock screen')
|
||||
parser.add_argument('-l', '--locker-cmd', default='swaylock-plugin', help='swaylock-plugin command to use')
|
||||
parser.add_argument('-t', '--terminal', default='alacritty', help='Terminal emulator to use')
|
||||
parser.add_argument('-i', '--instance', action='store_true', help='Run as instance')
|
||||
parser.add_argument('-s', '--screensaver', type=int, help='Force use of specific screensaver')
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.instance:
|
||||
cmd = [
|
||||
args.locker_cmd, '--command-each',
|
||||
f'@windowtolayer@/bin/windowtolayer -- {args.terminal} -e {sys.argv[0]} --instance']
|
||||
if args.screensaver is not None:
|
||||
cmd[-1] += f' --screensaver {args.screensaver}'
|
||||
subprocess.check_call(cmd)
|
||||
return
|
||||
|
||||
ms = MultiSaver(select=args.screensaver)
|
||||
ms.select()
|
||||
ms.run()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Binary file not shown.
Before Width: | Height: | Size: 251 KiB After Width: | Height: | Size: 249 KiB |
@@ -1,66 +0,0 @@
|
||||
# Use (un)bindcode or (un)bindsym, depending on what you used in your main sway config file.
|
||||
# The `--no-warn` setting is only added to shortcuts that exist in the default config. You may want to add or remove
|
||||
# that flag on some bindings depending on your config.
|
||||
|
||||
|
||||
# Change focus between workspaces
|
||||
bindsym $mod+Alt+1 exec "swaysome focus 1"
|
||||
bindsym $mod+Alt+2 exec "swaysome focus 2"
|
||||
bindsym $mod+Alt+3 exec "swaysome focus 3"
|
||||
bindsym $mod+Alt+4 exec "swaysome focus 4"
|
||||
bindsym $mod+Alt+5 exec "swaysome focus 5"
|
||||
bindsym $mod+Alt+6 exec "swaysome focus 6"
|
||||
bindsym $mod+Alt+7 exec "swaysome focus 7"
|
||||
bindsym $mod+Alt+8 exec "swaysome focus 8"
|
||||
bindsym $mod+Alt+9 exec "swaysome focus 9"
|
||||
bindsym $mod+Alt+0 exec "swaysome focus 0"
|
||||
|
||||
# Focus workspace groups
|
||||
bindsym --no-warn $mod+1 exec "swaysome focus-group 1"
|
||||
bindsym --no-warn $mod+2 exec "swaysome focus-group 2"
|
||||
bindsym --no-warn $mod+3 exec "swaysome focus-group 3"
|
||||
bindsym --no-warn $mod+4 exec "swaysome focus-group 4"
|
||||
bindsym --no-warn $mod+5 exec "swaysome focus-group 5"
|
||||
bindsym --no-warn $mod+6 exec "swaysome focus-group 6"
|
||||
bindsym --no-warn $mod+7 exec "swaysome focus-group 7"
|
||||
bindsym --no-warn $mod+8 exec "swaysome focus-group 8"
|
||||
bindsym --no-warn $mod+9 exec "swaysome focus-group 9"
|
||||
bindsym --no-warn $mod+0 exec "swaysome focus-group 0"
|
||||
|
||||
# Move containers between workspaces
|
||||
bindsym $mod+Alt+Shift+1 exec "swaysome move 1"
|
||||
bindsym $mod+Alt+Shift+2 exec "swaysome move 2"
|
||||
bindsym $mod+Alt+Shift+3 exec "swaysome move 3"
|
||||
bindsym $mod+Alt+Shift+4 exec "swaysome move 4"
|
||||
bindsym $mod+Alt+Shift+5 exec "swaysome move 5"
|
||||
bindsym $mod+Alt+Shift+6 exec "swaysome move 6"
|
||||
bindsym $mod+Alt+Shift+7 exec "swaysome move 7"
|
||||
bindsym $mod+Alt+Shift+8 exec "swaysome move 8"
|
||||
bindsym $mod+Alt+Shift+9 exec "swaysome move 9"
|
||||
bindsym $mod+Alt+Shift+0 exec "swaysome move 0"
|
||||
|
||||
# Move containers to other workspace groups
|
||||
bindsym --no-warn $mod+Shift+1 exec "swaysome move-to-group 1"
|
||||
bindsym --no-warn $mod+Shift+2 exec "swaysome move-to-group 2"
|
||||
bindsym --no-warn $mod+Shift+3 exec "swaysome move-to-group 3"
|
||||
bindsym --no-warn $mod+Shift+4 exec "swaysome move-to-group 4"
|
||||
bindsym --no-warn $mod+Shift+5 exec "swaysome move-to-group 5"
|
||||
bindsym --no-warn $mod+Shift+6 exec "swaysome move-to-group 6"
|
||||
bindsym --no-warn $mod+Shift+7 exec "swaysome move-to-group 7"
|
||||
bindsym --no-warn $mod+Shift+8 exec "swaysome move-to-group 8"
|
||||
bindsym --no-warn $mod+Shift+9 exec "swaysome move-to-group 9"
|
||||
bindsym --no-warn $mod+Shift+0 exec "swaysome move-to-group 0"
|
||||
|
||||
# Move focused container to next output
|
||||
bindsym $mod+Alt+Right exec "swaysome next-output"
|
||||
# Move focused container to previous output
|
||||
bindsym $mod+Alt+Left exec "swaysome prev-output"
|
||||
|
||||
# Move focused workspace group to next output
|
||||
bindsym $mod+Shift+Alt+Right exec "swaysome workspace-group-next-output"
|
||||
# Move focused workspace group to previous output
|
||||
bindsym $mod+Shift+Alt+Left exec "swaysome workspace-group-prev-output"
|
||||
|
||||
# Init workspaces for every screen
|
||||
exec "swaysome init 1"
|
||||
|
@@ -146,9 +146,9 @@ in
|
||||
dnd-none = "";
|
||||
};
|
||||
return-type = "json";
|
||||
exec = "${config.my.swaync.package}/bin/swaync-client -swb";
|
||||
on-click = "${config.my.swaync.package}/bin/swaync-client -t -sw";
|
||||
on-click-right = "${config.my.swaync.package}/bin/swaync-client -d -sw";
|
||||
exec = "${config.services.swaync.package}/bin/swaync-client -swb";
|
||||
on-click = "${config.services.swaync.package}/bin/swaync-client -t -sw";
|
||||
on-click-right = "${config.services.swaync.package}/bin/swaync-client -d -sw";
|
||||
escape = true;
|
||||
};
|
||||
};
|
||||
|
@@ -19,10 +19,10 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
cfg = config.my.swaync;
|
||||
cfg = config.services.swaync;
|
||||
in
|
||||
{
|
||||
options.my.swaync = with lib.types; {
|
||||
options.services.swaync = with lib.types; {
|
||||
enable = mkEnableOption "Sway Notification Center";
|
||||
package = mkOption {
|
||||
type = package;
|
||||
|
@@ -11,9 +11,6 @@ rec {
|
||||
jellyseerr = 402;
|
||||
atticd = 403;
|
||||
kea = 404;
|
||||
keepalived_script = 405;
|
||||
photoprism = 406;
|
||||
copyparty = 408;
|
||||
};
|
||||
gids = {
|
||||
matrix-syncv3 = 400;
|
||||
@@ -21,16 +18,12 @@ rec {
|
||||
jellyseerr = 402;
|
||||
atticd = 403;
|
||||
kea = 404;
|
||||
keepalived_script = 405;
|
||||
photoprism = 406;
|
||||
adbusers = 407;
|
||||
copyparty = 408;
|
||||
};
|
||||
};
|
||||
|
||||
kernel = {
|
||||
lts = pkgs: pkgs.linuxKernel.packages.linux_6_12;
|
||||
latest = pkgs: pkgs.linuxKernel.packages.linux_6_16;
|
||||
lts = pkgs: pkgs.linuxKernel.packages.linux_6_1;
|
||||
latest = pkgs: pkgs.linuxKernel.packages.linux_6_6;
|
||||
};
|
||||
|
||||
nginx = rec {
|
||||
@@ -101,10 +94,10 @@ rec {
|
||||
nix = {
|
||||
cache = rec {
|
||||
substituters = [
|
||||
"https://nix-cache.${pubDomain}"
|
||||
"https://nix-cache.${pubDomain}/main"
|
||||
];
|
||||
keys = [
|
||||
"nix-cache.nul.ie-1:BzH5yMfF4HbzY1C977XzOxoPhEc9Zbu39ftPkUbH+m4="
|
||||
"main:mMChkG8LwXrFirVfudqjSHasK1jV31OVElYD3eImYl8="
|
||||
];
|
||||
conf = ''
|
||||
extra-substituters = ${concatStringsSep " " substituters}
|
||||
@@ -114,7 +107,7 @@ rec {
|
||||
};
|
||||
|
||||
pubDomain = "nul.ie";
|
||||
colony = rec {
|
||||
colony = {
|
||||
domain = "ams1.int.${pubDomain}";
|
||||
pubV4 = "94.142.240.44";
|
||||
prefixes = with lib.my.net.cidr; rec {
|
||||
@@ -138,9 +131,6 @@ rec {
|
||||
v4 = subnet 8 3 all.v4;
|
||||
v6 = subnet 4 3 all.v6;
|
||||
};
|
||||
qclk = {
|
||||
v4 = subnet 8 4 all.v4;
|
||||
};
|
||||
|
||||
cust = {
|
||||
v4 = subnet 8 100 all.v4; # single ip for routing only
|
||||
@@ -154,10 +144,6 @@ rec {
|
||||
v4 = "94.142.242.255/32";
|
||||
v6 = subnet 8 1 cust.v6;
|
||||
};
|
||||
jam = {
|
||||
v4 = subnet 8 4 cust.v4;
|
||||
v6 = subnet 8 2 cust.v6;
|
||||
};
|
||||
|
||||
vip1 = "94.142.241.224/30";
|
||||
vip2 = "94.142.242.254/31";
|
||||
@@ -170,16 +156,6 @@ rec {
|
||||
home.v6 = "2a0e:97c0:4d0::/48";
|
||||
};
|
||||
|
||||
custRouting = with lib.my.net.cidr; {
|
||||
mail-vm = host 1 prefixes.cust.v4;
|
||||
darts-vm = host 2 prefixes.cust.v4;
|
||||
jam-ctr = host 3 prefixes.cust.v4;
|
||||
};
|
||||
|
||||
qclk = {
|
||||
wgPort = 51821;
|
||||
};
|
||||
|
||||
firewallForwards = aa: [
|
||||
{
|
||||
port = "http";
|
||||
@@ -194,29 +170,6 @@ rec {
|
||||
dst = aa.middleman.internal.ipv4.address;
|
||||
}
|
||||
|
||||
{
|
||||
port = 25565;
|
||||
dst = aa.simpcraft-oci.internal.ipv4.address;
|
||||
}
|
||||
{
|
||||
port = 25566;
|
||||
dst = aa.simpcraft-staging-oci.internal.ipv4.address;
|
||||
}
|
||||
{
|
||||
port = 25567;
|
||||
dst = aa.kevcraft-oci.internal.ipv4.address;
|
||||
}
|
||||
{
|
||||
port = 25568;
|
||||
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
||||
}
|
||||
|
||||
# RCON... unsafe?
|
||||
# {
|
||||
# port = 25575;
|
||||
# dst = aa.simpcraft-oci.internal.ipv4.address;
|
||||
# }
|
||||
|
||||
{
|
||||
port = 2456;
|
||||
dst = aa.valheim-oci.internal.ipv4.address;
|
||||
@@ -233,39 +186,6 @@ rec {
|
||||
dst = aa.waffletail.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
|
||||
{
|
||||
port = 25565;
|
||||
dst = aa.simpcraft-oci.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
{
|
||||
port = 25567;
|
||||
dst = aa.kevcraft-oci.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
{
|
||||
port = 25568;
|
||||
dst = aa.kinkcraft-oci.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
|
||||
{
|
||||
port = 15636;
|
||||
dst = aa.enshrouded-oci.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
{
|
||||
port = 15637;
|
||||
dst = aa.enshrouded-oci.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
|
||||
{
|
||||
port = qclk.wgPort;
|
||||
dst = aa.qclk.internal.ipv4.address;
|
||||
proto = "udp";
|
||||
}
|
||||
];
|
||||
|
||||
fstrimConfig = {
|
||||
@@ -289,8 +209,8 @@ rec {
|
||||
"stream"
|
||||
];
|
||||
routersPubV4 = [
|
||||
"109.255.108.88"
|
||||
"109.255.108.121"
|
||||
"109.255.31.25"
|
||||
"109.255.252.63"
|
||||
];
|
||||
|
||||
prefixes = with lib.my.net.cidr; rec {
|
||||
@@ -339,8 +259,6 @@ rec {
|
||||
v6 = host ((1*65536*65536*65536) + 65535) prefixes.as211024.v6;
|
||||
};
|
||||
};
|
||||
|
||||
roceBootModules = [ "ib_core" "ib_uverbs" "mlx5_core" "mlx5_ib" ];
|
||||
};
|
||||
|
||||
britway = {
|
||||
@@ -356,20 +274,6 @@ rec {
|
||||
assignedV6 = "2001:19f0:7402:128b:5400:04ff:feac:6e06";
|
||||
};
|
||||
|
||||
britnet = {
|
||||
domain = "bhx1.int.${pubDomain}";
|
||||
pubV4 = "77.74.199.67";
|
||||
vpn = {
|
||||
port = 51820;
|
||||
};
|
||||
prefixes = with lib.my.net.cidr; rec {
|
||||
vpn = {
|
||||
v4 = "10.200.0.0/24";
|
||||
v6 = "fdfb:5ebf:6e84::/64";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
tailscale = {
|
||||
prefix = {
|
||||
v4 = "100.64.0.0/10";
|
||||
@@ -380,13 +284,11 @@ rec {
|
||||
as211024 = rec {
|
||||
trusted = {
|
||||
v4 = [
|
||||
colony.prefixes.as211024.v4
|
||||
colony.prefixes.all.v4
|
||||
home.prefixes.all.v4
|
||||
tailscale.prefix.v4
|
||||
];
|
||||
v6 = [
|
||||
colony.prefixes.as211024.v6
|
||||
colony.prefixes.all.v6
|
||||
home.prefixes.all.v6
|
||||
tailscale.prefix.v6
|
||||
@@ -405,7 +307,6 @@ rec {
|
||||
};
|
||||
|
||||
domain = "hentai.engineer";
|
||||
ipv4MTU = 1460;
|
||||
vpn = {
|
||||
port = 51820;
|
||||
};
|
||||
@@ -419,7 +320,6 @@ rec {
|
||||
deploy = ../.keys/deploy.pub;
|
||||
rsyncNet = ../.keys/zh2855.rsync.net.pub;
|
||||
mailcowAcme = ../.keys/mailcow-acme.pub;
|
||||
harmonia = ../.keys/harmonia.pub;
|
||||
};
|
||||
sshHostKeys = {
|
||||
mail-vm = ../.keys/mail-vm-host.pub;
|
||||
|
@@ -1,11 +1,10 @@
|
||||
{ inputs, lib }:
|
||||
{ lib }:
|
||||
let
|
||||
inherit (builtins) length match elemAt filter replaceStrings substring;
|
||||
inherit (builtins) length match elemAt filter replaceStrings;
|
||||
inherit (lib)
|
||||
genAttrs mapAttrsToList filterAttrsRecursive nameValuePair types
|
||||
mkOption mkOverride mkForce mkIf mergeEqualOption optional
|
||||
showWarnings concatStringsSep flatten unique optionalAttrs
|
||||
mkBefore toLower splitString last;
|
||||
showWarnings concatStringsSep flatten unique optionalAttrs;
|
||||
inherit (lib.flake) defaultSystems;
|
||||
in
|
||||
rec {
|
||||
@@ -23,7 +22,7 @@ rec {
|
||||
|
||||
attrsToNVList = mapAttrsToList nameValuePair;
|
||||
|
||||
inherit ((import "${inputs.libnetRepo}/lib/netu.nix" { inherit lib; }).lib) net;
|
||||
inherit (import ./net.nix { inherit lib; }) net;
|
||||
dns = import ./dns.nix { inherit lib; };
|
||||
c = import ./constants.nix { inherit lib; };
|
||||
|
||||
@@ -53,7 +52,7 @@ rec {
|
||||
in mkApp "${app}/bin/${app.meta.mainProgram}";
|
||||
flakePackageOverlay' = flake: pkg: system: (final: prev:
|
||||
let
|
||||
pkg' = if pkg != null then flake.packages.${system}.${pkg} else flake.packages.${system}.default;
|
||||
pkg' = if pkg != null then flake.packages.${system}.${pkg} else flake.defaultPackage.${system};
|
||||
name = if pkg != null then pkg else pkg'.name;
|
||||
in
|
||||
{
|
||||
@@ -167,7 +166,7 @@ rec {
|
||||
|
||||
systemdAwaitPostgres = pkg: host: {
|
||||
after = [ "systemd-networkd-wait-online.service" ];
|
||||
preStart = mkBefore ''
|
||||
preStart = ''
|
||||
until ${pkg}/bin/pg_isready -h ${host}; do
|
||||
sleep 0.5
|
||||
done
|
||||
@@ -240,46 +239,4 @@ rec {
|
||||
|
||||
filterOpts = filterAttrsRecursive (_: v: v != null);
|
||||
};
|
||||
|
||||
versionOverlay = { self, pkgsFlake }: final: prev:
|
||||
let
|
||||
date = substring 0 8 (self.lastModifiedDate or self.lastModified or "19700101");
|
||||
revCode = flake: flake.shortRev or "dirty";
|
||||
in
|
||||
{
|
||||
trivial = prev.trivial // {
|
||||
release = "25.09:u-${prev.trivial.release}";
|
||||
codeName = "Giving";
|
||||
revisionWithDefault = default: self.rev or default;
|
||||
versionSuffix = ".${date}.${revCode self}:u-${revCode pkgsFlake}";
|
||||
};
|
||||
};
|
||||
upstreamRelease = last (splitString "-" lib.trivial.release);
|
||||
|
||||
netbootKeaClientClasses = { tftpIP, hostname, systems }:
|
||||
let
|
||||
testIPXE = "substring(option[user-class].hex, 0, 4) == 'iPXE'";
|
||||
in
|
||||
(mapAttrsToList (name: mac: {
|
||||
name = "nixos-${name}";
|
||||
test = "(${testIPXE}) and (hexstring(pkt4.mac, ':') == '${toLower mac}')";
|
||||
next-server = tftpIP;
|
||||
server-hostname = hostname;
|
||||
boot-file-name = "http://${hostname}/systems/${name}/menu.ipxe";
|
||||
}) systems) ++ [
|
||||
{
|
||||
name = "ipxe";
|
||||
test = testIPXE;
|
||||
next-server = tftpIP;
|
||||
server-hostname = hostname;
|
||||
boot-file-name = "http://${hostname}/boot.ipxe";
|
||||
}
|
||||
{
|
||||
name = "efi-x86_64";
|
||||
test = "option[client-system].hex == 0x0007";
|
||||
next-server = tftpIP;
|
||||
server-hostname = hostname;
|
||||
boot-file-name = "ipxe-x86_64.efi";
|
||||
}
|
||||
];
|
||||
}
|
||||
|
1322
lib/net.nix
Normal file
1322
lib/net.nix
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,191 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.britnet) domain pubV4 prefixes;
|
||||
in
|
||||
{
|
||||
nixos.systems.britnet = {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
|
||||
assignments = {
|
||||
allhost = {
|
||||
inherit domain;
|
||||
ipv4 = {
|
||||
address = pubV4;
|
||||
mask = 24;
|
||||
gateway = "77.74.199.1";
|
||||
};
|
||||
ipv6 = {
|
||||
address = "2a12:ab46:5344:99::a";
|
||||
gateway = "2a12:ab46:5344::1";
|
||||
};
|
||||
};
|
||||
vpn = {
|
||||
ipv4 = {
|
||||
address = net.cidr.host 1 prefixes.vpn.v4;
|
||||
gateway = null;
|
||||
};
|
||||
ipv6.address = net.cidr.host 1 prefixes.vpn.v6;
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) mkMerge mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
"${modulesPath}/profiles/qemu-guest.nix"
|
||||
];
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
boot = {
|
||||
initrd.availableKernelModules = [
|
||||
"ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "ahci" "sr_mod" "virtio_blk"
|
||||
];
|
||||
loader = {
|
||||
systemd-boot.enable = false;
|
||||
grub = {
|
||||
enable = true;
|
||||
device = "/dev/vda";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-uuid/457444a1-81dd-4934-960c-650ad16c92b5";
|
||||
fsType = "ext4";
|
||||
};
|
||||
"/nix" = {
|
||||
device = "/dev/disk/by-uuid/992c0c79-5be6-45b6-bc30-dc82e3ec082a";
|
||||
fsType = "ext4";
|
||||
};
|
||||
"/persist" = {
|
||||
device = "/dev/disk/by-uuid/f020a955-54d5-4098-98ba-d3615781d96a";
|
||||
fsType = "ext4";
|
||||
neededForBoot = true;
|
||||
};
|
||||
};
|
||||
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
wireguard-tools
|
||||
];
|
||||
};
|
||||
|
||||
services = {
|
||||
iperf3 = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
|
||||
tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = config.age.secrets."tailscale-auth.key".path;
|
||||
openFirewall = true;
|
||||
interfaceName = "tailscale0";
|
||||
extraUpFlags = [
|
||||
"--operator=${config.my.user.config.name}"
|
||||
"--login-server=https://hs.nul.ie"
|
||||
"--netfilter-mode=off"
|
||||
"--advertise-exit-node"
|
||||
"--accept-routes=false"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
networking = { inherit domain; };
|
||||
|
||||
systemd.network = {
|
||||
netdevs = {
|
||||
"30-wg0" = {
|
||||
netdevConfig = {
|
||||
Name = "wg0";
|
||||
Kind = "wireguard";
|
||||
};
|
||||
wireguardConfig = {
|
||||
PrivateKeyFile = config.age.secrets."britnet/wg.key".path;
|
||||
ListenPort = lib.my.c.britnet.vpn.port;
|
||||
};
|
||||
wireguardPeers = [
|
||||
{
|
||||
PublicKey = "EfPwREfZ/q3ogHXBIqFZh4k/1NRJRyq4gBkBXtegNkE=";
|
||||
AllowedIPs = [
|
||||
(net.cidr.host 10 prefixes.vpn.v4)
|
||||
(net.cidr.host 10 prefixes.vpn.v6)
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
links = {
|
||||
"10-veth0" = {
|
||||
matchConfig.PermanentMACAddress = "00:db:d9:62:68:1a";
|
||||
linkConfig.Name = "veth0";
|
||||
};
|
||||
};
|
||||
|
||||
networks = {
|
||||
"20-veth0" = mkMerge [
|
||||
(networkdAssignment "veth0" assignments.allhost)
|
||||
{
|
||||
dns = [ "1.1.1.1" "1.0.0.1" ];
|
||||
routes = [
|
||||
{
|
||||
# Gateway is on a different network for some reason...
|
||||
Destination = "2a12:ab46:5344::1";
|
||||
Scope = "link";
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
"30-wg0" = mkMerge [
|
||||
(networkdAssignment "wg0" assignments.vpn)
|
||||
{
|
||||
networkConfig.IPv6AcceptRA = mkForce false;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
server.enable = true;
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJIEx+1EC/lN6WKIaOB+O5LJgVHRK962YpZEPQg/m78O";
|
||||
files = {
|
||||
"tailscale-auth.key" = {};
|
||||
"britnet/wg.key" = {
|
||||
owner = "systemd-network";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
udp.allowed = [ lib.my.c.britnet.vpn.port ];
|
||||
trustedInterfaces = [ "tailscale0" ];
|
||||
extraRules = ''
|
||||
table inet filter {
|
||||
chain forward {
|
||||
iifname wg0 oifname veth0 accept
|
||||
}
|
||||
}
|
||||
table inet nat {
|
||||
chain postrouting {
|
||||
iifname { tailscale0, wg0 } oifname veth0 snat ip to ${assignments.allhost.ipv4.address}
|
||||
iifname { tailscale0, wg0 } oifname veth0 snat ip6 to ${assignments.allhost.ipv6.address}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
@@ -11,24 +11,23 @@ in
|
||||
config = {
|
||||
my = {
|
||||
secrets.files."britway/bgp-password-vultr.conf" = {
|
||||
owner = "bird";
|
||||
group = "bird";
|
||||
owner = "bird2";
|
||||
group = "bird2";
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc."bird/vultr-password.conf".source = config.age.secrets."britway/bgp-password-vultr.conf".path;
|
||||
|
||||
systemd = {
|
||||
services.bird.after = [ "systemd-networkd-wait-online@veth0.service" ];
|
||||
services.bird2.after = [ "systemd-networkd-wait-online@veth0.service" ];
|
||||
network = {
|
||||
config.networkConfig.ManageForeignRoutes = false;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
bird = {
|
||||
bird2 = {
|
||||
enable = true;
|
||||
package = pkgs.bird2;
|
||||
preCheckConfig = ''
|
||||
echo '"dummy"' > vultr-password.conf
|
||||
'';
|
||||
|
@@ -106,7 +106,7 @@ in
|
||||
{
|
||||
matchConfig.Name = "as211024";
|
||||
networkConfig.IPv6AcceptRA = mkForce false;
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = lib.my.c.colony.prefixes.all.v4;
|
||||
Gateway = allAssignments.estuary.as211024.ipv4.address;
|
||||
@@ -123,7 +123,7 @@ in
|
||||
Table = "ts-extra";
|
||||
}
|
||||
];
|
||||
routingPolicyRules = [
|
||||
routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
|
||||
{
|
||||
IncomingInterface = "tailscale0";
|
||||
To = lib.my.c.colony.prefixes.all.v6;
|
||||
@@ -154,7 +154,7 @@ in
|
||||
extraRules = ''
|
||||
table inet filter {
|
||||
chain forward {
|
||||
${lib.my.c.as211024.nftTrust}
|
||||
${lib.my.as211024.nftTrust}
|
||||
oifname as211024 accept
|
||||
}
|
||||
}
|
||||
|
@@ -80,7 +80,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
"hs.${pubDomain}" = {
|
||||
"ts.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:${toString config.services.headscale.port}";
|
||||
proxyWebsockets = true;
|
||||
|
@@ -4,6 +4,20 @@ let
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.britway) prefixes domain;
|
||||
|
||||
# Can't use overrideAttrs because we need to override `vendorHash` within `buildGoModule`
|
||||
headscale = pkgs.headscale.override {
|
||||
buildGoModule = args: pkgs.buildGoModule (args // rec {
|
||||
version = "0.23.0-alpha2";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "juanfont";
|
||||
repo = "headscale";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-sz+uQyyq/5YYDe5I44x5x2nvd48swAhNlInB8KZYvDo=";
|
||||
};
|
||||
vendorHash = "sha256-u9AmJguQ5dnJpfhOeLN43apvMHuraOrJhvlEIp9RoIc=";
|
||||
});
|
||||
};
|
||||
|
||||
advRoutes = concatStringsSep "," [
|
||||
lib.my.c.home.prefixes.all.v4
|
||||
lib.my.c.home.prefixes.all.v6
|
||||
@@ -25,34 +39,29 @@ in
|
||||
services = {
|
||||
headscale = {
|
||||
enable = true;
|
||||
package = headscale;
|
||||
settings = {
|
||||
disable_check_updates = true;
|
||||
unix_socket_permission = "0770";
|
||||
server_url = "https://hs.${pubDomain}";
|
||||
database = {
|
||||
type = "sqlite3";
|
||||
sqlite.path = "/var/lib/headscale/db.sqlite3";
|
||||
};
|
||||
server_url = "https://ts.${pubDomain}";
|
||||
db_type = "sqlite3";
|
||||
db_path = "/var/lib/headscale/db.sqlite3";
|
||||
noise.private_key_path = "/var/lib/headscale/noise_private.key";
|
||||
prefixes = with lib.my.c.tailscale.prefix; { inherit v4 v6; };
|
||||
dns = {
|
||||
override_local_dns = false;
|
||||
# Use IPs that will route inside the VPN to prevent interception
|
||||
# (e.g. DNS rebinding filtering)
|
||||
nameservers.split = {
|
||||
ip_prefixes = with lib.my.c.tailscale.prefix; [ v4 v6 ];
|
||||
dns_config = {
|
||||
restricted_nameservers = {
|
||||
"${domain}" = pubNameservers;
|
||||
"${lib.my.c.colony.domain}" = with allAssignments.estuary.base; [
|
||||
"${lib.my.c.colony.domain}" = with allAssignments.estuary.internal; [
|
||||
ipv4.address ipv6.address
|
||||
];
|
||||
"${lib.my.c.home.domain}" = with allAssignments; [
|
||||
river.hi.ipv4.address
|
||||
river.hi.ipv6.address
|
||||
stream.hi.ipv4.address
|
||||
stream.hi.ipv6.address
|
||||
];
|
||||
"${lib.my.c.home.domain}" = lib.my.c.home.routersPubV4 ++ ([
|
||||
allAssignments.river.as211024.ipv6.address
|
||||
allAssignments.stream.as211024.ipv6.address
|
||||
]);
|
||||
};
|
||||
magic_dns = true;
|
||||
base_domain = "ts.${pubDomain}";
|
||||
override_local_dns = false;
|
||||
};
|
||||
oidc = {
|
||||
only_start_if_oidc_is_available = true;
|
||||
@@ -72,7 +81,7 @@ in
|
||||
interfaceName = "tailscale0";
|
||||
extraUpFlags = [
|
||||
"--operator=${config.my.user.config.name}"
|
||||
"--login-server=https://hs.nul.ie"
|
||||
"--login-server=https://ts.nul.ie"
|
||||
"--netfilter-mode=off"
|
||||
"--advertise-exit-node"
|
||||
"--advertise-routes=${advRoutes}"
|
||||
|
@@ -1,8 +1,7 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) networkd;
|
||||
inherit (lib.my.c.home) domain vlans prefixes vips roceBootModules;
|
||||
inherit (lib.my.c.home) domain vlans prefixes;
|
||||
in
|
||||
{
|
||||
nixos.systems.castle = {
|
||||
@@ -16,7 +15,7 @@ in
|
||||
ipv4 = {
|
||||
address = net.cidr.host 40 prefixes.hi.v4;
|
||||
mask = 22;
|
||||
gateway = vips.hi.v4;
|
||||
gateway = null;
|
||||
};
|
||||
ipv6 = {
|
||||
iid = "::3:1";
|
||||
@@ -36,7 +35,7 @@ in
|
||||
cpu = {
|
||||
amd.updateMicrocode = true;
|
||||
};
|
||||
graphics.extraPackages = with pkgs; [
|
||||
opengl.extraPackages = with pkgs; [
|
||||
intel-media-driver
|
||||
];
|
||||
bluetooth.enable = true;
|
||||
@@ -48,7 +47,7 @@ in
|
||||
timeout = 10;
|
||||
};
|
||||
kernelPackages = lib.my.c.kernel.latest pkgs;
|
||||
kernelModules = [ "kvm-amd" "dm-snapshot" ];
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
kernelParams = [ "amd_iommu=on" "amd_pstate=passive" ];
|
||||
kernelPatches = [
|
||||
# {
|
||||
@@ -58,40 +57,27 @@ in
|
||||
# }
|
||||
];
|
||||
initrd = {
|
||||
availableKernelModules = [
|
||||
"thunderbolt" "xhci_pci" "nvme" "ahci" "usbhid" "usb_storage" "sd_mod"
|
||||
"8021q"
|
||||
] ++ roceBootModules;
|
||||
systemd.network = {
|
||||
netdevs = mkVLAN "lan-hi" vlans.hi;
|
||||
networks = {
|
||||
"10-et100g" = {
|
||||
matchConfig.Name = "et100g";
|
||||
vlan = [ "lan-hi" ];
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
networkConfig = networkd.noL3;
|
||||
availableKernelModules = [ "thunderbolt" "xhci_pci" "nvme" "ahci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
};
|
||||
"20-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
binfmt.emulatedSystems = [ "aarch64-linux" "armv7l-linux" ];
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-partuuid/8ce4248a-3ee4-f44f-801f-064a628b4d6e";
|
||||
fsType = "vfat";
|
||||
};
|
||||
"/nix" = {
|
||||
device = "/dev/nvmeof/nix";
|
||||
device = "/dev/disk/by-partuuid/2da23a1d-2daf-d943-b91e-fc175f3dad07";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
"/persist" = {
|
||||
device = "/dev/nvmeof/persist";
|
||||
device = "/dev/disk/by-partuuid/f4c80d4f-a022-e941-b5d1-fe2e65e444b9";
|
||||
fsType = "ext4";
|
||||
neededForBoot = true;
|
||||
};
|
||||
|
||||
"/home" = {
|
||||
device = "/dev/nvmeof/home";
|
||||
device = "/dev/disk/by-partuuid/992a93cf-6c9c-324b-b0ce-f8eb2d1ce10d";
|
||||
fsType = "ext4";
|
||||
};
|
||||
};
|
||||
@@ -115,12 +101,6 @@ in
|
||||
dnssec = "false";
|
||||
};
|
||||
|
||||
pipewire.extraConfig.pipewire = {
|
||||
"10-buffer"."context.properties" = {
|
||||
"default.clock.quantum" = 128;
|
||||
"default.clock.max-quantum" = 128;
|
||||
};
|
||||
};
|
||||
blueman.enable = true;
|
||||
};
|
||||
|
||||
@@ -134,7 +114,7 @@ in
|
||||
virtualisation.libvirtd.enable = true;
|
||||
|
||||
networking = {
|
||||
inherit domain;
|
||||
domain = "h.${lib.my.c.pubDomain}";
|
||||
firewall.enable = false;
|
||||
};
|
||||
|
||||
@@ -150,19 +130,23 @@ in
|
||||
mstflint
|
||||
qperf
|
||||
ethtool
|
||||
android-tools
|
||||
];
|
||||
environment.etc = {
|
||||
"pipewire/pipewire.conf.d/sample-size.conf".text = ''
|
||||
context.properties = {
|
||||
default.clock.quantum = 128
|
||||
default.clock.max-quantum = 128
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
nix = {
|
||||
gc.automatic = false;
|
||||
settings = {
|
||||
experimental-features = [ "recursive-nix" ];
|
||||
system-features = [ "nixos-test" "benchmark" "big-parallel" "kvm" "recursive-nix" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
network = {
|
||||
wait-online.enable = false;
|
||||
netdevs = mkMerge [
|
||||
(mkVLAN "lan-hi" vlans.hi)
|
||||
];
|
||||
@@ -179,20 +163,29 @@ in
|
||||
matchConfig.PermanentMACAddress = "24:8a:07:a8:fe:3a";
|
||||
linkConfig = {
|
||||
Name = "et100g";
|
||||
MTUBytes = toString lib.my.c.home.hiMTU;
|
||||
MTUBytes = "9000";
|
||||
};
|
||||
};
|
||||
};
|
||||
networks = {
|
||||
"30-et100g" = {
|
||||
"50-lan" = {
|
||||
matchConfig.Name = "et2.5g";
|
||||
DHCP = "no";
|
||||
address = [ "10.16.7.1/16" ];
|
||||
};
|
||||
|
||||
"50-et100g" = {
|
||||
matchConfig.Name = "et100g";
|
||||
vlan = [ "lan-hi" ];
|
||||
networkConfig.IPv6AcceptRA = false;
|
||||
};
|
||||
"40-lan-hi" = mkMerge [
|
||||
"60-lan-hi" = mkMerge [
|
||||
(networkdAssignment "lan-hi" assignments.hi)
|
||||
# So we don't drop the IP we use to connect to NVMe-oF!
|
||||
{ networkConfig.KeepConfiguration = "static"; }
|
||||
{
|
||||
DHCP = "yes";
|
||||
matchConfig.Name = "lan-hi";
|
||||
linkConfig.MTUBytes = "9000";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -212,7 +205,10 @@ in
|
||||
packages = with pkgs; [
|
||||
jacktrip
|
||||
qpwgraph
|
||||
boardie
|
||||
# TODO: seems to be borked (infinite recursion???)
|
||||
# (writeShellScriptBin "boardie" ''
|
||||
# exec pw-jack ${boardie}/bin/boardie "$@"
|
||||
# '')
|
||||
];
|
||||
};
|
||||
|
||||
@@ -226,7 +222,6 @@ in
|
||||
HDMI-A-1 = {
|
||||
transform = "270";
|
||||
position = "0 0";
|
||||
bg = "${./his-team-player.jpg} fill";
|
||||
};
|
||||
DP-1 = {
|
||||
mode = "2560x1440@170Hz";
|
||||
@@ -248,19 +243,11 @@ in
|
||||
};
|
||||
|
||||
#deploy.generate.system.mode = "boot";
|
||||
deploy.node.hostname = "castle.box.${config.networking.domain}";
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMlVuTzKObeaUuPocCF41IO/8X+443lzUJLuCIclt2vr";
|
||||
};
|
||||
netboot.client = {
|
||||
enable = true;
|
||||
};
|
||||
nvme = {
|
||||
uuid = "2230b066-a674-4f45-a1dc-f7727b3a9e7b";
|
||||
boot = {
|
||||
nqn = "nqn.2016-06.io.spdk:castle";
|
||||
address = "192.168.68.80";
|
||||
};
|
||||
};
|
||||
nvme.uuid = "2230b066-a674-4f45-a1dc-f7727b3a9e7b";
|
||||
|
||||
firewall = {
|
||||
enable = false;
|
@@ -1,7 +1,7 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.colony) domain prefixes custRouting firewallForwards;
|
||||
inherit (lib.my.c.colony) domain prefixes firewallForwards;
|
||||
in
|
||||
{
|
||||
imports = [ ./vms ];
|
||||
@@ -60,27 +60,16 @@ in
|
||||
kernelPackages = (lib.my.c.kernel.lts pkgs).extend (self: super: {
|
||||
kernel = super.kernel.override {
|
||||
structuredExtraConfig = with lib.kernel; {
|
||||
ACPI_APEI_PCIEAER = yes;
|
||||
PCIEAER = yes;
|
||||
#SOME_OPT = yes;
|
||||
#A_MOD = module;
|
||||
};
|
||||
};
|
||||
});
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
kernelParams = [
|
||||
"amd_iommu=on"
|
||||
"console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0"
|
||||
"systemd.setenv=SYSTEMD_SULOGIN_FORCE=1"
|
||||
];
|
||||
kernelParams = [ "amd_iommu=on" "console=ttyS0,115200n8" "console=ttyS1,115200n8" "console=tty0" ];
|
||||
initrd = {
|
||||
kernelModules = [ "dm-raid" ];
|
||||
availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "sr_mod" ];
|
||||
systemd = {
|
||||
enable = true;
|
||||
# Onlu activate volumes needed for boot to prevent thin check from getting killed while switching root
|
||||
contents."/etc/lvm/lvm.conf".text = ''
|
||||
activation/auto_activation_volume_list = [ "main/colony-nix" "main/colony-persist" ]
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -148,15 +137,6 @@ in
|
||||
services = {
|
||||
"serial-getty@ttyS0".enable = true;
|
||||
"serial-getty@ttyS1".enable = true;
|
||||
lvm-activate-main = {
|
||||
description = "Activate remaining LVs";
|
||||
unitConfig.DefaultDependencies = false;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.lvm2.bin}/bin/vgchange -aay main";
|
||||
};
|
||||
wantedBy = [ "local-fs-pre.target" ];
|
||||
};
|
||||
|
||||
rsync-lvm-meta = {
|
||||
description = "rsync lvm metadata backups / archives to rsync.net";
|
||||
@@ -252,10 +232,10 @@ in
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.vms.v6;
|
||||
ipv6PrefixConfig.Prefix = prefixes.vms.v6;
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = prefixes.ctrs.v4;
|
||||
Gateway = allAssignments.shill.routing.ipv4.address;
|
||||
@@ -264,12 +244,10 @@ in
|
||||
Destination = prefixes.ctrs.v6;
|
||||
Gateway = allAssignments.shill.internal.ipv6.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = allAssignments.shill.internal.ipv4.address;
|
||||
Gateway = allAssignments.shill.routing.ipv4.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = lib.my.c.tailscale.prefix.v4;
|
||||
Gateway = allAssignments.shill.routing.ipv4.address;
|
||||
@@ -278,15 +256,6 @@ in
|
||||
Destination = lib.my.c.tailscale.prefix.v6;
|
||||
Gateway = allAssignments.shill.internal.ipv6.address;
|
||||
}
|
||||
{
|
||||
Destination = prefixes.qclk.v4;
|
||||
Gateway = allAssignments.shill.routing.ipv4.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = prefixes.jam.v6;
|
||||
Gateway = allAssignments.shill.internal.ipv6.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = prefixes.oci.v4;
|
||||
@@ -318,7 +287,7 @@ in
|
||||
"90-vm-mail" = {
|
||||
matchConfig.Name = "vm-mail";
|
||||
address = [
|
||||
"${custRouting.mail-vm}/32"
|
||||
(net.cidr.subnet 8 1 prefixes.cust.v4)
|
||||
prefixes.mail.v6
|
||||
];
|
||||
networkConfig = {
|
||||
@@ -327,10 +296,10 @@ in
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.mail.v6;
|
||||
ipv6PrefixConfig.Prefix = prefixes.mail.v6;
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = prefixes.mail.v4;
|
||||
Scope = "link";
|
||||
@@ -341,7 +310,7 @@ in
|
||||
"90-vm-darts" = {
|
||||
matchConfig.Name = "vm-darts";
|
||||
address = [
|
||||
"${custRouting.darts-vm}/32"
|
||||
(net.cidr.subnet 8 2 prefixes.cust.v4)
|
||||
prefixes.darts.v6
|
||||
];
|
||||
networkConfig = {
|
||||
@@ -350,10 +319,10 @@ in
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.darts.v6;
|
||||
ipv6PrefixConfig.Prefix = prefixes.darts.v6;
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = prefixes.darts.v4;
|
||||
Scope = "link";
|
||||
|
@@ -29,9 +29,6 @@
|
||||
};
|
||||
in
|
||||
{
|
||||
# Kernel Same-Page Merging to attempt memory usage reduction
|
||||
hardware.ksm.enable = false;
|
||||
|
||||
systemd = {
|
||||
network = {
|
||||
links = {
|
||||
@@ -123,7 +120,7 @@
|
||||
cpus = 12;
|
||||
threads = 2;
|
||||
};
|
||||
memory = 40960;
|
||||
memory = 49152;
|
||||
networks.vms.mac = "52:54:00:27:3d:5c";
|
||||
cleanShutdown.timeout = 120;
|
||||
drives = [ ] ++ (optionals (!config.my.build.isDevVM) [
|
||||
@@ -133,8 +130,7 @@
|
||||
|
||||
(vm.lvmDisk "media")
|
||||
(vm.lvmDisk "minio")
|
||||
(vm.lvmDisk "nix-cache")
|
||||
(vm.lvmDisk "jam")
|
||||
(vm.lvmDisk "nix-atticd")
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -164,7 +160,7 @@
|
||||
cpus = 12;
|
||||
threads = 2;
|
||||
};
|
||||
memory = 40960;
|
||||
memory = 32768;
|
||||
networks.vms.mac = "52:54:00:75:78:a8";
|
||||
cleanShutdown.timeout = 120;
|
||||
drives = [
|
||||
@@ -185,7 +181,7 @@
|
||||
cpus = 3;
|
||||
threads = 2;
|
||||
};
|
||||
memory = 6144;
|
||||
memory = 8192;
|
||||
networks.public = {
|
||||
bridge = null;
|
||||
mac = "52:54:00:a8:d1:03";
|
||||
@@ -213,7 +209,6 @@
|
||||
drives = [
|
||||
(mkMerge [ (vm.disk "darts" "root") { frontendOpts.bootindex = 0; } ])
|
||||
(vm.lvmDisk' "media" "darts-media")
|
||||
(vm.lvmDisk' "ext" "darts-ext")
|
||||
];
|
||||
};
|
||||
};
|
||||
|
@@ -8,9 +8,8 @@ in
|
||||
{
|
||||
config = {
|
||||
services = {
|
||||
bird = {
|
||||
bird2 = {
|
||||
enable = true;
|
||||
package = pkgs.bird2;
|
||||
# TODO: Clean up and modularise
|
||||
config = ''
|
||||
define OWNAS = 211024;
|
||||
@@ -251,87 +250,41 @@ in
|
||||
neighbor 2001:7f8:10f::dc49:254 as 56393;
|
||||
}
|
||||
|
||||
protocol bgp ixp4_frysix_rs3 from ixp_bgp4 {
|
||||
description "Frys-IX route server 3 (IPv4)";
|
||||
neighbor 185.1.160.255 as 56393;
|
||||
}
|
||||
protocol bgp ixp6_frysix_rs3 from ixp_bgp6 {
|
||||
description "Frys-IX route server 3 (IPv6)";
|
||||
neighbor 2001:7f8:10f::dc49:1 as 56393;
|
||||
}
|
||||
|
||||
protocol bgp ixp4_frysix_rs4 from ixp_bgp4 {
|
||||
description "Frys-IX route server 4 (IPv4)";
|
||||
neighbor 185.1.161.0 as 56393;
|
||||
}
|
||||
protocol bgp ixp6_frysix_rs4 from ixp_bgp6 {
|
||||
description "Frys-IX route server 4 (IPv6)";
|
||||
neighbor 2001:7f8:10f::dc49:2 as 56393;
|
||||
}
|
||||
|
||||
protocol bgp peer4_frysix_luje from peer_bgp4 {
|
||||
description "LUJE.net (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.152 as 212855;
|
||||
neighbor 185.1.203.152 as 212855;
|
||||
}
|
||||
protocol bgp peer6_frysix_luje from peer_bgp6 {
|
||||
description "LUJE.net (on Frys-IX, IPv6)";
|
||||
neighbor 2001:7f8:10f::3:3f95:152 as 212855;
|
||||
}
|
||||
|
||||
protocol bgp peer4_frysix_he from peer_bgp4 {
|
||||
description "Hurricane Electric (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.154 as 6939;
|
||||
neighbor 185.1.203.154 as 6939;
|
||||
}
|
||||
|
||||
protocol bgp peer4_frysix_cloudflare1_old from peer_bgp4 {
|
||||
description "Cloudflare 1 (on Frys-IX, IPv4)";
|
||||
protocol bgp peer4_frysix_cloudflare from peer_bgp4 {
|
||||
description "Cloudflare (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.203.217 as 13335;
|
||||
}
|
||||
protocol bgp peer4_frysix_cloudflare2_old from peer_bgp4 {
|
||||
description "Cloudflare 2 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.203.109 as 13335;
|
||||
}
|
||||
protocol bgp peer4_frysix_cloudflare1 from peer_bgp4 {
|
||||
description "Cloudflare 1 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.217 as 13335;
|
||||
}
|
||||
protocol bgp peer4_frysix_cloudflare2 from peer_bgp4 {
|
||||
description "Cloudflare 2 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.109 as 13335;
|
||||
}
|
||||
protocol bgp peer6_frysix_cloudflare1 from peer_bgp6 {
|
||||
description "Cloudflare 1 (on Frys-IX, IPv6)";
|
||||
protocol bgp peer6_frysix_cloudflare from peer_bgp6 {
|
||||
description "Cloudflare (on Frys-IX, IPv6)";
|
||||
neighbor 2001:7f8:10f::3417:217 as 13335;
|
||||
}
|
||||
protocol bgp peer6_frysix_cloudflare2 from peer_bgp6 {
|
||||
description "Cloudflare 2 (on Frys-IX, IPv6)";
|
||||
neighbor 2001:7f8:10f::3417:109 as 13335;
|
||||
}
|
||||
|
||||
protocol bgp peer4_frysix_jurrian from peer_bgp4 {
|
||||
description "AS212635 aka jurrian (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.134 as 212635;
|
||||
neighbor 185.1.203.134 as 212635;
|
||||
}
|
||||
protocol bgp peer6_frysix_jurrian from peer_bgp6 {
|
||||
description "AS212635 aka jurrian (on Frys-IX, IPv6)";
|
||||
neighbor 2001:7f8:10f::3:3e9b:134 as 212635;
|
||||
}
|
||||
|
||||
protocol bgp peer4_frysix_meta1_old from peer_bgp4 {
|
||||
protocol bgp peer4_frysix_meta1 from peer_bgp4 {
|
||||
description "Meta 1 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.203.225 as 32934;
|
||||
}
|
||||
protocol bgp peer4_frysix_meta2_old from peer_bgp4 {
|
||||
description "Meta 2 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.203.226 as 32934;
|
||||
}
|
||||
protocol bgp peer4_frysix_meta1 from peer_bgp4 {
|
||||
description "Meta 1 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.225 as 32934;
|
||||
}
|
||||
protocol bgp peer4_frysix_meta2 from peer_bgp4 {
|
||||
description "Meta 2 (on Frys-IX, IPv4)";
|
||||
neighbor 185.1.160.226 as 32934;
|
||||
neighbor 185.1.203.226 as 32934;
|
||||
}
|
||||
protocol bgp peer6_frysix_meta1 from peer_bgp6 {
|
||||
description "Meta 1 (on Frys-IX, IPv6)";
|
||||
@@ -364,36 +317,36 @@ in
|
||||
ipv6 { preference (PREFIXP-1); };
|
||||
}
|
||||
|
||||
# protocol bgp peer4_nlix_cloudflare1 from peer_bgp4 {
|
||||
# description "Cloudflare NL-ix 1 (IPv4)";
|
||||
# neighbor 193.239.117.14 as 13335;
|
||||
# ipv4 { preference (PREFPEER-1); };
|
||||
# }
|
||||
# protocol bgp peer4_nlix_cloudflare2 from peer_bgp4 {
|
||||
# description "Cloudflare NL-ix 2 (IPv4)";
|
||||
# neighbor 193.239.117.114 as 13335;
|
||||
# ipv4 { preference (PREFPEER-1); };
|
||||
# }
|
||||
# protocol bgp peer4_nlix_cloudflare3 from peer_bgp4 {
|
||||
# description "Cloudflare NL-ix 3 (IPv4)";
|
||||
# neighbor 193.239.118.138 as 13335;
|
||||
# ipv4 { preference (PREFPEER-1); };
|
||||
# }
|
||||
# protocol bgp peer6_nlix_cloudflare1 from peer_bgp6 {
|
||||
# description "Cloudflare NL-ix 1 (IPv6)";
|
||||
# neighbor 2001:7f8:13::a501:3335:1 as 13335;
|
||||
# ipv6 { preference (PREFPEER-1); };
|
||||
# }
|
||||
# protocol bgp peer6_nlix_cloudflare2 from peer_bgp6 {
|
||||
# description "Cloudflare NL-ix 2 (IPv6)";
|
||||
# neighbor 2001:7f8:13::a501:3335:2 as 13335;
|
||||
# ipv6 { preference (PREFPEER-1); };
|
||||
# }
|
||||
# protocol bgp peer6_nlix_cloudflare3 from peer_bgp6 {
|
||||
# description "Cloudflare NL-ix 3 (IPv6)";
|
||||
# neighbor 2001:7f8:13::a501:3335:3 as 13335;
|
||||
# ipv6 { preference (PREFPEER-1); };
|
||||
# }
|
||||
protocol bgp peer4_nlix_cloudflare1 from peer_bgp4 {
|
||||
description "Cloudflare NL-ix 1 (IPv4)";
|
||||
neighbor 193.239.117.14 as 13335;
|
||||
ipv4 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer4_nlix_cloudflare2 from peer_bgp4 {
|
||||
description "Cloudflare NL-ix 2 (IPv4)";
|
||||
neighbor 193.239.117.114 as 13335;
|
||||
ipv4 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer4_nlix_cloudflare3 from peer_bgp4 {
|
||||
description "Cloudflare NL-ix 3 (IPv4)";
|
||||
neighbor 193.239.118.138 as 13335;
|
||||
ipv4 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer6_nlix_cloudflare1 from peer_bgp6 {
|
||||
description "Cloudflare NL-ix 1 (IPv6)";
|
||||
neighbor 2001:7f8:13::a501:3335:1 as 13335;
|
||||
ipv6 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer6_nlix_cloudflare2 from peer_bgp6 {
|
||||
description "Cloudflare NL-ix 2 (IPv6)";
|
||||
neighbor 2001:7f8:13::a501:3335:2 as 13335;
|
||||
ipv6 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer6_nlix_cloudflare3 from peer_bgp6 {
|
||||
description "Cloudflare NL-ix 3 (IPv6)";
|
||||
neighbor 2001:7f8:13::a501:3335:3 as 13335;
|
||||
ipv6 { preference (PREFPEER-1); };
|
||||
}
|
||||
protocol bgp peer4_nlix_jurrian from peer_bgp4 {
|
||||
description "AS212635 aka jurrian (on NL-ix, IPv4)";
|
||||
neighbor 193.239.117.55 as 212635;
|
||||
|
@@ -9,7 +9,6 @@ in
|
||||
vpns = {
|
||||
l2 = {
|
||||
as211024 = {
|
||||
udpEncapsulation = true;
|
||||
vni = 211024;
|
||||
security.enable = true;
|
||||
peers = {
|
||||
@@ -164,9 +163,11 @@ in
|
||||
};
|
||||
wireguardPeers = [
|
||||
{
|
||||
wireguardPeerConfig = {
|
||||
PublicKey = "7N9YdQaCMWWIwAnW37vrthm9ZpbnG4Lx3gheHeRYz2E=";
|
||||
AllowedIPs = [ allAssignments.kelder.estuary.ipv4.address ];
|
||||
PersistentKeepalive = 25;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -219,9 +220,6 @@ in
|
||||
mkMerge
|
||||
[
|
||||
(mkIXPConfig "frys-ix" "185.1.203.196/24" "2001:7f8:10f::3:3850:196/64")
|
||||
# FrysIX is migrating to a /23
|
||||
{ "85-frys-ix".address = [ "185.1.160.196/23" ]; }
|
||||
|
||||
(mkIXPConfig "nl-ix" "193.239.116.145/22" "2001:7f8:13::a521:1024:1/64")
|
||||
(mkIXPConfig "fogixp" "185.1.147.159/24" "2001:7f8:ca:1::159/64")
|
||||
{
|
||||
@@ -279,10 +277,11 @@ in
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.base.v6;
|
||||
ipv6PrefixConfig.Prefix = prefixes.base.v6;
|
||||
}
|
||||
];
|
||||
routes = flatten ([
|
||||
routes = map (r: { routeConfig = r; }) (flatten
|
||||
([
|
||||
{
|
||||
Destination = prefixes.vip1;
|
||||
Gateway = allAssignments.colony.routing.ipv4.address;
|
||||
@@ -308,11 +307,6 @@ in
|
||||
Destination = lib.my.c.tailscale.prefix.v6;
|
||||
Gateway = allAssignments.colony.internal.ipv6.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = prefixes.qclk.v4;
|
||||
Gateway = allAssignments.colony.routing.ipv4.address;
|
||||
}
|
||||
] ++
|
||||
(map (pName: [
|
||||
{
|
||||
@@ -323,7 +317,7 @@ in
|
||||
Destination = prefixes."${pName}".v6;
|
||||
Gateway = allAssignments.colony.internal.ipv6.address;
|
||||
}
|
||||
]) [ "vms" "ctrs" "oci" ]));
|
||||
]) [ "vms" "ctrs" "oci" ])));
|
||||
}
|
||||
];
|
||||
|
||||
@@ -332,7 +326,7 @@ in
|
||||
{
|
||||
matchConfig.Name = "as211024";
|
||||
networkConfig.IPv6AcceptRA = mkForce false;
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = lib.my.c.home.prefixes.all.v4;
|
||||
Gateway = lib.my.c.home.vips.as211024.v4;
|
||||
@@ -344,8 +338,10 @@ in
|
||||
matchConfig.Name = "kelder";
|
||||
routes = [
|
||||
{
|
||||
routeConfig = {
|
||||
Destination = allAssignments.kelder.estuary.ipv4.address;
|
||||
Scope = "link";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -397,24 +393,12 @@ in
|
||||
# Safe enough to allow all SSH
|
||||
tcp dport ssh accept
|
||||
|
||||
# jam-ctr forwards
|
||||
ip daddr ${aa.shill.internal.ipv4.address} tcp dport 60022 accept
|
||||
|
||||
ip6 daddr ${aa.middleman.internal.ipv6.address} tcp dport { http, https, 8448 } accept
|
||||
${matchInet "tcp dport { http, https } accept" "git"}
|
||||
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} tcp dport 25565 accept
|
||||
ip6 daddr ${aa.simpcraft-staging-oci.internal.ipv6.address} tcp dport 25565 accept
|
||||
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} tcp dport 25567 accept
|
||||
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} tcp dport 25568 accept
|
||||
${matchInet "tcp dport { http, https, 8448 } accept" "middleman"}
|
||||
return
|
||||
}
|
||||
chain routing-udp {
|
||||
ip6 daddr ${aa.valheim-oci.internal.ipv6.address} udp dport { 2456-2457 } accept
|
||||
ip6 daddr ${aa.waffletail.internal.ipv6.address} udp dport 41641 accept
|
||||
ip6 daddr ${aa.simpcraft-oci.internal.ipv6.address} udp dport 25565 accept
|
||||
ip6 daddr ${aa.enshrouded-oci.internal.ipv6.address} udp dport { 15636-15637 } accept
|
||||
ip6 daddr ${aa.kevcraft-oci.internal.ipv6.address} udp dport 25567 accept
|
||||
ip6 daddr ${aa.kinkcraft-oci.internal.ipv6.address} udp dport 25568 accept
|
||||
return
|
||||
}
|
||||
chain filter-routing {
|
||||
@@ -445,6 +429,8 @@ in
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
${matchInet "meta l4proto { udp, tcp } th dport domain redirect to :5353" "estuary"}
|
||||
ip daddr ${aa.git.internal.ipv4.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv4.address}
|
||||
ip6 daddr ${aa.git.internal.ipv6.address} tcp dport { http, https } dnat to ${aa.middleman.internal.ipv6.address}
|
||||
}
|
||||
chain postrouting {
|
||||
ip saddr ${prefixes.all.v4} oifname != as211024 snat to ${assignments.internal.ipv4.address}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
let
|
||||
inherit (builtins) attrNames;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.colony) prefixes custRouting;
|
||||
inherit (lib.my.c.colony) prefixes;
|
||||
|
||||
authZones = attrNames config.my.pdns.auth.bind.zones;
|
||||
in
|
||||
@@ -14,7 +14,7 @@ in
|
||||
owner = "pdns";
|
||||
group = "pdns";
|
||||
};
|
||||
"estuary/pdns/recursor.yml" = {
|
||||
"estuary/pdns/recursor.conf" = {
|
||||
owner = "pdns-recursor";
|
||||
group = "pdns-recursor";
|
||||
};
|
||||
@@ -31,7 +31,7 @@ in
|
||||
|
||||
pdns.recursor = {
|
||||
enable = true;
|
||||
extraSettingsFile = config.age.secrets."estuary/pdns/recursor.yml".path;
|
||||
extraSettingsFile = config.age.secrets."estuary/pdns/recursor.conf".path;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -44,37 +44,34 @@ in
|
||||
};
|
||||
|
||||
pdns-recursor = {
|
||||
yaml-settings = {
|
||||
incoming = {
|
||||
listen = [
|
||||
dns = {
|
||||
address = [
|
||||
"127.0.0.1" "::1"
|
||||
assignments.base.ipv4.address assignments.base.ipv6.address
|
||||
];
|
||||
allow_from = [
|
||||
allowFrom = [
|
||||
"127.0.0.0/8" "::1/128"
|
||||
prefixes.all.v4 prefixes.all.v6
|
||||
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
|
||||
|
||||
# DNS NOTIFY messages override TTL
|
||||
allow_notify_for = authZones;
|
||||
allow_notify_from = [ "127.0.0.0/8" "::1/128" ];
|
||||
];
|
||||
};
|
||||
|
||||
outgoing = {
|
||||
source_address = [
|
||||
settings = {
|
||||
query-local-address = [
|
||||
assignments.internal.ipv4.address
|
||||
assignments.internal.ipv6.address
|
||||
assignments.base.ipv6.address
|
||||
];
|
||||
};
|
||||
forward-zones = map (z: "${z}=127.0.0.1:5353") authZones;
|
||||
|
||||
recursor = {
|
||||
forward_zones = map (z: {
|
||||
zone = z;
|
||||
forwarders = [ "127.0.0.1:5353" ];
|
||||
}) authZones;
|
||||
# DNS NOTIFY messages override TTL
|
||||
allow-notify-for = authZones;
|
||||
allow-notify-from = [ "127.0.0.0/8" "::1/128" ];
|
||||
|
||||
lua_dns_script = pkgs.writeText "pdns-script.lua" ''
|
||||
webserver = true;
|
||||
webserver-address = "::";
|
||||
webserver-allow-from = [ "127.0.0.1" "::1" ];
|
||||
|
||||
lua-dns-script = pkgs.writeText "pdns-script.lua" ''
|
||||
function preresolve(dq)
|
||||
if dq.qname:equal("nix-cache.nul.ie") then
|
||||
dq:addAnswer(pdns.CNAME, "http.${config.networking.domain}.")
|
||||
@@ -87,13 +84,6 @@ in
|
||||
end
|
||||
'';
|
||||
};
|
||||
|
||||
webservice = {
|
||||
webserver = true;
|
||||
address = "::";
|
||||
allow_from = [ "127.0.0.1" "::1" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -155,19 +145,9 @@ in
|
||||
|
||||
http IN A ${assignments.internal.ipv4.address}
|
||||
http IN AAAA ${allAssignments.middleman.internal.ipv6.address}
|
||||
librespeed IN CNAME http.${config.networking.domain}.
|
||||
|
||||
valheim IN A ${assignments.internal.ipv4.address}
|
||||
valheim IN AAAA ${allAssignments.valheim-oci.internal.ipv6.address}
|
||||
simpcraft IN A ${assignments.internal.ipv4.address}
|
||||
simpcraft IN AAAA ${allAssignments.simpcraft-oci.internal.ipv6.address}
|
||||
simpcraft-staging IN A ${assignments.internal.ipv4.address}
|
||||
simpcraft-staging IN AAAA ${allAssignments.simpcraft-staging-oci.internal.ipv6.address}
|
||||
enshrouded IN A ${assignments.internal.ipv4.address}
|
||||
kevcraft IN A ${assignments.internal.ipv4.address}
|
||||
kevcraft IN AAAA ${allAssignments.kevcraft-oci.internal.ipv6.address}
|
||||
kinkcraft IN A ${assignments.internal.ipv4.address}
|
||||
kinkcraft IN AAAA ${allAssignments.kinkcraft-oci.internal.ipv6.address}
|
||||
|
||||
mail-vm IN A ${net.cidr.host 0 prefixes.mail.v4}
|
||||
mail-vm IN AAAA ${net.cidr.host 1 prefixes.mail.v6}
|
||||
@@ -177,10 +157,6 @@ in
|
||||
|
||||
andrey-cust IN A ${allAssignments.kelder.estuary.ipv4.address}
|
||||
|
||||
jam-cust IN A ${net.cidr.host 0 prefixes.jam.v4}
|
||||
jam-fwd IN A ${allAssignments.shill.internal.ipv4.address}
|
||||
jam-cust IN AAAA ${net.cidr.host 1 prefixes.jam.v6}
|
||||
|
||||
$TTL 3
|
||||
_acme-challenge IN LUA TXT @@FILE@@
|
||||
|
||||
|
@@ -1,11 +1,8 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (builtins) mapAttrs;
|
||||
inherit (lib) mkMerge mkDefault;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.colony) domain prefixes firewallForwards;
|
||||
inherit (lib.my.c.nginx) baseHttpConfig proxyHeaders;
|
||||
inherit (lib.my.c.colony) domain prefixes;
|
||||
in
|
||||
{
|
||||
nixos.systems.git = {
|
||||
@@ -75,81 +72,9 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
users = {
|
||||
nginx.extraGroups = [ "acme" ];
|
||||
};
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
defaults = {
|
||||
email = "dev@nul.ie";
|
||||
server = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
reloadServices = [ "nginx" ];
|
||||
dnsResolver = "8.8.8.8";
|
||||
};
|
||||
certs = {
|
||||
"${pubDomain}" = {
|
||||
extraDomainNames = [
|
||||
"*.${pubDomain}"
|
||||
];
|
||||
dnsProvider = "cloudflare";
|
||||
credentialsFile = config.age.secrets."middleman/cloudflare-credentials.conf".path;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
fstrim = lib.my.c.colony.fstrimConfig;
|
||||
netdata.enable = true;
|
||||
nginx = {
|
||||
enable = true;
|
||||
enableReload = true;
|
||||
|
||||
logError = "stderr info";
|
||||
recommendedTlsSettings = true;
|
||||
clientMaxBodySize = "0";
|
||||
serverTokens = true;
|
||||
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||
|
||||
# Based on recommended*Settings, but probably better to be explicit about these
|
||||
appendHttpConfig = ''
|
||||
${baseHttpConfig}
|
||||
|
||||
# caching
|
||||
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=512m;
|
||||
'';
|
||||
|
||||
virtualHosts =
|
||||
let
|
||||
hosts = {
|
||||
"_" = {
|
||||
default = true;
|
||||
forceSSL = true;
|
||||
onlySSL = false;
|
||||
locations = {
|
||||
"/".root = "${pkgs.nginx}/html";
|
||||
};
|
||||
};
|
||||
|
||||
"git.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://localhost:3000";
|
||||
};
|
||||
};
|
||||
|
||||
defaultsFor = mapAttrs (n: _: {
|
||||
onlySSL = mkDefault true;
|
||||
useACMEHost = mkDefault pubDomain;
|
||||
kTLS = mkDefault true;
|
||||
http2 = mkDefault true;
|
||||
});
|
||||
in
|
||||
mkMerge [
|
||||
hosts
|
||||
(defaultsFor hosts)
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
virtualisation = {
|
||||
@@ -179,25 +104,11 @@ in
|
||||
};
|
||||
|
||||
my = {
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
|
||||
files = {
|
||||
"dhparams.pem" = {
|
||||
owner = "acme";
|
||||
group = "acme";
|
||||
mode = "440";
|
||||
};
|
||||
"middleman/cloudflare-credentials.conf" = {
|
||||
owner = "acme";
|
||||
group = "acme";
|
||||
};
|
||||
};
|
||||
};
|
||||
secrets.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP+KINpHLMduBuW96JzfSRDLUzkI+XaCBghu5/wHiW5R";
|
||||
server.enable = true;
|
||||
|
||||
firewall = {
|
||||
tcp.allowed = [ 19999 "http" "https" ];
|
||||
nat.forwardPorts."${allAssignments.estuary.internal.ipv4.address}" = firewallForwards allAssignments;
|
||||
tcp.allowed = [ 19999 ];
|
||||
extraRules = ''
|
||||
table inet filter {
|
||||
chain forward {
|
||||
|
@@ -35,11 +35,6 @@ in
|
||||
];
|
||||
url = "https://git.${pubDomain}";
|
||||
tokenFile = config.age.secrets."gitea/actions-runner.env".path;
|
||||
settings = {
|
||||
runner = {
|
||||
timeout = "8h";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -26,6 +26,18 @@ in
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
# TODO: Figure out a way to do this properly... redirecting localhost is awkward...
|
||||
local-http-forward = {
|
||||
description = "Forward local HTTP connections";
|
||||
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:80,fork tcp:${allAssignments.middleman.internal.ipv4.address}:80";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
local-https-forward = {
|
||||
description = "Forward local HTTPS connections";
|
||||
serviceConfig.ExecStart = "${pkgs.socat}/bin/socat tcp-listen:443,fork tcp:${allAssignments.middleman.internal.ipv4.address}:443";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
|
||||
gitea = mkMerge [
|
||||
(lib.my.systemdAwaitPostgres pkgs.postgresql "colony-psql")
|
||||
{
|
||||
@@ -129,6 +141,21 @@ in
|
||||
"gitea/minio.txt" = ownedByGit;
|
||||
};
|
||||
};
|
||||
|
||||
firewall.extraRules = ''
|
||||
table inet filter {
|
||||
chain input {
|
||||
ip saddr ${prefixes.all.v4} tcp dport 3000 accept
|
||||
ip6 saddr ${prefixes.all.v6} tcp dport 3000 accept
|
||||
}
|
||||
}
|
||||
table inet nat {
|
||||
chain prerouting {
|
||||
ip daddr ${assignments.internal.ipv4.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv4.address}
|
||||
ip6 daddr ${assignments.internal.ipv6.address} tcp dport { http, https } dnat to ${allAssignments.middleman.internal.ipv6.address}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -1,105 +0,0 @@
|
||||
{ lib, pkgs, assignments, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.colony) prefixes custRouting;
|
||||
in
|
||||
{
|
||||
fileSystems = {
|
||||
"/mnt/jam" = {
|
||||
device = "/dev/disk/by-label/jam";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
"/var/lib/machines/jam" = {
|
||||
device = "/mnt/jam";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
nspawn = {
|
||||
jam = {
|
||||
enable = true;
|
||||
execConfig = {
|
||||
Boot = true;
|
||||
PrivateUsers = "pick";
|
||||
LinkJournal = false;
|
||||
};
|
||||
networkConfig = {
|
||||
Private = true;
|
||||
VirtualEthernet = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
network.networks = {
|
||||
"50-ve-jam" = {
|
||||
matchConfig = {
|
||||
Kind = "veth";
|
||||
Name = "ve-jam";
|
||||
};
|
||||
address = [
|
||||
custRouting.jam-ctr
|
||||
prefixes.jam.v6
|
||||
];
|
||||
networkConfig = {
|
||||
IPv6AcceptRA = false;
|
||||
IPv6SendRA = true;
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.jam.v6;
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
{
|
||||
Destination = prefixes.jam.v4;
|
||||
Scope = "link";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
services = {
|
||||
"systemd-nspawn@jam" = {
|
||||
overrideStrategy = "asDropin";
|
||||
|
||||
serviceConfig = {
|
||||
CPUQuota = "400%";
|
||||
MemoryHigh = "infinity";
|
||||
MemoryMax = "4G";
|
||||
};
|
||||
|
||||
wantedBy = [ "machines.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
firewall =
|
||||
let
|
||||
jamIP = net.cidr.host 0 prefixes.jam.v4;
|
||||
in
|
||||
{
|
||||
nat.forwardPorts."${assignments.internal.ipv4.address}" = [
|
||||
{
|
||||
port = 60022;
|
||||
dst = jamIP;
|
||||
dstPort = "ssh";
|
||||
}
|
||||
];
|
||||
extraRules = ''
|
||||
table inet filter {
|
||||
chain forward {
|
||||
iifname { ve-jam } oifname vms accept
|
||||
iifname vms oifname { ve-jam } accept
|
||||
}
|
||||
}
|
||||
|
||||
table inet nat {
|
||||
chain postrouting {
|
||||
ip saddr ${jamIP} snat to ${assignments.internal.ipv4.address}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@@ -24,7 +24,7 @@ in
|
||||
|
||||
configuration = { lib, pkgs, config, assignments, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) genAttrs mkMerge mkIf mkForce;
|
||||
inherit (lib) mkMerge mkIf mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
in
|
||||
{
|
||||
@@ -45,22 +45,9 @@ in
|
||||
owner = "matrix-synapse";
|
||||
group = "matrix-synapse";
|
||||
};
|
||||
"chatterbox/doublepuppet.yaml" = {
|
||||
owner = "matrix-synapse";
|
||||
group = "matrix-synapse";
|
||||
};
|
||||
|
||||
"chatterbox/mautrix-whatsapp.env" = {
|
||||
owner = "mautrix-whatsapp";
|
||||
group = "mautrix-whatsapp";
|
||||
};
|
||||
"chatterbox/mautrix-messenger.env" = {
|
||||
owner = "mautrix-meta-messenger";
|
||||
group = "mautrix-meta";
|
||||
};
|
||||
"chatterbox/mautrix-instagram.env" = {
|
||||
owner = "mautrix-meta-instagram";
|
||||
group = "mautrix-meta";
|
||||
"chatterbox/syncv3.env" = {
|
||||
owner = "matrix-syncv3";
|
||||
group = "matrix-syncv3";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -72,23 +59,28 @@ in
|
||||
|
||||
users = with lib.my.c.ids; {
|
||||
users = {
|
||||
matrix-synapse.extraGroups = [
|
||||
"mautrix-whatsapp"
|
||||
];
|
||||
matrix-syncv3 = {
|
||||
isSystemUser = true;
|
||||
uid = uids.matrix-syncv3;
|
||||
group = "matrix-syncv3";
|
||||
};
|
||||
};
|
||||
groups = {
|
||||
matrix-syncv3.gid = gids.matrix-syncv3;
|
||||
};
|
||||
groups = { };
|
||||
};
|
||||
|
||||
systemd = {
|
||||
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
|
||||
services = { } // (genAttrs [ "mautrix-whatsapp" "mautrix-meta-messenger" "mautrix-meta-instagram" ] (_: {
|
||||
# ffmpeg needed to convert GIFs to video
|
||||
path = with pkgs; [ ffmpeg ];
|
||||
}));
|
||||
services = {
|
||||
matrix-sliding-sync.serviceConfig = {
|
||||
# Needs to be able to read its secrets
|
||||
DynamicUser = mkForce false;
|
||||
User = "matrix-syncv3";
|
||||
Group = "matrix-syncv3";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# TODO/FIXME: https://github.com/NixOS/nixpkgs/issues/336052
|
||||
nixpkgs.config.permittedInsecurePackages = [ "olm-3.2.16" ];
|
||||
|
||||
services = {
|
||||
netdata.enable = true;
|
||||
@@ -176,10 +168,18 @@ in
|
||||
|
||||
app_service_config_files = [
|
||||
"/var/lib/heisenbridge/registration.yml"
|
||||
config.age.secrets."chatterbox/doublepuppet.yaml".path
|
||||
];
|
||||
};
|
||||
|
||||
sliding-sync = {
|
||||
enable = true;
|
||||
createDatabase = false;
|
||||
environmentFile = config.age.secrets."chatterbox/syncv3.env".path;
|
||||
settings = {
|
||||
SYNCV3_BINDADDR = "[::]:8009";
|
||||
SYNCV3_SERVER = "http://localhost:8008";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
heisenbridge = {
|
||||
@@ -195,145 +195,6 @@ in
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
mautrix-whatsapp = {
|
||||
enable = true;
|
||||
environmentFile = config.age.secrets."chatterbox/mautrix-whatsapp.env".path;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "nul.ie";
|
||||
};
|
||||
appservice = {
|
||||
database = {
|
||||
type = "postgres";
|
||||
uri = "$MAU_WAPP_PSQL_URI";
|
||||
};
|
||||
id = "whatsapp2";
|
||||
bot = {
|
||||
username = "whatsapp2";
|
||||
displayname = "WhatsApp Bridge Bot";
|
||||
};
|
||||
};
|
||||
bridge = {
|
||||
username_template = "wapp2_{{.}}";
|
||||
displayname_template = "{{or .BusinessName .PushName .JID}} (WA)";
|
||||
personal_filtering_spaces = true;
|
||||
delivery_receipts = true;
|
||||
allow_user_invite = true;
|
||||
url_previews = true;
|
||||
command_prefix = "!wa";
|
||||
login_shared_secret_map."nul.ie" = "$MAU_WAPP_DOUBLE_PUPPET_TOKEN";
|
||||
encryption = {
|
||||
allow = true;
|
||||
default = true;
|
||||
require = true;
|
||||
};
|
||||
permissions = {
|
||||
"@dev:nul.ie" = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
mautrix-meta.instances = {
|
||||
messenger = {
|
||||
enable = true;
|
||||
registerToSynapse = true;
|
||||
dataDir = "mautrix-messenger";
|
||||
environmentFile = config.age.secrets."chatterbox/mautrix-messenger.env".path;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "nul.ie";
|
||||
};
|
||||
appservice = {
|
||||
database = {
|
||||
type = "postgres";
|
||||
uri = "$MAU_FBM_PSQL_URI";
|
||||
};
|
||||
id = "fbm2";
|
||||
bot = {
|
||||
username = "messenger2";
|
||||
displayname = "Messenger Bridge Bot";
|
||||
avatar = "mxc://maunium.net/ygtkteZsXnGJLJHRchUwYWak";
|
||||
};
|
||||
};
|
||||
network = {
|
||||
mode = "messenger";
|
||||
displayname_template = ''{{or .DisplayName .Username "Unknown user"}} (FBM)'';
|
||||
};
|
||||
bridge = {
|
||||
username_template = "fbm2_{{.}}";
|
||||
personal_filtering_spaces = true;
|
||||
delivery_receipts = true;
|
||||
management_room_text.welcome = "Hello, I'm a Messenger bridge bot.";
|
||||
command_prefix = "!fbm";
|
||||
login_shared_secret_map."nul.ie" = "$MAU_FBM_DOUBLE_PUPPET_TOKEN";
|
||||
backfill = {
|
||||
history_fetch_pages = 5;
|
||||
};
|
||||
encryption = {
|
||||
allow = true;
|
||||
default = true;
|
||||
require = true;
|
||||
};
|
||||
permissions = {
|
||||
"@dev:nul.ie" = "admin";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
instagram = {
|
||||
enable = true;
|
||||
registerToSynapse = true;
|
||||
dataDir = "mautrix-instagram";
|
||||
environmentFile = config.age.secrets."chatterbox/mautrix-instagram.env".path;
|
||||
settings = {
|
||||
homeserver = {
|
||||
address = "http://localhost:8008";
|
||||
domain = "nul.ie";
|
||||
};
|
||||
appservice = {
|
||||
database = {
|
||||
type = "postgres";
|
||||
uri = "$MAU_IG_PSQL_URI";
|
||||
};
|
||||
id = "instagram";
|
||||
bot = {
|
||||
username = "instagram";
|
||||
displayname = "Instagram Bridge Bot";
|
||||
avatar = "mxc://maunium.net/JxjlbZUlCPULEeHZSwleUXQv";
|
||||
};
|
||||
};
|
||||
network = {
|
||||
mode = "instagram";
|
||||
displayname_template = ''{{or .DisplayName .Username "Unknown user"}} (IG)'';
|
||||
};
|
||||
bridge = {
|
||||
username_template = "ig_{{.}}";
|
||||
personal_filtering_spaces = true;
|
||||
delivery_receipts = true;
|
||||
management_room_text.welcome = "Hello, I'm an Instagram bridge bot.";
|
||||
command_prefix = "!ig";
|
||||
login_shared_secret_map."nul.ie" = "$MAU_IG_DOUBLE_PUPPET_TOKEN";
|
||||
backfill = {
|
||||
history_fetch_pages = 5;
|
||||
};
|
||||
encryption = {
|
||||
allow = true;
|
||||
default = true;
|
||||
require = true;
|
||||
};
|
||||
permissions = {
|
||||
"@dev:nul.ie" = "admin";
|
||||
"@adzerq:nul.ie" = "user";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
(mkIf config.my.build.isDevVM {
|
||||
|
@@ -8,6 +8,5 @@
|
||||
./object.nix
|
||||
./toot.nix
|
||||
./waffletail.nix
|
||||
./qclk
|
||||
];
|
||||
}
|
||||
|
@@ -1,8 +1,6 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib) concatStringsSep;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.colony) domain prefixes;
|
||||
in
|
||||
{
|
||||
@@ -23,7 +21,7 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, pkgs, config, allAssignments, ... }:
|
||||
configuration = { lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (lib) mkForce;
|
||||
in
|
||||
@@ -37,19 +35,6 @@ in
|
||||
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPUv1ntVrZv5ripsKpcOAnyDQX2PHjowzyhqWK10Ml53";
|
||||
files = {
|
||||
"jackflix/photoprism-pass.txt" = {};
|
||||
"jackflix/copyparty-pass.txt" = {
|
||||
owner = "copyparty";
|
||||
group = "copyparty";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
tcp.allowed = [
|
||||
3923
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -65,21 +50,10 @@ in
|
||||
uid = uids.jellyseerr;
|
||||
group = "jellyseerr";
|
||||
};
|
||||
photoprism = {
|
||||
isSystemUser = true;
|
||||
uid = uids.photoprism;
|
||||
group = "photoprism";
|
||||
};
|
||||
copyparty = {
|
||||
uid = uids.copyparty;
|
||||
extraGroups = [ "media" ];
|
||||
};
|
||||
};
|
||||
groups = {
|
||||
media.gid = 2000;
|
||||
jellyseerr.gid = gids.jellyseerr;
|
||||
photoprism.gid = gids.photoprism;
|
||||
copyparty.gid = gids.copyparty;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -102,10 +76,6 @@ in
|
||||
RootDirectoryStartOnly = lib.mkForce false;
|
||||
RootDirectory = lib.mkForce "";
|
||||
};
|
||||
photoprism.serviceConfig = {
|
||||
# Needs to be able to access its data
|
||||
DynamicUser = mkForce false;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -138,7 +108,6 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
flaresolverr.enable = true;
|
||||
jackett.enable = true;
|
||||
radarr.enable = true;
|
||||
sonarr.enable = true;
|
||||
@@ -148,68 +117,6 @@ in
|
||||
};
|
||||
|
||||
jellyfin.enable = true;
|
||||
|
||||
photoprism = {
|
||||
enable = true;
|
||||
address = "[::]";
|
||||
port = 2342;
|
||||
originalsPath = "/mnt/media/photoprism/originals";
|
||||
importPath = "/mnt/media/photoprism/import";
|
||||
passwordFile = config.age.secrets."jackflix/photoprism-pass.txt".path;
|
||||
settings = {
|
||||
PHOTOPRISM_AUTH_MODE = "password";
|
||||
PHOTOPRISM_ADMIN_USER = "dev";
|
||||
PHOTOPRISM_APP_NAME = "/dev/player0 Photos";
|
||||
PHOTOPRISM_SITE_URL = "https://photos.${pubDomain}/";
|
||||
PHOTOPRISM_SITE_TITLE = "/dev/player0 Photos";
|
||||
PHOTOPRISM_TRUSTED_PROXY = concatStringsSep "," (with prefixes.ctrs; [ v4 v6 ]);
|
||||
PHOTOPRISM_DATABASE_DRIVER = "sqlite";
|
||||
};
|
||||
};
|
||||
|
||||
copyparty = {
|
||||
enable = true;
|
||||
package = pkgs.copyparty.override {
|
||||
withMagic = true;
|
||||
};
|
||||
settings = {
|
||||
name = "dev-stuff";
|
||||
no-reload = true;
|
||||
j = 8; # cores
|
||||
http-only = true;
|
||||
xff-src =
|
||||
with allAssignments.middleman.internal;
|
||||
[ "${ipv4.address}/32" prefixes.ctrs.v6 ];
|
||||
rproxy = 1; # get if from x-forwarded-for
|
||||
magic = true; # enable checking file magic on upload
|
||||
hist = "/var/cache/copyparty";
|
||||
shr = "/share"; # enable share creation
|
||||
ed = true; # enable dotfiles
|
||||
chmod-f = 664;
|
||||
chmod-d = 775;
|
||||
e2dsa = true; # file indexing
|
||||
e2t = true; # metadata indexing
|
||||
og-ua = "(Discord|Twitter|Slack)bot"; # embeds
|
||||
theme = 6;
|
||||
};
|
||||
accounts.dev.passwordFile = config.age.secrets."jackflix/copyparty-pass.txt".path;
|
||||
volumes = {
|
||||
"/" = {
|
||||
path = "/mnt/media/public";
|
||||
access = {
|
||||
A = "dev";
|
||||
"r." = "*";
|
||||
};
|
||||
flags = {
|
||||
shr_who = "no"; # no reason to have shares here
|
||||
};
|
||||
};
|
||||
"/priv" = {
|
||||
path = "/mnt/media/stuff";
|
||||
access.A = "dev"; # dev has admin access
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -37,7 +37,7 @@ in
|
||||
tcp dport ${toString transmissionPeerPort} accept
|
||||
iifname vpn return
|
||||
|
||||
tcp dport { 19999, 9091, 9117, 7878, 8989, 8096, 2342 } accept
|
||||
tcp dport { 19999, 9091, 9117, 7878, 8989, 8096 } accept
|
||||
return
|
||||
}
|
||||
chain input {
|
||||
@@ -71,12 +71,14 @@ in
|
||||
RouteTable = routeTable;
|
||||
};
|
||||
wireguardPeers = [
|
||||
# AirVPN NL
|
||||
{
|
||||
# AirVPN NL
|
||||
wireguardPeerConfig = {
|
||||
Endpoint = "2a00:1678:1337:2329:e5f:35d4:4404:ef9f:1637";
|
||||
PublicKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=";
|
||||
PresharedKeyFile = config.age.secrets."${pskFile}".path;
|
||||
AllowedIPs = [ "0.0.0.0/0" "::/0" ];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -92,7 +94,7 @@ in
|
||||
matchConfig.Name = "vpn";
|
||||
address = [ "10.182.97.37/32" "fd7d:76ee:e68f:a993:735d:ef5e:6907:b122/128" ];
|
||||
dns = [ "10.128.0.1" "fd7d:76ee:e68f:a993::1" ];
|
||||
routingPolicyRules = [
|
||||
routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
|
||||
{
|
||||
Family = "both";
|
||||
SuppressPrefixLength = 0;
|
||||
|
@@ -66,7 +66,6 @@ in
|
||||
owner = "nginx";
|
||||
group = "nginx";
|
||||
};
|
||||
"librespeed.toml" = { };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -123,19 +122,6 @@ in
|
||||
baseURL = "https://sso.${pubDomain}";
|
||||
};
|
||||
};
|
||||
|
||||
librespeed = {
|
||||
frontend.servers = [
|
||||
{
|
||||
name = "Amsterdam, Netherlands";
|
||||
server = "//librespeed.${domain}";
|
||||
}
|
||||
];
|
||||
backend = {
|
||||
enable = true;
|
||||
extraSettingsFile = config.age.secrets."librespeed.toml".path;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users = {
|
||||
@@ -239,9 +225,6 @@ in
|
||||
];
|
||||
|
||||
recommendedTlsSettings = true;
|
||||
recommendedBrotliSettings = true;
|
||||
# Uh so nginx is hanging with zstd enabled... maybe let's not for now
|
||||
# recommendedZstdSettings = true;
|
||||
clientMaxBodySize = "0";
|
||||
serverTokens = true;
|
||||
resolver = {
|
||||
@@ -251,9 +234,6 @@ in
|
||||
proxyResolveWhileRunning = true;
|
||||
sslDhparam = config.age.secrets."dhparams.pem".path;
|
||||
|
||||
appendConfig = ''
|
||||
worker_processes auto;
|
||||
'';
|
||||
# Based on recommended*Settings, but probably better to be explicit about these
|
||||
appendHttpConfig = ''
|
||||
${baseHttpConfig}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
let
|
||||
inherit (builtins) mapAttrs toJSON;
|
||||
inherit (lib) mkMerge mkDefault genAttrs flatten concatStringsSep;
|
||||
inherit (lib.my.c) pubDomain home;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.nginx) proxyHeaders;
|
||||
inherit (config.networking) domain;
|
||||
|
||||
@@ -35,6 +35,7 @@ let
|
||||
# For clients
|
||||
(mkWellKnown "matrix/client" (toJSON {
|
||||
"m.homeserver".base_url = "https://matrix.nul.ie";
|
||||
"org.matrix.msc3575.proxy".url = "https://matrix-syncv3.nul.ie";
|
||||
}))
|
||||
];
|
||||
};
|
||||
@@ -49,7 +50,6 @@ let
|
||||
"/.well-known/webfinger".return = "301 https://toot.nul.ie$request_uri";
|
||||
"/.well-known/nodeinfo".return = "301 https://toot.nul.ie$request_uri";
|
||||
"/.well-known/host-meta".return = "301 https://toot.nul.ie$request_uri";
|
||||
"/.well-known/atproto-did".return = "301 https://pds.nul.ie$request_uri";
|
||||
};
|
||||
in
|
||||
{
|
||||
@@ -80,10 +80,6 @@ in
|
||||
sha256 = "018wh6ps19n7323fi44njzj9yd4wqslc90dykbwfyscv7bgxhlar";
|
||||
};
|
||||
}
|
||||
{
|
||||
name = "ssh.pub";
|
||||
path = lib.my.c.sshKeyFiles.me;
|
||||
}
|
||||
];
|
||||
}
|
||||
wellKnown
|
||||
@@ -149,7 +145,7 @@ in
|
||||
|
||||
"pass.${pubDomain}" =
|
||||
let
|
||||
upstream = "http://vaultwarden-ctr.${domain}:8080";
|
||||
upstream = "http://vaultwarden-ctr.${domain}";
|
||||
in
|
||||
{
|
||||
locations = {
|
||||
@@ -186,6 +182,10 @@ in
|
||||
];
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
"matrix-syncv3.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://chatterbox-ctr.${domain}:8009";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"element.${pubDomain}" =
|
||||
let
|
||||
@@ -206,8 +206,7 @@ in
|
||||
# Currently it seems like single quotes aren't escaped like they should be...
|
||||
conf = {
|
||||
brand = "/dev/player0 Matrix";
|
||||
show_labs_settings = true;
|
||||
default_country_code = "IE";
|
||||
showLabsSettings = true;
|
||||
disable_guests = true;
|
||||
default_server_config = {
|
||||
"m.homeserver" = {
|
||||
@@ -215,8 +214,9 @@ in
|
||||
server_name = "nul.ie";
|
||||
};
|
||||
};
|
||||
room_directory.servers = [
|
||||
roomDirectory.servers = [
|
||||
"nul.ie"
|
||||
"netsoc.ie"
|
||||
"matrix.org"
|
||||
];
|
||||
};
|
||||
@@ -327,15 +327,6 @@ in
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"pds.nul.ie" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://toot-ctr.${domain}:3000";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = proxyHeaders;
|
||||
};
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"share.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://object-ctr.${domain}:9090";
|
||||
@@ -347,16 +338,8 @@ in
|
||||
|
||||
"stuff.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://jackflix-ctr.${domain}:3923";
|
||||
};
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
"public.${pubDomain}" = {
|
||||
onlySSL = false;
|
||||
addSSL = true;
|
||||
serverAliases = [ "p.${pubDomain}" ];
|
||||
locations."/" = {
|
||||
root = "/mnt/media/public";
|
||||
basicAuthFile = config.age.secrets."middleman/htpasswd".path;
|
||||
root = "/mnt/media/stuff";
|
||||
extraConfig = ''
|
||||
fancyindex on;
|
||||
fancyindex_show_dotfiles on;
|
||||
@@ -365,76 +348,8 @@ in
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"mc-map.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://simpcraft-oci.${domain}:8100";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
"mc-rail.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://simpcraft-oci.${domain}:3876";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"mc-map-kink.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://kinkcraft-oci.${domain}:8100";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"librespeed.${domain}" = {
|
||||
locations."/".proxyPass = "http://localhost:8989";
|
||||
};
|
||||
"speed.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://localhost:8989";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"md.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://object-ctr.${domain}:3000";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = proxyHeaders;
|
||||
};
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
"pb.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://object-ctr.${domain}:8088";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
"photos.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://jackflix-ctr.${domain}:2342";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = proxyHeaders;
|
||||
};
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"pront.${pubDomain}" = mkMerge [
|
||||
{
|
||||
locations."/" = mkMerge [
|
||||
{
|
||||
proxyPass = "http://stream-hi.${home.domain}:5000";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = proxyHeaders;
|
||||
}
|
||||
(ssoLoc "generic")
|
||||
];
|
||||
locations."~* ^/webcam/(.*)" = mkMerge [
|
||||
{
|
||||
proxyPass = "http://stream-hi.${home.domain}:5050/$1$is_args$args";
|
||||
extraConfig = proxyHeaders;
|
||||
}
|
||||
(ssoLoc "generic")
|
||||
];
|
||||
useACMEHost = pubDomain;
|
||||
}
|
||||
(ssoServer "generic")
|
||||
];
|
||||
"hass.${pubDomain}" = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://hass-ctr.${home.domain}:8123";
|
||||
proxyWebsockets = true;
|
||||
extraConfig = proxyHeaders;
|
||||
};
|
||||
"git.${pubDomain}" = {
|
||||
locations."/".proxyPass = "http://git-vm.${domain}:3000";
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
};
|
||||
@@ -448,13 +363,10 @@ in
|
||||
ignore_invalid_headers off;
|
||||
'';
|
||||
|
||||
nixCacheableRegex = ''^\/(\S+\.narinfo|nar\/\S+\.nar.*|serve\/.+)$'';
|
||||
nixCacheableRegex = ''^\/(\S+\.narinfo|nar\/\S+\.nar\.\S+)$'';
|
||||
nixCacheHeaders = ''
|
||||
add_header Cache-Control $nix_cache_control;
|
||||
add_header Expires $nix_expires;
|
||||
|
||||
brotli on;
|
||||
brotli_types application/x-nix-archive;
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -475,32 +387,15 @@ in
|
||||
"s3.${pubDomain}" = {
|
||||
serverAliases = [ "*.s3.${pubDomain}" ];
|
||||
inherit extraConfig;
|
||||
locations = {
|
||||
"/".proxyPass = s3Upstream;
|
||||
"/gitea/packages/" = {
|
||||
proxyPass = s3Upstream;
|
||||
# HACK: Docker images need the MIME type to be correct for the manifest but Gitea
|
||||
# doesn't tell S3... By hiding the header we can use add_header to set Content-Type
|
||||
# (normally can't be set directly)
|
||||
extraConfig = ''
|
||||
proxy_hide_header Content-Type;
|
||||
add_header Content-Type $upstream_http_content_type always;
|
||||
if ($args ~ "response-content-disposition=.+filename%3D%22manifest\.json%22") {
|
||||
add_header Content-Type "application/vnd.docker.distribution.manifest.v2+json";
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
locations."/".proxyPass = s3Upstream;
|
||||
useACMEHost = pubDomain;
|
||||
};
|
||||
|
||||
"nix-cache.${pubDomain}" = {
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://${host}:5000";
|
||||
};
|
||||
"/".proxyPass = "http://${host}:8069";
|
||||
"~ ${nixCacheableRegex}" = {
|
||||
proxyPass = "http://${host}:5000";
|
||||
proxyPass = "http://${host}:8069";
|
||||
extraConfig = nixCacheHeaders;
|
||||
};
|
||||
};
|
||||
|
@@ -31,13 +31,6 @@ in
|
||||
{
|
||||
config = mkMerge [
|
||||
{
|
||||
fileSystems = {
|
||||
"/var/lib/harmonia" = {
|
||||
device = "/mnt/nix-cache";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
deploy.enable = false;
|
||||
server.enable = true;
|
||||
@@ -55,21 +48,11 @@ in
|
||||
group = config.my.user.config.group;
|
||||
};
|
||||
"object/atticd.env" = {};
|
||||
"nix-cache.key" = {};
|
||||
"object/hedgedoc.env" = {};
|
||||
"object/wastebin.env" = {};
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
tcp.allowed = [
|
||||
9000 9001
|
||||
config.services.sharry.config.bind.port
|
||||
8069
|
||||
5000
|
||||
config.services.hedgedoc.settings.port
|
||||
8088
|
||||
];
|
||||
tcp.allowed = [ 9000 9001 config.services.sharry.config.bind.port 8069 ];
|
||||
};
|
||||
|
||||
user.homeConfig = {
|
||||
@@ -77,26 +60,14 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
users = with lib.my.c.ids; mkMerge [
|
||||
(let inherit (config.services.atticd) user group; in {
|
||||
users = with lib.my.c.ids; let inherit (config.services.atticd) user group; in {
|
||||
users."${user}" = {
|
||||
isSystemUser = true;
|
||||
uid = uids.atticd;
|
||||
group = group;
|
||||
};
|
||||
groups."${user}".gid = gids.atticd;
|
||||
})
|
||||
{
|
||||
users = {
|
||||
harmonia = {
|
||||
shell = pkgs.bashInteractive;
|
||||
openssh.authorizedKeys.keyFiles = [
|
||||
lib.my.c.sshKeyFiles.harmonia
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
systemd = {
|
||||
network.networks."80-container-host0" = networkdAssignment "host0" assignments.internal;
|
||||
@@ -114,9 +85,7 @@ in
|
||||
MINIO_BROWSER_REDIRECT_URL = "https://minio.nul.ie";
|
||||
};
|
||||
};
|
||||
|
||||
sharry = awaitPostgres;
|
||||
|
||||
atticd = mkMerge [
|
||||
awaitPostgres
|
||||
{
|
||||
@@ -127,15 +96,6 @@ in
|
||||
};
|
||||
}
|
||||
];
|
||||
harmonia = {
|
||||
environment.NIX_REMOTE = "/var/lib/harmonia";
|
||||
preStart = ''
|
||||
${config.nix.package}/bin/nix store ping
|
||||
'';
|
||||
serviceConfig = {
|
||||
StateDirectory = "harmonia";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -215,8 +175,8 @@ in
|
||||
};
|
||||
|
||||
atticd = {
|
||||
enable = false;
|
||||
environmentFile = config.age.secrets."object/atticd.env".path;
|
||||
enable = true;
|
||||
credentialsFile = config.age.secrets."object/atticd.env".path;
|
||||
settings = {
|
||||
listen = "[::]:8069";
|
||||
allowed-hosts = [ "nix-cache.${pubDomain}" ];
|
||||
@@ -234,43 +194,6 @@ in
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
harmonia = {
|
||||
enable = true;
|
||||
signKeyPaths = [ config.age.secrets."nix-cache.key".path ];
|
||||
settings = {
|
||||
priority = 30;
|
||||
};
|
||||
};
|
||||
|
||||
hedgedoc = {
|
||||
enable = true;
|
||||
environmentFile = config.age.secrets."object/hedgedoc.env".path;
|
||||
settings = {
|
||||
domain = "md.${pubDomain}";
|
||||
protocolUseSSL = true;
|
||||
db = {
|
||||
dialect = "postgresql";
|
||||
username = "hedgedoc";
|
||||
database = "hedgedoc";
|
||||
host = "colony-psql";
|
||||
};
|
||||
host = "::";
|
||||
allowAnonymous = false;
|
||||
allowAnonymousEdits = true;
|
||||
email = true;
|
||||
allowEmailRegister = false;
|
||||
};
|
||||
};
|
||||
|
||||
wastebin = {
|
||||
enable = true;
|
||||
settings = {
|
||||
WASTEBIN_MAX_BODY_SIZE = 67108864; # 16 MiB
|
||||
WASTEBIN_PASSWORD_SALT = "TeGhaemeer0Siez3";
|
||||
};
|
||||
secretFile = config.age.secrets."object/wastebin.env".path;
|
||||
};
|
||||
};
|
||||
}
|
||||
(mkIf config.my.build.isDevVM {
|
||||
|
@@ -1,115 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.colony) domain prefixes qclk;
|
||||
in
|
||||
{
|
||||
nixos.systems.qclk = { config, ... }: {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
rendered = config.configuration.config.my.asContainer;
|
||||
|
||||
assignments = {
|
||||
internal = {
|
||||
name = "qclk-ctr";
|
||||
inherit domain;
|
||||
ipv4.address = net.cidr.host 10 prefixes.ctrs.v4;
|
||||
ipv6 = {
|
||||
iid = "::a";
|
||||
address = net.cidr.host 10 prefixes.ctrs.v6;
|
||||
};
|
||||
};
|
||||
qclk = {
|
||||
ipv4 = {
|
||||
address = net.cidr.host 1 prefixes.qclk.v4;
|
||||
gateway = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, pkgs, config, assignments, ... }:
|
||||
let
|
||||
inherit (lib) concatStringsSep mkMerge mkIf mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
|
||||
apiPort = 8080;
|
||||
|
||||
instances = [
|
||||
{
|
||||
host = 2;
|
||||
wgKey = "D7z1FhcdxpnrGCE0wBW5PZb5BKuhCu6tcZ/5ZaYxdwQ=";
|
||||
}
|
||||
];
|
||||
ipFor = i: net.cidr.host i.host prefixes.qclk.v4;
|
||||
in
|
||||
{
|
||||
config = {
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
wireguard-tools
|
||||
];
|
||||
};
|
||||
|
||||
my = {
|
||||
deploy.enable = false;
|
||||
server.enable = true;
|
||||
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC1kcfvahYmSk8IJKaUIcGkhxf/8Yse2XnU7Qqgcglyq";
|
||||
files = {
|
||||
"qclk/wg.key" = {
|
||||
group = "systemd-network";
|
||||
mode = "440";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
udp.allowed = [ qclk.wgPort ];
|
||||
extraRules = ''
|
||||
table inet filter {
|
||||
chain input {
|
||||
iifname management tcp dport ${toString apiPort} accept
|
||||
}
|
||||
chain forward {
|
||||
iifname host0 oifname management ip saddr { ${concatStringsSep ", " lib.my.c.as211024.trusted.v4} } accept
|
||||
}
|
||||
}
|
||||
table inet nat {
|
||||
chain postrouting {
|
||||
iifname host0 oifname management snat ip to ${assignments.qclk.ipv4.address}
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
network = {
|
||||
netdevs."30-management" = {
|
||||
netdevConfig = {
|
||||
Name = "management";
|
||||
Kind = "wireguard";
|
||||
};
|
||||
wireguardConfig = {
|
||||
PrivateKeyFile = config.age.secrets."qclk/wg.key".path;
|
||||
ListenPort = qclk.wgPort;
|
||||
};
|
||||
wireguardPeers = map (i: {
|
||||
PublicKey = i.wgKey;
|
||||
AllowedIPs = [ (ipFor i) ];
|
||||
}) instances;
|
||||
};
|
||||
networks = {
|
||||
"30-container-host0" = networkdAssignment "host0" assignments.internal;
|
||||
|
||||
"30-management" = networkdAssignment "management" assignments.qclk;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@@ -26,8 +26,6 @@ in
|
||||
let
|
||||
inherit (lib) mkMerge mkIf genAttrs;
|
||||
inherit (lib.my) networkdAssignment systemdAwaitPostgres;
|
||||
|
||||
pdsPort = 3000;
|
||||
in
|
||||
{
|
||||
config = mkMerge [
|
||||
@@ -38,7 +36,7 @@ in
|
||||
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILSslLkDe54AKYzxdtKD70zcU72W0EpYsfbdJ6UFq0QK";
|
||||
files = (genAttrs
|
||||
files = genAttrs
|
||||
(map (f: "toot/${f}") [
|
||||
"postgres-password.txt"
|
||||
"secret-key.txt"
|
||||
@@ -50,12 +48,7 @@ in
|
||||
(_: with config.services.mastodon; {
|
||||
owner = user;
|
||||
inherit group;
|
||||
})) // {
|
||||
"toot/pds.env" = {
|
||||
owner = "pds";
|
||||
group = "pds";
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
firewall = {
|
||||
@@ -63,7 +56,6 @@ in
|
||||
19999
|
||||
|
||||
"http"
|
||||
pdsPort
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -87,7 +79,7 @@ in
|
||||
netdata.enable = true;
|
||||
mastodon = mkMerge [
|
||||
rec {
|
||||
enable = false;
|
||||
enable = true;
|
||||
localDomain = extraConfig.WEB_DOMAIN; # for nginx config
|
||||
extraConfig = {
|
||||
LOCAL_DOMAIN = "nul.ie";
|
||||
@@ -95,9 +87,7 @@ in
|
||||
};
|
||||
|
||||
secretKeyBaseFile = config.age.secrets."toot/secret-key.txt".path;
|
||||
# TODO: This was removed at some point.
|
||||
# If we want to bring Mastodon back, this will probably need to be addressd.
|
||||
# otpSecretFile = config.age.secrets."toot/otp-secret.txt".path;
|
||||
otpSecretFile = config.age.secrets."toot/otp-secret.txt".path;
|
||||
vapidPrivateKeyFile = config.age.secrets."toot/vapid-key.txt".path;
|
||||
vapidPublicKeyFile = toString (pkgs.writeText
|
||||
"vapid-pubkey.txt"
|
||||
@@ -165,32 +155,6 @@ in
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
bluesky-pds = {
|
||||
enable = true;
|
||||
environmentFiles = [ config.age.secrets."toot/pds.env".path ];
|
||||
settings = {
|
||||
PDS_HOSTNAME = "pds.nul.ie";
|
||||
PDS_PORT = pdsPort;
|
||||
|
||||
PDS_BLOBSTORE_DISK_LOCATION = null;
|
||||
PDS_BLOBSTORE_S3_BUCKET = "pds";
|
||||
PDS_BLOBSTORE_S3_ENDPOINT = "https://s3.nul.ie/";
|
||||
PDS_BLOBSTORE_S3_REGION = "eu-central-1";
|
||||
PDS_BLOBSTORE_S3_ACCESS_KEY_ID = "pds";
|
||||
PDS_BLOB_UPLOAD_LIMIT = "52428800";
|
||||
|
||||
PDS_EMAIL_FROM_ADDRESS = "pds@nul.ie";
|
||||
|
||||
PDS_DID_PLC_URL = "https://plc.directory";
|
||||
PDS_INVITE_REQUIRED = 1;
|
||||
PDS_BSKY_APP_VIEW_URL = "https://api.bsky.app";
|
||||
PDS_BSKY_APP_VIEW_DID = "did:web:api.bsky.app";
|
||||
PDS_REPORT_SERVICE_URL = "https://mod.bsky.app";
|
||||
PDS_REPORT_SERVICE_DID = "did:plc:ar7c4by46qjdydhdevvrndac";
|
||||
PDS_CRAWLERS = "https://bsky.network";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
(mkIf config.my.build.isDevVM {
|
||||
|
@@ -83,7 +83,7 @@ in
|
||||
DOMAIN = "https://pass.${lib.my.c.pubDomain}";
|
||||
|
||||
ROCKET_ADDRESS = "::";
|
||||
ROCKET_PORT = 8080;
|
||||
ROCKET_PORT = 80;
|
||||
|
||||
SMTP_HOST = "mail.nul.ie";
|
||||
SMTP_FROM = "pass@nul.ie";
|
||||
@@ -99,8 +99,6 @@ in
|
||||
};
|
||||
|
||||
borgbackup.jobs.vaultwarden = {
|
||||
readWritePaths = [ "/var/lib/borgbackup" "/var/cache/borgbackup" ];
|
||||
|
||||
paths = [ vwData ];
|
||||
repo = "zh2855@zh2855.rsync.net:borg/vaultwarden2";
|
||||
doInit = true;
|
||||
|
@@ -86,7 +86,7 @@ in
|
||||
interfaceName = "tailscale0";
|
||||
extraUpFlags = [
|
||||
"--operator=${config.my.user.config.name}"
|
||||
"--login-server=https://hs.nul.ie"
|
||||
"--login-server=https://ts.nul.ie"
|
||||
"--netfilter-mode=off"
|
||||
"--advertise-exit-node"
|
||||
"--advertise-routes=${advRoutes}"
|
||||
|
@@ -49,11 +49,7 @@ in
|
||||
inherit (lib.my) networkdAssignment;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
"${modulesPath}/profiles/qemu-guest.nix"
|
||||
|
||||
./containers-ext.nix
|
||||
];
|
||||
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
|
||||
|
||||
config = mkMerge [
|
||||
{
|
||||
@@ -94,8 +90,8 @@ in
|
||||
device = "/dev/disk/by-label/minio";
|
||||
fsType = "xfs";
|
||||
};
|
||||
"/mnt/nix-cache" = {
|
||||
device = "/dev/disk/by-label/nix-cache";
|
||||
"/mnt/atticd" = {
|
||||
device = "/dev/disk/by-label/atticd";
|
||||
fsType = "ext4";
|
||||
};
|
||||
};
|
||||
@@ -140,10 +136,10 @@ in
|
||||
};
|
||||
ipv6Prefixes = [
|
||||
{
|
||||
Prefix = prefixes.ctrs.v6;
|
||||
ipv6PrefixConfig.Prefix = prefixes.ctrs.v6;
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = lib.my.c.tailscale.prefix.v4;
|
||||
Gateway = allAssignments.waffletail.internal.ipv4.address;
|
||||
@@ -152,11 +148,6 @@ in
|
||||
Destination = lib.my.c.tailscale.prefix.v6;
|
||||
Gateway = allAssignments.waffletail.internal.ipv6.address;
|
||||
}
|
||||
|
||||
{
|
||||
Destination = prefixes.qclk.v4;
|
||||
Gateway = allAssignments.qclk.internal.ipv4.address;
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
@@ -211,12 +202,11 @@ in
|
||||
object = {
|
||||
bindMounts = {
|
||||
"/mnt/minio".readOnly = false;
|
||||
"/mnt/nix-cache".readOnly = false;
|
||||
"/mnt/atticd".readOnly = false;
|
||||
};
|
||||
};
|
||||
toot = {};
|
||||
waffletail = {};
|
||||
qclk = {};
|
||||
};
|
||||
in
|
||||
mkMerge [
|
||||
|
@@ -50,11 +50,6 @@ in
|
||||
};
|
||||
}) {
|
||||
valheim-oci = 2;
|
||||
simpcraft-oci = 3;
|
||||
simpcraft-staging-oci = 4;
|
||||
enshrouded-oci = 5;
|
||||
kevcraft-oci = 6;
|
||||
kinkcraft-oci = 7;
|
||||
};
|
||||
|
||||
configuration = { lib, pkgs, modulesPath, config, assignments, allAssignments, ... }:
|
||||
@@ -68,8 +63,6 @@ in
|
||||
"${modulesPath}/profiles/qemu-guest.nix"
|
||||
|
||||
./valheim.nix
|
||||
./minecraft
|
||||
# ./enshrouded.nix
|
||||
];
|
||||
|
||||
config = mkMerge [
|
||||
@@ -112,31 +105,46 @@ in
|
||||
oci-containers = {
|
||||
backend = "podman";
|
||||
};
|
||||
containers.containersConf.settings.network = {
|
||||
network_backend = "netavark";
|
||||
firewall_driver = "none";
|
||||
};
|
||||
# NixOS has switched to using netavark, which is native to podman. It's currently missing an option to
|
||||
# disable iptables rules generation, which is very annoying.
|
||||
containers.containersConf.settings.network.network_backend = mkForce "cni";
|
||||
};
|
||||
|
||||
environment = {
|
||||
etc = {
|
||||
"containers/networks/colony.json".text = toJSON {
|
||||
"cni/net.d/90-colony.conflist".text = toJSON {
|
||||
cniVersion = "0.4.0";
|
||||
name = "colony";
|
||||
id = "0000000000000000000000000000000000000000000000000000000000000001";
|
||||
driver = "bridge";
|
||||
network_interface = "oci";
|
||||
ipv6_enabled = true;
|
||||
internal = false;
|
||||
dns_enabled = false;
|
||||
subnets = [
|
||||
plugins = [
|
||||
{
|
||||
type = "bridge";
|
||||
bridge = "oci";
|
||||
isGateway = true;
|
||||
ipMasq = false;
|
||||
hairpinMode = true;
|
||||
ipam = {
|
||||
type = "host-local";
|
||||
routes = [
|
||||
{ dst = "0.0.0.0/0"; }
|
||||
{ dst = "::/0"; }
|
||||
];
|
||||
ranges = [
|
||||
[
|
||||
{
|
||||
subnet = prefixes.oci.v4;
|
||||
gateway = net.cidr.host 1 prefixes.oci.v4;
|
||||
}
|
||||
]
|
||||
[
|
||||
{
|
||||
subnet = prefixes.oci.v6;
|
||||
gateway = net.cidr.host 1 prefixes.oci.v6;
|
||||
}
|
||||
]
|
||||
];
|
||||
};
|
||||
capabilities.ips = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
@@ -1,35 +0,0 @@
|
||||
{ lib, config, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) concatStringsSep;
|
||||
inherit (lib.my) dockerNetAssignment;
|
||||
in
|
||||
{
|
||||
config = {
|
||||
virtualisation.oci-containers.containers = {
|
||||
enshrouded = {
|
||||
image = "sknnr/enshrouded-dedicated-server@sha256:f163e8ba9caa2115d8a0a7b16c3696968242fb6fba82706d9a77a882df083497";
|
||||
|
||||
environment = {
|
||||
SERVER_NAME = "UWUshrouded";
|
||||
# SERVER_IP = "::"; # no IPv6?? :(
|
||||
TZ = "Europe/Dublin";
|
||||
};
|
||||
environmentFiles = [ config.age.secrets."whale2/enshrouded.env".path ];
|
||||
|
||||
volumes = [
|
||||
"enshrouded:/home/steam/enshrouded/savegame"
|
||||
];
|
||||
|
||||
extraOptions = [
|
||||
''--network=colony:${dockerNetAssignment allAssignments "enshrouded-oci"}''
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
secrets.files = {
|
||||
"whale2/enshrouded.env" = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@@ -1,228 +0,0 @@
|
||||
{ lib, pkgs, config, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) concatStringsSep;
|
||||
inherit (lib.my) dockerNetAssignment;
|
||||
|
||||
# devplayer0
|
||||
op = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
|
||||
kev = "703b378a-09f9-4c1d-9876-1c9305728c49";
|
||||
whitelist = concatStringsSep "," [
|
||||
op
|
||||
"dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56" # Elderlypug
|
||||
"fcb26db2-c3ce-41aa-b588-efec79d37a8a" # Jesthral_
|
||||
"1d366062-12c0-4e29-aba7-6ab5d8c6bb05" # shr3kas0ras
|
||||
kev
|
||||
"f105bbe6-eda6-4a13-a8cf-894e77cab77b" # Adzerq
|
||||
"1fc94979-41fb-497a-81e9-34ae24ca537a" # johnnyscrims
|
||||
"d53c91df-b6e6-4463-b106-e8427d7a8d01" # BossLonus
|
||||
"f439f64d-91c9-4c74-9ce5-df4d24cd8e05" # hynge_
|
||||
"d6ec4c91-5da2-44eb-b89d-71dc8fe017a0" # Eefah98
|
||||
"096a7348-fabe-4b2d-93fc-fd1fd5608fb0" # ToTheMoonStar
|
||||
];
|
||||
|
||||
fastback = {
|
||||
gitConfig = pkgs.writeText "git-config" ''
|
||||
[user]
|
||||
email = "simpcraft@nul.ie"
|
||||
name = "Simpcraft bot"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
config = {
|
||||
virtualisation.oci-containers.containers = {
|
||||
simpcraft = {
|
||||
image = "git.nul.ie/dev/craftblock:2024.1.0-java17-alpine";
|
||||
|
||||
environment = {
|
||||
TYPE = "MODRINTH";
|
||||
|
||||
EULA = "true";
|
||||
ENABLE_QUERY = "true";
|
||||
ENABLE_RCON = "true";
|
||||
MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t §4§k-----";
|
||||
ICON = "/ext/icon.png";
|
||||
|
||||
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
|
||||
WHITELIST = whitelist;
|
||||
EXISTING_OPS_FILE = "SYNCHRONIZE";
|
||||
OPS = op;
|
||||
DIFFICULTY = "normal";
|
||||
SPAWN_PROTECTION = "0";
|
||||
VIEW_DISTANCE = "20";
|
||||
|
||||
MAX_MEMORY = "8G";
|
||||
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/NGutsQSd/Simpcraft-0.2.1.mrpack";
|
||||
|
||||
TZ = "Europe/Dublin";
|
||||
};
|
||||
environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
|
||||
|
||||
volumes = [
|
||||
"minecraft_data:/data"
|
||||
"${./icon.png}:/ext/icon.png:ro"
|
||||
"${fastback.gitConfig}:/data/.config/git/config:ro"
|
||||
];
|
||||
|
||||
extraOptions = [
|
||||
''--network=colony:${dockerNetAssignment allAssignments "simpcraft-oci"}''
|
||||
];
|
||||
};
|
||||
|
||||
# simpcraft-staging = {
|
||||
# image = "git.nul.ie/dev/craftblock:2024.1.0-java17-alpine";
|
||||
|
||||
# environment = {
|
||||
# TYPE = "MODRINTH";
|
||||
|
||||
# EULA = "true";
|
||||
# ENABLE_QUERY = "true";
|
||||
# ENABLE_RCON = "true";
|
||||
# MOTD = "§4§k----- §9S§ai§bm§cp§dc§er§fa§6f§5t [staging] §4§k-----";
|
||||
# ICON = "/ext/icon.png";
|
||||
|
||||
# EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
|
||||
# WHITELIST = whitelist;
|
||||
# EXISTING_OPS_FILE = "SYNCHRONIZE";
|
||||
# OPS = op;
|
||||
# DIFFICULTY = "normal";
|
||||
# SPAWN_PROTECTION = "0";
|
||||
# VIEW_DISTANCE = "20";
|
||||
|
||||
# MAX_MEMORY = "4G";
|
||||
# MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/Ym3sIi6H/Simpcraft-0.2.0.mrpack";
|
||||
|
||||
# TZ = "Europe/Dublin";
|
||||
# };
|
||||
# environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
|
||||
|
||||
# volumes = [
|
||||
# "minecraft_staging_data:/data"
|
||||
# "${./icon.png}:/ext/icon.png:ro"
|
||||
# ];
|
||||
|
||||
# extraOptions = [
|
||||
# ''--network=colony:${dockerNetAssignment allAssignments "simpcraft-staging-oci"}''
|
||||
# ];
|
||||
# };
|
||||
|
||||
kevcraft = {
|
||||
# 2025.2.1-java21-alpine
|
||||
image = "itzg/minecraft-server@sha256:57e319c15e9fee63f61029a65a33acc3de85118b21a2b4bb29f351cf4a915027";
|
||||
|
||||
environment = {
|
||||
TYPE = "VANILLA";
|
||||
VERSION = "1.20.1";
|
||||
SERVER_PORT = "25567";
|
||||
QUERY_PORT = "25567";
|
||||
|
||||
EULA = "true";
|
||||
ENABLE_QUERY = "true";
|
||||
ENABLE_RCON = "true";
|
||||
MOTD = "§4§k----- §9K§ae§bv§cc§dr§ea§ff§6t §4§k-----";
|
||||
ICON = "/ext/icon.png";
|
||||
|
||||
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
|
||||
WHITELIST = whitelist;
|
||||
EXISTING_OPS_FILE = "SYNCHRONIZE";
|
||||
OPS = concatStringsSep "," [ op kev ];
|
||||
DIFFICULTY = "normal";
|
||||
SPAWN_PROTECTION = "0";
|
||||
# VIEW_DISTANCE = "20";
|
||||
|
||||
MAX_MEMORY = "4G";
|
||||
|
||||
TZ = "Europe/Dublin";
|
||||
};
|
||||
environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
|
||||
|
||||
volumes = [
|
||||
"kevcraft_data:/data"
|
||||
"${./kev.png}:/ext/icon.png:ro"
|
||||
];
|
||||
|
||||
extraOptions = [
|
||||
''--network=colony:${dockerNetAssignment allAssignments "kevcraft-oci"}''
|
||||
];
|
||||
};
|
||||
|
||||
kinkcraft = {
|
||||
# 2025.5.1-java21-alpine
|
||||
image = "itzg/minecraft-server@sha256:de26c7128e3935f3be48fd30283f0b5a6da1b3d9f1a10c9f92502ee1ba072f7b";
|
||||
|
||||
environment = {
|
||||
TYPE = "MODRINTH";
|
||||
SERVER_PORT = "25568";
|
||||
QUERY_PORT = "25568";
|
||||
|
||||
EULA = "true";
|
||||
ENABLE_QUERY = "true";
|
||||
ENABLE_RCON = "true";
|
||||
MOTD = "§4§k----- §9K§ai§bn§ck§dc§er§fa§6f§5t §4§k-----";
|
||||
ICON = "/ext/icon.png";
|
||||
|
||||
EXISTING_WHITELIST_FILE = "SYNCHRONIZE";
|
||||
WHITELIST = whitelist;
|
||||
EXISTING_OPS_FILE = "SYNCHRONIZE";
|
||||
OPS = op;
|
||||
DIFFICULTY = "normal";
|
||||
SPAWN_PROTECTION = "0";
|
||||
VIEW_DISTANCE = "20";
|
||||
|
||||
MAX_MEMORY = "6G";
|
||||
MODRINTH_MODPACK = "https://cdn.modrinth.com/data/CIYf3Hk8/versions/NGutsQSd/Simpcraft-0.2.1.mrpack";
|
||||
|
||||
TZ = "Europe/Dublin";
|
||||
};
|
||||
environmentFiles = [ config.age.secrets."whale2/simpcraft.env".path ];
|
||||
|
||||
volumes = [
|
||||
"kinkcraft_data:/data"
|
||||
"${./icon.png}:/ext/icon.png:ro"
|
||||
];
|
||||
|
||||
extraOptions = [
|
||||
''--network=colony:${dockerNetAssignment allAssignments "kinkcraft-oci"}''
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
services = {
|
||||
borgbackup.jobs.simpcraft =
|
||||
let
|
||||
rconCommand = cmd: ''${pkgs.mcrcon}/bin/mcrcon -H simpcraft-oci -p "$RCON_PASSWORD" "${cmd}"'';
|
||||
in
|
||||
{
|
||||
paths = [ "/var/lib/containers/storage/volumes/minecraft_data/_data/world" ];
|
||||
repo = "/var/lib/containers/backup/simpcraft";
|
||||
doInit = true;
|
||||
encryption.mode = "none";
|
||||
compression = "zstd,10";
|
||||
# every ~15 minutes offset from 5 minute intervals (Minecraft seems to save at precise times?)
|
||||
startAt = "*:03,17,33,47";
|
||||
prune.keep = {
|
||||
within = "12H";
|
||||
hourly = 48;
|
||||
};
|
||||
readWritePaths = [ "/var/lib/borgbackup" "/var/cache/borgbackup" ];
|
||||
|
||||
# Avoid Minecraft poking the files while we back up
|
||||
preHook = rconCommand "save-off";
|
||||
postHook = rconCommand "save-on";
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
borgbackup-job-simpcraft.serviceConfig.EnvironmentFile = [ config.age.secrets."whale2/simpcraft.env".path ];
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
secrets.files = {
|
||||
"whale2/simpcraft.env" = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.2 MiB |
@@ -94,7 +94,7 @@ in
|
||||
extraOptions = [ "-A /var/log/smartd/" "--interval=600" ];
|
||||
};
|
||||
udev.extraRules = ''
|
||||
ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="mlx5_core", ENV{ID_PATH}=="pci-0000:44:00.0", ATTR{device/sriov_numvfs}="4"
|
||||
ACTION=="add", SUBSYSTEM=="net", ENV{ID_NET_DRIVER}=="mlx5_core", ENV{ID_PATH}=="pci-0000:44:00.0", ATTR{device/sriov_numvfs}="2"
|
||||
'';
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ in
|
||||
hwloc
|
||||
];
|
||||
|
||||
networking = { inherit domain; };
|
||||
networking.domain = "h.${pubDomain}";
|
||||
|
||||
systemd = {
|
||||
tmpfiles.rules = [
|
||||
@@ -144,13 +144,6 @@ in
|
||||
|
||||
netdevs = mkMerge [
|
||||
(mkVLAN "lan-hi" vlans.hi)
|
||||
(mkVLAN "lan-lo-phy" vlans.lo)
|
||||
{
|
||||
"25-lan-lo".netdevConfig = {
|
||||
Name = "lan-lo";
|
||||
Kind = "bridge";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
networks = {
|
||||
@@ -158,7 +151,6 @@ in
|
||||
(networkdAssignment "lan-core" assignments.core)
|
||||
{
|
||||
matchConfig.Name = "lan-core";
|
||||
vlan = [ "lan-lo-phy" ];
|
||||
networkConfig.IPv6AcceptRA = mkForce false;
|
||||
}
|
||||
];
|
||||
@@ -181,35 +173,9 @@ in
|
||||
VirtualFunction=1
|
||||
LinkState=yes
|
||||
MACAddress=52:54:00:8a:8a:f2
|
||||
|
||||
# sfh
|
||||
[SR-IOV]
|
||||
VirtualFunction=2
|
||||
VLANId=${toString vlans.hi}
|
||||
LinkState=yes
|
||||
MACAddress=52:54:00:ac:15:a9
|
||||
|
||||
# sfh bridge
|
||||
[SR-IOV]
|
||||
VirtualFunction=3
|
||||
VLANId=${toString vlans.hi}
|
||||
LinkState=yes
|
||||
MACAddress=52:54:00:90:34:95
|
||||
'';
|
||||
};
|
||||
"60-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
|
||||
|
||||
"50-lan-lo-phy" = {
|
||||
matchConfig.Name = "lan-lo-phy";
|
||||
networkConfig = {
|
||||
Bridge = "lan-lo";
|
||||
} // networkd.noL3;
|
||||
};
|
||||
"60-lan-lo" = {
|
||||
matchConfig.Name = "lan-lo";
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
networkConfig = networkd.noL3;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -58,15 +58,12 @@ in
|
||||
};
|
||||
};
|
||||
|
||||
networking = { inherit domain; };
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
pciutils
|
||||
partclone
|
||||
];
|
||||
|
||||
services = {
|
||||
fstrim.enable = true;
|
||||
netdata.enable = true;
|
||||
};
|
||||
|
||||
|
@@ -129,12 +129,6 @@ in
|
||||
hostnqn =
|
||||
"nqn.2014-08.org.nvmexpress:uuid:2230b066-a674-4f45-a1dc-f7727b3a9e7b";
|
||||
serial = "SPDK00000000000002";
|
||||
}) ++ (nvmfBdev {
|
||||
bdev = "NVMeRaidp3";
|
||||
nqn = "nqn.2016-06.io.spdk:sfh";
|
||||
hostnqn =
|
||||
"nqn.2014-08.org.nvmexpress:uuid:85d7df36-0de0-431b-b06e-51f7c0a455b4";
|
||||
serial = "SPDK00000000000003";
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@@ -2,7 +2,6 @@
|
||||
imports = [
|
||||
./cellar
|
||||
./river.nix
|
||||
./sfh
|
||||
];
|
||||
|
||||
nixos.systems.palace.configuration = { lib, pkgs, config, systems, allAssignments, ... }:
|
||||
@@ -56,19 +55,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
let
|
||||
awaitVM = system: {
|
||||
after = [ "vm@${system}.service" ];
|
||||
bindsTo = [ "vm@${system}.service" ];
|
||||
preStart = ''
|
||||
until ${pkgs.netcat}/bin/nc -w1 -z ${allAssignments.${system}.hi.ipv4.address} 22; do
|
||||
sleep 1
|
||||
done
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
systemd.services = {
|
||||
"vm@cellar" = {
|
||||
serviceConfig = {
|
||||
CPUAffinity = "numa";
|
||||
@@ -76,19 +63,20 @@
|
||||
NUMAMask = "1";
|
||||
};
|
||||
};
|
||||
|
||||
"vm@river" =
|
||||
let
|
||||
vtapUnit = "sys-subsystem-net-devices-vm\\x2det1g0.device";
|
||||
in
|
||||
mkMerge [
|
||||
(awaitVM "cellar")
|
||||
{
|
||||
requires = [ vtapUnit ];
|
||||
after = [ vtapUnit ];
|
||||
}
|
||||
];
|
||||
"vm@sfh" = (awaitVM "river");
|
||||
after = [ vtapUnit "vm@cellar.service" ];
|
||||
bindsTo = [ "vm@cellar.service" ];
|
||||
preStart = ''
|
||||
until ${pkgs.netcat}/bin/nc -w1 -z ${allAssignments.cellar.hi.ipv4.address} 22; do
|
||||
sleep 1
|
||||
done
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
@@ -140,7 +128,7 @@
|
||||
threads = 2;
|
||||
};
|
||||
memory = 4096;
|
||||
cleanShutdown.timeout = 60;
|
||||
cleanShutdown.timeout = 120;
|
||||
networks = {
|
||||
et1g0 = {
|
||||
ifname = "vm-et1g0";
|
||||
@@ -162,40 +150,6 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sfh = {
|
||||
uuid = "82ec149d-577c-421a-93e2-a9307c756cd8";
|
||||
cpu = "host,topoext";
|
||||
smp = {
|
||||
cpus = 8;
|
||||
threads = 2;
|
||||
};
|
||||
memory = 32768;
|
||||
cleanShutdown.timeout = 120;
|
||||
networks.netboot = {
|
||||
bridge = "lan-lo";
|
||||
waitOnline = "carrier";
|
||||
mac = "52:54:00:a5:7e:93";
|
||||
extraOptions.bootindex = 1;
|
||||
};
|
||||
hostDevices = {
|
||||
et100g0vf2 = {
|
||||
index = 0;
|
||||
hostBDF = "44:00.3";
|
||||
};
|
||||
et100g0vf3 = {
|
||||
index = 1;
|
||||
hostBDF = "44:00.4";
|
||||
};
|
||||
};
|
||||
qemuFlags = [
|
||||
"device qemu-xhci,id=xhci"
|
||||
# Front-right port?
|
||||
"device usb-host,hostbus=1,hostport=4"
|
||||
# Front-left port
|
||||
"device usb-host,hostbus=1,hostport=3"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -10,7 +10,18 @@
|
||||
let
|
||||
inherit (lib.my) networkdAssignment mkVLAN;
|
||||
inherit (lib.my.c) networkd;
|
||||
inherit (lib.my.c.home) vlans domain prefixes roceBootModules;
|
||||
inherit (lib.my.c.home) vlans;
|
||||
|
||||
lanLink = {
|
||||
matchConfig = {
|
||||
Driver = "mlx5_core";
|
||||
PermanentMACAddress = "52:54:00:8a:8a:f2";
|
||||
};
|
||||
linkConfig = {
|
||||
Name = "lan";
|
||||
MTUBytes = toString lib.my.c.home.hiMTU;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
@@ -19,17 +30,29 @@
|
||||
|
||||
config = {
|
||||
boot = {
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
kernelParams = [ "console=ttyS0,115200n8" ];
|
||||
initrd = {
|
||||
availableKernelModules = [
|
||||
"virtio_pci" "ahci" "sr_mod" "virtio_blk"
|
||||
"8021q"
|
||||
] ++ roceBootModules;
|
||||
kernelModules = [ "dm-snapshot" ];
|
||||
"ib_core" "ib_uverbs" "mlx5_core" "mlx5_ib" "8021q"
|
||||
"rdma_cm" "iw_cm" "ib_cm" "nvme_core" "nvme_rdma"
|
||||
];
|
||||
kernelModules = [ "dm-snapshot" "nvme-fabrics" ];
|
||||
systemd = {
|
||||
extraBin = with pkgs; {
|
||||
dmesg = "${util-linux}/bin/dmesg";
|
||||
ip = "${iproute2}/bin/ip";
|
||||
};
|
||||
extraConfig = ''
|
||||
DefaultTimeoutStartSec=50
|
||||
DefaultDeviceTimeoutSec=50
|
||||
'';
|
||||
network = {
|
||||
# Don't need to put the link config here, they're copied from main config
|
||||
enable = true;
|
||||
wait-online.enable = true;
|
||||
|
||||
links."10-lan" = lanLink;
|
||||
netdevs = mkVLAN "lan-hi" vlans.hi;
|
||||
networks = {
|
||||
"20-lan" = {
|
||||
@@ -47,6 +70,9 @@
|
||||
|
||||
hardware = {
|
||||
enableRedistributableFirmware = true;
|
||||
cpu = {
|
||||
intel.updateMicrocode = true;
|
||||
};
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
@@ -70,7 +96,6 @@
|
||||
boot.thin.enable = true;
|
||||
dmeventd.enable = true;
|
||||
};
|
||||
fstrim.enable = true;
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
@@ -89,16 +114,7 @@
|
||||
};
|
||||
};
|
||||
|
||||
"10-lan" = {
|
||||
matchConfig = {
|
||||
Driver = "mlx5_core";
|
||||
PermanentMACAddress = "52:54:00:8a:8a:f2";
|
||||
};
|
||||
linkConfig = {
|
||||
Name = "lan";
|
||||
MTUBytes = toString lib.my.c.home.hiMTU;
|
||||
};
|
||||
};
|
||||
"10-lan" = lanLink;
|
||||
};
|
||||
|
||||
# So we don't drop the IP we use to connect to NVMe-oF!
|
||||
@@ -118,14 +134,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
netboot.server = {
|
||||
enable = true;
|
||||
ip = assignments.lo.ipv4.address;
|
||||
host = "boot.${domain}";
|
||||
allowedPrefixes = with prefixes; [ hi.v4 hi.v6 lo.v4 lo.v6 ];
|
||||
instances = [ "sfh" "castle" ];
|
||||
};
|
||||
|
||||
deploy.node.hostname = "192.168.68.1";
|
||||
};
|
||||
};
|
||||
|
@@ -1,6 +0,0 @@
|
||||
{
|
||||
imports = [
|
||||
./unifi.nix
|
||||
./hass.nix
|
||||
];
|
||||
}
|
@@ -1,262 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.home) domain prefixes vips hiMTU;
|
||||
in
|
||||
{
|
||||
nixos.systems.hass = { config, ... }: {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
rendered = config.configuration.config.my.asContainer;
|
||||
|
||||
assignments = {
|
||||
hi = {
|
||||
name = "hass-ctr";
|
||||
altNames = [ "frigate" ];
|
||||
inherit domain;
|
||||
mtu = hiMTU;
|
||||
ipv4 = {
|
||||
address = net.cidr.host 103 prefixes.hi.v4;
|
||||
mask = 22;
|
||||
gateway = vips.hi.v4;
|
||||
};
|
||||
ipv6 = {
|
||||
iid = "::5:3";
|
||||
address = net.cidr.host (65536*5+3) prefixes.hi.v6;
|
||||
};
|
||||
};
|
||||
lo = {
|
||||
name = "hass-ctr-lo";
|
||||
inherit domain;
|
||||
mtu = 1500;
|
||||
ipv4 = {
|
||||
address = net.cidr.host 103 prefixes.lo.v4;
|
||||
mask = 21;
|
||||
gateway = null;
|
||||
};
|
||||
ipv6 = {
|
||||
iid = "::5:3";
|
||||
address = net.cidr.host (65536*5+3) prefixes.lo.v6;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, config, pkgs, assignments, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) mkMerge mkIf mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
|
||||
hassCli = pkgs.writeShellScriptBin "hass-cli" ''
|
||||
export HASS_SERVER="http://localhost:${toString config.services.home-assistant.config.http.server_port}"
|
||||
export HASS_TOKEN="$(< ${config.age.secrets."hass/cli-token.txt".path})"
|
||||
exec ${pkgs.home-assistant-cli}/bin/hass-cli "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
config = {
|
||||
my = {
|
||||
deploy.enable = false;
|
||||
server.enable = true;
|
||||
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGpYX2WbYwUqHp8bFFf0eHFrqrR8xp8IheguA054F8V4";
|
||||
files = {
|
||||
"hass/cli-token.txt" = {
|
||||
owner = config.my.user.config.name;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
firewall = {
|
||||
tcp.allowed = [ "http" 1883 ];
|
||||
};
|
||||
};
|
||||
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
usbutils
|
||||
hassCli
|
||||
];
|
||||
};
|
||||
|
||||
systemd = {
|
||||
network.networks = {
|
||||
"80-container-host0" = networkdAssignment "host0" assignments.hi;
|
||||
"80-container-lan-lo" = networkdAssignment "lan-lo" assignments.lo;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
mosquitto = {
|
||||
enable = true;
|
||||
listeners = [
|
||||
{
|
||||
omitPasswordAuth = true;
|
||||
settings = {
|
||||
allow_anonymous = true;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
go2rtc = {
|
||||
enable = true;
|
||||
settings = {
|
||||
streams = {
|
||||
reolink_living_room = [
|
||||
# "http://reolink-living-room.${domain}/flv?port=1935&app=bcs&stream=channel0_main.bcs&user=admin#video=copy#audio=copy#audio=opus"
|
||||
"rtsp://admin:@reolink-living-room:554/h264Preview_01_main"
|
||||
];
|
||||
webcam_office = [
|
||||
"ffmpeg:device?video=/dev/video0&video_size=1024x576#video=h264"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
frigate = {
|
||||
enable = true;
|
||||
hostname = "frigate.${domain}";
|
||||
settings = {
|
||||
mqtt = {
|
||||
enabled = true;
|
||||
host = "localhost";
|
||||
topic_prefix = "frigate";
|
||||
};
|
||||
|
||||
cameras = {
|
||||
reolink_living_room = {
|
||||
ffmpeg.inputs = [
|
||||
{
|
||||
path = "rtsp://127.0.0.1:8554/reolink_living_room";
|
||||
input_args = "preset-rtsp-restream";
|
||||
roles = [ "record" "detect" ];
|
||||
}
|
||||
];
|
||||
detect = {
|
||||
enabled = false;
|
||||
};
|
||||
record = {
|
||||
enabled = true;
|
||||
retain.days = 1;
|
||||
};
|
||||
};
|
||||
|
||||
webcam_office = {
|
||||
ffmpeg.inputs = [
|
||||
{
|
||||
path = "rtsp://127.0.0.1:8554/webcam_office";
|
||||
input_args = "preset-rtsp-restream";
|
||||
roles = [ "record" "detect" ];
|
||||
}
|
||||
];
|
||||
detect.enabled = false;
|
||||
record = {
|
||||
enabled = true;
|
||||
retain.days = 1;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
home-assistant =
|
||||
let
|
||||
cfg = config.services.home-assistant;
|
||||
|
||||
pyirishrail = ps: ps.buildPythonPackage rec {
|
||||
pname = "pyirishrail";
|
||||
version = "0.0.2";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "ttroy50";
|
||||
repo = "pyirishrail";
|
||||
tag = version;
|
||||
hash = "sha256-NgARqhcXP0lgGpgBRiNtQaSn9JcRNtCcZPljcL7t3Xc=";
|
||||
};
|
||||
|
||||
dependencies = with ps; [
|
||||
requests
|
||||
];
|
||||
|
||||
pyproject = true;
|
||||
build-system = [ ps.setuptools ];
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
|
||||
extraComponents = [
|
||||
"default_config"
|
||||
"esphome"
|
||||
"google_translate"
|
||||
|
||||
"met"
|
||||
"zha"
|
||||
"denonavr"
|
||||
"webostv"
|
||||
"androidtv_remote"
|
||||
"heos"
|
||||
"mqtt"
|
||||
"wled"
|
||||
];
|
||||
extraPackages = python3Packages: with python3Packages; [
|
||||
zlib-ng
|
||||
isal
|
||||
|
||||
gtts
|
||||
(pyirishrail python3Packages)
|
||||
];
|
||||
customComponents = with pkgs.home-assistant-custom-components; [
|
||||
alarmo
|
||||
frigate
|
||||
];
|
||||
|
||||
configWritable = false;
|
||||
openFirewall = true;
|
||||
config = {
|
||||
default_config = {};
|
||||
homeassistant = {
|
||||
name = "Home";
|
||||
unit_system = "metric";
|
||||
currency = "EUR";
|
||||
country = "IE";
|
||||
time_zone = "Europe/Dublin";
|
||||
external_url = "https://hass.${pubDomain}";
|
||||
internal_url = "http://hass-ctr.${domain}:${toString cfg.config.http.server_port}";
|
||||
};
|
||||
http = {
|
||||
use_x_forwarded_for = true;
|
||||
trusted_proxies = with allAssignments.middleman.internal; [
|
||||
ipv4.address
|
||||
ipv6.address
|
||||
];
|
||||
ip_ban_enabled = false;
|
||||
};
|
||||
automation = "!include automations.yaml";
|
||||
script = "!include scripts.yaml";
|
||||
scene = "!include scenes.yaml";
|
||||
|
||||
sensor = [
|
||||
{
|
||||
platform = "irish_rail_transport";
|
||||
name = "To Work from Home";
|
||||
station = "Glenageary";
|
||||
stops_at = "Dublin Connolly";
|
||||
direction = "Northbound";
|
||||
}
|
||||
{
|
||||
platform = "irish_rail_transport";
|
||||
name = "To Home from Work";
|
||||
station = "Dublin Connolly";
|
||||
stops_at = "Glenageary";
|
||||
direction = "Southbound";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@@ -1,65 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.home) domain prefixes vips hiMTU;
|
||||
in
|
||||
{
|
||||
nixos.systems.unifi = { config, ... }: {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
rendered = config.configuration.config.my.asContainer;
|
||||
|
||||
assignments = {
|
||||
hi = {
|
||||
name = "unifi-ctr";
|
||||
inherit domain;
|
||||
mtu = hiMTU;
|
||||
ipv4 = {
|
||||
address = net.cidr.host 100 prefixes.hi.v4;
|
||||
mask = 22;
|
||||
gateway = vips.hi.v4;
|
||||
};
|
||||
ipv6 = {
|
||||
iid = "::5:1";
|
||||
address = net.cidr.host (65536*5+1) prefixes.hi.v6;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, config, pkgs, assignments, ... }:
|
||||
let
|
||||
inherit (lib) mkMerge mkIf mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
in
|
||||
{
|
||||
config = {
|
||||
my = {
|
||||
deploy.enable = false;
|
||||
server.enable = true;
|
||||
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKdgcziQki/RH7E+NH2bYnzSVKaJ27905Yo5TcOjSh/U";
|
||||
files = { };
|
||||
};
|
||||
|
||||
firewall = {
|
||||
tcp.allowed = [ 8443 ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
network.networks."80-container-host0" = networkdAssignment "host0" assignments.hi;
|
||||
};
|
||||
|
||||
services = {
|
||||
unifi = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
unifiPackage = pkgs.unifi;
|
||||
mongodbPackage = pkgs.mongodb-7_0;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@@ -1,200 +0,0 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.home) domain prefixes vips hiMTU roceBootModules;
|
||||
in
|
||||
{
|
||||
imports = [ ./containers ];
|
||||
|
||||
config.nixos.systems.sfh = {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
home-manager = "mine";
|
||||
|
||||
assignments = {
|
||||
hi = {
|
||||
inherit domain;
|
||||
mtu = hiMTU;
|
||||
ipv4 = {
|
||||
address = net.cidr.host 81 prefixes.hi.v4;
|
||||
mask = 22;
|
||||
gateway = vips.hi.v4;
|
||||
};
|
||||
ipv6 = {
|
||||
iid = "::4:2";
|
||||
address = net.cidr.host (65536*4+2) prefixes.hi.v6;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configuration = { lib, modulesPath, pkgs, config, assignments, allAssignments, ... }:
|
||||
let
|
||||
inherit (lib) mapAttrs mkMerge mkForce;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
inherit (lib.my.c) networkd;
|
||||
inherit (lib.my.c.home) domain;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
"${modulesPath}/profiles/qemu-guest.nix"
|
||||
];
|
||||
|
||||
config = {
|
||||
boot = {
|
||||
kernelModules = [ "kvm-amd" ];
|
||||
kernelParams = [ "console=ttyS0,115200n8" ];
|
||||
initrd = {
|
||||
availableKernelModules = [
|
||||
"virtio_pci" "ahci" "sr_mod" "virtio_blk"
|
||||
] ++ roceBootModules;
|
||||
kernelModules = [ "dm-snapshot" ];
|
||||
systemd = {
|
||||
network = {
|
||||
networks = {
|
||||
"20-lan-hi" = networkdAssignment "lan-hi" assignments.hi;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
hardware = {
|
||||
enableRedistributableFirmware = true;
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/nix" = {
|
||||
device = "/dev/main/nix";
|
||||
fsType = "ext4";
|
||||
};
|
||||
"/persist" = {
|
||||
device = "/dev/main/persist";
|
||||
fsType = "ext4";
|
||||
neededForBoot = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking = { inherit domain; };
|
||||
|
||||
services = {
|
||||
lvm = {
|
||||
boot.thin.enable = true;
|
||||
dmeventd.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
usbutils
|
||||
];
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
links = {
|
||||
"10-lan-hi" = {
|
||||
matchConfig = {
|
||||
Driver = "mlx5_core";
|
||||
PermanentMACAddress = "52:54:00:ac:15:a9";
|
||||
};
|
||||
linkConfig = {
|
||||
Name = "lan-hi";
|
||||
MTUBytes = toString lib.my.c.home.hiMTU;
|
||||
};
|
||||
};
|
||||
"10-lan-hi-ctrs" = {
|
||||
matchConfig = {
|
||||
Driver = "mlx5_core";
|
||||
PermanentMACAddress = "52:54:00:90:34:95";
|
||||
};
|
||||
linkConfig = {
|
||||
Name = "lan-hi-ctrs";
|
||||
MTUBytes = toString lib.my.c.home.hiMTU;
|
||||
};
|
||||
};
|
||||
"10-lan-lo-ctrs" = {
|
||||
matchConfig = {
|
||||
Driver = "virtio_net";
|
||||
PermanentMACAddress = "52:54:00:a5:7e:93";
|
||||
};
|
||||
linkConfig.Name = "lan-lo-ctrs";
|
||||
};
|
||||
};
|
||||
|
||||
networks = {
|
||||
"30-lan-hi" = mkMerge [
|
||||
(networkdAssignment "lan-hi" assignments.hi)
|
||||
# So we don't drop the IP we use to connect to NVMe-oF!
|
||||
{ networkConfig.KeepConfiguration = "static"; }
|
||||
];
|
||||
"30-lan-hi-ctrs" = {
|
||||
matchConfig.Name = "lan-hi-ctrs";
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
networkConfig = networkd.noL3;
|
||||
};
|
||||
"30-lan-lo-ctrs" = {
|
||||
matchConfig.Name = "lan-lo-ctrs";
|
||||
linkConfig.RequiredForOnline = "no";
|
||||
networkConfig = networkd.noL3;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.nspawn = {
|
||||
hass = {
|
||||
networkConfig = {
|
||||
MACVLAN = mkForce "lan-hi-ctrs:host0 lan-lo-ctrs:lan-lo";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
"systemd-nspawn@hass".serviceConfig.DeviceAllow = [
|
||||
"char-ttyUSB rw"
|
||||
"char-video4linux rw"
|
||||
];
|
||||
};
|
||||
|
||||
my = {
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAAaav5Se1E/AbqEXmADryVszYfNDscyP6jrWioN57R7";
|
||||
};
|
||||
server.enable = true;
|
||||
|
||||
netboot.client = {
|
||||
enable = true;
|
||||
};
|
||||
nvme = {
|
||||
uuid = "85d7df36-0de0-431b-b06e-51f7c0a455b4";
|
||||
boot = {
|
||||
nqn = "nqn.2016-06.io.spdk:sfh";
|
||||
address = "192.168.68.80";
|
||||
};
|
||||
};
|
||||
|
||||
containers.instances =
|
||||
let
|
||||
instances = {
|
||||
# unifi = {};
|
||||
hass = {
|
||||
bindMounts = {
|
||||
"/dev/bus/usb/001/002".readOnly = false;
|
||||
"/dev/video0".readOnly = false;
|
||||
"/dev/serial/by-id/usb-Nabu_Casa_Home_Assistant_Connect_ZBT-1_ce549704fe38ef11a2c2e5d154516304-if00-port0" = {
|
||||
readOnly = false;
|
||||
mountPoint = "/dev/ttyUSB0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
mkMerge [
|
||||
instances
|
||||
(mapAttrs (n: i: {
|
||||
networking.macVLAN = "lan-hi-ctrs";
|
||||
}) instances)
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@@ -141,40 +141,26 @@ in
|
||||
onState = [ "configured" ];
|
||||
script = ''
|
||||
#!${pkgs.runtimeShell}
|
||||
if [ "$IFACE" = "wan-ifb" ]; then
|
||||
${pkgs.iproute2}/bin/tc filter add dev wan parent ffff: matchall action mirred egress redirect dev "$IFACE"
|
||||
if [ $IFACE = "wan-ifb" ]; then
|
||||
${pkgs.iproute2}/bin/tc filter add dev wan parent ffff: matchall action mirred egress redirect dev $IFACE
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nginx.enable = true;
|
||||
};
|
||||
|
||||
networking = { inherit domain; };
|
||||
networking.domain = "h.${pubDomain}";
|
||||
|
||||
systemd.services =
|
||||
systemd.services = {
|
||||
ipsec =
|
||||
let
|
||||
waitOnline = "systemd-networkd-wait-online@wan.service";
|
||||
in
|
||||
{
|
||||
ipsec = {
|
||||
after = [ waitOnline ];
|
||||
requires = [ waitOnline ];
|
||||
};
|
||||
|
||||
ipv6-clear-default-route = {
|
||||
description = "Clear IPv6 RA default route";
|
||||
after = [ waitOnline ];
|
||||
requires = [ waitOnline ];
|
||||
script = ''
|
||||
# Seems like we can sometimes pick up a default route somehow...
|
||||
${pkgs.iproute2}/bin/ip -6 route del default via fe80::1 || true
|
||||
'';
|
||||
serviceConfig.Type = "oneshot";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
@@ -227,8 +213,8 @@ in
|
||||
networkConfig = networkd.noL3;
|
||||
extraConfig = ''
|
||||
[CAKE]
|
||||
Bandwidth=490M
|
||||
RTTSec=50ms
|
||||
Bandwidth=235M
|
||||
RTTSec=10ms
|
||||
PriorityQueueingPreset=besteffort
|
||||
# DOCSIS preset
|
||||
OverheadBytes=18
|
||||
@@ -251,8 +237,8 @@ in
|
||||
extraConfig = ''
|
||||
[CAKE]
|
||||
Parent=root
|
||||
Bandwidth=48M
|
||||
RTTSec=50ms
|
||||
Bandwidth=24M
|
||||
RTTSec=1ms
|
||||
'';
|
||||
}
|
||||
];
|
||||
@@ -276,7 +262,7 @@ in
|
||||
{
|
||||
matchConfig.Name = "as211024";
|
||||
networkConfig.IPv6AcceptRA = mkForce false;
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = lib.my.c.colony.prefixes.all.v4;
|
||||
Gateway = allAssignments.estuary.as211024.ipv4.address;
|
||||
@@ -301,7 +287,7 @@ in
|
||||
|
||||
{
|
||||
"60-lan-hi" = {
|
||||
routes = [
|
||||
routes = map (r: { routeConfig = r; }) [
|
||||
{
|
||||
Destination = elemAt routersPubV4 otherIndex;
|
||||
Gateway = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
|
||||
@@ -339,7 +325,6 @@ in
|
||||
''
|
||||
table inet filter {
|
||||
chain input {
|
||||
${lib.my.c.as211024.nftTrust}
|
||||
iifname base meta l4proto { udp, tcp } th dport domain accept
|
||||
iifname lan-core meta l4proto vrrp accept
|
||||
}
|
||||
@@ -372,16 +357,6 @@ in
|
||||
return
|
||||
}
|
||||
|
||||
chain forward-early {
|
||||
type filter hook forward priority -1; policy accept;
|
||||
|
||||
# MSS clamping to workaround IPv6 PMTUD being broken...
|
||||
tcp flags syn tcp option maxseg size set rt mtu counter
|
||||
|
||||
# More Disney+ discrimination...
|
||||
# TODO: This prefix could change (random AWS block)
|
||||
ip6 daddr 2600:9000:2245::/48 drop
|
||||
}
|
||||
chain forward {
|
||||
${lib.my.c.as211024.nftTrust}
|
||||
iifname lan-untrusted jump filter-untrusted
|
||||
|
@@ -1,74 +0,0 @@
|
||||
# Blocklist for LG WebOS Services (US)
|
||||
ad.lgappstv.com
|
||||
ibis.lgappstv.com
|
||||
info.lgsmartad.com
|
||||
lgtvsdp.com
|
||||
ngfts.lge.com
|
||||
rdx2.lgtvsdp.com
|
||||
smartshare.lgtvsdp.com
|
||||
lgappstv.com
|
||||
us.ad.lgsmartad.com
|
||||
us.ibs.lgappstv.com
|
||||
us.info.lgsmartad.com
|
||||
us.lgtvsdp.com
|
||||
|
||||
# Community Contributions
|
||||
lgad.cjpowercast.com
|
||||
edgesuite.net
|
||||
yumenetworks.com
|
||||
smartclip.net
|
||||
smartclip.com
|
||||
|
||||
# Non-US Entries
|
||||
rdx2.lgtvsdp.com
|
||||
info.lgsmartad.com
|
||||
ibs.lgappstv.com
|
||||
lgtvsdp.com
|
||||
lgappstv.com
|
||||
smartshare.lgtvsdp.com
|
||||
|
||||
# Full Block for Europe and Other Regions
|
||||
de.ad.lgsmartad.com
|
||||
de.emp.lgsmartplatform.com
|
||||
de.ibs.lgappstv.com
|
||||
de.info.lgsmartad.com
|
||||
de.lgeapi.com
|
||||
de.lgtvsdp.com
|
||||
de.rdx2.lgtvsdp.com
|
||||
eu.ad.lgsmartad.com
|
||||
eu.ibs.lgappstv.com
|
||||
eu.info.lgsmartad.com
|
||||
app-lgwebos.pluto.tv
|
||||
it.lgtvsdp.com
|
||||
it.lgeapi.com
|
||||
it.emp.lgsmartplatform.com
|
||||
|
||||
# LG ThinQ Services
|
||||
eic.common.lgthinq.com
|
||||
eic.iotservice.lgthinq.com
|
||||
eic.service.lgthinq.com
|
||||
eic.ngfts.lge.com
|
||||
eic.svc-lgthinq-com.aws-thinq-prd.net
|
||||
eic.cdpsvc.lgtvcommon.com
|
||||
eic.cdpbeacon.lgtvcommon.com
|
||||
eic.cdplauncher.lgtvcommon.com
|
||||
eic.homeprv.lgtvcommon.com
|
||||
eic.lgtviot.com
|
||||
eic.nudge.lgtvcommon.com
|
||||
eic.rdl.lgtvcommon.com
|
||||
eic.recommend.lgtvcommon.com
|
||||
eic.service.lgtvcommon.com
|
||||
gb-lgeapi-com.esi-prd.net
|
||||
gb.lgeapi.com
|
||||
lgtvonline.lge.com
|
||||
lg-channelplus-de-beacons.xumo.com
|
||||
lg-channelplus-de-mds.xumo.com
|
||||
lg-channelplus-eu-beacons.xumo.com
|
||||
lg-channelplus-eu-mds.xumo.com
|
||||
kr-op-v2.lgthinqhome.com
|
||||
ngfts.lge.com
|
||||
noti.lgthinq.com
|
||||
objectcontent.lgthinq.com
|
||||
|
||||
# Update Server Block
|
||||
#snu.lge.com
|
@@ -2,7 +2,6 @@ index: { lib, pkgs, config, assignments, allAssignments, ... }:
|
||||
let
|
||||
inherit (builtins) attrNames elemAt;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c) pubDomain;
|
||||
inherit (lib.my.c.home) prefixes vips routers;
|
||||
|
||||
name = elemAt routers index;
|
||||
@@ -19,121 +18,54 @@ in
|
||||
owner = "pdns";
|
||||
group = "pdns";
|
||||
};
|
||||
"home/pdns/recursor.yml" = {
|
||||
"home/pdns/recursor.conf" = {
|
||||
owner = "pdns-recursor";
|
||||
group = "pdns-recursor";
|
||||
};
|
||||
"home/ddclient-cloudflare.key" = {};
|
||||
};
|
||||
|
||||
pdns.recursor = {
|
||||
enable = true;
|
||||
extraSettingsFile = config.age.secrets."home/pdns/recursor.yml".path;
|
||||
extraSettingsFile = config.age.secrets."home/pdns/recursor.conf".path;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
pdns-recursor = {
|
||||
yaml-settings = {
|
||||
incoming = {
|
||||
listen = [
|
||||
dns = {
|
||||
address = [
|
||||
"127.0.0.1" "::1"
|
||||
assignments.hi.ipv4.address assignments.hi.ipv6.address
|
||||
assignments.lo.ipv4.address assignments.lo.ipv6.address
|
||||
];
|
||||
allow_from = [
|
||||
allowFrom = [
|
||||
"127.0.0.0/8" "::1/128"
|
||||
prefixes.hi.v4 prefixes.hi.v6
|
||||
prefixes.lo.v4 prefixes.lo.v6
|
||||
] ++ (with lib.my.c.tailscale.prefix; [ v4 v6 ]);
|
||||
];
|
||||
};
|
||||
|
||||
settings = {
|
||||
query-local-address = [
|
||||
"0.0.0.0"
|
||||
"::"
|
||||
];
|
||||
forward-zones = map (z: "${z}=127.0.0.1:5353") authZones;
|
||||
|
||||
# DNS NOTIFY messages override TTL
|
||||
allow_notify_for = authZones;
|
||||
allow_notify_from = [ "127.0.0.0/8" "::1/128" ];
|
||||
};
|
||||
allow-notify-for = authZones;
|
||||
allow-notify-from = [ "127.0.0.0/8" "::1/128" ];
|
||||
|
||||
outgoing = {
|
||||
source_address = [ "0.0.0.0" "::" ];
|
||||
};
|
||||
|
||||
recursor = {
|
||||
forward_zones = map (z: {
|
||||
zone = z;
|
||||
forwarders = [ "127.0.0.1:5353" ];
|
||||
}) authZones;
|
||||
|
||||
lua_dns_script = pkgs.writeText "pdns-script.lua" ''
|
||||
blocklist = newDS()
|
||||
|
||||
function preresolve(dq)
|
||||
local name = dq.qname:toString()
|
||||
|
||||
-- Disney+ doesn't like our IP space...
|
||||
if dq.qtype == pdns.AAAA and (string.find(name, "disneyplus") or string.find(name, "disney-plus") or string.find(name , "disney.api")) then
|
||||
dq.rcode = 0
|
||||
return true
|
||||
end
|
||||
|
||||
if blocklist:check(dq.qname) then
|
||||
if dq.qtype == pdns.A then
|
||||
dq:addAnswer(dq.qtype, "127.0.0.1")
|
||||
elseif dq.qtype == pdns.AAAA then
|
||||
dq:addAnswer(dq.qtype, "::1")
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
for line in io.lines("${./dns-blocklist.txt}") do
|
||||
entry = line:gsub("%s+", "")
|
||||
if entry ~= "" and string.sub(entry, 1, 1) ~= "#" then
|
||||
blocklist:add(entry)
|
||||
end
|
||||
end
|
||||
'';
|
||||
};
|
||||
|
||||
webservice = {
|
||||
webserver = true;
|
||||
address = "::";
|
||||
allow_from = [ "127.0.0.1" "::1" ];
|
||||
};
|
||||
webserver-address = "::";
|
||||
webserver-allow-from = [ "127.0.0.1" "::1" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
services = {
|
||||
systemd.services = {
|
||||
# Add AF_NETLINK to allow pulling IP from network interfaces
|
||||
pdns.serviceConfig.RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
||||
ddns-update = {
|
||||
description = "DNS update script";
|
||||
after = [ "network.target" ];
|
||||
path = [
|
||||
(pkgs.python3.withPackages (ps: [ ps.cloudflare ]))
|
||||
pkgs.ldns
|
||||
];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart =
|
||||
''${./dns_update.py} -k ${config.age.secrets."home/ddclient-cloudflare.key".path} '' +
|
||||
''${pubDomain} ns${toString (index + 1)}.${config.networking.domain}'';
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
timers = {
|
||||
ddns-update = {
|
||||
description = "Periodically update DNS";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "5min";
|
||||
OnUnitInactiveSec = "5min";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
@@ -196,9 +128,8 @@ in
|
||||
hostname = "${otherName}.${config.networking.domain}";
|
||||
server = net.cidr.host (otherIndex + 1) prefixes.hi.v4;
|
||||
}}
|
||||
${elemAt routers 0} IN AAAA ${allAssignments."${elemAt routers 0}".as211024.ipv6.address}
|
||||
${elemAt routers 1} IN AAAA ${allAssignments."${elemAt routers 1}".as211024.ipv6.address}
|
||||
boot IN CNAME river-hi.${config.networking.domain}.
|
||||
${elemAt routers 0} IN AAAA ${net.cidr.host 1 prefixes.hi.v6}
|
||||
${elemAt routers 1} IN AAAA ${net.cidr.host 2 prefixes.hi.v6}
|
||||
|
||||
@ IN NS ns1
|
||||
@ IN NS ns2
|
||||
@@ -222,19 +153,9 @@ in
|
||||
dave-lo IN A ${net.cidr.host 11 prefixes.lo.v4}
|
||||
dave-lo IN AAAA ${net.cidr.host (65536+2) prefixes.lo.v6}
|
||||
|
||||
shytzel IN A ${net.cidr.host 12 prefixes.core.v4}
|
||||
|
||||
wave IN A ${net.cidr.host 12 prefixes.hi.v4}
|
||||
; wave IN AAAA ${net.cidr.host (65536+3) prefixes.hi.v6}
|
||||
vibe IN A ${net.cidr.host 13 prefixes.hi.v4}
|
||||
vibe IN AAAA ${net.cidr.host (65536+4) prefixes.hi.v6}
|
||||
|
||||
ups IN A ${net.cidr.host 20 prefixes.lo.v4}
|
||||
palace-kvm IN A ${net.cidr.host 21 prefixes.lo.v4}
|
||||
|
||||
reolink-living-room IN A ${net.cidr.host 45 prefixes.lo.v4}
|
||||
nixlight IN A ${net.cidr.host 46 prefixes.lo.v4}
|
||||
|
||||
${lib.my.dns.fwdRecords {
|
||||
inherit allAssignments names;
|
||||
domain = config.networking.domain;
|
||||
|
@@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import subprocess
|
||||
|
||||
import cloudflare
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Cloudflare DNS update script')
|
||||
parser.add_argument('-k', '--api-token-file', help='Cloudflare API token file')
|
||||
parser.add_argument('zone', help='Cloudflare Zone')
|
||||
parser.add_argument('record', help='Cloudflare record name')
|
||||
args = parser.parse_args()
|
||||
|
||||
address = subprocess.check_output(
|
||||
['drill', '-Q', '-p5353', '@127.0.0.1', args.record, 'A'],
|
||||
encoding='utf8').strip()
|
||||
|
||||
cf_token = None
|
||||
if args.api_token_file:
|
||||
with open(args.api_token_file) as f:
|
||||
cf_token = f.readline().strip()
|
||||
cf = cloudflare.Cloudflare(api_token=cf_token)
|
||||
|
||||
zones = list(cf.zones.list(name=args.zone))
|
||||
assert zones, f'Zone {args.zone} not found'
|
||||
assert len(zones) == 1, f'More than one zone found for {args.zone}'
|
||||
zone = zones[0]
|
||||
|
||||
records = list(cf.dns.records.list(zone_id=zone.id, name=args.record, type='A'))
|
||||
assert records, f'Record {args.record} not found in zone {args.zone}'
|
||||
assert len(records) == 1, f'More than one record found for {args.record}'
|
||||
record = records[0]
|
||||
|
||||
print(f'Updating {args.record} -> {address}')
|
||||
cf.dns.records.edit(
|
||||
zone_id=zone.id, dns_record_id=record.id,
|
||||
type='A', content=address)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@@ -1,7 +1,7 @@
|
||||
index: { lib, pkgs, config, assignments, allAssignments, ... }:
|
||||
index: { lib, pkgs, assignments, ... }:
|
||||
let
|
||||
inherit (lib) mkForce;
|
||||
inherit (lib.my) net netbootKeaClientClasses;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.home) domain prefixes vips hiMTU;
|
||||
|
||||
dns-servers = [
|
||||
@@ -26,11 +26,7 @@ in
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
kea-dhcp4-server.serviceConfig = {
|
||||
# Sometimes interfaces might not be ready in time and Kea doesn't like that
|
||||
Restart = "on-failure";
|
||||
DynamicUser = mkForce false;
|
||||
};
|
||||
kea-dhcp4-server.serviceConfig.DynamicUser = mkForce false;
|
||||
kea-dhcp-ddns-server.serviceConfig.DynamicUser = mkForce false;
|
||||
};
|
||||
|
||||
@@ -59,18 +55,10 @@ in
|
||||
}
|
||||
{
|
||||
name = "domain-search";
|
||||
data = "${domain}, dyn.${domain}, ${lib.my.c.colony.domain}, ${lib.my.c.britway.domain}";
|
||||
data = "${domain}, dyn.${domain}";
|
||||
always-send = true;
|
||||
}
|
||||
];
|
||||
client-classes = netbootKeaClientClasses {
|
||||
tftpIP = allAssignments.river.lo.ipv4.address;
|
||||
hostname = "boot.${domain}";
|
||||
systems = {
|
||||
sfh = "52:54:00:a5:7e:93";
|
||||
castle = "c8:7f:54:6e:17:0f";
|
||||
};
|
||||
};
|
||||
subnet4 = [
|
||||
{
|
||||
id = 1;
|
||||
@@ -132,37 +120,6 @@ in
|
||||
hw-address = "24:8a:07:a8:fe:3a";
|
||||
ip-address = net.cidr.host 40 prefixes.lo.v4;
|
||||
}
|
||||
|
||||
{
|
||||
# avr
|
||||
hw-address = "8c:a9:6f:30:03:6b";
|
||||
ip-address = net.cidr.host 41 prefixes.lo.v4;
|
||||
}
|
||||
{
|
||||
# tv
|
||||
hw-address = "00:a1:59:b8:4d:86";
|
||||
ip-address = net.cidr.host 42 prefixes.lo.v4;
|
||||
}
|
||||
{
|
||||
# android tv
|
||||
hw-address = "b8:7b:d4:95:c6:74";
|
||||
ip-address = net.cidr.host 43 prefixes.lo.v4;
|
||||
}
|
||||
{
|
||||
# hass-panel
|
||||
hw-address = "80:30:49:cd:d7:51";
|
||||
ip-address = net.cidr.host 44 prefixes.lo.v4;
|
||||
}
|
||||
{
|
||||
# reolink-living-room
|
||||
hw-address = "ec:71:db:30:69:a4";
|
||||
ip-address = net.cidr.host 45 prefixes.lo.v4;
|
||||
}
|
||||
{
|
||||
# nixlight
|
||||
hw-address = "00:4b:12:3b:d3:14";
|
||||
ip-address = net.cidr.host 46 prefixes.lo.v4;
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
|
@@ -1,83 +1,52 @@
|
||||
index: { lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (builtins) attrNames concatMap length;
|
||||
inherit (lib) optional concatMapStringsSep;
|
||||
inherit (builtins) attrNames concatMap;
|
||||
inherit (lib) optional;
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.home) prefixes vips;
|
||||
|
||||
pingScriptFor = name: ips:
|
||||
let
|
||||
script' = pkgs.writeShellScript
|
||||
"keepalived-ping-${name}"
|
||||
(concatMapStringsSep " || " (ip: "${pkgs.iputils}/bin/ping -qnc 1 -W 1 ${ip}") ips);
|
||||
in
|
||||
{
|
||||
script = toString script';
|
||||
interval = 1;
|
||||
timeout = (length ips) + 1;
|
||||
rise = 3;
|
||||
fall = 3;
|
||||
};
|
||||
|
||||
vlanIface = vlan: if vlan == "as211024" then vlan else "lan-${vlan}";
|
||||
vrrpIPs = family: concatMap (vlan: (optional (family == "v6") {
|
||||
addr = "fe80::1/64";
|
||||
dev = vlanIface vlan;
|
||||
}) ++ [
|
||||
vrrpIPs = family: concatMap (vlan: [
|
||||
{
|
||||
addr = "${vips.${vlan}.${family}}/${toString (net.cidr.length prefixes.${vlan}.${family})}";
|
||||
dev = vlanIface vlan;
|
||||
}
|
||||
]) (attrNames vips);
|
||||
] ++ (optional (family == "v6") {
|
||||
addr = "fe80::1/64";
|
||||
dev = vlanIface vlan;
|
||||
})) (attrNames vips);
|
||||
mkVRRP = family: routerId: {
|
||||
state = if index == 0 then "MASTER" else "BACKUP";
|
||||
interface = "lan-core";
|
||||
priority = 255 - index;
|
||||
virtualRouterId = routerId;
|
||||
virtualIps = vrrpIPs family;
|
||||
trackScripts = [ "${family}Alive" ];
|
||||
extraConfig = ''
|
||||
notify_master "${config.systemd.package}/bin/systemctl start radvd.service"
|
||||
notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
users = with lib.my.c.ids; {
|
||||
users.keepalived_script = {
|
||||
uid = uids.keepalived_script;
|
||||
isSystemUser = true;
|
||||
group = "keepalived_script";
|
||||
};
|
||||
groups.keepalived_script.gid = gids.keepalived_script;
|
||||
};
|
||||
|
||||
services = {
|
||||
keepalived = {
|
||||
enable = true;
|
||||
enableScriptSecurity = true;
|
||||
extraGlobalDefs = ''
|
||||
vrrp_version 3
|
||||
nftables keepalived
|
||||
'';
|
||||
vrrpScripts = {
|
||||
v4Alive = pingScriptFor "v4" [ "1.1.1.1" "8.8.8.8" "216.218.236.2" ];
|
||||
v6Alive = pingScriptFor "v6" [ "2606:4700:4700::1111" "2001:4860:4860::8888" "2600::" ];
|
||||
};
|
||||
vrrpInstances = {
|
||||
v4 = mkVRRP "v4" 51;
|
||||
v6 = (mkVRRP "v6" 52) // {
|
||||
v6 = mkVRRP "v6" 52;
|
||||
};
|
||||
extraConfig = ''
|
||||
notify_master "${config.systemd.package}/bin/systemctl start radvd.service" root
|
||||
notify_backup "${config.systemd.package}/bin/systemctl stop radvd.service" root
|
||||
vrrp_sync_group main {
|
||||
group {
|
||||
v4
|
||||
v6
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
# Actually disable this for now, don't want to fault IPv4 just because IPv6 is broken...
|
||||
# extraConfig = ''
|
||||
# vrrp_sync_group main {
|
||||
# group {
|
||||
# v4
|
||||
# v6
|
||||
# }
|
||||
# }
|
||||
# '';
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@@ -24,8 +24,8 @@ in
|
||||
onState = [ "routable" ];
|
||||
script = ''
|
||||
#!${pkgs.runtimeShell}
|
||||
if [ "$IFACE" = "lan" ]; then
|
||||
${mstpd}/sbin/mstpctl setforcevers "$IFACE" rstp
|
||||
if [ $IFACE = "lan" ]; then
|
||||
${mstpd}/sbin/mstpctl setforcevers $IFACE rstp
|
||||
fi
|
||||
'';
|
||||
};
|
||||
|
@@ -11,7 +11,7 @@ let
|
||||
AdvLinkMTU ${toString prefixes."${name}".mtu};
|
||||
prefix ${prefixes."${name}".v6} {};
|
||||
RDNSS ${net.cidr.host 1 prefixes."${name}".v6} ${net.cidr.host 2 prefixes."${name}".v6} {};
|
||||
DNSSL ${domain} dyn.${domain} ${lib.my.c.colony.domain} ${lib.my.c.britway.domain} {};
|
||||
DNSSL ${domain} dyn.${domain} {};
|
||||
};
|
||||
'';
|
||||
in
|
||||
|
@@ -43,38 +43,6 @@
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
mjpg-streamer = {
|
||||
enable = false;
|
||||
inputPlugin = "input_uvc.so";
|
||||
outputPlugin = "output_http.so -w @www@ -n -p 5050";
|
||||
};
|
||||
octoprint = {
|
||||
enable = false;
|
||||
host = "::";
|
||||
extraConfig = {
|
||||
plugins = {
|
||||
classicwebcam = {
|
||||
snapshot = "/webcam/?action=snapshot";
|
||||
stream = "/webcam/?action=stream";
|
||||
streamRatio = "4:3";
|
||||
};
|
||||
};
|
||||
serial = {
|
||||
port = "/dev/ttyACM0";
|
||||
baudrate = 115200;
|
||||
};
|
||||
temperature.profiles = [
|
||||
{
|
||||
bed = 60;
|
||||
extruder = 215;
|
||||
name = "PLA";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
netdevs = {
|
||||
"25-lan" = {
|
||||
@@ -155,7 +123,7 @@
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPYTB4zeAqotrEJ8M+AiGm/s9PFsWlAodz3hYSROGuDb";
|
||||
};
|
||||
server.enable = true;
|
||||
# deploy.node.hostname = "192.168.68.2";
|
||||
deploy.node.hostname = "192.168.68.2";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -26,7 +26,7 @@ in
|
||||
|
||||
config = {
|
||||
# Hardware acceleration for Jellyfin
|
||||
hardware.graphics = {
|
||||
hardware.opengl = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; [
|
||||
vaapiIntel
|
||||
@@ -65,27 +65,13 @@ in
|
||||
systemd = {
|
||||
services = {
|
||||
jackett.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
||||
|
||||
transmission.bindsTo = [ "systemd-networkd-wait-online@vpn.service" ];
|
||||
# https://github.com/NixOS/nixpkgs/issues/258793#issuecomment-1748168206
|
||||
transmission.serviceConfig = {
|
||||
RootDirectoryStartOnly = lib.mkForce false;
|
||||
RootDirectory = lib.mkForce "";
|
||||
};
|
||||
|
||||
radarr.serviceConfig.UMask = "0002";
|
||||
sonarr.serviceConfig.UMask = "0002";
|
||||
};
|
||||
};
|
||||
|
||||
nixpkgs.config.permittedInsecurePackages = [
|
||||
# FIXME: This is needed for Sonarr
|
||||
"aspnetcore-runtime-wrapped-6.0.36"
|
||||
"aspnetcore-runtime-6.0.36"
|
||||
"dotnet-sdk-wrapped-6.0.428"
|
||||
"dotnet-sdk-6.0.428"
|
||||
];
|
||||
|
||||
services = {
|
||||
transmission = {
|
||||
enable = true;
|
||||
|
@@ -2,7 +2,6 @@
|
||||
let
|
||||
inherit (lib) mkMerge mkIf;
|
||||
inherit (lib.my) networkdAssignment;
|
||||
inherit (lib.my.c.kelder) ipv4MTU;
|
||||
|
||||
wg = {
|
||||
keyFile = "kelder/acquisition/airvpn-privkey";
|
||||
@@ -73,12 +72,14 @@ in
|
||||
RouteTable = routeTable;
|
||||
};
|
||||
wireguardPeers = [
|
||||
# AirVPN IE
|
||||
{
|
||||
# AirVPN IE
|
||||
wireguardPeerConfig = {
|
||||
Endpoint = "146.70.94.2:1637";
|
||||
PublicKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=";
|
||||
PresharedKeyFile = config.age.secrets."${pskFile}".path;
|
||||
AllowedIPs = [ "0.0.0.0/0" "::/0" ];
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -88,14 +89,13 @@ in
|
||||
(networkdAssignment "host0" assignments.internal)
|
||||
{
|
||||
networkConfig.DNSDefaultRoute = false;
|
||||
linkConfig.MTUBytes = toString ipv4MTU;
|
||||
}
|
||||
];
|
||||
"90-vpn" = with wg; {
|
||||
matchConfig.Name = "vpn";
|
||||
address = [ "10.161.170.28/32" "fd7d:76ee:e68f:a993:b12d:6d15:c80a:9516/128" ];
|
||||
dns = [ "10.128.0.1" "fd7d:76ee:e68f:a993::1" ];
|
||||
routingPolicyRules = [
|
||||
routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
|
||||
{
|
||||
Family = "both";
|
||||
SuppressPrefixLength = 0;
|
||||
|
@@ -92,19 +92,17 @@ in
|
||||
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
# TODO: Might need to do some bullshit to go from Nextcloud 28 (?) to 30
|
||||
package = pkgs.nextcloud30;
|
||||
package = pkgs.nextcloud27;
|
||||
datadir = "/mnt/storage/nextcloud";
|
||||
hostName = "cloud.${domain}";
|
||||
https = true;
|
||||
config = {
|
||||
extraTrustedDomains = [ "cloud-local.${domain}" ];
|
||||
adminpassFile = config.age.secrets."kelder/nextcloud-root.txt".path;
|
||||
dbtype = "sqlite";
|
||||
defaultPhoneRegion = "IE";
|
||||
};
|
||||
settings = {
|
||||
extraOptions = {
|
||||
updatechecker = false;
|
||||
trusted_domains = [ "cloud-local.${domain}" ];
|
||||
default_phone_region = "IE";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -84,7 +84,6 @@ in
|
||||
c
|
||||
];
|
||||
acquisition = "http://${allAssignments.kelder-acquisition.internal.ipv4.address}";
|
||||
# This is kinda borked because Virgin Media filters DNS responses with local IPs...
|
||||
localRedirect = to: ''
|
||||
rewrite_by_lua_block {
|
||||
if ngx.var.remote_addr == pub_ip then
|
||||
@@ -104,7 +103,7 @@ in
|
||||
|
||||
"monitor.${domain}" = withAuth {
|
||||
serverAliases = [ "monitor-local.${domain}" ];
|
||||
# extraConfig = localRedirect "monitor-local.${domain}";
|
||||
extraConfig = localRedirect "monitor-local.${domain}";
|
||||
locations = {
|
||||
"/" = {
|
||||
proxyPass = "http://${allAssignments.kelder.ctrs.ipv4.address}:19999";
|
||||
@@ -137,17 +136,17 @@ in
|
||||
};
|
||||
"torrents.${domain}" = withAuth {
|
||||
serverAliases = [ "torrents-local.${domain}" ];
|
||||
# extraConfig = localRedirect "torrents-local.${domain}";
|
||||
extraConfig = localRedirect "torrents-local.${domain}";
|
||||
locations."/".proxyPass = "${acquisition}:9091";
|
||||
};
|
||||
"jackett.${domain}" = withAuth {
|
||||
serverAliases = [ "jackett-local.${domain}" ];
|
||||
# extraConfig = localRedirect "jackett-local.${domain}";
|
||||
extraConfig = localRedirect "jackett-local.${domain}";
|
||||
locations."/".proxyPass = "${acquisition}:9117";
|
||||
};
|
||||
"radarr.${domain}" = withAuth {
|
||||
serverAliases = [ "radarr-local.${domain}" ];
|
||||
# extraConfig = localRedirect "radarr-local.${domain}";
|
||||
extraConfig = localRedirect "radarr-local.${domain}";
|
||||
locations."/" = {
|
||||
proxyPass = "${acquisition}:7878";
|
||||
proxyWebsockets = true;
|
||||
@@ -156,7 +155,7 @@ in
|
||||
};
|
||||
"sonarr.${domain}" = withAuth {
|
||||
serverAliases = [ "sonarr-local.${domain}" ];
|
||||
# extraConfig = localRedirect "sonarr-local.${domain}";
|
||||
extraConfig = localRedirect "sonarr-local.${domain}";
|
||||
locations."/" = {
|
||||
proxyPass = "${acquisition}:8989";
|
||||
proxyWebsockets = true;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ lib, ... }:
|
||||
let
|
||||
inherit (lib.my) net;
|
||||
inherit (lib.my.c.kelder) domain prefixes ipv4MTU;
|
||||
inherit (lib.my.c.kelder) domain prefixes;
|
||||
in
|
||||
{
|
||||
imports = [ ./containers ];
|
||||
@@ -121,7 +121,8 @@ in
|
||||
|
||||
samba = {
|
||||
enable = true;
|
||||
settings = {
|
||||
enableNmbd = true;
|
||||
shares = {
|
||||
storage = {
|
||||
path = "/mnt/storage";
|
||||
browseable = "yes";
|
||||
@@ -130,20 +131,16 @@ in
|
||||
"directory mask" = "0775";
|
||||
};
|
||||
};
|
||||
|
||||
nmbd.enable = true;
|
||||
};
|
||||
samba-wsdd.enable = true;
|
||||
|
||||
minecraft-server = {
|
||||
enable = false;
|
||||
package = pkgs.minecraftServers.vanilla-1-20;
|
||||
enable = true;
|
||||
package = pkgs.minecraftServers.vanilla-1-19;
|
||||
declarative = true;
|
||||
eula = true;
|
||||
whitelist = {
|
||||
devplayer0 = "6d7d971b-ce10-435b-85c5-c99c0d8d288c";
|
||||
Elderlypug = "dcd2ecb9-2b5e-49cb-9d4f-f5a76162df56";
|
||||
shr3kas0ras = "1d366062-12c0-4e29-aba7-6ab5d8c6bb05";
|
||||
};
|
||||
serverProperties = {
|
||||
motd = "Simpcraft";
|
||||
@@ -181,10 +178,12 @@ in
|
||||
};
|
||||
wireguardPeers = [
|
||||
{
|
||||
wireguardPeerConfig = {
|
||||
PublicKey = "bP1XUNxp9i8NLOXhgPaIaRzRwi5APbam44/xjvYcyjU=";
|
||||
Endpoint = "${allAssignments.estuary.internal.ipv4.address}:${toString lib.my.c.kelder.vpn.port}";
|
||||
Endpoint = "estuary-vm.${lib.my.c.colony.domain}:${toString lib.my.c.kelder.vpn.port}";
|
||||
AllowedIPs = [ "0.0.0.0/0" ];
|
||||
PersistentKeepalive = 25;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
@@ -199,7 +198,6 @@ in
|
||||
"50-lan" = {
|
||||
matchConfig.Name = "et1g0";
|
||||
DHCP = "yes";
|
||||
linkConfig.MTUBytes = toString ipv4MTU;
|
||||
};
|
||||
"80-ctrs" = mkMerge [
|
||||
(networkdAssignment "ctrs" assignments.ctrs)
|
||||
@@ -212,7 +210,7 @@ in
|
||||
address = with assignments.estuary; [
|
||||
(with ipv4; "${address}/${toString mask}")
|
||||
];
|
||||
routingPolicyRules = [
|
||||
routingPolicyRules = map (r: { routingPolicyRuleConfig = r; }) [
|
||||
{
|
||||
Family = "both";
|
||||
SuppressPrefixLength = 0;
|
||||
@@ -272,7 +270,7 @@ in
|
||||
config.name = "kontent";
|
||||
};
|
||||
|
||||
# deploy.node.hostname = "192.168.0.69";
|
||||
#deploy.node.hostname = "10.16.9.21";
|
||||
secrets = {
|
||||
key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOFvUdJshXkqmchEgkZDn5rgtZ1NO9vbd6Px+S6YioWi";
|
||||
files = {
|
||||
|
@@ -14,7 +14,7 @@
|
||||
cpu = {
|
||||
intel.updateMicrocode = true;
|
||||
};
|
||||
graphics.extraPackages = with pkgs; [
|
||||
opengl.extraPackages = with pkgs; [
|
||||
intel-media-driver
|
||||
];
|
||||
bluetooth.enable = true;
|
||||
@@ -116,10 +116,6 @@
|
||||
|
||||
programs = {
|
||||
steam.enable = true;
|
||||
wireshark = {
|
||||
enable = true;
|
||||
package = pkgs.wireshark-qt;
|
||||
};
|
||||
};
|
||||
|
||||
networking = {
|
||||
@@ -129,9 +125,10 @@
|
||||
wifi = {
|
||||
backend = "wpa_supplicant";
|
||||
};
|
||||
settings = {
|
||||
main.no-auto-default = "*";
|
||||
};
|
||||
extraConfig = ''
|
||||
[main]
|
||||
no-auto-default=*
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -174,14 +171,6 @@
|
||||
packages = with pkgs; [ ];
|
||||
};
|
||||
|
||||
programs = {
|
||||
fish = {
|
||||
shellAbbrs = {
|
||||
tsup = "doas tailscale up --login-server=https://hs.nul.ie --accept-routes";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
blueman-applet.enable = true;
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ self, lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
|
||||
{ lib, pkgsFlakes, hmFlakes, inputs, pkgs', config, ... }:
|
||||
let
|
||||
inherit (builtins) attrValues mapAttrs;
|
||||
inherit (lib)
|
||||
@@ -23,19 +23,15 @@ let
|
||||
pkgs = pkgs'.${config'.nixpkgs}.${config'.system};
|
||||
allPkgs = mapAttrs (_: p: p.${config'.system}) pkgs';
|
||||
|
||||
modules' = [ hmFlakes.${config'.home-manager}.nixosModules.default ] ++ (attrValues cfg.modules);
|
||||
modules' = [ hmFlakes.${config'.home-manager}.nixosModule ] ++ (attrValues cfg.modules);
|
||||
in
|
||||
# Import eval-config ourselves since the flake now force-sets lib
|
||||
import "${pkgsFlake}/nixos/lib/eval-config.nix" {
|
||||
pkgsFlake.lib.nixosSystem {
|
||||
# Gotta override lib here unforunately, eval-config.nix likes to import its own (unextended) lib. We explicitly
|
||||
# don't pass pkgs so that it'll be imported with modularly applied config and overlays.
|
||||
lib = pkgs.lib.extend (lib.my.versionOverlay { inherit self pkgsFlake; });
|
||||
|
||||
# Set to null since we pass modularly
|
||||
system = null;
|
||||
lib = pkgs.lib;
|
||||
|
||||
# Put the inputs in specialArgs to avoid infinite recursion when modules try to do imports
|
||||
specialArgs = { inherit self inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
|
||||
specialArgs = { inherit inputs pkgsFlakes pkgsFlake allAssignments; inherit (cfg) systems; };
|
||||
|
||||
# `baseModules` informs the manual which modules to document
|
||||
baseModules =
|
||||
@@ -55,7 +51,7 @@ let
|
||||
pkgs' = allPkgs;
|
||||
};
|
||||
|
||||
system = { inherit name; };
|
||||
system.name = name;
|
||||
networking = {
|
||||
domain = let d = config'.assignments.internal.domain or null; in mkIf (d != null) (mkDefault' d);
|
||||
hostName = mkDefault (config'.assignments.internal.name or name);
|
||||
@@ -90,8 +86,6 @@ let
|
||||
pkgsPath = toString pkgsFlakes.${config'.hmNixpkgs};
|
||||
pkgs' = allPkgs;
|
||||
};
|
||||
|
||||
home.enableNixpkgsReleaseCheck = false;
|
||||
}
|
||||
(homeStateVersion config'.home-manager)
|
||||
];
|
||||
@@ -135,7 +129,6 @@ let
|
||||
ipv6 = mkBoolOpt' false "Whether this mesh's underlay operates over IPv6.";
|
||||
baseMTU = mkOpt' ints.unsigned 1500 "Base MTU to calculate VXLAN MTU with.";
|
||||
l3Overhead = mkOpt' ints.unsigned 40 "Overhead of L3 header (to calculate MTU).";
|
||||
udpEncapsulation = mkBoolOpt' false "Whether to encapsulate ESP frames in UDP.";
|
||||
firewall = mkBoolOpt' true "Whether to generate firewall rules.";
|
||||
vni = mkOpt' ints.unsigned 1 "VXLAN VNI.";
|
||||
peers = mkOpt' (attrsOf (submodule l2PeerOpts)) { } "Peers.";
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
nixos.systems.installer = { config, ... }: {
|
||||
system = "x86_64-linux";
|
||||
nixpkgs = "mine";
|
||||
nixpkgs = "unstable";
|
||||
docCustom = false;
|
||||
rendered = config.configuration.config.my.asISO;
|
||||
|
||||
@@ -31,11 +31,8 @@
|
||||
server.enable = true;
|
||||
};
|
||||
|
||||
image = {
|
||||
baseName = "jackos-installer";
|
||||
};
|
||||
isoImage = {
|
||||
volumeID = "jackos-${config.system.nixos.release}-${pkgs.stdenv.hostPlatform.uname.processor}";
|
||||
isoBaseName = "nixos-installer-devplayer0";
|
||||
edition = "devplayer0";
|
||||
appendToMenuLabel = " /dev/player0 Installer";
|
||||
};
|
||||
@@ -54,8 +51,6 @@
|
||||
home.shellAliases = {
|
||||
show-hw-config = "nixos-generate-config --show-hardware-config --root $INSTALL_ROOT";
|
||||
};
|
||||
|
||||
my.gui.enable = false;
|
||||
};
|
||||
|
||||
services = {
|
||||
@@ -63,8 +58,8 @@
|
||||
};
|
||||
|
||||
networking = {
|
||||
# Will be set dynamically, but need something to satisfy `/etc/os-release` stuff
|
||||
hostName = "installer";
|
||||
# Will be set dynamically
|
||||
hostName = "";
|
||||
useNetworkd = false;
|
||||
};
|
||||
|
||||
@@ -84,8 +79,6 @@
|
||||
${pkgs.gawk}/bin/awk '{ print $1 }')"
|
||||
'';
|
||||
|
||||
boot.supportedFilesystems.nfs = true;
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
dhcpcd
|
||||
lm_sensors
|
||||
|
@@ -14,12 +14,10 @@
|
||||
network = ./network.nix;
|
||||
pdns = ./pdns.nix;
|
||||
nginx-sso = ./nginx-sso.nix;
|
||||
gui = ./gui;
|
||||
gui = ./gui.nix;
|
||||
l2mesh = ./l2mesh.nix;
|
||||
borgthin = ./borgthin.nix;
|
||||
nvme = ./nvme;
|
||||
spdk = ./spdk.nix;
|
||||
librespeed = ./librespeed;
|
||||
netboot = ./netboot;
|
||||
};
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
{ inputs, lib, pkgs, config, ... }:
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (builtins) substring match;
|
||||
inherit (lib)
|
||||
@@ -127,9 +127,7 @@ in
|
||||
enable = mkBoolOpt' false "Whether to enable borgthin jobs";
|
||||
lvmPackage = mkOpt' package pkgs.lvm2 "Packge containing LVM tools";
|
||||
thinToolsPackage = mkOpt' package pkgs.thin-provisioning-tools "Package containing thin-provisioning-tools";
|
||||
# Really we should use the version from the overlay, but the package is quite far behind...
|
||||
# Not bothering to update until Borg 2.0 releases
|
||||
package = mkOpt' package inputs.borgthin.packages.${config.nixpkgs.system}.borgthin "borgthin package";
|
||||
package = mkOpt' package pkgs.borgthin "borgthin package";
|
||||
jobs = mkOpt' (attrsOf jobType) { } "borgthin jobs";
|
||||
};
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{ lib, pkgs, extendModules, modulesPath, options, config, ... }:
|
||||
let
|
||||
inherit (lib) recursiveUpdate mkOption mkDefault mkIf mkMerge mkForce flatten optional;
|
||||
inherit (lib) recursiveUpdate mkOption mkDefault mkIf mkMerge flatten optional;
|
||||
inherit (lib.my) mkBoolOpt' dummyOption;
|
||||
|
||||
cfg = config.my.build;
|
||||
@@ -43,145 +43,15 @@ let
|
||||
modules = flatten [
|
||||
"${modulesPath}/installer/netboot/netboot.nix"
|
||||
allHardware
|
||||
];
|
||||
};
|
||||
|
||||
asNetboot = extendModules {
|
||||
modules = flatten [
|
||||
allHardware
|
||||
({ pkgs, config, ... }: {
|
||||
boot = {
|
||||
loader.grub.enable = false;
|
||||
initrd = {
|
||||
kernelModules = [ "nbd" ];
|
||||
availableKernelModules = [ "igb" "igc" ];
|
||||
|
||||
systemd = {
|
||||
storePaths = with pkgs; [
|
||||
gnused
|
||||
nbd
|
||||
netcat
|
||||
];
|
||||
extraBin = with pkgs; {
|
||||
dmesg = "${util-linux}/bin/dmesg";
|
||||
ip = "${iproute2}/bin/ip";
|
||||
nbd-client = "${nbd}/bin/nbd-client";
|
||||
};
|
||||
extraConfig = ''
|
||||
DefaultTimeoutStartSec=20
|
||||
DefaultDeviceTimeoutSec=20
|
||||
system.build.netbootArchive = pkgs.runCommand "netboot-${config.system.name}-archive.tar" { } ''
|
||||
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.kernel}" \
|
||||
-f "$out" "${config.system.boot.loader.kernelFile}"
|
||||
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootRamdisk}" \
|
||||
-f "$out" initrd
|
||||
${pkgs.gnutar}/bin/tar -rvC "${config.system.build.netbootIpxeScript}" \
|
||||
-f "$out" netboot.ipxe
|
||||
'';
|
||||
|
||||
network = {
|
||||
enable = true;
|
||||
wait-online.enable = true;
|
||||
|
||||
networks."10-netboot" = {
|
||||
matchConfig.Name = "et-boot";
|
||||
DHCP = "yes";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
nbd = {
|
||||
description = "NBD Root FS";
|
||||
|
||||
script = ''
|
||||
get_cmdline() {
|
||||
${pkgs.gnused}/bin/sed -rn "s/^.*$1=(\\S+).*\$/\\1/p" < /proc/cmdline
|
||||
}
|
||||
|
||||
s="$(get_cmdline nbd_server)"
|
||||
until ${pkgs.netcat}/bin/nc -zv "$s" 22; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
exec ${pkgs.nbd}/bin/nbd-client -systemd-mark -N "$(get_cmdline nbd_export)" "$s" /dev/nbd0
|
||||
'';
|
||||
unitConfig = {
|
||||
IgnoreOnIsolate = "yes";
|
||||
DefaultDependencies = "no";
|
||||
};
|
||||
serviceConfig = {
|
||||
Type = "forking";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
};
|
||||
|
||||
wantedBy = [ "initrd-root-device.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
postBootCommands = ''
|
||||
# After booting, register the contents of the Nix store
|
||||
# in the Nix database in the COW root.
|
||||
${config.nix.package}/bin/nix-store --load-db < /nix-path-registration
|
||||
|
||||
# nixos-rebuild also requires a "system" profile and an
|
||||
# /etc/NIXOS tag.
|
||||
touch /etc/NIXOS
|
||||
${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system
|
||||
'';
|
||||
};
|
||||
|
||||
programs.nbd.enable = true;
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
fsType = "ext4";
|
||||
device = "/dev/nbd0";
|
||||
noCheck = true;
|
||||
autoResize = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking.useNetworkd = mkForce true;
|
||||
|
||||
systemd = {
|
||||
network.networks."10-boot" = {
|
||||
matchConfig.Name = "et-boot";
|
||||
DHCP = "yes";
|
||||
networkConfig.KeepConfiguration = "yes";
|
||||
};
|
||||
};
|
||||
|
||||
system.build = {
|
||||
rootImage = pkgs.callPackage "${modulesPath}/../lib/make-ext4-fs.nix" {
|
||||
storePaths = [ config.system.build.toplevel ];
|
||||
volumeLabel = "netboot-root";
|
||||
};
|
||||
netbootScript = pkgs.writeText "boot.ipxe" ''
|
||||
#!ipxe
|
||||
kernel ${pkgs.stdenv.hostPlatform.linux-kernel.target} init=${config.system.build.toplevel}/init initrd=initrd ifname=et-boot:''${mac} nbd_server=''${next-server} ${toString config.boot.kernelParams} ''${cmdline}
|
||||
initrd initrd
|
||||
boot
|
||||
'';
|
||||
|
||||
netbootTree = pkgs.linkFarm "netboot-${config.system.name}" [
|
||||
{
|
||||
name = config.system.boot.loader.kernelFile;
|
||||
path = "${config.system.build.kernel}/${config.system.boot.loader.kernelFile}";
|
||||
}
|
||||
{
|
||||
name = "initrd";
|
||||
path = "${config.system.build.initialRamdisk}/initrd";
|
||||
}
|
||||
{
|
||||
name = "rootfs.ext4";
|
||||
path = config.system.build.rootImage;
|
||||
}
|
||||
{
|
||||
name = "boot.ipxe";
|
||||
path = config.system.build.netbootScript;
|
||||
}
|
||||
];
|
||||
netbootArchive = pkgs.runCommand "netboot-${config.system.name}.tar.zst" { } ''
|
||||
export PATH=${pkgs.zstd}/bin:$PATH
|
||||
${pkgs.gnutar}/bin/tar --dereference --zstd -cvC ${config.system.build.netbootTree} -f "$out" .
|
||||
'';
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
@@ -207,7 +77,6 @@ in
|
||||
asISO = mkAsOpt asISO "a bootable .iso image";
|
||||
asContainer = mkAsOpt asContainer "a container";
|
||||
asKexecTree = mkAsOpt asKexecTree "a kexec-able kernel and initrd";
|
||||
asNetboot = mkAsOpt asNetboot "a netboot-able kernel initrd, and iPXE script";
|
||||
|
||||
buildAs = options.system.build;
|
||||
};
|
||||
@@ -221,9 +90,8 @@ in
|
||||
memorySize = dummyOption;
|
||||
qemu.options = dummyOption;
|
||||
};
|
||||
image.baseName = dummyOption;
|
||||
isoImage = {
|
||||
volumeID = dummyOption;
|
||||
isoBaseName = dummyOption;
|
||||
edition = dummyOption;
|
||||
appendToMenuLabel = dummyOption;
|
||||
};
|
||||
@@ -241,8 +109,7 @@ in
|
||||
iso = config.my.asISO.config.system.build.isoImage;
|
||||
container = config.my.asContainer.config.system.build.toplevel;
|
||||
kexecTree = config.my.asKexecTree.config.system.build.kexecTree;
|
||||
netbootTree = config.my.asNetboot.config.system.build.netbootTree;
|
||||
netbootArchive = config.my.asNetboot.config.system.build.netbootArchive;
|
||||
netbootArchive = config.my.asKexecTree.config.system.build.netbootArchive;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{ lib, pkgsFlake, pkgs, pkgs', self, inputs, config, ... }:
|
||||
{ lib, pkgs, pkgs', inputs, config, ... }:
|
||||
let
|
||||
inherit (lib) mkIf mkDefault mkMerge;
|
||||
inherit (lib.my) mkDefault';
|
||||
inherit (lib.my) mkBoolOpt' dummyOption;
|
||||
in
|
||||
{
|
||||
options = with lib.types; {
|
||||
@@ -12,7 +12,7 @@ in
|
||||
inputs.impermanence.nixosModule
|
||||
inputs.ragenix.nixosModules.age
|
||||
inputs.sharry.nixosModules.default
|
||||
inputs.copyparty.nixosModules.default
|
||||
inputs.attic.nixosModules.atticd
|
||||
];
|
||||
|
||||
config = mkMerge [
|
||||
@@ -41,7 +41,6 @@ in
|
||||
|
||||
nix = {
|
||||
package = pkgs'.mine.nix;
|
||||
channel.enable = false;
|
||||
settings = with lib.my.c.nix; {
|
||||
trusted-users = [ "@wheel" ];
|
||||
experimental-features = [ "nix-command" "flakes" "ca-derivations" ];
|
||||
@@ -54,7 +53,7 @@ in
|
||||
pkgs = {
|
||||
to = {
|
||||
type = "path";
|
||||
path = "${pkgsFlake}";
|
||||
path = "${pkgs.path}";
|
||||
};
|
||||
exact = true;
|
||||
};
|
||||
@@ -66,12 +65,10 @@ in
|
||||
};
|
||||
nixpkgs = {
|
||||
overlays = [
|
||||
inputs.deploy-rs.overlays.default
|
||||
inputs.deploy-rs.overlay
|
||||
inputs.sharry.overlays.default
|
||||
# TODO: Re-enable when borgthin is updated
|
||||
# inputs.borgthin.overlays.default
|
||||
inputs.borgthin.overlays.default
|
||||
inputs.boardie.overlays.default
|
||||
inputs.copyparty.overlays.default
|
||||
];
|
||||
config = {
|
||||
allowUnfree = true;
|
||||
@@ -124,15 +121,7 @@ in
|
||||
services.lvm.enable = mkDefault true;
|
||||
};
|
||||
};
|
||||
system = {
|
||||
nixos = {
|
||||
distroName = mkDefault' "JackOS";
|
||||
};
|
||||
};
|
||||
|
||||
environment.etc = {
|
||||
"nixos/flake.nix".source = "/run/nixfiles/flake.nix";
|
||||
};
|
||||
environment.systemPackages = with pkgs; mkMerge [
|
||||
[
|
||||
bash-completion
|
||||
@@ -148,10 +137,7 @@ in
|
||||
fish.enable = mkDefault true;
|
||||
# TODO: This is expecting to look up the channel for the database...
|
||||
command-not-found.enable = mkDefault false;
|
||||
vim = {
|
||||
enable = true;
|
||||
defaultEditor = true;
|
||||
};
|
||||
vim.defaultEditor = true;
|
||||
};
|
||||
|
||||
services = {
|
||||
@@ -165,7 +151,6 @@ in
|
||||
font-name=SauceCodePro Nerd Font Mono
|
||||
'';
|
||||
};
|
||||
getty.greetingLine = mkDefault' ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>'';
|
||||
|
||||
openssh = {
|
||||
enable = mkDefault true;
|
||||
@@ -218,35 +203,14 @@ in
|
||||
# python.d plugin script does #!/usr/bin/env bash
|
||||
path = with pkgs; [ bash ];
|
||||
};
|
||||
|
||||
nixfiles-mutable = {
|
||||
description = "Mutable nixfiles";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
|
||||
path = with pkgs; [ util-linux ];
|
||||
script = ''
|
||||
nixfilesDir="${self}"
|
||||
|
||||
mkdir -p /run/nixfiles{,/.rw,/.work}
|
||||
mount -t overlay overlay -o lowerdir="$nixfilesDir",upperdir=/run/nixfiles/.rw,workdir=/run/nixfiles/.work /run/nixfiles
|
||||
chmod -R u+w /run/nixfiles
|
||||
'';
|
||||
preStop = ''
|
||||
umount /run/nixfiles
|
||||
rm -rf /run/nixfiles
|
||||
'';
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
(mkIf config.services.kmscon.enable {
|
||||
fonts.fonts = with pkgs; [
|
||||
nerd-fonts.sauce-code-pro
|
||||
(nerdfonts.override {
|
||||
fonts = [ "SourceCodePro" ];
|
||||
})
|
||||
];
|
||||
})
|
||||
];
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{ lib, pkgs, options, config, systems, ... }:
|
||||
let
|
||||
inherit (builtins) attrNames attrValues all hashString toJSON any;
|
||||
inherit (builtins) attrNames attrValues all hashString toJSON;
|
||||
inherit (lib)
|
||||
groupBy' mapAttrsToList optionalString optional concatMapStringsSep filterAttrs mkOption mkDefault mkIf mkMerge;
|
||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||
@@ -15,7 +15,6 @@ let
|
||||
passAsFile = [ "code" ];
|
||||
code = ''
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <systemd/sd-daemon.h>
|
||||
@@ -99,7 +98,6 @@ let
|
||||
};
|
||||
networking = {
|
||||
bridge = mkOpt' (nullOr str) null "Network bridge to connect to.";
|
||||
macVLAN = mkOpt' (nullOr str) null "Network interface to make MACVLAN interface from.";
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -117,19 +115,26 @@ in
|
||||
assertion = config.systemd.network.enable;
|
||||
message = "Containers currently require systemd-networkd!";
|
||||
}
|
||||
{
|
||||
assertion = all (i: i.networking.bridge == null || i.networking.macVLAN == null) (attrValues cfg.instances);
|
||||
message = "Only bridge OR MACVLAN can be set";
|
||||
}
|
||||
];
|
||||
|
||||
# TODO: Better security
|
||||
my.firewall.trustedInterfaces =
|
||||
mapAttrsToList
|
||||
(n: _: "ve-${n}")
|
||||
(filterAttrs (_: c: c.networking.bridge == null && c.networking.macVLAN == null) cfg.instances);
|
||||
(filterAttrs (_: c: c.networking.bridge == null) cfg.instances);
|
||||
|
||||
systemd = mkMerge (mapAttrsToList (n: c: {
|
||||
systemd = mkMerge ([
|
||||
{
|
||||
# By symlinking to the original systemd-nspawn@.service for every instance we force the unit generator to
|
||||
# create overrides instead of replacing the unit entirely
|
||||
packages = [
|
||||
(pkgs.linkFarm "systemd-nspawn-containers" (map (n: {
|
||||
name = "etc/systemd/system/systemd-nspawn@${n}.service";
|
||||
path = "${pkgs.systemd}/example/systemd/system/systemd-nspawn@.service";
|
||||
}) (attrNames cfg.instances)))
|
||||
];
|
||||
}
|
||||
] ++ (mapAttrsToList (n: c: {
|
||||
nspawn."${n}" = {
|
||||
execConfig = {
|
||||
Boot = true;
|
||||
@@ -160,8 +165,6 @@ in
|
||||
};
|
||||
networkConfig = if (c.networking.bridge != null) then {
|
||||
Bridge = c.networking.bridge;
|
||||
} else if (c.networking.macVLAN != null) then {
|
||||
MACVLAN = "${c.networking.macVLAN}:host0";
|
||||
} else {
|
||||
VirtualEthernet = true;
|
||||
};
|
||||
@@ -179,9 +182,6 @@ in
|
||||
c.containerSystem;
|
||||
in
|
||||
{
|
||||
# To prevent creating a whole new unit file
|
||||
overrideStrategy = "asDropin";
|
||||
|
||||
environment = {
|
||||
# systemd.nspawn units can't set the root directory directly, but /run/machines/${n} is one of the search paths
|
||||
root = "/run/machines/${n}";
|
||||
@@ -247,7 +247,7 @@ in
|
||||
Bridge = c.networking.bridge;
|
||||
};
|
||||
};
|
||||
}) cfg.instances);
|
||||
}) cfg.instances));
|
||||
})
|
||||
|
||||
# Inside container
|
||||
|
@@ -15,20 +15,16 @@ let
|
||||
# Based on https://github.com/serokell/deploy-rs/blob/master/flake.nix
|
||||
nixosActivate = cfg': base: (pkgs.deploy-rs.lib.activate.custom // {
|
||||
dryActivate = "$PROFILE/bin/switch-to-configuration dry-activate";
|
||||
boot = ''
|
||||
$PROFILE/bin/switch-to-configuration boot
|
||||
|
||||
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
|
||||
'';
|
||||
boot = "$PROFILE/bin/switch-to-configuration boot";
|
||||
}) base.config.system.build.toplevel ''
|
||||
# work around https://github.com/NixOS/nixpkgs/issues/73404
|
||||
cd /tmp
|
||||
|
||||
"$PROFILE"/bin/switch-to-configuration switch
|
||||
"$PROFILE"/bin/switch-to-configuration ${cfg'.mode}
|
||||
|
||||
# https://github.com/serokell/deploy-rs/issues/31
|
||||
${with base.config.boot.loader;
|
||||
optionalString systemd-boot.enable
|
||||
optionalString ((cfg'.mode == "switch" || cfg'.mode == "boot") && systemd-boot.enable)
|
||||
"sed -i '/^default /d' ${efi.efiSysMountPoint}/loader/loader.conf"}
|
||||
|
||||
${keepGensSnippet "$PROFILE" cfg'.keepGenerations}
|
||||
@@ -63,11 +59,7 @@ let
|
||||
{
|
||||
name = "container-${n}";
|
||||
value = {
|
||||
path = (pkgs.deploy-rs.lib.activate.custom // {
|
||||
boot = ''
|
||||
echo "Next systemd-nspawn@${n}.service restart / reload will load config"
|
||||
'';
|
||||
}) ctrConfig.my.buildAs.container ''
|
||||
path = pkgs.deploy-rs.lib.activate.custom ctrConfig.my.buildAs.container ''
|
||||
source ${systemdUtil}/bin/systemd-util.sh
|
||||
${if c.hotReload then ''
|
||||
if (! systemctl show -p ActiveState systemd-nspawn@${n} | grep -q "ActiveState=active") || \
|
||||
|
@@ -222,7 +222,7 @@ in
|
||||
"iifname ${cfg.nat.externalInterface} jump filter-iif-port-forwards"}
|
||||
${optionalString
|
||||
dipForward
|
||||
(concatMapStringsSep "\n " (ip: "jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
|
||||
(concatMapStringsSep "\n " (ip: "${ipK ip} daddr ${ip} jump ${natFilterChain ip}") (attrNames cfg.nat.forwardPorts))}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,12 +4,6 @@ let
|
||||
inherit (lib.my) mkBoolOpt';
|
||||
|
||||
cfg = config.my.gui;
|
||||
|
||||
androidUdevRules = pkgs.runCommand "udev-rules-android" {
|
||||
rulesFile = ./android-udev.rules;
|
||||
} ''
|
||||
install -D "$rulesFile" "$out"/lib/udev/rules.d/51-android.rules
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.my.gui = with lib.types; {
|
||||
@@ -18,7 +12,7 @@ in
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
hardware = {
|
||||
graphics.enable = mkDefault true;
|
||||
opengl.enable = mkDefault true;
|
||||
};
|
||||
|
||||
systemd = {
|
||||
@@ -29,19 +23,13 @@ in
|
||||
|
||||
security = {
|
||||
polkit.enable = true;
|
||||
pam.services.swaylock-plugin = {};
|
||||
};
|
||||
|
||||
users = {
|
||||
groups = {
|
||||
adbusers.gid = lib.my.c.ids.gids.adbusers;
|
||||
};
|
||||
pam.services.swaylock = {};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
# for pw-jack
|
||||
pipewire.jack
|
||||
swaylock-plugin
|
||||
swaylock
|
||||
];
|
||||
services = {
|
||||
pipewire = {
|
||||
@@ -56,21 +44,13 @@ in
|
||||
gnome = {
|
||||
gnome-keyring.enable = true;
|
||||
};
|
||||
udisks2.enable = true;
|
||||
|
||||
udev = {
|
||||
packages = [
|
||||
androidUdevRules
|
||||
];
|
||||
extraRules = ''
|
||||
# Nvidia
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0955", MODE="0664", GROUP="wheel"
|
||||
# Nintendo
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="057e", MODE="0664", GROUP="wheel"
|
||||
# FT
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", MODE="0664", GROUP="wheel"
|
||||
# /dev/player0
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="6969", MODE="0664", GROUP="wheel"
|
||||
'';
|
||||
};
|
||||
};
|
||||
@@ -104,13 +84,5 @@ in
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
user = {
|
||||
config = {
|
||||
extraGroups = [ "adbusers" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -36,16 +36,18 @@ let
|
||||
espOverhead =
|
||||
if (!mesh.security.enable) then 0
|
||||
else
|
||||
# UDP encap + SPI + seq + IV + pad / header + ICV
|
||||
(if mesh.udpEncapsulation then 8 else 0) + 4 + 4 + (if mesh.security.encrypt then 8 else 0) + 2 + 16;
|
||||
# SPI + seq + IV + pad / header + ICV
|
||||
4 + 4 + (if mesh.security.encrypt then 8 else 0) + 2 + 16;
|
||||
# UDP + VXLAN + Ethernet + L3 (IPv4/IPv6)
|
||||
overhead = espOverhead + 8 + 8 + 14 + mesh.l3Overhead;
|
||||
in
|
||||
toString (mesh.baseMTU - overhead);
|
||||
|
||||
bridgeFDBs = mapAttrsToList (n: peer: {
|
||||
bridgeFDBConfig = {
|
||||
MACAddress = "00:00:00:00:00:00";
|
||||
Destination = peer.addr;
|
||||
};
|
||||
}) otherPeers;
|
||||
};
|
||||
};
|
||||
@@ -60,12 +62,8 @@ let
|
||||
chain l2mesh-${name} {
|
||||
${optionalString mesh.security.enable ''
|
||||
udp dport isakmp accept
|
||||
${if mesh.udpEncapsulation then ''
|
||||
udp dport ipsec-nat-t accept
|
||||
'' else ''
|
||||
meta l4proto esp accept
|
||||
''}
|
||||
''}
|
||||
${optionalString (!mesh.security.enable) (vxlanAllow mesh.vni)}
|
||||
return
|
||||
}
|
||||
@@ -96,7 +94,6 @@ let
|
||||
esp=${if mesh.security.encrypt then "aes_gcm256" else "null-sha256"}
|
||||
ikev2=yes
|
||||
modecfgpull=no
|
||||
encapsulation=${if mesh.udpEncapsulation then "yes" else "no"}
|
||||
'';
|
||||
})
|
||||
otherPeers);
|
||||
|
@@ -1,76 +0,0 @@
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (builtins) toJSON;
|
||||
inherit (lib) mkOption mkMerge mkIf mkDefault;
|
||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||
|
||||
cfg = config.my.librespeed;
|
||||
|
||||
serversConf = map (s: s // {
|
||||
dlURL = "backend/garbage";
|
||||
ulURL = "backend/empty";
|
||||
pingURL = "backend/empty";
|
||||
getIpURL = "backend/getIP";
|
||||
}) cfg.frontend.servers;
|
||||
frontendTree = pkgs.runCommand "librespeed-frontend" {
|
||||
speedtestServers = toJSON serversConf;
|
||||
} ''
|
||||
mkdir "$out"
|
||||
cp "${pkgs.librespeed-go}"/assets/* "$out"/
|
||||
substitute ${./index.html} "$out"/index.html --subst-var speedtestServers
|
||||
'';
|
||||
|
||||
backendConf = pkgs.writers.writeTOML "librespeed.toml" cfg.backend.settings;
|
||||
generateBackendSettings = base: dst: if (cfg.backend.extraSettingsFile != null) then ''
|
||||
oldUmask="$(umask)"
|
||||
umask 006
|
||||
cat "${base}" "${cfg.backend.extraSettingsFile}" > "${dst}"
|
||||
umask "$oldUmask"
|
||||
'' else ''
|
||||
cp "${base}" "${dst}"
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.my.librespeed = with lib.types; {
|
||||
frontend = {
|
||||
servers = mkOpt' (listOf (attrsOf unspecified)) { } "Server configs.";
|
||||
webroot = mkOption {
|
||||
description = "Frontend webroot.";
|
||||
type = package;
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
backend = {
|
||||
enable = mkBoolOpt' false "Whether to enable librespeed backend.";
|
||||
settings = mkOpt' (attrsOf unspecified) { } "Backend settings.";
|
||||
extraSettingsFile = mkOpt' (nullOr str) null "Extra settings file.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf (cfg.frontend.servers != { }) {
|
||||
my.librespeed.frontend.webroot = frontendTree;
|
||||
})
|
||||
(mkIf cfg.backend.enable {
|
||||
my.librespeed.backend.settings = {
|
||||
assets_path = frontendTree;
|
||||
database_type = mkDefault "bolt";
|
||||
database_file = mkDefault "/var/lib/librespeed-go/speedtest.db";
|
||||
};
|
||||
|
||||
systemd.services.librespeed = {
|
||||
description = "LibreSpeed Go backend";
|
||||
wants = [ "network-online.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
|
||||
preStart = generateBackendSettings backendConf "/run/librespeed-go/settings.toml";
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.librespeed-go}/bin/speedtest -c /run/librespeed-go/settings.toml";
|
||||
RuntimeDirectory = "librespeed-go";
|
||||
StateDirectory = "librespeed-go";
|
||||
};
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
@@ -1,491 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no" />
|
||||
<meta charset="UTF-8" />
|
||||
<script type="text/javascript" src="speedtest.js"></script>
|
||||
<script type="text/javascript">
|
||||
function I(i){return document.getElementById(i);}
|
||||
|
||||
//LIST OF TEST SERVERS. See documentation for details if needed
|
||||
var SPEEDTEST_SERVERS=@speedtestServers@;
|
||||
// var SPEEDTEST_SERVERS=[
|
||||
// { //this server doesn't actually exist, remove it
|
||||
// name:"Example Server 1", //user friendly name for the server
|
||||
// server:"//test1.mydomain.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
// dlURL:"backend/garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
// ulURL:"backend/empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
// pingURL:"backend/empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
// getIpURL:"backend/getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
// },
|
||||
// { //this server doesn't actually exist, remove it
|
||||
// name:"Example Server 2", //user friendly name for the server
|
||||
// server:"//test2.example.com/", //URL to the server. // at the beginning will be replaced with http:// or https:// automatically
|
||||
// dlURL:"garbage.php", //path to download test on this server (garbage.php or replacement)
|
||||
// ulURL:"empty.php", //path to upload test on this server (empty.php or replacement)
|
||||
// pingURL:"empty.php", //path to ping/jitter test on this server (empty.php or replacement)
|
||||
// getIpURL:"getIP.php" //path to getIP on this server (getIP.php or replacement)
|
||||
// }
|
||||
// //add other servers here, comma separated
|
||||
// ];
|
||||
|
||||
//INITIALIZE SPEEDTEST
|
||||
var s=new Speedtest(); //create speed test object
|
||||
s.setParameter("telemetry_level","basic"); //enable telemetry
|
||||
|
||||
//SERVER AUTO SELECTION
|
||||
function initServers(){
|
||||
var noServersAvailable=function(){
|
||||
I("message").innerHTML="No servers available";
|
||||
}
|
||||
var runServerSelect=function(){
|
||||
s.selectServer(function(server){
|
||||
if(server!=null){ //at least 1 server is available
|
||||
I("loading").className="hidden"; //hide loading message
|
||||
//populate server list for manual selection
|
||||
for(var i=0;i<SPEEDTEST_SERVERS.length;i++){
|
||||
if(SPEEDTEST_SERVERS[i].pingT==-1) continue;
|
||||
var option=document.createElement("option");
|
||||
option.value=i;
|
||||
option.textContent=SPEEDTEST_SERVERS[i].name;
|
||||
if(SPEEDTEST_SERVERS[i]===server) option.selected=true;
|
||||
I("server").appendChild(option);
|
||||
}
|
||||
//show test UI
|
||||
I("testWrapper").className="visible";
|
||||
initUI();
|
||||
}else{ //no servers are available, the test cannot proceed
|
||||
noServersAvailable();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(typeof SPEEDTEST_SERVERS === "string"){
|
||||
//need to fetch list of servers from specified URL
|
||||
s.loadServerList(SPEEDTEST_SERVERS,function(servers){
|
||||
if(servers==null){ //failed to load server list
|
||||
noServersAvailable();
|
||||
}else{ //server list loaded
|
||||
SPEEDTEST_SERVERS=servers;
|
||||
runServerSelect();
|
||||
}
|
||||
});
|
||||
}else{
|
||||
//hardcoded server list
|
||||
s.addTestPoints(SPEEDTEST_SERVERS);
|
||||
runServerSelect();
|
||||
}
|
||||
}
|
||||
|
||||
var meterBk=/Trident.*rv:(\d+\.\d+)/i.test(navigator.userAgent)?"#EAEAEA":"#80808040";
|
||||
var dlColor="#6060AA",
|
||||
ulColor="#616161";
|
||||
var progColor=meterBk;
|
||||
|
||||
//CODE FOR GAUGES
|
||||
function drawMeter(c,amount,bk,fg,progress,prog){
|
||||
var ctx=c.getContext("2d");
|
||||
var dp=window.devicePixelRatio||1;
|
||||
var cw=c.clientWidth*dp, ch=c.clientHeight*dp;
|
||||
var sizScale=ch*0.0055;
|
||||
if(c.width==cw&&c.height==ch){
|
||||
ctx.clearRect(0,0,cw,ch);
|
||||
}else{
|
||||
c.width=cw;
|
||||
c.height=ch;
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=bk;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,Math.PI*0.1);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle=fg;
|
||||
ctx.lineWidth=12*sizScale;
|
||||
ctx.arc(c.width/2,c.height-58*sizScale,c.height/1.8-ctx.lineWidth,-Math.PI*1.1,amount*Math.PI*1.2-Math.PI*1.1);
|
||||
ctx.stroke();
|
||||
if(typeof progress !== "undefined"){
|
||||
ctx.fillStyle=prog;
|
||||
ctx.fillRect(c.width*0.3,c.height-16*sizScale,c.width*0.4*progress,4*sizScale);
|
||||
}
|
||||
}
|
||||
function mbpsToAmount(s){
|
||||
return 1-(1/(Math.pow(1.3,Math.sqrt(s))));
|
||||
}
|
||||
function format(d){
|
||||
d=Number(d);
|
||||
if(d<10) return d.toFixed(2);
|
||||
if(d<100) return d.toFixed(1);
|
||||
return d.toFixed(0);
|
||||
}
|
||||
|
||||
//UI CODE
|
||||
var uiData=null;
|
||||
function startStop(){
|
||||
if(s.getState()==3){
|
||||
//speed test is running, abort
|
||||
s.abort();
|
||||
data=null;
|
||||
I("startStopBtn").className="";
|
||||
I("server").disabled=false;
|
||||
initUI();
|
||||
}else{
|
||||
//test is not running, begin
|
||||
I("startStopBtn").className="running";
|
||||
I("shareArea").style.display="none";
|
||||
I("server").disabled=true;
|
||||
s.onupdate=function(data){
|
||||
uiData=data;
|
||||
};
|
||||
s.onend=function(aborted){
|
||||
I("startStopBtn").className="";
|
||||
I("server").disabled=false;
|
||||
updateUI(true);
|
||||
if(!aborted){
|
||||
//if testId is present, show sharing panel, otherwise do nothing
|
||||
try{
|
||||
var testId=uiData.testId;
|
||||
if(testId!=null){
|
||||
var shareURL=window.location.href.substring(0,window.location.href.lastIndexOf("/"))+"/results/?id="+testId;
|
||||
I("resultsImg").src=shareURL;
|
||||
I("resultsURL").value=shareURL;
|
||||
I("testId").innerHTML=testId;
|
||||
I("shareArea").style.display="";
|
||||
}
|
||||
}catch(e){}
|
||||
}
|
||||
};
|
||||
s.start();
|
||||
}
|
||||
}
|
||||
//this function reads the data sent back by the test and updates the UI
|
||||
function updateUI(forced){
|
||||
if(!forced&&s.getState()!=3) return;
|
||||
if(uiData==null) return;
|
||||
var status=uiData.testState;
|
||||
I("ip").textContent=uiData.clientIp;
|
||||
I("dlText").textContent=(status==1&&uiData.dlStatus==0)?"...":format(uiData.dlStatus);
|
||||
drawMeter(I("dlMeter"),mbpsToAmount(Number(uiData.dlStatus*(status==1?oscillate():1))),meterBk,dlColor,Number(uiData.dlProgress),progColor);
|
||||
I("ulText").textContent=(status==3&&uiData.ulStatus==0)?"...":format(uiData.ulStatus);
|
||||
drawMeter(I("ulMeter"),mbpsToAmount(Number(uiData.ulStatus*(status==3?oscillate():1))),meterBk,ulColor,Number(uiData.ulProgress),progColor);
|
||||
I("pingText").textContent=format(uiData.pingStatus);
|
||||
I("jitText").textContent=format(uiData.jitterStatus);
|
||||
}
|
||||
function oscillate(){
|
||||
return 1+0.02*Math.sin(Date.now()/100);
|
||||
}
|
||||
//update the UI every frame
|
||||
window.requestAnimationFrame=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||(function(callback,element){setTimeout(callback,1000/60);});
|
||||
function frame(){
|
||||
requestAnimationFrame(frame);
|
||||
updateUI();
|
||||
}
|
||||
frame(); //start frame loop
|
||||
//function to (re)initialize UI
|
||||
function initUI(){
|
||||
drawMeter(I("dlMeter"),0,meterBk,dlColor,0);
|
||||
drawMeter(I("ulMeter"),0,meterBk,ulColor,0);
|
||||
I("dlText").textContent="";
|
||||
I("ulText").textContent="";
|
||||
I("pingText").textContent="";
|
||||
I("jitText").textContent="";
|
||||
I("ip").textContent="";
|
||||
}
|
||||
</script>
|
||||
<style type="text/css">
|
||||
html,body{
|
||||
border:none; padding:0; margin:0;
|
||||
background:#FFFFFF;
|
||||
color:#202020;
|
||||
}
|
||||
body{
|
||||
text-align:center;
|
||||
font-family:"Roboto",sans-serif;
|
||||
}
|
||||
h1{
|
||||
color:#404040;
|
||||
}
|
||||
#loading{
|
||||
background-color:#FFFFFF;
|
||||
color:#404040;
|
||||
text-align:center;
|
||||
}
|
||||
span.loadCircle{
|
||||
display:inline-block;
|
||||
width:2em;
|
||||
height:2em;
|
||||
vertical-align:middle;
|
||||
background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAP1BMVEUAAAB2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZ2dnZyFzwnAAAAFHRSTlMAEvRFvX406baecwbf0casimhSHyiwmqgAAADpSURBVHja7dbJbQMxAENRahnN5lkc//5rDRAkDeRgHszXgACJoKiIiIiIiIiIiIiIiIiIiIj4HHspsrpAVhdVVguzrA4OWc10WcEqpwKbnBo0OU1Q5NSpsoJFTgOecrrdEag85DRgktNqfoEdTjnd7hrEHMEJvmRUYJbTYk5Agy6nau6Abp5Cm7mDBtRdPi9gyKdU7w4p1fsLvyqs8hl4z9/w3n/Hmr9WoQ65lAU4d7lMYOz//QboRR5jBZibLMZdAR6O/Vfa1PlxNr3XdS3HzK/HVPRu/KnLs8iAOh993VpRRERERMT/fAN60wwWaVyWwAAAAABJRU5ErkJggg==');
|
||||
background-size:2em 2em;
|
||||
margin-right:0.5em;
|
||||
animation: spin 0.6s linear infinite;
|
||||
}
|
||||
@keyframes spin{
|
||||
0%{transform:rotate(0deg);}
|
||||
100%{transform:rotate(359deg);}
|
||||
}
|
||||
#startStopBtn{
|
||||
display:inline-block;
|
||||
margin:0 auto;
|
||||
color:#6060AA;
|
||||
background-color:rgba(0,0,0,0);
|
||||
border:0.15em solid #6060FF;
|
||||
border-radius:0.3em;
|
||||
transition:all 0.3s;
|
||||
box-sizing:border-box;
|
||||
width:8em; height:3em;
|
||||
line-height:2.7em;
|
||||
cursor:pointer;
|
||||
box-shadow: 0 0 0 rgba(0,0,0,0.1), inset 0 0 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn:hover{
|
||||
box-shadow: 0 0 2em rgba(0,0,0,0.1), inset 0 0 1em rgba(0,0,0,0.1);
|
||||
}
|
||||
#startStopBtn.running{
|
||||
background-color:#FF3030;
|
||||
border-color:#FF6060;
|
||||
color:#FFFFFF;
|
||||
}
|
||||
#startStopBtn:before{
|
||||
content:"Start";
|
||||
}
|
||||
#startStopBtn.running:before{
|
||||
content:"Abort";
|
||||
}
|
||||
#serverArea{
|
||||
margin-top:1em;
|
||||
}
|
||||
#server{
|
||||
font-size:1em;
|
||||
padding:0.2em;
|
||||
}
|
||||
#test{
|
||||
margin-top:2em;
|
||||
margin-bottom:12em;
|
||||
}
|
||||
div.testArea{
|
||||
display:inline-block;
|
||||
width:16em;
|
||||
height:12.5em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
}
|
||||
div.testArea2{
|
||||
display:inline-block;
|
||||
width:14em;
|
||||
height:7em;
|
||||
position:relative;
|
||||
box-sizing:border-box;
|
||||
text-align:center;
|
||||
}
|
||||
div.testArea div.testName{
|
||||
position:absolute;
|
||||
top:0.1em; left:0;
|
||||
width:100%;
|
||||
font-size:1.4em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.testName{
|
||||
display:block;
|
||||
text-align:center;
|
||||
font-size:1.4em;
|
||||
}
|
||||
div.testArea div.meterText{
|
||||
position:absolute;
|
||||
bottom:1.55em; left:0;
|
||||
width:100%;
|
||||
font-size:2.5em;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.meterText{
|
||||
display:inline-block;
|
||||
font-size:2.5em;
|
||||
}
|
||||
div.meterText:empty:before{
|
||||
content:"0.00";
|
||||
}
|
||||
div.testArea div.unit{
|
||||
position:absolute;
|
||||
bottom:2em; left:0;
|
||||
width:100%;
|
||||
z-index:9;
|
||||
}
|
||||
div.testArea2 div.unit{
|
||||
display:inline-block;
|
||||
}
|
||||
div.testArea canvas{
|
||||
position:absolute;
|
||||
top:0; left:0; width:100%; height:100%;
|
||||
z-index:1;
|
||||
}
|
||||
div.testGroup{
|
||||
display:block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#shareArea{
|
||||
width:95%;
|
||||
max-width:40em;
|
||||
margin:0 auto;
|
||||
margin-top:2em;
|
||||
}
|
||||
#shareArea > *{
|
||||
display:block;
|
||||
width:100%;
|
||||
height:auto;
|
||||
margin: 0.25em 0;
|
||||
}
|
||||
#privacyPolicy{
|
||||
position:fixed;
|
||||
top:2em;
|
||||
bottom:2em;
|
||||
left:2em;
|
||||
right:2em;
|
||||
overflow-y:auto;
|
||||
width:auto;
|
||||
height:auto;
|
||||
box-shadow:0 0 3em 1em #000000;
|
||||
z-index:999999;
|
||||
text-align:left;
|
||||
background-color:#FFFFFF;
|
||||
padding:1em;
|
||||
}
|
||||
a.privacy{
|
||||
text-align:center;
|
||||
font-size:0.8em;
|
||||
color:#808080;
|
||||
padding: 0 3em;
|
||||
}
|
||||
div.closePrivacyPolicy {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
div.closePrivacyPolicy a.privacy {
|
||||
padding: 1em 3em;
|
||||
}
|
||||
@media all and (max-width:40em){
|
||||
body{
|
||||
font-size:0.8em;
|
||||
}
|
||||
}
|
||||
div.visible{
|
||||
animation: fadeIn 0.4s;
|
||||
display:block;
|
||||
}
|
||||
div.hidden{
|
||||
animation: fadeOut 0.4s;
|
||||
display:none;
|
||||
}
|
||||
@keyframes fadeIn{
|
||||
0%{
|
||||
opacity:0;
|
||||
}
|
||||
100%{
|
||||
opacity:1;
|
||||
}
|
||||
}
|
||||
@keyframes fadeOut{
|
||||
0%{
|
||||
display:block;
|
||||
opacity:1;
|
||||
}
|
||||
100%{
|
||||
display:block;
|
||||
opacity:0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<title>/dev/player0's speedtest</title>
|
||||
</head>
|
||||
<body onload="initServers()">
|
||||
<h1>/dev/player0's speedtest</h1>
|
||||
<div id="loading" class="visible">
|
||||
<p id="message"><span class="loadCircle"></span>Selecting a server...</p>
|
||||
</div>
|
||||
<div id="testWrapper" class="hidden">
|
||||
<div id="startStopBtn" onclick="startStop()"></div><br/>
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display=''">Privacy</a>
|
||||
<div id="serverArea">
|
||||
Server: <select id="server" onchange="s.setSelectedServer(SPEEDTEST_SERVERS[this.value])"></select>
|
||||
</div>
|
||||
<div id="test">
|
||||
<div class="testGroup">
|
||||
<div class="testArea2">
|
||||
<div class="testName">Ping</div>
|
||||
<div id="pingText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
<div class="testArea2">
|
||||
<div class="testName">Jitter</div>
|
||||
<div id="jitText" class="meterText" style="color:#AA6060"></div>
|
||||
<div class="unit">ms</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="testGroup">
|
||||
<div class="testArea">
|
||||
<div class="testName">Download</div>
|
||||
<canvas id="dlMeter" class="meter"></canvas>
|
||||
<div id="dlText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
</div>
|
||||
<div class="testArea">
|
||||
<div class="testName">Upload</div>
|
||||
<canvas id="ulMeter" class="meter"></canvas>
|
||||
<div id="ulText" class="meterText"></div>
|
||||
<div class="unit">Mbit/s</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ipArea">
|
||||
<span id="ip"></span>
|
||||
</div>
|
||||
<div id="shareArea" style="display:none">
|
||||
<h3>Share results</h3>
|
||||
<p>Test ID: <span id="testId"></span></p>
|
||||
<input type="text" value="" id="resultsURL" readonly="readonly" onclick="this.select();this.focus();this.select();document.execCommand('copy');alert('Link copied')"/>
|
||||
<img src="" id="resultsImg" />
|
||||
</div>
|
||||
</div>
|
||||
<a href="https://github.com/librespeed/speedtest">Source code</a>
|
||||
</div>
|
||||
<div id="privacyPolicy" style="display:none">
|
||||
<h2>Privacy Policy</h2>
|
||||
<p>This HTML5 speed test server is configured with telemetry enabled.</p>
|
||||
<h4>What data we collect</h4>
|
||||
<p>
|
||||
At the end of the test, the following data is collected and stored:
|
||||
<ul>
|
||||
<li>Test ID</li>
|
||||
<li>Time of testing</li>
|
||||
<li>Test results (download and upload speed, ping and jitter)</li>
|
||||
<li>IP address</li>
|
||||
<li>ISP information</li>
|
||||
<li>Approximate location (inferred from IP address, not GPS)</li>
|
||||
<li>User agent and browser locale</li>
|
||||
<li>Test log (contains no personal information)</li>
|
||||
</ul>
|
||||
</p>
|
||||
<h4>How we use the data</h4>
|
||||
<p>
|
||||
Data collected through this service is used to:
|
||||
<ul>
|
||||
<li>Allow sharing of test results (sharable image for forums, etc.)</li>
|
||||
<li>To improve the service offered to you (for instance, to detect problems on our side)</li>
|
||||
</ul>
|
||||
No personal information is disclosed to third parties.
|
||||
</p>
|
||||
<h4>Your consent</h4>
|
||||
<p>
|
||||
By starting the test, you consent to the terms of this privacy policy.
|
||||
</p>
|
||||
<h4>Data removal</h4>
|
||||
<p>
|
||||
If you want to have your information deleted, you need to provide either the ID of the test or your IP address. This is the only way to identify your data, without this information we won't be able to comply with your request.<br/><br/>
|
||||
Contact this email address for all deletion requests: <a href="mailto:dev@nul.ie">dev@nul.ie</a>.
|
||||
</p>
|
||||
<br/><br/>
|
||||
<div class="closePrivacyPolicy">
|
||||
<a class="privacy" href="#" onclick="I('privacyPolicy').style.display='none'">Close</a>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@@ -1,238 +0,0 @@
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (lib) mkMerge mkIf mkForce genAttrs concatMapStringsSep;
|
||||
inherit (lib.my) mkOpt' mkBoolOpt';
|
||||
|
||||
cfg = config.my.netboot;
|
||||
|
||||
# Newer releases don't boot on desktop?
|
||||
ipxe = pkgs.ipxe.overrideAttrs (o: rec {
|
||||
version = "1.21.1-unstable-2024-06-27";
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "ipxe";
|
||||
repo = "ipxe";
|
||||
rev = "b66e27d9b29a172a097c737ab4d378d60fe01b05";
|
||||
hash = "sha256-TKZ4WjNV2oZIYNefch7E7m1JpeoC/d7O1kofoNv8G40=";
|
||||
};
|
||||
|
||||
# This upstream patch (in newer versions) is needed for newer GCC
|
||||
patches = (if (o ? patches) then o.patches else []) ++ [ ./fix-uninitialised-var.patch ];
|
||||
});
|
||||
tftpRoot = pkgs.linkFarm "tftp-root" [
|
||||
{
|
||||
name = "ipxe-x86_64.efi";
|
||||
path = "${ipxe}/ipxe.efi";
|
||||
}
|
||||
];
|
||||
menuFile = pkgs.runCommand "menu.ipxe" {
|
||||
bootHost = cfg.server.host;
|
||||
} ''
|
||||
substituteAll ${./menu.ipxe} "$out"
|
||||
'';
|
||||
|
||||
bootBuilder = pkgs.replaceVarsWith {
|
||||
src = ./netboot-loader-builder.py;
|
||||
isExecutable = true;
|
||||
|
||||
replacements = {
|
||||
inherit (pkgs) python3;
|
||||
bootspecTools = pkgs.bootspec;
|
||||
nix = config.nix.package.out;
|
||||
|
||||
inherit (config.system.nixos) distroName;
|
||||
systemName = config.system.name;
|
||||
inherit (cfg.client) configurationLimit;
|
||||
checkMountpoints = pkgs.writeShellScript "check-mountpoints" ''
|
||||
if ! ${pkgs.util-linuxMinimal}/bin/findmnt /boot > /dev/null; then
|
||||
echo "/boot is not a mounted partition. Is the path configured correctly?" >&2
|
||||
exit 1
|
||||
fi
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.my.netboot = with lib.types; {
|
||||
client = {
|
||||
enable = mkBoolOpt' false "Whether network booting should be enabled.";
|
||||
configurationLimit = mkOpt' ints.unsigned 10 "Max generations to show in boot menu.";
|
||||
};
|
||||
server = {
|
||||
enable = mkBoolOpt' false "Whether a netboot server should be enabled.";
|
||||
ip = mkOpt' str null "IP clients should connect to via TFTP.";
|
||||
host = mkOpt' str config.networking.fqdn "Hostname clients should connect to over HTTP / NFS.";
|
||||
allowedPrefixes = mkOpt' (listOf str) null "Prefixes clients should be allowed to connect from (NFS).";
|
||||
installer = {
|
||||
storeSize = mkOpt' str "16GiB" "Total allowed writable size of store.";
|
||||
};
|
||||
instances = mkOpt' (listOf str) [ ] "Systems to hold boot files for.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.client.enable {
|
||||
systemd = {
|
||||
services = {
|
||||
mount-boot = {
|
||||
description = "Mount /boot";
|
||||
after = [ "systemd-networkd-wait-online.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
};
|
||||
path = with pkgs; [ gnused ldns nfs-utils ];
|
||||
script = ''
|
||||
get_cmdline() {
|
||||
sed -rn "s/^.*$1=(\\S+).*\$/\\1/p" < /proc/cmdline
|
||||
}
|
||||
|
||||
host="$(get_cmdline boothost)"
|
||||
if [ -z "$host" ]; then
|
||||
echo "boothost kernel parameter not found!" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
until [ -n "$(drill -Q $host)" ]; do
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
mkdir -p /boot
|
||||
mount.nfs $host:/srv/netboot/systems/${config.system.name} /boot
|
||||
'';
|
||||
|
||||
wantedBy = [ "remote-fs.target" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
boot.supportedFilesystems.nfs = true;
|
||||
boot.loader = {
|
||||
grub.enable = false;
|
||||
systemd-boot.enable = false;
|
||||
};
|
||||
system = {
|
||||
build.installBootLoader = bootBuilder;
|
||||
boot.loader.id = "ipxe-netboot";
|
||||
};
|
||||
})
|
||||
(mkIf cfg.server.enable {
|
||||
environment = {
|
||||
etc = {
|
||||
"netboot/menu.ipxe".source = menuFile;
|
||||
"netboot/shell.efi".source = "${pkgs.edk2-uefi-shell}/shell.efi";
|
||||
};
|
||||
};
|
||||
|
||||
systemd = {
|
||||
tmpfiles.settings."10-netboot" = genAttrs
|
||||
(map (i: "/srv/netboot/systems/${i}") cfg.server.instances)
|
||||
(p: {
|
||||
d = {
|
||||
user = "root";
|
||||
group = "root";
|
||||
mode = "0777";
|
||||
};
|
||||
});
|
||||
|
||||
services = {
|
||||
netboot-update = {
|
||||
description = "Update netboot images";
|
||||
after = [ "systemd-networkd-wait-online.service" ];
|
||||
serviceConfig.Type = "oneshot";
|
||||
path = with pkgs; [
|
||||
coreutils curl jq zstd gnutar
|
||||
];
|
||||
script = ''
|
||||
update_nixos() {
|
||||
latestShort="$(curl -s https://git.nul.ie/api/v1/repos/dev/nixfiles/tags/installer \
|
||||
| jq -r .commit.sha | cut -c -7)"
|
||||
if [ -f nixos-installer/tag.txt ] && [ "$(< nixos-installer/tag.txt)" = "$latestShort" ]; then
|
||||
echo "NixOS installer is up to date"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "Updating NixOS installer to $latestShort"
|
||||
mkdir -p nixos-installer
|
||||
fname="jackos-installer-netboot-$latestShort.tar.zst"
|
||||
downloadUrl="$(curl -s https://git.nul.ie/api/v1/repos/dev/nixfiles/releases/tags/installer | \
|
||||
jq -r ".assets[] | select(.name == \"$fname\").browser_download_url")"
|
||||
curl -Lo /tmp/nixos-installer-netboot.tar.zst "$downloadUrl"
|
||||
tar -C nixos-installer --zstd -xf /tmp/nixos-installer-netboot.tar.zst
|
||||
truncate -s "${cfg.server.installer.storeSize}" nixos-installer/rootfs.ext4
|
||||
rm /tmp/nixos-installer-netboot.tar.zst
|
||||
echo "$latestShort" > nixos-installer/tag.txt
|
||||
}
|
||||
|
||||
mkdir -p /srv/netboot
|
||||
cd /srv/netboot
|
||||
|
||||
ln -sf ${menuFile} boot.ipxe
|
||||
ln -sf "${pkgs.edk2-uefi-shell}/shell.efi" "efi-shell-${config.nixpkgs.localSystem.linuxArch}.efi"
|
||||
update_nixos
|
||||
'';
|
||||
startAt = "06:00";
|
||||
wantedBy = [ "network-online.target" ];
|
||||
};
|
||||
|
||||
nbd-server = {
|
||||
serviceConfig = {
|
||||
PrivateUsers = mkForce false;
|
||||
CacheDirectory = "netboot";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
atftpd = {
|
||||
enable = true;
|
||||
root = tftpRoot;
|
||||
};
|
||||
|
||||
nginx = {
|
||||
virtualHosts."${cfg.server.host}" = {
|
||||
locations."/" = {
|
||||
root = "/srv/netboot";
|
||||
extraConfig = ''
|
||||
autoindex on;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nbd.server = {
|
||||
enable = true;
|
||||
extraOptions = {
|
||||
allowlist = true;
|
||||
};
|
||||
exports = {
|
||||
nixos-installer = {
|
||||
path = "/srv/netboot/nixos-installer/rootfs.ext4";
|
||||
extraOptions = {
|
||||
copyonwrite = true;
|
||||
cowdir = "/var/cache/netboot";
|
||||
sparse_cow = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
nfs = {
|
||||
server = {
|
||||
enable = true;
|
||||
exports = ''
|
||||
/srv/netboot/systems ${concatMapStringsSep " " (p: "${p}(rw,all_squash)") cfg.server.allowedPrefixes}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
my = {
|
||||
tmproot.persistence.config.directories = [
|
||||
"/srv/netboot"
|
||||
{ directory = "/var/cache/netboot"; mode = "0700"; }
|
||||
];
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
From 7f75d320f6d8ac7ec5185b2145da87f698aec273 Mon Sep 17 00:00:00 2001
|
||||
From: Michael Brown <mcb30@ipxe.org>
|
||||
Date: Mon, 2 Sep 2024 12:24:57 +0100
|
||||
Subject: [PATCH] [etherfabric] Fix use of uninitialised variable in
|
||||
falcon_xaui_link_ok()
|
||||
|
||||
The link status check in falcon_xaui_link_ok() reads from the
|
||||
FCN_XX_CORE_STAT_REG_MAC register only on production hardware (where
|
||||
the FPGA version reads as zero), but modifies the value and writes
|
||||
back to this register unconditionally. This triggers an uninitialised
|
||||
variable warning on newer versions of gcc.
|
||||
|
||||
Fix by assuming that the register exists only on production hardware,
|
||||
and so moving the "modify-write" portion of the "read-modify-write"
|
||||
operation to also be covered by the same conditional check.
|
||||
|
||||
Signed-off-by: Michael Brown <mcb30@ipxe.org>
|
||||
---
|
||||
src/drivers/net/etherfabric.c | 15 +++++++++------
|
||||
1 file changed, 9 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c
|
||||
index b40596beae7..be30b71f79f 100644
|
||||
--- a/src/drivers/net/etherfabric.c
|
||||
+++ b/src/drivers/net/etherfabric.c
|
||||
@@ -2225,13 +2225,16 @@ falcon_xaui_link_ok ( struct efab_nic *efab )
|
||||
sync = ( sync == FCN_XX_SYNC_STAT_DECODE_SYNCED );
|
||||
|
||||
link_ok = align_done && sync;
|
||||
- }
|
||||
|
||||
- /* Clear link status ready for next read */
|
||||
- EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET, FCN_XX_COMMA_DET_RESET );
|
||||
- EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR, FCN_XX_CHARERR_RESET);
|
||||
- EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR, FCN_XX_DISPERR_RESET);
|
||||
- falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC );
|
||||
+ /* Clear link status ready for next read */
|
||||
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_COMMA_DET,
|
||||
+ FCN_XX_COMMA_DET_RESET );
|
||||
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_CHARERR,
|
||||
+ FCN_XX_CHARERR_RESET );
|
||||
+ EFAB_SET_DWORD_FIELD ( reg, FCN_XX_DISPERR,
|
||||
+ FCN_XX_DISPERR_RESET );
|
||||
+ falcon_xmac_writel ( efab, ®, FCN_XX_CORE_STAT_REG_MAC );
|
||||
+ }
|
||||
|
||||
has_phyxs = ( efab->phy_op->mmds & ( 1 << MDIO_MMD_PHYXS ) );
|
||||
if ( link_ok && has_phyxs ) {
|
@@ -1,68 +0,0 @@
|
||||
#!ipxe
|
||||
|
||||
set server http://@bootHost@
|
||||
|
||||
# Figure out if client is 64-bit capable
|
||||
cpuid --ext 29 && set arch x86_64 || set arch i386
|
||||
|
||||
isset ${menu-default} || set menu-default exit
|
||||
|
||||
:start
|
||||
menu Welcome to /dev/player0's humble iPXE boot menu
|
||||
item --gap -- Operating Systems
|
||||
iseq ${arch} x86_64 &&
|
||||
item --key n nixos NixOS installer
|
||||
# iseq ${arch} x86_64 &&
|
||||
# item --key a archlinux Arch Linux (archiso x86_64)
|
||||
# iseq ${arch} x86_64 &&
|
||||
# item --key p alpine Alpine Linux
|
||||
item --gap -- Other Options
|
||||
item --key e efi_shell UEFI Shell
|
||||
item --key x xyz netboot.xyz
|
||||
item --key c config iPXE settings
|
||||
item --key s shell Drop to iPXE shell
|
||||
item --key r reboot Reboot
|
||||
item --key q exit Exit (and continue to next boot device)
|
||||
choose --timeout 0 --default ${menu-default} selected || goto cancel
|
||||
goto ${selected}
|
||||
|
||||
:cancel
|
||||
echo You cancelled the menu, dropping you to an iPXE shell
|
||||
|
||||
:shell
|
||||
echo Type 'exit' to go back to the menu
|
||||
shell
|
||||
set menu-default nixos
|
||||
goto start
|
||||
|
||||
:failed
|
||||
echo Booting failed, dropping to shell
|
||||
goto shell
|
||||
|
||||
:reboot
|
||||
reboot
|
||||
|
||||
:exit
|
||||
exit
|
||||
|
||||
:config
|
||||
config
|
||||
set menu-default config
|
||||
goto start
|
||||
|
||||
:efi_shell
|
||||
chain ${server}/efi-shell-${arch}.efi || goto failed
|
||||
|
||||
:xyz
|
||||
chain --autofree https://boot.netboot.xyz || goto failed
|
||||
|
||||
:nixos
|
||||
set cmdline nbd_export=nixos-installer
|
||||
chain ${server}/nixos-installer/boot.ipxe || goto failed
|
||||
|
||||
:archlinux
|
||||
# set mirrorurl https://arch.nul.ie/
|
||||
chain ${server}/arch.ipxe || goto failed
|
||||
|
||||
:alpine
|
||||
chain ${server}/alpine.ipxe || goto failed
|
@@ -1,280 +0,0 @@
|
||||
#! @python3@/bin/python3 -B
|
||||
# Based on `nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py`
|
||||
import argparse
|
||||
import datetime
|
||||
import glob
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import json
|
||||
from typing import NamedTuple, Dict, List
|
||||
from dataclasses import dataclass
|
||||
|
||||
BOOT_MOUNT_POINT = '/boot'
|
||||
STORE_DIR = 'nix'
|
||||
|
||||
# These values will be replaced with actual values during the package build
|
||||
BOOTSPEC_TOOLS = '@bootspecTools@'
|
||||
NIX = '@nix@'
|
||||
DISTRO_NAME = '@distroName@'
|
||||
SYSTEM_NAME = '@systemName@'
|
||||
CONFIGURATION_LIMIT = int('@configurationLimit@')
|
||||
CHECK_MOUNTPOINTS = "@checkMountpoints@"
|
||||
|
||||
@dataclass
|
||||
class BootSpec:
|
||||
init: str
|
||||
initrd: str
|
||||
kernel: str
|
||||
kernelParams: List[str]
|
||||
label: str
|
||||
system: str
|
||||
toplevel: str
|
||||
specialisations: Dict[str, 'BootSpec']
|
||||
sortKey: str
|
||||
initrdSecrets: str | None = None
|
||||
|
||||
class SystemIdentifier(NamedTuple):
|
||||
profile: str | None
|
||||
generation: int
|
||||
specialisation: str | None
|
||||
|
||||
def copy_if_not_exists(source: str, dest: str) -> None:
|
||||
if not os.path.exists(dest):
|
||||
shutil.copyfile(source, dest)
|
||||
|
||||
def generation_dir(profile: str | None, generation: int) -> str:
|
||||
if profile:
|
||||
return f'/nix/var/nix/profiles/system-profiles/{profile}-{generation}-link'
|
||||
else:
|
||||
return f'/nix/var/nix/profiles/system-{generation}-link'
|
||||
|
||||
def system_dir(i: SystemIdentifier) -> str:
|
||||
d = generation_dir(i.profile, i.generation)
|
||||
if i.specialisation:
|
||||
return os.path.join(d, 'specialisation', i.specialisation)
|
||||
else:
|
||||
return d
|
||||
|
||||
def entry_key(i: SystemIdentifier) -> str:
|
||||
pieces = [
|
||||
'nixos',
|
||||
i.profile or None,
|
||||
'generation',
|
||||
str(i.generation),
|
||||
f'specialisation-{i.specialisation}' if i.specialisation else None,
|
||||
]
|
||||
return '-'.join(p for p in pieces if p)
|
||||
|
||||
def bootspec_from_json(bootspec_json: Dict) -> BootSpec:
|
||||
specialisations = bootspec_json['org.nixos.specialisation.v1']
|
||||
specialisations = {k: bootspec_from_json(v) for k, v in specialisations.items()}
|
||||
systemdBootExtension = bootspec_json.get('org.nixos.systemd-boot', {})
|
||||
sortKey = systemdBootExtension.get('sortKey', 'nixos')
|
||||
return BootSpec(
|
||||
**bootspec_json['org.nixos.bootspec.v1'],
|
||||
specialisations=specialisations,
|
||||
sortKey=sortKey
|
||||
)
|
||||
|
||||
bootspecs = {}
|
||||
def get_bootspec(profile: str | None, generation: int) -> BootSpec:
|
||||
k = (profile, generation)
|
||||
if k in bootspecs:
|
||||
return bootspecs[k]
|
||||
|
||||
system_directory = system_dir(SystemIdentifier(profile, generation, None))
|
||||
boot_json_path = os.path.realpath(f'{system_directory}/boot.json')
|
||||
if os.path.isfile(boot_json_path):
|
||||
boot_json_f = open(boot_json_path, 'r')
|
||||
bootspec_json = json.load(boot_json_f)
|
||||
else:
|
||||
boot_json_str = subprocess.check_output([
|
||||
f'{BOOTSPEC_TOOLS}/bin/synthesize',
|
||||
'--version',
|
||||
'1',
|
||||
system_directory,
|
||||
'/dev/stdout',
|
||||
],
|
||||
universal_newlines=True)
|
||||
bootspec_json = json.loads(boot_json_str)
|
||||
|
||||
bs = bootspec_from_json(bootspec_json)
|
||||
bootspecs[k] = bs
|
||||
return bs
|
||||
|
||||
def copy_from_file(file: str, dry_run: bool = False) -> str:
|
||||
store_file_path = os.path.realpath(file)
|
||||
suffix = os.path.basename(store_file_path)
|
||||
store_dir = os.path.basename(os.path.dirname(store_file_path))
|
||||
dst_path = f'/{STORE_DIR}/{store_dir}-{suffix}'
|
||||
if not dry_run:
|
||||
copy_if_not_exists(store_file_path, f'{BOOT_MOUNT_POINT}{dst_path}')
|
||||
return dst_path
|
||||
|
||||
MENU_ITEM = 'item {gen_key} {title} Generation {generation} {description}'
|
||||
|
||||
BOOT_ENTRY = ''':{gen_key}
|
||||
kernel ${{server}}/systems/{system_name}{kernel} {kernel_params} boothost=${{boothost}}
|
||||
initrd ${{server}}/systems/{system_name}{initrd}
|
||||
boot
|
||||
'''
|
||||
|
||||
def gen_entry(i: SystemIdentifier) -> (str, str):
|
||||
bootspec = get_bootspec(i.profile, i.generation)
|
||||
if i.specialisation:
|
||||
bootspec = bootspec.specialisations[i.specialisation]
|
||||
kernel = copy_from_file(bootspec.kernel)
|
||||
initrd = copy_from_file(bootspec.initrd)
|
||||
|
||||
gen_key = entry_key(i)
|
||||
title = '{name}{profile}{specialisation}'.format(
|
||||
name=DISTRO_NAME,
|
||||
profile=' [' + i.profile + ']' if i.profile else '',
|
||||
specialisation=f' ({i.specialisation})' if i.specialisation else '')
|
||||
|
||||
kernel_params = f'init={bootspec.init} '
|
||||
|
||||
kernel_params = kernel_params + ' '.join(bootspec.kernelParams)
|
||||
build_time = int(os.path.getctime(system_dir(i)))
|
||||
build_date = datetime.datetime.fromtimestamp(build_time).strftime('%F')
|
||||
|
||||
return MENU_ITEM.format(
|
||||
gen_key=gen_key,
|
||||
title=title,
|
||||
description=f'{bootspec.label}, built on {build_date}',
|
||||
generation=i.generation,
|
||||
), BOOT_ENTRY.format(
|
||||
gen_key=gen_key,
|
||||
generation=i.generation,
|
||||
system_name=SYSTEM_NAME,
|
||||
kernel=kernel,
|
||||
kernel_params=kernel_params,
|
||||
initrd=initrd,
|
||||
)
|
||||
|
||||
def get_generations(profile: str | None = None) -> list[SystemIdentifier]:
|
||||
gen_list = subprocess.check_output([
|
||||
f'{NIX}/bin/nix-env',
|
||||
'--list-generations',
|
||||
'-p',
|
||||
'/nix/var/nix/profiles/' + ('system-profiles/' + profile if profile else 'system')],
|
||||
universal_newlines=True)
|
||||
gen_lines = gen_list.split('\n')
|
||||
gen_lines.pop()
|
||||
|
||||
configurationLimit = CONFIGURATION_LIMIT
|
||||
configurations = [
|
||||
SystemIdentifier(
|
||||
profile=profile,
|
||||
generation=int(line.split()[0]),
|
||||
specialisation=None
|
||||
)
|
||||
for line in gen_lines
|
||||
]
|
||||
return configurations[-configurationLimit:]
|
||||
|
||||
def remove_old_files(gens: list[SystemIdentifier]) -> None:
|
||||
known_paths = []
|
||||
for gen in gens:
|
||||
bootspec = get_bootspec(gen.profile, gen.generation)
|
||||
known_paths.append(copy_from_file(bootspec.kernel, True))
|
||||
known_paths.append(copy_from_file(bootspec.initrd, True))
|
||||
for path in glob.iglob(f'{BOOT_MOUNT_POINT}/{STORE_DIR}/*'):
|
||||
if not path in known_paths and not os.path.isdir(path):
|
||||
os.unlink(path)
|
||||
|
||||
def get_profiles() -> list[str]:
|
||||
if os.path.isdir('/nix/var/nix/profiles/system-profiles/'):
|
||||
return [x
|
||||
for x in os.listdir('/nix/var/nix/profiles/system-profiles/')
|
||||
if not x.endswith('-link')]
|
||||
else:
|
||||
return []
|
||||
|
||||
MENU = '''#!ipxe
|
||||
# Server hostname option
|
||||
set boothost ${{66:string}}
|
||||
set server http://${{boothost}}
|
||||
|
||||
:start
|
||||
menu {distro} boot menu
|
||||
item --gap -- Generations
|
||||
{generation_items}
|
||||
item --gap -- Other
|
||||
item --key m main Main netboot menu
|
||||
choose --timeout 5000 --default {menu_default} selected || goto cancel
|
||||
goto ${{selected}}
|
||||
|
||||
:cancel
|
||||
shell
|
||||
goto start
|
||||
|
||||
:error
|
||||
echo Booting failed, dropping to shell
|
||||
shell
|
||||
goto start
|
||||
|
||||
:main
|
||||
chain ${{server}}/boot.ipxe || goto error
|
||||
'''
|
||||
|
||||
def write_menu(gens: list[SystemIdentifier], default: SystemIdentifier) -> None:
|
||||
gen_menu_items = []
|
||||
gen_cmds = []
|
||||
|
||||
for g in gens:
|
||||
bootspec = get_bootspec(g.profile, g.generation)
|
||||
specialisations = [
|
||||
SystemIdentifier(profile=g.profile, generation=g.generation, specialisation=s) for s in bootspec.specialisations]
|
||||
for i in [g] + specialisations:
|
||||
mi, cmds = gen_entry(i)
|
||||
gen_menu_items.append(mi)
|
||||
gen_cmds.append(cmds)
|
||||
|
||||
menu_file = f'{BOOT_MOUNT_POINT}/menu.ipxe'
|
||||
with open(f'{menu_file}.tmp', 'w') as f:
|
||||
f.write(MENU.format(
|
||||
distro=DISTRO_NAME,
|
||||
generation_items='\n'.join(gen_menu_items),
|
||||
menu_default=entry_key(default),
|
||||
))
|
||||
|
||||
print(file=f)
|
||||
print('\n\n'.join(gen_cmds), file=f)
|
||||
|
||||
os.rename(f'{menu_file}.tmp', menu_file)
|
||||
|
||||
def install_bootloader(args: argparse.Namespace) -> None:
|
||||
os.makedirs(f'{BOOT_MOUNT_POINT}/{STORE_DIR}', exist_ok=True)
|
||||
|
||||
gens = get_generations()
|
||||
for profile in get_profiles():
|
||||
gens += get_generations(profile)
|
||||
|
||||
gens = sorted(gens, key=lambda g: entry_key(g), reverse=True)
|
||||
|
||||
remove_old_files(gens)
|
||||
|
||||
for g in gens:
|
||||
if os.path.dirname(get_bootspec(g.profile, g.generation).init) == os.path.realpath(args.default_config):
|
||||
default = g
|
||||
break
|
||||
else:
|
||||
assert False, 'No default generation found'
|
||||
|
||||
write_menu(gens, default)
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=f'Update {DISTRO_NAME}-related netboot files')
|
||||
parser.add_argument('default_config', metavar='DEFAULT-CONFIG', help=f'The default {DISTRO_NAME} config to boot')
|
||||
args = parser.parse_args()
|
||||
|
||||
subprocess.check_call(CHECK_MOUNTPOINTS)
|
||||
|
||||
install_bootloader(args)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@@ -1,6 +1,6 @@
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
inherit (lib) flatten optional mkIf mkDefault mkMerge versionAtLeast;
|
||||
inherit (lib) flatten optional mkIf mkDefault mkMerge;
|
||||
in
|
||||
{
|
||||
config = mkMerge [
|
||||
@@ -12,6 +12,14 @@ in
|
||||
useNetworkd = mkDefault true;
|
||||
};
|
||||
|
||||
systemd = {
|
||||
additionalUpstreamSystemUnits = [
|
||||
# TODO: NixOS has its own version of this, but with `network` instead of `networkd`. Is this just a typo? It
|
||||
# hasn't been updated in 2 years...
|
||||
"systemd-networkd-wait-online@.service"
|
||||
];
|
||||
};
|
||||
|
||||
services.resolved = {
|
||||
domains = [ config.networking.domain ];
|
||||
# Explicitly unset fallback DNS (Nix module will not allow for a blank config)
|
||||
|
@@ -4,6 +4,11 @@ let
|
||||
inherit (lib.my) mkOpt';
|
||||
|
||||
cfg = config.my.nvme;
|
||||
nvme-cli = pkgs.nvme-cli.override {
|
||||
libnvme = pkgs.libnvme.overrideAttrs (o: {
|
||||
patches = o.patches ++ [ ./libnvme-hostconf.patch ];
|
||||
});
|
||||
};
|
||||
|
||||
hostNQN = "nqn.2014-08.org.nvmexpress:uuid:${cfg.uuid}";
|
||||
etc = prefix: {
|
||||
@@ -23,27 +28,14 @@ in
|
||||
config = mkIf (cfg.uuid != null) {
|
||||
environment = {
|
||||
systemPackages = [
|
||||
pkgs.nvme-cli
|
||||
nvme-cli
|
||||
];
|
||||
etc = etc "";
|
||||
};
|
||||
|
||||
boot = mkIf (cfg.boot.nqn != null) {
|
||||
initrd = {
|
||||
availableKernelModules = [ "rdma_cm" "iw_cm" "ib_cm" "nvme_core" "nvme_rdma" ];
|
||||
kernelModules = [ "nvme-fabrics" ];
|
||||
systemd = {
|
||||
boot.initrd.systemd = mkIf (cfg.boot.nqn != null) {
|
||||
contents = etc "/etc/";
|
||||
extraBin = with pkgs; {
|
||||
dmesg = "${util-linux}/bin/dmesg";
|
||||
ip = "${iproute2}/bin/ip";
|
||||
nvme = "${nvme-cli}/bin/nvme";
|
||||
};
|
||||
|
||||
network = {
|
||||
enable = true;
|
||||
wait-online.enable = true;
|
||||
};
|
||||
extraBin.nvme = "${nvme-cli}/bin/nvme";
|
||||
|
||||
services.connect-nvme = {
|
||||
description = "Connect NVMe-oF";
|
||||
@@ -53,26 +45,13 @@ in
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.nvme-cli}/bin/nvme connect -t rdma -a ${cfg.boot.address} -n ${cfg.boot.nqn} -q ${hostNQN}";
|
||||
ExecStart = "${nvme-cli}/bin/nvme connect -t rdma -a ${cfg.boot.address} -n ${cfg.boot.nqn}";
|
||||
Restart = "on-failure";
|
||||
RestartSec = 10;
|
||||
};
|
||||
|
||||
wantedBy = [ "initrd-root-device.target" ];
|
||||
};
|
||||
# TODO: Remove when 25.11 releases
|
||||
} // (if (lib.versionAtLeast lib.my.upstreamRelease "25.11") then {
|
||||
settings.Manager = {
|
||||
DefaultTimeoutStartSec = 20;
|
||||
DefaultDeviceTimeoutSec = 20;
|
||||
};
|
||||
} else {
|
||||
extraConfig = ''
|
||||
DefaultTimeoutStartSec=20
|
||||
DefaultDeviceTimeoutSec=20
|
||||
'';
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user