forked from jan-leila/nix-config
Compare commits
31 commits
Author | SHA1 | Date | |
---|---|---|---|
358f039460 | |||
3f3ae74fac | |||
c8f163ed0c | |||
3a875e0c1f | |||
1e5eed80c1 | |||
2fb56dc296 | |||
92839b4603 | |||
2188954b79 | |||
2e8eba7709 | |||
0e8a148517 | |||
b8e21e6c61 | |||
035089be38 | |||
776bf8f744 | |||
9699472b1e | |||
3631ba11a8 | |||
644f9371eb | |||
3ce9b625d1 | |||
1d7e0d11f0 | |||
c863b8c4b5 | |||
9650c7335a | |||
56ef83b4ba | |||
84dfcfddbd | |||
43ce007033 | |||
4db136d527 | |||
b6ce78b35c | |||
4c0c443048 | |||
b3f992f001 | |||
f8aa299e16 | |||
7c61f8617b | |||
4825c5ec5e | |||
4ded22c2f5 |
31 changed files with 685 additions and 593 deletions
31
README.md
31
README.md
|
@ -41,30 +41,33 @@ nix multi user, multi system, configuration with `sops` secret management, `home
|
|||
|
||||
## Research topics
|
||||
- Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/`
|
||||
- Look into this for flake templates https://nix.dev/manual/nix/2.22/command-ref/new-cli/nix3-flake-init
|
||||
- Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/
|
||||
- https://nixos-and-flakes.thiscute.world/
|
||||
- nix config mcp https://github.com/utensils/mcp-nixos
|
||||
|
||||
# Tasks:
|
||||
|
||||
## Tech Debt
|
||||
- monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/)
|
||||
- syncthing folder passwords
|
||||
- nfs export should be backed by the same values for server and client
|
||||
## New Features
|
||||
- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs)
|
||||
- samba mounts
|
||||
- crab-hole
|
||||
- figure out why syncthing and jellyfins permissions don't propagate downwards
|
||||
- figure out steam vr things?
|
||||
- Open GL?
|
||||
- rotate sops encryption keys periodically (and somehow sync between devices?)
|
||||
- auto turn off on power loss - nut
|
||||
- zfs email after scrubbing # TODO: test this
|
||||
- wake on LAN for updates
|
||||
- ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix
|
||||
- SMART test with email results
|
||||
- fix nfs
|
||||
- samba mounts
|
||||
- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs)
|
||||
- Create Tor guard/relay server
|
||||
- migrate away from flakes and move to npins
|
||||
- whisper
|
||||
- figure out ai vs code plugin
|
||||
- nix mcp
|
||||
- zfs encryption FIDO2 2fa (look into shavee)
|
||||
- Secure Boot - https://github.com/nix-community/lanzaboote
|
||||
- SMART test with email results
|
||||
- Create Tor guard/relay server
|
||||
- rotate sops encryption keys periodically (and somehow sync between devices?)
|
||||
- wake on LAN for updates
|
||||
- remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html
|
||||
- migrate away from flakes and move to npins
|
||||
- fix nfs
|
||||
- fix home assistant
|
||||
- create adguard server
|
||||
- ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix
|
|
@ -1,26 +1,23 @@
|
|||
{pkgs, ...}: {
|
||||
config = {
|
||||
gnome = {
|
||||
extraWindowControls = true;
|
||||
colorScheme = "prefer-dark";
|
||||
clockFormat = "24h";
|
||||
extensions = [
|
||||
pkgs.gnomeExtensions.dash-to-dock
|
||||
];
|
||||
hotkeys = {
|
||||
"Open Terminal" = {
|
||||
binding = "<Super>t";
|
||||
command = "kgx";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
dconf = {
|
||||
enable = true;
|
||||
settings = {
|
||||
"org/gnome/desktop/interface".color-scheme = "prefer-dark";
|
||||
|
||||
"org/gnome/desktop/wm/preferences".button-layout = ":minimize,maximize,close";
|
||||
|
||||
"org/gnome/shell" = {
|
||||
disable-user-extensions = false; # enables user extensions
|
||||
enabled-extensions = [
|
||||
# Put UUIDs of extensions that you want to enable here.
|
||||
# If the extension you want to enable is packaged in nixpkgs,
|
||||
# you can easily get its UUID by accessing its extensionUuid
|
||||
# field (look at the following example).
|
||||
pkgs.gnomeExtensions.dash-to-dock.extensionUuid
|
||||
|
||||
# Alternatively, you can manually pass UUID as a string.
|
||||
# "dash-to-dock@micxgx.gmail.com"
|
||||
];
|
||||
};
|
||||
|
||||
"org/gnome/shell/extensions/dash-to-dock" = {
|
||||
"dock-position" = "LEFT";
|
||||
"intellihide-mode" = "ALL_WINDOWS";
|
||||
|
@ -29,18 +26,6 @@
|
|||
"show-mounts" = false;
|
||||
};
|
||||
|
||||
"org/gnome/settings-daemon/plugins/media-keys" = {
|
||||
custom-keybindings = [
|
||||
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0/"
|
||||
];
|
||||
};
|
||||
|
||||
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/custom0" = {
|
||||
binding = "<Super>t";
|
||||
command = "kgx";
|
||||
name = "Open Terminal";
|
||||
};
|
||||
|
||||
"org/gnome/shell" = {
|
||||
favorite-apps = ["org.gnome.Nautilus.desktop" "firefox.desktop" "codium.desktop" "steam.desktop" "org.gnome.Console.desktop"];
|
||||
# app-picker-layout =
|
||||
|
|
|
@ -82,31 +82,5 @@
|
|||
# EDITOR = "emacs";
|
||||
};
|
||||
};
|
||||
|
||||
user = {
|
||||
continue = {
|
||||
enable = true;
|
||||
docs = {
|
||||
"Continue Docs" = {
|
||||
startUrl = "https://docs.continue.dev";
|
||||
};
|
||||
"Nixpkgs" = {
|
||||
startUrl = "https://ryantm.github.io/nixpkgs/#preface";
|
||||
};
|
||||
"Nix Manual" = {
|
||||
startUrl = "https://nixos.org/manual/nixos/stable/";
|
||||
};
|
||||
"Home manager Manual" = {
|
||||
startUrl = "https://nix-community.github.io/home-manager/";
|
||||
};
|
||||
"Nix Docs" = {
|
||||
startUrl = "https://nix.dev/index.html";
|
||||
};
|
||||
"Linux Man Page" = {
|
||||
startUrl = "https://linux.die.net/man/";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -69,8 +69,6 @@ in {
|
|||
(with pkgs; [
|
||||
aileron
|
||||
|
||||
gnomeExtensions.dash-to-dock
|
||||
|
||||
proxmark3
|
||||
])
|
||||
++ (
|
||||
|
|
|
@ -1,31 +1,20 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
inputs,
|
||||
config,
|
||||
osConfig,
|
||||
...
|
||||
}: let
|
||||
nix-development-enabled = osConfig.host.nix-development.enable;
|
||||
ai-tooling-enabled = config.user.continue.enable && osConfig.host.ai.enable;
|
||||
ai-tooling-enabled = osConfig.host.ai.enable;
|
||||
in {
|
||||
config = lib.mkIf config.user.isDesktopUser {
|
||||
nixpkgs = {
|
||||
overlays = [
|
||||
inputs.nix-vscode-extensions.overlays.default
|
||||
];
|
||||
};
|
||||
|
||||
programs = {
|
||||
bash.shellAliases = {
|
||||
code = "codium";
|
||||
};
|
||||
|
||||
vscode = let
|
||||
extensions = inputs.nix-vscode-extensions.extensions.${pkgs.system};
|
||||
open-vsx = extensions.open-vsx;
|
||||
vscode-marketplace = extensions.vscode-marketplace;
|
||||
in {
|
||||
vscode = {
|
||||
package = pkgs.vscodium;
|
||||
|
||||
mutableExtensionsDir = false;
|
||||
|
@ -57,12 +46,13 @@ in {
|
|||
};
|
||||
})
|
||||
(lib.mkIf ai-tooling-enabled {
|
||||
"continue.telemetryEnabled" = false;
|
||||
})
|
||||
})
|
||||
];
|
||||
|
||||
extensions = (
|
||||
with open-vsx;
|
||||
extensions = let
|
||||
extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
|
||||
in (
|
||||
with extension-pkgs.open-vsx;
|
||||
[
|
||||
# vs code feel extensions
|
||||
ms-vscode.atom-keybindings
|
||||
|
@ -80,7 +70,7 @@ in {
|
|||
dsznajder.es7-react-js-snippets
|
||||
dbaeumer.vscode-eslint
|
||||
standard.vscode-standard
|
||||
firsttris.vscode-jest-runner
|
||||
orta.vscode-jest
|
||||
stylelint.vscode-stylelint
|
||||
tauri-apps.tauri-vscode
|
||||
|
||||
|
@ -101,14 +91,18 @@ in {
|
|||
kamadorueda.alejandra
|
||||
])
|
||||
++ (
|
||||
with vscode-marketplace;
|
||||
with extension-pkgs.vscode-marketplace;
|
||||
[
|
||||
# js extensions
|
||||
karyfoundation.nearley
|
||||
]
|
||||
++ (lib.lists.optionals ai-tooling-enabled [
|
||||
continue.continue
|
||||
])
|
||||
])
|
||||
)
|
||||
++ (
|
||||
with pkgs.codium-extensions; [
|
||||
ai-code
|
||||
]
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -17,6 +17,12 @@
|
|||
"services/zfs_smtp_token" = {
|
||||
sopsFile = "${inputs.secrets}/defiant-services.yaml";
|
||||
};
|
||||
"services/paperless_password" = {
|
||||
sopsFile = "${inputs.secrets}/defiant-services.yaml";
|
||||
mode = "0700";
|
||||
owner = "paperless";
|
||||
group = "paperless";
|
||||
};
|
||||
};
|
||||
|
||||
host = {
|
||||
|
@ -109,13 +115,6 @@
|
|||
};
|
||||
};
|
||||
};
|
||||
# home-assistant = {
|
||||
# enable = false;
|
||||
# subdomain = "home";
|
||||
# };
|
||||
adguardhome = {
|
||||
enable = false;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
|
@ -282,10 +281,23 @@
|
|||
subdomain = "search";
|
||||
};
|
||||
|
||||
virt-home-assistant = {
|
||||
enable = false;
|
||||
networkBridge = "bond0";
|
||||
hostDevice = "0x10c4:0xea60";
|
||||
home-assistant = {
|
||||
enable = true;
|
||||
subdomain = "home";
|
||||
openFirewall = true;
|
||||
database = "postgres";
|
||||
|
||||
extensions = {
|
||||
sonos.enable = true;
|
||||
jellyfin.enable = true;
|
||||
wyoming.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
paperless = {
|
||||
enable = true;
|
||||
subdomain = "documents";
|
||||
passwordFile = config.sops.secrets."services/paperless_password".path;
|
||||
};
|
||||
|
||||
qbittorrent = {
|
||||
|
|
|
@ -126,6 +126,13 @@
|
|||
};
|
||||
|
||||
syncthing.enable = true;
|
||||
|
||||
ollama = {
|
||||
enable = true;
|
||||
loadModels = [
|
||||
"llama3.1:8b"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
# Enable touchpad support (enabled default in most desktopManager).
|
||||
|
|
56
flake.lock
generated
56
flake.lock
generated
|
@ -7,11 +7,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750680230,
|
||||
"narHash": "sha256-kD88T/NqmcgfOBFAwphN30ccaUdj6K6+LG0XdM2w2LA=",
|
||||
"lastModified": 1752113600,
|
||||
"narHash": "sha256-7LYDxKxZgBQ8LZUuolAQ8UkIB+jb4A2UmiR+kzY9CLI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"rev": "8fd2d6c75009ac75f9a6fb18c33a239806778d01",
|
||||
"rev": "79264292b7e3482e5702932949de9cbb69fedf6d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -28,11 +28,11 @@
|
|||
},
|
||||
"locked": {
|
||||
"dir": "pkgs/firefox-addons",
|
||||
"lastModified": 1750737804,
|
||||
"narHash": "sha256-wClGd2PhxdjjphR6wIgoiDcR+Gfg4/+FyseSOjIIzVU=",
|
||||
"lastModified": 1752379414,
|
||||
"narHash": "sha256-0R3slhrjrnzyxR/fAYy5UliZvSgaVS38YCESBdH5RJw=",
|
||||
"owner": "rycee",
|
||||
"repo": "nur-expressions",
|
||||
"rev": "aaaf4fec792bad465ea4a35c0be5bc2a54f33095",
|
||||
"rev": "51e77bb95540b7dd6c60f8fd65a0c472a2c9c3b7",
|
||||
"type": "gitlab"
|
||||
},
|
||||
"original": {
|
||||
|
@ -115,11 +115,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750730235,
|
||||
"narHash": "sha256-rZErlxiV7ssvI8t7sPrKU+fRigNc2KvoKZG3gtUtK50=",
|
||||
"lastModified": 1752467539,
|
||||
"narHash": "sha256-4kaR+xmng9YPASckfvIgl5flF/1nAZOplM+Wp9I5SMI=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "d07e9cceb4994ed64a22b9b36f8b76923e87ac38",
|
||||
"rev": "1e54837569e0b80797c47be4720fab19e0db1616",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -185,11 +185,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750618568,
|
||||
"narHash": "sha256-w9EG5FOXrjXGfbqCcQg9x1lMnTwzNDW5BMXp8ddy15E=",
|
||||
"lastModified": 1751313918,
|
||||
"narHash": "sha256-HsJM3XLa43WpG+665aGEh8iS8AfEwOIQWk3Mke3e7nk=",
|
||||
"owner": "LnL7",
|
||||
"repo": "nix-darwin",
|
||||
"rev": "1dd19f19e4b53a1fd2e8e738a08dd5fe635ec7e5",
|
||||
"rev": "e04a388232d9a6ba56967ce5b53a8a6f713cdfcf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -227,11 +227,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750730765,
|
||||
"narHash": "sha256-MIcOcvxqAXUv2TJjf19aVXdtVrD8Gkcfi4W4pKkT0Lw=",
|
||||
"lastModified": 1752459325,
|
||||
"narHash": "sha256-46TgjdxT02a4nFd9HCXCf8kK5ZSH7r9gYROLtc8zVOg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-vscode-extensions",
|
||||
"rev": "1a1442e13dc1730de0443f80dcf02658365e999a",
|
||||
"rev": "61c2e99ebd586f463a6c0ebe3d931e74883b163d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -242,11 +242,11 @@
|
|||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1750431636,
|
||||
"narHash": "sha256-vnzzBDbCGvInmfn2ijC4HsIY/3W1CWbwS/YQoFgdgPg=",
|
||||
"lastModified": 1752048960,
|
||||
"narHash": "sha256-gATnkOe37eeVwKKYCsL+OnS2gU4MmLuZFzzWCtaKLI8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "1552a9f4513f3f0ceedcf90320e48d3d47165712",
|
||||
"rev": "7ced9122cff2163c6a0212b8d1ec8c33a1660806",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -258,11 +258,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1750506804,
|
||||
"narHash": "sha256-VLFNc4egNjovYVxDGyBYTrvVCgDYgENp5bVi9fPTDYc=",
|
||||
"lastModified": 1751984180,
|
||||
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4206c4cb56751df534751b058295ea61357bbbaa",
|
||||
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -293,11 +293,11 @@
|
|||
"secrets": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1749061163,
|
||||
"narHash": "sha256-WflcbitH7ErNZBFqZCdy1ODUqKF51xbu2zYfqA35+1M=",
|
||||
"lastModified": 1752531440,
|
||||
"narHash": "sha256-04tQ3EUrtmZ7g6fVUkZC4AbAG+Z7lng79qU3jsiqWJY=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "1c5c059c0c7b6ce691993262fe10a2b63e1c31ba",
|
||||
"revCount": 19,
|
||||
"rev": "f016767c13aa36dde91503f7a9f01bdd02468045",
|
||||
"revCount": 20,
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git"
|
||||
},
|
||||
|
@ -313,11 +313,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1750119275,
|
||||
"narHash": "sha256-Rr7Pooz9zQbhdVxux16h7URa6mA80Pb/G07T4lHvh0M=",
|
||||
"lastModified": 1751606940,
|
||||
"narHash": "sha256-KrDPXobG7DFKTOteqdSVeL1bMVitDcy7otpVZWDE6MA=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "77c423a03b9b2b79709ea2cb63336312e78b72e2",
|
||||
"rev": "3633fc4acf03f43b260244d94c71e9e14a2f6e0d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
{inputs, ...}: {
|
||||
nixpkgs.overlays = [
|
||||
inputs.steam-fetcher.overlays.default
|
||||
inputs.nix-vscode-extensions.overlays.default
|
||||
];
|
||||
}
|
||||
|
|
42
modules/common-modules/pkgs/codium-extensions/ai-code.nix
Normal file
42
modules/common-modules/pkgs/codium-extensions/ai-code.nix
Normal file
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
buildNpmPackage,
|
||||
vscode-utils,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
version = "0.0.1";
|
||||
pname = "ai-code";
|
||||
publisher = "jan-leila";
|
||||
vsix = buildNpmPackage {
|
||||
inherit version pname;
|
||||
|
||||
src = builtins.fetchGit {
|
||||
url = "ssh://git@git.jan-leila.com/jan-leila/ai-code.git";
|
||||
rev = "480b51830602b28009e6b5c5014e7e2970a0a3b3";
|
||||
};
|
||||
|
||||
npmDepsHash = "sha256-WxLb+e0itOCIRXpVOjcbPm6QNWbdSKZOPeXLyOa4ROQ=";
|
||||
|
||||
nativeBuildInputs = with pkgs; [
|
||||
vsce
|
||||
];
|
||||
|
||||
buildPhase = ''
|
||||
${pkgs.vsce}/bin/vsce package -o ${pname}.zip
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
mv ${pname}.zip $out/${pname}.zip
|
||||
'';
|
||||
};
|
||||
in
|
||||
vscode-utils.buildVscodeExtension {
|
||||
inherit pname version;
|
||||
|
||||
src = "${vsix}/${pname}.zip";
|
||||
|
||||
vscodeExtUniqueId = "${publisher}.${pname}";
|
||||
vscodeExtPublisher = publisher;
|
||||
vscodeExtName = pname;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{pkgs, ...}: {
|
||||
ai-code = pkgs.callPackage ./ai-code.nix {};
|
||||
}
|
|
@ -19,5 +19,8 @@
|
|||
(final: prev: {
|
||||
gdx-liftoff = pkgs.callPackage ./gdx-liftoff.nix {};
|
||||
})
|
||||
(final: prev: {
|
||||
codium-extensions = pkgs.callPackage ./codium-extensions {};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
osConfig,
|
||||
...
|
||||
}: let
|
||||
ai-tooling-enabled = config.user.continue.enable && osConfig.host.ai.enable;
|
||||
in {
|
||||
options.user.continue = {
|
||||
enable = lib.mkEnableOption "should continue be enabled on this machine";
|
||||
docs = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
||||
options = {
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
};
|
||||
startUrl = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
context = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
||||
options = {
|
||||
provider = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {
|
||||
"code" = {};
|
||||
"docs" = {};
|
||||
"diff" = {};
|
||||
"terminal" = {};
|
||||
"problems" = {};
|
||||
"folder" = {};
|
||||
"codebase" = {};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
lib.mkIf ai-tooling-enabled
|
||||
(lib.mkMerge [
|
||||
{
|
||||
home = {
|
||||
file = {
|
||||
".continue/config.yaml".source = (pkgs.formats.yaml {}).generate "continue-config" {
|
||||
name = "Assistant";
|
||||
version = "1.0.0";
|
||||
schema = "v1";
|
||||
models = lib.attrsets.attrValues osConfig.host.ai.models;
|
||||
context = lib.attrsets.attrValues config.user.continue.context;
|
||||
docs = lib.attrsets.attrValues config.user.continue.docs;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
(lib.mkIf osConfig.host.impermanence.enable {
|
||||
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||
directories = [
|
||||
".continue/index"
|
||||
".continue/sessions"
|
||||
];
|
||||
allowOther = true;
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
|
@ -6,7 +6,7 @@
|
|||
./flipperzero.nix
|
||||
./i18n.nix
|
||||
./openssh.nix
|
||||
./continue.nix
|
||||
./gnome.nix
|
||||
./programs
|
||||
];
|
||||
}
|
||||
|
|
106
modules/home-manager-modules/gnome.nix
Normal file
106
modules/home-manager-modules/gnome.nix
Normal file
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.gnome = {
|
||||
extraWindowControls = lib.mkEnableOption "Should we add back in the minimize and maximize window controls?";
|
||||
clockFormat = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"12h"
|
||||
"24h"
|
||||
];
|
||||
default = "24h";
|
||||
};
|
||||
colorScheme = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"default"
|
||||
"prefer-dark"
|
||||
"prefer-light"
|
||||
];
|
||||
default = "default";
|
||||
};
|
||||
accentColor = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"blue"
|
||||
"teal"
|
||||
"green"
|
||||
"yellow"
|
||||
"orange"
|
||||
"red"
|
||||
"pink"
|
||||
"purple"
|
||||
"slate"
|
||||
];
|
||||
default = "blue";
|
||||
};
|
||||
extensions = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.package;
|
||||
default = [];
|
||||
description = "The set of extensions to install and enable in the user environment.";
|
||||
};
|
||||
hotkeys = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({name, ...}: {
|
||||
options = {
|
||||
key = lib.mkOption {
|
||||
type = lib.types.strMatching "[a-zA-Z0-9-]+";
|
||||
default = builtins.replaceStrings [" " "/" "_"] ["-" "-" "-"] name;
|
||||
};
|
||||
name = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
};
|
||||
binding = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
command = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
home.packages = config.gnome.extensions;
|
||||
dconf = {
|
||||
settings = lib.mkMerge [
|
||||
{
|
||||
"org/gnome/shell" = {
|
||||
disable-user-extensions = false; # enables user extensions
|
||||
enabled-extensions = builtins.map (extension: extension.extensionUuid) config.gnome.extensions;
|
||||
};
|
||||
|
||||
"org/gnome/desktop/wm/preferences".button-layout = lib.mkIf config.gnome.extraWindowControls ":minimize,maximize,close";
|
||||
|
||||
"org/gnome/desktop/interface".color-scheme = config.gnome.colorScheme;
|
||||
"org/gnome/desktop/interface".accent-color = config.gnome.accentColor;
|
||||
"org/gnome/desktop/interface".clock-format = config.gnome.clockFormat;
|
||||
}
|
||||
(
|
||||
lib.mkMerge (
|
||||
builtins.map (value: let
|
||||
entry = "org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/${value.key}";
|
||||
in {
|
||||
${entry} = {
|
||||
binding = value.binding;
|
||||
command = value.command;
|
||||
name = value.name;
|
||||
};
|
||||
|
||||
"org/gnome/settings-daemon/plugins/media-keys" = {
|
||||
custom-keybindings = [
|
||||
"/${entry}/"
|
||||
];
|
||||
};
|
||||
})
|
||||
(
|
||||
lib.attrsets.mapAttrsToList (_: value: value) config.gnome.hotkeys
|
||||
)
|
||||
)
|
||||
)
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,29 +1,15 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
osConfig,
|
||||
...
|
||||
}: {
|
||||
options.programs.anki = {
|
||||
enable = lib.mkEnableOption "enable anki";
|
||||
};
|
||||
|
||||
config = lib.mkIf config.programs.anki.enable (lib.mkMerge [
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
anki
|
||||
config = lib.mkIf (config.programs.anki.enable && osConfig.host.impermanence.enable) {
|
||||
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||
directories = [
|
||||
"${config.xdg.dataHome}/Anki2/"
|
||||
];
|
||||
}
|
||||
(
|
||||
lib.mkIf osConfig.host.impermanence.enable {
|
||||
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||
directories = [
|
||||
"${config.xdg.dataHome}/Anki2/"
|
||||
];
|
||||
allowOther = true;
|
||||
};
|
||||
}
|
||||
)
|
||||
]);
|
||||
allowOther = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,6 +25,18 @@
|
|||
}
|
||||
];
|
||||
|
||||
# fixes issues with /var/lib/private not having the correct permissions https://github.com/nix-community/impermanence/issues/254
|
||||
system.activationScripts."createPersistentStorageDirs".deps = ["var-lib-private-permissions" "users" "groups"];
|
||||
system.activationScripts = {
|
||||
"var-lib-private-permissions" = {
|
||||
deps = ["specialfs"];
|
||||
text = ''
|
||||
mkdir -p /persist/system/root/var/lib/private
|
||||
chmod 0700 /persist/system/root/var/lib/private
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
programs.fuse.userAllowOther = true;
|
||||
|
||||
boot.initrd.postResumeCommands = lib.mkAfter ''
|
||||
|
|
|
@ -28,10 +28,6 @@
|
|||
};
|
||||
}))
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
# TODO: move this somewhere common
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/private 0700 root root"
|
||||
];
|
||||
environment.persistence."/persist/system/root" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
dnsPort = 53;
|
||||
in {
|
||||
options.host.adguardhome = {
|
||||
enable = lib.mkEnableOption "should home-assistant be enabled on this computer";
|
||||
directory = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/AdGuardHome/";
|
||||
};
|
||||
};
|
||||
config = lib.mkIf config.host.adguardhome.enable (lib.mkMerge [
|
||||
{
|
||||
services.adguardhome = {
|
||||
enable = true;
|
||||
mutableSettings = false;
|
||||
settings = {
|
||||
dns = {
|
||||
bootstrap_dns = [
|
||||
"1.1.1.1"
|
||||
"9.9.9.9"
|
||||
];
|
||||
upstream_dns = [
|
||||
"dns.quad9.net"
|
||||
];
|
||||
};
|
||||
filtering = {
|
||||
protection_enabled = true;
|
||||
filtering_enabled = true;
|
||||
|
||||
parental_enabled = false; # Parental control-based DNS requests filtering.
|
||||
safe_search = {
|
||||
enabled = false; # Enforcing "Safe search" option for search engines, when possible.
|
||||
};
|
||||
};
|
||||
# The following notation uses map
|
||||
# to not have to manually create {enabled = true; url = "";} for every filter
|
||||
# This is, however, fully optional
|
||||
filters =
|
||||
map (url: {
|
||||
enabled = true;
|
||||
url = url;
|
||||
}) [
|
||||
"https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt"
|
||||
"https://adguardteam.github.io/HostlistsRegistry/assets/filter_9.txt" # The Big List of Hacked Malware Web Sites
|
||||
"https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt" # malicious url blocklist
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
dnsPort
|
||||
];
|
||||
}
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
environment.persistence."/persist/system/root" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
{
|
||||
directory = config.host.adguardhome.directory;
|
||||
user = "adguardhome";
|
||||
group = "adguardhome";
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
|
@ -8,9 +8,10 @@
|
|||
./jellyfin.nix
|
||||
./forgejo.nix
|
||||
./searx.nix
|
||||
./virt-home-assistant.nix
|
||||
./adguardhome.nix
|
||||
./home-assistant.nix
|
||||
./wyoming.nix
|
||||
./immich.nix
|
||||
./qbittorent.nix
|
||||
./paperless.nix
|
||||
];
|
||||
}
|
||||
|
|
|
@ -16,20 +16,6 @@ in {
|
|||
failregex = "limiting requests, excess:.* by zone.*client: <HOST>"
|
||||
'')
|
||||
);
|
||||
# "fail2ban/filter.d/hass.local".text = lib.mkIf config.services.home-assistant.enable (
|
||||
# pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||
# [INCLUDES]
|
||||
# before = common.conf
|
||||
|
||||
# [Definition]
|
||||
# failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
|
||||
|
||||
# ignoreregex =
|
||||
|
||||
# [Init]
|
||||
# datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
|
||||
# '')
|
||||
# );
|
||||
};
|
||||
|
||||
services.fail2ban = {
|
||||
|
@ -61,16 +47,6 @@ in {
|
|||
bantime = 600;
|
||||
maxretry = 5;
|
||||
};
|
||||
# home-assistant-iptables.settings = lib.mkIf config.services.home-assistant.enable {
|
||||
# enabled = true;
|
||||
# filter = "hass";
|
||||
# action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||
# logpath = "${config.services.home-assistant.configDir}/*.log";
|
||||
# backend = "auto";
|
||||
# findtime = 600;
|
||||
# bantime = 600;
|
||||
# maxretry = 5;
|
||||
# };
|
||||
# TODO; figure out if there is any fail2ban things we can do on searx
|
||||
# searx-iptables.settings = lib.mkIf config.services.searx.enable {};
|
||||
};
|
||||
|
|
|
@ -28,6 +28,12 @@ in {
|
|||
extraUsers = {
|
||||
${db_user} = {
|
||||
isClient = true;
|
||||
createUser = true;
|
||||
};
|
||||
};
|
||||
extraDatabases = {
|
||||
${db_user} = {
|
||||
name = db_user;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,130 +1,229 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
inputs,
|
||||
...
|
||||
}: let
|
||||
configDir = "/var/lib/hass";
|
||||
dbUser = "hass";
|
||||
in {
|
||||
options.host.home-assistant = {
|
||||
enable = lib.mkEnableOption "should home-assistant be enabled on this computer";
|
||||
options.services.home-assistant = {
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "subdomain of base domain that home-assistant will be hosted at";
|
||||
default = "home-assistant";
|
||||
};
|
||||
|
||||
database = lib.mkOption {
|
||||
type = lib.types.enum [
|
||||
"builtin"
|
||||
"postgres"
|
||||
];
|
||||
description = "what database do we want to use";
|
||||
default = "builtin";
|
||||
};
|
||||
|
||||
extensions = {
|
||||
sonos = {
|
||||
enable = lib.mkEnableOption "enable the sonos plugin";
|
||||
port = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = 1400;
|
||||
description = "what port to use for sonos discovery";
|
||||
};
|
||||
};
|
||||
jellyfin = {
|
||||
enable = lib.mkEnableOption "enable the jellyfin plugin";
|
||||
};
|
||||
wyoming = {
|
||||
enable = lib.mkEnableOption "enable wyoming";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.host.home-assistant.enable (lib.mkMerge [
|
||||
config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [
|
||||
{
|
||||
virtualisation.libvirt = {
|
||||
swtpm.enable = true;
|
||||
connections."qemu:///session" = {
|
||||
networks = [
|
||||
{
|
||||
definition = inputs.nix-virt.lib.network.writeXML (inputs.nix-virt.lib.network.templates.bridge
|
||||
{
|
||||
uuid = "d57e37e2-311f-4e5c-a484-97c2210c2770";
|
||||
subnet_byte = 71;
|
||||
});
|
||||
active = true;
|
||||
}
|
||||
];
|
||||
domains = [
|
||||
{
|
||||
definition = inputs.nix-virt.lib.domain.writeXML (inputs.nix-virt.lib.domain.templates.linux
|
||||
{
|
||||
name = "Home Assistant";
|
||||
uuid = "c5cc0efc-6101-4c1d-be31-acbba203ccde";
|
||||
memory = {
|
||||
count = 4;
|
||||
unit = "GiB";
|
||||
};
|
||||
# storage_vol = {
|
||||
# pool = "MyPool";
|
||||
# volume = "Penguin.qcow2";
|
||||
# };
|
||||
});
|
||||
}
|
||||
];
|
||||
host = {
|
||||
reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = {
|
||||
target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
|
||||
|
||||
websockets.enable = true;
|
||||
forwardHeaders.enable = true;
|
||||
|
||||
extraConfig = ''
|
||||
add_header Upgrade $http_upgrade;
|
||||
add_header Connection \"upgrade\";
|
||||
|
||||
proxy_buffering off;
|
||||
|
||||
proxy_read_timeout 90;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# systemd.tmpfiles.rules = [
|
||||
# "f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
|
||||
# ];
|
||||
# services.home-assistant = {
|
||||
# enable = true;
|
||||
# configDir = configDir;
|
||||
# extraComponents = [
|
||||
# "met"
|
||||
# "radio_browser"
|
||||
# "isal"
|
||||
# "zha"
|
||||
# "jellyfin"
|
||||
# "webostv"
|
||||
# "tailscale"
|
||||
# "syncthing"
|
||||
# "sonos"
|
||||
# "analytics_insights"
|
||||
# "unifi"
|
||||
# "openweathermap"
|
||||
# ];
|
||||
# config = {
|
||||
# http = {
|
||||
# server_port = 8082;
|
||||
# use_x_forwarded_for = true;
|
||||
# trusted_proxies = ["127.0.0.1" "::1"];
|
||||
# ip_ban_enabled = true;
|
||||
# login_attempts_threshold = 10;
|
||||
# };
|
||||
# # recorder.db_url = "postgresql://@/${db_user}";
|
||||
# "automation manual" = [];
|
||||
# "automation ui" = "!include automations.yaml";
|
||||
# };
|
||||
# extraPackages = python3Packages:
|
||||
# with python3Packages; [
|
||||
# hassil
|
||||
# numpy
|
||||
# gtts
|
||||
# ];
|
||||
# };
|
||||
# host = {
|
||||
# reverse_proxy.subdomains.${config.host.home-assistant.subdomain} = {
|
||||
# target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
|
||||
services.home-assistant = {
|
||||
configDir = configDir;
|
||||
extraComponents = [
|
||||
"default_config"
|
||||
"esphome"
|
||||
"met"
|
||||
"radio_browser"
|
||||
"isal"
|
||||
"zha"
|
||||
"webostv"
|
||||
"tailscale"
|
||||
"syncthing"
|
||||
"analytics_insights"
|
||||
"unifi"
|
||||
"openweathermap"
|
||||
"ollama"
|
||||
"mobile_app"
|
||||
"logbook"
|
||||
"ssdp"
|
||||
"usb"
|
||||
"webhook"
|
||||
"bluetooth"
|
||||
"dhcp"
|
||||
"energy"
|
||||
"history"
|
||||
"backup"
|
||||
"assist_pipeline"
|
||||
"conversation"
|
||||
"sun"
|
||||
"zeroconf"
|
||||
"cpuspeed"
|
||||
];
|
||||
config = {
|
||||
http = {
|
||||
server_port = 8123;
|
||||
use_x_forwarded_for = true;
|
||||
trusted_proxies = ["127.0.0.1" "::1"];
|
||||
ip_ban_enabled = true;
|
||||
login_attempts_threshold = 10;
|
||||
};
|
||||
homeassistant = {
|
||||
external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}";
|
||||
# internal_url = "http://192.168.1.2:8123";
|
||||
};
|
||||
recorder.db_url = "postgresql://@/${dbUser}";
|
||||
"automation manual" = [];
|
||||
"automation ui" = "!include automations.yaml";
|
||||
mobile_app = {};
|
||||
};
|
||||
extraPackages = python3Packages:
|
||||
with python3Packages; [
|
||||
hassil
|
||||
numpy
|
||||
gtts
|
||||
];
|
||||
};
|
||||
|
||||
# websockets.enable = true;
|
||||
# forwardHeaders.enable = true;
|
||||
# TODO: configure /var/lib/hass/secrets.yaml via sops
|
||||
|
||||
# extraConfig = ''
|
||||
# add_header Upgrade $http_upgrade;
|
||||
# add_header Connection \"upgrade\";
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
1900
|
||||
];
|
||||
|
||||
# proxy_buffering off;
|
||||
|
||||
# proxy_read_timeout 90;
|
||||
# '';
|
||||
# };
|
||||
# };
|
||||
systemd.tmpfiles.rules = [
|
||||
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
|
||||
];
|
||||
}
|
||||
(lib.mkIf (config.services.home-assistant.extensions.sonos.enable) {
|
||||
services.home-assistant.extraComponents = ["sonos"];
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
config.services.home-assistant.extensions.sonos.port
|
||||
];
|
||||
})
|
||||
(lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) {
|
||||
services.home-assistant.extraComponents = ["jellyfin"];
|
||||
# TODO: configure port, address, and login information here
|
||||
})
|
||||
(lib.mkIf (config.services.home-assistant.extensions.wyoming.enable) {
|
||||
services.home-assistant.extraComponents = ["wyoming"];
|
||||
services.wyoming.enable = true;
|
||||
})
|
||||
(lib.mkIf (config.services.home-assistant.database == "postgres") {
|
||||
host = {
|
||||
postgres = {
|
||||
enable = true;
|
||||
extraUsers = {
|
||||
${dbUser} = {
|
||||
isClient = true;
|
||||
createUser = true;
|
||||
};
|
||||
};
|
||||
extraDatabases = {
|
||||
${dbUser} = {
|
||||
name = dbUser;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.home-assistant = {
|
||||
extraPackages = python3Packages:
|
||||
with python3Packages; [
|
||||
psycopg2
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services.home-assistant = {
|
||||
requires = [
|
||||
config.systemd.services.postgresql.name
|
||||
];
|
||||
};
|
||||
})
|
||||
(lib.mkIf config.services.fail2ban.enable {
|
||||
environment.etc = {
|
||||
"fail2ban/filter.d/hass.local".text = lib.mkIf config.services.home-assistant.enable (
|
||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||
[INCLUDES]
|
||||
before = common.conf
|
||||
|
||||
[Definition]
|
||||
failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
|
||||
|
||||
ignoreregex =
|
||||
|
||||
[Init]
|
||||
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
|
||||
'')
|
||||
);
|
||||
};
|
||||
|
||||
services.fail2ban = {
|
||||
jails = {
|
||||
home-assistant-iptables.settings = lib.mkIf config.services.home-assistant.enable {
|
||||
enabled = true;
|
||||
filter = "hass";
|
||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||
logpath = "${config.services.home-assistant.configDir}/*.log";
|
||||
backend = "auto";
|
||||
findtime = 600;
|
||||
bantime = 600;
|
||||
maxretry = 5;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
# assertions = [
|
||||
# {
|
||||
# assertion = config.services.home-assistant.configDir == configDir;
|
||||
# message = "home assistant config directory does not match persistence";
|
||||
# }
|
||||
# ];
|
||||
# environment.persistence."/persist/system/root" = {
|
||||
# enable = true;
|
||||
# hideMounts = true;
|
||||
# directories = [
|
||||
# {
|
||||
# directory = configDir;
|
||||
# user = "hass";
|
||||
# group = "hass";
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.services.home-assistant.configDir == configDir;
|
||||
message = "home assistant config directory does not match persistence";
|
||||
}
|
||||
];
|
||||
environment.persistence."/persist/system/root" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
{
|
||||
directory = configDir;
|
||||
user = "hass";
|
||||
group = "hass";
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ in {
|
|||
}
|
||||
(lib.mkIf config.services.fail2ban.enable {
|
||||
environment.etc = {
|
||||
"fail2ban/filter.d/jellyfin.local".text = lib.mkIf config.services.jellyfin.enable (
|
||||
"fail2ban/filter.d/jellyfin.local".text = (
|
||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||
[Definition]
|
||||
failregex = "^.*Authentication request for .* has been denied \\\(IP: \"<ADDR>\"\\\)\\\."
|
||||
|
@ -65,7 +65,7 @@ in {
|
|||
|
||||
services.fail2ban = {
|
||||
jails = {
|
||||
jellyfin-iptables.settings = lib.mkIf config.services.jellyfin.enable {
|
||||
jellyfin-iptables.settings = {
|
||||
enabled = true;
|
||||
filter = "jellyfin";
|
||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||
|
|
110
modules/nixos-modules/server/paperless.nix
Normal file
110
modules/nixos-modules/server/paperless.nix
Normal file
|
@ -0,0 +1,110 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
dataDir = "/var/lib/paperless";
|
||||
in {
|
||||
options.services.paperless = {
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "subdomain of base domain that paperless will be hosted at";
|
||||
default = "paperless";
|
||||
};
|
||||
database = {
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "what is the user and database that we are going to use for paperless";
|
||||
default = "paperless";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.services.paperless.enable (lib.mkMerge [
|
||||
{
|
||||
host = {
|
||||
reverse_proxy.subdomains.${config.services.paperless.subdomain} = {
|
||||
target = "http://${config.services.paperless.address}:${toString config.services.paperless.port}";
|
||||
|
||||
websockets.enable = true;
|
||||
forwardHeaders.enable = true;
|
||||
|
||||
extraConfig = ''
|
||||
# allow large file uploads
|
||||
client_max_body_size 50000M;
|
||||
'';
|
||||
};
|
||||
postgres = {
|
||||
enable = true;
|
||||
extraUsers = {
|
||||
${config.services.paperless.database.user} = {
|
||||
isClient = true;
|
||||
createUser = true;
|
||||
};
|
||||
};
|
||||
extraDatabases = {
|
||||
${config.services.paperless.database.user} = {
|
||||
name = config.services.paperless.database.user;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
services.paperless = {
|
||||
configureTika = true;
|
||||
settings = {
|
||||
PAPERLESS_URL = "https://${config.services.paperless.subdomain}.${config.host.reverse_proxy.hostname}";
|
||||
|
||||
PAPERLESS_DBENGINE = "postgresql";
|
||||
PAPERLESS_DBHOST = "/run/postgresql";
|
||||
PAPERLESS_DBNAME = config.services.paperless.database.user;
|
||||
PAPERLESS_DBUSER = config.services.paperless.database.user;
|
||||
};
|
||||
};
|
||||
}
|
||||
(lib.mkIf config.services.fail2ban.enable {
|
||||
environment.etc = {
|
||||
"fail2ban/filter.d/paperless.local".text = (
|
||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||
[Definition]
|
||||
failregex = Login failed for user `.*` from (?:IP|private IP) `<HOST>`\.$
|
||||
ignoreregex =
|
||||
|
||||
'')
|
||||
);
|
||||
};
|
||||
|
||||
services.fail2ban = {
|
||||
jails = {
|
||||
paperless.settings = {
|
||||
enabled = true;
|
||||
filter = "paperless";
|
||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||
logpath = "${config.services.paperless.dataDir}/log/*.log";
|
||||
backend = "auto";
|
||||
findtime = 600;
|
||||
bantime = 600;
|
||||
maxretry = 5;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = config.services.paperless.dataDir == dataDir;
|
||||
message = "paperless data location does not match persistence";
|
||||
}
|
||||
];
|
||||
environment.persistence."/persist/system/root" = {
|
||||
directories = [
|
||||
{
|
||||
directory = dataDir;
|
||||
user = "paperless";
|
||||
group = "paperless";
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
...
|
||||
}: {
|
||||
options.host.podman = {
|
||||
enable = lib.mkEnableOption "should home-assistant be enabled on this computer";
|
||||
enable = lib.mkEnableOption "should podman be enabled on this computer";
|
||||
macvlan = {
|
||||
subnet = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: {
|
||||
options.services.virt-home-assistant = {
|
||||
enable = lib.mkEnableOption "Wether to enable home assistant virtual machine";
|
||||
networkBridge = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "what network bridge should we attach to the image";
|
||||
};
|
||||
hostDevice = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "what host devices should be attached to the image";
|
||||
};
|
||||
initialVersion = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "what home assistant image version should we pull for initial instal";
|
||||
default = "15.0";
|
||||
};
|
||||
imageName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "where should the image be installed to";
|
||||
default = "home-assistant.qcow2";
|
||||
};
|
||||
installLocation = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "where should the image be installed to";
|
||||
default = "/etc/hass";
|
||||
};
|
||||
virtualMachineName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "what name should we give the virtual machine";
|
||||
default = "home-assistant";
|
||||
};
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "subdomain of base domain that home-assistant will be hosted at";
|
||||
default = "home-assistant";
|
||||
};
|
||||
};
|
||||
config = lib.mkIf config.services.virt-home-assistant.enable (lib.mkMerge [
|
||||
{
|
||||
# environment.systemPackages = with pkgs; [
|
||||
# virt-manager
|
||||
# ];
|
||||
|
||||
# TODO: move this to external module and just have an assertion here that its enabled
|
||||
# enable virtualization on the system
|
||||
virtualisation = {
|
||||
libvirtd = {
|
||||
enable = true;
|
||||
qemu.ovmf.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
# TODO: deactivation script?
|
||||
# create service to install and start the container
|
||||
systemd.services.virt-install-home-assistant = let
|
||||
# TODO: all of these need to be escaped to be used in commands reliably
|
||||
bridgedNetwork = config.services.virt-home-assistant.networkBridge;
|
||||
hostDevice = config.services.virt-home-assistant.hostDevice;
|
||||
virtualMachineName = config.services.virt-home-assistant.virtualMachineName;
|
||||
imageName = config.services.virt-home-assistant.imageName;
|
||||
installLocation = config.services.virt-home-assistant.installLocation;
|
||||
installImage = "${installLocation}/${imageName}";
|
||||
initialVersion = config.services.virt-home-assistant.initialVersion;
|
||||
|
||||
home-assistant-qcow2 = pkgs.fetchurl {
|
||||
name = "home-assistant.qcow2";
|
||||
url = "https://github.com/home-assistant/operating-system/releases/download/${initialVersion}/haos_ova-${initialVersion}.qcow2.xz";
|
||||
hash = "sha256-V1BEjvvLNbMMKJVyMCmipjQ/3owoJteeVxoF9LDHo1U=";
|
||||
postFetch = ''
|
||||
cp $out src.xz
|
||||
rm -r $out
|
||||
${pkgs.xz}/bin/unxz src.xz --stdout > $out/${imageName}
|
||||
'';
|
||||
};
|
||||
|
||||
# Write a script to install the Home Assistant OS qcow2 image
|
||||
virtInstallScript = pkgs.writeShellScriptBin "virt-install-hass" ''
|
||||
# Copy the initial image out of the package store to the install location if we don't have one yet
|
||||
if [ ! -f ${installImage} ]; then
|
||||
cp ${home-assistant-qcow2} ${installLocation}
|
||||
fi
|
||||
|
||||
# Check if VM already exists, and other pre-conditions
|
||||
if ! ${pkgs.libvirt}/bin/virsh list --all | grep -q ${virtualMachineName}; then
|
||||
${pkgs.virt-manager}/bin/virt-install --name ${virtualMachineName} \
|
||||
--description "Home Assistant OS" \
|
||||
--os-variant=generic \
|
||||
--boot uefi \
|
||||
--ram=2048 \
|
||||
--vcpus=2 \
|
||||
--import \
|
||||
--disk ${installImage},bus=sata \
|
||||
--network bridge=${bridgedNetwork} \
|
||||
--host-device ${hostDevice} \
|
||||
--graphics none
|
||||
${pkgs.libvirt}/bin/virsh autostart ${virtualMachineName}
|
||||
fi
|
||||
'';
|
||||
in {
|
||||
description = "Install and start Home Assistant";
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["local-fs.target"];
|
||||
requires = ["libvirtd.service"];
|
||||
serviceConfig.Type = "oneshot";
|
||||
serviceConfig = {
|
||||
ExecStart = "${virtInstallScript}/bin/virt-install-hass";
|
||||
};
|
||||
};
|
||||
|
||||
# TODO: figure out what we need to proxy to the virtual image
|
||||
# host = {
|
||||
# reverse_proxy.subdomains.${config.services.virt-home-assistant.subdomain} = {
|
||||
# target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
|
||||
|
||||
# websockets.enable = true;
|
||||
# forwardHeaders.enable = true;
|
||||
|
||||
# extraConfig = ''
|
||||
# add_header Upgrade $http_upgrade;
|
||||
# add_header Connection \"upgrade\";
|
||||
|
||||
# proxy_buffering off;
|
||||
|
||||
# proxy_read_timeout 90;
|
||||
# '';
|
||||
# };
|
||||
# };
|
||||
}
|
||||
(lib.mkIf config.services.fail2ban.enable {
|
||||
# TODO: figure out how to write a config for this, prob based on nginx proxy logs?
|
||||
})
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
# assertions = [
|
||||
# {
|
||||
# assertion = config.services.virt-home-assistant.installLocation == configDir;
|
||||
# message = "home assistant install location does not match persistence";
|
||||
# }
|
||||
# ];
|
||||
environment.persistence."/persist/system/root" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
{
|
||||
directory = config.services.virt-home-assistant.installLocation;
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
63
modules/nixos-modules/server/wyoming.nix
Normal file
63
modules/nixos-modules/server/wyoming.nix
Normal file
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: {
|
||||
options.services.wyoming.enable = lib.mkEnableOption "should wyoming be enabled on this device";
|
||||
config = lib.mkIf config.services.wyoming.enable (lib.mkMerge [
|
||||
{
|
||||
services.wyoming = {
|
||||
# Text to speech
|
||||
piper = {
|
||||
servers = {
|
||||
"en" = {
|
||||
enable = true;
|
||||
# see https://github.com/rhasspy/rhasspy3/blob/master/programs/tts/piper/script/download.py
|
||||
voice = "en-us-amy-low";
|
||||
uri = "tcp://0.0.0.0:10200";
|
||||
speaker = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Speech to text
|
||||
faster-whisper = {
|
||||
servers = {
|
||||
"en" = {
|
||||
enable = true;
|
||||
# see https://github.com/rhasspy/rhasspy3/blob/master/programs/asr/faster-whisper/script/download.py
|
||||
model = "tiny-int8";
|
||||
language = "en";
|
||||
uri = "tcp://0.0.0.0:10300";
|
||||
device = "cpu";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
openwakeword = {
|
||||
enable = true;
|
||||
uri = "tcp://0.0.0.0:10400";
|
||||
preloadModels = [
|
||||
"ok_nabu"
|
||||
];
|
||||
# TODO: custom models
|
||||
};
|
||||
};
|
||||
|
||||
# needs access to /proc/cpuinfo
|
||||
systemd.services."wyoming-faster-whisper-en".serviceConfig.ProcSubset = lib.mkForce "all";
|
||||
}
|
||||
(lib.mkIf config.host.impermanence.enable {
|
||||
environment.persistence."/persist/system/root" = {
|
||||
enable = true;
|
||||
hideMounts = true;
|
||||
directories = [
|
||||
{
|
||||
directory = "/var/lib/private/wyoming";
|
||||
mode = "0700";
|
||||
}
|
||||
];
|
||||
};
|
||||
})
|
||||
]);
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
git = 2009;
|
||||
immich = 2010;
|
||||
qbittorrent = 2011;
|
||||
paperless = 2012;
|
||||
};
|
||||
|
||||
gids = {
|
||||
|
@ -40,6 +41,7 @@
|
|||
git = 2009;
|
||||
immich = 2010;
|
||||
qbittorrent = 2011;
|
||||
paperless = 2012;
|
||||
};
|
||||
|
||||
users = config.users.users;
|
||||
|
@ -169,6 +171,12 @@ in {
|
|||
isNormalUser = true;
|
||||
group = config.users.users.qbittorrent.name;
|
||||
};
|
||||
|
||||
paperless = {
|
||||
uid = lib.mkForce uids.paperless;
|
||||
isSystemUser = true;
|
||||
group = config.users.users.paperless.name;
|
||||
};
|
||||
};
|
||||
|
||||
groups = {
|
||||
|
@ -273,6 +281,13 @@ in {
|
|||
leyla
|
||||
];
|
||||
};
|
||||
|
||||
paperless = {
|
||||
gid = lib.mkForce gids.paperless;
|
||||
members = [
|
||||
users.paperless.name
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 1c5c059c0c7b6ce691993262fe10a2b63e1c31ba
|
||||
Subproject commit f016767c13aa36dde91503f7a9f01bdd02468045
|
|
@ -65,7 +65,7 @@ flake=${flake:-$target}
|
|||
mode=${mode:-switch}
|
||||
user=${user:-$USER}
|
||||
|
||||
command="nixos-rebuild $mode --use-remote-sudo --ask-sudo-password --flake .#$flake"
|
||||
command="nixos-rebuild $mode --sudo --ask-sudo-password --flake .#$flake"
|
||||
|
||||
if [[ $host ]];
|
||||
then
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue