Compare commits

...

20 commits

Author SHA1 Message Date
7b585dec5a Add essential cli tools to home-manager 2026-02-08 19:04:00 +01:00
70e04e428e Add genericLinux target for homemanager 2026-02-08 19:04:00 +01:00
bdf0cecf54 Add username in extraSpecialArgs 2026-02-08 19:04:00 +01:00
6f805ea6a4 Explicitly set nix package to use 2026-02-08 19:04:00 +01:00
e81a7875ed Add nix config to home-manager configuration 2026-02-08 19:04:00 +01:00
e16f304745 Add initial home-manager configuration 2026-02-08 19:04:00 +01:00
9813193c7d Remove kube server configurations 2026-02-08 12:30:44 +01:00
c9216f6468 Update flake.lock 2026-02-08 12:28:32 +01:00
fd6810bd59 Migrate srv01-hf to pangolin and dockhand 2026-02-08 12:28:02 +01:00
e890501a0a Add dockhand module 2026-02-08 12:25:30 +01:00
074a553351 Add newt module 2026-02-08 12:17:00 +01:00
7adb75ed32 Add pangolin module 2026-02-08 12:11:20 +01:00
24cf657f9c Add virtiofsd to enable shared folder to qemu 2026-01-18 22:34:11 +01:00
cba8dea9c7 Add firefly to test Remote-User authentication 2026-01-09 22:03:01 +01:00
a70450af2a Add Remote-User authentication from mTLS with headers 2026-01-09 22:01:10 +01:00
b65effa878 Update flake.lock 2026-01-04 22:23:15 +01:00
5115744f46 Test traefik, arcane and immich on vServer 2026-01-04 22:22:53 +01:00
cb0408abd4 Add modules for traefik and arcane 2026-01-04 22:20:20 +01:00
ed21c24262 Enable ipv6 in docker 2026-01-04 22:17:40 +01:00
d4e4ecf9a9 Disallow ping on servers 2026-01-04 22:17:30 +01:00
21 changed files with 591 additions and 280 deletions

79
flake.lock generated
View file

@ -30,11 +30,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1765042799, "lastModified": 1769608722,
"narHash": "sha256-G7UJDUNcuHm1n2EuA+2iKPNISSWoUgqk85ktncJoelo=", "narHash": "sha256-yWUG0Emd9EuqIZ8jQ6fxqf7USw7Gtcqb4+sBhn+S+Wg=",
"owner": "AdnanHodzic", "owner": "AdnanHodzic",
"repo": "auto-cpufreq", "repo": "auto-cpufreq",
"rev": "2e5c725be0a7da2c749a345e09f3df3b9ef8c209", "rev": "a11a98c46bf6a77d0c2e0ea8d87acef78507cae5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -50,11 +50,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1766150702, "lastModified": 1769524058,
"narHash": "sha256-P0kM+5o+DKnB6raXgFEk3azw8Wqg5FL6wyl9jD+G5a4=", "narHash": "sha256-zygdD6X1PcVNR2PsyK4ptzrVEiAdbMqLos7utrMDEWE=",
"owner": "nix-community", "owner": "nix-community",
"repo": "disko", "repo": "disko",
"rev": "916506443ecd0d0b4a0f4cf9d40a3c22ce39b378", "rev": "71a3fc97d80881e91710fe721f1158d3b96ae14d",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -144,11 +144,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1766529401, "lastModified": 1769580047,
"narHash": "sha256-OJAjJcW6ZADEzTBrvOTZanbgC8ObEWveObujtpazEbg=", "narHash": "sha256-tNqCP/+2+peAXXQ2V8RwsBkenlfWMERb+Uy6xmevyhM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "home-manager", "repo": "home-manager",
"rev": "aaf46506426cc8c53719dd20de660fc856a5561e", "rev": "366d78c2856de6ab3411c15c1cb4fb4c2bf5c826",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -181,11 +181,11 @@
}, },
"nixos-hardware": { "nixos-hardware": {
"locked": { "locked": {
"lastModified": 1764440730, "lastModified": 1769302137,
"narHash": "sha256-ZlJTNLUKQRANlLDomuRWLBCH5792x+6XUJ4YdFRjtO4=", "narHash": "sha256-QEDtctEkOsbx8nlFh4yqPEOtr4tif6KTqWwJ37IM2ds=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixos-hardware", "repo": "nixos-hardware",
"rev": "9154f4569b6cdfd3c595851a6ba51bfaa472d9f3", "rev": "a351494b0e35fd7c0b7a1aae82f0afddf4907aa8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -197,11 +197,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1766473571, "lastModified": 1769598131,
"narHash": "sha256-5G1NDO2PulBx1RoaA6U1YoUDX0qZslpPxv+n5GX6Qto=", "narHash": "sha256-e7VO/kGLgRMbWtpBqdWl0uFg8Y2XWFMdz0uUJvlML8o=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "76701a179d3a98b07653e2b0409847499b2a07d3", "rev": "fa83fd837f3098e3e678e6cf017b2b36102c7211",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -221,9 +221,10 @@
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "NixOS",
"repo": "nixpkgs",
"rev": "e6f23dc08d3624daab7094b701aa3954923c6bbb", "rev": "e6f23dc08d3624daab7094b701aa3954923c6bbb",
"type": "indirect" "type": "github"
} }
}, },
"nixpkgs-stable": { "nixpkgs-stable": {
@ -244,32 +245,34 @@
}, },
"nixpkgs-stable_2": { "nixpkgs-stable_2": {
"locked": { "locked": {
"lastModified": 1761016216, "lastModified": 1769318308,
"narHash": "sha256-G/iC4t/9j/52i/nm+0/4ybBmAF4hzR8CNHC75qEhjHo=", "narHash": "sha256-Mjx6p96Pkefks3+aA+72lu1xVehb6mv2yTUUqmSet6Q=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "481cf557888e05d3128a76f14c76397b7d7cc869", "rev": "1cd347bf3355fce6c64ab37d3967b4a2cb4b878c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "NixOS",
"ref": "nixos-25.05", "ref": "nixos-25.11",
"type": "indirect" "repo": "nixpkgs",
"type": "github"
} }
}, },
"nixpkgs-unstable": { "nixpkgs-unstable": {
"locked": { "locked": {
"lastModified": 1761114652, "lastModified": 1769861584,
"narHash": "sha256-f/QCJM/YhrV/lavyCVz8iU3rlZun6d+dAiC3H+CDle4=", "narHash": "sha256-Tu85RXpHMAWmsltAEKsG1IB7JfNGbekeHh2CSR0/xG8=",
"owner": "NixOS", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "01f116e4df6a15f4ccdffb1bcd41096869fb385c", "rev": "015e5f32a6258dc210b8e02fb47d86983959e243",
"type": "github" "type": "github"
}, },
"original": { "original": {
"id": "nixpkgs", "owner": "nixos",
"ref": "nixos-unstable", "ref": "pull/483348/merge",
"type": "indirect" "repo": "nixpkgs",
"type": "github"
} }
}, },
"pre-commit-hooks": { "pre-commit-hooks": {
@ -301,15 +304,14 @@
"flake-compat": "flake-compat_2", "flake-compat": "flake-compat_2",
"nixpkgs-libvncserver": "nixpkgs-libvncserver", "nixpkgs-libvncserver": "nixpkgs-libvncserver",
"nixpkgs-stable": "nixpkgs-stable_2", "nixpkgs-stable": "nixpkgs-stable_2",
"nixpkgs-unstable": "nixpkgs-unstable",
"utils": "utils" "utils": "utils"
}, },
"locked": { "locked": {
"lastModified": 1764188113, "lastModified": 1769870714,
"narHash": "sha256-Oq4aCjczgnFQqFNWZ6Ablg6x9579CO8tyBktYDYiZEs=", "narHash": "sha256-wjwCj70iiFXoAasQto+3jTaA4wCMOAs/rdX+nsmtBrQ=",
"owner": "SaumonNet", "owner": "SaumonNet",
"repo": "proxmox-nixos", "repo": "proxmox-nixos",
"rev": "3be878a84866b9ef9214b8ea6f53630f47f4b192", "rev": "c1f79f104930347a0b84abbca0d42884063a8c09",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -327,6 +329,7 @@
"lazy-apps": "lazy-apps", "lazy-apps": "lazy-apps",
"nixos-hardware": "nixos-hardware", "nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nixpkgs-unstable": "nixpkgs-unstable",
"proxmox-nixos": "proxmox-nixos", "proxmox-nixos": "proxmox-nixos",
"secrets": "secrets", "secrets": "secrets",
"systems": "systems_3" "systems": "systems_3"
@ -335,11 +338,11 @@
"secrets": { "secrets": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1758149597, "lastModified": 1769426267,
"narHash": "sha256-qUkhfFBEuDJ7nP6jcdBZzGBBhLKnXYxumBQI75DGcFc=", "narHash": "sha256-OBHSfMHZ+sWEtigOxTfIGnkZLPOz2P7VR8+KA2KY89g=",
"ref": "refs/heads/main", "ref": "refs/heads/main",
"rev": "8404f6877e25b8cbf3f504ef1926034e8c401dbe", "rev": "ebefef468e16eb692df0a3d54352c94a56110a97",
"revCount": 6, "revCount": 20,
"type": "git", "type": "git",
"url": "ssh://git@git.jfreudenberger.de/JuliusFreudenberger/nix-private.git" "url": "ssh://git@git.jfreudenberger.de/JuliusFreudenberger/nix-private.git"
}, },

View file

@ -11,7 +11,7 @@
}; };
inputs = { inputs = {
#nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable"; nixpkgs-unstable.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
nixos-hardware.url = "github:NixOS/nixos-hardware/master"; nixos-hardware.url = "github:NixOS/nixos-hardware/master";
home-manager = { home-manager = {
@ -48,7 +48,7 @@
outputs = { outputs = {
self, self,
nixpkgs, nixpkgs,
#nixpkgs-unstable, nixpkgs-unstable,
nixos-hardware, nixos-hardware,
home-manager, home-manager,
auto-cpufreq, auto-cpufreq,
@ -81,10 +81,6 @@
system = "x86_64-linux"; system = "x86_64-linux";
specialArgs = { specialArgs = {
#pkgs-unstable = import nixpkgs-unstable {
# inherit system;
# config.allowUnfree = true;
#};
inherit inputs outputs username; inherit inputs outputs username;
}; };
@ -142,6 +138,10 @@
specialArgs = { specialArgs = {
inherit inputs outputs; inherit inputs outputs;
pkgs-unstable = import nixpkgs-unstable {
inherit system;
config.allowUnfree = true;
};
}; };
modules = [ modules = [
@ -151,45 +151,34 @@
]; ];
}; };
kube01 = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux";
specialArgs = {
inherit inputs outputs;
};
modules = [
disko.nixosModules.disko
./hosts/kube01
];
};
kube02 = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux";
specialArgs = {
inherit inputs outputs;
};
modules = [
disko.nixosModules.disko
./hosts/kube02
];
};
kube03 = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux";
specialArgs = {
inherit inputs outputs;
};
modules = [
disko.nixosModules.disko
./hosts/kube03
];
};
}; };
homeConfigurations = {
jufr2 = let
username = "jufr2";
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in
home-manager.lib.homeManagerConfiguration {
inherit pkgs;
extraSpecialArgs = {
inherit username;
};
modules = [
home/core.nix
home/targets/genericLinux.nix
modules/nix.nix
home/neovim/default.nix
home/zsh/default.nix
home/cli.nix
];
};
};
}; };
} }

24
home/cli.nix Normal file
View file

@ -0,0 +1,24 @@
{
pkgs,
lib,
config,
...
}: {
home.packages = with pkgs; [
wget
curl
git
neofetch
tealdeer
pdfgrep
pdftk
p7zip
];
programs = {
htop.enable = true;
git.enable = true;
bat.enable = true;
};
}

View file

@ -0,0 +1,7 @@
{
...
}: {
targets.genericLinux.enable = true;
}

View file

@ -1,41 +0,0 @@
{ inputs, outputs, config, lib, pkgs, ... }:
{
imports =
[
../../modules/disko/efi-full-btrfs.nix
../../modules/systemd-boot.nix
../../users/julius/nixos-server.nix
../../modules/nix.nix
../../modules/network-server.nix
../../modules/locale.nix
../../modules/server-cli.nix
../../modules/sshd.nix
../../modules/k3s.nix
../../modules/qemu-guest.nix
# Include the results of the hardware scan.
./hardware-configuration.nix
];
networking.hostName = "kube01"; # Define your hostname.
services.k3s = {
clusterInit = true;
};
# This option defines the first version of NixOS you have installed on this particular machine,
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
# Most users should NEVER change this value after the initial install, for any reason,
# even if you've upgraded your system to a new NixOS release.
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
# to actually do that.
# This value being lower than the current NixOS release does NOT mean your system is
# out of date, out of support, or vulnerable.
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
# and migrated your data accordingly.
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
system.stateVersion = "25.05"; # Did you read the comment?
}

View file

@ -1,24 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View file

@ -1,41 +0,0 @@
{ inputs, outputs, config, lib, pkgs, ... }:
{
imports =
[
../../modules/disko/efi-full-btrfs.nix
../../modules/systemd-boot.nix
../../users/julius/nixos-server.nix
../../modules/nix.nix
../../modules/network-server.nix
../../modules/locale.nix
../../modules/server-cli.nix
../../modules/sshd.nix
../../modules/k3s.nix
../../modules/qemu-guest.nix
# Include the results of the hardware scan.
./hardware-configuration.nix
];
networking.hostName = "kube02"; # Define your hostname.
services.k3s = {
serverAddr = "https://kube01:6443";
clusterInit = false;
};
# This option defines the first version of NixOS you have installed on this particular machine,
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
# Most users should NEVER change this value after the initial install, for any reason,
# even if you've upgraded your system to a new NixOS release.
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
# to actually do that.
# This value being lower than the current NixOS release does NOT mean your system is
# out of date, out of support, or vulnerable.
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
# and migrated your data accordingly.
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
system.stateVersion = "25.05"; # Did you read the comment?
}

View file

@ -1,24 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View file

@ -1,42 +0,0 @@
{ inputs, outputs, config, lib, pkgs, ... }:
{
imports =
[
../../modules/disko/efi-full-btrfs.nix
../../modules/systemd-boot.nix
../../users/julius/nixos-server.nix
../../modules/nix.nix
../../modules/network-server.nix
../../modules/locale.nix
../../modules/server-cli.nix
../../modules/sshd.nix
../../modules/k3s.nix
../../modules/qemu-guest.nix
# Include the results of the hardware scan.
./hardware-configuration.nix
];
networking.hostName = "kube03"; # Define your hostname.
services.k3s = {
serverAddr = "https://kube01:6443";
clusterInit = false;
};
# This option defines the first version of NixOS you have installed on this particular machine,
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
# Most users should NEVER change this value after the initial install, for any reason,
# even if you've upgraded your system to a new NixOS release.
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
# to actually do that.
# This value being lower than the current NixOS release does NOT mean your system is
# out of date, out of support, or vulnerable.
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
# and migrated your data accordingly.
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
system.stateVersion = "25.05"; # Did you read the comment?
}

View file

@ -1,24 +0,0 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/profiles/qemu-guest.nix")
];
boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "sr_mod" "virtio_blk" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
}

View file

@ -17,6 +17,9 @@
../../modules/docker.nix ../../modules/docker.nix
../../modules/teleport.nix ../../modules/teleport.nix
../../modules/portainer_agent.nix ../../modules/portainer_agent.nix
../../modules/pangolin.nix
../../modules/newt.nix
../../modules/dockhand.nix
../../modules/auto-upgrade.nix ../../modules/auto-upgrade.nix
# Include the results of the hardware scan. # Include the results of the hardware scan.
./hardware-configuration.nix ./hardware-configuration.nix
@ -33,6 +36,29 @@
virtualisation.oci-containers.containers.portainer_agent.environmentFiles = [ config.age.secrets."portainer-join_token".path ]; virtualisation.oci-containers.containers.portainer_agent.environmentFiles = [ config.age.secrets."portainer-join_token".path ];
services = {
pangolin = {
dnsProvider = "netcup";
baseDomain = "juliusfr.eu";
letsEncryptEmail = "contact@jfreudenberger.de";
environmentFile = config.age.secrets."pangolin".path;
};
traefik = {
environmentFiles = [ config.age.secrets."netcup-dns".path ];
};
};
services.newt-docker = {
enable = true;
pangolinEndpoint = "https://pangolin.juliusfr.eu";
connectionSecret = config.age.secrets."newt";
};
services.dockhand = {
enable = true;
appUrl = "dockhand.juliusfr.eu";
};
systemd.network = { systemd.network = {
enable = true; enable = true;
networks."10-wan" = { networks."10-wan" = {

View file

@ -4,5 +4,8 @@
teleport-ca_pin.file = "${inputs.secrets}/secrets/teleport/ca_pin"; teleport-ca_pin.file = "${inputs.secrets}/secrets/teleport/ca_pin";
teleport-join_token.file = "${inputs.secrets}/secrets/srv01-hf/teleport_auth_token"; teleport-join_token.file = "${inputs.secrets}/secrets/srv01-hf/teleport_auth_token";
portainer-join_token.file = "${inputs.secrets}/secrets/srv01-hf/portainer_join_token"; portainer-join_token.file = "${inputs.secrets}/secrets/srv01-hf/portainer_join_token";
netcup-dns.file = "${inputs.secrets}/secrets/dns-management/netcup";
pangolin.file = "${inputs.secrets}/secrets/srv01-hf/pangolin";
newt.file = "${inputs.secrets}/secrets/srv01-hf/newt";
}; };
} }

64
modules/arcane.nix Normal file
View file

@ -0,0 +1,64 @@
{
config,
lib,
...
}:
let
cfg = config.services.arcane;
in {
options.services.arcane = {
enable = lib.mkEnableOption "arcane, a modern Docker management UI";
appUrl = lib.mkOption {
description = "External URL arcane will be reachable from, without protocol";
type = lib.types.str;
};
secretFile = lib.mkOption {
description = ''
Agenix secret containing the following needed environment variables in dotenv notation:
- ENCRYPTION_KEY
- JWT_SECRET
- OIDC_CLIENT_ID
- OIDC_CLIENT_SECRET
- OIDC_ISSUER_URL
- OIDC_ADMIN_CLAIM
- OIDC_ADMIN_VALUE
'';
};
};
config = lib.mkIf cfg.enable {
virtualisation.oci-containers.containers = {
arcane = {
image = "ghcr.io/getarcaneapp/arcane:v1.11.2";
volumes = [
"/var/run/docker.sock:/var/run/docker.sock"
];
environment = {
APP_URL = "https://${cfg.appUrl}";
PUID = "1000";
PGID = "1000";
LOG_LEVEL = "info";
LOG_JSON = "false";
OIDC_ENABLED = "true";
OIDC_SCOPES = "openid email profile groups";
DATABASE_URL = "file:data/arcane.db?_pragma=journal_mode(WAL)&_pragma=busy_timeout(2500)&_txlock=immediate";
};
environmentFiles = [
cfg.secretFile.path
];
networks = [
"traefik"
];
labels = {
"traefik.enable" = "true";
"traefik.http.routers.arcane.middlewares" = "arcane-oidc-auth@file";
"traefik.http.routers.arcane.rule" = "Host(`${cfg.appUrl}`)";
"traefik.http.services.arcane.loadbalancer.server.port" = "3552";
};
extraOptions = [
''--mount=type=volume,source=arcane-data,target=/app/data,volume-driver=local''
];
};
};
};
}

View file

@ -7,6 +7,10 @@
virtualisation = { virtualisation = {
docker = { docker = {
enable = true; enable = true;
daemon.settings = {
ipv6 = true;
ip6tables = true;
};
}; };
oci-containers.backend = "docker"; oci-containers.backend = "docker";
}; };

46
modules/dockhand.nix Normal file
View file

@ -0,0 +1,46 @@
{
config,
lib,
...
}:
let
cfg = config.services.dockhand;
in {
options.services.dockhand = {
enable = lib.mkEnableOption "dockhand, a powerful, intuitive Docker platform";
appUrl = lib.mkOption {
description = "External URL dockhand will be reachable from, without protocol";
type = lib.types.str;
};
};
config = lib.mkIf cfg.enable {
virtualisation.oci-containers.containers = {
dockhand = {
image = "fnsys/dockhand:v1.0.12";
volumes = [
"/var/run/docker.sock:/var/run/docker.sock"
];
environment = {
PUID = "1000";
PGID = "1000";
};
networks = [
"pangolin"
];
labels = {
"pangolin.public-resources.dockhand.name" = "dockhand";
"pangolin.public-resources.dockhand.full-domain" = cfg.appUrl;
"pangolin.public-resources.dockhand.protocol" = "http";
"pangolin.public-resources.dockhand.auth.sso-enabled" = "true";
"pangolin.public-resources.dockhand.auth.auto-login-idp" = "1";
"pangolin.public-resources.dockhand.targets[0].method" = "http";
};
extraOptions = [
''--mount=type=volume,source=dockhand-data,target=/app/data,volume-driver=local''
''--group-add=131'' # docker group
];
};
};
};
}

View file

@ -5,5 +5,6 @@
}: { }: {
networking = { networking = {
useDHCP = true; useDHCP = true;
firewall.allowPing = false;
}; };
} }

72
modules/newt.nix Normal file
View file

@ -0,0 +1,72 @@
{
pkgs,
config,
lib,
...
}:
let
cfg = config.services.newt-docker;
in {
options.services.newt-docker = {
enable = lib.mkEnableOption "Newt, user space tunnel client for Pangolin";
pangolinEndpoint = lib.mkOption {
description = "External URL of the Pangolin instance";
type = lib.types.str;
};
connectionSecret = lib.mkOption {
description = "Secrets for Pangolin authentication.";
type = lib.types.anything;
};
};
config = lib.mkIf cfg.enable {
virtualisation.oci-containers.containers = {
newt = {
image = "fosrl/newt:1.9.0";
autoStart = true;
networks = [
"pangolin"
];
environment = {
PANGOLIN_ENDPOINT = cfg.pangolinEndpoint;
DOCKER_SOCKET = "/var/run/docker.sock";
};
environmentFiles = [ cfg.connectionSecret.path ];
volumes = [
"/var/run/docker.sock:/var/run/docker.sock:ro"
];
extraOptions = [
"--add-host=host.docker.internal:host-gateway"
];
};
};
systemd.services."docker-pangolin" = {
after = [
"docker-network-pangolin.service"
];
requires = [
"docker-network-pangolin.service"
];
};
systemd.services."docker-network-pangolin" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
};
script = ''
docker network inspect pangolin || docker network create pangolin --ipv4 --ipv6 --subnet=172.18.0.0/16 --gateway=172.18.0.1
'';
};
networking.firewall.extraCommands = ''
iptables -A INPUT -p icmp --source 100.89.128.0/24 -j ACCEPT
iptables -A INPUT -p tcp --source 172.18.0.0/12 --dport 22 -j ACCEPT
'';
};
}

View file

@ -5,6 +5,7 @@
}: { }: {
# do garbage collection weekly to keep disk usage low # do garbage collection weekly to keep disk usage low
nix = { nix = {
package = pkgs.nix;
settings = { settings = {
experimental-features = ["nix-command" "flakes"]; experimental-features = ["nix-command" "flakes"];
}; };

43
modules/pangolin.nix Normal file
View file

@ -0,0 +1,43 @@
{
pkgs-unstable,
...
}: {
services = {
pangolin = {
enable = true;
package = pkgs-unstable.fosrl-pangolin;
openFirewall = true;
settings = {
app = {
save_logs = true;
log_failed_attempts = true;
};
domains = {
domain1 = {
prefer_wildcard_cert = true;
};
};
flags = {
disable_signup_without_invite = true;
disable_user_create_org = true;
};
};
};
};
}
# Settings needed on the host
#
# services = {
# pangolin = {
# dnsProvider = "";
# baseDomain = "";
# letsEncryptEmail = "";
# environmentFile = config.age.secrets."".path;
# };
# traefik = {
# environmentFiles = [ config.age.secrets."".path ];
# };
# };

221
modules/traefik.nix Normal file
View file

@ -0,0 +1,221 @@
{
pkgs,
config,
lib,
...
}:
let
cfg = config.services.traefik-docker;
mapOidcClientNameToEnv = stringToReplace: lib.replaceString "-" "_" (lib.toUpper stringToReplace);
traefik-mtls-config = (pkgs.formats.yaml { }).generate "traefik-mtls-config" {
tls.options.default.clientAuth = {
caFiles = "caFiles/root_ca.crt";
clientAuthType = "VerifyClientCertIfGiven";
};
};
in {
options.services.traefik-docker = {
enable = lib.mkEnableOption "traefik web server hosted as OCI container";
dashboardUrl = lib.mkOption {
description = "External URL the traefik dashboard will be reachable from, without protocol";
type = lib.types.str;
};
dnsSecrets = lib.mkOption {
description = "Secrets for DNS providers.";
type = lib.types.listOf lib.types.anything;
};
mTLSCaCertSecret = lib.mkOption {
description = "Agenix secret containing the CA file to verify client certificates against.";
};
oidcAuthProviderUrl = lib.mkOption {
description = "Provider URL of OIDC auth provider.";
type = lib.types.str;
};
oidcClients = lib.mkOption {
example = ''
immich = {
scopes = [
"openid"
"email"
"profile"
];
enableBypassUsingClientCertificate = true;
usePkce = true;
};
'';
description = "Attribute set of OIDC clients with their configurations.";
type = lib.types.attrsOf (
lib.types.submodule {
options = {
secret = lib.mkOption {
description = ''Agenix secret containing the following needed environment variables in dotenv notation:
- <clientName>_OIDC_AUTH_SECRET
- <clientName>_OIDC_AUTH_PROVIDER_CLIENT_ID
- <clientName>_OIDC_CLIENT_SECRET
'';
};
scopes = lib.mkOption {
default = [ "openid" ];
example = [ "openid" "email" "profile" "groups" ];
description = "OIDC scopes to request from auth provider.";
type = lib.types.listOf lib.types.str;
};
usePkce = lib.mkOption {
default = true;
description = "Whether to enable PKCE for this provider.";
type = lib.types.bool;
};
enableBypassUsingClientCertificate = lib.mkOption {
default = false;
description = "Whether to allow bypassing OIDC protection when a verified client certificate is presented.";
type = lib.types.bool;
};
useClaimsFromUserInfo = lib.mkOption {
default = false;
description = "When enabled, an additional request to the provider's userinfo_endpoint is made to validate the token and to retrieve additional claims. The userinfo claims are merged directly into the token claims, with userinfo values overriding token values for non-security-critical claims.";
type = lib.types.bool;
};
headers = lib.mkOption {
default = [];
description = "Headers to be added to the upstream request. Templating is possible. Documentation can be found here: https://traefik-oidc-auth.sevensolutions.cc/docs/getting-started/middleware-configuration";
type = lib.types.listOf (lib.types.submodule {
options = {
Name = lib.mkOption {
description = "The name of the header which should be added to the upstream request.";
type = lib.types.str;
};
Value = lib.mkOption {
description = "The value of the header, which can use Go-Templates.";
type = lib.types.str;
};
};
});
};
};
}
);
};
};
config = lib.mkIf cfg.enable {
virtualisation.oci-containers.containers = {
traefik = {
image = "traefik:v3.6.6";
cmd = [
"--providers.docker=true"
"--providers.docker.exposedByDefault=false"
"--providers.docker.network=traefik"
"--providers.file.directory=/dynamic-config"
"--log.level=INFO"
"--api=true"
"--ping=true"
"--entrypoints.web.address=:80"
"--entrypoints.websecure.address=:443"
"--entrypoints.websecure.transport.respondingTimeouts.readTimeout=600s"
"--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=600s"
"--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=600s"
"--entrypoints.web.http.redirections.entrypoint.to=websecure"
"--entrypoints.websecure.asDefault=true"
"--entrypoints.websecure.http.middlewares=strip-mtls-headers@docker,pass-tls-client-cert@docker"
"--entrypoints.websecure.http.tls.certresolver=letsencrypt"
"--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
"--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=netcup"
"--experimental.plugins.traefik-oidc-auth.modulename=github.com/sevensolutions/traefik-oidc-auth"
"--experimental.plugins.traefik-oidc-auth.version=v0.17.0"
];
autoStart = true;
ports = [
"80:80"
"443:443"
];
networks = [
"traefik"
];
environment = {
OIDC_AUTH_PROVIDER_URL = cfg.oidcAuthProviderUrl;
};
environmentFiles = lib.forEach cfg.dnsSecrets (secret: secret.path) ++ (lib.mapAttrsToList (oidcClientName: oidcClientConfig: oidcClientConfig.secret.path) cfg.oidcClients);
labels = {
"traefik.enable" = "true";
"traefik.http.routers.dashboard.rule" = "Host(`${cfg.dashboardUrl}`)";
"traefik.http.routers.dashboard.service" = "dashboard@internal";
"traefik.http.routers.dashboard.middlewares" = "traefik-dashboard-oidc-auth@file";
"traefik.http.routers.api.rule" = "Host(`${cfg.dashboardUrl}`) && (PathPrefix(`/api`) || PathPrefix(`/oidc/callback`))";
"traefik.http.routers.api.service" = "api@internal";
"traefik.http.routers.api.middlewares" = "traefik-dashboard-oidc-auth@file";
"traefik.http.middlewares.strip-mtls-headers.headers.customrequestheaders.X-Forwarded-Tls-Client-Cert" = "";
"traefik.http.middlewares.pass-tls-client-cert.passtlsclientcert.pem" = "true";
};
volumes = let
oidc-config = lib.mapAttrs' (
oidcClientName: oidcClientConfig:
lib.nameValuePair "${oidcClientName}-oidc-auth" {
plugin.traefik-oidc-auth = {
LogLevel = "INFO";
Secret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_SECRET" }}'';
Provider = {
Url = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
ClientId = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_ID" }}'';
ClientSecret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_SECRET" }}'';
UsePkce = oidcClientConfig.usePkce;
UseClaimsFromUserInfo = oidcClientConfig.useClaimsFromUserInfo;
};
Scopes = oidcClientConfig.scopes;
LoginUrl = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
} // (lib.attrsets.optionalAttrs oidcClientConfig.enableBypassUsingClientCertificate {
BypassAuthenticationRule = "HeaderRegexp(`X-Forwarded-Tls-Client-Cert`, `.+`)";
}) // (lib.attrsets.optionalAttrs ((lib.length oidcClientConfig.headers) > 0) {
Headers = oidcClientConfig.headers;
});
}
) cfg.oidcClients;
traefik-oidc-authentication-config = (pkgs.formats.yaml {}).generate "traefik-oidc-auth" {
http.middlewares = oidc-config;
};
in [
"/var/run/docker.sock:/var/run/docker.sock"
"${traefik-oidc-authentication-config}:/dynamic-config/traefik-oidc-auth.yaml:ro"
"${traefik-mtls-config}:/dynamic-config/traefik-mtls.yaml:ro"
"${cfg.mTLSCaCertSecret.path}:/caFiles/root_ca.crt:ro"
];
extraOptions = [
''--mount=type=volume,source=certs,target=/certs,volume-driver=local''
"--add-host=host.docker.internal:host-gateway"
"--health-cmd=wget --spider --quiet http://localhost:8080/ping"
"--health-interval=10s"
"--health-timeout=5s"
"--health-retries=3"
"--health-start-period=5s"
];
};
};
systemd.services."docker-traefik" = {
after = [
"docker-network-traefik.service"
];
requires = [
"docker-network-traefik.service"
];
};
systemd.services."docker-network-traefik" = {
path = [ pkgs.docker ];
serviceConfig = {
Type = "oneshot";
};
script = ''
docker network inspect traefik || docker network create traefik --ipv4 --ipv6 --subnet=172.18.0.0/16 --gateway=172.18.0.1
'';
};
networking.firewall.extraCommands = "iptables -t nat -I PREROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j MASQUERADE";
};
}

View file

@ -6,7 +6,10 @@
virtualisation = { virtualisation = {
libvirtd = { libvirtd = {
enable = true; enable = true;
qemu.swtpm.enable = true; qemu = {
swtpm.enable = true;
vhostUserPackages = [ pkgs.virtiofsd ];
};
}; };
spiceUSBRedirection.enable = true; spiceUSBRedirection.enable = true;
}; };