Added hetzner server configs
This commit is contained in:
@@ -0,0 +1,71 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
# Least-privilege by default; jobs opt into what they need.
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
# Cancel superseded runs on the same ref.
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.head_ref || github.sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check:
|
||||||
|
name: Flake check (${{ matrix.system }})
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
system:
|
||||||
|
- x86_64-linux
|
||||||
|
- aarch64-linux
|
||||||
|
# Match the architecture to a native runner, exactly like nixpkgs
|
||||||
|
# (its treefmt/parse/owners jobs run on ubuntu-24.04-arm).
|
||||||
|
runs-on: ${{ matrix.system == 'aarch64-linux' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||||
|
timeout-minutes: 30
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
|
||||||
|
with:
|
||||||
|
extra_nix_config: |
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
|
||||||
|
# Evaluate the flake for this system (incl. nixosConfigurations) without
|
||||||
|
# building. Catches the class of break we hit with the duplicate module block.
|
||||||
|
- name: Flake check (${{ matrix.system }})
|
||||||
|
run: nix flake check --no-build --system ${{ matrix.system }}
|
||||||
|
|
||||||
|
format:
|
||||||
|
name: Formatting check (${{ matrix.system }})
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
system:
|
||||||
|
- x86_64-linux
|
||||||
|
- aarch64-linux
|
||||||
|
runs-on: ${{ matrix.system == 'aarch64-linux' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
|
||||||
|
timeout-minutes: 10
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- uses: cachix/install-nix-action@a49548c11d9846ad46ecc0115273879b045f001c # v31.10.7
|
||||||
|
with:
|
||||||
|
extra_nix_config: |
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
|
||||||
|
# alejandra is the configured formatter (flake.nix perSystem.formatter).
|
||||||
|
# Checked per-system so both architectures stay formatted.
|
||||||
|
- name: Formatting check (${{ matrix.system }})
|
||||||
|
run: nix run .#formatter.${{ matrix.system }} -- --check .
|
||||||
Generated
+76
@@ -47,6 +47,26 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"disko": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixos-24-05"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1781152676,
|
||||||
|
"narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "disko",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767039857,
|
"lastModified": 1767039857,
|
||||||
@@ -179,6 +199,22 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixos-24-05": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1735563628,
|
||||||
|
"narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-24.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1777268161,
|
"lastModified": 1777268161,
|
||||||
@@ -195,20 +231,60 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-unstable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1783522502,
|
||||||
|
"narHash": "sha256-iffAls3iaNTyJC2faYcUXSI+Gp02cDjYl+MygxKl2GI=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "0bb7ec54c8483066ec9d7720e780a5caa71f8612",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"agenix": "agenix",
|
"agenix": "agenix",
|
||||||
|
"disko": "disko",
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"helium": "helium",
|
"helium": "helium",
|
||||||
"import-tree": "import-tree",
|
"import-tree": "import-tree",
|
||||||
"nix-index-db": "nix-index-db",
|
"nix-index-db": "nix-index-db",
|
||||||
|
"nixos-24-05": "nixos-24-05",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
|
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||||
|
"sops-nix": "sops-nix",
|
||||||
"systems": "systems_2",
|
"systems": "systems_2",
|
||||||
"zen-browser": "zen-browser"
|
"zen-browser": "zen-browser"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sops-nix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixos-24-05"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1783174389,
|
||||||
|
"narHash": "sha256-aCWC8ngycU7OdJrU2+Je3qf+1a2ykuBvpPhZT/9tXMc=",
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"rev": "f1406619a3884cd5c47992a70b8b35c9c0fcb4c9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "Mic92",
|
||||||
|
"repo": "sops-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
|
|||||||
@@ -67,5 +67,25 @@
|
|||||||
url = "github:Mic92/nix-index-database";
|
url = "github:Mic92/nix-index-database";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# --- Server (hetzner) inputs ---
|
||||||
|
# Pinned to 24.05 to match the deployed Hetzner server exactly.
|
||||||
|
nixos-24-05 = {
|
||||||
|
url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs-unstable = {
|
||||||
|
url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
};
|
||||||
|
|
||||||
|
disko = {
|
||||||
|
url = "github:nix-community/disko";
|
||||||
|
inputs.nixpkgs.follows = "nixos-24-05";
|
||||||
|
};
|
||||||
|
|
||||||
|
sops-nix = {
|
||||||
|
url = "github:Mic92/sops-nix";
|
||||||
|
inputs.nixpkgs.follows = "nixos-24-05";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
username = "someone";
|
|
||||||
in
|
|
||||||
{
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
username = "someone";
|
||||||
|
in {
|
||||||
users.users.${username}.packages = with pkgs; [
|
users.users.${username}.packages = with pkgs; [
|
||||||
neovim
|
neovim
|
||||||
];
|
];
|
||||||
|
|||||||
+10
-8
@@ -8,16 +8,18 @@
|
|||||||
gsettings-desktop-schemas
|
gsettings-desktop-schemas
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.dconf.enable = true;
|
programs.dconf.enable = true;
|
||||||
|
|
||||||
programs.dconf.profiles.user.databases = [{
|
programs.dconf.profiles.user.databases = [
|
||||||
settings = {
|
{
|
||||||
"org/gnome/desktop/interface" = {
|
settings = {
|
||||||
color-scheme = "prefer-dark";
|
"org/gnome/desktop/interface" = {
|
||||||
gtk-application-prefer-dark-theme = true;
|
color-scheme = "prefer-dark";
|
||||||
|
gtk-application-prefer-dark-theme = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}];
|
];
|
||||||
|
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
XDG_ICON_DIR = "${pkgs.whitesur-icon-theme}/share/icons/WhiteSur";
|
XDG_ICON_DIR = "${pkgs.whitesur-icon-theme}/share/icons/WhiteSur";
|
||||||
|
|||||||
@@ -2,13 +2,10 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}: let
|
||||||
|
configFile = "mpv/mpv.conf";
|
||||||
let
|
|
||||||
configFile = "mpv/mpv.conf";
|
|
||||||
mpvInputFile = "mpv/input.conf";
|
mpvInputFile = "mpv/input.conf";
|
||||||
in
|
in {
|
||||||
{
|
|
||||||
users.users.someone.packages = with pkgs; [
|
users.users.someone.packages = with pkgs; [
|
||||||
mpv
|
mpv
|
||||||
mpvScripts.mpris
|
mpvScripts.mpris
|
||||||
@@ -16,12 +13,11 @@ in
|
|||||||
|
|
||||||
xdg.configFile."${configFile}".text =
|
xdg.configFile."${configFile}".text =
|
||||||
lib.generators.toKeyValue {
|
lib.generators.toKeyValue {
|
||||||
mkKeyValue = k: v:
|
mkKeyValue = k: v: "${lib.escapeShellArg k}=${lib.escapeShellArg v}";
|
||||||
"${lib.escapeShellArg k}=${lib.escapeShellArg v}";
|
|
||||||
listsAsDuplicateKeys = true;
|
listsAsDuplicateKeys = true;
|
||||||
} {
|
} {
|
||||||
profile = "gpu-hq";
|
profile = "gpu-hq";
|
||||||
volume = "100";
|
volume = "100";
|
||||||
};
|
};
|
||||||
|
|
||||||
xdg.configFile."${mpvInputFile}".text = ''
|
xdg.configFile."${mpvInputFile}".text = ''
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ in {
|
|||||||
{
|
{
|
||||||
"type" = "ladspa";
|
"type" = "ladspa";
|
||||||
"name" = "rnnoise";
|
"name" = "rnnoise";
|
||||||
"plugin" = "librnnoise_ladspa";
|
"plugin" = "librnnoise_ladspa";
|
||||||
"label" = "noise_suppressor_stereo";
|
"label" = "noise_suppressor_stereo";
|
||||||
"control" = {"VAD Threshold (%)" = 50.0;};
|
"control" = {"VAD Threshold (%)" = 50.0;};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,5 +71,5 @@
|
|||||||
"Mod+Shift+Up".move-column-to-workspace-up = {};
|
"Mod+Shift+Up".move-column-to-workspace-up = {};
|
||||||
"Mod+Shift+Down".move-column-to-workspace-down = {};
|
"Mod+Shift+Down".move-column-to-workspace-down = {};
|
||||||
"Mod+P" = {spawn-sh = "wl-mirror $(niri msg --json focused-output | jq -r .name)";};
|
"Mod+P" = {spawn-sh = "wl-mirror $(niri msg --json focused-output | jq -r .name)";};
|
||||||
# "Mod+Alt".toggle-overview = { repeat=false; };
|
# "Mod+Alt".toggle-overview = { repeat=false; };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ in {
|
|||||||
|
|
||||||
screenshot-path = "~/Pictures/Screenshots/Screenshot-from-%Y-%m-%d-%H-%M-%S.png";
|
screenshot-path = "~/Pictures/Screenshots/Screenshot-from-%Y-%m-%d-%H-%M-%S.png";
|
||||||
|
|
||||||
overview = {
|
overview = {
|
||||||
workspace-shadow.off = {};
|
workspace-shadow.off = {};
|
||||||
backdrop-color = "transparent";
|
backdrop-color = "transparent";
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,40 +7,39 @@
|
|||||||
users.users.someone.packages = [pkgs.ashell];
|
users.users.someone.packages = [pkgs.ashell];
|
||||||
|
|
||||||
xdg.configFile."ashell/config.toml".text = ''
|
xdg.configFile."ashell/config.toml".text = ''
|
||||||
[modules]
|
[modules]
|
||||||
left = [ [ "appLauncher", "Updates", "Workspaces", "ScreenMirror" ], "MediaPlayer" ]
|
left = [ [ "appLauncher", "Updates", "Workspaces", "ScreenMirror" ], "MediaPlayer" ]
|
||||||
center = [ "WindowTitle" ]
|
center = [ "WindowTitle" ]
|
||||||
right = [ "SystemInfo", [ "Tray", "Clock", "Privacy", "Settings" ] ]
|
right = [ "SystemInfo", [ "Tray", "Clock", "Privacy", "Settings" ] ]
|
||||||
|
|
||||||
|
|
||||||
[system_info]
|
[system_info]
|
||||||
indicators = [ "Cpu", "Memory", "Temperature" ]
|
indicators = [ "Cpu", "Memory", "Temperature" ]
|
||||||
|
|
||||||
[system_info.cpu]
|
[system_info.cpu]
|
||||||
warn_threshold = 60
|
warn_threshold = 60
|
||||||
alert_threshold = 80
|
alert_threshold = 80
|
||||||
|
|
||||||
[system_info.memory]
|
[system_info.memory]
|
||||||
warn_threshold = 70
|
warn_threshold = 70
|
||||||
alert_threshold = 85
|
alert_threshold = 85
|
||||||
|
|
||||||
[system_info.temperature]
|
[system_info.temperature]
|
||||||
warn_threshold = 60
|
warn_threshold = 60
|
||||||
alert_threshold = 80
|
alert_threshold = 80
|
||||||
|
|
||||||
[tempo]
|
[tempo]
|
||||||
clock_format = "%a %d %b %R"
|
clock_format = "%a %d %b %R"
|
||||||
weather_location = { City = "Amsterdam" }
|
weather_location = { City = "Amsterdam" }
|
||||||
|
|
||||||
[appearance]
|
[appearance]
|
||||||
style = "Islands"
|
style = "Islands"
|
||||||
|
|
||||||
[[ScreenMirror]]
|
[[ScreenMirror]]
|
||||||
name = "ScreenMirror"
|
name = "ScreenMirror"
|
||||||
icon = ""
|
icon = ""
|
||||||
command = "bash /etc/nixos/scripts/screen-mirror.sh"
|
command = "bash /etc/nixos/scripts/screen-mirror.sh"
|
||||||
|
|
||||||
|
|
||||||
'';
|
'';
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,61 +67,61 @@
|
|||||||
};
|
};
|
||||||
"fish/functions/extract.fish" = {
|
"fish/functions/extract.fish" = {
|
||||||
text = ''
|
text = ''
|
||||||
function extract
|
function extract
|
||||||
if test -f "$argv[1]"
|
if test -f "$argv[1]"
|
||||||
set file "$argv[1]"
|
set file "$argv[1]"
|
||||||
set filename (basename "$file")
|
set filename (basename "$file")
|
||||||
set dirname (string replace -r '\.tar\.bz2$|\.tar\.gz$|\.tbz2$|\.tgz$|\.tar$|\.bz2$|\.gz$|\.zip$|\.Z$|\.7z$|\.xz$|\.rar$' "" "$filename")
|
set dirname (string replace -r '\.tar\.bz2$|\.tar\.gz$|\.tbz2$|\.tgz$|\.tar$|\.bz2$|\.gz$|\.zip$|\.Z$|\.7z$|\.xz$|\.rar$' "" "$filename")
|
||||||
mkdir -p "$dirname"
|
mkdir -p "$dirname"
|
||||||
switch $file
|
switch $file
|
||||||
case "*.tar.bz2"
|
case "*.tar.bz2"
|
||||||
tar xjf "$file" -C "$dirname"
|
tar xjf "$file" -C "$dirname"
|
||||||
case "*.tar.gz"
|
case "*.tar.gz"
|
||||||
tar xzf "$file" -C "$dirname"
|
tar xzf "$file" -C "$dirname"
|
||||||
case "*.tbz2"
|
case "*.tbz2"
|
||||||
tar xjf "$file" -C "$dirname"
|
tar xjf "$file" -C "$dirname"
|
||||||
case "*.tgz"
|
case "*.tgz"
|
||||||
tar xzf "$file" -C "$dirname"
|
tar xzf "$file" -C "$dirname"
|
||||||
case "*.tar"
|
case "*.tar"
|
||||||
tar xf "$file" -C "$dirname"
|
tar xf "$file" -C "$dirname"
|
||||||
case "*.bz2"
|
case "*.bz2"
|
||||||
bunzip2 -c "$file" >"$dirname/$dirname"
|
bunzip2 -c "$file" >"$dirname/$dirname"
|
||||||
case "*.gz"
|
case "*.gz"
|
||||||
gunzip -c "$file" >"$dirname/$dirname"
|
gunzip -c "$file" >"$dirname/$dirname"
|
||||||
case "*.zip"
|
case "*.zip"
|
||||||
unzip "$file" -d "$dirname"
|
unzip "$file" -d "$dirname"
|
||||||
case "*.Z"
|
case "*.Z"
|
||||||
uncompress -c "$file" >"$dirname/$dirname"
|
uncompress -c "$file" >"$dirname/$dirname"
|
||||||
case "*.7z"
|
case "*.7z"
|
||||||
7z x "$file" -o"$dirname"
|
7z x "$file" -o"$dirname"
|
||||||
case "*.xz"
|
case "*.xz"
|
||||||
xz -dc "$file" >"$dirname/$dirname"
|
xz -dc "$file" >"$dirname/$dirname"
|
||||||
case "*.rar"
|
case "*.rar"
|
||||||
unrar x "$file" "$dirname"
|
unrar x "$file" "$dirname"
|
||||||
case "*"
|
case "*"
|
||||||
echo "'$file' cannot be extracted via extract()"
|
echo "'$file' cannot be extracted via extract()"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
echo "'$argv[1]' is not a valid file"
|
echo "'$argv[1]' is not a valid file"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
"fish/functions/weather.fish" = {
|
"fish/functions/weather.fish" = {
|
||||||
text = ''
|
text = ''
|
||||||
function weather
|
function weather
|
||||||
if test "$argv[1]" = week
|
if test "$argv[1]" = week
|
||||||
wthrr -f w $argv[2]
|
wthrr -f w $argv[2]
|
||||||
else if test -z "$argv[1]"
|
else if test -z "$argv[1]"
|
||||||
wthrr -f d
|
wthrr -f d
|
||||||
wthrr -f t
|
wthrr -f t
|
||||||
else
|
else
|
||||||
wthrr -f d $argv[1]
|
wthrr -f d $argv[1]
|
||||||
wthrr -f t $argv[1]
|
wthrr -f t $argv[1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
"fish/functions/fcd.fish" = {
|
"fish/functions/fcd.fish" = {
|
||||||
text = ''
|
text = ''
|
||||||
function fcd
|
function fcd
|
||||||
@@ -168,44 +168,44 @@ end
|
|||||||
};
|
};
|
||||||
"fish/conf.d/aliases.fish" = {
|
"fish/conf.d/aliases.fish" = {
|
||||||
text = ''
|
text = ''
|
||||||
alias cleanup="sudo nix-collect-garbage --delete-older-than 1d"
|
alias cleanup="sudo nix-collect-garbage --delete-older-than 1d"
|
||||||
alias listgen="sudo nix-env -p /nix/var/nix/profiles/system --list-generations"
|
alias listgen="sudo nix-env -p /nix/var/nix/profiles/system --list-generations"
|
||||||
alias nixremove="nix-store --gc"
|
alias nixremove="nix-store --gc"
|
||||||
alias bloat="nix path-info -Sh /run/current-system"
|
alias bloat="nix path-info -Sh /run/current-system"
|
||||||
alias cleanram="sudo sh -c 'sync; echo 3 > /proc/sys/vm/drop_caches'"
|
alias cleanram="sudo sh -c 'sync; echo 3 > /proc/sys/vm/drop_caches'"
|
||||||
alias trimall="sudo fstrim -va"
|
alias trimall="sudo fstrim -va"
|
||||||
alias c="clear"
|
alias c="clear"
|
||||||
alias add="git add ."
|
alias add="git add ."
|
||||||
alias commit="git commit"
|
alias commit="git commit"
|
||||||
alias push="git push"
|
alias push="git push"
|
||||||
alias pull="git pull"
|
alias pull="git pull"
|
||||||
alias diff="git diff --staged"
|
alias diff="git diff --staged"
|
||||||
alias gcld="git clone --depth 1"
|
alias gcld="git clone --depth 1"
|
||||||
alias koji="meteor"
|
alias koji="meteor"
|
||||||
alias gitui="lazygit"
|
alias gitui="lazygit"
|
||||||
alias ls="eza -lah --grid -s modified --smart-group --group-directories-first --icons"
|
alias ls="eza -lah --grid -s modified --smart-group --group-directories-first --icons"
|
||||||
alias l="eza -ah --grid -s modified --smart-group --group-directories-first --icons"
|
alias l="eza -ah --grid -s modified --smart-group --group-directories-first --icons"
|
||||||
alias tree="eza --tree --icons --tree"
|
alias tree="eza --tree --icons --tree"
|
||||||
alias cat="${pkgs.bat}/bin/bat --paging=never --theme gruvbox-dark"
|
alias cat="${pkgs.bat}/bin/bat --paging=never --theme gruvbox-dark"
|
||||||
alias us="systemctl --user"
|
alias us="systemctl --user"
|
||||||
alias rs="sudo systemctl"
|
alias rs="sudo systemctl"
|
||||||
alias zed="zeditor"
|
alias zed="zeditor"
|
||||||
alias nl="nl -ba"
|
alias nl="nl -ba"
|
||||||
alias cp="cp -riv"
|
alias cp="cp -riv"
|
||||||
alias mv="mv -iv"
|
alias mv="mv -iv"
|
||||||
alias mkdir="mkdir -pv"
|
alias mkdir="mkdir -pv"
|
||||||
alias less="bat -p --theme gruvbox-dark"
|
alias less="bat -p --theme gruvbox-dark"
|
||||||
alias myip="curl ip.severijnse.eu"
|
alias myip="curl ip.severijnse.eu"
|
||||||
alias pscpu="ps -eo pid,ppid,cmd,%mem,%cpu,etime --sort=-%cpu | head -n 21"
|
alias pscpu="ps -eo pid,ppid,cmd,%mem,%cpu,etime --sort=-%cpu | head -n 21"
|
||||||
alias psmem="ps -eo pid,ppid,cmd,%mem,%cpu,etime --sort=-%mem | head -n 21"
|
alias psmem="ps -eo pid,ppid,cmd,%mem,%cpu,etime --sort=-%mem | head -n 21"
|
||||||
alias weer="weather"
|
alias weer="weather"
|
||||||
alias v="nvim"
|
alias v="nvim"
|
||||||
alias copy="wl-copy"
|
alias copy="wl-copy"
|
||||||
alias send="croc"
|
alias send="croc"
|
||||||
alias img="loupe"
|
alias img="loupe"
|
||||||
alias cat-md="glow"
|
alias cat-md="glow"
|
||||||
alias du="dust"
|
alias du="dust"
|
||||||
alias df="duf"
|
alias df="duf"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
{ config, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
let
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
configFile = "starship/starship.toml";
|
configFile = "starship/starship.toml";
|
||||||
toTOML = (pkgs.formats.toml {}).generate;
|
toTOML = (pkgs.formats.toml {}).generate;
|
||||||
in
|
in {
|
||||||
{
|
|
||||||
environment.sessionVariables = {
|
environment.sessionVariables = {
|
||||||
STARSHIP_CONFIG = "${config.xdg.configHome}/${configFile}";
|
STARSHIP_CONFIG = "${config.xdg.configHome}/${configFile}";
|
||||||
STARSHIP_LOG = "error";
|
STARSHIP_LOG = "error";
|
||||||
};
|
};
|
||||||
|
|
||||||
users.users.someone.packages = [ pkgs.starship ];
|
users.users.someone.packages = [pkgs.starship];
|
||||||
|
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
"${configFile}".source = toTOML "starship.toml" {
|
"${configFile}".source = toTOML "starship.toml" {
|
||||||
|
|
||||||
"$schema" = "https://starship.rs/config-schema.json";
|
"$schema" = "https://starship.rs/config-schema.json";
|
||||||
|
|
||||||
add_newline = true;
|
add_newline = true;
|
||||||
@@ -137,7 +137,6 @@ in
|
|||||||
starship init fish | source
|
starship init fish | source
|
||||||
'';
|
'';
|
||||||
|
|
||||||
"fish/completions/starship.fish".source =
|
"fish/completions/starship.fish".source = "${pkgs.starship}/share/fish/vendor_completions.d/starship.fish";
|
||||||
"${pkgs.starship}/share/fish/vendor_completions.d/starship.fish";
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
{ pkgs, ... }:
|
{pkgs, ...}: let
|
||||||
let
|
languages = import ./_languages.nix {inherit pkgs;};
|
||||||
languages = import ./_languages.nix { inherit pkgs; };
|
|
||||||
providers = import ./_providers.nix;
|
providers = import ./_providers.nix;
|
||||||
skills = import ./_skills.nix { inherit pkgs; };
|
skills = import ./_skills.nix {inherit pkgs;};
|
||||||
|
|
||||||
inherit (pkgs) opencode;
|
inherit (pkgs) opencode;
|
||||||
|
|
||||||
@@ -23,7 +22,7 @@ let
|
|||||||
'';
|
'';
|
||||||
opencodeWrapped =
|
opencodeWrapped =
|
||||||
pkgs.runCommand "opencode-wrapped" {
|
pkgs.runCommand "opencode-wrapped" {
|
||||||
buildInputs = [ pkgs.makeWrapper ];
|
buildInputs = [pkgs.makeWrapper];
|
||||||
} ''
|
} ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
makeWrapper ${opencodeInitScript} $out/bin/opencode \
|
makeWrapper ${opencodeInitScript} $out/bin/opencode \
|
||||||
@@ -36,110 +35,110 @@ in {
|
|||||||
users.users.someone.packages = [
|
users.users.someone.packages = [
|
||||||
opencodeWrapped
|
opencodeWrapped
|
||||||
];
|
];
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
"${configFile}".text = builtins.toJSON {
|
"${configFile}".text = builtins.toJSON {
|
||||||
"$schema" = "https://opencode.ai/config.json";
|
"$schema" = "https://opencode.ai/config.json";
|
||||||
plugin = [
|
plugin = [
|
||||||
"opencode-antigravity-auth@latest"
|
"opencode-antigravity-auth@latest"
|
||||||
"@tarquinen/opencode-dcp@latest"
|
"@tarquinen/opencode-dcp@latest"
|
||||||
"oh-my-openagent@latest"
|
"oh-my-openagent@latest"
|
||||||
];
|
];
|
||||||
model = "google/antigravity-gemini-3-flash";
|
model = "google/antigravity-gemini-3-flash";
|
||||||
small_model = "opencode/big-pickle";
|
small_model = "opencode/big-pickle";
|
||||||
autoupdate = false;
|
autoupdate = false;
|
||||||
agent = {
|
agent = {
|
||||||
build = { model = "opencode/nemotron-3-super-free"; };
|
build = {model = "opencode/nemotron-3-super-free";};
|
||||||
plan = { model = "opencode/big-pickle"; };
|
plan = {model = "opencode/big-pickle";};
|
||||||
task = { model = "opencode/nemotron-3-super-free"; };
|
task = {model = "opencode/nemotron-3-super-free";};
|
||||||
"sisyphus-junior" = { model = "opencode/nemotron-3-super-free"; };
|
"sisyphus-junior" = {model = "opencode/nemotron-3-super-free";};
|
||||||
explore = { model = "opencode/minimax-m2.5-free"; };
|
explore = {model = "opencode/minimax-m2.5-free";};
|
||||||
general = { model = "opencode/big-pickle"; };
|
general = {model = "opencode/big-pickle";};
|
||||||
oracle = { model = "opencode/nemotron-3-super-free"; };
|
oracle = {model = "opencode/nemotron-3-super-free";};
|
||||||
"ultrabrain" = { model = "opencode/nemotron-3-super-free"; };
|
"ultrabrain" = {model = "opencode/nemotron-3-super-free";};
|
||||||
"deep" = { model = "opencode/nemotron-3-super-free"; };
|
"deep" = {model = "opencode/nemotron-3-super-free";};
|
||||||
"quick" = { model = "opencode/gpt-5-nano"; };
|
"quick" = {model = "opencode/gpt-5-nano";};
|
||||||
"artistry" = { model = "opencode/nemotron-3-super-free"; };
|
"artistry" = {model = "opencode/nemotron-3-super-free";};
|
||||||
"visual-engineering" = { model = "opencode/hy3-preview-free"; };
|
"visual-engineering" = {model = "opencode/hy3-preview-free";};
|
||||||
"writing" = { model = "opencode/hy3-preview-free"; };
|
"writing" = {model = "opencode/hy3-preview-free";};
|
||||||
};
|
|
||||||
share = "disabled";
|
|
||||||
disabled_providers = [
|
|
||||||
"amazon-bedrock"
|
|
||||||
"anthropic"
|
|
||||||
"azure-openai"
|
|
||||||
"azure-cognitive-services"
|
|
||||||
"baseten"
|
|
||||||
"cerebras"
|
|
||||||
"cloudflare-ai-gateway"
|
|
||||||
"cortecs"
|
|
||||||
"deep-infra"
|
|
||||||
"fireworks-ai"
|
|
||||||
"google-vertex-ai"
|
|
||||||
"groq"
|
|
||||||
"hugging-face"
|
|
||||||
"helicone"
|
|
||||||
"llama.cpp"
|
|
||||||
"io-net"
|
|
||||||
"lmstudio"
|
|
||||||
"moonshot-ai"
|
|
||||||
"nebius-token-factory"
|
|
||||||
"ollama"
|
|
||||||
"ollama-cloud"
|
|
||||||
"openai"
|
|
||||||
"sap-ai-core"
|
|
||||||
"ovhcloud-ai-endpoints"
|
|
||||||
"together-ai"
|
|
||||||
"venice-ai"
|
|
||||||
"xai"
|
|
||||||
"zai"
|
|
||||||
"zenmux"
|
|
||||||
];
|
|
||||||
enabled_providers = [ "opencode" "google" "openrouter" "deepseek" "nvidia" "alibaba" "mistral" "cloudflare-workers-ai" ];
|
|
||||||
mcp = {
|
|
||||||
gh_grep = {
|
|
||||||
type = "remote";
|
|
||||||
url = "https://mcp.grep.app/";
|
|
||||||
enabled = true;
|
|
||||||
timeout = 10000;
|
|
||||||
};
|
|
||||||
deepwiki = {
|
|
||||||
type = "remote";
|
|
||||||
url = "https://mcp.deepwiki.com/mcp";
|
|
||||||
enabled = true;
|
|
||||||
timeout = 10000;
|
|
||||||
};
|
|
||||||
context7 = {
|
|
||||||
type = "remote";
|
|
||||||
url = "https://mcp.context7.com/mcp";
|
|
||||||
enabled = true;
|
|
||||||
timeout = 10000;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
inherit (languages) formatter lsp;
|
|
||||||
provider = providers.config;
|
|
||||||
};
|
};
|
||||||
|
share = "disabled";
|
||||||
"opencode/oh-my-openagent.json".text = builtins.toJSON {
|
disabled_providers = [
|
||||||
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/master/assets/oh-my-opencode.schema.json";
|
"amazon-bedrock"
|
||||||
agents = {
|
"anthropic"
|
||||||
"sisyphus-junior" = { model = "opencode/nemotron-3-super-free"; };
|
"azure-openai"
|
||||||
|
"azure-cognitive-services"
|
||||||
|
"baseten"
|
||||||
|
"cerebras"
|
||||||
|
"cloudflare-ai-gateway"
|
||||||
|
"cortecs"
|
||||||
|
"deep-infra"
|
||||||
|
"fireworks-ai"
|
||||||
|
"google-vertex-ai"
|
||||||
|
"groq"
|
||||||
|
"hugging-face"
|
||||||
|
"helicone"
|
||||||
|
"llama.cpp"
|
||||||
|
"io-net"
|
||||||
|
"lmstudio"
|
||||||
|
"moonshot-ai"
|
||||||
|
"nebius-token-factory"
|
||||||
|
"ollama"
|
||||||
|
"ollama-cloud"
|
||||||
|
"openai"
|
||||||
|
"sap-ai-core"
|
||||||
|
"ovhcloud-ai-endpoints"
|
||||||
|
"together-ai"
|
||||||
|
"venice-ai"
|
||||||
|
"xai"
|
||||||
|
"zai"
|
||||||
|
"zenmux"
|
||||||
|
];
|
||||||
|
enabled_providers = ["opencode" "google" "openrouter" "deepseek" "nvidia" "alibaba" "mistral" "cloudflare-workers-ai"];
|
||||||
|
mcp = {
|
||||||
|
gh_grep = {
|
||||||
|
type = "remote";
|
||||||
|
url = "https://mcp.grep.app/";
|
||||||
|
enabled = true;
|
||||||
|
timeout = 10000;
|
||||||
};
|
};
|
||||||
categories = {
|
deepwiki = {
|
||||||
"quick" = { model = "opencode/gpt-5-nano"; };
|
type = "remote";
|
||||||
"ultrabrain" = { model = "opencode/nemotron-3-super-free"; };
|
url = "https://mcp.deepwiki.com/mcp";
|
||||||
"deep" = { model = "opencode/nemotron-3-super-free"; };
|
enabled = true;
|
||||||
"visual-engineering" = { model = "opencode/hy3-preview-free"; };
|
timeout = 10000;
|
||||||
"writing" = { model = "opencode/hy3-preview-free"; };
|
};
|
||||||
"unspecified-low" = { model = "opencode/gpt-5-nano"; };
|
context7 = {
|
||||||
"unspecified-high" = { model = "opencode/nemotron-3-super-free"; };
|
type = "remote";
|
||||||
|
url = "https://mcp.context7.com/mcp";
|
||||||
|
enabled = true;
|
||||||
|
timeout = 10000;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
inherit (languages) formatter lsp;
|
||||||
"${tuiFile}".text = builtins.toJSON {
|
provider = providers.config;
|
||||||
"$schema" = "https://opencode.ai/tui.json";
|
|
||||||
theme = "gruvbox";
|
|
||||||
};
|
|
||||||
|
|
||||||
"opencode/skill".source = skills.skillsSource + "/skill";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"opencode/oh-my-openagent.json".text = builtins.toJSON {
|
||||||
|
"$schema" = "https://raw.githubusercontent.com/code-yeongyu/oh-my-openagent/master/assets/oh-my-opencode.schema.json";
|
||||||
|
agents = {
|
||||||
|
"sisyphus-junior" = {model = "opencode/nemotron-3-super-free";};
|
||||||
|
};
|
||||||
|
categories = {
|
||||||
|
"quick" = {model = "opencode/gpt-5-nano";};
|
||||||
|
"ultrabrain" = {model = "opencode/nemotron-3-super-free";};
|
||||||
|
"deep" = {model = "opencode/nemotron-3-super-free";};
|
||||||
|
"visual-engineering" = {model = "opencode/hy3-preview-free";};
|
||||||
|
"writing" = {model = "opencode/hy3-preview-free";};
|
||||||
|
"unspecified-low" = {model = "opencode/gpt-5-nano";};
|
||||||
|
"unspecified-high" = {model = "opencode/nemotron-3-super-free";};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
"${tuiFile}".text = builtins.toJSON {
|
||||||
|
"$schema" = "https://opencode.ai/tui.json";
|
||||||
|
theme = "gruvbox";
|
||||||
|
};
|
||||||
|
|
||||||
|
"opencode/skill".source = skills.skillsSource + "/skill";
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,38 +3,37 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
users.users.someone.packages = with pkgs;
|
users.users.someone.packages = with pkgs; [
|
||||||
[
|
# archives
|
||||||
# archives
|
zip
|
||||||
zip
|
unzip
|
||||||
unzip
|
unrar
|
||||||
unrar
|
ouch
|
||||||
ouch
|
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
mako
|
mako
|
||||||
libnotify
|
libnotify
|
||||||
fontconfig
|
fontconfig
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
dust
|
dust
|
||||||
duf
|
duf
|
||||||
fd
|
fd
|
||||||
file
|
file
|
||||||
killall
|
killall
|
||||||
jq
|
jq
|
||||||
ps_mem
|
ps_mem
|
||||||
inshellisense
|
inshellisense
|
||||||
|
|
||||||
fum
|
fum
|
||||||
gtt
|
gtt
|
||||||
meteor-git
|
meteor-git
|
||||||
nix-search-tv
|
nix-search-tv
|
||||||
scope-tui
|
scope-tui
|
||||||
tuicam
|
tuicam
|
||||||
wiremix
|
wiremix
|
||||||
zfxtop
|
zfxtop
|
||||||
opencode
|
opencode
|
||||||
loupe
|
loupe
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-2
@@ -5,6 +5,9 @@
|
|||||||
}: let
|
}: let
|
||||||
# shorten paths
|
# shorten paths
|
||||||
inherit (inputs.nixpkgs.lib) nixosSystem;
|
inherit (inputs.nixpkgs.lib) nixosSystem;
|
||||||
|
# Server uses its own pinned 24.05 nixpkgs (kept isolated from the laptop's unstable)
|
||||||
|
nixosSystem24 = inputs.nixos-24-05.lib.nixosSystem;
|
||||||
|
unstablePkgs = import inputs.nixpkgs-unstable {system = "x86_64-linux";};
|
||||||
mod = "${self}/system";
|
mod = "${self}/system";
|
||||||
home = "${self}/home";
|
home = "${self}/home";
|
||||||
|
|
||||||
@@ -39,8 +42,27 @@ in {
|
|||||||
# Laptop: laptop with GUI + battery + bluetooth
|
# Laptop: laptop with GUI + battery + bluetooth
|
||||||
laptop = nixosSystem {
|
laptop = nixosSystem {
|
||||||
inherit specialArgs;
|
inherit specialArgs;
|
||||||
modules = laptop ++ sharedModules ++ [
|
modules =
|
||||||
"${mod}/services/location.nix"
|
laptop
|
||||||
|
++ sharedModules
|
||||||
|
++ [
|
||||||
|
"${mod}/services/location.nix"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Server: severijnse.eu (Hetzner) — fully isolated under servers/hetzner/.
|
||||||
|
# Uses nixos-24.05 + disko + sops-nix and does NOT inherit the laptop's shared modules.
|
||||||
|
hetzner = nixosSystem24 {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
specialArgs = {
|
||||||
|
inherit inputs self;
|
||||||
|
unstablePkgs = unstablePkgs;
|
||||||
|
};
|
||||||
|
modules = [
|
||||||
|
inputs.disko.nixosModules.disko
|
||||||
|
inputs.sops-nix.nixosModules.sops
|
||||||
|
"${self}/servers/hetzner/hosts/hetzner/hardware-configuration.nix"
|
||||||
|
"${self}/servers/hetzner/hosts/hetzner/default.nix"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
keys:
|
||||||
|
- &admin age1yd59qp5km4cxt99rlfjehnsucrjn9lmj0su4h3avhf6vrtjvnyjqstldl5
|
||||||
|
- &local age15rhqdpwejyf3r6ww70qgv6hqmkpsqraakn26kc49wlauhaceaeqsmuwrdd
|
||||||
|
- &server age1xekdrkjfu82hkxltydm72tllzgayyvfavvudeks3xjuujm5wt5hq6g55v0
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: secrets/.*\.yaml
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *admin
|
||||||
|
- *local
|
||||||
|
- *server
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Deploy NixOS to a Hetzner VPS using nixos-anywhere
|
||||||
|
# Usage: ./deploy.sh [user@host]
|
||||||
|
#
|
||||||
|
# IMPORTANT: Run this from a SEPARATE machine with Nix installed
|
||||||
|
# (laptop, another VPS, etc.), NOT from the target VPS itself.
|
||||||
|
# nixos-anywhere uses kexec to reboot the target; you can't reboot
|
||||||
|
# the machine you're running on.
|
||||||
|
#
|
||||||
|
# Steps:
|
||||||
|
# 1. git clone <this-repo> && cd nixos-config
|
||||||
|
# 2. Add your SSH pubkey to ./hosts/hetzner/users.nix
|
||||||
|
# 3. ./deploy.sh root@<vps-ip>
|
||||||
|
#
|
||||||
|
# This wipes the target disk and installs NixOS fresh.
|
||||||
|
|
||||||
|
HOST=${1:-root@localhost}
|
||||||
|
|
||||||
|
echo "=== Deploying NixOS to $HOST ==="
|
||||||
|
echo "WARNING: This will WIPE the target disk!"
|
||||||
|
read -rp "Continue? [y/N] " confirm
|
||||||
|
[[ "$confirm" =~ ^[Yy]$ ]] || exit 1
|
||||||
|
|
||||||
|
nix run github:nix-community/nixos-anywhere -- \
|
||||||
|
--generate-hardware-config nixos-generate-config ./hosts/hetzner/hardware-configuration.nix \
|
||||||
|
--flake ".#hetzner" "$HOST"
|
||||||
|
|
||||||
|
# After deploy, the generated hw config MUST be imported to flake.nix
|
||||||
|
echo ""
|
||||||
|
echo "=== CRITICAL: Post-deploy steps! ==="
|
||||||
|
echo "1. Import the generated hw config into flake.nix:"
|
||||||
|
echo " git add hosts/hetzner/hardware-configuration.nix"
|
||||||
|
echo " # In flake.nix, add to modules array:"
|
||||||
|
echo " ./hosts/hetzner/hardware-configuration.nix"
|
||||||
|
echo ""
|
||||||
|
echo "2. Copy the age key to the new system for sops-nix:"
|
||||||
|
echo " # From the deploy machine:"
|
||||||
|
echo " ssh root@<new-ip> 'mkdir -p /etc/age'"
|
||||||
|
echo " scp /home/admin/age/keys.txt root@<new-ip>:/etc/age/keys.txt"
|
||||||
|
echo ""
|
||||||
|
echo "3. IMPORTANT: The old gitea_db Docker Postgres needs migration."
|
||||||
|
echo " The pg_dump is at /tmp/gitea-db-dump-YYYY-MM-DD.sql.gz"
|
||||||
|
echo " Restore with:"
|
||||||
|
echo " sudo -u postgres psql -c \"CREATE DATABASE gitea;\""
|
||||||
|
echo " sudo -u postgres psql -c \"CREATE USER gitea WITH PASSWORD 'gitea';\""
|
||||||
|
echo " sudo -u postgres psql -c \"GRANT ALL PRIVILEGES ON DATABASE gitea TO gitea;\""
|
||||||
|
echo " zcat /tmp/gitea-db-dump-YYYY-MM-DD.sql.gz | sudo -u postgres psql gitea"
|
||||||
|
echo ""
|
||||||
|
echo "4. Restore Caddy certs for the mailserver:"
|
||||||
|
echo " # The old Debian Caddy certs were backed up at /home/admin/backups/caddy-certs-mail.tar.gz"
|
||||||
|
echo " # On NixOS Caddy stores at /var/lib/caddy/certificates/..."
|
||||||
|
echo ""
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
imports = [
|
||||||
|
./networking.nix
|
||||||
|
./users.nix
|
||||||
|
./hardware.nix
|
||||||
|
./disko-config.nix
|
||||||
|
../../modules/system/env.nix
|
||||||
|
../../modules/security/acme.nix
|
||||||
|
../../modules/services/caddy.nix
|
||||||
|
../../modules/services/coredns.nix
|
||||||
|
../../modules/services/gitea.nix
|
||||||
|
../../modules/services/wireguard.nix
|
||||||
|
../../modules/services/fail2ban.nix
|
||||||
|
../../modules/services/vaultwarden.nix
|
||||||
|
../../modules/services/mailserver.nix
|
||||||
|
../../modules/services/snappymail.nix
|
||||||
|
../../modules/services/rustdesk.nix
|
||||||
|
../../modules/services/wrxproxy.nix
|
||||||
|
../../modules/services/watchtower.nix
|
||||||
|
../../modules/services/tlsa-updater.nix
|
||||||
|
../../modules/services/shkeeper.nix
|
||||||
|
../../modules/services/backup.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
system.stateVersion = "24.05";
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{lib, ...}: {
|
||||||
|
disko.devices = {
|
||||||
|
disk.disk1 = {
|
||||||
|
device = lib.mkDefault "/dev/sda";
|
||||||
|
type = "disk";
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
boot = {
|
||||||
|
name = "boot";
|
||||||
|
size = "1M";
|
||||||
|
type = "EF02";
|
||||||
|
};
|
||||||
|
esp = {
|
||||||
|
name = "ESP";
|
||||||
|
size = "256M";
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot/efi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
root = {
|
||||||
|
name = "root";
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Zone file for severijnse.eu
|
||||||
|
# This is the authoritative DNS zone served by CoreDNS
|
||||||
|
# Update serial number on changes
|
||||||
|
{
|
||||||
|
serial = "2026071003";
|
||||||
|
adminEmail = "abuse.severijnse.eu";
|
||||||
|
nameservers = ["ns1.severijnse.eu" "ns2.severijnse.eu"];
|
||||||
|
ipv4 = "49.13.92.205";
|
||||||
|
ipv6 = "2a01:4f8:c014:2585::1";
|
||||||
|
mailIpv4 = "49.13.92.205";
|
||||||
|
mailIpv6 = "2a01:4f8:c014:2585::1";
|
||||||
|
dkimRecord = ''
|
||||||
|
v=DKIM1; k=rsa;
|
||||||
|
p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAskpG7m4kninxRE4JF5KzpnBhLbOlGJL2RO/iDfzdz6sHEvxe78q9c5UnZ0OQddOSuQo4q48dJkXR/XzqY7Ak109lhoAx+Kr1neYsi8/
|
||||||
|
JaoTC8OURk365+/aBSmWXUCCBphCx43QWfC9h8GMQ6PUIqawkz5CcGPT7X7hPdwHQcd5Vn3CqmABptxdwshdkBjZs
|
||||||
|
oi79BOo9ZrQSTY7iiLcOP7hVVC9Ad+ydlZ4MWGfy5BxgyTGrrtuSuLcM219oqdovIvr2EtXs8AMx5fyXplKE3R/
|
||||||
|
YlwF2Jcy50Gmb5y/E9pOaFjVv8HXUmKsvuhA2b8K+rt0WVHNc3dvbgZUl8bGAQIDAQAB
|
||||||
|
'';
|
||||||
|
dnssecKeyTag = "20930";
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||||
|
# and may be overwritten by future invocations. Please make changes
|
||||||
|
# to /etc/nixos/configuration.nix instead.
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
modulesPath,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
imports = [
|
||||||
|
(modulesPath + "/profiles/qemu-guest.nix")
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = ["ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod"];
|
||||||
|
boot.initrd.kernelModules = [];
|
||||||
|
boot.kernelModules = [];
|
||||||
|
boot.extraModulePackages = [];
|
||||||
|
|
||||||
|
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
boot = {
|
||||||
|
loader = {
|
||||||
|
grub = {
|
||||||
|
enable = true;
|
||||||
|
device = "/dev/sda";
|
||||||
|
efiSupport = true;
|
||||||
|
efiInstallAsRemovable = true;
|
||||||
|
};
|
||||||
|
efi = {
|
||||||
|
efiSysMountPoint = "/boot/efi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
initrd.availableKernelModules = ["ata_piix" "virtio_pci" "virtio_scsi" "virtio_blk"];
|
||||||
|
};
|
||||||
|
|
||||||
|
swapDevices = [
|
||||||
|
{
|
||||||
|
device = "/swap";
|
||||||
|
size = 2048;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Enable Podman OCI container support
|
||||||
|
virtualisation = {
|
||||||
|
podman = {
|
||||||
|
enable = true;
|
||||||
|
dockerCompat = true;
|
||||||
|
defaultNetwork.settings = {
|
||||||
|
dns_enabled = true;
|
||||||
|
ipv6_enabled = true;
|
||||||
|
subnets = [
|
||||||
|
{
|
||||||
|
subnet = "10.88.0.0/16";
|
||||||
|
gateway = "10.88.0.1";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
subnet = "fd00:dead:beef::/48";
|
||||||
|
gateway = "fd00:dead:beef::1";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
oci-containers.backend = "podman";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
networking = {
|
||||||
|
hostName = "debian-4gb-fsn1-1";
|
||||||
|
domain = "severijnse.eu";
|
||||||
|
useDHCP = true;
|
||||||
|
dhcpcd.enable = true;
|
||||||
|
nameservers = [
|
||||||
|
"2a01:4ff:ff00::add:2"
|
||||||
|
"2a01:4ff:ff00::add:1"
|
||||||
|
"185.12.64.2"
|
||||||
|
];
|
||||||
|
search = ["severijnse.eu"];
|
||||||
|
interfaces."enp1s0" = {
|
||||||
|
ipv6.addresses = [
|
||||||
|
{
|
||||||
|
address = "2a01:4f8:c014:2585::1";
|
||||||
|
prefixLength = 64;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
ipv6.routes = [
|
||||||
|
{
|
||||||
|
address = "::";
|
||||||
|
prefixLength = 0;
|
||||||
|
via = "fe80::1";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
firewall = {
|
||||||
|
enable = true;
|
||||||
|
allowedTCPPorts = [
|
||||||
|
22 # SSH
|
||||||
|
53 # DNS (CoreDNS)
|
||||||
|
80 # HTTP (Caddy)
|
||||||
|
443 # HTTPS (Caddy)
|
||||||
|
465 # SMTP over TLS
|
||||||
|
587 # SMTP (STARTTLS)
|
||||||
|
993 # IMAP over TLS
|
||||||
|
143 # IMAP
|
||||||
|
25 # SMTP
|
||||||
|
222 # Gitea SSH
|
||||||
|
51821 # WG-Easy web UI
|
||||||
|
];
|
||||||
|
allowedUDPPorts = [
|
||||||
|
53 # DNS
|
||||||
|
51820 # WireGuard
|
||||||
|
];
|
||||||
|
};
|
||||||
|
nat = {
|
||||||
|
enable = true;
|
||||||
|
externalInterface = "enp1s0";
|
||||||
|
internalInterfaces = ["wg0"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.kernel.sysctl = {
|
||||||
|
"net.ipv4.ip_forward" = 1;
|
||||||
|
"net.ipv4.conf.all.src_valid_mark" = 1;
|
||||||
|
"net.ipv6.conf.all.forwarding" = 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
users.users = {
|
||||||
|
root = {
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYboWHsP50CXzMpz4FogC3ecFchjZARCdY4wSTc/Et0 someone@archlinux"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKAlpdPnqihMxE6XPBUQ9Kb6MrvWUWw/BYx6kf2kTPD6 admin@severijnse.eu"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
admin = {
|
||||||
|
isNormalUser = true;
|
||||||
|
uid = 1000;
|
||||||
|
description = "Jory";
|
||||||
|
extraGroups = ["wheel" "docker" "podman"];
|
||||||
|
openssh.authorizedKeys.keys = [
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGYboWHsP50CXzMpz4FogC3ecFchjZARCdY4wSTc/Et0 someone@archlinux"
|
||||||
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKAlpdPnqihMxE6XPBUQ9Kb6MrvWUWw/BYx6kf2kTPD6 admin@severijnse.eu"
|
||||||
|
];
|
||||||
|
shell = pkgs.fish;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
PermitRootLogin = "prohibit-password";
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
PubkeyAuthentication = true;
|
||||||
|
};
|
||||||
|
hostKeys = [
|
||||||
|
{
|
||||||
|
path = "/etc/ssh/ssh_host_ed25519_key";
|
||||||
|
type = "ed25519";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
# NOTE: Caddy handles all TLS natively via its ACME integration.
|
||||||
|
# This module is kept as a fallback for non-Caddy services.
|
||||||
|
# Currently NOT imported in default.nix — uncomment there to activate.
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults = {
|
||||||
|
email = "jory@severijnse.eu";
|
||||||
|
group = "caddy";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
backupScript = pkgs.writeShellScript "weekly-backup" ''
|
||||||
|
BACKUP_DIR="/home/admin/backups"
|
||||||
|
SRC="/home/admin"
|
||||||
|
DATE=$(date +%Y-%m-%dT%H-%M-%S)
|
||||||
|
FILENAME="weekly-backup-$DATE.tar.gz"
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
# Backup everything under /home/admin EXCEPT:
|
||||||
|
# - The backups dir itself (infinite loop)
|
||||||
|
# - DMS mail data (GBs of email, backed up separately)
|
||||||
|
# - NixOS-managed service data (at their own paths below)
|
||||||
|
tar czf "$BACKUP_DIR/$FILENAME" \
|
||||||
|
--exclude="$BACKUP_DIR" \
|
||||||
|
--exclude="/home/admin/backups" \
|
||||||
|
--exclude="/home/admin/dms/mail-data" \
|
||||||
|
--exclude="/home/admin/dms/mail-state" \
|
||||||
|
"$SRC"
|
||||||
|
|
||||||
|
# Prune backups older than 14 days
|
||||||
|
find "$BACKUP_DIR" -name "weekly-backup-*" -mtime +14 -delete
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
systemd.services.weekly-backup = {
|
||||||
|
description = "Weekly backup of home directory";
|
||||||
|
path = with pkgs; [coreutils gnutar findutils];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${backupScript}";
|
||||||
|
User = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.timers.weekly-backup = {
|
||||||
|
wantedBy = ["timers.target"];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "Mon *-*-* 03:00:00";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
domain = "severijnse.eu";
|
||||||
|
antiScrape = ''
|
||||||
|
@bad_bot {
|
||||||
|
header_regexp User-Agent "(?i)(scrapy|cpython-requests|python-requests|curl|wget|go-http-client|ltx71|petalbot|bytespider|dotbot|ahrefsbot|semrushbot|mj12bot|dataforseo|facebookexternalhit|claudebot|anthropic-ai|perplexity|gptbot|chatgpt-user|omnisci|imgproxy|ccbot|exabot|360spider|baiduspider|sogou|duckduckgo|amazonbot|cohere-ai|diffbot|imagesiftbot).*"
|
||||||
|
}
|
||||||
|
respond @bad_bot "" 444
|
||||||
|
header {
|
||||||
|
X-Robots-Tag "noindex, nofollow, noai, noimageai"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
group = "caddy";
|
||||||
|
dataDir = "/var/lib/caddy";
|
||||||
|
logDir = "/var/log/caddy";
|
||||||
|
globalConfig = ''
|
||||||
|
email jory@severijnse.eu
|
||||||
|
servers {
|
||||||
|
trusted_proxies static private_ranges
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
# Global Caddyfile snippets (shared across all virtual hosts).
|
||||||
|
extraConfig = ''
|
||||||
|
(admin_gate) {
|
||||||
|
@notvpn not remote_ip 10.8.0.0/24
|
||||||
|
respond @notvpn "Forbidden" 403
|
||||||
|
}
|
||||||
|
# Security headers applied to every response of every site that
|
||||||
|
# imports this snippet (covers all current and future hosts).
|
||||||
|
# For proxied hosts whose upstream sets its own copies, strip them
|
||||||
|
# with `header_down` inside the reverse_proxy block instead.
|
||||||
|
(security_headers) {
|
||||||
|
header {
|
||||||
|
X-Content-Type-Options "nosniff"
|
||||||
|
X-XSS-Protection "0"
|
||||||
|
X-Frame-Options "SAMEORIGIN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(csp) {
|
||||||
|
header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; connect-src 'self' wss: ws:"
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
virtualHosts = {
|
||||||
|
"severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
@logo path /logo.svg
|
||||||
|
handle @logo {
|
||||||
|
root * /srv
|
||||||
|
file_server
|
||||||
|
header Content-Type image/svg+xml
|
||||||
|
header Cache-Control "public, immutable, max-age=31536000"
|
||||||
|
header X-Content-Type-Options nosniff
|
||||||
|
}
|
||||||
|
handle {
|
||||||
|
redir https://jory.severijnse.eu{uri} permanent
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"www.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
redir https://jory.severijnse.eu{uri} permanent
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"jory.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
root * /srv/jory
|
||||||
|
file_server
|
||||||
|
try_files {path} /index.html
|
||||||
|
encode zstd gzip
|
||||||
|
header Strict-Transport-Security "max-age=31536000;"
|
||||||
|
@robots path /robots.txt
|
||||||
|
handle @robots {
|
||||||
|
header Content-Type text/plain
|
||||||
|
respond `User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Googlebot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Bingbot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: Twitterbot
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: facebookexternalhit
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
User-agent: GPTBot
|
||||||
|
User-agent: ChatGPT-User
|
||||||
|
User-agent: OAI-SearchBot
|
||||||
|
User-agent: ClaudeBot
|
||||||
|
User-agent: Claude-Web
|
||||||
|
User-agent: anthropic-ai
|
||||||
|
User-agent: PerplexityBot
|
||||||
|
User-agent: Bytespider
|
||||||
|
User-agent: Amazonbot
|
||||||
|
User-agent: CCBot
|
||||||
|
User-agent: Google-Extended
|
||||||
|
User-agent: Applebot-Extended
|
||||||
|
Disallow: /
|
||||||
|
` 200
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"mta-sts.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
root * /srv
|
||||||
|
file_server
|
||||||
|
header Content-Type text/plain
|
||||||
|
header Cache-Control "public, max-age=300"
|
||||||
|
header X-Content-Type-Options nosniff
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"vault.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
import admin_gate
|
||||||
|
header Strict-Transport-Security "max-age=31536000;"
|
||||||
|
reverse_proxy 127.0.0.1:1001
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"git.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
reverse_proxy 127.0.0.1:3000
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"mail.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
${antiScrape}
|
||||||
|
reverse_proxy 127.0.0.1:8888 {
|
||||||
|
# Strip copies set by the upstream SnappyMail container so we
|
||||||
|
# emit exactly one correct value of each security header.
|
||||||
|
header_down -X-Frame-Options
|
||||||
|
header_down -X-XSS-Protection
|
||||||
|
header_down -X-Content-Type-Options
|
||||||
|
}
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"vpn.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
reverse_proxy 127.0.0.1:51821
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"mine.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
reverse_proxy 127.0.0.1:81
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"music.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
reverse_proxy 127.0.0.1:4321
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"fail2ban.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
import admin_gate
|
||||||
|
reverse_proxy 127.0.0.1:8080
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"automate.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
import admin_gate
|
||||||
|
reverse_proxy 127.0.0.1:5678
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"pay.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
${antiScrape}
|
||||||
|
import admin_gate
|
||||||
|
reverse_proxy 127.0.0.1:5000
|
||||||
|
encode zstd gzip
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
"http://ip.severijnse.eu" = {
|
||||||
|
extraConfig = ''
|
||||||
|
import security_headers
|
||||||
|
import csp
|
||||||
|
header Content-Type text/plain
|
||||||
|
respond {client_ip} 200
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /srv 0755 caddy caddy -"
|
||||||
|
"d /srv/jory 0755 caddy caddy -"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
zoneFile = pkgs.writeText "severijnse.eu.db" ''
|
||||||
|
$ORIGIN severijnse.eu.
|
||||||
|
$TTL 3600
|
||||||
|
severijnse.eu. 3600 IN SOA ns1.severijnse.eu. abuse.severijnse.eu. 2026071003 3600 1800 1209600 86400
|
||||||
|
IN NS ns1.severijnse.eu.
|
||||||
|
IN NS ns2.severijnse.eu.
|
||||||
|
|
||||||
|
@ IN A 49.13.92.205
|
||||||
|
www IN A 49.13.92.205
|
||||||
|
ns1 IN A 49.13.92.205
|
||||||
|
ns2 IN A 49.13.92.205
|
||||||
|
mail IN A 49.13.92.205
|
||||||
|
|
||||||
|
@ IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
www IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
ns1 IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
ns2 IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
mail IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
|
||||||
|
*.severijnse.eu. IN A 49.13.92.205
|
||||||
|
*.severijnse.eu. IN AAAA 2a01:4f8:c014:2585::1
|
||||||
|
|
||||||
|
@ IN MX 10 mail.severijnse.eu.
|
||||||
|
|
||||||
|
mail._domainkey.severijnse.eu. 300 IN TXT (
|
||||||
|
"v=DKIM1; k=rsa; "
|
||||||
|
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAskpG7m4kninxRE4JF5KzpnBhLbOlGJL2RO/iDfzdz6sHEvxe78q9c5UnZ0OQddOSuQo4q48dJkXR/XzqY7Ak109lhoAx+Kr1neYsi8/"
|
||||||
|
"JaoTC8OURk365+/aBSmWXUCCBphCx43QWfC9h8GMQ6PUIqawkz5CcGPT7X7hPdwHQcd5Vn3CqmABptxdwshdkBjZs"
|
||||||
|
"oi79BOo9ZrQSTY7iiLcOP7hVVC9Ad+ydlZ4MWGfy5BxgyTGrrtuSuLcM219oqdovIvr2EtXs8AMx5fyXplKE3R/"
|
||||||
|
"YlwF2Jcy50Gmb5y/E9pOaFjVv8HXUmKsvuhA2b8K+rt0WVHNc3dvbgZUl8bGAQIDAQAB"
|
||||||
|
)
|
||||||
|
_dmarc.severijnse.eu. IN TXT "v=DMARC1; p=reject; rua=mailto:abuse@severijnse.eu"
|
||||||
|
severijnse.eu. IN TXT "v=spf1 mx ip4:49.13.92.205 -all"
|
||||||
|
|
||||||
|
default._bimi.severijnse.eu. IN TXT "v=BIMI1; l=https://severijnse.eu/logo.svg; avp=personal;"
|
||||||
|
|
||||||
|
severijnse.eu. IN CAA 0 issue "letsencrypt.org"
|
||||||
|
severijnse.eu. IN CAA 0 issuewild "letsencrypt.org"
|
||||||
|
severijnse.eu. IN CAA 0 iodef "mailto:abuse@severijnse.eu"
|
||||||
|
|
||||||
|
_smtp._tls.severijnse.eu. IN TXT "v=TLSRPTv1; rua=mailto:abuse@severijnse.eu"
|
||||||
|
_mta-sts.severijnse.eu. IN TXT "v=STSv1; id=2024120501"
|
||||||
|
|
||||||
|
severijnse.eu. 300 IN TXT "google-site-verification=H0HHB7zNQ10uom1zH5f8CEtHcVVcWiuu41ZQv348T5U"
|
||||||
|
|
||||||
|
; TLSA records updated dynamically by mail-cert-sync service.
|
||||||
|
; The placeholders below mirror the current live certificate so the zone is
|
||||||
|
; correct even if the sync service has not yet run (e.g. a failed boot).
|
||||||
|
_25._tcp.mail.severijnse.eu. 3600 IN TLSA 3 1 1 15ec4d8823874c8363af004188338f76e6e6c5878faf25cdf40556b44b26677d
|
||||||
|
_465._tcp.mail.severijnse.eu. 3600 IN TLSA 3 1 1 15ec4d8823874c8363af004188338f76e6e6c5878faf25cdf40556b44b26677d
|
||||||
|
_993._tcp.mail.severijnse.eu. 3600 IN TLSA 3 1 1 15ec4d8823874c8363af004188338f76e6e6c5878faf25cdf40556b44b26677d
|
||||||
|
|
||||||
|
severijnse.eu. IN DS 20930 13 2 B0D9B13DCE5FA0D41589239EB5166D124B0C9D3060A538726DDCCBFC91E8DBD8
|
||||||
|
|
||||||
|
@ IN DNSKEY 257 3 13 kOc88RGHKdWa7YLjNs7mljux7cT9/9wVNgcp+8jaVe6zle4cHAk6+Sub9wKEVa7Q4FlQYzS1KFL2HOW05Azq1A==
|
||||||
|
@ IN DNSKEY 256 3 13 QTFplRlXes5NExKLvuCJmX0l8FhulFNS+sJw+pvcAq4+0T3cCzT6hmcJPjd4BVl6KvvyS78Vij2f7HjrcjyHfw==
|
||||||
|
@ IN CDS 20930 13 2 B0D9B13DCE5FA0D41589239EB5166D124B0C9D3060A538726DDCCBFC91E8DBD8
|
||||||
|
@ IN CDNSKEY 257 3 13 kOc88RGHKdWa7YLjNs7mljux7cT9/9wVNgcp+8jaVe6zle4cHAk6+Sub9wKEVa7Q4FlQYzS1KFL2HOW05Azq1A==
|
||||||
|
|
||||||
|
severijnse.eu IN SSHFP 1 1 7f5235b2997e0c621fe773acaaae45b9551049ce
|
||||||
|
severijnse.eu IN SSHFP 1 2 2ec1d37df094915253c0b059762052ae19e66cd97e82d7a58ac1a0d1bd5d5e52
|
||||||
|
severijnse.eu IN SSHFP 3 1 240418eb7cc2a3969257c30363d16103dbfd5822
|
||||||
|
severijnse.eu IN SSHFP 3 2 43dbfdd8b131efda4c98844e1434e4f35e773f472bdb355ede94f8a9f7001c35
|
||||||
|
severijnse.eu IN SSHFP 4 1 efbd7836208684d110f3a72543eba74ad8e54b44
|
||||||
|
severijnse.eu IN SSHFP 4 2 c02f4b13aef78579f3466851fcc741c0169eaa63237463ceacc9bb72a2be0519
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
# Decrypt DNSSEC keys from sops-encrypted file using the age key at /etc/age/keys.txt
|
||||||
|
# Uses sops CLI directly instead of sops-nix's sops-install-secrets (avoids Go 1.25 build dep)
|
||||||
|
systemd.services.decrypt-coredns-keys = {
|
||||||
|
description = "Decrypt CoreDNS DNSSEC signing keys";
|
||||||
|
before = ["coredns.service"];
|
||||||
|
wantedBy = ["coredns.service"];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
Environment = "SOPS_AGE_KEY_FILE=/etc/age/keys.txt";
|
||||||
|
};
|
||||||
|
script = ''
|
||||||
|
SOPS_FILE=${../../secrets/coredns-keys.yaml}
|
||||||
|
KEYS_DIR=/var/lib/coredns/keys
|
||||||
|
mkdir -p "$KEYS_DIR"
|
||||||
|
|
||||||
|
${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.key"
|
||||||
|
${pkgs.sops}/bin/sops --decrypt --extract '["coredns_ksk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+20930.private"
|
||||||
|
${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_key"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.key"
|
||||||
|
${pkgs.sops}/bin/sops --decrypt --extract '["coredns_zsk_private"]' "$SOPS_FILE" > "$KEYS_DIR/Kseverijnse.eu.+013+38678.private"
|
||||||
|
|
||||||
|
chmod 644 "$KEYS_DIR/"*
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure coredns waits for key decryption
|
||||||
|
systemd.services.coredns = {
|
||||||
|
after = ["decrypt-coredns-keys.service"];
|
||||||
|
requires = ["decrypt-coredns-keys.service"];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.coredns = {
|
||||||
|
enable = true;
|
||||||
|
config = ''
|
||||||
|
severijnse.eu {
|
||||||
|
bind 127.0.0.1 49.13.92.205 2a01:4f8:c014:2585::1
|
||||||
|
file /var/lib/coredns/zones/severijnse.eu.db {
|
||||||
|
reload 300s
|
||||||
|
}
|
||||||
|
dnssec {
|
||||||
|
key file /var/lib/coredns/keys/Kseverijnse.eu.+013+38678
|
||||||
|
key file /var/lib/coredns/keys/Kseverijnse.eu.+013+20930
|
||||||
|
}
|
||||||
|
log
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
|
||||||
|
. {
|
||||||
|
bind 127.0.0.1
|
||||||
|
forward . 1.1.1.1 8.8.8.8
|
||||||
|
log
|
||||||
|
errors
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# Copy zone file from Nix store to writable location on service start
|
||||||
|
# TLSA updater will modify the writable copy at runtime
|
||||||
|
systemd.services.coredns = {
|
||||||
|
preStart = ''
|
||||||
|
cp -f ${zoneFile} /var/lib/coredns/zones/severijnse.eu.db
|
||||||
|
chown coredns:coredns /var/lib/coredns/zones/severijnse.eu.db
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/lib/coredns 0750 coredns coredns -"
|
||||||
|
"d /var/lib/coredns/zones 0750 coredns coredns -"
|
||||||
|
"d /var/lib/coredns/keys 0750 coredns coredns -"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
# Keep fail2ban as OCI container to preserve the web UI
|
||||||
|
virtualisation.oci-containers.containers.fail2ban = {
|
||||||
|
image = "crazymax/fail2ban:latest";
|
||||||
|
autoStart = true;
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/dms/mail-logs:/var/log/mail:ro"
|
||||||
|
"/home/admin/fail2ban/data:/data:Z"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
TZ = "Europe/Amsterdam";
|
||||||
|
};
|
||||||
|
extraOptions = [
|
||||||
|
"--network=host"
|
||||||
|
"--cap-add=NET_ADMIN"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /var/log/mail 0755 root root -"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
unstablePkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.postgresql_14;
|
||||||
|
ensureDatabases = ["gitea"];
|
||||||
|
ensureUsers = [
|
||||||
|
{
|
||||||
|
name = "gitea";
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Gitea connects to local Postgres via Unix socket (peer auth).
|
||||||
|
# No password needed — the socket is at /run/postgresql by default.
|
||||||
|
# createDatabase = true ensures the DB + user are set up automatically.
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
package = unstablePkgs.gitea;
|
||||||
|
database.type = "postgres";
|
||||||
|
database.name = "gitea";
|
||||||
|
database.user = "gitea";
|
||||||
|
appName = "Jory's Git";
|
||||||
|
lfs.enable = true;
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
DOMAIN = "git.severijnse.eu";
|
||||||
|
ROOT_URL = "https://git.severijnse.eu/";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
SSH_PORT = 222;
|
||||||
|
SSH_LISTEN_PORT = 2222;
|
||||||
|
START_SSH_SERVER = true;
|
||||||
|
SSH_USER = "git";
|
||||||
|
BUILTIN_SSH_SERVER_USER = "git";
|
||||||
|
LANDING_PAGE = "explore";
|
||||||
|
};
|
||||||
|
service = {
|
||||||
|
DISABLE_REGISTRATION = true;
|
||||||
|
REQUIRE_SIGNIN_VIEW = false;
|
||||||
|
};
|
||||||
|
repository = {
|
||||||
|
DEFAULT_BRANCH = "main";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Gitea built-in SSH server: listens on high port 2222 (no privileged-cap needed),
|
||||||
|
# while clone URLs advertise port 222. Firewall redirects 222 -> 2222.
|
||||||
|
networking.firewall.allowedTCPPorts = [222 2222];
|
||||||
|
|
||||||
|
# Redirect external git SSH (222) to Gitea's internal listener (2222)
|
||||||
|
networking.firewall.extraCommands = ''
|
||||||
|
${pkgs.nftables}/bin/nft add table inet gitea-redirect 2>/dev/null || true
|
||||||
|
${pkgs.nftables}/bin/nft flush chain inet gitea-redirect prerouting 2>/dev/null || true
|
||||||
|
${pkgs.nftables}/bin/nft add chain inet gitea-redirect prerouting '{ type nat hook prerouting priority dstnat; }' 2>/dev/null || true
|
||||||
|
${pkgs.nftables}/bin/nft add rule inet gitea-redirect prerouting tcp dport 222 redirect to :2222 2>/dev/null || true
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.mailserver = {
|
||||||
|
image = "ghcr.io/docker-mailserver/docker-mailserver:latest";
|
||||||
|
autoStart = true;
|
||||||
|
hostname = "mail.severijnse.eu";
|
||||||
|
ports = [
|
||||||
|
"25:25"
|
||||||
|
"[::]:25:25"
|
||||||
|
"143:143"
|
||||||
|
"[::]:143:143"
|
||||||
|
"465:465"
|
||||||
|
"[::]:465:465"
|
||||||
|
"587:587"
|
||||||
|
"[::]:587:587"
|
||||||
|
"993:993"
|
||||||
|
"[::]:993:993"
|
||||||
|
];
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/dms/mail-data/:/var/mail/:Z"
|
||||||
|
"/home/admin/dms/mail-state/:/var/mail-state/:Z"
|
||||||
|
"/home/admin/dms/mail-logs/:/var/log/mail/:Z"
|
||||||
|
"/home/admin/dms/config/:/tmp/docker-mailserver/:Z"
|
||||||
|
"/etc/localtime:/etc/localtime:ro"
|
||||||
|
# On the running Debian, Caddy v2 stores certs at /home/admin/caddy/data/caddy/certificates/...
|
||||||
|
# On NixOS, Caddy stores certs at /var/lib/caddy/certificates/...
|
||||||
|
"/var/lib/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.severijnse.eu/:/etc/letsencrypt/live/mail.severijnse.eu/:ro"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
OVERRIDE_HOSTNAME = "";
|
||||||
|
LOG_LEVEL = "info";
|
||||||
|
SPOOF_PROTECTION = "1";
|
||||||
|
MOVE_SPAM_TO_JUNK = "1";
|
||||||
|
};
|
||||||
|
environmentFiles = ["/home/admin/mailserver.env"];
|
||||||
|
extraOptions = [
|
||||||
|
"--label=com.centurylinklabs.watchtower.enable=true"
|
||||||
|
"--dns=1.1.1.1"
|
||||||
|
"--dns=8.8.8.8"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers = {
|
||||||
|
hbbr = {
|
||||||
|
image = "rustdesk/rustdesk-server:latest";
|
||||||
|
cmd = ["hbbr"];
|
||||||
|
autoStart = true;
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/rustdesk:/root:Z"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--network=host"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
hbbs = {
|
||||||
|
image = "rustdesk/rustdesk-server:latest";
|
||||||
|
cmd = ["hbbs"];
|
||||||
|
autoStart = true;
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/rustdesk:/root:Z"
|
||||||
|
];
|
||||||
|
dependsOn = ["hbbr"];
|
||||||
|
extraOptions = [
|
||||||
|
"--network=host"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.shkeeper = {
|
||||||
|
image = "vsyshost/shkeeper:2.5.29";
|
||||||
|
autoStart = true;
|
||||||
|
ports = ["5000:5000"];
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/shkeeper-data:/app/data:Z"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
SHKEEPER_HOST = "0.0.0.0";
|
||||||
|
SHKEEPER_PORT = "5000";
|
||||||
|
};
|
||||||
|
extraOptions = [
|
||||||
|
"--env-file=/home/admin/shkeeper.env"
|
||||||
|
"--label=com.centurylinklabs.watchtower.enable=true"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.snappymail = {
|
||||||
|
image = "djmaze/snappymail:latest";
|
||||||
|
autoStart = true;
|
||||||
|
ports = ["127.0.0.1:8888:8888"];
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/snappymail-data:/var/lib/snappymail:Z"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
TZ = "Europe/Berlin";
|
||||||
|
};
|
||||||
|
extraOptions = [
|
||||||
|
"--label=com.centurylinklabs.watchtower.enable=true"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Ensure the persistent data dir exists so podman's :Z relabel (statfs) succeeds on first boot.
|
||||||
|
# Owned by 82:82 (www-data) because the container's PHP worker runs as UID 82 and must be
|
||||||
|
# able to write to /var/lib/snappymail (SnappyMail checks is_writable on that path).
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /home/admin/snappymail-data 0755 82 82 - -"
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# Caddy's canonical certificate storage (XDG data dir). Renewals land here,
|
||||||
|
# owned caddy:caddy 0600 — the mail server's non-root Postfix/Dovecot cannot
|
||||||
|
# read it directly, so we copy it into a world-readable distribution dir.
|
||||||
|
caddyCertDir = "/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.severijnse.eu";
|
||||||
|
# World-readable distribution dir mounted (RO) into the mail server container.
|
||||||
|
distCertDir = "/var/lib/caddy/certificates/acme-v02.api.letsencrypt.org-directory/mail.severijnse.eu";
|
||||||
|
zoneFile = "/var/lib/coredns/zones/severijnse.eu.db";
|
||||||
|
|
||||||
|
syncScript = pkgs.writeShellScript "tlsa-update" ''
|
||||||
|
set -euo pipefail
|
||||||
|
OPENSSL="${pkgs.openssl}/bin/openssl"
|
||||||
|
|
||||||
|
SRC_CERT="${caddyCertDir}/mail.severijnse.eu.crt"
|
||||||
|
SRC_KEY="${caddyCertDir}/mail.severijnse.eu.key"
|
||||||
|
DST_CERT="${distCertDir}/mail.severijnse.eu.crt"
|
||||||
|
DST_KEY="${distCertDir}/mail.severijnse.eu.key"
|
||||||
|
|
||||||
|
# Caddy has not obtained the certificate yet (e.g. first boot before HTTP-01).
|
||||||
|
if [ ! -f "$SRC_CERT" ] || [ ! -f "$SRC_KEY" ]; then
|
||||||
|
echo "tlsa-update: certificate not found at $caddyCertDir, skipping" >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 1) Propagate Caddy's renewed certificate into the distribution dir the
|
||||||
|
# mail server mounts. Caddy stores certs 0600 caddy:caddy. The cert is
|
||||||
|
# world-readable (Postfix/Dovecot read it as root before dropping
|
||||||
|
# privileges); the private key is restricted to root (0640) so it is not
|
||||||
|
# exposed to other local users.
|
||||||
|
install -D -m 0644 "$SRC_CERT" "$DST_CERT"
|
||||||
|
install -D -m 0640 "$SRC_KEY" "$DST_KEY"
|
||||||
|
|
||||||
|
# 2) TLSA 3 1 1 = SHA-256 of the certificate's SubjectPublicKeyInfo (SPKI),
|
||||||
|
# NOT the whole certificate. Matching type 1 = SHA-256 of the SPKI DER.
|
||||||
|
HEX=$("$OPENSSL" x509 -in "$DST_CERT" -noout -pubkey 2>/dev/null | "$OPENSSL" pkey -pubin -outform DER 2>/dev/null | "$OPENSSL" dgst -sha256 | cut -d' ' -f2)
|
||||||
|
|
||||||
|
# 3) Update the CoreDNS zone. coredns.service regenerates this file from the
|
||||||
|
# Nix store on every start, so this unit (which is partOf coredns and runs
|
||||||
|
# after it) re-applies the correct TLSA after each rebuild/restart.
|
||||||
|
if [ -f "${zoneFile}" ]; then
|
||||||
|
sed -i -E "s/^(_25\._tcp\.mail.*TLSA 3 1 1).*/\1 $HEX/" "${zoneFile}"
|
||||||
|
sed -i -E "s/^(_465\._tcp\.mail.*TLSA 3 1 1).*/\1 $HEX/" "${zoneFile}"
|
||||||
|
sed -i -E "s/^(_993\._tcp\.mail.*TLSA 3 1 1).*/\1 $HEX/" "${zoneFile}"
|
||||||
|
chown coredns:coredns "${zoneFile}"
|
||||||
|
chmod 0640 "${zoneFile}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 4) Reload services so the changes take effect immediately.
|
||||||
|
systemctl reload coredns.service || true
|
||||||
|
podman exec mailserver postfix reload || true
|
||||||
|
podman exec mailserver dovecot reload || true
|
||||||
|
|
||||||
|
echo "tlsa-update: TLSA set to $HEX"
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
# Ensure the distribution dir exists (Caddy does not write here).
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${distCertDir} 0755 root root - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.tlsa-update = {
|
||||||
|
description = "Sync Caddy TLS certificate to mail server and update DANE/TLSA records";
|
||||||
|
after = ["caddy.service" "coredns.service"];
|
||||||
|
partOf = ["coredns.service"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
path = with pkgs; [openssl coreutils gnused podman systemd];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${syncScript}";
|
||||||
|
User = "root";
|
||||||
|
Group = "root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Fire as soon as Caddy rewrites the certificate on renewal (the atomic rewrite
|
||||||
|
# changes the directory mtime), eliminating the up-to-24h DANE drift window.
|
||||||
|
systemd.paths.tlsa-update = {
|
||||||
|
description = "Watch Caddy certificate directory for renewal";
|
||||||
|
wantedBy = ["paths.target"];
|
||||||
|
pathConfig = {
|
||||||
|
PathModified = [caddyCertDir];
|
||||||
|
Unit = "tlsa-update.service";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Fallback in case a renewal event is missed (e.g. inotify overflow).
|
||||||
|
systemd.timers.tlsa-update = {
|
||||||
|
wantedBy = ["timers.target"];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "daily";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.vaultwarden = {
|
||||||
|
image = "vaultwarden/server:latest";
|
||||||
|
autoStart = true;
|
||||||
|
ports = ["1001:80"];
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/vw-data:/data:Z"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
DOMAIN = "https://vault.severijnse.eu";
|
||||||
|
LOG_FILE = "/data/vaultwarden.log";
|
||||||
|
};
|
||||||
|
extraOptions = [
|
||||||
|
"--label=com.centurylinklabs.watchtower.enable=true"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.watchtower = {
|
||||||
|
image = "ghcr.io/nicholas-fedor/watchtower:latest";
|
||||||
|
autoStart = true;
|
||||||
|
volumes = [
|
||||||
|
"/var/run/podman/podman.sock:/var/run/docker.sock:ro"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
WATCHTOWER_CLEANUP = "true";
|
||||||
|
WATCHTOWER_POLL_INTERVAL = "86400";
|
||||||
|
WATCHTOWER_INCLUDE_STOPPED = "true";
|
||||||
|
WATCHTOWER_REVIVE_STOPPED = "true";
|
||||||
|
TZ = "Europe/Amsterdam";
|
||||||
|
};
|
||||||
|
cmd = ["--label-enable"];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.wg-easy = {
|
||||||
|
image = "ghcr.io/wg-easy/wg-easy:latest";
|
||||||
|
autoStart = true;
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/config:/etc/wireguard:Z"
|
||||||
|
];
|
||||||
|
environment = {
|
||||||
|
WG_HOST = "severijnse.eu";
|
||||||
|
PASSWORD_HASH = "$2a$12$b3n4drXgS3B6ubMZxxjPUOQ1XktZ1EuDwm4AIdVulhtoD7b1.WQGC";
|
||||||
|
WG_DEFAULT_ADDRESS = "10.8.0.x";
|
||||||
|
WG_DEFAULT_DNS = "1.1.1.1";
|
||||||
|
WG_PORT = "51820";
|
||||||
|
};
|
||||||
|
extraOptions = [
|
||||||
|
"--cap-add=NET_ADMIN"
|
||||||
|
"--cap-add=SYS_MODULE"
|
||||||
|
"--cap-add=NET_RAW"
|
||||||
|
"--network=host"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
virtualisation.oci-containers.containers.wrxproxy = {
|
||||||
|
image = "localhost/wrxproxy:latest";
|
||||||
|
autoStart = false;
|
||||||
|
ports = ["81:81"];
|
||||||
|
volumes = [
|
||||||
|
"/home/admin/WRXproxy/config.json:/app/config.json:ro"
|
||||||
|
];
|
||||||
|
extraOptions = [
|
||||||
|
"--label=com.centurylinklabs.watchtower.enable=true"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
time.timeZone = "Europe/Amsterdam";
|
||||||
|
|
||||||
|
i18n.defaultLocale = "en_US.UTF-8";
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
vim
|
||||||
|
git
|
||||||
|
curl
|
||||||
|
wget
|
||||||
|
htop
|
||||||
|
iotop
|
||||||
|
btop
|
||||||
|
bind.dnsutils # provides dig, nslookup, host
|
||||||
|
jq
|
||||||
|
yq
|
||||||
|
fish
|
||||||
|
podman-compose
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.fish.enable = true;
|
||||||
|
programs.bash.enableCompletion = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
keys:
|
||||||
|
- &admin age1yd59qp5km4cxt99rlfjehnsucrjn9lmj0su4h3avhf6vrtjvnyjqstldl5
|
||||||
|
- &local age15rhqdpwejyf3r6ww70qgv6hqmkpsqraakn26kc49wlauhaceaeqsmuwrdd
|
||||||
|
- &server age1xekdrkjfu82hkxltydm72tllzgayyvfavvudeks3xjuujm5wt5hq6g55v0
|
||||||
|
creation_rules:
|
||||||
|
- path_regex: secrets/.*\.yaml
|
||||||
|
key_groups:
|
||||||
|
- age:
|
||||||
|
- *admin
|
||||||
|
- *local
|
||||||
|
- *server
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
# Secrets
|
||||||
|
|
||||||
|
This directory contains encrypted secrets managed with sops-nix.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Generate an age key on the target machine:
|
||||||
|
```
|
||||||
|
mkdir -p /etc/age
|
||||||
|
age-keygen -o /etc/age/keys.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add the public key to `.sops.yaml`
|
||||||
|
|
||||||
|
3. Create/edit secrets:
|
||||||
|
```
|
||||||
|
sops secrets/mail-accounts.yaml
|
||||||
|
sops secrets/env.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
- `env.yaml` - Environment variables (WG_HOST, PASSWORD_HASH, etc.)
|
||||||
|
- `mail-accounts.yaml` - Mail server account credentials
|
||||||
|
- `wireguard-keys.yaml` - WireGuard private keys
|
||||||
|
- `ssh-keys.yaml` - SSH private keys (mail.private, etc.)
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
coredns_ksk_key: ENC[AES256_GCM,data:mPjyv74ujSVnbJ6cjFdO7XtkThDv4clF+K+d485njvvx7IBrC4t+DMMtJxqL7qad8Cf4g/vx3cO0dsB8UbsbuyVAEPpgmGnqTJ+Ec4zbP73g7u4W/HcgT+ZcGY2fzuz/K7uETRN852KfE6RIKkTZkOfBfo1YsOglpRTiSQMh4Jnso9Nihdh7hfbQQ0yXjhQMhGFTUGYR4AQM3ZUFkjY2hN0Ys34Tbwg4HnHwcmWMnwGj7Ab29HU/UP//AAb1rlUNcde6MuWAGlObj6P/poxjeVyWL7lfAveAEqZiHyUDUE2939cCROT1TLZ+f3t2hinK4bzTfp3n9fxhVt4LG7WnDDms97+7M9rI2dVSxDnDTAElyU8NGlYmDcUOOzeTBccxnVegUuRNHMhT2Hrut3K+TGgpTdDNA93PXNB/cCodvNDWtZGrZuRtANZPVMTe7E/3fiw6urrxR59G,iv:fByY/Z4kzxAFXobtrV8Y59IdqzN4W/HsvEPGOhBGI+E=,tag:FoB4jrxsLXNKnhFykX6F/g==,type:str]
|
||||||
|
coredns_ksk_private: ENC[AES256_GCM,data:yaVhVVR1QHXshePY2x9qbOJszl3tj3ne71W7TP+JG2gF1BiU+EBp8QJNQBcj58sFwun88RPIUK5OUgJ/n9dyEWOCf3jfDO4yRD7XLqJVp3tf15Ou2FytHd7hg52id+1gJxSRmhxHWw5of1v9Jo6cocET6tnVnygsPmxJEufoW3DyFZrPscba7rsJhpjJNINEcvgcD44ySy47gisA2s1oIgXp/UJmoZ/H6IXm9/HL66bvfl0ubZ0rxa0Rlg==,iv:pXl8ppb1Pxl5mRBY2sa595ChSAD/zdbKK+H4xeeMG+I=,tag:ez8xqxXfzf3U15YHbaxUZg==,type:str]
|
||||||
|
coredns_zsk_key: ENC[AES256_GCM,data:AdGcUU1qjdRSlI1j6LJGsrqXgUqMfHJGETaVJETPN8+JEjdHvLXCpuiqnJE20hqXDi6gIrBaUQMruJG2KfSZTfxSPoqIYoAlbBQBpTsGwpFazWIsggMJNlqUYKSnBr4QsBTj6A/IZYR4KzcJX+vo7pL0nLz+bpH1/o6ry7lghqt7sIjS9Nx1CKW6WpMPePjBViGp8i5jQWijsUCj+DRjQatycBKhpQWCqlYqn+CM99/QWjy/qXWFmgBiiFjQ8lT1AjOIIL0Icger06ReWCl2387xB/JqHbtsq65WOLuJiyxBBw02wOQz09UaKsDsoM59w3SINKqK+YyCkonHXycLuMAuE7tasHVRPEdWsr6os18cystLQO8qp1oVSGtUSVM07TkM8OowMlOmN44veIkgON4s8pN7S9V9N46N0BSC6w7A3u2VqCfAgPLUjPWNieIfir8P3p+gQSPWuw==,iv:Kvc8N+fp2rVd1TTsZHbk67fL2nOlGhqDE+TvH+aU0VE=,tag:1wkgkV1gqddhkkOs1NoztA==,type:str]
|
||||||
|
coredns_zsk_private: ENC[AES256_GCM,data:BZxC5iYY8wh6kXbXpNheVrvBh6TB0968ivw06sJ1driytCt3RK6ZtNcr7PMxjxbKCdZKllLIdCABJDrj8eQCLLLMRspYVXLWquJvLHCCGqteY+Ha4b5bdsUO64I+HkDGagZSj7mIsaD7+aGOI2FN4bFhd364qGc1hGACePBUWlUi8AHSQY9KgadXBX2+ud6BIsoyoEN8AhjNK6zSADZYeA3JMJ1HTP1MbAB6owbmQMieunMHwudi6fi6eQ==,iv:lSjLOF6u1gLUv2IQ6rqG9nNCkFa6Yruknx0Lc+E6vzY=,tag:QQv1+47UtX+ZxrYwsrHLSg==,type:str]
|
||||||
|
sops:
|
||||||
|
age:
|
||||||
|
- recipient: age1yd59qp5km4cxt99rlfjehnsucrjn9lmj0su4h3avhf6vrtjvnyjqstldl5
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSUVZKYWFmSU5xbWo2N0Qy
|
||||||
|
c0VPeVIxQ1lNMTB5VkI4dVdsTXlkSEo3azN3CjJtR0lqclZOUjFkVjFWSDM2SGF1
|
||||||
|
OWNKcFNFSGpzd3A3MUZyS09CUWUyMlEKLS0tIG5VdmU1b0YwdWxUTXBzaGR2d2tR
|
||||||
|
UjI1K1pYaC9pTnNNcldXQ3B3endUTDgKHISJEvZrn6VO/voH2ORzeJbpVjpX8MxP
|
||||||
|
qGJ+G7sMM8trCOpkR3wjqSaZVU1hric+0R5oHiMKDLcb3hGN9mgJFA==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age15rhqdpwejyf3r6ww70qgv6hqmkpsqraakn26kc49wlauhaceaeqsmuwrdd
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5RzlaWXU3ZVo0Y0JiV0xk
|
||||||
|
RlBYR3RHdklSdVhoY0UzYmFxeGl3YkFITW5BCmhITk9DMjRmekFyd0hQbnRCWEY5
|
||||||
|
NFRlUkdRT2lyZzdxbFJxelAyY1ZLYm8KLS0tIEdWc0lOQWU1ZFdHQjVIeTFVdGpH
|
||||||
|
WWxTeW96TC9UWTRMOXdkNVNzd1Rra0kKzkam9SYaIbkSOE+g2FIzIV7nyDHHt+gk
|
||||||
|
Uvhb6dvKW3omRYlh5ln7xDRcHiX83rz/TfPh2GdtXs/J0Oxkeo7drg==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
- recipient: age1xekdrkjfu82hkxltydm72tllzgayyvfavvudeks3xjuujm5wt5hq6g55v0
|
||||||
|
enc: |
|
||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWWTc0ZUJrL0dmallFb2Nv
|
||||||
|
TVR0VU9ZdGpzK3FNdjlaR1pmc3RucGZLcXhrClhmWHNjQk5kZ1ZBT2xYek9JM0x1
|
||||||
|
M0krWE8yUVVZMmVCbk83TGhMSUoyVWsKLS0tIDRocWI3L1ZVMmppSU1rUytDTDJz
|
||||||
|
dm5SYXc0VTdWSE1hQ2JtczdUenF1RUkKNfLtmhzZBFqGJKT4MMMVdKG/MmqNqUgF
|
||||||
|
DFPkw2uLlPTW1Wws37ac9u53G7AfcE1zRHiIzGYz9O2Cqc+xKjRpDQ==
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
|
lastmodified: "2026-07-10T13:18:54Z"
|
||||||
|
mac: ENC[AES256_GCM,data:La/qXs87taoMI4KT3Mnb/MMyVshP3c+sgS5jzSZSGhsT02pOsE3AvG8UFlgcz2gZvD0aTsm3P54B3bHjq61OCcYOKAcS9dJjqDwC91utRf3CL+1hezIJUUjXNMUMTwVbRmNPuP6gZMKsdqztkAqvCxRwqXQWkC10ds2IfzKCQD4=,iv:e/LTO8wzKDw2DP4b/HdSTakcz7lPkLGqcdeU6N5dDDA=,tag:ASw3jQj7mrcVrOdhjlbwng==,type:str]
|
||||||
|
unencrypted_suffix: _unencrypted
|
||||||
|
version: 3.12.2
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
{ config, pkgs, lib, ... }:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
boot = {
|
boot = {
|
||||||
bootspec.enable = true;
|
bootspec.enable = true;
|
||||||
|
|
||||||
initrd.systemd.enable = true;
|
initrd.systemd.enable = true;
|
||||||
|
|
||||||
supportedFilesystems = [ "ntfs" ];
|
supportedFilesystems = ["ntfs"];
|
||||||
|
|
||||||
kernelPackages = pkgs.linuxPackages_latest;
|
kernelPackages = pkgs.linuxPackages_latest;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
{ lib, pkgs, ... }:
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
boot.loader = {
|
boot.loader = {
|
||||||
limine = {
|
limine = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
+4
-4
@@ -15,10 +15,10 @@ let
|
|||||||
|
|
||||||
# GUI-specific modules (display manager, GPU, pipewire)
|
# GUI-specific modules (display manager, GPU, pipewire)
|
||||||
gui = [
|
gui = [
|
||||||
./core/boot.nix # plymouth boot splash
|
./core/boot.nix # plymouth boot splash
|
||||||
./hardware/graphics.nix # GPU drivers
|
./hardware/graphics.nix # GPU drivers
|
||||||
./services/greetd.nix # display manager
|
./services/greetd.nix # display manager
|
||||||
./services/pipewire.nix # audio
|
./services/pipewire.nix # audio
|
||||||
];
|
];
|
||||||
|
|
||||||
# Laptop-specific modules (battery, bluetooth)
|
# Laptop-specific modules (battery, bluetooth)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
services.avahi = {
|
services.avahi = {
|
||||||
enable = true;
|
enable = true;
|
||||||
nssmdns4 = true;
|
nssmdns4 = true;
|
||||||
denyInterfaces = [ "docker0" "veth*" "virbr*" ];
|
denyInterfaces = ["docker0" "veth*" "virbr*"];
|
||||||
publish = {
|
publish = {
|
||||||
enable = true;
|
enable = true;
|
||||||
domain = true;
|
domain = true;
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
}: let
|
}: let
|
||||||
# Patch termfilechooser .portal to add Niri to UseIn
|
# Patch termfilechooser .portal to add Niri to UseIn
|
||||||
termfilechooser-niri = pkgs.xdg-desktop-portal-termfilechooser.overrideAttrs (old: {
|
termfilechooser-niri = pkgs.xdg-desktop-portal-termfilechooser.overrideAttrs (old: {
|
||||||
postFixup = (old.postFixup or "") + ''
|
postFixup =
|
||||||
substituteInPlace $out/share/xdg-desktop-portal/portals/termfilechooser.portal \
|
(old.postFixup or "")
|
||||||
--replace-fail "wlroots;" "wlroots;Niri;"
|
+ ''
|
||||||
'';
|
substituteInPlace $out/share/xdg-desktop-portal/portals/termfilechooser.portal \
|
||||||
|
--replace-fail "wlroots;" "wlroots;Niri;"
|
||||||
|
'';
|
||||||
});
|
});
|
||||||
in {
|
in {
|
||||||
xdg.portal = {
|
xdg.portal = {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
alsa.support32Bit = true;
|
alsa.support32Bit = true;
|
||||||
jack.enable = true;
|
jack.enable = true;
|
||||||
pulse.enable = true;
|
pulse.enable = true;
|
||||||
extraLadspaPackages = [ pkgs.rnnoise-plugin ];
|
extraLadspaPackages = [pkgs.rnnoise-plugin];
|
||||||
|
|
||||||
wireplumber = {
|
wireplumber = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user