Compare commits
3 Commits
master
...
laptopshit
Author | SHA1 | Date | |
---|---|---|---|
3a28439153 | |||
2c66c51224 | |||
|
91dd406c3e |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,5 +1,3 @@
|
||||
result
|
||||
result/
|
||||
|
||||
.aider*
|
||||
.env
|
||||
|
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="
|
||||
];
|
||||
};
|
||||
}
|
||||
|
248
flake.lock
generated
248
flake.lock
generated
@ -1,125 +1,33 @@
|
||||
{
|
||||
"nodes": {
|
||||
"agenix-flake": {
|
||||
"inputs": {
|
||||
"darwin": "darwin",
|
||||
"home-manager": "home-manager",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747575206,
|
||||
"narHash": "sha256-NwmAFuDUO/PFcgaGGr4j3ozG9Pe5hZ/ogitWhY+D81k=",
|
||||
"owner": "ryantm",
|
||||
"repo": "agenix",
|
||||
"rev": "4835b1dc898959d8547a871ef484930675cb47f1",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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": 1748665073,
|
||||
"narHash": "sha256-RMhjnPKWtCoIIHiuR9QKD7xfsKb3agxzMfJY8V9MOew=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "282e1e029cb6ab4811114fc85110613d72771dea",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.05",
|
||||
"repo": "home-manager",
|
||||
"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": 1750506804,
|
||||
"narHash": "sha256-VLFNc4egNjovYVxDGyBYTrvVCgDYgENp5bVi9fPTDYc=",
|
||||
"lastModified": 1639699734,
|
||||
"narHash": "sha256-tlX6WebGmiHb2Hmniff+ltYp+7dRfdsBxw9YczLsP60=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4206c4cb56751df534751b058295ea61357bbbaa",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "4206c4cb56751df534751b058295ea61357bbbaa",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1745391562,
|
||||
"narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
|
||||
"rev": "03ec468b14067729a285c2c7cfa7b9434a04816c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@ -129,151 +37,27 @@
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-master": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1749040375,
|
||||
"narHash": "sha256-zwVvfxgrXcInI2E/dDg9v80OrvKUT7HtPECu53Khcq0=",
|
||||
"lastModified": 1639794673,
|
||||
"narHash": "sha256-bjauV0+Z4WmxeiHXecyiEOEwo+XysO6kx36beeatbl0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "57afa2783caf7d6713f63c8e29fba6c52a3a5300",
|
||||
"rev": "2627c4b795107ba94562626925f5a9a2bc62ebc6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "master",
|
||||
"ref": "nixos-21.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1750622754,
|
||||
"narHash": "sha256-kMhs+YzV4vPGfuTpD3mwzibWUE6jotw5Al2wczI0Pv8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c7ab75210cb8cb16ddd8f290755d9558edde7ee1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "c7ab75210cb8cb16ddd8f290755d9558edde7ee1",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1735264675,
|
||||
"narHash": "sha256-MgdXpeX2GuJbtlBrH9EdsUeWl/yXEubyvxM1G+yO4Ak=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d49da4c08359e3c39c4e27c74ac7ac9b70085966",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-24.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nvidia-patch": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"utils": "utils"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748931931,
|
||||
"narHash": "sha256-0NUhiMITsYlXDjgcVbLayI0rgrEdf5NIbpW3oLueYUs=",
|
||||
"owner": "icewind1991",
|
||||
"repo": "nvidia-patch-nixos",
|
||||
"rev": "fa8f006a236349790c94801ac85e43f103b35baf",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "icewind1991",
|
||||
"repo": "nvidia-patch-nixos",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pepeflake": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"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",
|
||||
"local-unstable": "local-unstable",
|
||||
"home-manager": "home-manager",
|
||||
"nixos-unstable": "nixos-unstable",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"utils": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
172
flake.nix
172
flake.nix
@ -1,160 +1,62 @@
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/c7ab75210cb8cb16ddd8f290755d9558edde7ee1";
|
||||
nixos-unstable.url = "github:NixOS/nixpkgs/4206c4cb56751df534751b058295ea61357bbbaa";
|
||||
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";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nvidia-patch = {
|
||||
url = "github:icewind1991/nvidia-patch-nixos";
|
||||
url = "github:rycee/home-manager/release-21.11";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
navidrome.url = "github:antifuchs/nixpkgs/fix-151550";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self
|
||||
, nixpkgs
|
||||
, nixos-unstable
|
||||
, nixpkgs-master
|
||||
, local-unstable
|
||||
, home-manager
|
||||
, nvidia-patch
|
||||
, agenix-flake
|
||||
, pepeflake
|
||||
}:
|
||||
outputs = inputs@{ self, nixpkgs, nixos-unstable, home-manager, navidrome}:
|
||||
let
|
||||
sysLinuxX64 = "x86_64-linux";
|
||||
sysDarwin = "aarch64-darwin";
|
||||
sysLinuxAarch = "aarch64-linux";
|
||||
system = "x86_64-linux";
|
||||
|
||||
wrapPkgsSystem = { system, cudaSupport ? false }:
|
||||
let
|
||||
config = {
|
||||
inherit cudaSupport;
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
overlays = [ (final: prev: { inherit unstable; }) ];
|
||||
};
|
||||
|
||||
allowUnfree = true;
|
||||
};
|
||||
unstable = import nixos-unstable {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
|
||||
cachixOverlay = final: prev: {
|
||||
nixosModules = (prev.nixosModules or { }) // {
|
||||
cachixConfig = import ./cachix.nix;
|
||||
};
|
||||
};
|
||||
utils = import ./lib {
|
||||
inherit pkgs unstable nixpkgs nixos-unstable home-manager;
|
||||
};
|
||||
|
||||
|
||||
extOverlays = [
|
||||
(nvidia-patch.overlays.default)
|
||||
cachixOverlay
|
||||
];
|
||||
|
||||
importNixpkgs = { flake }:
|
||||
import flake {
|
||||
inherit system config;
|
||||
|
||||
overlays = extOverlays;
|
||||
};
|
||||
|
||||
unstablePkgs = importNixpkgs { flake = nixos-unstable; };
|
||||
masterPkgs = importNixpkgs { flake = nixpkgs-master; };
|
||||
localPkgs = importNixpkgs { flake = local-unstable; };
|
||||
agenixPkgs = importNixpkgs { flake = agenix-flake; };
|
||||
pepePkgs = pepeflake.packages.${system} // pepeflake.legacyPackages.${system} or { };
|
||||
|
||||
additionalOverlays = [
|
||||
(final: prev: { inherit unstablePkgs; })
|
||||
(final: prev: { inherit localPkgs; })
|
||||
(final: prev: { inherit agenixPkgs; })
|
||||
(final: prev: { inherit masterPkgs; })
|
||||
(final: prev: { inherit pepePkgs; })
|
||||
];
|
||||
in
|
||||
import nixpkgs {
|
||||
inherit system config;
|
||||
overlays = additionalOverlays ++ extOverlays ++ [
|
||||
(final: prev: {
|
||||
ctranslate2 = prev.ctranslate2.override {
|
||||
withCUDA = true;
|
||||
withCuDNN = true;
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
wrapUtils = { pkgs }:
|
||||
let
|
||||
inherit (pkgs.lib) makeScope;
|
||||
inherit (pkgs) newScope;
|
||||
in
|
||||
makeScope newScope (self: rec {
|
||||
inherit nixpkgs home-manager nixos-unstable;
|
||||
inherit (self.callPackage ./lib/utils.nix { }) mkSysRole mkHomeRole;
|
||||
inherit (user) mkUser;
|
||||
|
||||
user = self.callPackage ./lib/user.nix { };
|
||||
host = self.callPackage ./lib/host.nix { };
|
||||
});
|
||||
|
||||
|
||||
pkgsLinuxX64Cuda = wrapPkgsSystem { system = sysLinuxX64; cudaSupport = true; };
|
||||
utilsLinuxX64Cuda = wrapUtils { pkgs = pkgsLinuxX64Cuda; };
|
||||
|
||||
pkgsLinuxAarch = wrapPkgsSystem { system = sysLinuxAarch; };
|
||||
utilsLinuxAarch = wrapUtils { pkgs = pkgsLinuxAarch; };
|
||||
|
||||
pkgsDarwin = wrapPkgsSystem { system = sysDarwin; };
|
||||
utilsDarwin = wrapUtils { pkgs = pkgsDarwin; };
|
||||
in
|
||||
{
|
||||
inherit (utils) host;
|
||||
inherit (utils) user;
|
||||
in {
|
||||
nixosConfigurations = {
|
||||
architect = utilsLinuxX64Cuda.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") ];
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
homeConfigurations = {
|
||||
giulioMac = utilsDarwin.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" ];
|
||||
gAluminum = host.mkHost {
|
||||
name = "gAluminum";
|
||||
users = [{
|
||||
user = "giulio";
|
||||
roles = [ "desktop" "ssh" "git" ];
|
||||
}];
|
||||
roles = [ "gnome" ];
|
||||
};
|
||||
gdepasqualeMac = utilsDarwin.user.mkHMUser {
|
||||
name = "gdepasquale";
|
||||
roles = [ "ssh" ];
|
||||
};
|
||||
giulioAarch = utilsLinuxAarch.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" ];
|
||||
};
|
||||
giulioX64 = utilsLinuxX64Cuda.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "ssh" "go" ];
|
||||
};
|
||||
giulioX64NoSSH = utilsLinuxX64Cuda.user.mkHMUser {
|
||||
name = "giulio";
|
||||
roles = [ "go" ];
|
||||
};
|
||||
gdepasqualeX64 = utilsLinuxX64Cuda.user.mkHMUser {
|
||||
name = "gdepasquale";
|
||||
roles = [ "ssh" "go" ];
|
||||
};
|
||||
};
|
||||
|
||||
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" ];
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "books.giugl.io";
|
||||
auth_block = (import ./openid.nix { inherit lib; }).openresty_oidc_block;
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
services = {
|
||||
calibre-web = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
options = {
|
||||
enableBookConversion = true;
|
||||
enableBookUploading = true;
|
||||
};
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:8083";
|
||||
extraConfig = ''
|
||||
client_max_body_size 500M;
|
||||
'' + auth_block { access_role = "calibre"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "calibre-web" ];
|
||||
}
|
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,40 +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
|
||||
./netdata.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 = {
|
||||
@ -42,20 +61,22 @@ 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 = {
|
||||
systemd-boot ={
|
||||
enable = true;
|
||||
memtest86.enable = true;
|
||||
};
|
||||
@ -64,212 +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
|
||||
'';
|
||||
};
|
||||
|
||||
services = {
|
||||
fwupd.enable = true;
|
||||
das_watchdog.enable = true;
|
||||
zfs.autoScrub.enable = true;
|
||||
environment.systemPackages = with pkgs; [ cudatoolkit cachix ];
|
||||
|
||||
hardware = {
|
||||
opengl.enable = true;
|
||||
opengl.extraPackages = with pkgs; [ vaapiVdpau ];
|
||||
opengl.driSupport = true;
|
||||
};
|
||||
|
||||
services.das_watchdog.enable = true;
|
||||
|
||||
services = {
|
||||
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}"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
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";
|
||||
package = pkgs.unstablePkgs.radarr;
|
||||
};
|
||||
|
||||
sonarr = {
|
||||
enable = true;
|
||||
domain = "htson.giugl.io";
|
||||
package = pkgs.unstablePkgs.sonarr;
|
||||
};
|
||||
|
||||
bazarr = {
|
||||
enable = true;
|
||||
domain = "htbaz.giugl.io";
|
||||
package = pkgs.unstablePkgs.bazarr;
|
||||
};
|
||||
|
||||
nzbget = {
|
||||
enable = true;
|
||||
domain = "htnzb.giugl.io";
|
||||
package = pkgs.unstablePkgs.nzbget;
|
||||
};
|
||||
|
||||
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.unstablePkgs.ollama-cuda;
|
||||
backendDomain = "ollama.giugl.io";
|
||||
acceleration = "cuda";
|
||||
};
|
||||
|
||||
homeassistant = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.home-assistant;
|
||||
domain = "home.giugl.io";
|
||||
extraComponents = [
|
||||
"otbr"
|
||||
"litterrobot"
|
||||
"apple_tv"
|
||||
"homekit"
|
||||
"homekit_controller"
|
||||
"spotify"
|
||||
"hue"
|
||||
"sonos"
|
||||
"tplink"
|
||||
"ollama"
|
||||
"wyoming"
|
||||
"whisper"
|
||||
"piper"
|
||||
"isal"
|
||||
"radarr"
|
||||
"sonarr"
|
||||
"mqtt"
|
||||
"mqtt_eventstream"
|
||||
"mqtt_json"
|
||||
"mqtt_room"
|
||||
"mqtt_statestream"
|
||||
"github"
|
||||
"webostv"
|
||||
"reolink"
|
||||
"onvif"
|
||||
"xiaomi_miio"
|
||||
"ring"
|
||||
];
|
||||
|
||||
extraPackages = python3Packages: with pkgs.unstablePkgs.python3Packages; [
|
||||
pyporscheconnectapi
|
||||
];
|
||||
|
||||
config = {
|
||||
http = {
|
||||
server_host = "127.0.0.1";
|
||||
server_port = 8123;
|
||||
use_x_forwarded_for = true;
|
||||
trusted_proxies = [ "127.0.0.1" ];
|
||||
};
|
||||
homeassistant = {
|
||||
name = "Brigettine Square";
|
||||
latitude = 52.1958;
|
||||
longitude = 0.180746;
|
||||
unit_system = "metric";
|
||||
};
|
||||
default_config = { };
|
||||
automation = "!include automations.yaml";
|
||||
frontend.themes = "!include_dir_merge_named themes";
|
||||
};
|
||||
};
|
||||
|
||||
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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
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 = {
|
||||
enable = true;
|
||||
nextDNSId = "d65174";
|
||||
extraDomains = {
|
||||
"architect.devs.giugl.io" = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
services = {
|
||||
dnsmasq = {
|
||||
enable = true;
|
||||
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,150 +35,170 @@ in
|
||||
|
||||
nftables = {
|
||||
enable = true;
|
||||
ruleset = with config.pepe.core.network.interfaces; ''
|
||||
table ip raw {
|
||||
chain PREROUTING {
|
||||
type filter hook prerouting priority raw; policy accept;
|
||||
}
|
||||
ruleset = ''
|
||||
table ip raw {
|
||||
chain PREROUTING {
|
||||
type filter hook prerouting priority raw; policy accept;
|
||||
}
|
||||
|
||||
chain OUTPUT {
|
||||
type filter hook output priority raw; policy accept;
|
||||
}
|
||||
}
|
||||
chain OUTPUT {
|
||||
type filter hook output priority raw; policy accept;
|
||||
}
|
||||
}
|
||||
|
||||
table ip nat {
|
||||
chain DOCKER {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
chain PREROUTING {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
table ip nat {
|
||||
chain PREROUTING {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
}
|
||||
|
||||
chain INPUT {
|
||||
type nat hook input priority 100; policy accept;
|
||||
}
|
||||
chain INPUT {
|
||||
type nat hook input priority 100; policy accept;
|
||||
}
|
||||
|
||||
chain OUTPUT {
|
||||
type nat hook output priority -100; policy accept;
|
||||
}
|
||||
chain OUTPUT {
|
||||
type nat hook output priority -100; policy accept;
|
||||
}
|
||||
|
||||
chain POSTROUTING {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
oifname ${lan.interface} ip saddr ${tailscale.net} masquerade
|
||||
}
|
||||
}
|
||||
chain POSTROUTING {
|
||||
type nat hook postrouting priority srcnat; policy accept;
|
||||
oifname ${wan-if} ip saddr {${
|
||||
lib.concatStringsSep "," towan-wg
|
||||
}} masquerade
|
||||
}
|
||||
}
|
||||
|
||||
table ip mangle {
|
||||
chain PREROUTING {
|
||||
type filter hook prerouting priority mangle; policy drop;
|
||||
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 "lo" accept comment "bind any ip to intf lo"
|
||||
jump mangle_drop
|
||||
}
|
||||
table ip mangle {
|
||||
chain PREROUTING {
|
||||
type filter hook prerouting priority mangle; policy drop;
|
||||
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 ${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
|
||||
}
|
||||
|
||||
chain INPUT {
|
||||
type filter hook input priority mangle; policy accept;
|
||||
}
|
||||
chain INPUT {
|
||||
type filter hook input priority mangle; policy accept;
|
||||
}
|
||||
|
||||
chain FORWARD {
|
||||
type filter hook forward priority mangle; policy accept;
|
||||
}
|
||||
chain FORWARD {
|
||||
type filter hook forward priority mangle; policy accept;
|
||||
}
|
||||
|
||||
chain OUTPUT {
|
||||
type route hook output priority mangle; policy accept;
|
||||
}
|
||||
chain OUTPUT {
|
||||
type route hook output priority mangle; policy accept;
|
||||
}
|
||||
|
||||
chain POSTROUTING {
|
||||
type filter hook postrouting priority mangle; policy accept;
|
||||
}
|
||||
chain POSTROUTING {
|
||||
type filter hook postrouting priority mangle; policy accept;
|
||||
}
|
||||
|
||||
chain mangle_drop {
|
||||
ip protocol icmp jump mangle_drop_icmp
|
||||
ip protocol udp jump mangle_drop_udp
|
||||
ip protocol tcp jump mangle_drop_tcp
|
||||
log prefix "MANGLE-DROP-UNK "
|
||||
drop
|
||||
}
|
||||
chain mangle_drop {
|
||||
ip protocol icmp jump mangle_drop_icmp
|
||||
ip protocol udp jump mangle_drop_udp
|
||||
ip protocol tcp jump mangle_drop_tcp
|
||||
log prefix "MANGLE-DROP-UNK "
|
||||
drop
|
||||
}
|
||||
|
||||
chain mangle_drop_icmp {
|
||||
log prefix "MANGLE-DROP-ICMP "
|
||||
drop
|
||||
}
|
||||
chain mangle_drop_icmp {
|
||||
log prefix "MANGLE-DROP-ICMP "
|
||||
drop
|
||||
}
|
||||
|
||||
chain mangle_drop_tcp {
|
||||
log prefix "MANGLE-DROP-TCP "
|
||||
drop
|
||||
}
|
||||
chain mangle_drop_tcp {
|
||||
log prefix "MANGLE-DROP-TCP "
|
||||
drop
|
||||
}
|
||||
|
||||
chain mangle_drop_udp {
|
||||
log prefix "MANGLE-DROP-UDP "
|
||||
drop
|
||||
}
|
||||
}
|
||||
chain mangle_drop_udp {
|
||||
log prefix "MANGLE-DROP-UDP "
|
||||
drop
|
||||
}
|
||||
}
|
||||
|
||||
table ip filter {
|
||||
chain INPUT {
|
||||
type filter hook input priority filter; policy drop;
|
||||
table ip filter {
|
||||
chain INPUT {
|
||||
type filter hook input priority filter; policy drop;
|
||||
|
||||
ct state established,related accept
|
||||
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"
|
||||
ct state established,related accept
|
||||
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 ${proxy-wg} accept comment "proxy > local"
|
||||
ip saddr {${lib.concatStringsSep "," gdevices-wg}} accept comment "vpn > local"
|
||||
|
||||
iifname ${lan.interface} tcp dport {${openTCP}} accept
|
||||
iifname ${lan.interface} udp dport {${openUDP}} accept
|
||||
jump filter_drop
|
||||
}
|
||||
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
|
||||
|
||||
chain FORWARD {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
ct state established,related accept
|
||||
jump filter_drop
|
||||
}
|
||||
|
||||
oifname ${lan.interface} ip saddr ${tailscale.net} accept
|
||||
chain FORWARD {
|
||||
type filter hook forward priority filter; policy drop;
|
||||
ct state established,related accept
|
||||
|
||||
jump filter_drop
|
||||
}
|
||||
# client to client
|
||||
ip saddr {${lib.concatStringsSep "," c2c-wg}} ip daddr {${
|
||||
lib.concatStringsSep "," c2c-wg
|
||||
}} accept
|
||||
|
||||
chain OUTPUT {
|
||||
type filter hook output priority filter; policy drop;
|
||||
ct state established,related accept
|
||||
accept comment "local > *"
|
||||
jump filter_drop
|
||||
}
|
||||
# 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
|
||||
|
||||
chain filter_drop {
|
||||
ip protocol icmp jump filter_drop_icmp
|
||||
ip protocol udp jump filter_drop_udp
|
||||
ip protocol tcp jump filter_drop_tcp
|
||||
log prefix "DROP-UNK "
|
||||
drop
|
||||
}
|
||||
# nat to wan
|
||||
oifname ${wan-if} ip saddr {${
|
||||
lib.concatStringsSep "," towan-wg
|
||||
}} accept
|
||||
|
||||
chain filter_drop_icmp {
|
||||
log prefix "DROP-icmp "
|
||||
drop
|
||||
}
|
||||
jump filter_drop
|
||||
}
|
||||
|
||||
chain filter_drop_tcp {
|
||||
log prefix "DROP-tcp "
|
||||
drop
|
||||
}
|
||||
chain OUTPUT {
|
||||
type filter hook output priority filter; policy drop;
|
||||
ct state established,related accept
|
||||
accept comment "local > *"
|
||||
jump filter_drop
|
||||
}
|
||||
|
||||
chain filter_drop_udp {
|
||||
log prefix "DROP-udp "
|
||||
drop
|
||||
}
|
||||
}
|
||||
'';
|
||||
chain filter_drop {
|
||||
ip protocol icmp jump filter_drop_icmp
|
||||
ip protocol udp jump filter_drop_udp
|
||||
ip protocol tcp jump filter_drop_tcp
|
||||
log prefix "DROP-UNK "
|
||||
drop
|
||||
}
|
||||
|
||||
chain filter_drop_icmp {
|
||||
log prefix "DROP-icmp "
|
||||
drop
|
||||
}
|
||||
|
||||
chain filter_drop_tcp {
|
||||
log prefix "DROP-tcp "
|
||||
drop
|
||||
}
|
||||
|
||||
chain filter_drop_udp {
|
||||
log prefix "DROP-udp "
|
||||
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.initrd.availableKernelModules =
|
||||
[ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-amd" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
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 =
|
||||
[ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
};
|
||||
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";
|
||||
fsType = "vfat";
|
||||
};
|
||||
fileSystems."/media" = {
|
||||
device = "datapool/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
"/backednvme" = {
|
||||
device = "/dev/mapper/backedNvme";
|
||||
};
|
||||
fileSystems."/secrets" = {
|
||||
device = "backedpool/secrets";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
"/services" = {
|
||||
device = "/backednvme/services";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
fileSystems."/var/lib" = {
|
||||
device = "backedpool/services";
|
||||
fsType = "zfs";
|
||||
};
|
||||
|
||||
"/secrets" = {
|
||||
device = "/backednvme/secrets";
|
||||
options = [ "bind" ];
|
||||
};
|
||||
|
||||
"${config.pepe.core.media.path}" = lib.mkIf config.pepe.core.media.enable {
|
||||
device = "nvmedata/media";
|
||||
fsType = "zfs";
|
||||
};
|
||||
fileSystems."/boot" = {
|
||||
device = "/dev/disk/by-uuid/AF19-5616";
|
||||
fsType = "vfat";
|
||||
};
|
||||
|
||||
swapDevices = [{
|
||||
device = "/swapfile";
|
||||
size = 1024 * 64;
|
||||
device = "/dev/sdc1";
|
||||
size = 10000;
|
||||
}];
|
||||
|
||||
}
|
||||
|
@ -1,22 +1,24 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "tube.giugl.io";
|
||||
in
|
||||
{
|
||||
services.invidious = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.invidious;
|
||||
settings = {
|
||||
hmac_key = "a2a91eca269d26de1221285e8981879834045bff";
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
invidious = {
|
||||
enable = true;
|
||||
port = 9092;
|
||||
};
|
||||
|
||||
nginx.virtualHosts.${domain} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = { proxyPass = "http://localhost:9092"; };
|
||||
};
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations."/" = {
|
||||
port = config.services.invidious.port;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
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}
|
||||
'';
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
{ config, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "photos.giugl.io";
|
||||
backendPort = 8001;
|
||||
frontendPort = 3000;
|
||||
in
|
||||
{
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "tailscale" ];
|
||||
|
||||
locations."/" = {
|
||||
host = "172.17.0.1";
|
||||
port = frontendPort;
|
||||
# allowLan = true;
|
||||
# allow = [ config.architect.networks."tailscale".net ];
|
||||
};
|
||||
|
||||
locations."~ ^/(api|media)/" = {
|
||||
host = "172.17.0.1";
|
||||
port = backendPort;
|
||||
# allowLan = true;
|
||||
# allow = [ config.architect.networks."tailscale".net ];
|
||||
};
|
||||
|
||||
locations."/ws" = {
|
||||
host = "172.17.0.1";
|
||||
port = backendPort;
|
||||
proxyWebsockets = true;
|
||||
# allowLan = true;
|
||||
# allow = [ config.architect.networks."tailscale".net ];
|
||||
};
|
||||
};
|
||||
|
||||
services.redis.servers."librephotos" = {
|
||||
enable = true;
|
||||
port = 1233;
|
||||
bind = "172.17.0.1";
|
||||
extraParams = [ "--protected-mode no" ];
|
||||
};
|
||||
|
||||
virtualisation.oci-containers = {
|
||||
containers = {
|
||||
librephotos-front = {
|
||||
image = "reallibrephotos/librephotos-frontend:latest";
|
||||
autoStart = true;
|
||||
ports = [
|
||||
"172.17.0.1:${toString frontendPort}:${toString frontendPort}"
|
||||
];
|
||||
};
|
||||
|
||||
librephotos-back = {
|
||||
image = "reallibrephotos/librephotos:latest";
|
||||
autoStart = true;
|
||||
|
||||
ports = [
|
||||
"172.17.0.1:${toString backendPort}:${toString backendPort}"
|
||||
];
|
||||
|
||||
environment = {
|
||||
SECRET_KEY = "LOLOL";
|
||||
BACKEND_HOST = domain;
|
||||
ADMIN_EMAIL = "me@giugl.io";
|
||||
ADMIN_USERNAME = "giulio";
|
||||
ADMIN_PASSWORD = "giulio";
|
||||
ALLOWED_HOSTS = domain;
|
||||
DB_BACKEND = "mysql";
|
||||
DB_NAME = "librephotos";
|
||||
DB_USER = "librephotos";
|
||||
DB_PASS = "librephotos";
|
||||
DB_HOST = "172.17.0.1";
|
||||
DB_PORT = toString config.services.mysql.settings.mysqld.port;
|
||||
REDIS_HOST = "172.17.0.1";
|
||||
REDIS_PORT = toString config.services.redis.servers."librephotos".port;
|
||||
MAPBOX_API_KEY = "SOME_KEY";
|
||||
WEB_CONCURRENCY = "24";
|
||||
DEBUG = "0";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
@ -1,25 +1,34 @@
|
||||
{ config, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htlid.giugl.io";
|
||||
in
|
||||
{
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
lidarr = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations."/" = {
|
||||
port = 8686;
|
||||
allowLan = true;
|
||||
allowWAN = false;
|
||||
allow = [ config.architect.networks."tailscale".net ];
|
||||
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,45 +1,85 @@
|
||||
{ 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}";
|
||||
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}" ];
|
||||
|
||||
listeners = [{
|
||||
port = 8008;
|
||||
bind_addresses = [ "127.0.0.1" ];
|
||||
type = "http";
|
||||
tls = false;
|
||||
x_forwarded = true;
|
||||
resources = [{
|
||||
names = [ "client" "federation" ];
|
||||
compress = false;
|
||||
}];
|
||||
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 = 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_address = "::1";
|
||||
type = "http";
|
||||
tls = false;
|
||||
x_forwarded = true;
|
||||
resources = [{
|
||||
names = [ "client" "federation" ];
|
||||
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
|
||||
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
|
||||
''
|
||||
add_header Content-Type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON client}';
|
||||
'';
|
||||
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 ''
|
||||
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 ];
|
||||
}
|
@ -1,83 +1,53 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
{ lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "music.giugl.io";
|
||||
library_path = "/media/Music";
|
||||
beets_config = "/media/beets.conf";
|
||||
in
|
||||
{
|
||||
services.navidrome = {
|
||||
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;
|
||||
|
||||
settings = {
|
||||
MusicFolder = library_path;
|
||||
LastFM.enable = true;
|
||||
LastFM.ApiKey = "5cef5cb5f9d31326b97d0f929ca9cf20";
|
||||
LastFM.Secret = "d1296896126f4caae47407aecf080b25";
|
||||
Spotify.ID = "3900c029b4f34f3fb61d554dda64794d";
|
||||
Spotify.Secret = "d931ce5575a9401aa5ff8d37558cca0a";
|
||||
EnableGravatar = true;
|
||||
LogLevel = "WARN";
|
||||
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";
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations."/" = {
|
||||
port = 4533;
|
||||
allowLan = true;
|
||||
allowWAN = true;
|
||||
# allow = [ config.architect.networks."tailscale".net ];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
"beets-update" = {
|
||||
enable = true;
|
||||
# requires = [ "remove-badmp3.service" "remove-badflac.service" ];
|
||||
before = [ "beets-import.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.beets}/bin/beet -c ${beets_config} update";
|
||||
};
|
||||
};
|
||||
|
||||
"beets-import" = {
|
||||
enable = true;
|
||||
path = [ pkgs.imagemagick ];
|
||||
requires = [ "beets-update.service" ];
|
||||
after = [ "beets-update.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart =
|
||||
"${pkgs.beets}/bin/beet -c ${beets_config} import --flat -q ${library_path}";
|
||||
};
|
||||
startAt = "weekly";
|
||||
};
|
||||
};
|
||||
|
||||
# "remove-badmp3" = {
|
||||
# enable = true;
|
||||
# before = [ "beets-import.service" "beets-update.service" ];
|
||||
# serviceConfig = {
|
||||
# Type = "oneshot";
|
||||
# ExecStart = ''
|
||||
# ${pkgs.findutils}/bin/find ${library_path} -name "*.mp3" -type f -exec ${pkgs.bash}/bin/sh -c '${pkgs.mp3val}/bin/mp3val "{}" | grep -Pi error 1>/dev/null && ${pkgs.busybox}/bin/rm "{}"' \;
|
||||
# '';
|
||||
# };
|
||||
# };
|
||||
|
||||
# "remove-badflac" = {
|
||||
# enable = true;
|
||||
# before = [ "beets-import.service" "beets-update.service" ];
|
||||
# serviceConfig = {
|
||||
# Type = "oneshot";
|
||||
# ExecStart = ''
|
||||
# ${pkgs.findutils}/bin/find ${library_path} -name "*.flac" -type f -exec ${pkgs.bash}/bin/sh -c '${pkgs.flac}/bin/flac -st "{}" || ${pkgs.busybox}/bin/rm "{}"' \;
|
||||
# '';
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
networking.extraHosts = ''
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups.media.members = [ "navidrome" ];
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "monitor.giugl.io";
|
||||
in
|
||||
{
|
||||
services.netdata = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.netdata;
|
||||
config = {
|
||||
db.mode = "dbengine";
|
||||
};
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = with config.architect.networks; {
|
||||
dnsInterfaces = [ "tailscale" "lan" ];
|
||||
|
||||
locations."/" = {
|
||||
port = 19999;
|
||||
allowLan = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
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}
|
||||
'';
|
||||
}
|
@ -1,24 +1,33 @@
|
||||
{ config, ... }:
|
||||
{ lib, ... }:
|
||||
|
||||
let
|
||||
domain = "htnzb.giugl.io";
|
||||
in
|
||||
{
|
||||
services.nzbget = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
nzbget = {
|
||||
enable = true;
|
||||
group = "media";
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = with config.architect.networks; {
|
||||
dnsInterfaces = [ "tailscale" "lan" ];
|
||||
|
||||
locations."/" = {
|
||||
port = 6789;
|
||||
allowLan = true;
|
||||
|
||||
allow = [ tailscale.net ];
|
||||
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,50 +0,0 @@
|
||||
{ lib }:
|
||||
|
||||
{
|
||||
openresty_oidc_block =
|
||||
{ access_role ? "", whitelisted_ips ? [ ] }: ''
|
||||
|
||||
'';
|
||||
# access_by_lua_block {
|
||||
# local opts = {
|
||||
# discovery = "https://auth.giugl.io/realms/master/.well-known/openid-configuration",
|
||||
# client_id = "nginx",
|
||||
# client_secret = "9C6BYxPhTbrRS4DIwd3Smk7e11ABmnt8",
|
||||
# logout_path = "/logout",
|
||||
# redirect_after_logout_uri = "/",
|
||||
# redirect_uri = "/redirect_uri",
|
||||
# keepalive = "yes",
|
||||
# accept_none_alg = true,
|
||||
# revoke_tokens_on_logout = true,
|
||||
# -- access token valid for a day
|
||||
# access_token_expires_in = 86400
|
||||
# }
|
||||
|
||||
# ${lib.optionalString (whitelisted_ips != []) ''
|
||||
# local whitelist = {${lib.strings.concatMapStringsSep "," (x: "\"${x}\"") whitelisted_ips}}
|
||||
|
||||
# if is_ip_whitelisted(ngx.var.remote_addr, whitelist) then
|
||||
# return
|
||||
# end
|
||||
# ''}
|
||||
|
||||
# -- call introspect for OAuth 2.0 Bearer Access Token validation
|
||||
# local res, err = require("resty.openidc").authenticate(opts)
|
||||
|
||||
# if err then
|
||||
# ngx.status = 403
|
||||
# ngx.say(err)
|
||||
# ngx.exit(ngx.HTTP_FORBIDDEN)
|
||||
# end
|
||||
|
||||
# ${lib.optionalString (access_role != "") ''
|
||||
# if not check_role(res, "${access_role}") then
|
||||
# ngx.status = 401
|
||||
# ngx.header.content_type = 'text/html';
|
||||
# ngx.say("You are not authorized to access this page. Please contact Er Pepotto.")
|
||||
# ngx.exit(ngx.HTTP_UNAUTHORIZED)
|
||||
# end
|
||||
# ''}
|
||||
# }
|
||||
# '';
|
||||
}
|
@ -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" ];
|
||||
};
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "photos.giugl.io";
|
||||
in
|
||||
{
|
||||
services.photoprism = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.photoprism;
|
||||
originalsPath = "/var/lib/private/photoprism/originals";
|
||||
address = "0.0.0.0";
|
||||
settings = {
|
||||
PHOTOPRISM_DEFAULT_LOCALE = "en";
|
||||
PHOTOPRISM_DATABASE_DRIVER = "mysql";
|
||||
PHOTOPRISM_DATABASE_NAME = "photoprism";
|
||||
PHOTOPRISM_DATABASE_SERVER = "/run/mysqld/mysqld.sock";
|
||||
PHOTOPRISM_DATABASE_USER = "photoprism";
|
||||
PHOTOPRISM_SITE_URL = "https://${domain}";
|
||||
PHOTOPRISM_SITE_TITLE = "PePrism";
|
||||
PHOTOPRISM_FFMPEG_ENCODER = "nvidia";
|
||||
PHOTOPRISM_INIT = "tensorflow";
|
||||
NVIDIA_VISIBLE_DEVICES = "all";
|
||||
NVIDIA_DRIVER_CAPABILITIES = "compute,video,utility";
|
||||
PHOTOPRISM_FFMPEG_BIN = "${pkgs.ffmpeg}/bin/ffmpeg";
|
||||
};
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "tailscale" "lan" ];
|
||||
locations."/" = {
|
||||
port = config.services.photoprism.port;
|
||||
allowLan = true;
|
||||
allow = [ config.architect.networks."tailscale".net ];
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
}
|
@ -1,79 +1,91 @@
|
||||
{ pkgs, config, ... }:
|
||||
{ pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "media.giugl.io";
|
||||
port = 32400;
|
||||
in
|
||||
{
|
||||
architect.firewall = {
|
||||
openTCP = [ 32400 3005 8324 32469 ];
|
||||
openUDP = [ 1900 5353 32410 32412 32413 32414 ];
|
||||
};
|
||||
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services.plex = {
|
||||
enable = true;
|
||||
package = pkgs.unstablePkgs.plex;
|
||||
package = pkgs.unstable.plex;
|
||||
dataDir = "/plex";
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = with config.architect.networks; {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit port;
|
||||
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;
|
||||
|
||||
proxyWebsockets = true;
|
||||
allowLan = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
extraConfig = ''
|
||||
#Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause
|
||||
send_timeout 100m;
|
||||
#Some players don't reopen a socket and playback stops totally instead of resuming after an extended pause
|
||||
send_timeout 100m;
|
||||
|
||||
# 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;
|
||||
# Why this is important: https://blog.cloudflare.com/ocsp-stapling-how-cloudflare-just-made-ssl-30/
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
|
||||
# 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]\.";
|
||||
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';
|
||||
|
||||
# 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;
|
||||
# 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 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;
|
||||
# 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]\.";
|
||||
|
||||
# Buffering off send to the client as soon as the data is received from Plex.
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
# 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;
|
||||
|
||||
add_header 'Content-Security-Policy' 'upgrade-insecure-requests';
|
||||
'';
|
||||
};
|
||||
# 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;
|
||||
};
|
||||
}
|
@ -4,25 +4,19 @@ let
|
||||
domain = "xmpp.giugl.io";
|
||||
conference_domain = "conference.${domain}";
|
||||
upload_domain = "uploads.${domain}";
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
architect.firewall = {
|
||||
openTCP = [ 5222 5269 ];
|
||||
};
|
||||
|
||||
network = import ./network.nix;
|
||||
in {
|
||||
services = {
|
||||
prosody = {
|
||||
enable = true;
|
||||
virtualHosts.${domain} = {
|
||||
inherit domain;
|
||||
|
||||
enabled = true;
|
||||
ssl.key = "${config.security.acme.certs.${domain}.directory}/key.pem";
|
||||
ssl.cert =
|
||||
"${config.security.acme.certs.${domain}.directory}/fullchain.pem";
|
||||
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; }];
|
||||
@ -32,24 +26,16 @@ in
|
||||
#httpInterfaces = [ "wg0" ];
|
||||
#httpsInterfaces = [ "wg0" ];
|
||||
};
|
||||
|
||||
nginx.virtualHosts = {
|
||||
"${domain}" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
};
|
||||
# "${conference_domain}".enableACME = true;
|
||||
# "${upload_domain}".enableACME = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."${domain}".enableACME = true;
|
||||
#services.nginx.virtualHosts."${conference_domain}".enableACME = true;
|
||||
#services.nginx.virtualHosts."${upload_domain}".enableACME = true;
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
'';
|
||||
${network.architect-lan} ${domain}
|
||||
${network.architect-wg} ${domain}
|
||||
'';
|
||||
|
||||
users.groups = {
|
||||
acme.members = [ "prosody" ];
|
||||
nginx.members = [ "prosody" ];
|
||||
};
|
||||
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" ];
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "reddit.giugl.io";
|
||||
in
|
||||
{
|
||||
systemd.services.redlib.environment = {
|
||||
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";
|
||||
};
|
||||
|
||||
services.redlib = {
|
||||
enable = true;
|
||||
port = 9090;
|
||||
package = pkgs.unstablePkgs.redlib;
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations."/" = {
|
||||
port = config.services.redlib.port;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
domain = "runas.rocks";
|
||||
runas_root = "/var/lib/runas.rocks/dist";
|
||||
service_name = "runas.rocks-pull";
|
||||
mkStartScript = name: pkgs.writeShellScript "${name}.sh" ''
|
||||
set -euo pipefail
|
||||
cd ${runas_root}
|
||||
git pull origin main --rebase
|
||||
'';
|
||||
|
||||
utilities = import ./utilities.nix { inherit lib config; };
|
||||
inherit (utilities) architectInterfaceAddress;
|
||||
in
|
||||
{
|
||||
services.nginx.virtualHosts.${domain} = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
|
||||
locations."/".root = runas_root;
|
||||
|
||||
locations."/.git" = { return = "404"; };
|
||||
};
|
||||
|
||||
systemd = {
|
||||
services.${service_name} = {
|
||||
path = [ pkgs.git ];
|
||||
enable = true;
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = mkStartScript "${service_name}";
|
||||
};
|
||||
};
|
||||
timers.${service_name} = {
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnCalendar = "hourly";
|
||||
Unit = "${service_name}.service";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
networking.extraHosts = ''
|
||||
${architectInterfaceAddress "lan"} ${domain}
|
||||
${architectInterfaceAddress "tailscale"} ${domain}
|
||||
'';
|
||||
}
|
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,206 +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 ];
|
||||
|
||||
hardware = {
|
||||
pulseaudio.enable = false;
|
||||
};
|
||||
|
||||
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 = {
|
||||
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,43 +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}"; };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
{ config, ... }:
|
||||
|
||||
let
|
||||
domain = "tesla.giugl.io";
|
||||
teslamatePort = 11234;
|
||||
grafanaPort = 11334;
|
||||
allowLan = true;
|
||||
allowWAN = false;
|
||||
in
|
||||
{
|
||||
age.secrets.teslamate = {
|
||||
file = ../../secrets/teslamate.age;
|
||||
owner = "teslamate";
|
||||
};
|
||||
|
||||
architect.vhost.${domain} = with config.architect.networks; {
|
||||
dnsInterfaces = [ "lan" "tailscale" ];
|
||||
locations = {
|
||||
"/" = {
|
||||
inherit allowLan allowWAN;
|
||||
port = teslamatePort;
|
||||
proxyWebsockets = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
};
|
||||
"/live/websocket" = {
|
||||
inherit allowLan allowWAN;
|
||||
port = teslamatePort;
|
||||
proxyWebsockets = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
};
|
||||
"/grafana" = {
|
||||
inherit allowLan allowWAN;
|
||||
port = grafanaPort;
|
||||
proxyWebsockets = true;
|
||||
allow = [
|
||||
tailscale.net
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.teslamate = {
|
||||
enable = true;
|
||||
port = teslamatePort;
|
||||
|
||||
listenAddress = "127.0.0.1";
|
||||
secretsFile = config.age.secrets.teslamate.path;
|
||||
virtualHost = domain;
|
||||
postgres.enable_server = true;
|
||||
grafana = {
|
||||
enable = true;
|
||||
port = grafanaPort;
|
||||
listenAddress = "127.0.0.1";
|
||||
urlPath = "/grafana";
|
||||
};
|
||||
mqtt = {
|
||||
enable = true;
|
||||
};
|
||||
};
|
||||
}
|
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;
|
||||
};
|
||||
}
|
79
lib/host.nix
79
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);
|
||||
add_imports = imports;
|
||||
in
|
||||
nixpkgs.lib.nixosSystem {
|
||||
inherit system pkgs;
|
||||
mkHost = { name, users, roles ? [], imports ? [] }:
|
||||
let
|
||||
system = "x86_64-linux";
|
||||
|
||||
modules = [
|
||||
{
|
||||
imports = users_mod ++
|
||||
roles_mod ++
|
||||
add_imports ++ [
|
||||
(mkSysRole "common")
|
||||
(mkSysRole "acme")
|
||||
(mkUser { name = "root"; roles = [ ]; })
|
||||
../modules
|
||||
];
|
||||
mkRole = role : import (../roles + "/${role}.nix");
|
||||
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
};
|
||||
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;
|
||||
|
||||
system.stateVersion = "25.05";
|
||||
}
|
||||
modules = [
|
||||
{
|
||||
imports = users_mod ++ roles_mod ++ add_imports;
|
||||
nixpkgs = {
|
||||
pkgs = pkgs;
|
||||
};
|
||||
|
||||
home-manager.nixosModules.home-manager
|
||||
../hosts/${name}/default.nix
|
||||
pkgs.nixosModules.cachixConfig
|
||||
];
|
||||
};
|
||||
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
|
||||
];
|
||||
};
|
||||
}
|
||||
|
63
lib/user.nix
63
lib/user.nix
@ -1,55 +1,36 @@
|
||||
{ pkgs
|
||||
, stdenv
|
||||
, home-manager
|
||||
, mkHomeRole
|
||||
, ...
|
||||
}:
|
||||
{ pkgs, unstable, ... }:
|
||||
|
||||
{
|
||||
mkUser = { name, roles ? [ ] }:
|
||||
let
|
||||
roles_mod = (map (r: mkHomeRole r) roles);
|
||||
in
|
||||
{
|
||||
fileSystems."/home/${name}/Downloads" = pkgs.lib.mkIf stdenv.isLinux {
|
||||
mkRole = role: import (../roles/home + "/${role}.nix");
|
||||
roles_mod = (map (r: mkRole r) roles);
|
||||
in {
|
||||
users.groups.plugdev = { };
|
||||
|
||||
fileSystems."/home/${name}/Downloads" = {
|
||||
device = "tmpfs";
|
||||
fsType = "tmpfs";
|
||||
options = [ "size=3G" ];
|
||||
};
|
||||
|
||||
users = {
|
||||
users.${name} = {
|
||||
isNormalUser = name != "root";
|
||||
extraGroups = [ "wheel" "plugdev" ];
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
users.users.${name} = {
|
||||
isNormalUser = true;
|
||||
shell = pkgs.zsh;
|
||||
extraGroups = [ "wheel" "plugdev" ];
|
||||
};
|
||||
|
||||
programs.zsh.enable = true;
|
||||
home-manager.users.${name}.imports = [ (mkRole "common") ]
|
||||
++ roles_mod;
|
||||
};
|
||||
|
||||
home-manager.users.${name}.imports = [
|
||||
(mkHomeRole "common")
|
||||
(mkHomeRole "zsh")
|
||||
(mkHomeRole "aichat")
|
||||
] ++ roles_mod;
|
||||
};
|
||||
mkHMUser = { name, roles ? [] }:
|
||||
let
|
||||
mkRole = role: import (../roles/home + "/${role}.nix");
|
||||
in{
|
||||
home-manager.users.${name}.imports = [ (mkRole "common") ]
|
||||
++ roles_mod;
|
||||
};
|
||||
|
||||
mkHMUser = { name, roles ? [ ] }:
|
||||
let
|
||||
roles_mod = (map (r: mkHomeRole r) roles);
|
||||
in
|
||||
home-manager.lib.homeManagerConfiguration {
|
||||
inherit pkgs;
|
||||
modules = [
|
||||
{
|
||||
home = {
|
||||
username = name;
|
||||
homeDirectory =
|
||||
if stdenv.isLinux then "/home/${name}" else "/Users/${name}";
|
||||
};
|
||||
}
|
||||
(mkHomeRole "common")
|
||||
(mkHomeRole "aichat")
|
||||
] ++ roles_mod;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
{ ... }:
|
||||
|
||||
{
|
||||
mkSysRole = role: import (../roles/${role}.nix);
|
||||
mkHomeRole = role: import (../roles/home/${role}.nix);
|
||||
}
|
@ -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,20 +0,0 @@
|
||||
{ ... }: {
|
||||
imports = [
|
||||
./bazarr
|
||||
./gitea
|
||||
./homeassistant
|
||||
./immich
|
||||
./jellyfin
|
||||
./jellyseer
|
||||
./lidarr
|
||||
./llm
|
||||
./minio
|
||||
./navidrome
|
||||
./nzbget
|
||||
./prowlarr
|
||||
./radarr
|
||||
./redlib
|
||||
./sonarr
|
||||
./headscale
|
||||
];
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
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,69 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.homeassistant;
|
||||
in
|
||||
{
|
||||
options.pepe.services.homeassistant = with lib; {
|
||||
enable = mkEnableOption "Enable Home Assistant";
|
||||
package = mkPackageOption pkgs "home-assistant" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
extraComponents = mkOption {
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
description = "Additional components to enable in Home Assistant";
|
||||
};
|
||||
extraPackages = mkOption {
|
||||
type = types.functionTo (types.listOf types.package);
|
||||
default = _: [];
|
||||
description = "Additional Python packages for Home Assistant";
|
||||
};
|
||||
config = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Home Assistant configuration";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.home-assistant = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
extraComponents = cfg.extraComponents;
|
||||
extraPackages = cfg.extraPackages;
|
||||
config = cfg.config;
|
||||
};
|
||||
|
||||
services.mosquitto = {
|
||||
enable = true;
|
||||
listeners = [
|
||||
{
|
||||
address = "127.0.0.1";
|
||||
acl = [ "pattern readwrite #" ];
|
||||
omitPasswordAuth = true;
|
||||
settings.allow_anonymous = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.go2rtc = {
|
||||
enable = true;
|
||||
settings.api.listen = "127.0.0.1:1984";
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = {
|
||||
locations."/" = {
|
||||
port = config.services.home-assistant.config.http.server_port or 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,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,110 +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
|
||||
uiPackage = mkPackageOption pkgs "open-webui" { };
|
||||
tikaPackage = mkPackageOption pkgs "tika" { }; # Tika for document processing with 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.uiPackage cfg.frontend.tikaPackage ] else [ ]);
|
||||
}
|
||||
|
||||
# Backend Ollama Service Configuration
|
||||
(mkIf cfg.enable {
|
||||
services.ollama = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
acceleration = cfg.acceleration;
|
||||
environmentVariables = cfg.environmentVariables;
|
||||
};
|
||||
|
||||
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};
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
|
||||
# Frontend Open WebUI and Tika Service Configuration
|
||||
(mkIf (cfg.enable && cfg.frontend.enable) {
|
||||
services.open-webui = {
|
||||
enable = true;
|
||||
package = cfg.frontend.uiPackage;
|
||||
};
|
||||
|
||||
services.tika = {
|
||||
enable = true;
|
||||
package = cfg.frontend.tikaPackage;
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
@ -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,84 +0,0 @@
|
||||
{ config, lib, pkgs, ... }:
|
||||
|
||||
let
|
||||
inherit (lib) mkIf;
|
||||
|
||||
cfg = config.pepe.services.navidrome;
|
||||
in
|
||||
{
|
||||
options.pepe.services.navidrome = with lib; {
|
||||
enable = mkEnableOption "Enable navidrome";
|
||||
package = mkPackageOption pkgs "navidrome" { };
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
};
|
||||
musicFolder = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/Music";
|
||||
description = "Path to the music library";
|
||||
};
|
||||
beetsConfig = mkOption {
|
||||
type = types.str;
|
||||
default = "/media/beets.conf";
|
||||
description = "Path to the beets configuration file";
|
||||
};
|
||||
settings = mkOption {
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
description = "Additional settings for Navidrome";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.navidrome = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
settings = {
|
||||
MusicFolder = cfg.musicFolder;
|
||||
LastFM.enable = true;
|
||||
LastFM.ApiKey = "5cef5cb5f9d31326b97d0f929ca9cf20";
|
||||
LastFM.Secret = "d1296896126f4caae47407aecf080b25";
|
||||
Spotify.ID = "3900c029b4f34f3fb61d554dda64794d";
|
||||
Spotify.Secret = "d931ce5575a9401aa5ff8d37558cca0a";
|
||||
EnableGravatar = true;
|
||||
LogLevel = "WARN";
|
||||
} // cfg.settings;
|
||||
};
|
||||
|
||||
pepe.core.vhost.hosts.${cfg.domain} = with config.pepe.core.network; {
|
||||
dnsInterfaces = [ interfaceTypes.lan interfaceTypes.vpn ];
|
||||
locations."/" = {
|
||||
port = 4533;
|
||||
allowLAN = true;
|
||||
allowVPN = true;
|
||||
allowWAN = true;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services = {
|
||||
"beets-update" = {
|
||||
enable = true;
|
||||
before = [ "beets-import.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.beets}/bin/beet -c ${cfg.beetsConfig} update";
|
||||
};
|
||||
};
|
||||
|
||||
"beets-import" = {
|
||||
enable = true;
|
||||
path = [ pkgs.imagemagick ];
|
||||
requires = [ "beets-update.service" ];
|
||||
after = [ "beets-update.service" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${pkgs.beets}/bin/beet -c ${cfg.beetsConfig} 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,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,204 +0,0 @@
|
||||
---
|
||||
model: ollama:pino-coder
|
||||
temperature: 0
|
||||
---
|
||||
|
||||
You are a panel of three expert developers specializing in commit message generation:
|
||||
|
||||
- A (Version Control Specialist): Expert in Git workflows and commit conventions
|
||||
- B (Code Review Expert): Specializes in code change analysis and impact assessment
|
||||
- C (Technical Writer): Focuses on clarity, consistency, and documentation standards
|
||||
|
||||
Commit Convention Format:
|
||||
<type>(<scope>): <description>
|
||||
|
||||
[body description]
|
||||
|
||||
|
||||
Types:
|
||||
- feat: New feature
|
||||
- fix: Bug fix
|
||||
- docs: Documentation changes
|
||||
- style: Code style changes (non-functional)
|
||||
- refactor: Code restructuring (non-functional)
|
||||
- test: Test-related changes
|
||||
- chore: Build process or tool changes
|
||||
- perf: Performance improvements
|
||||
|
||||
Panel Analysis Process:
|
||||
|
||||
1. Initial Assessment:
|
||||
- Alex: Analyzes commit convention compliance and change scope
|
||||
- Blake: Reviews technical changes and their impact
|
||||
- Casey: Evaluates message clarity and completeness
|
||||
|
||||
2. Message Components:
|
||||
- Type Selection: Panel agrees on the most appropriate type
|
||||
- Scope Definition: Identify affected components/systems
|
||||
- Description: Craft clear, concise summary, bullet points only
|
||||
|
||||
3. Quality Criteria:
|
||||
- Conventional commits compliance
|
||||
- Technical accuracy
|
||||
- Clear and concise language
|
||||
- Meaningful context
|
||||
- Future maintainer consideration
|
||||
- Breaking change identification
|
||||
|
||||
Guidelines:
|
||||
- Exclude trivial changes (imports, formatting)
|
||||
- Focus on functional and behavioral changes
|
||||
- Include breaking changes prominently
|
||||
- Reference relevant issue numbers
|
||||
- Keep first line under 72 characters
|
||||
- Use imperative mood ("add" not "added")
|
||||
|
||||
### INPUT:
|
||||
|
||||
diff --git a/src/utils/date-formatter.js b/src/utils/date-formatter.js
|
||||
index 2345678..3456789 100644
|
||||
--- a/src/utils/date-formatter.js
|
||||
+++ b/src/utils/date-formatter.js
|
||||
@@ -5,7 +5,7 @@ export function formatDate(date) {
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
- return `$${year}-$${month}-$${day}`;
|
||||
+ return `$${year}/$${month}/$${day}`;
|
||||
}
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
fix(date-formatter): modified `formatDate()` to use '/' instead of '-' as the separator
|
||||
|
||||
### INPUT:
|
||||
|
||||
diff --git a/src/app.js b/src/app.js
|
||||
index 83d2e7a..b6a1c3f 100644
|
||||
--- a/src/app.js
|
||||
+++ b/src/app.js
|
||||
@@ -10,6 +10,10 @@ function initialize() {
|
||||
setupEventListeners();
|
||||
}
|
||||
|
||||
+// TODO: add other listeners
|
||||
+// https://github.com/user/project/issue/123
|
||||
+function setupEventListeners() {
|
||||
+ document.getElementById('submit').addEventListener('click', handleSubmit);
|
||||
+ document.getElementById('reset').addEventListener('click', handleReset);
|
||||
+}
|
||||
+
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
const data = new FormData(event.target);
|
||||
@@ -20,6 +24,10 @@ function handleSubmit(event) {
|
||||
|
||||
console.log('Form submitted:', data);
|
||||
}
|
||||
|
||||
+function handleReset(event) {
|
||||
+ event.preventDefault();
|
||||
+ event.target.form.reset();
|
||||
+ console.log('Form reset');
|
||||
}
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
feat(app): implement form event listeners
|
||||
|
||||
- Added `setupEventListeners()` to handle form interactions
|
||||
- Implemented `handleReset()` for form reset functionality
|
||||
- Added event listeners for submit and reset buttons
|
||||
- Track TODO comment for future listener additions (https://github.com/user/project/issue/123)
|
||||
|
||||
### INPUT:
|
||||
|
||||
diff --git a/pkg/database/client.go b/pkg/database/client.go
|
||||
index 003740f..6fc4861 100644
|
||||
--- a/pkg/database/client.go
|
||||
+++ b/pkg/database/client.go
|
||||
@@ -24,9 +24,12 @@ var ErrNilDatabaseClient = errors.New("database client is nil after setup")
|
||||
|
||||
// InitDB initializes the database with the given application name and optional dbpath for SQLite.
|
||||
func InitDB(appName string, dbpath ...string) error {
|
||||
- cfg := config.New()
|
||||
+ var (
|
||||
+ psqlReadReplica string
|
||||
+ err error
|
||||
+ )
|
||||
|
||||
- var err error
|
||||
+ cfg := config.New()
|
||||
|
||||
// Set up a new logger with your required configuration.
|
||||
newLogger := logger.New(
|
||||
@@ -38,9 +41,8 @@ func InitDB(appName string, dbpath ...string) error {
|
||||
},
|
||||
)
|
||||
|
||||
- // Load PostgreSQL configurations
|
||||
- var psqlReadReplica string
|
||||
psqlSource, err := cfg.Load(config.PSQL.String())
|
||||
+
|
||||
if err != nil {
|
||||
log.Println("PSQL not set, using SQLite instead.")
|
||||
} else {
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
style(database/client): group together `psqlReadReplica` and `err` in function's prologue
|
||||
|
||||
### INPUT:
|
||||
|
||||
diff --git a/pkg/khttp/client.go b/pkg/khttp/client.go
|
||||
index a53064c..3aff938 100644
|
||||
--- a/pkg/khttp/client.go
|
||||
+++ b/pkg/khttp/client.go
|
||||
@@ -11,14 +11,17 @@ import (
|
||||
"github.pie.apple.com/kerosene/Core/structs"
|
||||
)
|
||||
|
||||
+// TODO: https://github.pie.apple.com/Kerosene/Core/issues/43
|
||||
+// feat: Centralise and remove over use of os.Environment
|
||||
const (
|
||||
- // Environment variables and file names.
|
||||
authFilesDirEnvVar = "WHISPER_AUTH_FILES_DIR"
|
||||
keyName = "decrypted_key.pem"
|
||||
certName = "cert.pem"
|
||||
)
|
||||
|
||||
// Error for missing environment variable.
|
||||
+// TODO: refactor: move errors into centralized errors.go files
|
||||
+// https://github.pie.apple.com/Kerosene/Core/issues/57
|
||||
var errMissingEnvironmentVariable = fmt.Errorf("%s environment variable is not set", authFilesDirEnvVar)
|
||||
|
||||
// AuthConfig holds authentication file paths.
|
||||
@@ -31,9 +34,11 @@ type AuthConfig struct {
|
||||
// NewAuthConfig creates an AuthConfig from environment variables.
|
||||
func NewAuthConfig() (*AuthConfig, error) {
|
||||
dir := os.Getenv(authFilesDirEnvVar)
|
||||
+
|
||||
if dir == "" {
|
||||
return nil, errMissingEnvironmentVariable
|
||||
}
|
||||
+
|
||||
return &AuthConfig{
|
||||
Dir: dir,
|
||||
CertFile: filepath.Join(dir, certName),
|
||||
@@ -211,7 +216,7 @@ func setupMTLSOnlyTransport(certData string, keyData string) (*http.Transport, e
|
||||
|
||||
// Make scheme and Auth Type separate and load from DB.
|
||||
func parseProxyURL(scheme string, routing structs.Routing) (*url.URL, error) {
|
||||
- return url.Parse(fmt.Sprintf("%s://%s:%s", scheme, routing.Proxy, routing.Port))
|
||||
+ return url.Parse(fmt.Sprintf("%s://%s:%d", scheme, routing.Proxy, routing.Port))
|
||||
}
|
||||
|
||||
// loadX509KeyPair loads an X509 key pair from the specified cert and key files.
|
||||
|
||||
### OUTPUT:
|
||||
|
||||
fix/refactor(khttp/client): use correct format specifier for and add TODOs
|
||||
|
||||
- Parsed proxy URL using `fmt.Sprintf()` with correct format specifier for port
|
||||
- Added TODOs to centralize errors and remove overuse of `os.Environment` (#43, #57)
|
||||
|
||||
|
@ -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
|
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