Compare commits

...

125 Commits

Author SHA1 Message Date
numbus df3c3d1c08 Update Whiteboard 2026-06-08 12:45:17 +02:00
numbus e98263b100 Update Immich 2026-06-08 12:42:04 +02:00
numbus 0500445003 Update Traefik 2026-06-08 12:40:06 +02:00
numbus ce4fa00b77 Update NixOS 2026-06-08 12:38:50 +02:00
numbus ec9b8f7d55 Update Traefik 2026-05-14 11:48:55 +02:00
numbus 0cc60dcd29 Update Nextcloud, Whiteboard and OnlyOffice 2026-05-14 11:48:03 +02:00
numbus 3b432d8bd4 Update Nextcloud 2026-04-13 09:21:29 +02:00
numbus 19b2459f65 Up the amount of RAM usable by Nextcloud 2026-04-12 15:12:01 +02:00
numbus 76fbcd86db Added screen package 2026-03-25 09:13:09 +01:00
numbus d1e511bfc0 Typo : 1 data disk 2026-03-15 12:34:23 +01:00
numbus 090cb2a7e4 Remove the /mnt/content-0 if more than 2 data disks 2026-03-15 12:30:20 +01:00
numbus c994337e1f Change onlyoffice headers. 2026-03-09 00:35:21 +01:00
numbus f1e24678b9 Remove security option to make Nextcloud onlyoffice work. 2026-03-09 00:28:25 +01:00
Raphaël Numbus dcde9fad01 Changed trusted proxy address. 2026-03-05 22:09:01 +01:00
Raphaël Numbus 3c41c307ee Fixed Nextcloud headers. OnlyOffice now works with Nextcloud. 2026-03-05 22:05:32 +01:00
Raphaël Numbus 7e4ef7b679 Get nextcloud-onlyoffice to work. 2026-03-05 13:04:24 +01:00
Raphaël Numbus 3e927af8f9 Get nextcloud-onlyoffice to work. 2026-03-05 12:58:05 +01:00
Raphaël Numbus 6de5f0cd28 Get gitea to work. 2026-03-05 12:48:25 +01:00
Raphaël Numbus 5394287b3a Home-assistant bug. Get nextcloud-onlyoffice to work. 2026-03-05 12:42:26 +01:00
Raphaël Numbus a4c0c2b051 Fixed home-assistant 400: bad request. Fixed Nextcloud-Quirk failing. Fixed Nextcloud-Onlyoffice mkdir: permission denied. 2026-03-05 09:24:51 +01:00
Raphaël Numbus 7933a3aa57 Added slirp4netns 2026-03-04 21:54:46 +01:00
Raphaël Numbus b5bece34ed Moved coral tpu config to a single file. Added slirp4netns. 2026-03-04 21:22:33 +01:00
Raphaël Numbus 4ab54cae0a Added AdGuard (NEEDS TESTING). Fixed bad indentation for middlewares. Switched from every 2 month periodic scan to every 3 months. 2026-03-03 22:27:24 +01:00
Raphaël Numbus e6907ddd0a Try to fix newuidmap exec not found 2026-03-03 22:08:21 +01:00
Raphaël Numbus 5bf87a1f83 Try to fix newuidmap exec not found 2026-03-03 22:04:58 +01:00
Raphaël Numbus cca3e0d42b Try to fix newuidmap exec not found 2026-03-03 21:46:15 +01:00
Raphaël Numbus f190eb2040 Try to fix newuidmap exec not found 2026-03-03 21:14:06 +01:00
Raphaël Numbus 96d049d486 Try to fix newuidmap exec not found 2026-03-03 20:49:21 +01:00
Raphaël Numbus e09301c493 Try to fix newuidmap exec not found 2026-03-03 16:30:21 +01:00
Raphaël Numbus 3721e41e94 Try to fix newuidmap exec not found 2026-03-03 16:00:48 +01:00
Raphaël Numbus 5b604fac08 Try to fix newuidmap exec not found 2026-03-03 15:43:21 +01:00
Raphaël Numbus e1ddf88300 Try to fix newuidmap exec not found 2026-03-03 15:35:18 +01:00
Raphaël Numbus 07e7084b1b Try to fix Traefik not launching on startup 2026-03-03 15:07:39 +01:00
Raphaël Numbus e46ee8495c Fixed Home-assistant script. 2026-03-03 14:45:23 +01:00
Raphaël Numbus 5cd7f661c0 Fixed passbolt error. 2026-03-03 14:38:25 +01:00
Raphaël Numbus 4d1448189c Added coral TPU driver compile files. Try to fix passbolt YAML error. 2026-03-03 14:23:53 +01:00
Raphaël Numbus 501383bc8d Get periodic scan to work. 2026-03-02 14:45:59 +01:00
Raphaël Numbus 331b686bae Get periodic scan to work. 2026-03-01 19:11:39 +01:00
Raphaël Numbus ca8e8c967e Remove unnecessary input 2026-03-01 17:58:26 +01:00
Raphaël Numbus 487889e3c6 Forgot with lib 2026-03-01 17:58:04 +01:00
Raphaël Numbus de6c80d7b4 Fixed bad option in it-tools, pi-hole and traefik. Added virtualization file. 2026-03-01 17:57:01 +01:00
Raphaël Numbus d384fe1f7c Fix clamAV onacc service. 2026-03-01 17:39:30 +01:00
Raphaël Numbus 65e1ba4ed2 Enable clamAV mail alerts. 2026-03-01 15:06:36 +01:00
Raphaël Numbus 6705329887 Debugging 2026-03-01 15:02:58 +01:00
Raphaël Numbus ae00cb69de Fix nextcloud-quirk systemD service failures. Also get clamAV configuration to work. 2026-03-01 14:49:28 +01:00
Raphaël Numbus 19b2ac7426 Fix nextcloud-quirk systemD service failures. 2026-03-01 14:25:19 +01:00
Raphaël Numbus b12f081bc3 Malformed if statement. 2026-03-01 14:10:38 +01:00
Raphaël Numbus 0ff3ec0e1b Fix nextcloud-quirk systemD service failures. 2026-03-01 14:08:03 +01:00
Raphaël Numbus 45495b114f Fix nextcloud-quirk systemD service failures. 2026-03-01 13:46:18 +01:00
Raphaël Numbus 3bfaf5fa6f Added periodic clamAV scan. Added mail alert on virus detection. 2026-03-01 13:18:35 +01:00
Raphaël Numbus bbe269bfcd Fix systemD service failures. 2026-03-01 12:25:12 +01:00
Raphaël Numbus af4f384797 Fixed syntax error. 2026-03-01 12:10:03 +01:00
Raphaël Numbus 68949dc81b Forgot to add lib. 2026-03-01 12:06:57 +01:00
Raphaël Numbus fad1f51323 Updated clamAV configuration. Fixed nextcloud-quirk typo. 2026-03-01 12:05:30 +01:00
Raphaël Numbus ab886a8a0b Fixed error. 2026-03-01 11:29:26 +01:00
Raphaël Numbus 87b857071d Add records for onlyoffice and whiteboard. 2026-03-01 11:22:16 +01:00
Raphaël Numbus ea86da660d Improved Nextcloud systemD services to avoid failures. Added middleware for carddav/caldav 2026-02-28 22:41:11 +01:00
Raphaël Numbus 41f8298078 Set slirp4netns as default bridge backend. 2026-02-28 18:24:21 +01:00
Raphaël Numbus 60bf000973 Fix missing else. 2026-02-28 15:14:44 +01:00
Raphaël Numbus 384f8cf1ce Fix indentation on multiple services. 2026-02-28 15:11:52 +01:00
Raphaël Numbus d753c34e37 Remove empty space when no domain. 2026-02-28 15:10:02 +01:00
Raphaël Numbus e3e6cac8a3 Fix pi-hole's compose file indentation. 2026-02-28 15:07:22 +01:00
Raphaël Numbus 25820b8578 Typo 2026-02-28 14:59:35 +01:00
Raphaël Numbus 33766aaded Back to normal firewall. Updated systemD container start service. 2026-02-28 14:56:02 +01:00
Raphaël Numbus 98f727c904 Updated firewall rules. 2026-02-28 12:30:14 +01:00
Raphaël Numbus 3558fc5d5c TEST 2026-02-27 17:39:45 +01:00
Raphaël Numbus af86328ec1 Try to get nextcloud to be able to connect to itself. 2026-02-27 17:36:17 +01:00
Raphaël Numbus d7a28f93f1 Forgot pkgs input 2026-02-27 17:25:41 +01:00
Raphaël Numbus d9ee1967fd Added some ClamAV configuration, needs more research. Try to get nextcloud to be able to connect to itself. 2026-02-27 17:24:16 +01:00
Raphaël Numbus 346c2094a9 Removed TimeOut. 2026-02-27 16:06:10 +01:00
Raphaël Numbus 42f463152f Closed firewall port. Fixed middlewares not defined error. 2026-02-27 16:03:59 +01:00
Raphaël Numbus bf753471ba Fixed indentation. Fixed Immich not working correctly behind Traefik (too restrictive headers). 2026-02-27 14:49:25 +01:00
Raphaël Numbus c2b49d7d67 Temporarily open port on firewall. 2026-02-27 12:00:02 +01:00
Raphaël Numbus df165acd1c Removed unnecessary variable 2026-02-27 00:33:01 +01:00
Raphaël Numbus 88bfa9d1ec Added redis persistent storage 2026-02-27 00:13:40 +01:00
Raphaël Numbus d98fd8cebf Added back immich_version variable. 2026-02-26 23:41:42 +01:00
Raphaël Numbus 8bd9f05621 Try to fix immich database not found 2026-02-26 23:40:53 +01:00
Raphaël Numbus acbc0ce72d Fixed bad variable assignment. 2026-02-26 22:26:47 +01:00
Raphaël Numbus 260807ea82 Try to get nextcloud database to initialize properly. 2026-02-26 21:41:43 +01:00
Raphaël Numbus bd91b1e8bf Added port to mysql_host variable nextcloud. 2026-02-26 21:05:43 +01:00
Raphaël Numbus 5220822812 Bunch of bugfixes. Made quirk and permissions fixing scripts more reliable. 2026-02-26 19:45:36 +01:00
Raphaël Numbus 1697952fc4 Bunch of bugfixes. Made quirk and permissions fixing scripts more reliable. 2026-02-26 19:40:31 +01:00
Raphaël Numbus 329355d6c0 Bunch of bugfixes. Made quirk and permissions fixing scripts more reliable. 2026-02-26 19:34:47 +01:00
Raphaël Numbus a98e25abe5 Added back code. 2026-02-26 18:15:38 +01:00
Raphaël Numbus 38154bbd0d Added back code. 2026-02-26 18:13:52 +01:00
Raphaël Numbus 16c1517d95 Removed unnecessary code. Fixed immich env not found. Fixed nextcloud-quirks by quoting .env variable values. 2026-02-26 18:07:57 +01:00
Raphaël Numbus b68deed2e7 Try to break systemD start cycle to work. 2026-02-26 17:31:00 +01:00
Raphaël Numbus 169ead06a4 Get cp to no copy symlinks but actual files. 2026-02-26 17:14:53 +01:00
Raphaël Numbus 6e9ea3fde3 Fixed sudo executable not found. 2026-02-26 16:57:40 +01:00
Raphaël Numbus 30e4291089 Fixed folder not created. 2026-02-26 16:52:50 +01:00
Raphaël Numbus 75c5775369 Bugfixes 2026-02-26 16:40:38 +01:00
Raphaël Numbus f377b0a4ec Fixed Traefik folders situation. Configuration is defined in /etc/traefik and then copied to Traefik'sconfigDir. 2026-02-26 16:28:51 +01:00
Raphaël Numbus 3385f6551f Try to fix Traefik no such file or dir error. 2026-02-26 11:44:32 +01:00
Raphaël Numbus 47db93e61b Removed Traefik rules location modularity (why would anyone change it ?) and fixed Traefik no such file or dir error. 2026-02-26 11:36:31 +01:00
Raphaël Numbus ca3f766975 Try to fix Traefik no such directory 2026-02-26 11:02:02 +01:00
Raphaël Numbus 6e188590ce Added quotes. 2026-02-25 23:23:03 +01:00
Raphaël Numbus d8056117de Bugfixes. 2026-02-25 23:13:27 +01:00
Raphaël Numbus 2a3a2f3832 Fixed startDelay 2026-02-25 22:58:00 +01:00
Raphaël Numbus f95cdf5d26 Fix can't find sudo error. 2026-02-25 22:53:30 +01:00
Raphaël Numbus c4a83ff303 Fix can't find sleep error. 2026-02-25 22:44:00 +01:00
Raphaël Numbus 33a00771e5 Fix can't find sleep error. 2026-02-25 22:39:50 +01:00
Raphaël Numbus 3375f3566e Fix can't find bash error. 2026-02-25 22:32:09 +01:00
Raphaël Numbus 71eb11efe0 Fixed bad path for Traefik configuration files. 2026-02-25 22:14:12 +01:00
Raphaël Numbus a2d8fcb929 Fixed bad path for Traefik configuration files. 2026-02-25 22:03:23 +01:00
Raphaël Numbus 6063267e46 Fixed bad path for Traefik configuration files. 2026-02-25 22:01:03 +01:00
Raphaël Numbus 81da85cd91 Moved Traefik static file to config dir to avoid systemD error. 2026-02-25 21:51:58 +01:00
Raphaël Numbus b673f94b07 Moved Traefik static file to config dir to avoid systemD error. 2026-02-25 21:50:28 +01:00
Raphaël Numbus eaf7aa32ed Moved traefikDynamicConfigDir under config.numbus.services 2026-02-25 21:47:28 +01:00
Raphaël Numbus 555751aa7a Fixed typo service--> services 2026-02-25 21:42:49 +01:00
Raphaël Numbus 9b0c350219 Bugfixes. 2026-02-25 21:39:07 +01:00
Raphaël Numbus 70acd769d6 Wrong variable. 2026-02-25 14:03:40 +01:00
Raphaël Numbus 4a5bef02fc Added config. to `time.timeZone 2026-02-25 14:00:12 +01:00
Raphaël Numbus 966e3288dd Added toString transformation for smtpPort variable. 2026-02-25 13:29:14 +01:00
Raphaël Numbus bc3de08c2b Added top-level config. 2026-02-25 13:13:46 +01:00
Raphaël Numbus dd47755f74 Fixed syntax error. 2026-02-25 13:00:11 +01:00
Raphaël Numbus ae18febf6d Fixed undefined variable : name when addind extraConfig. 2026-02-25 12:18:13 +01:00
Raphaël Numbus 475e37d559 Fixed wrongly defined options. 2026-02-25 12:00:58 +01:00
Raphaël Numbus 10611475a6 Fixed typo type --> types. 2026-02-25 11:56:30 +01:00
Raphaël Numbus e678e08634 Added spindownDisksList list to provide the HDD spindown capable list. Tried to fix mkPodmanService error. 2026-02-25 10:53:24 +01:00
Raphaël Numbus f0e304507b Added missing config attribute. 2026-02-24 22:39:35 +01:00
Raphaël Numbus f301f48227 Fixed typo. 2026-02-24 22:35:44 +01:00
Raphaël Numbus 0d80044380 Updated inputs. 2026-02-24 22:31:50 +01:00
Raphaël Numbus 596c03a800 Added missing variable. 2026-02-24 22:13:14 +01:00
Raphaël Numbus 12150fa8a8 Update flake. 2026-02-24 21:48:12 +01:00
Raphaël Numbus a3906244f0 Update flake. 2026-02-24 21:43:03 +01:00
31 changed files with 830 additions and 273 deletions
+4 -10
View File
@@ -1,17 +1,11 @@
{
description = "Numbus Server - Your Personal Cloud, Simplified";
description = "Numbus Server Module";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.11";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05";
};
outputs = { self, nixpkgs, ... }: {
nixosModules = {
default = { config, pkgs, lib, ... }: {
imports = [
./modules/default.nix
];
};
};
outputs = { self, nixpkgs }: {
nixosModules.numbus = import ./modules/default.nix;
};
}
+6 -12
View File
@@ -4,20 +4,20 @@ with lib;
{
options.numbus = {
owner = {
type = type.str;
owner = mkOption {
type = types.str;
example = "Alex";
default = "Numbus";
description = "The name of the person who owns this server";
};
language = {
type = type.str;
language = mkOption {
type = types.str;
example = "FR";
default = "FR";
description = "The language for this server";
};
locale = {
type = type.str;
locale = mkOption {
type = types.str;
example = "fr_FR";
default = "fr_FR";
description = "The default locale for this server";
@@ -36,12 +36,6 @@ with lib;
description = "The preferred DNS resolver service (pi-hole or adguard) that other services should depend on";
};
};
traefikDynamicConfigDir = mkOption {
type = types.str;
default = "/etc/traefik/rules";
example = "/etc/traefik/rules";
description = "! Choosing a directory outside of /etc/ will break things ! The directory where Traefik's dynamic configuration files will be stored";
};
email = {
administratorEmail = mkOption {
+2
View File
@@ -1,6 +1,7 @@
{ config, ... }:
{
config = {
boot.initrd.systemd.enable = true;
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
@@ -8,4 +9,5 @@
boot.kernel.sysctl = {
"vm.overcommit_memory" = 1;
};
};
}
+2
View File
@@ -1,7 +1,9 @@
{ config, ... }:
{
config = {
hardware.enableRedistributableFirmware = true;
hardware.cpu.intel.updateMicrocode = true;
hardware.cpu.amd.updateMicrocode = true;
};
}
+1
View File
@@ -5,5 +5,6 @@
./boot.nix
./cpu.nix
./disks.nix
./pcie-coral.nix
];
}
+7 -1
View File
@@ -225,6 +225,12 @@ in
example = [ "/dev/disk/by-id/nvme_SAMSUNG_MZVPYEHCO_159Ejz224G0000" "/dev/disk/by-id/ata-San_Disk_159Ejz224G" ];
description = "List of by-id path of devices for boot disks";
};
spindownDisksList = mkOption {
type = types.listOf types.str;
default = [];
example = [ "/dev/disk/by-id/WD_Blue_ATO431_159Ejz224G0000382b" "/dev/disk/by-id/Seagate_Barracuda_159Ejz224G" ];
description = "List of by-id path of devices to spindown when inactive to save power (HDD only)";
};
swapSize = mkOption {
type = types.str;
default = "16G";
@@ -259,7 +265,7 @@ in
services.snapraid = {
enable = true;
contentFiles = [ "/mnt/content-0/snapraid.content" ] ++
contentFiles = (optionals (length cfg.dataDisksList == 1) [ "/mnt/content-0/snapraid.content" ]) ++
(map (i: "/mnt/content-${toString i}/snapraid.content") (range 1 (length cfg.dataDisksList)));
parityFiles = map (i: "/mnt/parity-${toString i}/snapraid.parity") (range 1 (length cfg.parityDisksList));
dataDisks = listToAttrs (imap1 (i: _: nameValuePair "d${toString i}" "/mnt/content-${toString i}") cfg.dataDisksList);
+111
View File
@@ -0,0 +1,111 @@
{ config, lib, pkgs, ... }:
let
cfg = config.numbus.hardware.pcie-coral;
gasket-driver = { stdenv, lib, fetchFromGitHub, kernel }: stdenv.mkDerivation rec {
pname = "gasket";
version = "1.0-18";
src = fetchFromGitHub {
owner = "google";
repo = "gasket-driver";
rev = "97aeba584efd18983850c36dcf7384b0185284b3";
sha256 = "pJwrrI7jVKFts4+bl2xmPIAD01VKFta2SRuElerQnTo=";
};
makeFlags = [
"-C"
"${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
"M=$(PWD)"
];
buildFlags = [ "modules" ];
installFlags = [ "INSTALL_MOD_PATH=${placeholder "out"}" ];
installTargets = [ "modules_install" ];
sourceRoot = "source/src";
hardeningDisable = [ "pic" "format" ];
nativeBuildInputs = kernel.moduleBuildDependencies;
meta = with lib; {
description = "The Coral Gasket Driver allows usage of the Coral EdgeTPU on Linux systems.";
homepage = "https://github.com/google/gasket-driver";
license = licenses.gpl2;
maintainers = [ maintainers.kylehendricks ];
platforms = platforms.linux;
};
};
libedgetpu-pkg = { stdenv, lib, fetchFromGitHub, libusb1, abseil-cpp, flatbuffers, xxd }:
let
flatbuffers_1_12 = flatbuffers.overrideAttrs (oldAttrs: rec {
version = "1.12.0";
NIX_CFLAGS_COMPILE = "-Wno-error=class-memaccess -Wno-error=maybe-uninitialized";
cmakeFlags = (oldAttrs.cmakeFlags or []) ++ ["-DFLATBUFFERS_BUILD_SHAREDLIB=ON"];
NIX_CXXSTDLIB_COMPILE = "-std=c++17";
configureFlags = (oldAttrs.configureFlags or []) ++ ["--enable-shared"];
src = fetchFromGitHub {
owner = "google";
repo = "flatbuffers";
rev = "v${version}";
sha256 = "sha256-L1B5Y/c897Jg9fGwT2J3+vaXsZ+lfXnskp8Gto1p/Tg=";
};
});
in stdenv.mkDerivation rec {
pname = "libedgetpu";
version = "grouper";
src = fetchFromGitHub {
owner = "google-coral";
repo = pname;
rev = "release-${version}";
sha256 = "sha256-73hwItimf88Iqnb40lk4ul/PzmCNIfdt6Afi+xjNiBE=";
};
makeFlags = ["-f" "makefile_build/Makefile" "libedgetpu" ];
buildInputs = [
libusb1
abseil-cpp
flatbuffers_1_12
];
nativeBuildInputs = [
xxd
];
NIX_CXXSTDLIB_COMPILE = "-std=c++17";
TFROOT = "${fetchFromGitHub {
owner = "tensorflow";
repo = "tensorflow";
rev = "v2.7.4";
sha256 = "sha256-liDbUAdaVllB0b74aBeqNxkYNu/zPy7k3CevzRF5dk0=";
}}";
enableParallelBuilding = false;
installPhase = ''
mkdir -p $out/lib
cp out/direct/k8/libedgetpu.so.1.0 $out/lib
ln -s $out/lib/libedgetpu.so.1.0 $out/lib/libedgetpu.so.1
mkdir -p $out/lib/udev/rules.d
cp debian/edgetpu-accelerator.rules $out/lib/udev/rules.d/99-edgetpu-accelerator.rules
'';
};
gasket = config.boot.kernelPackages.callPackage gasket-driver {};
libedgetpu = pkgs.callPackage libedgetpu-pkg {};
in
{
options.numbus.hardware.pcie-coral = lib.mkEnableOption "PCIe Coral TPU support";
config = lib.mkIf cfg {
services.udev.packages = [ libedgetpu ];
users.groups.plugdev = {};
boot.extraModulePackages = [ gasket ];
};
}
+89
View File
@@ -0,0 +1,89 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.numbus.services.clamav;
clamav_notifier = pkgs.writeScript "clamav-notify.sh" ''
#!${pkgs.bash}/bin/bash
# Check if triggered by Real-time event (file exists)
if [ -f /var/lib/clamav/virus_event.env ]; then
source /var/lib/clamav/virus_event.env
rm /var/lib/clamav/virus_event.env
fi
ADMIN_EMAIL="${config.numbus.mail.adminAddress}"
USER_EMAIL="${config.numbus.mail.userAddress}"
OWNER_NAME="${config.numbus.owner}"
if [ -n "$CLAM_VIRUSEVENT_VIRUSNAME" ]; then
# --- Real-time / VirusEvent Mode ---
SUBJECT="Numbus Server Alert: Virus Detected (Real-time)"
# Retrieve logs from clamav-daemon
LOGS=$(journalctl -u clamav-daemon.service -n 50 --no-pager | grep "FOUND")
TECH_BODY="
ClamAV Real-time Alert:
Server owner: $OWNER_NAME
Virus detected: $CLAM_VIRUSEVENT_VIRUSNAME
File: $CLAM_VIRUSEVENT_FILENAME
Logs:
$LOGS
Action taken: Access blocked (OnAccessPrevention).
Please investigate manually.
"
FRIENDLY_BODY="Cher/Chère $OWNER_NAME,
L'antivirus de votre serveur a détecté et bloqué une menace en temps réel.
Fichier : $CLAM_VIRUSEVENT_FILENAME
Votre administrateur a été notifié.
"
else
# --- Scheduled Scan Summary Mode ---
SUBJECT="Numbus Server Alert: Virus Detected during Scheduled Scan"
# Retrieve logs (clamdscan prints FOUND when a virus is detected)
LOGS=$(journalctl -u clamav-periodic-scan.service -n 100 --no-pager | grep "FOUND")
TECH_BODY="
ClamAV Scan Alert:
Server owner: $OWNER_NAME
Viruses detected:
$LOGS
Action taken: Detection only.
Please investigate manually.
"
FRIENDLY_BODY="Cher/Chère $OWNER_NAME,
L'antivirus de votre serveur a détecté une menace potentielle lors de l'analyse périodique.
Votre administrateur a été notifié avec les détails techniques.
Nous vous conseillons d'être prudent avec vos fichiers récents.
"
fi
printf "Subject: [ADMIN] %s\n\n%s" "$SUBJECT" "$TECH_BODY" | /run/wrappers/bin/sendmail -t "$ADMIN_EMAIL"
printf "Subject: [Alerte] Menace détectée sur votre serveur Numbus\n\n%s\n\nMerci de votre confiance,\nL'équipe de support,\nNumbus-Server." "$FRIENDLY_BODY" | /run/wrappers/bin/sendmail -t "$USER_EMAIL"
'';
in
{
config = mkIf cfg.enable {
systemd.services.clamav-virus-notify = {
description = "Email notification for ClamAV virus detection";
serviceConfig = {
Type = "oneshot";
ExecStart = "${clamav_notifier}";
};
};
};
}
+1
View File
@@ -2,6 +2,7 @@
{
imports = [
./clamav.nix
./smart.nix
./systemd.nix
./smtp.nix
+2
View File
@@ -1,6 +1,7 @@
{ config, lib, ... }:
{
config = {
i18n.defaultLocale = "${config.numbus.locale}.UTF-8";
i18n.extraLocaleSettings = {
LC_ADDRESS = "${config.numbus.locale}.UTF-8";
@@ -19,4 +20,5 @@
layout = lib.toLower config.numbus.language;
variant = "";
};
};
}
+3 -1
View File
@@ -1,10 +1,11 @@
{ config, lib, pkgs, ... }:
let
hardDrives = config.numbus.hardware.dataDisksList ++ config.numbus.hardware.parityDisksList;
hardDrives = config.numbus.hardware.spindownDisksList;
in
{
config = {
systemd.services.hd-idle = {
description = "External HD spin down daemon";
wantedBy = [ "multi-user.target" ];
@@ -25,4 +26,5 @@ in
"pcie_aspm=force"
"consoleblank=60"
];
};
}
+3 -1
View File
@@ -1,6 +1,7 @@
{ config, ... }:
{ config, inputs, ... }:
{
config = {
system.autoUpgrade = {
enable = true;
allowReboot = false;
@@ -18,4 +19,5 @@
nix.settings.experimental-features = [ "nix-command" "flakes" ];
nix.settings.auto-optimise-store = true;
};
}
+1 -1
View File
@@ -1,4 +1,4 @@
{ config, ... }:
{ config, pkgs, ... }:
{
users.users.numbus-admin = {
+3 -1
View File
@@ -1,6 +1,7 @@
{ config, ... }:
{ config, pkgs, lib, ... }:
{
config = {
networking.nftables.enable = true;
networking.firewall = {
enable = true;
@@ -8,4 +9,5 @@
allowedTCPPorts = [ 53 80 443 ];
allowedUDPPorts = [ 53 443 ];
};
};
}
+3 -1
View File
@@ -37,6 +37,7 @@ in
};
};
config = {
networking.hostName = "numbus-server";
networking.networkmanager.enable = false;
@@ -46,7 +47,7 @@ in
networking.bridges.br0.interfaces = [ "${cfg.interface}" ];
networking.interfaces."${cfg.interface}".useDHCP = false;
networking.interfaces.br0.useDHCP = false;
networking.nameservers = ${cfg.dnsServers};
networking.nameservers = cfg.dnsServers;
networking.interfaces.br0.ipv4.addresses = [{
address = "${cfg.ipAddress}";
prefixLength = 24;
@@ -55,4 +56,5 @@ in
address = "${cfg.routerIpAddress}";
interface = "br0";
};
};
}
+1
View File
@@ -5,6 +5,7 @@
environment.systemPackages = with pkgs; [
git
screen
ncdu
fastfetch
tpm2-tss
+5 -2
View File
@@ -1,11 +1,14 @@
{ config, pkgs, ...}:
{ pkgs, ... }:
{
virtualisation.podman.enable = true;
virtualisation.podman.defaultNetwork.settings.dns_enabled = true;
virtualisation.containers.containersConf.settings = {
network.default_rootless_network_cmd = "slirp4netns";
};
environment.systemPackages = with pkgs; [
podman
podman-compose
podman-tui
slirp4netns
+51
View File
@@ -0,0 +1,51 @@
{ config, pkgs, lib, ... }:
with lib;
let
# Version tagging
adguardVersion = "latest";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.adguard;
# Container config
name = "adguard";
in
helper.mkPodmanService {
inherit name;
description = "AdGuard, feature-rich DNS service";
pod = "false";
defaultPort = "3000";
scheme = "http";
dependencies = [ "network.target" ];
dataDirEnabled = false;
startDelay = 10;
middlewares = [ "secureHeaders" ];
dirPermissions = [
"100999:100 ${cfg.configDir}"
];
# Compose file good
composeText = ''
services:
adguardhome:
image: adguard/adguardhome:${adguardVersion}
container_name: adguard
hostname: adguard
network_mode: pasta
user: '1000:1000'
ports:
- "3000:3000/tcp"
- "53:53/tcp"
- "53:53/udp"
volumes:
- ${cfg.configDir}/work:/opt/adguardhome/work
- ${cfg.configDir}/config:/opt/adguardhome/conf
cap_add:
- SYS_NICE
security_opt:
- no-new-privileges:true
restart: unless-stopped
'';
}
+91
View File
@@ -0,0 +1,91 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.numbus.services.clamav;
onAccessPaths = lib.mapAttrsToList (n: v: v.dataDir) (lib.filterAttrs (n: v:
v ? enable && v.enable && v ? dataDir && v.dataDir != null && v.dataDir != false
) config.numbus.services);
clamonacc_virus_notifier = pkgs.writeScript "clamonacc_virus_notifier.sh" ''
#!${pkgs.bash}/bin/bash
echo "CLAM_VIRUSEVENT_VIRUSNAME=\"$CLAM_VIRUSEVENT_VIRUSNAME\"" > /var/lib/clamav/virus_event.env
echo "CLAM_VIRUSEVENT_FILENAME=\"$CLAM_VIRUSEVENT_FILENAME\"" >> /var/lib/clamav/virus_event.env
/run/wrappers/bin/sudo /run/current-system/sw/bin/systemctl start clamav-virus-notify.service
'';
in
{
options.numbus.services.clamav = {
enable = mkEnableOption "ClamAV open-source anti-virus software";
};
config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.clamav pkgs.curl ];
system.activationScripts.clamav-quarantine = ''
mkdir -p /quarantine
chown clamav:clamav /quarantine
chmod 440 /quarantine
'';
security.sudo.extraRules = [{
users = [ "clamav" ];
commands = [{
command = "/run/current-system/sw/bin/systemctl start clamav-virus-notify.service";
options = [ "NOPASSWD" ];
}];
}];
services.clamav = {
updater.enable = true;
clamonacc.enable = true;
scanner = {
enable = true;
interval = "*-*-* 04:00:00"; # Everyday at 4am
scanDirectories = [
"/etc"
"/home"
"/var/lib"
"/var/tmp"
"/tmp"
];
};
daemon = {
enable = true;
settings = {
OnAccessPrevention = true;
OnAccessIncludePath = onAccessPaths;
VirusEvent = "${clamonacc_virus_notifier}";
};
};
};
systemd.services.clamav-periodic-scan = mkIf (onAccessPaths != []) {
description = "Periodic ClamAV virus scan";
after = [ "clamav-daemon.service" "clamav-freshclam.service" ];
requires = [ "clamav-daemon.service" ];
wants = [ "clamav-freshclam.service" ];
onFailure = [ "clamav-virus-notify.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.clamav}/bin/clamdscan --multiscan --fdpass --infected --allmatch --move=/quarantine ${lib.escapeShellArgs onAccessPaths}";
Slice = "system-clamav.slice";
};
};
systemd.timers.clamav-periodic-scan = mkIf (onAccessPaths != []) {
description = "Timer for ClamAV periodic scan";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "*-1/3-01 04:00:00";
Persistent = true;
Unit = "clamav-periodic-scan.service";
};
};
};
}
+2
View File
@@ -3,6 +3,7 @@
{
imports = [
# ./adguard.nix
./clamav.nix
./frigate.nix
./gitea.nix
./home-assistant.nix
@@ -12,5 +13,6 @@
./passbolt.nix
./pi-hole.nix
./traefik.nix
./virtualization.nix
];
}
+9 -2
View File
@@ -8,16 +8,23 @@ let
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.frigate;
# Container config
name = "frigate";
in
helper.mkPodmanService {
inherit name;
description = "Frigate, your fully-local NVR (Network Video Recorder)";
name = "frigate";
pod = "home-assistant";
defaultPort = "8971";
scheme = "https";
dependencies = [ "traefik.service" "${config.numbus.services.dns}.service" "home-assistant.service" ];
envFile = "/var/lib/numbus-server/home-assistant/.env";
dependencies = [ "traefik.service" "${config.numbus.services.dns}.service" "home-assistant.service" ];
middlewares = [ "secureHeaders" ];
dirPermissions = [
"1000:100 ${cfg.configDir}"
"1000:100 ${cfg.dataDir}"
];
extraOptions = {
devices = mkOption {
+9 -4
View File
@@ -9,12 +9,13 @@ let
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.gitea;
# Container config
name = "gitea";
in
helper.mkPodmanService {
inherit name;
description = "Gitea, your own self-hosted git platform";
name = "gitea";
pod = "gitea";
defaultPort = "3000";
dataDirEnabled = false;
generatedSecrets = {
@@ -22,8 +23,12 @@ helper.mkPodmanService {
DB_USERNAME = "xkcdpass -n 2 -d -";
DB_PASSWORD = "xkcdpass -n 8 -d -";
};
middlewares = [ "secureHeaders" ];
dirPermissions = [
"100999:users ${cfg.configDir}"
"100999:100 ${cfg.configDir}"
"100999:100 ${cfg.configDir}/data"
"100999:100 ${cfg.configDir}/config"
"100999:100 ${cfg.configDir}/database"
];
composeText = ''
@@ -48,7 +53,7 @@ helper.mkPodmanService {
- GITEA__database__USER=$DB_USERNAME
- GITEA__database__PASSWD=$DB_PASSWORD
- GITEA__server__SSH_PORT=2424
- GITEA__server__ROOT_URL=${cfg.subdomain}.${config.numbus.services.domain}
- GITEA__server__ROOT_URL=https://${cfg.subdomain}.${config.numbus.services.domain}
depends_on:
- gitea-database
security_opt:
+38 -21
View File
@@ -3,25 +3,30 @@
with lib;
let
# Version tagging
homeAssistantVersion = "2026.2.3";
mqttVersion = "2.1-alpine";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.home-assistant;
# Container config
name = "home-assistant";
in
helper.mkPodmanService {
inherit name;
description = "Home Assistant, libre house control and much more";
name = "home-assistant";
pod = "home-assistant";
defaultPort = "8123";
dataDirEnabled = false;
generatedSecrets = {
HOME_ASSISTANT_MQTT_USER = "xkcdpass -n 2 -d -";
HOME_ASSISTANT_MQTT_PASSWORD = "xkcdpass -n 8 -d -";
};
middlewares = [ "secureHeaders" ];
dirPermissions = [
"numbus-admin:users ${cfg.configDir}/home-assistant"
"100999:users ${cfg.configDir}/mqtt"
"1000:100 ${cfg.configDir}"
"1000:100 ${cfg.configDir}/config"
"100999:100 ${cfg.configDir}/mqtt"
];
# Compose file good
@@ -36,7 +41,7 @@ helper.mkPodmanService {
ports:
- "${cfg.port}:8123/tcp"
volumes:
- ${cfg.configDir}/home-assistant:/config
- ${cfg.configDir}/config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
${lib.optionalString (cfg.devices != []) ''
@@ -78,8 +83,8 @@ ${lib.concatStringsSep "\n" (map (d: " - \"${d}\"") cfg.devices)}
};
extraConfig = {
systemd.services."${name}-quirk-1" = {
description = "Podman container quirk 1 : ${name}";
systemd.services."${name}-quirk" = {
description = "Podman container quirk : ${name}";
wantedBy = [ "multi-user.target" ];
after = [ "${name}.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
@@ -92,31 +97,37 @@ ${lib.concatStringsSep "\n" (map (d: " - \"${d}\"") cfg.devices)}
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
if [[ -e /var/lib/numbus-server/${name}/quirk-1.true ]]; then
if [[ -e ${cfg.configDir}/config/configuration.yaml ]]; then
if grep -qF "${config.numbus.networking.ipAddress}/24" ${cfg.configDir}/config/configuration.yaml; then
exit 0
elif grep -qF "use_x_forwarded_for" ${cfg.configDir}/config/configuration.yaml && ! grep -qF "${config.numbus.networking.ipAddress}/24" ${cfg.configDir}/config/configuration.yaml; then
tmp=$(mktemp)
head -n -6 ${cfg.configDir}/config/configuration.yaml > "$tmp"
mv "$tmp" ${cfg.configDir}/config/configuration.yaml
fi
until [[ -e ${cfg.configDir}/home-assistant/configuration.yaml ]]; do
fi
until [[ -e ${cfg.configDir}/config/configuration.yaml ]]; do
sleep 15
done
cat << 'EOF' >> ${cfg.configDir}/home-assistant/configuration.yaml
cat << 'EOF' >> ${cfg.configDir}/config/configuration.yaml
http:
use_x_forwarded_for: true
trusted_proxies: ${config.numbus.networking.ipAddress}/24
trusted_proxies: 10.89.0.0/16
zha:
EOF
systemctl restart ${name}.service
touch /var/lib/numbus-server/${name}/quirk-1.true
'';
};
};
systemd.services."${name}-quirk-2" = {
description = "Podman container quirk 2 : ${name}";
wantedBy = [ "multi-user.target" "${name}.service" ];
after = [ "${name}-secrets.service" ];
before = [ "${name}.service" "${name}-permissions.service" ];
systemd.services."mqtt-quirk" = {
description = "Podman container quirk : Home-assistant MQTT";
wantedBy = [ "multi-user.target" "mqtt.service" ];
after = [ "mqtt-secrets.service" ];
before = [ "mqtt.service" "mqtt-permissions.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
@@ -126,10 +137,17 @@ EOF
RemainAfterExit = true;
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
if [[ -e /var/lib/numbus-server/${name}/quirk-2.true ]]; then
if [[ -e ${cfg.configDir}/mqtt/mosquitto.conf && ${cfg.configDir}/mqtt/password.txt ]]; then
if grep -qF "listener 1883" ${cfg.configDir}/mqtt/mosquitto.conf; then
exit 0
else
rm ${cfg.configDir}/mqtt/mosquitto.conf
rm ${cfg.configDir}/mqtt/password.txt
touch ${cfg.configDir}/mqtt/mosquitto.conf
touch ${cfg.configDir}/mqtt/password.txt
fi
fi
cat << EOF >> ${cfg.configDir}/mqtt/mosquitto.conf
persistence true
persistence_location /mosquitto/data/
@@ -139,10 +157,9 @@ listener 1883
allow_anonymous false
password_file /mosquitto/password.txt
EOF
source /var/lib/numbus-server/${name}/.env
source /var/lib/numbus-server/mqtt/.env
mosquitto_passwd -b ${cfg.configDir}/mqtt/password.txt "$HOME_ASSISTANT_MQTT_USER" "$HOME_ASSISTANT_MQTT_PASSWORD"
chmod 600 ${cfg.configDir}/mqtt/password.txt
touch /var/lib/numbus-server/${name}/quirk-2.true
'';
};
}
+53 -11
View File
@@ -4,23 +4,22 @@ with lib;
let
# Version tagging
immichVersion = "v2.5.6";
immichVersion = "v2.7.5";
redisVersion = "9@sha256:546304417feac0874c3dd576e0952c6bb8f06bb4093ea0c9ca303c73cf458f63";
databaseVersion = "14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.${name};
cfg = config.numbus.services.immich;
# Container configuration
name = "immich";
in
helper.mkPodmanService {
description = "Immich, Google Photos but better";
inherit name;
pod = "immich";
description = "Immich, Google Photos but better";
defaultPort = "2283";
generatedSecrets = {
DB_NAME = "xkcdpass -n 2 -d -";
DB_DATABASE_NAME = "xkcdpass -n 2 -d -";
DB_USERNAME = "xkcdpass -n 2 -d -";
DB_PASSWORD = "xkcdpass -n 8 -d -";
};
@@ -29,11 +28,18 @@ helper.mkPodmanService {
DB_HOSTNAME = "immich-database";
UPLOAD_LOCATION = "${cfg.dataDir}";
DB_DATA_LOCATION = "${cfg.configDir}/database";
TZ = "${time.timeZone}";
TZ = "${config.time.timeZone}";
IMMICH_VERSION = "v2.7.5";
};
middlewares = [ "immichSecureHeaders" ];
dirPermissions = [
"100999:users ${cfg.dataDir}"
"100999:users ${cfg.configDir}"
"100999:100 ${cfg.configDir}"
"100999:100 ${cfg.configDir}/redis"
"100999:100 ${cfg.configDir}/model-cache"
"100999:100 ${cfg.configDir}/machine-learning-cache"
"100999:100 ${cfg.configDir}/machine-learning-config"
"100999:100 ${cfg.configDir}/database"
"100999:100 ${cfg.dataDir}"
];
# Compose file good
@@ -52,7 +58,15 @@ helper.mkPodmanService {
- $UPLOAD_LOCATION:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
- /var/lib/numbus-server/immich/.env
environment:
TZ: $TZ
REDIS_HOSTNAME: $REDIS_HOSTNAME
DB_HOSTNAME: $DB_HOSTNAME
DB_DATABASE_NAME: $DB_DATABASE_NAME
DB_USERNAME: $DB_USERNAME
DB_PASSWORD: $DB_PASSWORD
IMMICH_TRUSTED_PROXIES: ${config.numbus.networking.ipAddress}
depends_on:
- immich-redis
- immich-database
@@ -75,7 +89,7 @@ helper.mkPodmanService {
- ${cfg.configDir}/machine-learning-config:/usr/src/.config
- ${cfg.configDir}/machine-learning-cache:/usr/src/.cache/
env_file:
- .env
- /var/lib/numbus-server/immich/.env
healthcheck:
disable: false
security_opt:
@@ -90,6 +104,8 @@ helper.mkPodmanService {
user: '1000:1000'
networks:
immich:
volumes:
- ${cfg.configDir}/redis:/data
healthcheck:
test: redis-cli ping || exit 1
restart: unless-stopped
@@ -103,7 +119,7 @@ helper.mkPodmanService {
environment:
POSTGRES_PASSWORD: $DB_PASSWORD
POSTGRES_USER: $DB_USERNAME
POSTGRES_DB: $DB_NAME
POSTGRES_DB: $DB_DATABASE_NAME
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- $DB_DATA_LOCATION:/var/lib/postgresql/data
@@ -120,4 +136,30 @@ helper.mkPodmanService {
name: immich
driver: bridge
'';
extraConfig = {
environment.etc."traefik/rules/immichSecureHeaders.yaml".text = ''
http:
middlewares:
immichSecureHeaders:
headers:
FrameDeny: true
AccessControlAllowMethods: 'GET,POST,PUT,DELETE,OPTIONS'
AccessControlAllowOriginList:
- https://${cfg.subdomain}.${config.numbus.services.domain}
- origin-list-or-null
AccessControlMaxAge: 100
AddVaryHeader: true
BrowserXssFilter: true
ContentTypeNosniff: true
ForceSTSHeader: true
STSIncludeSubdomains: true
STSPreload: true
ContentSecurityPolicy: "default-src 'self'; base-uri 'self'; img-src 'self' https://static.immich.cloud https://tiles.immich.cloud data: blob:; connect-src 'self' https://${cfg.subdomain}.${config.numbus.services.domain} wss://${cfg.subdomain}.${config.numbus.services.domain} https://static.immich.cloud https://tiles.immich.cloud; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; script-src 'self' 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob: https://${cfg.subdomain}.${config.numbus.services.domain}; frame-ancestors 'self';"
CustomFrameOptionsValue: SAMEORIGIN
ReferrerPolicy: same-origin
PermissionsPolicy: vibrate 'self'
STSSeconds: 315360000
'';
};
}
+8 -3
View File
@@ -3,18 +3,23 @@
with lib;
let
# Version tagging
it-toolsVersion = "2024.10.22-7ca5933";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.it-tools;
# Container config
name = "it-tools";
in
helper.mkPodmanService {
inherit name;
description = "IT-tools, useful tools when doing IT";
name = "it-tools";
pod = "false";
defaultPort = "8880";
configDir = false;
dataDir = false;
configDirEnabled = false;
dataDirEnabled = false;
middlewares = [ "secureHeaders" ];
# Compose file good
composeText = ''
+28 -21
View File
@@ -12,7 +12,7 @@ with lib;
reverseProxied ? true,
composeText,
scheme ? "http",
middlewares ? [ "secureHeaders" ],
middlewares ? null,
dependencies ? [ "traefik.service" "${config.numbus.services.dns}.service" ],
extraOptions ? {},
extraConfig ? {},
@@ -23,6 +23,7 @@ with lib;
generatedSecrets ? {},
importedSecrets ? {},
envFile ? null,
...
}:
let
@@ -76,7 +77,7 @@ with lib;
{
environment.etc."podman/${name}/compose.yaml".text = composeText;
environment.etc."${config.numbus.traefikDynamicConfigDir}/${name}.yaml" = mkIf cfg.reverseProxied {
environment.etc."traefik/rules/${name}.yaml" = mkIf cfg.reverseProxied {
text = ''
http:
routers:
@@ -100,27 +101,27 @@ ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
systemd.services."${name}" = {
description = "Podman container : ${name}";
requires = dependencies;
after = dependencies;
wantedBy = [ "multi-user.target" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.podman pkgs.podman-compose pkgs.coreutils pkgs.sudo ];
path = [ pkgs.podman pkgs.podman-compose pkgs.slirp4netns pkgs.su pkgs.sudo pkgs.coreutils ];
serviceConfig = {
Type = "exec";
TimeoutStartSec = "1000";
ExecStartPre = [
"bash -c 'sleep $((RANDOM % ${toString startDelay}))'"
"- sudo -u numbus-admin podman-compose ${envFileArg} -f /etc/podman/${name}/compose.yaml pull"
"${pkgs.bash}/bin/bash -c 'sleep $((RANDOM % ${toString startDelay}))'"
"${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose -f /etc/podman/${name}/compose.yaml pull'"
];
ExecStart = "sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans";
ExecStop = "sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down";
ExecStart = "${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml up --remove-orphans'";
ExecStop = "${pkgs.bash}/bin/bash -c 'export PATH=/run/wrappers/bin:$PATH; exec ${pkgs.sudo}/bin/sudo -u numbus-admin podman-compose ${envFileArg} --in-pod ${toString pod} -f /etc/podman/${name}/compose.yaml down'";
Restart = "on-failure";
RestartSec = "1m";
RestartSec = "3m";
};
};
systemd.services."${name}-permissions" = mkIf dirPermissions != [] {
systemd.services."${name}-permissions" = mkIf (dirPermissions != []) {
description = "Podman container : ${name} : check and fix permissions";
before = [ "${name}.service" ];
wantedBy = [ "multi-user.target" "${name}.service" ];
@@ -132,18 +133,24 @@ ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
Type = "oneshot";
RemainAfterExit = true;
Restart = "on-failure";
RestartSec = "1m";
RestartSec = "5m";
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
${concatStringsSep "\n" (map (perm: ''
set -- ${perm}
MARKER="/var/lib/numbus-server/${name}/.perm-fixed-$(echo "$1:$2" | md5sum | cut -d' ' -f1)"
if [ ! -f "$MARKER" ]; then
rm -f /var/lib/numbus-server/${name}/.perm-fixed-*
mkdir -p "$2"
chown -R "$1" "$2"
touch "$MARKER"
WANTED_PERMISSIONS=$1
FOLDER_PATH=$2
if [[ ! -e "$FOLDER_PATH" ]]; then
mkdir -p "$FOLDER_PATH"
elif [[ ! -d "$FOLDER_PATH" ]]; then
rm "$FOLDER_PATH"
mkdir -p "$FOLDER_PATH"
fi
ACTUAL_PERMISSIONS=$(stat -c '%u:%g' "$FOLDER_PATH")
if [[ "$ACTUAL_PERMISSIONS" != "$WANTED_PERMISSIONS" ]]; then
chown -R "$WANTED_PERMISSIONS" "$FOLDER_PATH"
fi
'') dirPermissions)}
exit 0
@@ -162,7 +169,7 @@ ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
Type = "oneshot";
RemainAfterExit = true;
Restart = "on-failure";
RestartSec = "1m";
RestartSec = "5m";
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
@@ -175,7 +182,7 @@ ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
# Generated Secrets (only if missing)
${concatStringsSep "\n" (mapAttrsToList (k: v: ''
if ! grep -q "^${k}=" "$SECRETS_FILE"; then
echo "${k}=$(${v})" >> "$SECRETS_FILE"
echo "${k}=\"$(${v})\"" >> "$SECRETS_FILE"
fi
'') generatedSecrets)}
@@ -185,7 +192,7 @@ ${concatStringsSep "\n" (map (m: " - ${m}") middlewares)}
grep -v "^${k}=" "$SECRETS_FILE" > "$SECRETS_FILE.tmp"
mv "$SECRETS_FILE.tmp" "$SECRETS_FILE"
fi
echo "${k}=${lib.escapeShellArg v}" >> "$SECRETS_FILE"
echo "${k}=\"${lib.escapeShellArg v}\"" >> "$SECRETS_FILE"
'') importedSecrets)}
chown numbus-admin:users "$SECRETS_FILE"
+124 -50
View File
@@ -4,20 +4,21 @@ with lib;
let
# Version tagging
nextcloudVersion = "32.0.6";
nextcloudVersion = "33.0.5-apache";
redisVersion = "8.6-alpine";
databaseVersion = "11.8";
onlyofficeVersion = "9.2";
whiteboardVersion = "v1.5.6";
onlyofficeVersion = "9.4.0";
whiteboardVersion = "v1.5.9";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.nextcloud;
# Container config
name = "nextcloud";
in
helper.mkPodmanService {
inherit name;
description = "Nextcloud, your own online office suite";
name = "nextcloud";
pod = "nextcloud";
defaultPort = "1100";
generatedSecrets = {
DB_NAME = "xkcdpass -n 2 -d -";
@@ -28,12 +29,18 @@ helper.mkPodmanService {
WHITEBOARD_PASSWORD = "xkcdpass -n 10 -d -";
SMTP_PASSWORD = "cat ${config.numbus.mail.smtpPasswordPath}";
};
middlewares = [ "nextcloudSecureHeaders" ];
dirPermissions = [
"100032:users ${cfg.configDir}/web"
"100999:users ${cfg.configDir}/redis"
"100999:users ${cfg.configDir}/database"
"100999:users ${cfg.configDir}/onlyoffice"
"100032:users ${cfg.dataDir}"
"100032:100 ${cfg.dataDir}"
"100032:100 ${cfg.configDir}"
"100032:100 ${cfg.configDir}/web"
"100999:100 ${cfg.configDir}/redis"
"100999:100 ${cfg.configDir}/database"
"1000:100 ${cfg.configDir}/onlyoffice"
"1000:100 ${cfg.configDir}/onlyoffice/log"
"1000:100 ${cfg.configDir}/onlyoffice/cache"
"1000:100 ${cfg.configDir}/onlyoffice/data"
"1000:100 ${cfg.configDir}/onlyoffice/database"
];
# Compose file good
@@ -51,7 +58,7 @@ helper.mkPodmanService {
- ${cfg.configDir}/web:/var/www/html
- ${cfg.dataDir}:/mnt/ncdata
environment:
MYSQL_HOST: nextcloud-database
MYSQL_HOST: nextcloud-database:3306
MYSQL_DATABASE: $DB_NAME
MYSQL_USER: $DB_USERNAME
MYSQL_PASSWORD: $DB_PASSWORD
@@ -61,19 +68,21 @@ helper.mkPodmanService {
NEXTCLOUD_DATA_DIR: /mnt/ncdata
SMTP_SECURE: tls
SMTP_HOST: ${config.numbus.mail.smtpServer}
SMTP_PORT: ${config.numbus.mail.smtpPort}
SMTP_PORT: ${toString config.numbus.mail.smtpPort}
SMTP_NAME: ${config.numbus.mail.smtpUsername}
SMTP_PASSWORD: $SMTP_PASSWORD
MAIL_FROM_ADDRESS: nextcloud-noreply
MAIL_DOMAIN: ${config.numbus.services.domain}
APACHE_DISABLE_REWRITE_IP: 1
TRUSTED_PROXIES: ${config.numbus.networking.ipAddress}
OVERWRITEPROTOCOL: https
TRUSTED_PROXIES: 10.89.0.0/16
NC_default_phone_region: "${config.numbus.language}"
NC_default_language: "${config.numbus.language}"
NC_default_locale: "${config.numbus.locale}"
NC_default_timezone: "${time.timeZone}"
NC_default_timezone: "${config.time.timeZone}"
NC_maintenance_window_start: "1"
PHP_MEMORY_LIMIT: 1024M
PHP_OPCACHE_MEMORY_CONSUMPTION: 256
depends_on:
- nextcloud-database
security_opt:
@@ -106,15 +115,17 @@ helper.mkPodmanService {
volumes:
- ${cfg.configDir}/database:/var/lib/mysql
environment:
MARIADB_DATABASE: $MYSQL_DATABASE
MARIADB_USER: $MYSQL_USER
MARIADB_PASSWORD: $MYSQL_PASSWORD
MARIADB_DATABASE: $DB_NAME
MARIADB_USER: $DB_USERNAME
MARIADB_PASSWORD: $DB_PASSWORD
MARIADB_RANDOM_ROOT_PASSWORD: true
security_opt:
- no-new-privileges:true
cap_drop:
- NET_RAW
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
command:
- "--transaction-isolation=READ-COMMITTED"
- "--binlog-format=ROW"
restart: unless-stopped
nextcloud-onlyoffice:
container_name: nextcloud-onlyoffice
@@ -122,14 +133,19 @@ helper.mkPodmanService {
image: docker.io/onlyoffice/documentserver:${onlyofficeVersion}
environment:
- JWT_SECRET=$ONLYOFFICE_PASSWORD
- REDIS_SERVER_HOST=nextcloud-redis
- REDIS_SERVER_PORT=6379
- REDIS_SERVER_PASS=$REDIS_PASSWORD
- ADMINPANEL_ENABLED=false
- EXAMPLE_ENABLED=false
- METRICS_ENABLED=false
ports:
- "9980:80/tcp"
volumes:
- ${cfg.configDir}/onlyoffice/log:/var/log/onlyoffice
- ${cfg.configDir}/onlyoffice/cache:/var/lib/onlyoffice
- ${cfg.configDir}/onlyoffice/data:/var/www/onlyoffice/Data
- ${cfg.configDir}/onlyoffice/database:/var/lib/postgresql
security_opt:
- no-new-privileges:true
cap_drop:
- NET_RAW
restart: unless-stopped
@@ -155,7 +171,7 @@ helper.mkPodmanService {
'';
extraConfig = {
environment.etc."${config.numbus.traefikDynamicConfigDir}/nextcloud-onlyoffice.yaml".text = ''
environment.etc."traefik/rules/nextcloud-onlyoffice.yaml".text = ''
http:
routers:
nextcloud-onlyoffice:
@@ -164,7 +180,7 @@ helper.mkPodmanService {
- "websecure"
service: nextcloud-onlyoffice
middlewares:
- "secureHeaders"
- "nextcloudSecureHeaders"
tls:
certresolver: "cloudflare"
options: "secureTLS"
@@ -175,7 +191,7 @@ helper.mkPodmanService {
- url: "http://host.containers.internal:9980"
'';
environment.etc."${config.numbus.traefikDynamicConfigDir}/nextcloud-whiteboard.yaml".text = ''
environment.etc."traefik/rules/nextcloud-whiteboard.yaml".text = ''
http:
routers:
nextcloud-whiteboard:
@@ -195,6 +211,39 @@ helper.mkPodmanService {
- url: "http://host.containers.internal:3002"
'';
environment.etc."traefik/rules/nextcloudSecureHeaders.yaml".text = ''
http:
middlewares:
nextcloudSecureHeaders:
headers:
FrameDeny: false
CustomFrameOptionsValue: "SAMEORIGIN"
AddVaryHeader: true
BrowserXssFilter: true
ContentTypeNosniff: true
ForceSTSHeader: true
STSSeconds: 315360000
STSIncludeSubdomains: true
STSPreload: true
AccessControlAllowMethods: "GET,OPTIONS,PUT"
AccessControlAllowOriginList:
- origin-list-or-null
AccessControlMaxAge: 100
ReferrerPolicy: same-origin
PermissionsPolicy: "vibrate=()"
ContentSecurityPolicy: >-
default-src https://onlyoffice.${config.numbus.services.domain} 'self';
script-src https://onlyoffice.${config.numbus.services.domain} 'self' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
connect-src 'self';
img-src 'self' data:;
font-src 'self' data:;
frame-src https://onlyoffice.${config.numbus.services.domain} 'self';
frame-ancestors https://onlyoffice.${config.numbus.services.domain} 'self';
object-src 'none';
base-uri 'self';
'';
systemd.services."${name}-quirk" = {
description = "Podman container quirk : ${name}";
wantedBy = [ "multi-user.target" ];
@@ -202,38 +251,62 @@ helper.mkPodmanService {
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils pkgs.sudo pkgs.podman ];
path = [ pkgs.coreutils pkgs.sudo pkgs.podman pkgs.systemd pkgs.gnugrep ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
mkdir -p /var/lib/numbus-server/${name}
if [[ -e /var/lib/numbus-server/${name}/quirk.true ]]; then
exit 0
fi
OCC="sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ"
[[ ! -e /var/lib/numbus-server/${name}/.env ]] && systemctl start ${name}-secrets.service
until [[ -e /var/lib/numbus-server/${name}/.env ]]; do
echo "Waiting for secrets generation..."
sleep 5
done
source /var/lib/numbus-server/${name}/.env
sleep 300
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ background:cron
until $OCC status | grep -iq "installed: true" >/dev/null 2>&1; do
echo "Waiting for Nextcloud to be up and running..."
sleep 60
done
$OCC db:add-missing-indices
$OCC maintenance:repair --include-expensive
INSTALL_APPS_LIST=( "calendar" "contacts" "mail" "notes" "onlyoffice" "cookbook" "whiteboard" )
DISABLE_APPS_LIST=( "activity" "federation" "webhook_listeners" "photos" "recommendations" "sharebymail" "teams" "support" "richdocumentscode" )
for app in ''${INSTALL_APPS_LIST[@]}; do
if ! $OCC --no-warnings app:list | grep -iq "$app:"; then
$OCC --no-warnings app:install "$app"
fi
if $OCC --no-warnings app:list --disabled | grep -iq "$app:"; then
$OCC --no-warnings app:enable "$app"
fi
done
for app in ''${DISABLE_APPS_LIST[@]}; do
if $OCC --no-warnings app:list --enabled | grep -iq "$app:"; then
$OCC --no-warnings app:disable "$app"
fi
done
$OCC --no-warnings config:system:set onlyoffice DocumentServerInternalUrl --value="https://onlyoffice.${config.numbus.services.domain}/"
$OCC --no-warnings config:system:set onlyoffice DocumentServerUrl --value="https://onlyoffice.${config.numbus.services.domain}/"
$OCC --no-warnings config:system:set onlyoffice jwt_secret --value="$ONLYOFFICE_PASSWORD"
$OCC --no-warnings config:app:set whiteboard collabBackendUrl --value="https://whiteboard.${config.numbus.services.domain}"
$OCC --no-warnings config:app:set whiteboard jwt_secret_key --value="$WHITEBOARD_PASSWORD"
if [[ ! -f /var/lib/numbus-server/${name}/croned.true ]]; then
$OCC background:cron
sudo -u numbus-admin podman exec --user www-data nextcloud-server php -f /var/www/html/cron.php
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ db:add-missing-indices
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ maintenance:repair --include-expensive
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ files:scan --all
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ files:repair-tree
for app in calendar contacts mail note onlyoffice cookbook whiteboard; do
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ app:install $app
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ app:enable $app
done
for app in activity app_api federatedfilesharing federation webhook_listeners photos recommendations sharebymail teams support richdocumentscode; do
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ app:disable $app
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ app:remove $app
done
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ config:system:set onlyoffice DocumentServerInternalUrl --value="https://onlyoffice.${config.numbus.services.domain}/"
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ config:system:set onlyoffice DocumentServerUrl --value="https://onlyoffice.${config.numbus.services.domain}/"
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ config:system:set onlyoffice jwt_secret --value="$ONLYOFFICE_PASSWORD"
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ config:app:set whiteboard collabBackendUrl --value="https://whiteboard.${config.numbus.services.domain}"
sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ config:app:set whiteboard jwt_secret_key --value="$WHITEBOARD_PASSWORD"
touch /var/lib/numbus-server/${name}/quirk.true
touch /var/lib/numbus-server/${name}/croned.true
fi
if [[ ! -f /var/lib/numbus-server/${name}/scanned.true ]]; then
$OCC files:scan --all
$OCC files:repair-tree
touch /var/lib/numbus-server/${name}/scanned.true
fi
'';
};
@@ -241,10 +314,11 @@ helper.mkPodmanService {
description = "Podman container crontab : ${name}";
after = [ "${name}.service" "${name}-quirk.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
path = [ pkgs.coreutils pkgs.sudo pkgs.podman ];
path = [ pkgs.sudo pkgs.podman ];
serviceConfig = {
Type = "oneshot";
ExecStart = "sudo -u numbus-admin podman exec --user www-data nextcloud-server php -f /var/www/html/cron.php";
ExecCondition = ''${pkgs.sudo}/bin/sudo -u numbus-admin podman exec --user www-data nextcloud-server php occ status'';
ExecStart = "${pkgs.sudo}/bin/sudo -u numbus-admin podman exec --user www-data nextcloud-server php -f /var/www/html/cron.php";
};
};
+11 -8
View File
@@ -9,12 +9,13 @@ let
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.passbolt;
# Container config
name = "passbolt";
in
helper.mkPodmanService {
inherit name;
description = "Passbolt, your password manager";
name = "passbolt";
pod = "passbolt";
defaultPort = "4433";
scheme = "https";
dataDirEnabled = false;
@@ -24,10 +25,12 @@ helper.mkPodmanService {
DB_PASSWORD = "xkcdpass -n 10 -d -";
SMTP_PASSWORD = "cat ${config.numbus.mail.smtpPasswordPath}";
};
middlewares = [ "secureHeaders" ];
dirPermissions = [
"100032:users ${cfg.configDir}/gpg"
"100032:users ${cfg.configDir}/jwt"
"100999:users ${cfg.configDir}/database"
"100032:100 ${cfg.configDir}"
"100032:100 ${cfg.configDir}/gpg"
"100032:100 ${cfg.configDir}/jwt"
"100999:100 ${cfg.configDir}/database"
];
# Compose file good
@@ -46,7 +49,7 @@ helper.mkPodmanService {
- ${cfg.configDir}/gpg:/etc/passbolt/gpg
- ${cfg.configDir}/jwt:/etc/passbolt/jwt
environment:
APP_DEFAULT_TIMEZONE: ${time.timeZone}
APP_DEFAULT_TIMEZONE: ${config.time.timeZone}
APP_FULL_BASE_URL: https://${cfg.subdomain}.${config.numbus.services.domain}
DATASOURCES_DEFAULT_HOST: "passbolt-database"
DATASOURCES_DEFAULT_USERNAME: $DB_USERNAME
@@ -54,7 +57,7 @@ helper.mkPodmanService {
DATASOURCES_DEFAULT_DATABASE: $DB_NAME
EMAIL_DEFAULT_FROM_NAME: "Passbolt"
EMAIL_TRANSPORT_DEFAULT_HOST: ${config.numbus.mail.smtpServer}
EMAIL_TRANSPORT_DEFAULT_PORT: ${config.numbus.mail.smtpPort}
EMAIL_TRANSPORT_DEFAULT_PORT: ${toString config.numbus.mail.smtpPort}
EMAIL_TRANSPORT_DEFAULT_USERNAME: ${config.numbus.mail.smtpUsername}
EMAIL_TRANSPORT_DEFAULT_PASSWORD: $EMAIL_TRANSPORT_DEFAULT_PASSWORD
EMAIL_TRANSPORT_DEFAULT_TLS: true
@@ -67,7 +70,7 @@ helper.mkPodmanService {
"0",
"passbolt-database:3306",
"--",
"/docker-entrypoint.sh",
"/docker-entrypoint.sh"
]
depends_on:
- passbolt-database
+16 -9
View File
@@ -8,21 +8,25 @@ let
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.pi-hole;
# Container config
name = "pi-hole";
in
helper.mkPodmanService {
inherit name;
description = "Pi-Hole, the ads black hole";
name = "pi-hole";
pod = "false";
defaultPort = "4443";
scheme = "https";
dependencies = [ "network.target" "multi-user.target" ];
dataDir = false;
delaySec = 10;
dependencies = [ "network.target" ];
dataDirEnabled = false;
startDelay = 10;
generatedSecrets = {
PIHOLE_PASSWORD = "xkcdpass -n 10 -d -";
};
middlewares = [ "secureHeaders" ];
dirPermissions = [
"numbus-admin:users ${cfg.configDir}"
"100999:100 ${cfg.configDir}"
];
# Compose file good
@@ -42,16 +46,19 @@ helper.mkPodmanService {
environment:
PIHOLE_UID: '1000'
PIHOLE_GID: '1000'
TZ: ${time.timeZone}
TZ: ${config.time.timeZone}
FTLCONF_webserver_api_password: $PIHOLE_PASSWORD
FTLCONF_webserver_domain: ${cfg.subdomain}.${config.numbus.services.domain}
FTLCONF_dns_upstreams: 9.9.9.9;149.112.112.112
FTLCONF_dns_hosts: |
${lib.concatStringsSep "" (lib.mapAttrsToList (name: service:
if builtins.isAttrs service && service ? enable && service.enable && service ? subdomain then
" ${config.numbus.networking.ipAddress} ${service.subdomain}.${config.numbus.services.domain}\n"
else
""
" ${config.numbus.networking.ipAddress} ${service.subdomain}.${config.numbus.services.domain}\n" +
(if name == "nextcloud" then
" ${config.numbus.networking.ipAddress} onlyoffice.${config.numbus.services.domain}\n" +
" ${config.numbus.networking.ipAddress} whiteboard.${config.numbus.services.domain}\n"
else "")
else ""
) config.numbus.services)}
FTLCONF_dns_listeningMode: "BIND"
FTLCONF_dns_domain_name: "${config.numbus.services.domain}"
+39 -24
View File
@@ -4,27 +4,30 @@ with lib;
let
# Version tagging
traefikVersion = "v3.6.8";
traefikVersion = "v3.7.4";
# Helper
helper = import ./lib.nix { inherit config pkgs lib; };
cfg = config.numbus.services.traefik;
# Container config
name = "traefik";
in
helper.mkPodmanService {
inherit name;
description = "Traefik reverse proxy, one to rule them all";
name = "traefik";
reverseProxied = false;
dependencies = [ "network.target" "multi-user.target" ];
dataDir = false;
delaySec = 10;
pod = "false";
dataDirEnabled = false;
dependencies = [ "network.target" ];
startDelay = 10;
generatedSecrets = {
CLOUDFLARE_DNS_API_TOKEN = "cat ${config.numbus.mail.smtpPasswordPath}";
CLOUDFLARE_DNS_API_TOKEN = "cat ${config.sops.secrets."cloudflareDnsApiToken".path}";
};
dirPermissions = [
"100999:users ${cfg.configDir}"
"100999:users /etc/${cfg.staticConfigFile}"
"100999:users ${config.numbus.traefikDynamicConfigDir}"
"100999:100 ${cfg.configDir}"
"100999:100 ${cfg.configDir}/rules"
"100999:100 ${cfg.configDir}/certs"
];
reverseProxied = false;
# Compose file good
composeText = ''
@@ -39,9 +42,9 @@ helper.mkPodmanService {
- "80:80/tcp"
- "443:443/tcp"
volumes:
- /etc/${cfg.staticConfigFile}:/etc/traefik/traefik.yaml:ro
- ${config.numbus.traefikDynamicConfigDir}:/etc/traefik/conf:ro
- ${cfg.configDir}:/var/traefik/certs:rw
- ${cfg.configDir}/traefik.yaml:/etc/traefik/traefik.yaml:ro
- ${cfg.configDir}/rules:/etc/traefik/rules:ro
- ${cfg.configDir}/certs:/var/traefik/certs:rw
environment:
- CF_DNS_API_TOKEN=$CLOUDFLARE_DNS_API_TOKEN
cap_add:
@@ -52,7 +55,7 @@ helper.mkPodmanService {
'';
extraConfig = {
environment.etc."${cfg.staticConfigFile}".text = ''
environment.etc."traefik/traefik.yaml".text = ''
global:
checkNewVersion: false
sendAnonymousUsage: false
@@ -81,7 +84,7 @@ helper.mkPodmanService {
certificatesResolvers:
cloudflare:
acme:
email: ${config.numbus.email.administratorEmail}
email: ${config.numbus.mail.adminAddress}
storage: /var/traefik/certs/cloudflare-acme.json
caServer: "https://acme-v02.api.letsencrypt.org/directory"
dnsChallenge:
@@ -93,11 +96,11 @@ helper.mkPodmanService {
insecureSkipVerify: true
providers:
file:
directory: "/etc/traefik/conf/"
directory: "/etc/traefik/rules"
watch: true
'';
environment.etc."${config.numbus.traefikDynamicConfigDir}/secureHeaders.yaml".text = ''
environment.etc."traefik/rules/secureHeaders.yaml".text = ''
http:
middlewares:
secureHeaders:
@@ -120,7 +123,7 @@ helper.mkPodmanService {
STSSeconds: 315360000
'';
environment.etc."${config.numbus.traefikDynamicConfigDir}/secureTLS.yaml".text = ''
environment.etc."traefik/rules/secureTLS.yaml".text = ''
tls:
options:
secureTLS:
@@ -134,20 +137,32 @@ helper.mkPodmanService {
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
'';
systemd.services."${name}-quirk" = {
description = "Podman container quirk : ${name}";
wantedBy = [ "multi-user.target" ];
after = [ "${name}.service" "${name}-secrets.service" ];
onFailure = [ "service-failure-notify@%n.service" ];
startLimitBurst = 5;
startLimitIntervalSec = 600;
path = [ pkgs.coreutils ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
cp -Lurv /etc/traefik/* ${cfg.configDir}
'';
};
};
extraOptions = {
enable.default = true;
staticConfigFile = mkOption {
type = types.str;
default = "traefik/config.yaml";
description = "The path for Traefik's static configuration file, relative to /etc/";
};
logLevel = mkOption {
type = types.enum [ "TRACE" "DEBUG" "INFO" "WARN" "ERROR" "FATAL" ];
default = "ERROR";
example = "ERROR";
description = "The level of detail Traefik should print in the logs.";
};
# traefikDynamicConfigDir defined at global.nix
};
}
+17
View File
@@ -0,0 +1,17 @@
{ config, lib, ... }:
with lib;
let
cfg = config.numbus.services.virtualization;
in
{
options.numbus.services.virtualization = {
enable = mkEnableOption "QEMU/KVM virtualization software";
};
config = mkIf cfg.enable {
virtualisation.libvirtd.enable = true;
};
}