Compare commits
3 Commits
master
...
laptopshit
Author | SHA1 | Date | |
---|---|---|---|
3a28439153 | |||
2c66c51224 | |||
|
91dd406c3e |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,7 +1,3 @@
|
||||
result
|
||||
result/
|
||||
|
||||
.aider*
|
||||
.env
|
||||
|
||||
**/.claude/settings.local.json
|
||||
|
15
README.md
15
README.md
@ -1,15 +0,0 @@
|
||||
# Nix Flake README
|
||||
|
||||
This Nix Flake defines the NixOS configurations and Home-Manager configurations for my personal systems.
|
||||
|
||||
## NixOS Configurations
|
||||
|
||||
- `architect`
|
||||
- `gAluminum`
|
||||
|
||||
## Home-Manager Configurations
|
||||
|
||||
- `giulioMac`
|
||||
- `giulioAarch`
|
||||
- `giulioX64`
|
||||
- `giulioX64NoSSH`
|
@ -9,5 +9,6 @@ let
|
||||
imports = lib.mapAttrsToList toImport (lib.filterAttrs filterCaches (builtins.readDir folder));
|
||||
in {
|
||||
inherit imports;
|
||||
nix.settings.substituters = ["https://cache.nixos.org/"];
|
||||
nix.binaryCaches = ["https://cache.nixos.org/"];
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
|
||||
{
|
||||
nix = {
|
||||
settings = {
|
||||
substituters = [
|
||||
"https://nix-community.cachix.org"
|
||||
];
|
||||
trusted-public-keys = [
|
||||
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
12
cachix/ropfuscator.nix
Normal file
12
cachix/ropfuscator.nix
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
{
|
||||
nix = {
|
||||
binaryCaches = [
|
||||
"https://ropfuscator.cachix.org"
|
||||
];
|
||||
binaryCachePublicKeys = [
|
||||
"ropfuscator.cachix.org-1:LZ03aJ1yqFlxpU+wfGhLlOkA3MwXqnntd2Wk7u2LnHQ="
|
||||
];
|
||||
};
|
||||
}
|
||||
|
317
flake.lock
generated
317
flake.lock
generated
@ -1,348 +1,63 @@
|
||||
{
|
||||
"nodes": {
|
||||
"agenix-flake": {
|
||||
"inputs": {
|
||||
"darwin": "darwin",
|
||||
"home-manager": "home-manager",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1754433428,
|
||||
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"darwin": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"agenix-flake",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1744478979,
|
||||
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
|
||||
"owner": "lnl7",
|
||||
"repo": "nix-darwin",
|
||||
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "lnl7",
|
||||
"ref": "master",
|
||||
"repo": "nix-darwin",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"agenix-flake",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1745494811,
|
||||
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
|
||||
"owner": "nix-community",
|
||||
"lastModified": 1639871969,
|
||||
"narHash": "sha256-6feWUnMygRzA9tzkrfAzpA5/NBYg75bkFxnqb1DtD7E=",
|
||||
"owner": "rycee",
|
||||
"repo": "home-manager",
|
||||
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
|
||||
"rev": "697cc8c68ed6a606296efbbe9614c32537078756",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"owner": "rycee",
|
||||
"ref": "release-21.11",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager_2": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753592768,
|
||||
"narHash": "sha256-oV695RvbAE4+R9pcsT9shmp6zE/+IZe6evHWX63f2Qg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "fc3add429f21450359369af74c2375cb34a2d204",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.05",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"langtool-ngrams": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1752491272,
|
||||
"narHash": "sha256-lEGxYHo1Q7qBj0tiMGPAhZC0u1lBEP14UanKFRiIhhc=",
|
||||
"owner": "peperunas",
|
||||
"repo": "nix-languagetool-ngram",
|
||||
"rev": "10725a39dc6b9ba2dcd8cfe59abe6a7e1a62b503",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "peperunas",
|
||||
"repo": "nix-languagetool-ngram",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"local-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 0,
|
||||
"narHash": "sha256-eCA4jXsPHiBkrf1sNOfQPYS2g9DoCsICVzk4ec0cEdo=",
|
||||
"path": "/home/giulio/dev/nixpkgs",
|
||||
"type": "path"
|
||||
},
|
||||
"original": {
|
||||
"path": "/home/giulio/dev/nixpkgs",
|
||||
"type": "path"
|
||||
}
|
||||
},
|
||||
"nixos-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1754214453,
|
||||
"narHash": "sha256-Q/I2xJn/j1wpkGhWkQnm20nShYnG7TI99foDBpXm1SY=",
|
||||
"lastModified": 1639699734,
|
||||
"narHash": "sha256-tlX6WebGmiHb2Hmniff+ltYp+7dRfdsBxw9YczLsP60=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5b09dc45f24cf32316283e62aec81ffee3c3e376",
|
||||
"rev": "03ec468b14067729a285c2c7cfa7b9434a04816c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5b09dc45f24cf32316283e62aec81ffee3c3e376",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1754028485,
|
||||
"narHash": "sha256-IiiXB3BDTi6UqzAZcf2S797hWEPCRZOwyNThJIYhUfk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "59e69648d345d6e8fef86158c555730fa12af9de",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-master": {
|
||||
"locked": {
|
||||
"lastModified": 1754468877,
|
||||
"narHash": "sha256-4f2CMXEM6PtLcfIC5Emo4pYaj+yLizWEQAekSwy4gzQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5b7d804f77c2e9e89ddd527ed6a5e5bf77f0a826",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "master",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1751984180,
|
||||
"narHash": "sha256-LwWRsENAZJKUdD3SpLluwDmdXY9F45ZEgCb0X+xgOL0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9807714d6944a957c2e036f84b0ff8caf9930bc0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1754292888,
|
||||
"narHash": "sha256-1ziydHSiDuSnaiPzCQh1mRFBsM2d2yRX9I+5OPGEmIE=",
|
||||
"lastModified": 1639794673,
|
||||
"narHash": "sha256-bjauV0+Z4WmxeiHXecyiEOEwo+XysO6kx36beeatbl0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ce01daebf8489ba97bd1609d185ea276efdeb121",
|
||||
"rev": "2627c4b795107ba94562626925f5a9a2bc62ebc6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "ce01daebf8489ba97bd1609d185ea276efdeb121",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1735264675,
|
||||
"narHash": "sha256-MgdXpeX2GuJbtlBrH9EdsUeWl/yXEubyvxM1G+yO4Ak=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d49da4c08359e3c39c4e27c74ac7ac9b70085966",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-24.11",
|
||||
"ref": "nixos-21.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nvidia-patch": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"utils": "utils"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1753078133,
|
||||
"narHash": "sha256-z+cvobe/+6pSVmwVrI+/k4lt7CjsQtfhlMaAlLQcSPY=",
|
||||
"owner": "icewind1991",
|
||||
"repo": "nvidia-patch-nixos",
|
||||
"rev": "b5bb7576a5a951cea1a46703f488ac76fa827876",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "icewind1991",
|
||||
"repo": "nvidia-patch-nixos",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pepeflake": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1739457875,
|
||||
"narHash": "sha256-ak7EyrCKa79mZjr98PE1lFBj3UuDDIIpaYtky1MN2a0=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "249e02c5c915fed09c448092d9066257317a4d68",
|
||||
"revCount": 10,
|
||||
"type": "git",
|
||||
"url": "https://git.giugl.io/peperunas/pepeflake"
|
||||
},
|
||||
"original": {
|
||||
"type": "git",
|
||||
"url": "https://git.giugl.io/peperunas/pepeflake"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"agenix-flake": "agenix-flake",
|
||||
"home-manager": "home-manager_2",
|
||||
"langtool-ngrams": "langtool-ngrams",
|
||||
"local-unstable": "local-unstable",
|
||||
"home-manager": "home-manager",
|
||||
"nixos-unstable": "nixos-unstable",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"nixpkgs-master": "nixpkgs-master",
|
||||
"nvidia-patch": "nvidia-patch",
|
||||
"pepeflake": "pepeflake"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_3": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
122
flake.nix
122
flake.nix
@ -1,108 +1,62 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/ce01daebf8489ba97bd1609d185ea276efdeb121";
|
||||
nixos-unstable.url = "github:NixOS/nixpkgs/5b09dc45f24cf32316283e62aec81ffee3c3e376";
|
||||
nixpkgs-master.url = "github:NixOS/nixpkgs/master";
|
||||
local-unstable.url = "path:///home/giulio/dev/nixpkgs";
|
||||
pepeflake.url = "git+https://git.giugl.io/peperunas/pepeflake";
|
||||
agenix-flake.url = "github:ryantm/agenix";
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.11";
|
||||
nixos-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager/release-25.05";
|
||||
url = "github:rycee/home-manager/release-21.11";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nvidia-patch = {
|
||||
url = "github:icewind1991/nvidia-patch-nixos";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
langtool-ngrams.url = "github:peperunas/nix-languagetool-ngram";
|
||||
navidrome.url = "github:antifuchs/nixpkgs/fix-151550";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self
|
||||
, nixpkgs
|
||||
, nixos-unstable
|
||||
, nixpkgs-master
|
||||
, local-unstable
|
||||
, home-manager
|
||||
, nvidia-patch
|
||||
, agenix-flake
|
||||
, pepeflake
|
||||
, langtool-ngrams
|
||||
}:
|
||||
outputs = inputs@{ self, nixpkgs, nixos-unstable, home-manager, navidrome}:
|
||||
let
|
||||
sysLinuxX64 = "x86_64-linux";
|
||||
sysDarwin = "aarch64-darwin";
|
||||
sysLinuxAarch = "aarch64-linux";
|
||||
forAllSystems = nixpkgs.lib.genAttrs [ sysLinuxX64 sysLinuxAarch sysDarwin ];
|
||||
system = "x86_64-linux";
|
||||
|
||||
mkSystem = (import ./lib/systems.nix {
|
||||
inherit nixpkgs;
|
||||
inputs = {
|
||||
inherit nixos-unstable nixpkgs-master local-unstable
|
||||
agenix-flake pepeflake langtool-ngrams
|
||||
nvidia-patch home-manager;
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
overlays = [ (final: prev: { inherit unstable; }) ];
|
||||
};
|
||||
}).mkSystem;
|
||||
|
||||
linuxX64Cuda = mkSystem { system = sysLinuxX64; cudaSupport = true; };
|
||||
linuxAarch = mkSystem { system = sysLinuxAarch; };
|
||||
darwin = mkSystem { system = sysDarwin; };
|
||||
in
|
||||
{
|
||||
unstable = import nixos-unstable {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
|
||||
utils = import ./lib {
|
||||
inherit pkgs unstable nixpkgs nixos-unstable home-manager;
|
||||
};
|
||||
|
||||
inherit (utils) host;
|
||||
inherit (utils) user;
|
||||
in {
|
||||
nixosConfigurations = {
|
||||
architect = linuxX64Cuda.utils.host.mkHost {
|
||||
architect = host.mkHost {
|
||||
name = "architect";
|
||||
users = [{
|
||||
user = "giulio";
|
||||
roles = [ ];
|
||||
}];
|
||||
imports = [
|
||||
agenix-flake.nixosModules.default
|
||||
{
|
||||
disabledModules = [ "services/audio/navidrome.nix" ];
|
||||
imports =
|
||||
[ (navidrome + "/nixos/modules/services/audio/navidrome.nix") ];
|
||||
}
|
||||
];
|
||||
};
|
||||
gAluminum = host.mkHost {
|
||||
name = "gAluminum";
|
||||
users = [{
|
||||
user = "giulio";
|
||||
roles = [ "desktop" "ssh" "git" ];
|
||||
}];
|
||||
roles = [ "gnome" ];
|
||||
};
|
||||
|
||||
homeConfigurations = {
|
||||
giulioMac = darwin.utils.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" ];
|
||||
};
|
||||
gdepasqualeMac = darwin.utils.user.mkHMUser {
|
||||
name = "gdepasquale";
|
||||
roles = [ "ssh" ];
|
||||
};
|
||||
giulioAarch = linuxAarch.utils.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" ];
|
||||
};
|
||||
giulioX64 = linuxX64Cuda.utils.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" "go" ];
|
||||
};
|
||||
giulioX64NoSSH = linuxX64Cuda.utils.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "go" ];
|
||||
};
|
||||
gdepasqualeX64 = linuxX64Cuda.utils.user.mkHMUser {
|
||||
name = "gdepasquale";
|
||||
roles = [ "ssh" "go" ];
|
||||
};
|
||||
};
|
||||
|
||||
packages = forAllSystems (system:
|
||||
let pkgs = nixpkgs.legacyPackages.${system}; in rec {
|
||||
default = update;
|
||||
|
||||
update = pkgs.callPackage ./update.nix { };
|
||||
});
|
||||
|
||||
|
||||
|
||||
defaultTemplate = self.templates.basicShell;
|
||||
templates = {
|
||||
basicShell = {
|
||||
path = ./templates/basicShell;
|
||||
description = "A barebone shell with custom defined packages";
|
||||
proxy = host.mkHost {
|
||||
name = "proxy";
|
||||
users = [ ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -1,25 +1,13 @@
|
||||
{ config, ... }:
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
age.secrets = {
|
||||
restic-passwords = {
|
||||
file = ../../secrets/restic-passwords.age;
|
||||
};
|
||||
restic-environment = {
|
||||
file = ../../secrets/restic-environment.age;
|
||||
};
|
||||
};
|
||||
|
||||
services.restic.backups = {
|
||||
backblaze = {
|
||||
initialize = true;
|
||||
passwordFile = config.age.secrets.restic-passwords.path;
|
||||
environmentFile = config.age.secrets.restic-environment.path;
|
||||
passwordFile = "/secrets/restic/data.key";
|
||||
environmentFile = "/secrets/restic/credentials.txt";
|
||||
repository = "b2:architect:/";
|
||||
paths = [ "/var/lib" "/services" ];
|
||||
exclude = [
|
||||
"/var/lib/ollama"
|
||||
];
|
||||
paths = [ "/var/lib" "/secrets" ];
|
||||
pruneOpts = [
|
||||
"--keep-daily 45"
|
||||
"--keep-weekly 12"
|
||||
@ -27,8 +15,8 @@
|
||||
"--keep-yearly 3"
|
||||
];
|
||||
timerConfig = {
|
||||
OnCalendar = "monday 09:00";
|
||||
RandomizedDelaySec = "1h";
|
||||
OnCalendar = "monday 00:05";
|
||||
RandomizedDelaySec = "2h";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
33
hosts/architect/bazarr.nix
Normal file
33
hosts/architect/bazarr.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htbaz.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
bazarr = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:6767";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "bazarr" ];
|
||||
}
|
6
hosts/architect/ccache.nix
Normal file
6
hosts/architect/ccache.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
programs.ccache.enable = true;
|
||||
nix.extraOptions = ''
|
||||
extra-sandbox-paths = /nix/var/cache/ccache
|
||||
'';
|
||||
}
|
@ -1,39 +1,59 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
macbookPubkey = (import ../pubkeys.nix).macbook;
|
||||
pubkeys = [ macbookPubkey ];
|
||||
domain = "devs.giugl.io";
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./options.nix
|
||||
pubkeys = [
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1we38/N+t8Ah5yrLof8QUwhrob7/VXFKIddaJeOVBLuDVnW7ljiAtdtEiL69D/DV4Ohmt5wMvkAAjfuHmim6FD9A6lzPbSU4KH9W2dcckszKbbI636kuDwem/xui6BW3wJa6P+0xW5ksygEAkzcK2PXuC2b4B9uwhuUdKahiGMKDxISG/WianqAe72cGMfNkYvion3Y1VsMLUdm48d2ABnxNpr7NI9B5iJ8dziOft9gpgfz13CCQRlReo75gk/4xI+vSNrQp7eR+wzJy2/dZg/T8jtyA9Q6jVxrxBpqQ1LNXkAKaJkGo9OabF6Wgpzp+YTAurL4nwR2NaJxwFuyoKvACQy0ai4jrS3206gC6JXZv8ktZMZrwUN+jPqCwfgh5qObFkAqKCxbp52ioDek2MQLdOvzQBX//DBhGEp5rzHGLZ3vhRIiiQiaof5sF5zWiYDW5mqezSPNxJPX/BrTP/Wbs/jpwTLBh3wytiia0S1WXQmya89bqzTPFiDWvTRA62EVKB/JaQtPQQOFAxWwg799DMycPeZ81xttZOyMtI/MZSddyqx2S8fWGwvToZQvuZ38mSIpFseLM1IkgabRIrAmat5SBNGGy9Dqa0eMEa7bwIY/4CMB1y6HMTnaoMXA6cnQfHMoB/zyTZ6oTXIeqeOyiZsK+RN0Mvahj8mXi7dw== giulio@giulio-X230"
|
||||
];
|
||||
hostname = "architect";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
imports = [ # Include the results of the hardware scan.
|
||||
./backup.nix
|
||||
./hardware.nix
|
||||
./firewall.nix
|
||||
./nginx.nix
|
||||
./gitea.nix
|
||||
./sonarr.nix
|
||||
./radarr.nix
|
||||
./bazarr.nix
|
||||
./nzbget.nix
|
||||
./nextcloud.nix
|
||||
./wireguard.nix
|
||||
./minio.nix
|
||||
./matrix.nix
|
||||
./fail2ban.nix
|
||||
./dns.nix
|
||||
./tailscale.nix
|
||||
./sunshine.nix
|
||||
./postgres.nix
|
||||
./searx.nix
|
||||
#./minecraft.nix
|
||||
./prowlarr.nix
|
||||
./plex.nix
|
||||
./githubrunner.nix
|
||||
./libreddit.nix
|
||||
./invidious.nix
|
||||
./nitter.nix
|
||||
./ccache.nix
|
||||
./lidarr.nix
|
||||
./navidrome.nix
|
||||
./jellyfin.nix
|
||||
./prosody.nix
|
||||
./deluge.nix
|
||||
];
|
||||
|
||||
age.identityPaths = [ "/root/.ssh/id_ed25519" ];
|
||||
|
||||
architect = {
|
||||
|
||||
firewall = {
|
||||
openTCP = [ 22 ];
|
||||
};
|
||||
};
|
||||
|
||||
time.timeZone = "Europe/London";
|
||||
time.timeZone = "Europe/Rome";
|
||||
system.stateVersion = "21.11"; # Did you read the comment?
|
||||
users.users.giulio.openssh.authorizedKeys.keys = pubkeys;
|
||||
|
||||
services.fwupd.enable = true;
|
||||
boot = {
|
||||
kernelParams = [
|
||||
"ip=${network.architect-lan}::10.0.0.1:255.255.255.0::${network.wan-if}:off"
|
||||
"nvme_core.default_ps_max_latency_us=5500"
|
||||
];
|
||||
|
||||
kernel.sysctl= {
|
||||
"net.ipv4.ip_forward" = 1;
|
||||
"fs.protected_regular" = 0;
|
||||
};
|
||||
|
||||
initrd = {
|
||||
availableKernelModules = [ "igc" "r8169" ];
|
||||
network = {
|
||||
@ -41,18 +61,20 @@ in
|
||||
ssh = {
|
||||
enable = true;
|
||||
port = 22;
|
||||
hostKeys = [ /secrets/ssh_host_rsa_key ];
|
||||
hostKeys = [ /boot/ssh_host_rsa_key ];
|
||||
authorizedKeys = pubkeys;
|
||||
};
|
||||
|
||||
postCommands = ''
|
||||
zpool import backedpool
|
||||
zpool import zpool
|
||||
|
||||
mkdir /mnt-root
|
||||
echo "zfs load-key -ar; mount -t zfs zpool/nixos/root /mnt-root; zfs load-key -a; umount /mnt-root; rmdir /mnt-root; killall zfs" >> /root/.profile
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
kernelParams = with config.pepe.core.network.interfaces.lan; [
|
||||
"ip=${devices.architect.address}::${devices.brigettine.address}:255.255.255.0::${interface}:off"
|
||||
];
|
||||
|
||||
kernel.sysctl = { "net.ipv4.ip_forward" = 1; };
|
||||
|
||||
loader = {
|
||||
systemd-boot ={
|
||||
enable = true;
|
||||
@ -63,169 +85,71 @@ in
|
||||
|
||||
supportedFilesystems = [ "zfs" ];
|
||||
zfs.requestEncryptionCredentials = true;
|
||||
tmp.tmpfsSize = "50%";
|
||||
tmpOnTmpfsSize = "80%";
|
||||
};
|
||||
|
||||
networking = with config.pepe.core.network.interfaces.lan; {
|
||||
hostName = "architect";
|
||||
networking = {
|
||||
hostName = hostname;
|
||||
hostId = "49350853";
|
||||
useDHCP = false;
|
||||
defaultGateway = devices.brigettine.address;
|
||||
defaultGateway = "10.0.0.1";
|
||||
interfaces = {
|
||||
${interface}.ipv4.addresses = [{
|
||||
address = devices.architect.address;
|
||||
enp5s0.ipv4.addresses = [{
|
||||
address = network.architect-lan;
|
||||
prefixLength = 24;
|
||||
}];
|
||||
enp6s0.useDHCP = false;
|
||||
wlp4s0.useDHCP = false;
|
||||
};
|
||||
extraHosts = ''
|
||||
127.0.0.1 ${hostname}.devs.giugl.io localhost
|
||||
|
||||
# LAN
|
||||
${network.architect-lan} ${hostname}.devs.giugl.io
|
||||
|
||||
${network.dvr-lan} dvr.devs.giugl.io
|
||||
${network.nas-lan} nas.devs.giugl.io
|
||||
192.168.1.1 vodafone.station
|
||||
# Blacklist
|
||||
0.0.0.0 metrics.plex.tv
|
||||
0.0.0.0 analytics.plex.tv
|
||||
0.0.0.0 cdn.luckyorange.com
|
||||
0.0.0.0 w1.luckyorange.com
|
||||
0.0.0.0 browser.sentry-cdn.com
|
||||
0.0.0.0 analytics.facebook.com
|
||||
0.0.0.0 ads.facebook.com
|
||||
0.0.0.0 extmaps-api.yandex.net
|
||||
0.0.0.0 logservice.hicloud.com
|
||||
0.0.0.0 logbak.hicloud.com
|
||||
0.0.0.0 logservice1.hicloud.com
|
||||
0.0.0.0 samsung-com.112.2o7.net
|
||||
0.0.0.0 supportmetrics.apple.com
|
||||
0.0.0.0 analytics.oneplus.cn
|
||||
0.0.0.0 click.oneplus.cn
|
||||
0.0.0.0 analytics-api.samsunghealthcn.com
|
||||
'';
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [ cudatoolkit cachix ];
|
||||
|
||||
hardware = {
|
||||
opengl.enable = true;
|
||||
opengl.extraPackages = with pkgs; [ vaapiVdpau ];
|
||||
opengl.driSupport = true;
|
||||
};
|
||||
|
||||
services.das_watchdog.enable = true;
|
||||
|
||||
services = {
|
||||
fwupd.enable = true;
|
||||
das_watchdog.enable = true;
|
||||
zfs.autoScrub.enable = true;
|
||||
|
||||
xserver.videoDrivers = [ "nvidia" ];
|
||||
openssh = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
PasswordAuthentication = false;
|
||||
KbdInteractiveAuthentication = false;
|
||||
};
|
||||
|
||||
extraConfig = ''
|
||||
MaxAuthTries 15
|
||||
'';
|
||||
passwordAuthentication = false;
|
||||
challengeResponseAuthentication = false;
|
||||
};
|
||||
smartd.enable = true;
|
||||
};
|
||||
|
||||
pepe = {
|
||||
core = {
|
||||
media = {
|
||||
enable = true;
|
||||
path = "/media";
|
||||
};
|
||||
|
||||
network.interfaces = {
|
||||
lan = {
|
||||
interface = "enp6s0";
|
||||
type = "lan";
|
||||
net = "10.0.0.0/24";
|
||||
devices = {
|
||||
architect = { address = "10.0.0.250"; hostname = "architect.${domain}"; isEndpoint = true; };
|
||||
brigettine = { address = "10.0.0.1"; hostname = "router.${domain}"; };
|
||||
dreamel10 = { address = "10.0.0.199"; hostname = "dreamel10.${domain}"; };
|
||||
reolinkcamera = { address = "10.0.0.200"; hostname = "reolinkcamera.${domain}"; };
|
||||
lgtv = { address = "10.0.0.202"; hostname = "lgtv.${domain}"; };
|
||||
homeassistant = { address = "10.0.0.251"; hostname = "homeassistant.${domain}"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
services = {
|
||||
gitea = {
|
||||
enable = true;
|
||||
domain = "git.giugl.io";
|
||||
};
|
||||
|
||||
immich = {
|
||||
enable = true;
|
||||
domain = "photos.giugl.io";
|
||||
package = pkgs.unstablePkgs.immich;
|
||||
};
|
||||
|
||||
radarr = {
|
||||
enable = true;
|
||||
domain = "htrad.giugl.io";
|
||||
};
|
||||
|
||||
sonarr = {
|
||||
enable = true;
|
||||
domain = "htson.giugl.io";
|
||||
};
|
||||
|
||||
bazarr = {
|
||||
enable = true;
|
||||
domain = "htbaz.giugl.io";
|
||||
};
|
||||
|
||||
nzbget = {
|
||||
enable = true;
|
||||
domain = "htnzb.giugl.io";
|
||||
};
|
||||
|
||||
jellyfin = {
|
||||
enable = true;
|
||||
domain = "media.giugl.io";
|
||||
package = pkgs.unstablePkgs.jellyfin;
|
||||
};
|
||||
|
||||
jellyseer = {
|
||||
enable = true;
|
||||
domain = "aumm-aumm.giugl.io";
|
||||
};
|
||||
|
||||
prowlarr = {
|
||||
enable = true;
|
||||
domain = "htpro.giugl.io";
|
||||
};
|
||||
|
||||
redlib = {
|
||||
enable = true;
|
||||
domain = "reddit.giugl.io";
|
||||
package = pkgs.unstablePkgs.redlib;
|
||||
settings = {
|
||||
REDLIB_ROBOTS_DISABLE_INDEXING = "on";
|
||||
REDLIB_DEFAULT_THEME = "dracula";
|
||||
REDLIB_DEFAULT_SHOW_NSFW = "on";
|
||||
REDLIB_DEFAULT_BLUR_NSFW = "off";
|
||||
REDLIB_DEFAULT_USE_HLS = "on";
|
||||
REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION = "on";
|
||||
};
|
||||
};
|
||||
|
||||
llm = {
|
||||
enable = true;
|
||||
package = pkgs.masterPkgs.ollama-cuda;
|
||||
backendDomain = "ollama.giugl.io";
|
||||
acceleration = "cuda";
|
||||
|
||||
# frontend = {
|
||||
# enable = true;
|
||||
# domain = "pino.giugl.io";
|
||||
# package = pkgs.unstablePkgs.open-webui;
|
||||
# };
|
||||
};
|
||||
|
||||
homeassistant = {
|
||||
enable = true;
|
||||
domain = "home.giugl.io";
|
||||
};
|
||||
|
||||
headscale = {
|
||||
enable = true;
|
||||
domain = "vipienne.giugl.io";
|
||||
settings = with config.pepe.core.network.interfaces.tailscale; {
|
||||
server_url = "https://${domain}";
|
||||
prefixes.v4 = net;
|
||||
dns = {
|
||||
magic_dns = false;
|
||||
override_local_dns = true;
|
||||
global = [ devices.architect.address ];
|
||||
nameservers.global = [ devices.architect.address ];
|
||||
};
|
||||
log.level = "debug";
|
||||
};
|
||||
};
|
||||
|
||||
navidrome = {
|
||||
enable = true;
|
||||
domain = "music.giugl.io";
|
||||
package = pkgs.unstablePkgs.navidrome;
|
||||
};
|
||||
};
|
||||
};
|
||||
environment.variables = { LIBVA_DRIVER_NAME = "vdpau"; };
|
||||
}
|
||||
|
||||
|
52
hosts/architect/deluge.nix
Normal file
52
hosts/architect/deluge.nix
Normal file
@ -0,0 +1,52 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "htdel.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
deluge = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
declarative = true;
|
||||
config = {
|
||||
download_location = "/media/deluge";
|
||||
max_upload_speed = 20;
|
||||
# full-stream
|
||||
enc_level = 1;
|
||||
# forced
|
||||
enc_in_policy = 0;
|
||||
# forced
|
||||
enc_out_policy = 0;
|
||||
max_active_seeding = 100;
|
||||
max_connections_global = 1000;
|
||||
max_active_limit = 100;
|
||||
max_active_downloading = 100;
|
||||
listen_ports = [ 51413 51414 ];
|
||||
random_port = false;
|
||||
enabled_plugins = [ "Label" "Extractor" ];
|
||||
};
|
||||
web.enable = true;
|
||||
authFile = "/secrets/deluge/auth";
|
||||
extraPackages = [ pkgs.unrar ];
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8112";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "deluge" ];
|
||||
}
|
@ -1,12 +1,40 @@
|
||||
{ ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
pepe.core.dns = {
|
||||
services = {
|
||||
dnsmasq = {
|
||||
enable = true;
|
||||
nextDNSId = "d65174";
|
||||
extraDomains = {
|
||||
"architect.devs.giugl.io" = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
servers = [ "127.0.0.1#5300" ];
|
||||
extraConfig = ''
|
||||
localise-queries
|
||||
min-cache-ttl=120
|
||||
max-cache-ttl=2400
|
||||
'';
|
||||
};
|
||||
|
||||
adguardhome = {
|
||||
enable = true;
|
||||
port = 3031;
|
||||
};
|
||||
|
||||
dnscrypt-proxy2 = {
|
||||
enable = true;
|
||||
settings = {
|
||||
listen_addresses = [ "127.0.0.1:5353" ];
|
||||
ipv4_servers = true;
|
||||
ipv6_servers = false;
|
||||
block_ipv6 = true;
|
||||
dnscrypt_servers = true;
|
||||
doh_servers = true;
|
||||
require_nolog = true;
|
||||
require_nofilter = true;
|
||||
timeout = 350;
|
||||
lb_strategy = "p4";
|
||||
lb_estimator = true;
|
||||
ignore_system_dns = true;
|
||||
fallback_resolvers = [ "1.1.1.1:53" "9.9.9.9:53" ];
|
||||
cache_min_ttl = 450;
|
||||
cache_max_ttl = 2400;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -1,25 +0,0 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
architect.networks.docker = {
|
||||
interface = "docker0";
|
||||
net = "172.17.0.0/16";
|
||||
};
|
||||
|
||||
hardware.nvidia-container-toolkit.enable = true;
|
||||
|
||||
virtualisation = {
|
||||
oci-containers.backend = "docker";
|
||||
|
||||
docker = {
|
||||
enable = true;
|
||||
extraOptions = ''
|
||||
--dns 127.0.0.1 --dns ${config.architect.networks.lan.devices.architect.address} --data-root /docker
|
||||
'';
|
||||
enableOnBoot = false;
|
||||
daemon.settings.iptables = false;
|
||||
};
|
||||
};
|
||||
|
||||
users.users.giulio.extraGroups = [ "docker" ];
|
||||
}
|
@ -1,14 +1,9 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
{ config, pkgs, ... }: {
|
||||
services.fail2ban = {
|
||||
enable = true;
|
||||
package = pkgs.fail2ban;
|
||||
packageFirewall = pkgs.nftables;
|
||||
bantime-increment.enable = true;
|
||||
ignoreIP = [
|
||||
config.pepe.core.network.interfaces.tailscale.net
|
||||
config.pepe.core.network.interfaces.lan.net
|
||||
];
|
||||
ignoreIP = [ "10.0.0.0/24" "10.3.0.0/24" ];
|
||||
};
|
||||
}
|
||||
|
@ -1,21 +1,33 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
with import ./network.nix;
|
||||
|
||||
let
|
||||
firewallRules = config.pepe.core.firewall;
|
||||
openTCP = lib.concatMapStringsSep "," (x: toString x) firewallRules.openTCP;
|
||||
openUDP = lib.concatMapStringsSep "," (x: toString x) firewallRules.openUDP;
|
||||
ifaces = config.pepe.core.network.interfaces;
|
||||
|
||||
deviceAddress = interface: device:
|
||||
ifaces.${interface}.devices.${device}.address;
|
||||
|
||||
gdevices = [
|
||||
(deviceAddress "tailscale" "architect")
|
||||
(deviceAddress "tailscale" "manduria")
|
||||
(deviceAddress "tailscale" "kmerr")
|
||||
open_tcp_ports = lib.concatMapStringsSep "," (x: toString x) [
|
||||
22 # ssh
|
||||
80 # http
|
||||
443 # https
|
||||
8448 # matrix
|
||||
10022 # gitea
|
||||
18080 # monero
|
||||
51413 # transmission
|
||||
];
|
||||
in
|
||||
{
|
||||
open_udp_ports = lib.concatMapStringsSep "," (x: toString x) [
|
||||
1194 # wireguard
|
||||
51413 # transmission
|
||||
];
|
||||
open_tcp_ports_vpn = lib.concatMapStringsSep "," (x: toString x) [
|
||||
22
|
||||
80
|
||||
443
|
||||
32400 # plex
|
||||
];
|
||||
open_udp_ports_vpn = lib.concatMapStringsSep "," (x: toString x) [
|
||||
53 # dns
|
||||
1194 # vpn
|
||||
];
|
||||
|
||||
in {
|
||||
networking = {
|
||||
# needed to use nftables
|
||||
firewall.enable = false;
|
||||
@ -23,7 +35,7 @@ in
|
||||
|
||||
nftables = {
|
||||
enable = true;
|
||||
ruleset = with config.pepe.core.network.interfaces; ''
|
||||
ruleset = ''
|
||||
table ip raw {
|
||||
chain PREROUTING {
|
||||
type filter hook prerouting priority raw; policy accept;
|
||||
@ -35,9 +47,6 @@ in
|
||||
}
|
||||
|
||||
table ip nat {
|
||||
chain DOCKER {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
chain PREROUTING {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
@ -52,7 +61,9 @@ in
|
||||
|
||||
chain POSTROUTING {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
oifname ${lan.interface} ip saddr ${tailscale.net} masquerade
|
||||
oifname ${wan-if} ip saddr {${
|
||||
lib.concatStringsSep "," towan-wg
|
||||
}} masquerade
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,10 +73,11 @@ in
|
||||
ct state invalid,untracked drop comment "drop invalid"
|
||||
ip daddr 255.255.255.255 accept comment "allow broadcast traffic"
|
||||
ip daddr 224.0.0.0/4 accept comment "allow multicast traffic"
|
||||
iifname ${lan.interface} ip saddr 127.0.0.0/8 drop comment "bind any ip to intf ${lan.interface}"
|
||||
iifname ${lan.interface} accept comment "bind any ip to intf ${lan.interface}"
|
||||
iifname ${tailscale.interface} ip saddr ${tailscale.net} accept
|
||||
iifname ${tailscale.interface} ip saddr 100.100.100.100/32 accept
|
||||
iifname ${wan-if} ip saddr ${vpn-net} drop comment "bind any ip to intf ${wan-if}"
|
||||
iifname ${wan-if} ip saddr 127.0.0.0/8 drop comment "bind any ip to intf ${wan-if}"
|
||||
iifname ${wan-if} accept comment "bind any ip to intf ${wan-if}"
|
||||
iifname ${proxy-if} ip saddr ${proxy-net} accept comment "bind ip ${proxy-net} to intf ${proxy-if}"
|
||||
iifname ${vpn-if} ip saddr ${vpn-net} accept comment "bind ip ${vpn-net} to intf ${vpn-if}"
|
||||
iifname "lo" accept comment "bind any ip to intf lo"
|
||||
jump mangle_drop
|
||||
}
|
||||
@ -118,12 +130,16 @@ in
|
||||
iifname "lo" accept comment "loopback"
|
||||
ip daddr 255.255.255.255 accept comment "allow broadcast traffic"
|
||||
ip daddr 224.0.0.0/4 accept comment "allow multicast traffic"
|
||||
ip saddr ${lan.net} accept comment "lan > local"
|
||||
ip saddr ${tailscale.net} accept comment "tailscale > local"
|
||||
ip saddr {${lib.concatStringsSep "," gdevices}} accept comment "vpn > local"
|
||||
ip saddr ${lan-net} accept comment "lan > local"
|
||||
ip saddr ${proxy-wg} accept comment "proxy > local"
|
||||
ip saddr {${lib.concatStringsSep "," gdevices-wg}} accept comment "vpn > local"
|
||||
|
||||
iifname ${wan-if} tcp dport {${open_tcp_ports}} accept
|
||||
iifname ${wan-if} udp dport {${open_udp_ports}} accept
|
||||
iifname ${vpn-if} tcp dport {${open_tcp_ports_vpn}} accept
|
||||
iifname ${vpn-if} udp dport {${open_udp_ports_vpn}} accept
|
||||
iifname ${vpn-if} icmp type echo-request accept
|
||||
|
||||
iifname ${lan.interface} tcp dport {${openTCP}} accept
|
||||
iifname ${lan.interface} udp dport {${openUDP}} accept
|
||||
jump filter_drop
|
||||
}
|
||||
|
||||
@ -131,7 +147,23 @@ in
|
||||
type filter hook forward priority filter; policy drop;
|
||||
ct state established,related accept
|
||||
|
||||
oifname ${lan.interface} ip saddr ${tailscale.net} accept
|
||||
# client to client
|
||||
ip saddr {${lib.concatStringsSep "," c2c-wg}} ip daddr {${
|
||||
lib.concatStringsSep "," c2c-wg
|
||||
}} accept
|
||||
|
||||
# gdevices talking to everyone in VPN
|
||||
ip saddr {${
|
||||
lib.concatStringsSep "," gdevices-wg
|
||||
}} ip daddr ${vpn-net} accept
|
||||
ip saddr {${
|
||||
lib.concatStringsSep "," gamenet-wg
|
||||
}} ip daddr {${lib.concatStringsSep "," gamenet-wg}} accept
|
||||
|
||||
# nat to wan
|
||||
oifname ${wan-if} ip saddr {${
|
||||
lib.concatStringsSep "," towan-wg
|
||||
}} accept
|
||||
|
||||
jump filter_drop
|
||||
}
|
||||
|
37
hosts/architect/gitea.nix
Normal file
37
hosts/architect/gitea.nix
Normal file
@ -0,0 +1,37 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "git.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
database.type = "sqlite3";
|
||||
domain = domain;
|
||||
appName = "Gitea";
|
||||
rootUrl = "https://${domain}";
|
||||
ssh.clonePort = 22;
|
||||
settings.server.LFS_START_SERVER = true;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:3000";
|
||||
extraConfig = ''
|
||||
allow 127.0.0.1;
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
allow 10.4.0.0/24;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
}
|
15
hosts/architect/githubrunner.nix
Normal file
15
hosts/architect/githubrunner.nix
Normal file
@ -0,0 +1,15 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
services.github-runner = {
|
||||
enable = true;
|
||||
url = "https://github.com/ropfuscator";
|
||||
tokenFile = "/secrets/github-runner/token";
|
||||
replace = true;
|
||||
};
|
||||
|
||||
nix.extraOptions = ''
|
||||
tarball-ttl = 0
|
||||
access-tokens = github.com=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
|
||||
'';
|
||||
}
|
@ -1,69 +1,50 @@
|
||||
{ config, lib, modulesPath, ... }:
|
||||
# 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 + "/installer/scan/not-detected.nix") ];
|
||||
hardware.cpu.amd.updateMicrocode =
|
||||
lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
|
||||
environment.etc."crypttab".text = ''
|
||||
backedNvme /dev/disk/by-uuid/92cfaa4a-82a1-4336-b552-b7f4f3c68613 /newdrive.key
|
||||
'';
|
||||
|
||||
boot = {
|
||||
kernelModules = [ "kvm-amd" "dm-snapshot" ];
|
||||
initrd = {
|
||||
luks.devices = {
|
||||
# backedNvme = {
|
||||
# device = "/dev/disk/by-uuid/92cfaa4a-82a1-4336-b552-b7f4f3c68613";
|
||||
# keyFile = "/newdrive.key";
|
||||
# allowDiscards = true;
|
||||
|
||||
# };
|
||||
root = {
|
||||
device = "/dev/disk/by-uuid/bdd5f111-ecec-48d8-861f-94083098c724";
|
||||
preLVM = true;
|
||||
allowDiscards = true;
|
||||
fallbackToPassword = true;
|
||||
};
|
||||
};
|
||||
availableKernelModules =
|
||||
boot.initrd.availableKernelModules =
|
||||
[ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
};
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "zpool/nixos/root";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-uuid/28ce6650-de21-4c1d-ae42-95d1e3507740";
|
||||
fsType = "ext4";
|
||||
fileSystems."/home" = {
|
||||
device = "zpool/data/home";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-uuid/B790-869D";
|
||||
fileSystems."/media" = {
|
||||
device = "datapool/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/secrets" = {
|
||||
device = "backedpool/secrets";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/var/lib" = {
|
||||
device = "backedpool/services";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/AF19-5616";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
"/backednvme" = {
|
||||
device = "/dev/mapper/backedNvme";
|
||||
};
|
||||
|
||||
"/services" = {
|
||||
device = "/backednvme/services";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
|
||||
"/secrets" = {
|
||||
device = "/backednvme/secrets";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
|
||||
"${config.pepe.core.media.path}" = lib.mkIf config.pepe.core.media.enable {
|
||||
device = "nvmedata/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [{
|
||||
device = "/swapfile";
|
||||
size = 1024 * 64;
|
||||
device = "/dev/sdc1";
|
||||
size = 10000;
|
||||
}];
|
||||
|
||||
}
|
||||
|
24
hosts/architect/invidious.nix
Normal file
24
hosts/architect/invidious.nix
Normal file
@ -0,0 +1,24 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "tube.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
invidious = {
|
||||
enable = true;
|
||||
port = 9092;
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = { proxyPass = "http://localhost:9092"; };
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
}
|
45
hosts/architect/jellyfin.nix
Normal file
45
hosts/architect/jellyfin.nix
Normal file
@ -0,0 +1,45 @@
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
network = import ./network.nix;
|
||||
domain = "jellyfin.giugl.io";
|
||||
in {
|
||||
disabledModules = [ "services/misc/jellyfin.nix" ];
|
||||
imports = [ ./modules/jellyfin.nix ];
|
||||
|
||||
services = {
|
||||
jellyfin = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
package = pkgs.unstable.jellyfin;
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
# forceSSL = true;
|
||||
# enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8096";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
allow 10.3.0.0/24;
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "jellyfin" ];
|
||||
users.groups.video.members = [ "jellyfin" ];
|
||||
users.groups.render.members = [ "jellyfin" ];
|
||||
|
||||
fileSystems."/tmp/jellyfin" = {
|
||||
device = "none";
|
||||
fsType = "tmpfs";
|
||||
options = [ "defaults" "size=20G" "uid=jellyfin" ];
|
||||
};
|
||||
}
|
24
hosts/architect/libreddit.nix
Normal file
24
hosts/architect/libreddit.nix
Normal file
@ -0,0 +1,24 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "reddit.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
libreddit = {
|
||||
enable = true;
|
||||
port = 9090;
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = { proxyPass = "http://localhost:9090"; };
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
}
|
34
hosts/architect/lidarr.nix
Normal file
34
hosts/architect/lidarr.nix
Normal file
@ -0,0 +1,34 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htlid.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
lidarr = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8686";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
deny 10.0.0.1;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "lidarr" ];
|
||||
}
|
@ -1,36 +1,34 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "runas.rocks";
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
age.secrets.matrix = {
|
||||
file = ../../secrets/matrix-synapse.age;
|
||||
owner = "matrix-synapse";
|
||||
};
|
||||
|
||||
domain = "matrix.giugl.io";
|
||||
webui_domain = "chat.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
matrix-synapse = {
|
||||
enable = true;
|
||||
# Database config is in the .age file
|
||||
extraConfigFiles = [ config.age.secrets.matrix.path ];
|
||||
settings = {
|
||||
server_name = "${domain}";
|
||||
database_name = "synapse";
|
||||
public_baseurl = "https://${domain}";
|
||||
registration_shared_secret = "runas!";
|
||||
url_preview_enabled = true;
|
||||
dynamic_thumbnails = true;
|
||||
withJemalloc = true;
|
||||
enable_registration = false;
|
||||
password_config.enabled = true;
|
||||
|
||||
auto_join_rooms = [ "#general:${domain}" "#music:${domain}" "#movies:${domain}" ];
|
||||
|
||||
# enable_registration = true;
|
||||
app_service_config_files = [
|
||||
"/var/lib/matrix-synapse/discord-registration.yaml"
|
||||
# "/var/lib/matrix-synapse/hookshot-registration.yml"
|
||||
# "/var/lib/matrix-synapse/telegram-registration.yaml"
|
||||
];
|
||||
extraConfig = ''
|
||||
auto_join_rooms:
|
||||
- "#general:matrix.giugl.io"
|
||||
max_upload_size: "50M"
|
||||
'';
|
||||
listeners = [{
|
||||
port = 8008;
|
||||
bind_addresses = [ "127.0.0.1" ];
|
||||
bind_address = "::1";
|
||||
type = "http";
|
||||
tls = false;
|
||||
x_forwarded = true;
|
||||
@ -39,7 +37,49 @@ in
|
||||
compress = false;
|
||||
}];
|
||||
}];
|
||||
turn_uris = [
|
||||
"turns:turn.giugl.io:5349?transport=udp"
|
||||
"turns:turn.giugl.io:5349?transport=tcp"
|
||||
];
|
||||
turn_shared_secret = "69duck duck fuck420";
|
||||
turn_user_lifetime = "1h";
|
||||
logConfig = ''
|
||||
version: 1
|
||||
|
||||
# In systemd's journal, loglevel is implicitly stored, so let's omit it
|
||||
# from the message text.
|
||||
formatters:
|
||||
journal_fmt:
|
||||
format: '%(name)s: [%(request)s] %(message)s'
|
||||
|
||||
filters:
|
||||
context:
|
||||
(): synapse.util.logcontext.LoggingContextFilter
|
||||
request: ""
|
||||
|
||||
handlers:
|
||||
journal:
|
||||
class: systemd.journal.JournalHandler
|
||||
formatter: journal_fmt
|
||||
filters: [context]
|
||||
SYSLOG_IDENTIFIER: synapse
|
||||
|
||||
root:
|
||||
level: WARN
|
||||
handlers: [journal]
|
||||
|
||||
disable_existing_loggers: False
|
||||
'';
|
||||
};
|
||||
|
||||
postgresql = {
|
||||
enable = true;
|
||||
package = pkgs.postgresql_11;
|
||||
ensureDatabases = [ "synapse" ];
|
||||
ensureUsers = [{
|
||||
name = "matrix-synapse";
|
||||
ensurePermissions = { "DATABASE synapse" = "ALL PRIVILEGES"; };
|
||||
}];
|
||||
};
|
||||
|
||||
nginx.virtualHosts = {
|
||||
@ -52,44 +92,120 @@ in
|
||||
'';
|
||||
locations."= /.well-known/matrix/server".extraConfig =
|
||||
let server = { "m.server" = "${domain}:443"; };
|
||||
in
|
||||
''
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
return 200 '${builtins.toJSON server}';
|
||||
'';
|
||||
|
||||
locations."= /.well-known/matrix/client".extraConfig =
|
||||
let
|
||||
locations."= /.well-known/matrix/client".extraConfig = let
|
||||
client = {
|
||||
"m.homeserver" = { "base_url" = "https://${domain}:443"; };
|
||||
"m.identity_server" = { "base_url" = "https://vector.im"; };
|
||||
};
|
||||
# ACAO required to allow element-web on any URL to request this json file
|
||||
in
|
||||
''
|
||||
in ''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON client}';
|
||||
'';
|
||||
|
||||
# locations."/".extraConfig = ''
|
||||
# return 404;
|
||||
# '';
|
||||
locations."/".extraConfig = ''
|
||||
return 404;
|
||||
'';
|
||||
|
||||
# forward all Matrix API calls to the synapse Matrix homeserver
|
||||
locations."/_matrix" = {
|
||||
proxyPass = "http://127.0.0.1:8008"; # without a trailing /
|
||||
proxyPass = "http://[::1]:8008"; # without a trailing /
|
||||
};
|
||||
};
|
||||
|
||||
locations."/_synapse" = {
|
||||
proxyPass = "http://127.0.0.1:8008"; # without a trailing /
|
||||
# web client
|
||||
"${webui_domain}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
|
||||
root = pkgs.element-web.override {
|
||||
conf = {
|
||||
default_server_config."m.homeserver" = {
|
||||
"base_url" = "https://${domain}";
|
||||
"server_name" = "${domain}";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# discord bridge
|
||||
matrix-appservice-discord = {
|
||||
enable = true;
|
||||
environmentFile = /secrets/matrix-appservice-discord/tokens.env;
|
||||
# The appservice is pre-configured to use SQLite by default.
|
||||
# It's also possible to use PostgreSQL.
|
||||
settings = {
|
||||
bridge = {
|
||||
domain = domain;
|
||||
homeserverUrl = "https://${domain}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# telegram bridge
|
||||
|
||||
# mautrix-telegram = {
|
||||
# enable = true;
|
||||
# environmentFile = /secrets/mautrix-telegram/mautrix-telegram.env;
|
||||
|
||||
# settings = {
|
||||
# homeserver = {
|
||||
# address = "https://${domain}";
|
||||
# domain = "${domain}";
|
||||
# };
|
||||
|
||||
# appservice = {
|
||||
# provisioning.enabled = false;
|
||||
# id = "telegram";
|
||||
# };
|
||||
|
||||
# bridge = {
|
||||
# permissions = {
|
||||
# "@pepe:${domain}" = "admin";
|
||||
# "${domain}" = "puppeting";
|
||||
# };
|
||||
|
||||
# # Animated stickers conversion requires additional packages in the
|
||||
# # service's path.
|
||||
# # If this isn't a fresh installation, clearing the bridge's uploaded
|
||||
# # file cache might be necessary (make a database backup first!):
|
||||
# # delete from telegram_file where \
|
||||
# # mime_type in ('application/gzip', 'application/octet-stream')
|
||||
# animated_sticker = {
|
||||
# target = "gif";
|
||||
# args = {
|
||||
# width = 256;
|
||||
# height = 256;
|
||||
# fps = 30; # only for webm
|
||||
# background = "020202"; # only for gif, transparency not supported
|
||||
# };
|
||||
# };
|
||||
|
||||
# encryption = {
|
||||
# allow = true;
|
||||
# default = true;
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
|
||||
};
|
||||
|
||||
# systemd.services.mautrix-telegram.path = with pkgs; [
|
||||
# lottieconverter # for animated stickers conversion, unfree package
|
||||
# ffmpeg # if converting animated stickers to webm (very slow!)
|
||||
# ];
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
${network.architect-lan} ${domain} ${webui_domain}
|
||||
${network.architect-wg} ${domain} ${webui_domain}
|
||||
'';
|
||||
|
||||
}
|
||||
|
@ -1,24 +1,18 @@
|
||||
{ lib, config, pkgs, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "minecraft.giugl.io";
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
architect.firewall.openTCP = [ 25565 ];
|
||||
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services.minecraft-server = {
|
||||
enable = true;
|
||||
eula = true;
|
||||
declarative = true;
|
||||
package = pkgs.unstablePkgs.minecraft-server;
|
||||
serverProperties = { motd = "Welcome on the RuNas server!"; };
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
}
|
||||
|
28
hosts/architect/minio.nix
Normal file
28
hosts/architect/minio.nix
Normal file
@ -0,0 +1,28 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "s3.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
minio.enable = true;
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:9000";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
}
|
130
hosts/architect/modules/jellyfin.nix
Normal file
130
hosts/architect/modules/jellyfin.nix
Normal file
@ -0,0 +1,130 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let cfg = config.services.jellyfin;
|
||||
in {
|
||||
options = {
|
||||
services.jellyfin = {
|
||||
enable = mkEnableOption "Jellyfin Media Server";
|
||||
|
||||
user = mkOption {
|
||||
type = types.str;
|
||||
default = "jellyfin";
|
||||
description = "User account under which Jellyfin runs.";
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.jellyfin;
|
||||
example = literalExample "pkgs.jellyfin";
|
||||
description = ''
|
||||
Jellyfin package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "jellyfin";
|
||||
description = "Group under which jellyfin runs.";
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Open the default ports in the firewall for the media server. The
|
||||
HTTP/HTTPS ports can be changed in the Web UI, so this option should
|
||||
only be used if they are unchanged.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
systemd.services.jellyfin = {
|
||||
description = "Jellyfin Media Server";
|
||||
after = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = rec {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
# # Allows access to drm devices for transcoding with hardware acceleration
|
||||
# SupplementaryGroups = [ "video" ];
|
||||
StateDirectory = "jellyfin";
|
||||
CacheDirectory = "jellyfin";
|
||||
ExecStart =
|
||||
"${cfg.package}/bin/jellyfin --datadir '/var/lib/${StateDirectory}' --cachedir '/var/cache/${CacheDirectory}'";
|
||||
Restart = "on-failure";
|
||||
|
||||
# Security options:
|
||||
|
||||
NoNewPrivileges = true;
|
||||
|
||||
AmbientCapabilities = "";
|
||||
CapabilityBoundingSet = "";
|
||||
|
||||
# # ProtectClock= adds DeviceAllow=char-rtc r
|
||||
# DeviceAllow = [
|
||||
# "char-drm r"
|
||||
# "/dev/nvidia0 r"
|
||||
# "/dev/nvidiactl r"
|
||||
# "/dev/nvidia-uvm r"
|
||||
# "/dev/nvidia-uvm-tools r"
|
||||
# ];
|
||||
DeviceAllow = "";
|
||||
LockPersonality = true;
|
||||
|
||||
PrivateTmp = true;
|
||||
PrivateUsers = true;
|
||||
|
||||
# ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
|
||||
RemoveIPC = true;
|
||||
|
||||
RestrictNamespaces = true;
|
||||
# # AF_NETLINK needed because Jellyfin monitors the network connection
|
||||
RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" "AF_UNIX" ];
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallErrorNumber = "EPERM";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@cpu-emulation"
|
||||
"~@debug"
|
||||
"~@keyring"
|
||||
"~@memlock"
|
||||
"~@obsolete"
|
||||
"~@privileged"
|
||||
"~@setuid"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
users.users = mkIf (cfg.user == "jellyfin") {
|
||||
jellyfin = {
|
||||
group = cfg.group;
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
users.groups = mkIf (cfg.group == "jellyfin") { jellyfin = { }; };
|
||||
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
# from https://jellyfin.org/docs/general/networking/index.html
|
||||
allowedTCPPorts = [ 8096 8920 ];
|
||||
allowedUDPPorts = [ 1900 7359 ];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
meta.maintainers = with lib.maintainers; [ minijackson ];
|
||||
}
|
53
hosts/architect/navidrome.nix
Normal file
53
hosts/architect/navidrome.nix
Normal file
@ -0,0 +1,53 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "music.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
navidrome = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
MusicFolder = "/media/Music";
|
||||
LastFM.enable = true;
|
||||
LastFM.ApiKey = "5cef5cb5f9d31326b97d0f929ca9cf20";
|
||||
LastFM.Secret = "d1296896126f4caae47407aecf080b25";
|
||||
Spotify.ID = "3900c029b4f34f3fb61d554dda64794d";
|
||||
Spotify.Secret = "d931ce5575a9401aa5ff8d37558cca0a";
|
||||
EnableGravatar = true;
|
||||
LogLevel = "WARN";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:4533";
|
||||
# extraConfig = ''
|
||||
# allow 10.0.0.0/24;
|
||||
# ${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
# deny all;
|
||||
# '';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."beets-rename" = {
|
||||
enable = true;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart =
|
||||
"${pkgs.findutils}/bin/find /media/Music -type d -mindepth 2 -maxdepth 2 -exec ${pkgs.beets}/bin/beet -c /media/config.conf import --flat -q {} \\;";
|
||||
};
|
||||
startAt = "daily";
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "navidrome" ];
|
||||
}
|
73
hosts/architect/network.nix
Normal file
73
hosts/architect/network.nix
Normal file
@ -0,0 +1,73 @@
|
||||
rec {
|
||||
# interfaces
|
||||
wan-if = "enp5s0";
|
||||
vpn-if = "wg0";
|
||||
proxy-if = "proxy";
|
||||
|
||||
# nets
|
||||
lan-net = "10.0.0.0/24";
|
||||
vpn-net = "10.3.0.0/24";
|
||||
proxy-net = "10.4.0.0/24";
|
||||
external_lan-net = "192.168.1.0/24";
|
||||
|
||||
# ips
|
||||
dvr-lan = "10.0.0.2";
|
||||
nas-lan = "10.0.0.3";
|
||||
architect-lan = "10.0.0.250";
|
||||
|
||||
proxy-wg = "10.4.0.1";
|
||||
architect-wg = "10.3.0.1";
|
||||
galuminum-wg = "10.3.0.2";
|
||||
oneplus-wg = "10.3.0.3";
|
||||
ipad-wg = "10.3.0.4";
|
||||
manduria-wg = "10.3.0.5";
|
||||
antonio-wg = "10.3.0.6";
|
||||
gbeast-wg = "10.3.0.7";
|
||||
parisaphone-wg = "10.3.0.8";
|
||||
parisapc-wg = "10.3.0.9";
|
||||
peppiniell-wg = "10.3.0.10";
|
||||
padulino-wg = "10.3.0.11";
|
||||
shield-wg = "10.3.0.12";
|
||||
pepos-wg = "10.3.0.15";
|
||||
salvatore-wg = "10.3.0.16";
|
||||
papa-wg = "10.3.0.17";
|
||||
defy-wg = "10.3.0.18";
|
||||
germano-wg = "10.3.0.19";
|
||||
flavio-wg = "10.3.0.20";
|
||||
tommy-wg = "10.3.0.21";
|
||||
alain-wg = "10.3.0.22";
|
||||
dima-wg = "10.3.0.23";
|
||||
mikey-wg = "10.3.0.24";
|
||||
andrew-wg = "10.3.0.25";
|
||||
mikeylaptop-wg = "10.3.0.26";
|
||||
andrewdesktop-wg = "10.3.0.27";
|
||||
jacopo-wg = "10.3.0.28";
|
||||
frznn-wg = "10.3.0.29";
|
||||
ludo-wg = "10.3.0.30";
|
||||
parina-wg = "10.3.0.31";
|
||||
nilo-wg = "10.3.0.32";
|
||||
parina-ipad-wg = "10.3.0.33";
|
||||
eleonora-wg = "10.3.0.100";
|
||||
angellane-wg = "10.3.0.200";
|
||||
hotpottino-wg = "10.3.0.201";
|
||||
dodino-wg = "10.3.0.202";
|
||||
wolfsonhouse-wg = "10.3.0.203";
|
||||
|
||||
# groups
|
||||
gdevices-wg =
|
||||
[ galuminum-wg oneplus-wg ipad-wg gbeast-wg peppiniell-wg padulino-wg wolfsonhouse-wg ];
|
||||
routers-wg = [ hotpottino-wg angellane-wg dodino-wg wolfsonhouse-wg ];
|
||||
c2c-wg = [ ] ++ gdevices-wg;
|
||||
towan-wg = [ shield-wg parisaphone-wg parisapc-wg parina-wg parina-ipad-wg ] ++ gdevices-wg
|
||||
++ routers-wg;
|
||||
gamenet-wg = [
|
||||
andrew-wg
|
||||
galuminum-wg
|
||||
gbeast-wg
|
||||
mikey-wg
|
||||
andrewdesktop-wg
|
||||
mikeylaptop-wg
|
||||
flavio-wg
|
||||
salvatore-wg
|
||||
];
|
||||
}
|
@ -1,86 +1,37 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "cloud.giugl.io";
|
||||
redis_port = 6379;
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
age.secrets = {
|
||||
nextcloud-admin = {
|
||||
file = ../../secrets/nextcloud-admin.age;
|
||||
owner = "nextcloud";
|
||||
group ="nginx";
|
||||
};
|
||||
nextcloud-database = {
|
||||
file = ../../secrets/nextcloud-database.age;
|
||||
owner = "nextcloud";
|
||||
group = "nginx";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
ffmpeg
|
||||
];
|
||||
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
extraConfig = ''
|
||||
aio threads;
|
||||
directio 1M;
|
||||
output_buffers 3 1M;
|
||||
mysql.enable = true;
|
||||
mysql.package = pkgs.unstable.mysql80;
|
||||
|
||||
sendfile on;
|
||||
sendfile_max_chunk 0;
|
||||
|
||||
autoindex on;
|
||||
'';
|
||||
};
|
||||
|
||||
mysql = {
|
||||
enable = true;
|
||||
package = pkgs.mariadb_1011;
|
||||
};
|
||||
|
||||
redis = {
|
||||
vmOverCommit = true;
|
||||
servers."nextcloud" = {
|
||||
enable = true;
|
||||
port = redis_port;
|
||||
};
|
||||
};
|
||||
redis.enable = true;
|
||||
|
||||
nextcloud = {
|
||||
enable = true;
|
||||
hostName = domain;
|
||||
hostName = "${domain}";
|
||||
https = true;
|
||||
package = pkgs.nextcloud31;
|
||||
datadir = "/services/nextcloud";
|
||||
configureRedis = true;
|
||||
caching = {
|
||||
redis = true;
|
||||
};
|
||||
package = pkgs.unstable.nextcloud23;
|
||||
|
||||
caching.redis = true;
|
||||
|
||||
autoUpdateApps.enable = true;
|
||||
autoUpdateApps.startAt = "05:00:00";
|
||||
|
||||
maxUploadSize = "50G";
|
||||
|
||||
settings = {
|
||||
overwriteprotocol = "https";
|
||||
};
|
||||
logLevel = 1;
|
||||
|
||||
config = {
|
||||
overwriteProtocol = "https";
|
||||
dbtype = "mysql";
|
||||
dbuser = "nextcloud";
|
||||
dbuser = "oc_giulio2";
|
||||
dbhost = "localhost";
|
||||
dbname = "nextcloud";
|
||||
dbpassFile = config.age.secrets.nextcloud-database.path;
|
||||
adminpassFile = config.age.secrets.nextcloud-admin.path;
|
||||
dbname = "nextcloud_final";
|
||||
dbpassFile = "/secrets/nextcloud/dbpass.txt";
|
||||
adminpassFile = "/secrets/nextcloud/adminpass.txt";
|
||||
adminuser = "giulio";
|
||||
extraTrustedDomains = [ "${domain}" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
@ -91,8 +42,12 @@ in
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
};
|
||||
}
|
||||
|
@ -1,93 +1,35 @@
|
||||
{ services, pkgs, lib, ... }:
|
||||
{ services, ... }:
|
||||
|
||||
{
|
||||
architect.firewall = {
|
||||
openTCP = [ 80 443 ];
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
package = pkgs.nginx;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
|
||||
virtualHosts."architect.devs.giugl.io" = {
|
||||
default = true;
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
root = "/var/lib/nginx/error_pages";
|
||||
extraConfig = "error_page 404 /index.htm;";
|
||||
|
||||
locations = {
|
||||
"/" = { return = "404"; };
|
||||
|
||||
"/index.htm" = { };
|
||||
|
||||
"/style.css" = { };
|
||||
|
||||
"/wat.jpg" = { };
|
||||
};
|
||||
};
|
||||
|
||||
# appendHttpConfig =
|
||||
# let
|
||||
# extraPureLuaPackages = with pkgs.luajitPackages; [
|
||||
# lua-resty-openidc
|
||||
# lua-resty-http
|
||||
# lua-resty-session
|
||||
# lua-resty-jwt
|
||||
# lua-resty-openssl
|
||||
# ];
|
||||
# luaPath = pkg: "${pkg}/share/lua/5.1/?.lua";
|
||||
# makeLuaPath = lib.concatMapStringsSep ";" luaPath;
|
||||
# in
|
||||
# ''
|
||||
# # https://stackoverflow.com/questions/38931468/nginx-reverse-proxy-error14077438ssl-ssl-do-handshake-failed
|
||||
# proxy_ssl_server_name on;
|
||||
|
||||
# lua_package_path '${makeLuaPath extraPureLuaPackages};;';
|
||||
# lua_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||
# lua_ssl_verify_depth 5;
|
||||
|
||||
# # cache for OIDC discovery metadata
|
||||
# lua_shared_dict discovery 1m;
|
||||
# lua_shared_dict jwks 1m;
|
||||
|
||||
# # https://github.com/openresty/lua-resty-redis/issues/159
|
||||
# resolver local=on ipv6=off;
|
||||
|
||||
# init_worker_by_lua_block {
|
||||
# function check_role (res, role)
|
||||
# if res.user.roles == nil then
|
||||
# return false
|
||||
# end
|
||||
|
||||
# for _,v in pairs(res.user.roles) do
|
||||
# if string.lower(v) == role then
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
|
||||
# return false
|
||||
# end
|
||||
|
||||
# function is_ip_whitelisted(ip, whitelist)
|
||||
# for _, x in ipairs(whitelist) do
|
||||
# if ip == x then
|
||||
# return true
|
||||
# end
|
||||
# end
|
||||
|
||||
# return false
|
||||
# end
|
||||
# }
|
||||
# '';
|
||||
|
||||
appendConfig = ''
|
||||
worker_processes 24;
|
||||
'';
|
||||
# virtualHosts."giugl.io" = {
|
||||
# default = true;
|
||||
# enableACME = true;
|
||||
# addSSL = true;
|
||||
# root = "/var/lib/nginx/error_pages";
|
||||
# extraConfig = "error_page 404 /index.htm;";
|
||||
#
|
||||
# locations = {
|
||||
# "/" = {
|
||||
# return = "404";
|
||||
# };
|
||||
#
|
||||
# "/index.htm" = {
|
||||
# };
|
||||
#
|
||||
# "/style.css" = {
|
||||
# };
|
||||
#
|
||||
# "/wat.jpg" = {
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
};
|
||||
|
||||
users.groups.acme.members = [ "nginx" ];
|
||||
|
32
hosts/architect/nitter.nix
Normal file
32
hosts/architect/nitter.nix
Normal file
@ -0,0 +1,32 @@
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "tweet.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
nitter = {
|
||||
enable = true;
|
||||
server = {
|
||||
port = 9093;
|
||||
hostname = domain;
|
||||
staticDir = "${pkgs.unstable.nitter}/share/nitter/public";
|
||||
};
|
||||
preferences = {
|
||||
replaceYouTube = "tube.giugl.io";
|
||||
replaceTwitter = "tweet.giugl.io";
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = { proxyPass = "http://localhost:9093"; };
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
}
|
33
hosts/architect/nzbget.nix
Normal file
33
hosts/architect/nzbget.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htnzb.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
nzbget = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:6789";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "nzbget" ];
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
{
|
||||
options.architect = {
|
||||
firewall = lib.mkOption {
|
||||
internal = true;
|
||||
default = config.pepe.core.firewall;
|
||||
};
|
||||
|
||||
networks = lib.mkOption {
|
||||
internal = true;
|
||||
default = config.pepe.core.network.interfaces;
|
||||
};
|
||||
|
||||
vhost = lib.mkOption {
|
||||
internal = true;
|
||||
default = config.pepe.core.vhost.hosts;
|
||||
};
|
||||
};
|
||||
|
||||
config.architect.networks.docker = {
|
||||
interface = "docker0";
|
||||
net = "172.17.0.0/16";
|
||||
};
|
||||
}
|
13
hosts/architect/overseerr.nix
Normal file
13
hosts/architect/overseerr.nix
Normal file
@ -0,0 +1,13 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
virtualisation.oci-containers.containers."overseerr" = {
|
||||
image = "sctx/overseerr:latest";
|
||||
volumes = [ "/var/lib/overseerr:/app/config" ];
|
||||
environment = {
|
||||
"LOG_LEVEL" = "debug";
|
||||
"TZ" = "Europe/Rome";
|
||||
};
|
||||
#ports = [ "5055:5055" ];
|
||||
};
|
||||
}
|
91
hosts/architect/plex.nix
Normal file
91
hosts/architect/plex.nix
Normal file
@ -0,0 +1,91 @@
|
||||
{ pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "media.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services.plex = {
|
||||
enable = true;
|
||||
package = pkgs.unstable.plex;
|
||||
dataDir = "/plex";
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
# give a name to the virtual host. It also becomes the server name.
|
||||
virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
http2 = true;
|
||||
extraConfig = ''
|
||||
allow 10.3.0.0/24;
|
||||
allow 10.0.0.0/24;
|
||||
deny all;
|
||||
|
||||
#Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause
|
||||
send_timeout 100m;
|
||||
|
||||
# Why this is important: https://blog.cloudflare.com/ocsp-stapling-how-cloudflare-just-made-ssl-30/
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_prefer_server_ciphers on;
|
||||
#Intentionally not hardened for security for player support and encryption video streams has a lot of overhead with something like AES-256-GCM-SHA384.
|
||||
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
|
||||
|
||||
# Forward real ip and host to Plex
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header Host $server_addr;
|
||||
proxy_set_header Referer $server_addr;
|
||||
proxy_set_header Origin $server_addr;
|
||||
|
||||
# Plex has A LOT of javascript, xml and html. This helps a lot, but if it causes playback issues with devices turn it off.
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied any;
|
||||
gzip_types text/plain text/css text/xml application/xml text/javascript application/x-javascript image/svg+xml;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
# Nginx default client_max_body_size is 1MB, which breaks Camera Upload feature from the phones.
|
||||
# Increasing the limit fixes the issue. Anyhow, if 4K videos are expected to be uploaded, the size might need to be increased even more
|
||||
client_max_body_size 100M;
|
||||
|
||||
# Plex headers
|
||||
proxy_set_header X-Plex-Client-Identifier $http_x_plex_client_identifier;
|
||||
proxy_set_header X-Plex-Device $http_x_plex_device;
|
||||
proxy_set_header X-Plex-Device-Name $http_x_plex_device_name;
|
||||
proxy_set_header X-Plex-Platform $http_x_plex_platform;
|
||||
proxy_set_header X-Plex-Platform-Version $http_x_plex_platform_version;
|
||||
proxy_set_header X-Plex-Product $http_x_plex_product;
|
||||
proxy_set_header X-Plex-Token $http_x_plex_token;
|
||||
proxy_set_header X-Plex-Version $http_x_plex_version;
|
||||
proxy_set_header X-Plex-Nocache $http_x_plex_nocache;
|
||||
proxy_set_header X-Plex-Provides $http_x_plex_provides;
|
||||
proxy_set_header X-Plex-Device-Vendor $http_x_plex_device_vendor;
|
||||
proxy_set_header X-Plex-Model $http_x_plex_model;
|
||||
|
||||
# Websockets
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
|
||||
# Buffering off send to the client as soon as the data is received from Plex.
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
'';
|
||||
locations."/" = { proxyPass = "http://localhost:32400"; };
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "plex" ];
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{ pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
package = lib.mkForce pkgs.postgresql_16;
|
||||
};
|
||||
}
|
41
hosts/architect/prosody.nix
Normal file
41
hosts/architect/prosody.nix
Normal file
@ -0,0 +1,41 @@
|
||||
{ lib, config, ... }:
|
||||
|
||||
let
|
||||
domain = "xmpp.giugl.io";
|
||||
conference_domain = "conference.${domain}";
|
||||
upload_domain = "uploads.${domain}";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
prosody = {
|
||||
enable = true;
|
||||
virtualHosts = {
|
||||
"${domain}" = {
|
||||
domain = domain;
|
||||
enabled = true;
|
||||
ssl.key = "${config.security.acme.certs.${domain}.directory}/key.pem";
|
||||
ssl.cert =
|
||||
"${config.security.acme.certs.${domain}.directory}/fullchain.pem";
|
||||
};
|
||||
};
|
||||
|
||||
muc = [{ domain = conference_domain; }];
|
||||
uploadHttp = { domain = upload_domain; };
|
||||
|
||||
admins = [ "giulio@${domain}" ];
|
||||
#httpInterfaces = [ "wg0" ];
|
||||
#httpsInterfaces = [ "wg0" ];
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${domain}".enableACME = true;
|
||||
#services.nginx.virtualHosts."${conference_domain}".enableACME = true;
|
||||
#services.nginx.virtualHosts."${upload_domain}".enableACME = true;
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.acme.members = [ "prosody" ];
|
||||
}
|
38
hosts/architect/prowlarr.nix
Normal file
38
hosts/architect/prowlarr.nix
Normal file
@ -0,0 +1,38 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htpro.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
prowlarr.enable = true;
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:9696";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
|
||||
# locations."/api" = {
|
||||
# proxyPass = "http://127.0.0.1:9696/prowlarr/api";
|
||||
# };
|
||||
#
|
||||
# locations."/Content" = {
|
||||
# proxyPass = "http://127.0.0.1:9696/prowlarr/Content";
|
||||
# };
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "prowlarr" ];
|
||||
}
|
33
hosts/architect/radarr.nix
Normal file
33
hosts/architect/radarr.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htrad.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
radarr = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:7878";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "radarr" ];
|
||||
}
|
49
hosts/architect/scripts/fetch-adblock-hosts.sh
Normal file
49
hosts/architect/scripts/fetch-adblock-hosts.sh
Normal file
@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
EASYLIST_HOSTSNAME="easylist_hosts.txt"
|
||||
EASYPRIVACY_HOSTSNAME="easyprivacy_hosts.txt"
|
||||
STEVENBLACK_HOSTSNAME="stevenblack_hosts.txt"
|
||||
|
||||
get_easylist() {
|
||||
EASYLIST_URL="https://raw.githubusercontent.com/easylist/easylist/master/easylist/easylist_adservers.txt"
|
||||
|
||||
tmpfile=`mktemp`
|
||||
|
||||
# download easylist
|
||||
${pkgs.wget}/bin/wget $EASYLIST_URL -O $tmpfile
|
||||
|
||||
# remove IP addresses and prepend 0.0.0.0 to create hosts file
|
||||
|
||||
cat $tmpfile | egrep -v "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -oP "^\|\|(\K[a-zA-Z0-9\.\-]+)" | ${pkgs.gawk}/bin/gawk '{print "0.0.0.0 " $0}' > $EASYLIST_HOSTSNAME
|
||||
}
|
||||
|
||||
get_easyprivacy() {
|
||||
EASYLIST_URL="https://raw.githubusercontent.com/easylist/easylist/master/easyprivacy/easyprivacy_trackingservers.txt"
|
||||
|
||||
tmpfile=`mktemp`
|
||||
|
||||
# download easylist
|
||||
${pkgs.wget}/bin/wget $EASYLIST_URL -O $tmpfile
|
||||
|
||||
# remove IP addresses and prepend 0.0.0.0 to create hosts file
|
||||
|
||||
cat $tmpfile | egrep -v "([0-9]{1,3}\.){3}[0-9]{1,3}" | grep -oP "^\|\|(\K[a-zA-Z0-9\.\-]+)" | ${pkgs.gawk}/bin/gawk '{print "0.0.0.0 " $0}' > $EASYPRIVACY_HOSTSNAME
|
||||
}
|
||||
|
||||
get_stevenblack() {
|
||||
STEVENBLACK_URL="https://raw.githubusercontent.com/StevenBlack/hosts/master/alternates/fakenews/hosts"
|
||||
|
||||
${pkgs.wget}/bin/wget $STEVENBLACK_URL -O $STEVENBLACK_HOSTSNAME
|
||||
}
|
||||
|
||||
|
||||
get_easylist
|
||||
get_easyprivacy
|
||||
get_stevenblack
|
||||
|
||||
|
||||
# create unified file
|
||||
|
||||
cat *hosts.txt | sort | uniq | grep "^0" > /etc/adblock_hosts
|
||||
|
||||
rm $EASYLIST_HOSTSNAME $STEVENBLACK_HOSTSNAME
|
@ -1,64 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "search.giugl.io";
|
||||
in
|
||||
{
|
||||
services = {
|
||||
redis.servers."searx" = { enable = true; port = 4456; };
|
||||
searx = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.searxng;
|
||||
|
||||
environmentFile = /secrets/searx/env;
|
||||
settings = {
|
||||
server = {
|
||||
secret_key = "@SEARX_SECRET_KEY@";
|
||||
port = 4455;
|
||||
};
|
||||
|
||||
general = {
|
||||
instance_name = "PepoSearch";
|
||||
contact_url = "mailto:search@depasquale.giugl.io";
|
||||
enable_metrics = true;
|
||||
};
|
||||
|
||||
search = {
|
||||
safe_search = 0;
|
||||
autocomplete = "google";
|
||||
prefer_configured_language = false;
|
||||
formats = [ "html" "json"];
|
||||
};
|
||||
|
||||
ui = {
|
||||
infinite_scroll = true;
|
||||
query_in_title = true;
|
||||
results_on_new_tab = true;
|
||||
theme_args.simple_style = "dark";
|
||||
};
|
||||
|
||||
redis.url = "redis://127.0.0.1:${toString config.services.redis.servers."searx".port}";
|
||||
|
||||
engines = [
|
||||
{ name = "google"; disabled = false; }
|
||||
{ name = "bing"; disabled = false; }
|
||||
{ name = "qwant"; disabled = true; }
|
||||
{ name = "brave"; disabled = true; }
|
||||
{ name = "duckduckgo"; disabled = false; }
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = with config.architect.networks; {
|
||||
dnsInterfaces = [ "tailscale" ];
|
||||
locations."/" = {
|
||||
port = config.services.searx.settings.server.port;
|
||||
allowLan = true;
|
||||
allowWAN = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
33
hosts/architect/sonarr.nix
Normal file
33
hosts/architect/sonarr.nix
Normal file
@ -0,0 +1,33 @@
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htson.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
sonarr = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:8989";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "sonarr" ];
|
||||
}
|
@ -1,203 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
user = "sunshine";
|
||||
resolutionScript = pkgs.writeTextFile {
|
||||
name = "sunshine-resolution-script";
|
||||
text = ''
|
||||
#!${pkgs.bash}/bin/bash
|
||||
|
||||
width=''${1:-1280}
|
||||
height=''${2:-720}
|
||||
refresh_rate=''${3:-120}
|
||||
|
||||
# Get the modeline info from the 2nd row in the cvt output
|
||||
modeline=$(${pkgs.xorg.libxcvt}/bin/cvt ''${width} ''${height} ''${refresh_rate} | ${pkgs.gawk}/bin/gawk 'FNR == 2')
|
||||
xrandr_mode_str=''${modeline//Modeline \"*\" /}
|
||||
mode_alias="''${width}x''${height}"
|
||||
|
||||
echo "xrandr setting new mode ''${mode_alias} ''${xrandr_mode_str}"
|
||||
|
||||
# Check if mode exists before trying to remove it
|
||||
if ${pkgs.xorg.xrandr}/bin/xrandr --listmodes | grep -q "^''${mode_alias}"; then
|
||||
${pkgs.xorg.xrandr}/bin/xrandr --rmmode ''${mode_alias} || echo "Failed to remove existing mode"
|
||||
fi
|
||||
|
||||
${pkgs.xorg.xrandr}/bin/xrandr --newmode ''${mode_alias} ''${xrandr_mode_str} || echo "Failed to create new mode"
|
||||
${pkgs.xorg.xrandr}/bin/xrandr --addmode DP-0 ''${mode_alias} || echo "Failed to add mode to output"
|
||||
|
||||
# Apply new xrandr mode
|
||||
${pkgs.xorg.xrandr}/bin/xrandr --output DP-0 --primary --mode ''${mode_alias} --pos 0x0 --rotate normal || echo "Failed to apply mode"
|
||||
|
||||
${config.boot.kernelPackages.nvidia_x11.settings}/bin/nvidia-settings -a 'SyncToVBlank=0' || echo "Failed to disable VSync"
|
||||
${config.boot.kernelPackages.nvidia_x11.bin}/bin/nvidia-smi --persistence-mode=ENABLED || echo "Failed to enable persistence mode"
|
||||
'';
|
||||
executable = true;
|
||||
destination = "/bin/resolution.sh";
|
||||
};
|
||||
sunshinePkg = (pkgs.unstablePkgs.sunshine.override { cudaSupport = true; });
|
||||
in
|
||||
{
|
||||
pepe.core.graphics = {
|
||||
enable = true;
|
||||
nvidia = true;
|
||||
};
|
||||
|
||||
boot.kernelModules = [ "uinput" ];
|
||||
|
||||
environment.systemPackages = with pkgs.unstablePkgs; [ gamemode heroic ];
|
||||
|
||||
systemd.services.NetworkManager-wait-online.enable = pkgs.lib.mkForce false;
|
||||
programs.steam = {
|
||||
enable = true;
|
||||
gamescopeSession.enable = true;
|
||||
};
|
||||
|
||||
security = {
|
||||
polkit.extraConfig = ''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.login1.suspend" ||
|
||||
action.id == "org.freedesktop.login1.suspend-multiple-sessions" ||
|
||||
action.id == "org.freedesktop.login1.hibernate" ||
|
||||
action.id == "org.freedesktop.login1.hibernate-multiple-sessions")
|
||||
{
|
||||
return polkit.Result.NO;
|
||||
}
|
||||
});
|
||||
'';
|
||||
rtkit.enable = true;
|
||||
};
|
||||
|
||||
systemd.user.services.sunshine = {
|
||||
serviceConfig = {
|
||||
Restart = pkgs.lib.mkForce "always";
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
pulseaudio.enable = false;
|
||||
sunshine = {
|
||||
enable = true;
|
||||
autoStart = true;
|
||||
package = sunshinePkg;
|
||||
settings = {
|
||||
sunshine_name = "The Architect";
|
||||
capture = "nvfbc";
|
||||
encoder = "nvenc";
|
||||
wan_encryption_mode = 0;
|
||||
lan_encryption_mode = 0;
|
||||
origin_web_ui_allowed = "lan";
|
||||
min_threads = 12;
|
||||
log_path = "sunshine.log";
|
||||
back_button_timeout = 2500;
|
||||
};
|
||||
applications = {
|
||||
env = {
|
||||
VDPAU_DRIVER = "nvidia";
|
||||
LIBVA_DRIVER_NAME = "nvidia";
|
||||
NVD_BACKEND = "direct";
|
||||
__GL_SYNC_TO_VBLANK = "0";
|
||||
__GL_VRR_ALLOWED = "0";
|
||||
DXVK_ASYNC = "1";
|
||||
};
|
||||
apps = [
|
||||
{
|
||||
name = "Steam w/ Hue Lights";
|
||||
cmd = ''${pkgs.bash}/bin/bash -c "${pkgs.gamescope}/bin/gamescope --adaptive-sync --force-composition --immediate-flips --rt -C 3000 -f -e -W ''${SUNSHINE_CLIENT_WIDTH} -H ''${SUNSHINE_CLIENT_HEIGHT} -r ''${SUNSHINE_CLIENT_FPS} -- ${pkgs.steam}/bin/steam -pipewire"'';
|
||||
detached = [
|
||||
"${pkgs.pepePkgs.huenicorn}/bin/huenicorn"
|
||||
];
|
||||
prep-cmd = [
|
||||
{
|
||||
do = ''${pkgs.bash}/bin/bash -c "${resolutionScript}/bin/resolution.sh ''${SUNSHINE_CLIENT_WIDTH} ''${SUNSHINE_CLIENT_HEIGHT}" ''${SUNSHINE_CLIENT_FPS}"'';
|
||||
undo = ''${pkgs.bash}/bin/bash -c "${pkgs.procps}/bin/pkill gamescope; ${pkgs.procps}/bin/pkill sunshine; ${pkgs.procps}/bin/pkill -KILL huenicorn"'';
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "Steam";
|
||||
cmd = ''${pkgs.bash}/bin/bash -c "${pkgs.steam}/bin/steam -pipewire"'';
|
||||
prep-cmd = [
|
||||
{
|
||||
do = ''${pkgs.bash}/bin/bash -c "${resolutionScript}/bin/resolution.sh ''${SUNSHINE_CLIENT_WIDTH} ''${SUNSHINE_CLIENT_HEIGHT}" ''${SUNSHINE_CLIENT_FPS}"'';
|
||||
undo = ''${pkgs.bash}/bin/bash -c "${pkgs.procps}/bin/pkill gamescope; ${pkgs.procps}/bin/pkill sunshine"'';
|
||||
}
|
||||
];
|
||||
}
|
||||
{
|
||||
name = "Heroic";
|
||||
cmd = ''${pkgs.bash}/bin/bash -c "${pkgs.unstablePkgs.heroic}/bin/heroic"'';
|
||||
prep-cmd = [
|
||||
{
|
||||
do = ''${pkgs.bash}/bin/bash -c "${resolutionScript}/bin/resolution.sh ''${SUNSHINE_CLIENT_WIDTH} ''${SUNSHINE_CLIENT_HEIGHT}" ''${SUNSHINE_CLIENT_FPS}"'';
|
||||
undo = ''${pkgs.bash}/bin/bash -c "${pkgs.procps}/bin/pkill heroic; ${pkgs.procps}/bin/pkill sunshine"'';
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
displayManager = {
|
||||
autoLogin = {
|
||||
inherit user;
|
||||
enable = true;
|
||||
};
|
||||
|
||||
sddm = {
|
||||
enable = true;
|
||||
wayland.enable = false;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
xserver = {
|
||||
enable = true;
|
||||
desktopManager.xfce.enable = true;
|
||||
|
||||
monitorSection = ''
|
||||
HorizSync 5.0 - 1000.0
|
||||
VertRefresh 5.0 - 1000.0
|
||||
Option "DPMS"
|
||||
'';
|
||||
|
||||
deviceSection = ''
|
||||
VendorName "NVIDIA Corporation"
|
||||
Option "CustomEDID" "DFP-1:/etc/X11/120edid.bin"
|
||||
Option "ConnectedMonitor" "DFP-1"
|
||||
'';
|
||||
|
||||
screenSection = ''
|
||||
Monitor "Configured Monitor"
|
||||
DefaultDepth 24
|
||||
|
||||
Option "ModeValidation" "NoVertRefreshCheck, NoHorizSyncCheck, NoMaxSizeCheck, NoMaxPClkCheck, AllowNonEdidModes, NoEdidMaxPClkCheck"
|
||||
Option "UseEdidfreqs" "False"
|
||||
Option "TripleBuffer" "False"
|
||||
|
||||
SubSection "Display"
|
||||
Depth 24
|
||||
EndSubSection
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.targets = {
|
||||
sleep.enable = false;
|
||||
suspend.enable = false;
|
||||
hibernate.enable = false;
|
||||
hybrid-sleep.enable = false;
|
||||
};
|
||||
|
||||
users = {
|
||||
users.${user} = {
|
||||
isNormalUser = true;
|
||||
home = "/home/${user}";
|
||||
description = "Sunshine Server";
|
||||
extraGroups = [ "wheel" "networkmanager" "input" "video" "sound" ];
|
||||
openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1we38/N+t8Ah5yrLof8QUwhrob7/VXFKIddaJeOVBLuDVnW7ljiAtdtEiL69D/DV4Ohmt5wMvkAAjfuHmim6FD9A6lzPbSU4KH9W2dcckszKbbI636kuDwem/xui6BW3wJa6P+0xW5ksygEAkzcK2PXuC2b4B9uwhuUdKahiGMKDxISG/WianqAe72cGMfNkYvion3Y1VsMLUdm48d2ABnxNpr7NI9B5iJ8dziOft9gpgfz13CCQRlReo75gk/4xI+vSNrQp7eR+wzJy2/dZg/T8jtyA9Q6jVxrxBpqQ1LNXkAKaJkGo9OabF6Wgpzp+YTAurL4nwR2NaJxwFuyoKvACQy0ai4jrS3206gC6JXZv8ktZMZrwUN+jPqCwfgh5qObFkAqKCxbp52ioDek2MQLdOvzQBX//DBhGEp5rzHGLZ3vhRIiiQiaof5sF5zWiYDW5mqezSPNxJPX/BrTP/Wbs/jpwTLBh3wytiia0S1WXQmya89bqzTPFiDWvTRA62EVKB/JaQtPQQOFAxWwg799DMycPeZ81xttZOyMtI/MZSddyqx2S8fWGwvToZQvuZ38mSIpFseLM1IkgabRIrAmat5SBNGGy9Dqa0eMEa7bwIY/4CMB1y6HMTnaoMXA6cnQfHMoB/zyTZ6oTXIeqeOyiZsK+RN0Mvahj8mXi7dw== giulio@giulio-X230" ];
|
||||
};
|
||||
|
||||
groups.media.members = [ user ];
|
||||
};
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
{ pkgs, config, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "devs.giugl.io";
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) generateDeviceStrings;
|
||||
in
|
||||
{
|
||||
pepe.core = {
|
||||
firewall.openUDP = [ 41641 ];
|
||||
|
||||
network.interfaces.tailscale = {
|
||||
interface = "ts0";
|
||||
net = "100.64.0.0/10";
|
||||
type = "vpn";
|
||||
devices = {
|
||||
architect = { address = "100.64.0.1"; hostname = "architect.${domain}"; isEndpoint = true; };
|
||||
kmerr = { address = "100.64.0.2"; hostname = "kmerr.${domain}"; };
|
||||
work_laptop = { address = "100.64.0.4"; hostname = "work_laptop.${domain}"; };
|
||||
work_desktop = { address = "100.64.0.5"; hostname = "work_desktop.${domain}"; };
|
||||
manduria = { address = "100.64.0.6"; hostname = "manduria.${domain}"; };
|
||||
tommy = { address = "100.64.0.7"; hostname = "tommy.${domain}"; };
|
||||
alfredo = { address = "100.64.0.9"; hostname = "alfredo.${domain}"; };
|
||||
appletv = { address = "100.64.0.13"; hostname = "appletv.${domain}"; };
|
||||
afsun = { address = "100.64.0.15"; hostname = "afsun.${domain}"; };
|
||||
jacopo-desktop = { address = "100.64.0.21"; hostname = "jacopo-desktop.${domain}"; };
|
||||
jacopo-tv = { address = "100.64.0.22"; hostname = "jacopo-tv.${domain}"; };
|
||||
jacopo-phone = { address = "100.64.0.28"; hostname = "jacopo-phone.${domain}"; };
|
||||
jacopo-ipad = { address = "100.64.0.8"; hostname = "jacopo-ipad.${domain}"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
tailscale = {
|
||||
enable = true;
|
||||
interfaceName = config.pepe.core.network.interfaces.tailscale.interface;
|
||||
package = pkgs.unstablePkgs.tailscale;
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = generateDeviceStrings config.pepe.core.network.interfaces.tailscale.devices;
|
||||
}
|
43
hosts/architect/transmission.nix
Normal file
43
hosts/architect/transmission.nix
Normal file
@ -0,0 +1,43 @@
|
||||
{ lib, config, ... }:
|
||||
|
||||
let
|
||||
domain = "httra.giugl.io";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
transmission = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
settings = {
|
||||
download-dir = "/media/transmission";
|
||||
incomplete-dir = "/media/transmission/.incomplete";
|
||||
rpc-host-whitelist = "${domain}";
|
||||
encryption = 2;
|
||||
speed-limit-up = 10;
|
||||
speed-limit-up-enabled = true;
|
||||
peer-port = 51413;
|
||||
};
|
||||
performanceNetParameters = true;
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://localhost:9091";
|
||||
extraConfig = ''
|
||||
allow 10.0.0.0/24;
|
||||
${lib.concatMapStrings (x: "allow ${x};") network.gdevices-wg}
|
||||
deny all;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "transmission" ];
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
ifaces = config.pepe.core.network.interfaces;
|
||||
in
|
||||
{
|
||||
# device.address device.hostname
|
||||
generateDeviceStrings = devices: lib.concatStringsSep "\n"
|
||||
(lib.mapAttrsToList (name: device: "${device.address} ${device.hostname}") devices);
|
||||
|
||||
getDeviceAddress = interface: device:
|
||||
ifaces.${interface}.devices.${device}.address;
|
||||
|
||||
architectInterfaceAddress = interface:
|
||||
ifaces.${interface}.devices.architect.address;
|
||||
}
|
270
hosts/architect/wireguard.nix
Normal file
270
hosts/architect/wireguard.nix
Normal file
@ -0,0 +1,270 @@
|
||||
with import ./network.nix; {
|
||||
networking = {
|
||||
extraHosts = ''
|
||||
${architect-wg} architect.devs.giugl.io
|
||||
${galuminum-wg} galuminum.devs.giugl.io
|
||||
${oneplus-wg} oneplus.devs.giugl.io
|
||||
${ipad-wg} ipad.devs.giugl.io
|
||||
${manduria-wg} manduria.devs.giugl.io
|
||||
${antonio-wg} antonio.devs.giugl.io
|
||||
${gbeast-wg} gbeast.devs.giugl.io
|
||||
${parisaphone-wg} parisa-phone.devs.giugl.io
|
||||
${parisapc-wg} parisa-pc.devs.giugl.io
|
||||
${peppiniell-wg} peppiniell.devs.giugl.io
|
||||
${padulino-wg} padulino.devs.giugl.io
|
||||
${shield-wg} shield.devs.giugl.io
|
||||
${pepos-wg} pepos.devs.giugl.io
|
||||
${eleonora-wg} eleonora.devs.giugl.io
|
||||
${angellane-wg} angellane.devs.giugl.io
|
||||
${hotpottino-wg} hotpottino.devs.giugl.io
|
||||
${salvatore-wg} salvatore.devs.giugl.io
|
||||
${papa-wg} papa.devs.giugl.io
|
||||
${defy-wg} defy.devs.giugl.io
|
||||
${germano-wg} germano.devs.giugl.io
|
||||
${dodino-wg} dodino.devs.giugl.io
|
||||
${tommy-wg} tommy.devs.giugl.io
|
||||
${alain-wg} alain.devs.giugl.io
|
||||
${dima-wg} dima.devs.giugl.io
|
||||
${mikey-wg} mikey.devs.giugl.io
|
||||
${andrew-wg} andrew.devs.giugl.io
|
||||
${mikeylaptop-wg} mikeylaptop.devs.giugl.io
|
||||
${wolfsonhouse-wg} wolfsonhouse.devs.giugl.io
|
||||
${frznn-wg} frznn.devs.giugl.io
|
||||
${ludo-wg} ludo.devs.giugl.io
|
||||
${parina-wg} parina.devs.giugl.io
|
||||
${parina-ipad-wg} parinaipad.devs.giugl.io
|
||||
${nilo-wg} nilo.devs.giugl.io
|
||||
'';
|
||||
|
||||
wireguard = {
|
||||
interfaces.${proxy-if} = {
|
||||
ips = [ "10.4.0.2/32" ];
|
||||
privateKeyFile = "/secrets/wireguard/proxy.key";
|
||||
peers = [{
|
||||
publicKey = "WmJBpXpYebcmJEF8nVTKMqQK01KyBe42vzc38K66rVs=";
|
||||
allowedIPs = [ "10.4.0.1/32" ];
|
||||
endpoint = "giugl.io:1195";
|
||||
persistentKeepalive = 21;
|
||||
}];
|
||||
};
|
||||
|
||||
interfaces.${vpn-if} = {
|
||||
listenPort = 1194;
|
||||
ips = [ "10.3.0.1/24" ];
|
||||
privateKeyFile = "/secrets/wireguard/server.key";
|
||||
|
||||
peers = [
|
||||
{
|
||||
# gAluminum
|
||||
allowedIPs = [ galuminum-wg ];
|
||||
publicKey = "pEEgSs7xmO0cfyvoQlU8lfwqdYM1ISgmPAunPtF+0xw=";
|
||||
}
|
||||
|
||||
{
|
||||
# OnePlus
|
||||
allowedIPs = [ oneplus-wg ];
|
||||
publicKey = "zynSERy6VhxN5zBf1ih3BOAHxvigDixHB9YKnSBgYFs=";
|
||||
}
|
||||
|
||||
{
|
||||
# iPad
|
||||
allowedIPs = [ ipad-wg ];
|
||||
publicKey = "DPpd+P/hV1XLuvdcrCRv1sgz8BeZt1y5D6VehNuhjSQ=";
|
||||
}
|
||||
|
||||
{
|
||||
# Manduria
|
||||
allowedIPs = [ manduria-wg ];
|
||||
publicKey = "wT38oXvDQ8g0hI+pAXQobOWf/Wott2zhwo8TLvXK400=";
|
||||
}
|
||||
|
||||
{
|
||||
# Antonio
|
||||
allowedIPs = [ antonio-wg ];
|
||||
publicKey = "SPndCvEzuLHtGAQV8u/4dfLlFHoPcXS3L98oFOwTljc=";
|
||||
}
|
||||
|
||||
{
|
||||
# Eleonora
|
||||
allowedIPs = [ eleonora-wg ];
|
||||
publicKey = "SL54f1ZeieFyn5X5UAPmypP10GV/c419O94vCzGHFhg=";
|
||||
}
|
||||
|
||||
{
|
||||
# padulino
|
||||
allowedIPs = [ padulino-wg ];
|
||||
publicKey = "sk2Wr2OesND9jcuP/8k7BirSpR4pNNbS9gBkbOxZxwg=";
|
||||
}
|
||||
|
||||
{
|
||||
# GBEAST
|
||||
allowedIPs = [ gbeast-wg ];
|
||||
publicKey = "XiK+wk+DErz0RmCWRxuaJN1cvdj+3DoiU6tcR+uZfAI=";
|
||||
}
|
||||
|
||||
{
|
||||
# parisa-phone
|
||||
allowedIPs = [ parisaphone-wg ];
|
||||
publicKey = "MGdaRMmsik7SLRUsijS0TctcKUD6Tnr7XugGJClTCC4=";
|
||||
}
|
||||
|
||||
{
|
||||
# parisa-pc
|
||||
allowedIPs = [ parisapc-wg ];
|
||||
publicKey = "b2QzZDTgGQbNXSCLYB4KUzq0/099pH2T8H5BckfNSTQ=";
|
||||
}
|
||||
|
||||
{
|
||||
# peppiniell
|
||||
allowedIPs = [ peppiniell-wg ];
|
||||
publicKey = "bzoW3Rx+7Un9hx/2opgBQJmmnZ/hgj1lQ2FnonCHjTc=";
|
||||
}
|
||||
|
||||
{
|
||||
# angellane
|
||||
allowedIPs = [ angellane-wg ];
|
||||
publicKey = "MZ+nZklHpBxTL7QN9QJpBBx7yOYRZLONfvqAnuk85x0=";
|
||||
}
|
||||
|
||||
{
|
||||
# hotpottino
|
||||
allowedIPs = [ hotpottino-wg ];
|
||||
publicKey = "YqtzTWqGBs2GwSPNO0aRSV4nvJDW3UHHt6fV4UC7vnU=";
|
||||
}
|
||||
|
||||
{
|
||||
# shield
|
||||
allowedIPs = [ shield-wg ];
|
||||
publicKey = "1GaV/M48sHqQTrBVRQ+jrFU2pUMmv2xkguncVcwPCFs=";
|
||||
}
|
||||
|
||||
{
|
||||
# pepos
|
||||
allowedIPs = [ pepos-wg ];
|
||||
publicKey = "mb1VaMLML5J24oCMBuhqvBrT6S4tAqWERn30z+h/LwM=";
|
||||
}
|
||||
|
||||
{
|
||||
# salvatore
|
||||
allowedIPs = [ salvatore-wg ];
|
||||
publicKey = "fhlnBHeMyHZKLUCTSA9kmkKoM5x/qzz/rnCJrUh3Gzs=";
|
||||
}
|
||||
|
||||
{
|
||||
# papa
|
||||
allowedIPs = [ papa-wg ];
|
||||
publicKey = "oGHygt02Oni3IFbScKD0NVEfHKCp6bpw68aq5g4RrAA=";
|
||||
}
|
||||
|
||||
{
|
||||
# defy
|
||||
allowedIPs = [ defy-wg ];
|
||||
publicKey = "Cvi/eto7E6Ef+aiL81ou7x12fJCeuXrf/go9fxEqXG4=";
|
||||
}
|
||||
|
||||
{
|
||||
# germano
|
||||
allowedIPs = [ germano-wg ];
|
||||
publicKey = "gi4o+pZWKItzVs7vY8fvXh98jX6CNeCwc1YDzhc3mA4=";
|
||||
}
|
||||
|
||||
{
|
||||
# flavio
|
||||
allowedIPs = [ flavio-wg ];
|
||||
publicKey = "Yg0P+yHi/9SZHyoel8jT9fmmu+irLYmT8yMp/CZoaSg=";
|
||||
}
|
||||
|
||||
{
|
||||
# dodino
|
||||
allowedIPs = [ dodino-wg ];
|
||||
publicKey = "JHkqlADQpY1CUcivraG9i6rIzCzLVFcl8HP5uIk35lk=";
|
||||
}
|
||||
|
||||
{
|
||||
# tommy
|
||||
allowedIPs = [ tommy-wg ];
|
||||
publicKey = "tytknU7wql1d0A2provX3RP7CNcEIajfgBJKoSyVLgo=";
|
||||
}
|
||||
|
||||
{
|
||||
# alain
|
||||
allowedIPs = [ alain-wg ];
|
||||
publicKey = "/o2msFJoUL4yovcIQJTU8c1faFtekrjSBBWJABouWno=";
|
||||
}
|
||||
|
||||
{
|
||||
# dima
|
||||
allowedIPs = [ dima-wg ];
|
||||
publicKey = "svzWYIZ6v+cLCp/emGG7mx2YpBJqw2fqjVuHZy7b6H0=";
|
||||
}
|
||||
|
||||
{
|
||||
# wolfsonhouse
|
||||
allowedIPs = [ wolfsonhouse-wg ];
|
||||
publicKey = "UJRJcAOcnEjEB3o4K2I7gEM97SrhENEesZNf28z+EBQ=";
|
||||
}
|
||||
|
||||
{
|
||||
# mikey
|
||||
allowedIPs = [ mikey-wg ];
|
||||
publicKey = "ewbDdX3z7nxG2aPIf9TogXkhxPlGipLFcy6XfyDC6gI=";
|
||||
}
|
||||
|
||||
{
|
||||
# andrew
|
||||
allowedIPs = [ andrew-wg ];
|
||||
publicKey = "LP/FgST9fmBQSoKQFq9sFGvjRFOtRooMcuEcjuqaoWM=";
|
||||
}
|
||||
|
||||
{
|
||||
# mikey laptop
|
||||
allowedIPs = [ mikeylaptop-wg ];
|
||||
publicKey = "kz/pY/PgV+dwF1JZ2It4r5B5QfRSQM7HkbFCdvd5Yxk=";
|
||||
}
|
||||
|
||||
{
|
||||
# andrew desktop
|
||||
allowedIPs = [ andrewdesktop-wg ];
|
||||
publicKey = "rpYr3JNLIzxpxzFuQuaHFEl/XvPEPfwLbDETBP8KYXI=";
|
||||
}
|
||||
|
||||
{
|
||||
# laptop desktop
|
||||
allowedIPs = [ jacopo-wg ];
|
||||
publicKey = "W/taWI79bPIKOolVVu5xZfiJnPw9K91Xn1zhcM0+4g0=";
|
||||
}
|
||||
|
||||
{
|
||||
# frznn
|
||||
allowedIPs = [ frznn-wg ];
|
||||
publicKey = "dXcrdME6VnnE5PBYwvUmayf7cn2wpcExeCR9gIXOO0o=";
|
||||
}
|
||||
|
||||
{
|
||||
# ludo
|
||||
allowedIPs = [ ludo-wg ];
|
||||
publicKey = "ecrxdzx7tQZwMPxZOjHUvxZT2xY79B6XEDIW+fhEtEM=";
|
||||
}
|
||||
|
||||
{
|
||||
# parina
|
||||
allowedIPs = [ parina-wg ];
|
||||
publicKey = "7nubNnfGsg4/7KemMDn9r99mNK8RFU9uOFFqaYv6rUA=";
|
||||
}
|
||||
|
||||
{
|
||||
# nilo
|
||||
allowedIPs = [ nilo-wg ];
|
||||
publicKey = "lhTEDJ9WnizvEHTd5kN21fTHF27HNk+fPLQnB1B3LW0=";
|
||||
}
|
||||
|
||||
{
|
||||
# parina ipad
|
||||
allowedIPs = [ parina-ipad-wg ];
|
||||
publicKey = "ezkCzl2qC7Hd7rFKfqMa0JXDKRhVqy79H52rA06x7mU=";
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -9,8 +9,7 @@ let
|
||||
export __VK_LAYER_NV_optimus=NVIDIA_only
|
||||
exec -a "$0" "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
in {
|
||||
imports = [ ./hardware.nix ./wireguard.nix ./sound.nix ];
|
||||
|
||||
boot = {
|
||||
@ -71,5 +70,5 @@ in
|
||||
|
||||
programs.steam.enable = true;
|
||||
environment.systemPackages = with pkgs; [ efibootmgr nvidia-offload ];
|
||||
# system.stateVersion = "21.05"; # Did you read the comment?
|
||||
system.stateVersion = "21.05"; # Did you read the comment?
|
||||
}
|
||||
|
73
hosts/proxy/coturn.nix
Normal file
73
hosts/proxy/coturn.nix
Normal file
@ -0,0 +1,73 @@
|
||||
{ pkgs, config, ... }:
|
||||
|
||||
let
|
||||
public_ip = "23.88.108.216";
|
||||
realm = "turn.giugl.io";
|
||||
static-auth-secret = "69duck duck fuck420";
|
||||
in {
|
||||
services.coturn = rec {
|
||||
inherit realm static-auth-secret;
|
||||
|
||||
secure-stun = true;
|
||||
enable = true;
|
||||
no-cli = true;
|
||||
no-tcp-relay = true;
|
||||
min-port = 49000;
|
||||
max-port = 50000;
|
||||
use-auth-secret = true;
|
||||
relay-ips = [ public_ip ];
|
||||
listening-ips = [ public_ip ];
|
||||
cert = "${config.security.acme.certs.${realm}.directory}/full.pem";
|
||||
pkey = "${config.security.acme.certs.${realm}.directory}/key.pem";
|
||||
extraConfig = ''
|
||||
verbose
|
||||
|
||||
cipher-list=\"HIGH\"
|
||||
no-multicast-peers
|
||||
denied-peer-ip=0.0.0.0-0.255.255.255
|
||||
denied-peer-ip=10.0.0.0-10.255.255.255
|
||||
denied-peer-ip=100.64.0.0-100.127.255.255
|
||||
denied-peer-ip=127.0.0.0-127.255.255.255
|
||||
denied-peer-ip=169.254.0.0-169.254.255.255
|
||||
denied-peer-ip=172.16.0.0-172.31.255.255
|
||||
denied-peer-ip=192.0.0.0-192.0.0.255
|
||||
denied-peer-ip=192.0.2.0-192.0.2.255
|
||||
denied-peer-ip=192.88.99.0-192.88.99.255
|
||||
denied-peer-ip=192.168.0.0-192.168.255.255
|
||||
denied-peer-ip=198.18.0.0-198.19.255.255
|
||||
denied-peer-ip=198.51.100.0-198.51.100.255
|
||||
denied-peer-ip=203.0.113.0-203.0.113.255
|
||||
denied-peer-ip=240.0.0.0-255.255.255.255
|
||||
denied-peer-ip=::1
|
||||
denied-peer-ip=64:ff9b::-64:ff9b::ffff:ffff
|
||||
denied-peer-ip=::ffff:0.0.0.0-::ffff:255.255.255.255
|
||||
denied-peer-ip=100::-100::ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=2001::-2001:1ff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=2002::-2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
|
||||
'';
|
||||
};
|
||||
networking.firewall = {
|
||||
interfaces.ens3 = let
|
||||
range = with config.services.coturn; [{
|
||||
from = min-port;
|
||||
to = max-port;
|
||||
}];
|
||||
in {
|
||||
allowedUDPPortRanges = range;
|
||||
allowedUDPPorts = [ 5349 ];
|
||||
#allowedTCPPortRanges = range;
|
||||
allowedTCPPorts = [ 80 443 5349 ];
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.enable = true;
|
||||
services.nginx.virtualHosts.${realm} = {
|
||||
addSSL = true;
|
||||
enableACME = true;
|
||||
};
|
||||
|
||||
# to access the ACME files
|
||||
users.groups.nginx.members = [ "turnserver" ];
|
||||
}
|
26
hosts/proxy/default.nix
Normal file
26
hosts/proxy/default.nix
Normal file
@ -0,0 +1,26 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ ./hardware-configuration.nix ./coturn.nix ./wireguard.nix ./ssh.nix ];
|
||||
|
||||
boot.loader.grub = {
|
||||
enable = true;
|
||||
version = 2;
|
||||
devices = [ "/dev/sda" ];
|
||||
};
|
||||
|
||||
system.stateVersion = "21.05";
|
||||
|
||||
networking = {
|
||||
useDHCP = false;
|
||||
hostName = "proxy";
|
||||
nameservers = [ "10.4.0.2" "1.1.1.1" ];
|
||||
|
||||
interfaces.ens3.useDHCP = true;
|
||||
};
|
||||
|
||||
users.users.root.openssh.authorizedKeys.keys = [
|
||||
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCuURERnIFe2XbNu6AsPe2DO11RuaHxVGUcaoJUsIB1F+VOggOVLhxSenOPYLm6NvvGeXVi95G5Sm1UZRcJEEkvxus4bSViV4t/Q2azfYFE27yRH/IeMMoWNPGYNm5Bok2qFb4vHifra9FffwXnOzr0nDDTdHXCft4TO5nsenLJwqu5zOO1CR7J52otY7LheNPyzbGxgIkB3Y7LeOj1+/xXSOJ379NOL2RQBobsg7k442WCX7tU6AC1ct3W+93tcJUUdzJKTT9TJ+XmhdjXNWhDd+QZUNAMr+nKoEdExHp0H40/wIhcLD2OV95gX4i/YBzCg4OQOqZqWiibiEQfGTSAh5aD+nX/PqjXf0XSLEUOA81biLFu28oO8gocjwnhgqmlghvO4SG1rs6uZ8EyPyWsrVMjy8B9FX4aloKqua3aicgC+upjLl3x+KkMJizlMB5Ew7KOjPsjXwMqeJmeBOEd6TSEctttR+lIp+/368FtwXeBxzx9MBT4620mnjWtVKM= giulio@gAluminum"
|
||||
];
|
||||
}
|
22
hosts/proxy/hardware-configuration.nix
Normal file
22
hosts/proxy/hardware-configuration.nix
Normal file
@ -0,0 +1,22 @@
|
||||
# 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 =
|
||||
[ "ata_piix" "virtio_pci" "virtio_scsi" "xhci_pci" "sd_mod" "sr_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-uuid/8b5bcd4a-02b8-4e11-b856-eda792b8b7b8";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
}
|
15
hosts/proxy/ssh.nix
Normal file
15
hosts/proxy/ssh.nix
Normal file
@ -0,0 +1,15 @@
|
||||
{ config, ... }:
|
||||
|
||||
{
|
||||
services = {
|
||||
fail2ban.enable = true;
|
||||
|
||||
openssh = {
|
||||
permitRootLogin = "prohibit-password";
|
||||
passwordAuthentication = false;
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = [ 22 ];
|
||||
}
|
42
hosts/proxy/wireguard.nix
Normal file
42
hosts/proxy/wireguard.nix
Normal file
@ -0,0 +1,42 @@
|
||||
{ config, ... }:
|
||||
|
||||
let
|
||||
wg_if = "wg0";
|
||||
wan_if = "ens3";
|
||||
in {
|
||||
networking = {
|
||||
firewall.allowedUDPPorts = [ 1195 ];
|
||||
|
||||
nat = {
|
||||
enable = true;
|
||||
externalInterface = wan_if;
|
||||
internalInterfaces = [ wg_if ];
|
||||
forwardPorts = [{
|
||||
destination = "10.4.0.2:1194";
|
||||
proto = "udp";
|
||||
sourcePort = 1194;
|
||||
}];
|
||||
};
|
||||
|
||||
wireguard = {
|
||||
interfaces.${wg_if} = {
|
||||
listenPort = 1195;
|
||||
ips = [ "10.4.0.1/24" ];
|
||||
privateKeyFile = "/secrets/wireguard/server.key";
|
||||
|
||||
postSetup = ''
|
||||
/run/current-system/sw/bin/iptables -t nat -A POSTROUTING -o ${wg_if} -j MASQUERADE
|
||||
'';
|
||||
|
||||
postShutdown = ''
|
||||
/run/current-system/sw/bin/iptables -t nat -D POSTROUTING -o ${wg_if} -j MASQUERADE
|
||||
'';
|
||||
|
||||
peers = [{
|
||||
allowedIPs = [ "10.4.0.2" "10.3.0.0/24" ];
|
||||
publicKey = "73oFhyQA3mgX4GmN6ul5HuOsgxa4INlzCPsyuXna0AA=";
|
||||
}];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
rec {
|
||||
architect = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICu7rSsZ+d3BkppimNHJj8xL5jfl5RxMU0+Q5cue0LUu root@architect";
|
||||
architectHostKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGLLAtRzLtCExHLhpsC+vH1nXcla3wibbMOFRCwXfXjtn2A9DjewHBwcbQbYQa6yuaEa3vmvUyrUtW6RUAiGSNhDMUPz7swr5tujgO/6ToPf0vKDDeOCwK5wqmNoUlDf7qzkxwCiI0dPYuCr7uGt00/ebSGfp+F1zmgC9MxuefYMdX5Q5I7HoHOYbBC9q9ue5mc0g+F8GnmD+Pd2pDDiHpCflT+iOzLJH0gCcW/0e5q7XYKGs09Cm/L1zroHIb14Borndu0Mby7x2FlnSeap5KXr9rkKVyr3amX0mksb4N0T36MMJwLYcrvE0S8utFdHEusoYEkP3fjSgsKKHKEgiZbqaeA0oZHddG49JNBsCLmmrN8T142t1fftP4NdFyKpcI9gYsbXhZf6bheV1wQ/cpv3KkLGG7JlZeORRAc4xgT33BHvVXTcWCE2EYcNmdscrMOEw3mcDESu7S14iXZgGIUgYISZ3GTZ5+mNB6OoEwxqK+eYzYMyDpNBxv6/LlEvc= root@architect";
|
||||
macbook = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC1we38/N+t8Ah5yrLof8QUwhrob7/VXFKIddaJeOVBLuDVnW7ljiAtdtEiL69D/DV4Ohmt5wMvkAAjfuHmim6FD9A6lzPbSU4KH9W2dcckszKbbI636kuDwem/xui6BW3wJa6P+0xW5ksygEAkzcK2PXuC2b4B9uwhuUdKahiGMKDxISG/WianqAe72cGMfNkYvion3Y1VsMLUdm48d2ABnxNpr7NI9B5iJ8dziOft9gpgfz13CCQRlReo75gk/4xI+vSNrQp7eR+wzJy2/dZg/T8jtyA9Q6jVxrxBpqQ1LNXkAKaJkGo9OabF6Wgpzp+YTAurL4nwR2NaJxwFuyoKvACQy0ai4jrS3206gC6JXZv8ktZMZrwUN+jPqCwfgh5qObFkAqKCxbp52ioDek2MQLdOvzQBX//DBhGEp5rzHGLZ3vhRIiiQiaof5sF5zWiYDW5mqezSPNxJPX/BrTP/Wbs/jpwTLBh3wytiia0S1WXQmya89bqzTPFiDWvTRA62EVKB/JaQtPQQOFAxWwg799DMycPeZ81xttZOyMtI/MZSddyqx2S8fWGwvToZQvuZ38mSIpFseLM1IkgabRIrAmat5SBNGGy9Dqa0eMEa7bwIY/4CMB1y6HMTnaoMXA6cnQfHMoB/zyTZ6oTXIeqeOyiZsK+RN0Mvahj8mXi7dw== giulio@giulio-X230";
|
||||
|
||||
groups.architect = [ architect architectHostKey ];
|
||||
}
|
6
lib/default.nix
Normal file
6
lib/default.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{ pkgs, unstable, nixpkgs, nixos-unstable, home-manager, ... }: rec {
|
||||
user = import ./user.nix { inherit pkgs unstable; };
|
||||
host = import ./host.nix {
|
||||
inherit pkgs nixpkgs unstable nixos-unstable home-manager user;
|
||||
};
|
||||
}
|
59
lib/host.nix
59
lib/host.nix
@ -1,49 +1,44 @@
|
||||
{ pkgs
|
||||
, nixpkgs
|
||||
, home-manager
|
||||
, system
|
||||
, mkSysRole
|
||||
, mkUser
|
||||
, ...
|
||||
}:
|
||||
{ pkgs, nixpkgs, nixos-unstable, unstable, home-manager, user, ... }:
|
||||
|
||||
{
|
||||
mkHost = { name, users, roles ? [], imports ? [] }:
|
||||
let
|
||||
users_mod = (map
|
||||
(u:
|
||||
mkUser {
|
||||
name = u.user;
|
||||
roles = u.roles;
|
||||
})
|
||||
users);
|
||||
roles_mod = (map (r: mkSysRole r) roles);
|
||||
system = "x86_64-linux";
|
||||
|
||||
mkRole = role : import (../roles + "/${role}.nix");
|
||||
|
||||
users_mod= (map (u: user.mkUser {name = u.user; roles = u.roles; }) users);
|
||||
roles_mod = (map (r: mkRole r) roles);
|
||||
add_imports = imports;
|
||||
in
|
||||
nixpkgs.lib.nixosSystem {
|
||||
inherit system pkgs;
|
||||
in nixpkgs.lib.nixosSystem {
|
||||
inherit system;
|
||||
|
||||
modules = [
|
||||
{
|
||||
imports = users_mod ++
|
||||
roles_mod ++
|
||||
add_imports ++ [
|
||||
(mkSysRole "common")
|
||||
(mkSysRole "acme")
|
||||
(mkUser { name = "root"; roles = [ ]; })
|
||||
../modules
|
||||
];
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
imports = users_mod ++ roles_mod ++ add_imports;
|
||||
nixpkgs = {
|
||||
pkgs = pkgs;
|
||||
};
|
||||
|
||||
system.stateVersion = "25.05";
|
||||
nix.nixPath = [
|
||||
"nixpkgs=${nixpkgs}"
|
||||
"unstable=${nixos-unstable}"
|
||||
];
|
||||
nix.registry.nixpkgs.flake = nixpkgs;
|
||||
nix.registry.unstable.flake = nixos-unstable;
|
||||
|
||||
users.users.root = {
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
|
||||
home-manager.users.root.imports = [ ../roles/home/common.nix ];
|
||||
home-manager.extraSpecialArgs.unstable = unstable;
|
||||
}
|
||||
|
||||
home-manager.nixosModules.home-manager
|
||||
../roles/common.nix
|
||||
../roles/acme.nix
|
||||
../hosts/${name}/default.nix
|
||||
pkgs.nixosModules.cachixConfig
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
{ nixpkgs, inputs }:
|
||||
|
||||
let
|
||||
mkSystem = { system, cudaSupport ? false }:
|
||||
let
|
||||
config = {
|
||||
inherit cudaSupport;
|
||||
allowUnfree = true;
|
||||
};
|
||||
|
||||
cachixOverlay = final: prev: {
|
||||
nixosModules = (prev.nixosModules or { }) // {
|
||||
cachixConfig = import ../cachix.nix;
|
||||
};
|
||||
};
|
||||
|
||||
extOverlays = [
|
||||
(inputs.nvidia-patch.overlays.default)
|
||||
cachixOverlay
|
||||
];
|
||||
|
||||
importNixpkgs = { flake }:
|
||||
import flake {
|
||||
inherit system config;
|
||||
overlays = extOverlays;
|
||||
};
|
||||
|
||||
unstablePkgs = importNixpkgs { flake = inputs.nixos-unstable; };
|
||||
masterPkgs = importNixpkgs { flake = inputs.nixpkgs-master; };
|
||||
localPkgs = importNixpkgs { flake = inputs.local-unstable; };
|
||||
agenixPkgs = importNixpkgs { flake = inputs.agenix-flake; };
|
||||
pepePkgs = inputs.pepeflake.packages.${system} // inputs.pepeflake.legacyPackages.${system} or { };
|
||||
langtoolPkgs = inputs.langtool-ngrams.packages.${system} // inputs.langtool-ngrams.legacyPackages.${system} or { };
|
||||
|
||||
additionalOverlays = [
|
||||
(final: prev: { inherit unstablePkgs; })
|
||||
(final: prev: { inherit localPkgs; })
|
||||
(final: prev: { inherit agenixPkgs; })
|
||||
(final: prev: { inherit masterPkgs; })
|
||||
(final: prev: { inherit pepePkgs; })
|
||||
(final: prev: { inherit langtoolPkgs; })
|
||||
];
|
||||
|
||||
pkgs = import nixpkgs {
|
||||
inherit system config;
|
||||
overlays = additionalOverlays ++ extOverlays ++ [
|
||||
(final: prev: {
|
||||
ctranslate2 = prev.ctranslate2.override {
|
||||
withCUDA = cudaSupport;
|
||||
withCuDNN = cudaSupport;
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
utils =
|
||||
let
|
||||
inherit (pkgs.lib) makeScope;
|
||||
inherit (pkgs) newScope;
|
||||
in
|
||||
makeScope newScope (self: rec {
|
||||
inherit nixpkgs inputs;
|
||||
inherit (self.callPackage ../lib/utils.nix { }) mkSysRole mkHomeRole;
|
||||
inherit (user) mkUser;
|
||||
|
||||
user = self.callPackage ../lib/user.nix { home-manager = inputs.home-manager; };
|
||||
host = self.callPackage ../lib/host.nix { home-manager = inputs.home-manager; };
|
||||
});
|
||||
in
|
||||
{ inherit pkgs utils; };
|
||||
in
|
||||
{ inherit mkSystem; }
|
62
lib/user.nix
62
lib/user.nix
@ -1,58 +1,36 @@
|
||||
{ pkgs
|
||||
, stdenv
|
||||
, home-manager
|
||||
, mkHomeRole
|
||||
, ...
|
||||
}:
|
||||
{ pkgs, unstable, ... }:
|
||||
|
||||
{
|
||||
mkUser = { name, roles ? [ ] }:
|
||||
let
|
||||
# Default roles that all NixOS users get
|
||||
defaultSystemUserRoles = [ "common" "zsh" "aichat" ];
|
||||
mkRole = role: import (../roles/home + "/${role}.nix");
|
||||
roles_mod = (map (r: mkRole r) roles);
|
||||
in {
|
||||
users.groups.plugdev = { };
|
||||
|
||||
# Default roles for standalone home-manager configs
|
||||
defaultHMUserRoles = [ "common" "aichat" ];
|
||||
in
|
||||
{
|
||||
mkUser = { name, roles ? [ ], defaultRoles ? defaultSystemUserRoles }:
|
||||
let
|
||||
roles_mod = (map (r: mkHomeRole r) roles);
|
||||
defaults_mod = (map (r: mkHomeRole r) defaultRoles);
|
||||
in
|
||||
{
|
||||
fileSystems."/home/${name}/Downloads" = pkgs.lib.mkIf stdenv.isLinux {
|
||||
fileSystems."/home/${name}/Downloads" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
options = [ "size=3G" ];
|
||||
};
|
||||
|
||||
users = {
|
||||
users.${name} = {
|
||||
isNormalUser = name != "root";
|
||||
extraGroups = [ "wheel" "plugdev" ];
|
||||
users.users.${name} = {
|
||||
isNormalUser = true;
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
extraGroups = [ "wheel" "plugdev" ];
|
||||
};
|
||||
|
||||
programs.zsh.enable = true;
|
||||
|
||||
home-manager.users.${name}.imports = defaults_mod ++ roles_mod;
|
||||
home-manager.users.${name}.imports = [ (mkRole "common") ]
|
||||
++ roles_mod;
|
||||
};
|
||||
|
||||
mkHMUser = { name, roles ? [ ], defaultRoles ? defaultHMUserRoles }:
|
||||
mkHMUser = { name, roles ? [] }:
|
||||
let
|
||||
roles_mod = (map (r: mkHomeRole r) roles);
|
||||
defaults_mod = (map (r: mkHomeRole r) defaultRoles);
|
||||
in
|
||||
home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
modules = [
|
||||
{
|
||||
home = {
|
||||
username = name;
|
||||
homeDirectory =
|
||||
if stdenv.isLinux then "/home/${name}" else "/Users/${name}";
|
||||
};
|
||||
}
|
||||
] ++ defaults_mod ++ roles_mod;
|
||||
mkRole = role: import (../roles/home + "/${role}.nix");
|
||||
in{
|
||||
home-manager.users.${name}.imports = [ (mkRole "common") ]
|
||||
++ roles_mod;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
{ ... }:
|
||||
|
||||
let
|
||||
mkSysRole = role:
|
||||
let
|
||||
path = ../roles + "/${role}.nix";
|
||||
in
|
||||
if builtins.pathExists path then
|
||||
import path
|
||||
else
|
||||
throw "System role '${role}' not found at ${toString path}";
|
||||
|
||||
mkHomeRole = role:
|
||||
let
|
||||
path = ../roles/home + "/${role}.nix";
|
||||
in
|
||||
if builtins.pathExists path then
|
||||
import path
|
||||
else
|
||||
throw "Home role '${role}' not found at ${toString path}";
|
||||
in
|
||||
{
|
||||
inherit mkSysRole mkHomeRole;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
{...}: {
|
||||
imports = [
|
||||
./media.nix
|
||||
./graphics.nix
|
||||
./network.nix
|
||||
./vhost.nix
|
||||
./firewall.nix
|
||||
./dns.nix
|
||||
./docker.nix
|
||||
];
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types mkIf concatMapStrings concatStrings mapAttrsToList attrsets;
|
||||
cfg = config.pepe.core.dns;
|
||||
in
|
||||
{
|
||||
options.pepe.core.dns = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether to enable the DNS server.";
|
||||
};
|
||||
|
||||
nextDNSId = mkOption {
|
||||
type = types.str;
|
||||
default = "d65174";
|
||||
description = "NextDNS ID for DNS over TLS.";
|
||||
};
|
||||
|
||||
extraDomains = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
dnsInterfaces = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
description = "List of interfaces to add DNS entries for this domain.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "Additional domains to add to DNS configuration.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.coredns = {
|
||||
enable = true;
|
||||
config =
|
||||
let
|
||||
# Function to generate domain-specific configurations
|
||||
generateDomainConfig = domain: conf: ifaceName:
|
||||
let
|
||||
iface = config.pepe.core.network.interfaces.${ifaceName};
|
||||
|
||||
ifaceEndpoint = lib.head (lib.attrNames (lib.filterAttrs (_: device: device.isEndpoint) iface.devices));
|
||||
serverIP = iface.devices.${ifaceEndpoint}.address;
|
||||
interfaceNet = iface.net;
|
||||
in
|
||||
''
|
||||
${domain} {
|
||||
view ${ifaceName} {
|
||||
expr incidr(client_ip(), '${interfaceNet}')
|
||||
}
|
||||
|
||||
template IN A ${domain} {
|
||||
answer "${domain}. 60 IN A ${serverIP}"
|
||||
}
|
||||
|
||||
template IN HTTPS ${domain} {
|
||||
answer "${domain}. 60 IN HTTPS 1 . ipv4hint=\"${serverIP}\""
|
||||
}
|
||||
|
||||
cache
|
||||
log
|
||||
}
|
||||
'';
|
||||
|
||||
# Function to generate device views for an interface
|
||||
generateDeviceViews = ifaceName:
|
||||
let
|
||||
iface = config.pepe.core.network.interfaces.${ifaceName};
|
||||
in
|
||||
concatMapStrings
|
||||
({ name, device }:
|
||||
let
|
||||
deviceIP = device.address;
|
||||
serverName = "${name}-${cfg.nextDNSId}.dns.nextdns.io";
|
||||
in
|
||||
''
|
||||
. {
|
||||
view ${name} {
|
||||
expr client_ip() == '${deviceIP}'
|
||||
}
|
||||
|
||||
forward . tls://45.90.28.77 tls://45.90.30.77 {
|
||||
tls_servername ${serverName}
|
||||
health_check 5s
|
||||
}
|
||||
}
|
||||
''
|
||||
)
|
||||
(attrsets.mapAttrsToList
|
||||
(name: device: { inherit name device; })
|
||||
iface.devices
|
||||
);
|
||||
|
||||
# Collect all interfaces used across all domains
|
||||
allInterfaces = lib.unique (lib.flatten
|
||||
(lib.mapAttrsToList
|
||||
(_: conf: conf.dnsInterfaces)
|
||||
(config.pepe.core.vhost.hosts // cfg.extraDomains)
|
||||
));
|
||||
|
||||
# Generate all device views once
|
||||
allDeviceViews = concatMapStrings generateDeviceViews allInterfaces;
|
||||
|
||||
# Function to generate configurations for all domains
|
||||
generateCoreDNSConfig = domains:
|
||||
let
|
||||
generateForDomain = domain: conf:
|
||||
concatMapStrings
|
||||
(ifaceName: generateDomainConfig domain conf ifaceName)
|
||||
conf.dnsInterfaces;
|
||||
in
|
||||
concatStrings (mapAttrsToList generateForDomain domains);
|
||||
|
||||
allDomains = config.pepe.core.vhost.hosts // cfg.extraDomains;
|
||||
in
|
||||
let
|
||||
# Function to generate DNS records for individual devices based on dnsResolvableName
|
||||
generateDeviceHostRecords =
|
||||
let
|
||||
generateRecordsForInterface = ifaceName: ifaceConfig:
|
||||
lib.concatStringsSep "\n" (lib.mapAttrsToList
|
||||
(deviceName: deviceConfig:
|
||||
if deviceConfig.hostname!= null then
|
||||
let
|
||||
deviceAddress = deviceConfig.address;
|
||||
deviceIface = ifaceConfig.net;
|
||||
deviceHost = deviceConfig.hostname;
|
||||
in
|
||||
''
|
||||
${deviceHost} {
|
||||
view ${ifaceName} {
|
||||
expr incidr(client_ip(), '${deviceIface}')
|
||||
}
|
||||
|
||||
template IN A ${deviceHost} {
|
||||
answer "${deviceHost}. 60 IN A ${deviceAddress}"
|
||||
}
|
||||
|
||||
cache
|
||||
log
|
||||
}
|
||||
''
|
||||
else ""
|
||||
)
|
||||
ifaceConfig.devices);
|
||||
in
|
||||
lib.concatStringsSep "\n" (lib.mapAttrsToList generateRecordsForInterface config.pepe.core.network.interfaces);
|
||||
in
|
||||
''
|
||||
${generateCoreDNSConfig allDomains}
|
||||
|
||||
${generateDeviceHostRecords}
|
||||
|
||||
${allDeviceViews}
|
||||
|
||||
. {
|
||||
forward . tls://45.90.28.77 tls://45.90.30.77 {
|
||||
tls_servername "lan-${cfg.nextDNSId}.dns.nextdns.io"
|
||||
health_check 5s
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.core.docker;
|
||||
in
|
||||
{
|
||||
options.pepe.core.docker = with lib; {
|
||||
enable = mkEnableOption "Enable Docker";
|
||||
nvidia = mkEnableOption "Enable NVIDIA Container Toolkit";
|
||||
dataRoot = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/docker";
|
||||
description = "Docker data root directory";
|
||||
};
|
||||
extraOptions = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "Extra options for Docker daemon";
|
||||
};
|
||||
enableOnBoot = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Start Docker on boot";
|
||||
};
|
||||
iptables = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether Docker should manipulate iptables";
|
||||
};
|
||||
users = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Users to add to the docker group";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
hardware.nvidia-container-toolkit.enable = cfg.nvidia;
|
||||
|
||||
virtualisation = {
|
||||
oci-containers.backend = "docker";
|
||||
|
||||
docker = {
|
||||
enable = true;
|
||||
extraOptions = cfg.extraOptions;
|
||||
enableOnBoot = cfg.enableOnBoot;
|
||||
daemon.settings = {
|
||||
iptables = cfg.iptables;
|
||||
data-root = cfg.dataRoot;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users.users = lib.genAttrs cfg.users (user: {
|
||||
extraGroups = [ "docker" ];
|
||||
});
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.pepe.core.firewall;
|
||||
in
|
||||
{
|
||||
options.pepe.core.firewall = {
|
||||
openTCP = mkOption {
|
||||
type = types.listOf types.int;
|
||||
default = [ ];
|
||||
description = "TCP ports to open in the firewall";
|
||||
};
|
||||
openUDP = mkOption {
|
||||
type = types.listOf types.int;
|
||||
default = [ ];
|
||||
description = "UDP ports to open in the firewall";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = cfg.openTCP;
|
||||
allowedUDPPorts = cfg.openUDP;
|
||||
};
|
||||
};
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.core.graphics;
|
||||
in
|
||||
{
|
||||
options.pepe.core.graphics = with lib; {
|
||||
enable = mkEnableOption "Enable graphics";
|
||||
nvidia = mkEnableOption "Enable nvidia graphics";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
hardware = {
|
||||
graphics = {
|
||||
enable = true;
|
||||
extraPackages = with pkgs; mkIf cfg.nvidia [ vaapiVdpau ];
|
||||
};
|
||||
|
||||
nvidia = mkIf cfg.nvidia {
|
||||
modesetting.enable = true;
|
||||
powerManagement.enable = false;
|
||||
powerManagement.finegrained = false;
|
||||
open = false;
|
||||
nvidiaSettings = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.latest;
|
||||
};
|
||||
};
|
||||
|
||||
services = {
|
||||
xserver = {
|
||||
enable = true;
|
||||
videoDrivers = mkIf cfg.nvidia [ "nvidia" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.pepe.core.media;
|
||||
in
|
||||
{
|
||||
options.pepe.core.media = with lib; {
|
||||
enable = mkEnableOption "Enable media library";
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "media";
|
||||
};
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
groupMembers = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
users.groups.${cfg.group}.members = [ cfg.group ] ++ cfg.groupMembers;
|
||||
};
|
||||
}
|
||||
|
@ -1,126 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types;
|
||||
cfg = config.pepe.core.network;
|
||||
in
|
||||
{
|
||||
options.pepe.core.network = {
|
||||
interfaces = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
description = "The network interface name.";
|
||||
};
|
||||
|
||||
type = mkOption {
|
||||
type = types.enum [ "lan" "wan" "vpn" ];
|
||||
description = "The type of interface (lan, wan, or vpn).";
|
||||
};
|
||||
|
||||
net = mkOption {
|
||||
type = types.str;
|
||||
description = "The network address in CIDR format.";
|
||||
};
|
||||
|
||||
devices = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = "The IP address of the device.";
|
||||
};
|
||||
|
||||
hostname = mkOption {
|
||||
type = types.str;
|
||||
description = "The hostname of the device.";
|
||||
};
|
||||
|
||||
isEndpoint = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Whether this device serves as a DNS endpoint for this interface.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "An attribute set of devices with their configurations.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "An attribute set of networks with their configurations.";
|
||||
};
|
||||
|
||||
interfacesByType = mkOption {
|
||||
type = types.attrsOf (types.listOf types.str);
|
||||
default = { };
|
||||
description = "Interfaces grouped by type (lan, wan, vpn) for easy access.";
|
||||
internal = true;
|
||||
};
|
||||
|
||||
dnsEndpoints = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
interface = mkOption {
|
||||
type = types.str;
|
||||
description = "The interface this DNS endpoint belongs to.";
|
||||
};
|
||||
|
||||
device = mkOption {
|
||||
type = types.str;
|
||||
description = "The device name that serves as the DNS endpoint.";
|
||||
};
|
||||
|
||||
address = mkOption {
|
||||
type = types.str;
|
||||
description = "The IP address of the DNS endpoint.";
|
||||
};
|
||||
|
||||
serverName = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = "DNS server name for TLS connections.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "DNS endpoints for each interface.";
|
||||
internal = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
# Create lists of interfaces by type for easy access elsewhere
|
||||
pepe.core.network.interfacesByType = {
|
||||
lan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "lan") cfg.interfaces);
|
||||
wan = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "wan") cfg.interfaces);
|
||||
vpn = lib.attrNames (lib.filterAttrs (_: iface: iface.type == "vpn") cfg.interfaces);
|
||||
};
|
||||
|
||||
# Collect DNS endpoints from all interfaces
|
||||
pepe.core.network.dnsEndpoints =
|
||||
let
|
||||
collectEndpoints = ifaceName: iface:
|
||||
lib.mapAttrs'
|
||||
(deviceName: device:
|
||||
lib.nameValuePair
|
||||
"${ifaceName}-${deviceName}"
|
||||
{
|
||||
interface = ifaceName;
|
||||
device = deviceName;
|
||||
address = device.address;
|
||||
serverName = device.dnsServerName;
|
||||
}
|
||||
)
|
||||
(lib.filterAttrs (_: device: device.isDnsEndpoint) iface.devices);
|
||||
in
|
||||
lib.foldl
|
||||
(acc: ifaceName:
|
||||
acc // (collectEndpoints ifaceName cfg.interfaces.${ifaceName})
|
||||
)
|
||||
{ }
|
||||
(lib.attrNames cfg.interfaces);
|
||||
};
|
||||
}
|
@ -1,131 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkOption types mapAttrs concatMapStringsSep optionalString mkIf;
|
||||
cfg = config.pepe.core.vhost;
|
||||
in
|
||||
{
|
||||
options.pepe.core.vhost = {
|
||||
hosts = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
locations = mkOption {
|
||||
type = types.attrsOf (types.submodule {
|
||||
options = {
|
||||
extraConfig = mkOption {
|
||||
type = types.str;
|
||||
description = "Extra configuration for the location.";
|
||||
default = "";
|
||||
};
|
||||
|
||||
proxyWebsockets = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
description = "The host for the location.";
|
||||
default = "127.0.0.1";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
description = "The port number for the location.";
|
||||
};
|
||||
|
||||
allow = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [ ];
|
||||
description = "IP address or CIDR block to allow.";
|
||||
};
|
||||
|
||||
allowVPN = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If set to true, allow VPN traffic.";
|
||||
};
|
||||
|
||||
allowLAN = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If set to true, allow LAN traffic.";
|
||||
};
|
||||
|
||||
allowWAN = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "If set to true, allow WAN traffic. If false, deny all WAN traffic.";
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
recommendedProxySettings = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Force the use of recommended proxy configuration.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "An attribute set of location configurations.";
|
||||
};
|
||||
|
||||
resolveLocally = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "If true, ensure the vhost is resolvable to 127.0.0.1 locally on this server.";
|
||||
};
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "An attribute set of domain configurations.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
pepe.core.firewall.openTCP = [ 80 443 ];
|
||||
# Configure DNS entries for vhosts when DNS is enabled
|
||||
pepe.core.dns = mkIf config.pepe.core.dns.enable {
|
||||
extraDomains = mapAttrs
|
||||
(domain: conf: {
|
||||
dnsInterfaces =
|
||||
(lib.optionals (lib.any (loc: loc.allowLAN) (lib.attrValues conf.locations))
|
||||
config.pepe.core.network.interfacesByType.lan) ++
|
||||
(lib.optionals (lib.any (loc: loc.allowVPN) (lib.attrValues conf.locations))
|
||||
config.pepe.core.network.interfacesByType.vpn);
|
||||
})
|
||||
cfg.hosts;
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts = mapAttrs
|
||||
(domain: conf: {
|
||||
forceSSL = true;
|
||||
useACMEHost = "giugl.io";
|
||||
locations = mapAttrs
|
||||
(path: location: {
|
||||
proxyPass = "http://${location.host}:${toString location.port}${location.path}";
|
||||
proxyWebsockets = location.proxyWebsockets;
|
||||
recommendedProxySettings = location.recommendedProxySettings;
|
||||
extraConfig = ''
|
||||
${concatMapStringsSep "\n" (allowCIDR: "allow ${allowCIDR};") location.allow}
|
||||
${optionalString location.allowLAN (concatMapStringsSep "\n" (ifaceName: "allow ${config.pepe.core.network.interfaces.${ifaceName}.net};") config.pepe.core.network.interfacesByType.lan)}
|
||||
${optionalString location.allowVPN (concatMapStringsSep "\n" (ifaceName: "allow ${config.pepe.core.network.interfaces.${ifaceName}.net};") config.pepe.core.network.interfacesByType.vpn)}
|
||||
${optionalString (!location.allowWAN) "deny all;"}
|
||||
'' + location.extraConfig;
|
||||
})
|
||||
conf.locations;
|
||||
})
|
||||
cfg.hosts;
|
||||
|
||||
networking.extraHosts = lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList
|
||||
(domain: hostConf:
|
||||
lib.optionals hostConf.resolveLocally "127.0.0.1 ${domain}"
|
||||
)
|
||||
cfg.hosts
|
||||
));
|
||||
};
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
{ ... }: {
|
||||
imports = [
|
||||
./services
|
||||
./core
|
||||
];
|
||||
}
|
||||
|
@ -1,35 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.bazarr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.bazarr = with lib; {
|
||||
enable = mkEnableOption "Enable bazarr";
|
||||
package = mkPackageOption pkgs "bazarr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.bazarr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 6767;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "bazarr" ];
|
||||
};
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
{ ... }: {
|
||||
imports = [
|
||||
./bazarr
|
||||
./gitea
|
||||
./homeassistant
|
||||
./immich
|
||||
./jellyfin
|
||||
./jellyseer
|
||||
./lidarr
|
||||
./llm
|
||||
./minio
|
||||
./navidrome
|
||||
./nzbget
|
||||
./prowlarr
|
||||
./radarr
|
||||
./redlib
|
||||
./sonarr
|
||||
./headscale
|
||||
./languagetool
|
||||
./whisparr
|
||||
];
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.gitea;
|
||||
in
|
||||
{
|
||||
options.pepe.services.gitea = with lib; {
|
||||
enable = mkEnableOption "Enable gitea";
|
||||
package = mkPackageOption pkgs "gitea" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
pepe.core = {
|
||||
firewall.openTCP = [ config.services.gitea.settings.server.SSH_PORT ];
|
||||
vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.gitea.settings.server.HTTP_PORT;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.gitea = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
database.type = "sqlite3";
|
||||
appName = "Gitea";
|
||||
# https://github.com/NixOS/nixpkgs/issues/235442#issuecomment-1574329453
|
||||
lfs.enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = cfg.domain;
|
||||
ROOT_URL = "https://${cfg.domain}";
|
||||
SSH_PORT = 22;
|
||||
HTTP_PORT = 3001;
|
||||
};
|
||||
service = {
|
||||
DISABLE_REGISTRATION = true;
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.headscale;
|
||||
in
|
||||
{
|
||||
options.pepe.services.headscale = with lib; {
|
||||
enable = mkEnableOption "Enable Headscale";
|
||||
package = mkPackageOption pkgs "headscale" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
description = "Domain for the Headscale service.";
|
||||
};
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = "Host for the Headscale service.";
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 1194;
|
||||
description = "Port for the Headscale service.";
|
||||
};
|
||||
settings = mkOption {
|
||||
type = types.attrsOf types.anything;
|
||||
default = { };
|
||||
description = "Arbitrary configuration settings for Headscale.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
environment.systemPackages = [ cfg.package ];
|
||||
|
||||
services.headscale = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
port = cfg.port;
|
||||
settings = cfg.settings // { server_url = "https://${cfg.domain}"; };
|
||||
};
|
||||
|
||||
pepe.core = {
|
||||
firewall.openUDP = [ cfg.port ];
|
||||
vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
host = cfg.host;
|
||||
port = cfg.port;
|
||||
allowWAN = true;
|
||||
proxyWebsockets = true;
|
||||
extraConfig = ''
|
||||
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
|
||||
proxy_buffering off;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.homeassistant;
|
||||
in
|
||||
{
|
||||
options.pepe.services.homeassistant = with lib; {
|
||||
enable = mkEnableOption "Enable Home Assistant";
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
host = "10.0.0.251";
|
||||
port = 8123;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.pepe.services.immich;
|
||||
in
|
||||
{
|
||||
options.pepe.services.immich = with lib; {
|
||||
enable = mkEnableOption "Enable immich";
|
||||
package = mkPackageOption pkgs "immich" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services = {
|
||||
immich = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
# accelerationDevices = null;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
host = "[::1]";
|
||||
port = config.services.immich.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
proxyWebsockets = true;
|
||||
extraConfig = ''
|
||||
# allow large file uploads
|
||||
client_max_body_size 50000M;
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
users.users.immich.extraGroups = [ "video" "render" "media" "nextcloud" ];
|
||||
};
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf mkForce;
|
||||
|
||||
cfg = config.pepe.services.jellyfin;
|
||||
in
|
||||
{
|
||||
options.pepe.services.jellyfin = with lib; {
|
||||
enable = mkEnableOption "Enable jellyfin";
|
||||
package = mkPackageOption pkgs "jellyfin" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
tmpfsSize = mkOption {
|
||||
type = types.str;
|
||||
default = "20G";
|
||||
description = "Size of the tmpfs mount for Jellyfin";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# needed since StateDirectory does not accept symlinks
|
||||
systemd.services.jellyfin.serviceConfig.StateDirectory = mkForce "";
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations = {
|
||||
"/" = {
|
||||
port = 8096;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
|
||||
"/socket" = {
|
||||
port = 8096;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.jellyfin = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
users.groups = {
|
||||
video.members = [ "jellyfin" ];
|
||||
render.members = [ "jellyfin" ];
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "jellyfin" ];
|
||||
|
||||
fileSystems."/tmp/jellyfin" = {
|
||||
device = "none";
|
||||
fsType = "tmpfs";
|
||||
options = [ "defaults" "size=${cfg.tmpfsSize}" "uid=jellyfin" ];
|
||||
};
|
||||
};
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.jellyseer;
|
||||
in
|
||||
{
|
||||
options.pepe.services.jellyseer = with lib; {
|
||||
enable = mkEnableOption "Enable jellyseer";
|
||||
package = mkPackageOption pkgs "jellyseerr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.jellyseerr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.jellyseerr.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.languagetool;
|
||||
|
||||
ngramDataDir = pkgs.symlinkJoin {
|
||||
name = "languagetool-ngrams";
|
||||
paths = builtins.attrValues pkgs.langtoolPkgs;
|
||||
};
|
||||
in
|
||||
{
|
||||
options.pepe.services.languagetool = with lib; {
|
||||
enable = mkEnableOption "Enable LanguageTool";
|
||||
package = mkPackageOption pkgs "languagetool" { };
|
||||
fasttextPackage = mkPackageOption pkgs "fasttext" {};
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
pepe.core = {
|
||||
vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.languagetool.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.languagetool = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
allowOrigin = cfg.domain;
|
||||
settings = {
|
||||
languageModel = "${ngramDataDir}/share/languagetool/ngrams/";
|
||||
fasttextModel = "${pkgs.langtoolPkgs.fasttextmodel}/share/languagetool/fasttextmodel/lid.176.bin";
|
||||
fasttextBinary = "${cfg.fasttextPackage}/bin/fasttext";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.lidarr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.lidarr = with lib; {
|
||||
enable = mkEnableOption "Enable lidarr";
|
||||
package = mkPackageOption pkgs "lidarr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.lidarr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = with config.pepe.core.network; {
|
||||
dnsInterfaces = [ interfaceTypes.lan interfaceTypes.vpn ];
|
||||
locations."/" = {
|
||||
port = 8686;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "lidarr" ];
|
||||
};
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf mkEnableOption mkPackageOption mkOption types optionalAttrs mkMerge;
|
||||
|
||||
cfg = config.pepe.services.llm;
|
||||
in
|
||||
{
|
||||
options.pepe.services.llm = {
|
||||
enable = mkEnableOption "Enable LLM backend service (Ollama)";
|
||||
|
||||
package = mkPackageOption pkgs "ollama" { };
|
||||
|
||||
backendDomain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Domain for Ollama backend. If null, no vhost is created for the backend.";
|
||||
};
|
||||
|
||||
acceleration = mkOption {
|
||||
type = types.enum [ "none" "cuda" "rocm" ];
|
||||
default = "none";
|
||||
description = "Acceleration type for Ollama";
|
||||
};
|
||||
|
||||
environmentVariables = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {
|
||||
OLLAMA_FLASH_ATTENTION = "1";
|
||||
OLLAMA_NUM_PARALLEL = "2";
|
||||
OLLAMA_KV_CACHE_TYPE = "q8_0";
|
||||
};
|
||||
description = "Environment variables for Ollama";
|
||||
};
|
||||
|
||||
frontend = {
|
||||
enable = mkEnableOption "Enable LLM frontend service (Open WebUI)"; # Defaults to false
|
||||
package = mkPackageOption pkgs "open-webui" { };
|
||||
domain = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Domain for Open WebUI frontend. If null, no vhost is created for the frontend.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
# Combined environment packages
|
||||
{
|
||||
environment.systemPackages =
|
||||
(if cfg.enable then [ cfg.package ] else [ ]) ++
|
||||
(if cfg.enable && cfg.frontend.enable then [ cfg.frontend.package ] else [ ]);
|
||||
}
|
||||
|
||||
# Backend Ollama Service Configuration
|
||||
(mkIf cfg.enable {
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
acceleration = cfg.acceleration;
|
||||
environmentVariables = cfg.environmentVariables;
|
||||
};
|
||||
|
||||
services.docling-serve = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.docling-serve;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts = optionalAttrs (cfg.backendDomain != null) {
|
||||
"${cfg.backendDomain}" = {
|
||||
locations."/" = {
|
||||
host = config.services.ollama.host;
|
||||
port = config.services.ollama.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
recommendedProxySettings = false;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 600s; # Ollama can take time to respond
|
||||
proxy_set_header Host localhost:${toString config.services.ollama.port};
|
||||
'';
|
||||
};
|
||||
|
||||
locations."/docling/" = {
|
||||
host = config.services.docling-serve.host;
|
||||
port = config.services.docling-serve.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
recommendedProxySettings = false;
|
||||
extraConfig = ''
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 600s;
|
||||
|
||||
rewrite ^/docling/(.*) /$1 break;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
# Frontend Open WebUI and Tika Service Configuration
|
||||
(mkIf (cfg.enable && cfg.frontend.enable) {
|
||||
services.open-webui = {
|
||||
enable = true;
|
||||
package = cfg.frontend.package;
|
||||
};
|
||||
|
||||
services.docling-serve = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.docling-serve;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts = optionalAttrs (cfg.frontend.domain != null) {
|
||||
"${cfg.frontend.domain}" = {
|
||||
locations."/" = {
|
||||
host = config.services.open-webui.host;
|
||||
port = config.services.open-webui.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
"${cfg.backend.domain}" = {
|
||||
locations."/docling" = {
|
||||
host = config.services.docling-serve.host;
|
||||
port = config.services.docling-serve.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.minio;
|
||||
in
|
||||
{
|
||||
options.pepe.services.minio = with lib; {
|
||||
enable = mkEnableOption "Enable MinIO S3-compatible object storage";
|
||||
package = mkPackageOption pkgs "minio" {};
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.minio = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 9000;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
extraConfig = ''
|
||||
client_max_body_size 500M;
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,170 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.navidrome;
|
||||
|
||||
beetsConfigTemplate = pkgs.writeText "beets.conf.template" ''
|
||||
directory: ${cfg.musicFolder}
|
||||
plugins: embedart fetchart scrub lastgenre chroma
|
||||
|
||||
import:
|
||||
write: yes
|
||||
move: yes
|
||||
incremental: yes
|
||||
from_scratch: yes
|
||||
group_albums: yes
|
||||
log: ${cfg.musicFolder}/beets.log
|
||||
original_date: yes
|
||||
discogs:
|
||||
user_token: "__DISCOGS_TOKEN__"
|
||||
paths:
|
||||
default: $albumartist/$album ($original_year)/$track - $title
|
||||
singleton: $artist/singles/$title
|
||||
match:
|
||||
strong_rec_thresh: 0.20
|
||||
musicbrainz:
|
||||
extra_tags: [year]
|
||||
lastfm:
|
||||
user: peperunas
|
||||
api_key: "__LASTFM_KEY__"
|
||||
embedart:
|
||||
auto: yes
|
||||
fetchart:
|
||||
auto: yes
|
||||
lastfmkey: "__LASTFM_KEY__"
|
||||
enforce_ratio: 0.5%
|
||||
scrub:
|
||||
auto: yes
|
||||
lastgenre:
|
||||
auto: yes
|
||||
count: 5
|
||||
min_weight: 10
|
||||
prefer_specific: yes
|
||||
force: yes
|
||||
chroma:
|
||||
auto: yes
|
||||
'';
|
||||
|
||||
preStartBeetsDecrypt = ''
|
||||
set -eu
|
||||
sed \
|
||||
-e "s|__DISCOGS_TOKEN__|$(cat ${config.age.secrets.discogs.path})|g" \
|
||||
-e "s|__LASTFM_KEY__|$(cat ${config.age.secrets.lastfmKey.path})|g" \
|
||||
${beetsConfigTemplate} > /run/beets.conf
|
||||
'';
|
||||
|
||||
navidromeWrapped = pkgs.writeShellScriptBin "navidrome-wrapped" ''
|
||||
set -eu
|
||||
|
||||
${preStartNavidromeDecrypt}
|
||||
|
||||
exec ${cfg.package}/bin/navidrome "$@"
|
||||
'';
|
||||
|
||||
preStartNavidromeDecrypt = ''
|
||||
set -eu
|
||||
|
||||
# export ND_LASTFM_APIKEY=$(cat ${config.age.secrets.lastfmKey.path})
|
||||
# export ND_LASTFM_SECRET=$(cat ${config.age.secrets.lastfmSecret.path})
|
||||
# export ND_SPOTIFY_ID=$(cat ${config.age.secrets.spotifyID.path})
|
||||
# export ND_SPOTIFY_SECRET=$(cat ${config.age.secrets.spotifySecret.path})
|
||||
'';
|
||||
in
|
||||
{
|
||||
options.pepe.services.navidrome = with lib; {
|
||||
enable = mkEnableOption "Enable navidrome";
|
||||
enableBeets = mkEnableOption "Enable beets";
|
||||
|
||||
package = mkPackageOption pkgs "navidrome" { };
|
||||
beetsPackage = mkPackageOption pkgs "beets" { };
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
musicFolder = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/Music";
|
||||
description = "Path to the music library";
|
||||
};
|
||||
settings = mkOption {
|
||||
type = types.attrs;
|
||||
default = { };
|
||||
description = "Additional settings for Navidrome";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.navidrome = {
|
||||
enable = true;
|
||||
package = navidromeWrapped;
|
||||
settings = {
|
||||
MusicFolder = cfg.musicFolder;
|
||||
LastFM.enable = true;
|
||||
EnableGravatar = true;
|
||||
LogLevel = "WARN";
|
||||
} // cfg.settings;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.navidrome.settings.Port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
|
||||
age.secrets = {
|
||||
discogs = mkIf cfg.enableBeets {
|
||||
file = ../../../secrets/discogs.age;
|
||||
};
|
||||
|
||||
lastfmKey = {
|
||||
file = ../../../secrets/lastfm-key.age;
|
||||
};
|
||||
|
||||
lastfmSecret = {
|
||||
file = ../../../secrets/lastfm-key.age;
|
||||
};
|
||||
|
||||
spotifyID = {
|
||||
file = ../../../secrets/spotify-id.age;
|
||||
};
|
||||
|
||||
spotifySecret = {
|
||||
file = ../../../secrets/spotify-secret.age;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
"navidrome".preStart = preStartNavidromeDecrypt;
|
||||
} // mkIf cfg.enableBeets {
|
||||
"beets-update" = {
|
||||
enable = true;
|
||||
preStart = preStartBeetsDecrypt;
|
||||
before = [ "beets-import.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${cfg.beetsPackage}/bin/beet -c /run/beets.conf update";
|
||||
};
|
||||
};
|
||||
|
||||
"beets-import" = {
|
||||
enable = true;
|
||||
path = [ pkgs.imagemagick ];
|
||||
requires = [ "beets-update.service" ];
|
||||
after = [ "beets-update.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${cfg.beetsPackage}/bin/beet -c /run/beets.conf import --flat -q ${cfg.musicFolder}";
|
||||
};
|
||||
startAt = "weekly";
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "navidrome" ];
|
||||
};
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.nzbget;
|
||||
in
|
||||
{
|
||||
options.pepe.services.nzbget = with lib; {
|
||||
enable = mkEnableOption "Enable nzbget";
|
||||
package = mkPackageOption pkgs "nzbget" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.nzbget = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 6789;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "nzbget" ];
|
||||
};
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.prowlarr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.prowlarr = with lib; {
|
||||
enable = mkEnableOption "Enable prowlarr";
|
||||
package = mkPackageOption pkgs "prowlarr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.prowlarr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 9696;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ "prowlarr" ];
|
||||
};
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.radarr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.radarr = with lib; {
|
||||
enable = mkEnableOption "Enable radarr";
|
||||
package = mkPackageOption pkgs "radarr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.radarr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 7878;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ config.services.radarr.group ];
|
||||
};
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.redlib;
|
||||
in
|
||||
{
|
||||
options.pepe.services.redlib = with lib; {
|
||||
enable = mkEnableOption "Enable Redlib";
|
||||
package = mkPackageOption pkgs "redlib" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
settings = mkOption {
|
||||
type = types.attrsOf types.str;
|
||||
default = {
|
||||
REDLIB_ROBOTS_DISABLE_INDEXING = "on";
|
||||
REDLIB_DEFAULT_THEME = "dracula";
|
||||
REDLIB_DEFAULT_SHOW_NSFW = "on";
|
||||
REDLIB_DEFAULT_BLUR_NSFW = "off";
|
||||
REDLIB_DEFAULT_USE_HLS = "on";
|
||||
REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION = "on";
|
||||
};
|
||||
description = "Environment variables for Redlib configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.redlib = {
|
||||
enable = true;
|
||||
port = 9090;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
systemd.services.redlib.environment = cfg.settings;
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.redlib.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.sonarr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.sonarr = with lib; {
|
||||
enable = mkEnableOption "Enable sonarr";
|
||||
package = mkPackageOption pkgs "sonarr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.sonarr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = 8989;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ config.services.sonarr.group ];
|
||||
};
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.whisparr;
|
||||
in
|
||||
{
|
||||
options.pepe.services.whisparr = with lib; {
|
||||
enable = mkEnableOption "Enable whisparr";
|
||||
package = mkPackageOption pkgs "whisparr" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.whisparr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.whisparr.settings.server.port;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
};
|
||||
};
|
||||
|
||||
pepe.core.media.groupMembers = mkIf config.pepe.core.media.enable [ config.services.whisparr.group ];
|
||||
};
|
||||
}
|
@ -1,25 +1,4 @@
|
||||
{ config, ... }:
|
||||
|
||||
let
|
||||
giuglioDomain = "giugl.io";
|
||||
in
|
||||
{
|
||||
age.secrets.cloudflare = {
|
||||
file = ../secrets/cloudflare.age;
|
||||
owner = "acme";
|
||||
};
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
certs.${giuglioDomain} =
|
||||
{
|
||||
dnsProvider = "cloudflare";
|
||||
environmentFile = config.age.secrets.cloudflare.path;
|
||||
extraDomainNames = [ "*.${giuglioDomain}" ];
|
||||
};
|
||||
defaults = {
|
||||
email = "letsencrypt@depasquale.giugl.io";
|
||||
dnsProvider = "cloudflare";
|
||||
environmentFile = config.age.secrets.cloudflare.path;
|
||||
};
|
||||
};
|
||||
{ ... }: {
|
||||
security.acme.acceptTerms = true;
|
||||
security.acme.email = "sysadmin@giugl.io";
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
{ config, pkgs, variables, lib, ... }:
|
||||
|
||||
{
|
||||
boot.tmp = {
|
||||
useTmpfs = true;
|
||||
};
|
||||
boot.tmpOnTmpfs = true;
|
||||
|
||||
console = {
|
||||
keyMap = "us";
|
||||
@ -13,7 +11,8 @@
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
nix = {
|
||||
settings.auto-optimise-store = true;
|
||||
autoOptimiseStore = true;
|
||||
package = pkgs.nixUnstable;
|
||||
extraOptions = ''
|
||||
experimental-features = nix-command flakes
|
||||
'';
|
||||
@ -25,11 +24,10 @@
|
||||
};
|
||||
};
|
||||
|
||||
nixpkgs = { config = { allowUnfree = true; }; };
|
||||
|
||||
fonts = {
|
||||
fontconfig.enable = true;
|
||||
packages = with pkgs; [ cascadia-code victor-mono ];
|
||||
};
|
||||
fonts.fontconfig.enable = true;
|
||||
fonts.fonts = with pkgs; [ cascadia-code victor-mono ];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
file
|
||||
@ -42,6 +40,7 @@
|
||||
glances
|
||||
tcpdump
|
||||
restic
|
||||
neovim
|
||||
tmux
|
||||
parted
|
||||
unzip
|
||||
@ -50,7 +49,5 @@
|
||||
nmap
|
||||
ripgrep
|
||||
jq
|
||||
helix
|
||||
poetry
|
||||
];
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
environment.systemPackages = with pkgs; [
|
||||
gnomeExtensions.appindicator
|
||||
gnomeExtensions.sound-output-device-chooser
|
||||
pkgs.unstablePkgs.gnomeExtensions.pop-shell
|
||||
pkgs.unstable.gnomeExtensions.pop-shell
|
||||
];
|
||||
security.pam.services.gdm.enableGnomeKeyring = true;
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
lib = pkgs.lib;
|
||||
configDir = "$HOME/.config/aichat";
|
||||
in
|
||||
{
|
||||
home = {
|
||||
sessionVariables = {
|
||||
AICHAT_CONFIG_DIR = configDir;
|
||||
};
|
||||
packages = [ pkgs.aichat ];
|
||||
|
||||
file.".config/aichat/config.yaml".text = lib.readFile ./aichat/config.yaml;
|
||||
file.".config/aichat/roles/commitmessage.md".text = lib.readFile ./aichat/roles/commitmessage.md;
|
||||
file.".config/aichat/roles/createpr.md".text = lib.readFile ./aichat/roles/createpr.md;
|
||||
};
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
clients:
|
||||
- type: openai-compatible
|
||||
name: ollama
|
||||
api_base: https://ollama.giugl.io/v1
|
||||
models:
|
||||
- name: pino
|
||||
max_input_tokens: 8192
|
||||
max_output_tokens: 16000
|
||||
|
||||
- name: pino-coder
|
||||
max_input_tokens: 16000
|
||||
max_output_tokens: 16000
|
||||
|
||||
- name: pino-embed
|
||||
type: embedding
|
||||
default_chunk_size: 512
|
||||
max_batch_size: 100
|
||||
|
||||
rag_embedding_model: ollama:pino-embed
|
||||
rag_top_k: 5
|
@ -1,98 +0,0 @@
|
||||
---
|
||||
model: ollama:pino-coder
|
||||
temperature: 0
|
||||
---
|
||||
|
||||
You are an expert software developer and a master of Git version control. Your sole purpose is to analyze a `git diff` provided by the user and write an impeccable commit message that strictly follows the Conventional Commits specification v1.0.0.
|
||||
|
||||
You must adhere to the following rules without exception:
|
||||
|
||||
1. **Structure**: The commit message must be structured as follows:
|
||||
```
|
||||
<type>[optional scope]: <subject>
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
|
||||
2. **Type**: The `<type>` must be one of the following allowed values:
|
||||
* **feat**: A new feature for the user.
|
||||
* **fix**: A bug fix for the user.
|
||||
* **docs**: Documentation only changes.
|
||||
* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc).
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature.
|
||||
* **perf**: A code change that improves performance.
|
||||
* **test**: Adding missing tests or correcting existing tests.
|
||||
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm).
|
||||
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs).
|
||||
* **chore**: Other changes that don't modify src or test files.
|
||||
|
||||
3. **Scope**: The `(scope)` is optional. If used, it must be a noun describing the section of the codebase affected.
|
||||
|
||||
4. **Subject**: The `<subject>` line:
|
||||
* Must be written in the imperative mood (e.g., "Add feature", not "Added feature" or "Adds feature").
|
||||
* Must not be capitalized.
|
||||
* Must not end with a period.
|
||||
|
||||
5. **Body**: The `[body]` is optional but highly encouraged for anything other than trivial changes.
|
||||
* It must be separated from the subject by one blank line.
|
||||
* It must explain the "what" and "why" of the change, not the "how".
|
||||
|
||||
6. **Output**: Your final output must be ONLY the raw text of the commit message and nothing else. Do not include any explanations, apologies, or surrounding markdown like ` ``` `.
|
||||
|
||||
---
|
||||
### EXAMPLE
|
||||
|
||||
**INPUT GIT DIFF:**
|
||||
```diff
|
||||
diff --git a/.config/aichat/roles/commit.md b/.config/aichat/roles/commit.md
|
||||
new file mode 100644
|
||||
index 0000000..d67e2a9
|
||||
--- /dev/null
|
||||
+++ b/.config/aichat/roles/commit.md
|
||||
@@ -0,0 +1,52 @@
|
||||
+# The name of the role.
|
||||
+name: commit
|
||||
+
|
||||
+# The author of the role.
|
||||
+author: Gemini
|
||||
+
|
||||
+# A description of the role.
|
||||
+description: Generates a conventional commit message from a git diff.
|
||||
+
|
||||
+# The model to use.
|
||||
+model: qwen2:14b-instruct
|
||||
+
|
||||
+# The temperature to use.
|
||||
+temperature: 0.1
|
||||
+
|
||||
+# The prompt type.
|
||||
+prompt: embedded
|
||||
+
|
||||
+# The prompt text.
|
||||
+---
|
||||
+You are an expert software developer and a master of Git version control. Your sole purpose is to analyze a `git diff` provided by the user and write an impeccable commit message that strictly follows the Conventional Commits specification v1.0.0.
|
||||
+
|
||||
+You must adhere to the following rules without exception:
|
||||
+
|
||||
+1. **Structure**: The commit message must be structured as follows:
|
||||
+ ```
|
||||
+ <type>[optional scope]: <subject>
|
||||
+
|
||||
+ [optional body]
|
||||
+
|
||||
+ [optional footer(s)]
|
||||
+ ```
|
||||
+
|
||||
+2. **Type**: The `<type>` must be one of the following allowed values:
|
||||
+ * **feat**: A new feature for the user.
|
||||
+ * **fix**: A bug fix for the user.
|
||||
+ * **docs**: Documentation only changes.
|
||||
+ * **style**: Changes that do not affect the meaning of the code.
|
||||
+ * **refactor**: A code change that neither fixes a bug nor adds a feature.
|
||||
+ * **perf**: A code change that improves performance.
|
||||
+ * **test**: Adding missing tests or correcting existing tests.
|
||||
+ * **build**: Changes that affect the build system or external dependencies.
|
||||
+ * **ci**: Changes to our CI configuration files and scripts.
|
||||
+ * **chore**: Other changes that don't modify src or test files.
|
@ -1,626 +0,0 @@
|
||||
You are a technical documentation assistant specializing in creating clear, concise PR messages. Given a git diff, you will:
|
||||
|
||||
1. Analyze the structural changes to identify:
|
||||
- New components/interfaces
|
||||
- Architectural changes
|
||||
- Behavioral modifications
|
||||
- Impact on existing systems
|
||||
|
||||
2. Create a PR message following this format:
|
||||
<type>(<scope>): <description>
|
||||
|
||||
[PROSE DESCRIPTION explaining the changes and their purpose]
|
||||
|
||||
---
|
||||
|
||||
[OPTIONAL SECTIONS like "Structs:", "Interfaces:", "Methods:", etc. when relevant]
|
||||
|
||||
Each section should:
|
||||
- Use bullet points for clarity
|
||||
- Bold key terms
|
||||
- Include brief descriptions
|
||||
- Focus on significant changes
|
||||
- Exclude trivial details (imports, formatting)
|
||||
|
||||
### INPUT:
|
||||
|
||||
```
|
||||
diff --git a/pkg/cli/cli.go b/pkg/cli/cli.go
|
||||
index 9aee19c..9863f0b 100644
|
||||
--- a/pkg/cli/cli.go
|
||||
+++ b/pkg/cli/cli.go
|
||||
@@ -1,21 +1,13 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
- "context"
|
||||
- "net/http"
|
||||
"strings"
|
||||
- "time"
|
||||
|
||||
"github.com/sanity-io/litter"
|
||||
"github.com/spf13/cobra"
|
||||
- "github.com/org/Core/pkg/logging"
|
||||
"github.com/org/Core/pkg/structs"
|
||||
- "github.com/org/example/internal/storage"
|
||||
- "github.com/org/example/pkg/browser"
|
||||
"github.com/org/example/pkg/config"
|
||||
- "github.com/org/example/pkg/crawler"
|
||||
"github.com/org/example/pkg/errors"
|
||||
- "github.com/org/example/pkg/models"
|
||||
cookieflags "github.com/org/example/pkg/plugins/cookieflags"
|
||||
cookiescope "github.com/org/example/pkg/plugins/cookiescope"
|
||||
corsmisconfig "github.com/org/example/pkg/plugins/cors"
|
||||
@@ -124,7 +116,18 @@ func NewRootCmd() (*cobra.Command, error) {
|
||||
logger.Tracef("Crawler Configuration:
|
||||
=============
|
||||
%s
|
||||
=============
|
||||
", litter.Sdump(crawlConfig))
|
||||
logger.Tracef("Vulnerability Scan Configuration:
|
||||
=============
|
||||
%s
|
||||
=============
|
||||
", litter.Sdump(pluginsConfig))
|
||||
|
||||
- return StartScan(sysConfig, crawlConfig, pluginsConfig)
|
||||
+ manager, err := NewManagerBuilder(sysConfig, crawlConfig, pluginsConfig).Build()
|
||||
+
|
||||
+ if err != nil {
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ err = manager.Start()
|
||||
+ if err != nil {
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ return manager.Stop()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -186,113 +189,6 @@ func parseConfigFiles(crawlConfPath, systemConfPath, pluginConfPath string) (*co
|
||||
return crawlConfig, sysConfig, vulnConfig, nil
|
||||
}
|
||||
|
||||
-func StartScan(sysCfg *config.SystemConfiguration, //nolint:cyclop
|
||||
- crawlCfg *config.CrawlConfiguration,
|
||||
- pluginCfg *config.PluginsConfiguration,
|
||||
-) error {
|
||||
- // Initialize shared components
|
||||
- logger := logging.NewLoggerBuilder().Build()
|
||||
- metrics := &models.Metrics{}
|
||||
|
||||
- // Initialize the browser session
|
||||
- browserSession, err := browser.New(logger, crawlCfg)
|
||||
- if err != nil {
|
||||
- return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- defer browserSession.Close()
|
||||
|
||||
- if err := browserSession.Start(context.Background()); err != nil {
|
||||
- return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- // Create custom HTTP client if needed
|
||||
- // TODO: Change and centralise
|
||||
- // see https://github.com/org/example/issues/436
|
||||
- customClient := &http.Client{
|
||||
- Timeout: time.Second * 30,
|
||||
- // Add other custom configurations...
|
||||
- }
|
||||
- // Iniialize storage once
|
||||
- scanStorage, err := storage.NewScanStorage(sysCfg, metrics, logger)
|
||||
- if err != nil {
|
||||
- return errors.ErrStorageSetup.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- // Start batch session before any operations
|
||||
- err = scanStorage.BatchSession.Start()
|
||||
- if err != nil {
|
||||
- return errors.ErrStorageSetup.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- // Initialize crawler with all options
|
||||
- crawler, err := crawler.New(
|
||||
- crawlCfg,
|
||||
- sysCfg,
|
||||
- crawler.WithStorage(scanStorage.Database, scanStorage.BatchSession),
|
||||
- crawler.WithLogger(logger),
|
||||
- crawler.WithMetrics(metrics),
|
||||
- crawler.WithHTTPClient(customClient),
|
||||
- crawler.WithBrowser(browserSession),
|
||||
- )
|
||||
- if err != nil {
|
||||
- return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- // Initialize scanner with shared components
|
||||
- scan, err := scanner.NewScanner(
|
||||
- sysCfg,
|
||||
- crawlCfg,
|
||||
- pluginCfg,
|
||||
- browserSession,
|
||||
- scanner.WithStorage(scanStorage),
|
||||
- scanner.WithLogger(logger),
|
||||
- scanner.WithHTTPClient(customClient),
|
||||
- )
|
||||
- if err != nil {
|
||||
- return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- err = initializePluginsFromConfig(scan, pluginCfg)
|
||||
- if err != nil {
|
||||
- return errors.ErrInitialisePlugin.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- output, err := crawler.Start()
|
||||
- if err != nil {
|
||||
- crawler.Close()
|
||||
|
||||
- return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- // Add this: Stop scanner before waiting for batch operations
|
||||
- scan.Stop()
|
||||
- logger.Debugf("Crawl completed with metrics: %+v", output.Metrics)
|
||||
|
||||
- if sysCfg.ShouldExportMetrics() {
|
||||
- err := output.Metrics.ToJSONFile()
|
||||
|
||||
- if err != nil {
|
||||
- return errors.ErrJSONMarshalling.WrapWithNoMessage(err)
|
||||
- }
|
||||
- }
|
||||
|
||||
- if output.BenchmarkResults != nil {
|
||||
- logger.Debugf("Benchmark results: %+v", output.BenchmarkResults)
|
||||
- }
|
||||
|
||||
- scanStorage.BatchSession.Wait()
|
||||
- err = scanStorage.BatchSession.Stop()
|
||||
|
||||
- if err != nil {
|
||||
- return errors.ErrStorageSetup.WrapWithNoMessage(err)
|
||||
- }
|
||||
|
||||
- crawler.Close()
|
||||
|
||||
- return nil
|
||||
-}
|
||||
|
||||
// BuildPluginsFromConfig creates plugin instances based on configuration
|
||||
func BuildPluginsFromConfig(config *config.PluginsConfiguration) []*structs.Plugin {
|
||||
enabledPlugins := []*structs.Plugin{}
|
||||
diff --git a/pkg/cli/interface.go b/pkg/cli/interface.go
|
||||
new file mode 100644
|
||||
index 0000000..4d68a45
|
||||
--- /dev/null
|
||||
+++ b/pkg/cli/interface.go
|
||||
@@ -0,0 +1,10 @@
|
||||
+package cli
|
||||
+
|
||||
+// Scanner represents the core scanning operations lifecycle
|
||||
+type ScanManagerInterface interface {
|
||||
+ // Start initializes and begins the scanning process
|
||||
+ Start() error
|
||||
+
|
||||
+ // Stop gracefully terminates all scanning operations
|
||||
+ Stop() error
|
||||
+}
|
||||
diff --git a/pkg/cli/manager.go b/pkg/cli/manager.go
|
||||
new file mode 100644
|
||||
index 0000000..3f2a8fc
|
||||
--- /dev/null
|
||||
+++ b/pkg/cli/manager.go
|
||||
@@ -0,0 +1,277 @@
|
||||
+package cli
|
||||
+
|
||||
+import (
|
||||
+ "context"
|
||||
+ "net/http"
|
||||
+
|
||||
+ "github.com/org/Core/pkg/logging"
|
||||
+ "github.com/org/example/internal/storage"
|
||||
+ "github.com/org/example/pkg/browser"
|
||||
+ "github.com/org/example/pkg/config"
|
||||
+ "github.com/org/example/pkg/crawler"
|
||||
+ "github.com/org/example/pkg/errors"
|
||||
+ "github.com/org/example/pkg/models"
|
||||
+ "github.com/org/example/pkg/scanner"
|
||||
+)
|
||||
+
|
||||
+var _ ScanManagerInterface = (*ScanManager)(nil)
|
||||
+
|
||||
+type ScanManager struct {
|
||||
+ browser *browser.Session
|
||||
+ crawler *crawler.Crawler
|
||||
+ scanner *scanner.Scanner
|
||||
+ storage *storage.ScanStorage
|
||||
+ logger *logging.Logger
|
||||
+ metrics *models.Metrics
|
||||
+ httpClient *http.Client
|
||||
+
|
||||
+ sysCfg *config.SystemConfiguration
|
||||
+ crawlCfg *config.CrawlConfiguration
|
||||
+ pluginCfg *config.PluginsConfiguration
|
||||
+}
|
||||
+
|
||||
+// ScanManagerBuilder handles the construction of a ScanManager
|
||||
+type ScanManagerBuilder struct {
|
||||
+ manager *ScanManager
|
||||
+ err error
|
||||
+}
|
||||
+
|
||||
+// NewManagerBuilder creates a new builder for ScanManager
|
||||
+func NewManagerBuilder(sysCfg *config.SystemConfiguration,
|
||||
+ crawlCfg *config.CrawlConfiguration,
|
||||
+ pluginCfg *config.PluginsConfiguration,
|
||||
+) *ScanManagerBuilder {
|
||||
+ builder := &ScanManagerBuilder{
|
||||
+ manager: &ScanManager{
|
||||
+ logger: logging.NewLoggerBuilder().Build(),
|
||||
+ metrics: &models.Metrics{},
|
||||
+ httpClient: &http.Client{},
|
||||
+ },
|
||||
+ }
|
||||
+
|
||||
+ if sysCfg == nil || crawlCfg == nil || pluginCfg == nil {
|
||||
+ builder.err = errors.ErrInvalidArgument.New("configurations cannot be nil")
|
||||
+
|
||||
+ return builder
|
||||
+ }
|
||||
+
|
||||
+ builder.manager.sysCfg = sysCfg
|
||||
+ builder.manager.crawlCfg = crawlCfg
|
||||
+ builder.manager.pluginCfg = pluginCfg
|
||||
+
|
||||
+ return builder
|
||||
+}
|
||||
+
|
||||
+// WithLogger sets a custom logger
|
||||
+func (b *ScanManagerBuilder) WithLogger(logger *logging.Logger) *ScanManagerBuilder {
|
||||
+ if b.err != nil {
|
||||
+ return b
|
||||
+ }
|
||||
+
|
||||
+ if logger == nil {
|
||||
+ b.err = errors.ErrInvalidArgument.New("logger cannot be nil")
|
||||
+
|
||||
+ return b
|
||||
+ }
|
||||
+
|
||||
+ b.manager.logger = logger
|
||||
+
|
||||
+ return b
|
||||
+}
|
||||
+
|
||||
+// WithMetrics sets custom metrics
|
||||
+func (b *ScanManagerBuilder) WithMetrics(metrics *models.Metrics) *ScanManagerBuilder {
|
||||
+ if b.err != nil {
|
||||
+ return b
|
||||
+ }
|
||||
+
|
||||
+ if metrics == nil {
|
||||
+ b.err = errors.ErrInvalidArgument.New("metrics cannot be nil")
|
||||
+
|
||||
+ return b
|
||||
+ }
|
||||
+
|
||||
+ b.manager.metrics = metrics
|
||||
+
|
||||
+ return b
|
||||
+}
|
||||
+
|
||||
+// Build creates the ScanManager instance
|
||||
+func (b *ScanManagerBuilder) Build() (*ScanManager, error) {
|
||||
+ if b.err != nil {
|
||||
+ return nil, b.err
|
||||
+ }
|
||||
+
|
||||
+ return b.manager, nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) initBrowser(crawlCfg *config.CrawlConfiguration) error {
|
||||
+ var err error
|
||||
+
|
||||
+ sm.browser, err = browser.New(sm.logger, crawlCfg)
|
||||
+ if err != nil {
|
||||
+ return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ if err := sm.browser.Start(context.Background()); err != nil {
|
||||
+ sm.browser.Close()
|
||||
+
|
||||
+ return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) initStorage(sysCfg *config.SystemConfiguration) error {
|
||||
+ var err error
|
||||
+
|
||||
+ storage, err := storage.NewScanStorage(sysCfg, sm.metrics, sm.logger)
|
||||
+ if err != nil {
|
||||
+ return errors.ErrStorageSetup.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ sm.storage = &storage
|
||||
+
|
||||
+ err = sm.storage.BatchSession.Start()
|
||||
+ if err != nil {
|
||||
+ return errors.ErrStorageSetup.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) initCrawler(sysCfg *config.SystemConfiguration, crawlCfg *config.CrawlConfiguration) error {
|
||||
+ var err error
|
||||
+
|
||||
+ sm.crawler, err = crawler.New(
|
||||
+ crawlCfg,
|
||||
+ sysCfg,
|
||||
+ crawler.WithStorage(sm.storage.Database, sm.storage.BatchSession),
|
||||
+ crawler.WithLogger(sm.logger),
|
||||
+ crawler.WithMetrics(sm.metrics),
|
||||
+ crawler.WithHTTPClient(sm.httpClient),
|
||||
+ crawler.WithBrowser(sm.browser),
|
||||
+ )
|
||||
+
|
||||
+ if err != nil {
|
||||
+ return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) initScanner() error {
|
||||
+ var err error
|
||||
+
|
||||
+ sm.scanner, err = scanner.NewScanner(
|
||||
+ sm.sysCfg,
|
||||
+ sm.crawlCfg,
|
||||
+ sm.pluginCfg,
|
||||
+ sm.browser,
|
||||
+ scanner.WithStorage(*sm.storage),
|
||||
+ scanner.WithLogger(sm.logger),
|
||||
+ scanner.WithHTTPClient(sm.httpClient),
|
||||
+ )
|
||||
+
|
||||
+ if err != nil {
|
||||
+ return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ err = initializePluginsFromConfig(sm.scanner, sm.pluginCfg)
|
||||
+ if err != nil {
|
||||
+ return errors.ErrInitialisePlugin.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) cleanup() error {
|
||||
+ var errs []error
|
||||
+
|
||||
+ if sm.crawler != nil {
|
||||
+ sm.crawler.Close()
|
||||
+ }
|
||||
+
|
||||
+ if sm.scanner != nil {
|
||||
+ sm.scanner.Stop()
|
||||
+ }
|
||||
+
|
||||
+ if sm.storage != nil && sm.storage.BatchSession != nil {
|
||||
+ sm.storage.BatchSession.Wait()
|
||||
+
|
||||
+ err := sm.storage.BatchSession.Stop()
|
||||
+ if err != nil {
|
||||
+ errs = append(errs, errors.ErrStorageSetup.WrapWithNoMessage(err))
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if sm.browser != nil {
|
||||
+ sm.browser.Close()
|
||||
+ }
|
||||
+
|
||||
+ if len(errs) > 0 {
|
||||
+ return errors.ErrFailedExecution.New("multiple cleanup errors occurred: %v", errs)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) Start() error {
|
||||
+ err := sm.initBrowser(sm.crawlCfg)
|
||||
+ if err != nil {
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ err = sm.initStorage(sm.sysCfg)
|
||||
+ if err != nil {
|
||||
+ _ = sm.cleanup()
|
||||
+
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ err = sm.initCrawler(sm.sysCfg, sm.crawlCfg)
|
||||
+ if err != nil {
|
||||
+ _ = sm.cleanup()
|
||||
+
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ err = sm.initScanner()
|
||||
+ if err != nil {
|
||||
+ _ = sm.cleanup()
|
||||
+
|
||||
+ return err
|
||||
+ }
|
||||
+
|
||||
+ // Start the crawl
|
||||
+ output, err := sm.crawler.Start()
|
||||
+ if err != nil {
|
||||
+ _ = sm.cleanup()
|
||||
+
|
||||
+ return errors.ErrFailedExecution.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+
|
||||
+ sm.logger.Debugf("Crawl completed with metrics: %+v", output.Metrics)
|
||||
+
|
||||
+ if sm.sysCfg.ShouldExportMetrics() {
|
||||
+ err := output.Metrics.ToJSONFile()
|
||||
+
|
||||
+ if err != nil {
|
||||
+ return errors.ErrJSONMarshalling.WrapWithNoMessage(err)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if output.BenchmarkResults != nil {
|
||||
+ sm.logger.Debugf("Benchmark results: %+v", output.BenchmarkResults)
|
||||
+ }
|
||||
+
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
+func (sm *ScanManager) Stop() error {
|
||||
+ if sm == nil {
|
||||
+ return nil
|
||||
+ }
|
||||
+
|
||||
+ return sm.cleanup()
|
||||
+}
|
||||
diff --git a/pkg/scanner/scanner.go b/pkg/scanner/scanner.go
|
||||
index c0a104f..6ef620a 100644
|
||||
--- a/pkg/scanner/scanner.go
|
||||
+++ b/pkg/scanner/scanner.go
|
||||
@@ -676,6 +676,8 @@ func (s *Scanner) Stop() {
|
||||
s.wg.Wait()
|
||||
close(s.initialRequestQueue)
|
||||
close(s.processedRequestQueue)
|
||||
+
|
||||
+ instance = nil
|
||||
}
|
||||
|
||||
// Wait blocks until all workers have finished processing.
|
||||
diff --git a/tests/e2e/wallace_test.go b/tests/e2e/wallace_test.go
|
||||
index 0e899e9..b8de5c8 100644
|
||||
--- a/tests/e2e/wallace_test.go
|
||||
+++ b/tests/e2e/wallace_test.go
|
||||
@@ -550,31 +550,26 @@ type scanResults struct {
|
||||
// }
|
||||
|
||||
// TestPlugins verifies that each plugin detects at least one vulnerability for each test path
|
||||
-func TestPlugins(t *testing.T) { //nolint: paralleltest
|
||||
- // Retrieve all available plugins without specific configurations
|
||||
+func TestPlugins(t *testing.T) {
|
||||
plugins := cli.BuildAllPlugins()
|
||||
|
||||
if len(plugins) == 0 {
|
||||
t.Fatal("No plugins available to test")
|
||||
}
|
||||
|
||||
- // Ensure that there are test paths to scan
|
||||
if len(SiteURLs) == 0 {
|
||||
t.Fatal("No site URLs available for scanning")
|
||||
}
|
||||
|
||||
- // Iterate over each plugin and perform the test
|
||||
- for _, plugin := range plugins { //nolint: paralleltest
|
||||
+ for _, plugin := range plugins {
|
||||
pluginName := plugin.Name()
|
||||
|
||||
t.Run(pluginName, func(t *testing.T) {
|
||||
- // t.Parallel()
|
||||
// Setup test environment for the current plugin
|
||||
resultDir, dbPath, cleanup := setupTestEnvironment(t, pluginName)
|
||||
defer cleanup()
|
||||
|
||||
- // Initialize plugin-specific configuration if needed
|
||||
- // Currently, using default configurations
|
||||
+ // Initialize plugin-specific configuration
|
||||
pluginConfig := coreStructs.NewPluginConfigBuilder(pluginName).
|
||||
WithCustomConfiguration(coreStructs.CustomPluginConfig{"name": pluginName}).
|
||||
Build()
|
||||
@@ -595,7 +590,6 @@ func TestPlugins(t *testing.T) { //nolint: paralleltest
|
||||
// Collect test URLs from initialized plugins' metadata
|
||||
testURLs := collectTestURLs(pluginInstances)
|
||||
|
||||
- // Skip the test if no test URLs are defined for the plugin
|
||||
if len(testURLs) == 0 {
|
||||
t.Skipf("No test URLs defined for plugin '%s'. Skipping test.", pluginName)
|
||||
}
|
||||
@@ -606,11 +600,26 @@ func TestPlugins(t *testing.T) { //nolint: paralleltest
|
||||
t.Fatalf("Failed to get default test config: %v", err)
|
||||
}
|
||||
|
||||
- // Run the scan
|
||||
- if err := cli.StartScan(sysConfig, crawlConfig, vulnConfig); err != nil {
|
||||
+ // Create and start scanner using the new interface
|
||||
+ scanner, err := cli.NewManagerBuilder(sysConfig, crawlConfig, vulnConfig).
|
||||
+ Build()
|
||||
+ if err != nil {
|
||||
+ t.Fatalf("Failed to create scanner: %v", err)
|
||||
+ }
|
||||
+
|
||||
+ // Start the scan
|
||||
+ if err := scanner.Start(); err != nil {
|
||||
t.Fatalf("Failed to start scan: %v", err)
|
||||
}
|
||||
|
||||
+ // Ensure scanner is stopped after test
|
||||
+ defer func() {
|
||||
+ if err := scanner.Stop(); err != nil {
|
||||
+ t.Errorf("Failed to stop scanner: %v", err)
|
||||
+ }
|
||||
+ }()
|
||||
+
|
||||
+ // Allow time for processing
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// Verify results in the database
|
||||
@@ -621,11 +630,11 @@ func TestPlugins(t *testing.T) { //nolint: paralleltest
|
||||
|
||||
// Assert that at least one vulnerability was found per test path
|
||||
expectedVulns := len(testURLs)
|
||||
- assert.GreaterOrEqual(t, vulnCount, expectedVulns, "Expected at least %d vulnerabilities", expectedVulns)
|
||||
- time.Sleep(5 * time.Second)
|
||||
+ assert.GreaterOrEqual(t, vulnCount, expectedVulns,
|
||||
+ "Expected at least %d vulnerabilities", expectedVulns)
|
||||
+
|
||||
// Verify that result files are present
|
||||
results := readScanResults(sysConfig.GetOutputDirectory())
|
||||
|
||||
assert.True(t, results.resultsFound, "Expected at least one result file")
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
```
|
||||
refactor(cli): introduce ScanManager for scan lifecycle management
|
||||
|
||||
Introduced `ScanManager` which simplifies the scan initiation process and makes the scan modular (instead of a monolithic function that bubbles everything). The manager implements the `ScanManagerInterface`:
|
||||
|
||||
- **Start():** Initializes and starts the scan process.
|
||||
- **Stop():** Gracefully terminates the scan process.
|
||||
|
||||
---
|
||||
|
||||
Structs:
|
||||
|
||||
- **ScanManager:** A new struct that manages the lifecycle of scanning components such as browser, crawler, scanner, storage, logger, and metrics.
|
||||
- **ScanManagerBuilder:** A builder pattern implementation to construct a `ScanManager` with custom configurations.
|
||||
```
|
||||
|
||||
Guidelines:
|
||||
- Title should follow commit convention
|
||||
- Description should be clear and business-focused
|
||||
- Technical details should be organized in sections
|
||||
- Use markdown formatting for readability
|
||||
- Focus on architectural and behavioral changes
|
||||
- Exclude trivial changes
|
||||
- Keep descriptions concise but complete
|
@ -1,77 +0,0 @@
|
||||
---
|
||||
model: ollama:pino-coder
|
||||
temperature: 0
|
||||
---
|
||||
|
||||
You are a documentation assistant skilled in writing professional, high-quality function documentation. Your task is to write top-level documentation for a given function, following these guidelines:
|
||||
|
||||
1. **High-Level Description**:
|
||||
- Start with a concise, high-level summary of what the function does.
|
||||
- Focus on *what* the function achieves rather than *how* it works internally.
|
||||
- Avoid mentioning specific internal functions, algorithms, or implementation details.
|
||||
|
||||
2. **Parameters**:
|
||||
- List all parameters with their names, types (if applicable), and purposes.
|
||||
- Clearly describe what each parameter represents and how it is used.
|
||||
|
||||
3. **Return Values**:
|
||||
- Explain what the function returns, including the type and purpose of each return value.
|
||||
- If applicable, describe any errors or exceptions that might be returned and under what conditions.
|
||||
|
||||
4. **Notes**:
|
||||
- Highlight any important behaviors, constraints, or side effects of the function.
|
||||
- Mention whether the function modifies its inputs or is side-effect free.
|
||||
|
||||
5. **Style**:
|
||||
- Use concise, professional language suitable for technical audiences.
|
||||
- Structure the documentation clearly and logically for easy readability.
|
||||
|
||||
### INPUT:
|
||||
|
||||
```
|
||||
func ReplaceAllRequestParameters(
|
||||
req models.CrawlRequest, payload string,
|
||||
) ([]models.CrawlRequest, error) {
|
||||
requests := make([]models.CrawlRequest, 0, len(req.Path.Parameters))
|
||||
|
||||
for _, param := range req.Path.Parameters {
|
||||
var modifiedParams []models.CrawlParameter
|
||||
|
||||
var err error
|
||||
|
||||
modifiedParams, err = ReplaceParameterValue(payload, &req, param.Name, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modPluginRequest := SetParameters(req, modifiedParams)
|
||||
|
||||
requests = append(requests, modPluginRequest)
|
||||
}
|
||||
|
||||
return requests, nil
|
||||
}
|
||||
```
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
```
|
||||
// ReplaceAllRequestParameters generates a new set of requests by replacing
|
||||
// each parameter's value with the provided payload.
|
||||
//
|
||||
// This function iterates over all parameters in the given request and creates a new request for each parameter,
|
||||
// replacing its value with the specified payload. The resulting requests are returned as a slice, leaving the original
|
||||
// request unmodified.
|
||||
//
|
||||
// Parameters:
|
||||
// - req (models.CrawlRequest): The original CrawlRequest containing parameters to be processed.
|
||||
// - payload (string): The value to replace each parameter's value.
|
||||
//
|
||||
// Returns:
|
||||
// - ([]models.CrawlRequest): A slice of new CrawlRequest instances, each with one parameter's value replaced by the payload.
|
||||
// - (error): An error if any issue occurs during processing.
|
||||
//
|
||||
// Notes:
|
||||
// - A new request is created for every parameter in the original request.
|
||||
// - The function is side-effect free and does not modify the original `CrawlRequest`.
|
||||
```
|
@ -1,34 +1,208 @@
|
||||
{ pkgs, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
stablePkgs = with pkgs;[
|
||||
rizin
|
||||
sshfs
|
||||
victor-mono
|
||||
home-manager
|
||||
ripgrep
|
||||
ydiff
|
||||
nix-index
|
||||
pipenv
|
||||
htop
|
||||
glances
|
||||
tree
|
||||
direnv
|
||||
devenv
|
||||
] ++ lib.optional (!pkgs.stdenv.isDarwin) pastebinit;
|
||||
|
||||
unstablePkgs = with pkgs.unstablePkgs; [ aider-chat ];
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./zsh.nix
|
||||
./git.nix
|
||||
./helix.nix
|
||||
];
|
||||
let unstable = import <nixpkgs-unstable> { };
|
||||
in {
|
||||
imports = [ ./zsh.nix ./git.nix ];
|
||||
|
||||
home = {
|
||||
packages = stablePkgs ++ unstablePkgs;
|
||||
sessionVariables = {
|
||||
EDITOR = "nvim";
|
||||
VISUAL = "nvim";
|
||||
};
|
||||
};
|
||||
|
||||
stateVersion = "25.05";
|
||||
programs.neovim = {
|
||||
enable = true;
|
||||
package = unstable.neovim-unwrapped;
|
||||
extraPackages = with pkgs; [
|
||||
nodePackages.prettier
|
||||
nodePackages.pyright
|
||||
rnix-lsp
|
||||
rust-analyzer
|
||||
cmake-format
|
||||
clang-tools
|
||||
rustfmt
|
||||
nixfmt
|
||||
];
|
||||
extraConfig = ''
|
||||
" syntax
|
||||
syntax enable
|
||||
|
||||
" color themes
|
||||
set termguicolors
|
||||
colorscheme molokai
|
||||
|
||||
" wildcard mode
|
||||
set wildmode=longest:full,full
|
||||
|
||||
" remapping popup menu (command autocompletion)
|
||||
" cnoremap <expr> <up> pumvisible() ? "<C-p>" : "<up>
|
||||
" cnoremap <expr> <down> pumvisible() ? "<C-n>" : "<down>"
|
||||
" cnoremap <expr> <CR> pumvisible() ? "<C-e>":"<CR>"
|
||||
" set line numbers
|
||||
set number
|
||||
|
||||
" enable indent guides
|
||||
let g:indent_guides_enable_on_vim_startup = 1
|
||||
|
||||
" Exit Vim if NERDTree is the only window left.
|
||||
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() |
|
||||
\ quit | endif
|
||||
|
||||
" Start NERDTree. If a file is specified, move the cursor to its window.
|
||||
autocmd StdinReadPre * let s:std_in=1
|
||||
autocmd VimEnter * NERDTree | if argc() > 0 || exists("s:std_in") | wincmd p | endif
|
||||
|
||||
" Start NERDTree when Vim starts with a directory argument.
|
||||
autocmd StdinReadPre * let s:std_in=1
|
||||
autocmd VimEnter * if argc() == 1 && isdirectory(argv()[0]) && !exists('s:std_in') |
|
||||
\ execute 'NERDTree' argv()[0] | wincmd p | enew | execute 'cd '.argv()[0] | endif
|
||||
|
||||
" Exit Vim if NERDTree is the only window left.
|
||||
autocmd BufEnter * if tabpagenr('$') == 1 && winnr('$') == 1 && exists('b:NERDTree') && b:NERDTree.isTabTree() |
|
||||
\ quit | endif
|
||||
|
||||
" Start interactive EasyAlign in visual mode (e.g. vipga)
|
||||
xmap ga <Plug>(EasyAlign)
|
||||
|
||||
" Start interactive EasyAlign for a motion/text object (e.g. gaip)
|
||||
nmap ga <Plug>(EasyAlign)
|
||||
|
||||
" Highlight row and column
|
||||
set cul
|
||||
set cuc
|
||||
|
||||
" Fix for code not being aligned if between comment blocks
|
||||
set cindent cinkeys-=0#
|
||||
set expandtab shiftwidth=2 tabstop=2 softtabstop=2
|
||||
|
||||
" Enable alignment
|
||||
let g:neoformat_basic_format_align = 1
|
||||
|
||||
" Enable tab to spaces conversion
|
||||
let g:neoformat_basic_format_retab = 1
|
||||
|
||||
" Enable trimmming of trailing whitespace
|
||||
let g:neoformat_basic_format_trim = 1
|
||||
|
||||
lua << EOF
|
||||
------------------
|
||||
-- Setup nvim-cmp.
|
||||
------------------
|
||||
|
||||
-- Set completeopt to have a better completion experience
|
||||
vim.o.completeopt = 'menuone,noselect'
|
||||
|
||||
local cmp = require'cmp'
|
||||
|
||||
cmp.setup({
|
||||
snippet = {
|
||||
-- REQUIRED - you must specify a snippet engine
|
||||
expand = function(args)
|
||||
vim.fn["vsnip#anonymous"](args.body) -- For `vsnip` users.
|
||||
end,
|
||||
},
|
||||
mapping = {
|
||||
['<C-b>'] = cmp.mapping(cmp.mapping.scroll_docs(-4), { 'i', 'c' }),
|
||||
['<C-f>'] = cmp.mapping(cmp.mapping.scroll_docs(4), { 'i', 'c' }),
|
||||
['<C-Space>'] = cmp.mapping(cmp.mapping.complete(), { 'i', 'c' }),
|
||||
['<C-y>'] = cmp.config.disable, -- Specify `cmp.config.disable` if you want to remove the default `<C-y>` mapping.
|
||||
['<C-e>'] = cmp.mapping({
|
||||
i = cmp.mapping.abort(),
|
||||
c = cmp.mapping.close(),
|
||||
}),
|
||||
['<CR>'] = cmp.mapping.confirm({ select = true }), -- Accept currently selected item. Set `select` to `false` to only confirm explicitly selected items.
|
||||
},
|
||||
sources = cmp.config.sources({
|
||||
{ name = 'nvim_lsp' },
|
||||
{ name = 'vsnip' }, -- For vsnip users.
|
||||
}, {
|
||||
{ name = 'buffer' },
|
||||
})
|
||||
})
|
||||
|
||||
-- Use buffer source for `/` (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline('/', {
|
||||
sources = {
|
||||
{ name = 'buffer' }
|
||||
}
|
||||
})
|
||||
|
||||
-- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore).
|
||||
cmp.setup.cmdline(':', {
|
||||
sources = cmp.config.sources({
|
||||
{ name = 'path' }
|
||||
}, {
|
||||
{ name = 'cmdline' }
|
||||
})
|
||||
})
|
||||
|
||||
-- Setup lspconfig.
|
||||
local capabilities = require('cmp_nvim_lsp').update_capabilities(vim.lsp.protocol.make_client_capabilities())
|
||||
|
||||
--------------
|
||||
-- LSP Servers
|
||||
--------------
|
||||
|
||||
require'lspconfig'.pyright.setup{
|
||||
capabilities = capabilities
|
||||
}
|
||||
require'lspconfig'.rust_analyzer.setup{
|
||||
capabilities = capabilities
|
||||
}
|
||||
require'lspconfig'.rnix.setup{
|
||||
capabilities = capabilities
|
||||
}
|
||||
require'lspconfig'.clangd.setup{
|
||||
capabilities = capabilities,
|
||||
cmd = {
|
||||
"clangd",
|
||||
"--background-index",
|
||||
"--clang-tidy",
|
||||
},
|
||||
}
|
||||
|
||||
-------------------
|
||||
-- TreeSitter setup
|
||||
-------------------
|
||||
require'nvim-treesitter.configs'.setup {
|
||||
highlight = {
|
||||
enable = true,
|
||||
custom_captures = {
|
||||
-- Highlight the @foo.bar capture group with the "Identifier" highlight group.
|
||||
["foo.bar"] = "Identifier",
|
||||
},
|
||||
-- Setting this to true will run `:h syntax` and tree-sitter at the same time.
|
||||
-- Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
|
||||
-- Using this option may slow down your editor, and you may see some duplicate highlights.
|
||||
-- Instead of true it can also be a list of languages
|
||||
additional_vim_regex_highlighting = false,
|
||||
},
|
||||
}
|
||||
EOF
|
||||
'';
|
||||
|
||||
viAlias = true;
|
||||
vimAlias = true;
|
||||
plugins = with unstable.vimPlugins; [
|
||||
vim-nix
|
||||
molokai
|
||||
vim-airline
|
||||
vim-airline-themes
|
||||
vim-lsp
|
||||
vim-indent-guides
|
||||
vim-signify
|
||||
nerdtree
|
||||
vim-easy-align
|
||||
vim-fugitive
|
||||
vimtex
|
||||
neoformat
|
||||
nvim-lspconfig
|
||||
vim-vsnip
|
||||
nvim-cmp
|
||||
cmp-nvim-lsp
|
||||
(nvim-treesitter.withPlugins (_: unstable.tree-sitter.allGrammars))
|
||||
nvim-treesitter-textobjects
|
||||
];
|
||||
};
|
||||
}
|
||||
|
@ -9,8 +9,7 @@ let
|
||||
name = "guake";
|
||||
package = pkgs.guake;
|
||||
});
|
||||
in
|
||||
{
|
||||
in {
|
||||
imports = [ ./gnome.nix ];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
@ -1,27 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
home.packages = with pkgs; [ any-nix-shell fishPlugins.tide fishPlugins.bass fishPlugins.fzf-fish ];
|
||||
|
||||
programs.fish = {
|
||||
enable = true;
|
||||
|
||||
shellAbbrs = {
|
||||
"_" = "sudo";
|
||||
};
|
||||
|
||||
shellInit = ''
|
||||
# avoid macOS updates to destroy nix
|
||||
# if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then
|
||||
# source '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
|
||||
# end
|
||||
|
||||
any-nix-shell fish --info-right | source
|
||||
# source ${pkgs.nix-index}/etc/profile.d/command-not-found.sh
|
||||
|
||||
# disable autosuggestions
|
||||
set -g fish_autosuggestion_enabled 0
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
@ -1,11 +1,8 @@
|
||||
{ pkgs, ... }: {
|
||||
{ config, pkgs, lib, ... }: {
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "Giulio De Pasquale";
|
||||
userEmail = "git@depasquale.giugl.io";
|
||||
delta.enable = true;
|
||||
lfs.enable = true;
|
||||
|
||||
userEmail = "depasquale+git@giugl.io";
|
||||
extraConfig = {
|
||||
filter."lfs" = {
|
||||
process = "git-lfs filter-process";
|
||||
@ -14,12 +11,7 @@
|
||||
smudge = "git-lfs smudge -- %f";
|
||||
};
|
||||
};
|
||||
|
||||
aliases = {
|
||||
ai = ''! cd -- "''${GIT_PREFIX:-.}" && git diff HEAD -- "$@" | aichat -m ollama:pino-coder -c -r commitmessage #'';
|
||||
ais = ''! cd -- "''${GIT_PREFIX:-.}" && git diff --staged HEAD -- "$@" | aichat -m ollama:pino-coder -c -r commitmessage #'';
|
||||
delta.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
home.packages = [ pkgs.git-lfs ];
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user