30 Commits

Author SHA1 Message Date
4097e02d09 [nidaros] Update Forgejo runner token 2025-10-18 13:17:32 +00:00
5f064118e6 [nidaros] Use 25.11 Unstable 2025-10-18 13:17:17 +00:00
a4a9b70a39 [shared] Home-manager unstable and fix nixpkgs unstable on system 2025-10-18 13:16:19 +00:00
ca2c627815 [shared] Remove problematic ssh extraHostnames 2025-10-18 14:24:57 +02:00
8ea8cf381b [shared] Merge knownSystems into systems attrSet 2025-10-18 13:49:54 +02:00
c07940e86f [shared] Allow systems to run on unstable 2025-10-18 13:46:41 +02:00
ddb8f8cfb5 [nidaros] Update Forgejo to latest version 2025-10-18 11:36:29 +00:00
2195c208ae [pi4] Add proxy to Forgejo and disable Home-assistant 2025-10-18 11:21:22 +00:00
6ff59b7c22 [nidaros] Add Forgejo and Podman 2025-10-14 19:32:40 +00:00
07fc2acecc [pi4] Add proxy to keycloak 2025-10-14 18:36:16 +00:00
3eaa836098 [nidaros] Add Keycloak 2025-10-14 18:35:15 +00:00
0109aeec8a [shared] Move git signing key to systemConfig 2025-10-14 20:15:41 +02:00
9434f32e06 [nidaros] Add signing key to systemConfig 2025-10-14 20:11:05 +02:00
af54dea18a [shared] Refactor systems 2025-10-14 20:11:04 +02:00
7cbab15cc9 [nidaros] Add Postgres config 2025-10-14 18:09:43 +00:00
e3df55c8fd [nidaros] Add gpg signing key 2025-10-14 18:08:39 +00:00
b807fd578d [nidaros] Re-encrypt secrets 2025-10-14 19:30:44 +02:00
33f99f1406 [nidaros] Update nidaros config 2025-10-14 18:24:56 +02:00
7ef07ac32a [nidaros] Add missing boot import 2025-10-14 17:49:00 +02:00
a032fc0f14 [shared] Add experimental flag to commands 2025-10-14 17:45:56 +02:00
ac2b847118 [nidaros] Update hardware.nix 2025-10-14 17:45:03 +02:00
61676ed77c [nidaros] Add boot config and remove configuration.nix 2025-10-13 22:25:54 +02:00
1fc1b0e7be [nidaros] Update ssh and age 2025-10-13 21:55:19 +02:00
b1dd673fc5 [nidaros] Copy security config from pi4 2025-10-13 21:40:13 +02:00
e7240d511e [nidaros] Update ssh and age 2025-10-13 21:16:24 +02:00
cfb4131cf3 [nidaros] Add initial Nidaros homelab config 2025-10-08 20:07:14 +02:00
dcfa416eb6 [shared] Re-encrypt sops secrets 2025-10-07 21:39:03 +02:00
110684c713 [shared] Add Nidaros public age key 2025-10-07 21:38:10 +02:00
fb2f8a8888 📦 [shared] Update dependencies 2025-10-04 18:29:38 +02:00
ee2e14ee47 [shared] Set default branch in git to main and disable advice 2025-10-03 17:21:06 +02:00
26 changed files with 502 additions and 318 deletions

View File

@@ -2,6 +2,7 @@ keys:
- &thinkpad age1j66v6z6hlsgqjfv5fz7fldm5q9jay4j5v5du6ymfda6hv40nsqesg89g7p - &thinkpad age1j66v6z6hlsgqjfv5fz7fldm5q9jay4j5v5du6ymfda6hv40nsqesg89g7p
- &desktop age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w - &desktop age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w
- &pi4 age1xlnprpvshv93eerthxzg6cahklsfc4efh8dd6u8dte9u6cl0u5qsz48qlt - &pi4 age1xlnprpvshv93eerthxzg6cahklsfc4efh8dd6u8dte9u6cl0u5qsz48qlt
- &nidaros age1sf8tspnmyj2cn6gmzdfuh2vt00tmeqa0vf23rn5s44s9avafsd7sz6wgql
creation_rules: creation_rules:
- path_regex: shared/secrets/secrets.yaml$ - path_regex: shared/secrets/secrets.yaml$
key_groups: key_groups:
@@ -9,3 +10,4 @@ creation_rules:
- *thinkpad - *thinkpad
- *desktop - *desktop
- *pi4 - *pi4
- *nidaros

39
flake.lock generated
View File

@@ -119,6 +119,26 @@
"type": "github" "type": "github"
} }
}, },
"home-manager-unstable": {
"inputs": {
"nixpkgs": [
"nixpkgs-unstable"
]
},
"locked": {
"lastModified": 1760662441,
"narHash": "sha256-mlDqR1Ntgs9uYYEAUR1IhamKBO0lxoNS4zGLzEZaY0A=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "722792af097dff5790f1a66d271a47759f477755",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "home-manager",
"type": "github"
}
},
"home-manager_2": { "home-manager_2": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -206,11 +226,11 @@
}, },
"nixpkgs_2": { "nixpkgs_2": {
"locked": { "locked": {
"lastModified": 1757020766, "lastModified": 1759439645,
"narHash": "sha256-PLoSjHRa2bUbi1x9HoXgTx2AiuzNXs54c8omhadyvp0=", "narHash": "sha256-oiAyQaRilPk525Z5aTtTNWNzSrcdJ7IXM0/PL3CGlbI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "fe83bbdde2ccdc2cb9573aa846abe8363f79a97a", "rev": "879bd460b3d3e8571354ce172128fbcbac1ed633",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -256,6 +276,7 @@
"inputs": { "inputs": {
"catppuccin": "catppuccin", "catppuccin": "catppuccin",
"home-manager": "home-manager", "home-manager": "home-manager",
"home-manager-unstable": "home-manager-unstable",
"nixpkgs": "nixpkgs_2", "nixpkgs": "nixpkgs_2",
"nixpkgs-stable": "nixpkgs-stable", "nixpkgs-stable": "nixpkgs-stable",
"nixpkgs-unstable": "nixpkgs-unstable", "nixpkgs-unstable": "nixpkgs-unstable",
@@ -316,11 +337,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1756614537, "lastModified": 1759444170,
"narHash": "sha256-qyszmZO9CEKAlj5NBQo1AIIADm5Fgqs5ZggW1sU1TVo=", "narHash": "sha256-b5ShONncU4Gf39QtaL5OySC9G2o612rTE/TCwx3kMeM=",
"owner": "Gerg-L", "owner": "Gerg-L",
"repo": "spicetify-nix", "repo": "spicetify-nix",
"rev": "374eb5d97092b97f7aaafd58a2012943b388c0df", "rev": "e13267e8f3eb1664329fcb78a43b38b985f96f6f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -350,11 +371,11 @@
"nixpkgs": "nixpkgs_4" "nixpkgs": "nixpkgs_4"
}, },
"locked": { "locked": {
"lastModified": 1757142986, "lastModified": 1759584043,
"narHash": "sha256-HB01usaR5wg5LK3lV6S7Za2x4AfKrNceOnun/mlpChk=", "narHash": "sha256-YCuCmg9nRLrtTz7Zex94C8kYzh8hoSzPOA72kMLpuxM=",
"owner": "0xc000022070", "owner": "0xc000022070",
"repo": "zen-browser-flake", "repo": "zen-browser-flake",
"rev": "ed4bfefc49ef23e55b4f6e39d2e297a79f5ab2df", "rev": "176555a4128ce90461354142ab85c7f536bfd267",
"type": "github" "type": "github"
}, },
"original": { "original": {

201
flake.nix
View File

@@ -19,6 +19,11 @@
inputs.nixpkgs.follows = "nixpkgs"; inputs.nixpkgs.follows = "nixpkgs";
}; };
home-manager-unstable = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs-unstable";
};
# #
# ========= Utilities ========= # ========= Utilities =========
# #
@@ -43,7 +48,9 @@
{ {
self, self,
nixpkgs, nixpkgs,
nixpkgs-unstable,
home-manager, home-manager,
home-manager-unstable,
... ...
}@inputs: }@inputs:
let let
@@ -59,61 +66,9 @@
"aarch64-linux" "aarch64-linux"
]; ];
# ========== Extend lib with lib.custom ========== systems = import ./systems.nix {
# NOTE: This approach allows lib.custom to propagate into hm inherit common;
# see: https://github.com/nix-community/home-manager/pull/3454
customLib = (_self: _super: { custom = import ./lib { inherit (nixpkgs) lib; }; });
lib = nixpkgs.lib.extend customLib;
libHm = home-manager.lib.extend customLib;
systems = builtins.map (config: defaultAttrs // config) [
{
hostName = "desktop";
nvidia.enable = true;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMSzXyTuQyTrWsfORQbvgrqt/33+hfSUDXeMg6D1T2wz";
}
{
hostName = "thinkpad";
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNlHKE/BD8kKfhJD7GBk1A3whZf3gTjk9VEgGAj3qsH";
}
{
hostName = "pi4";
system = "aarch64-linux";
wayland.enable = false;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJE9m7YiITe1sDqSZ7Pa8luIw3WToLsypixZEqE4wCQE";
address.private = common.localIpAddr 188;
}
{
hostName = "homelab";
wayland.enable = false;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIARDv5nRlfPDXdV+Db4FaqeSJZ3/3MO0frYGzuVeqYAl";
address.private = common.localIpAddr 231;
address.tailnet = common.tailnetAddr "admin";
}
];
defaultAttrs = {
hostName = builtins.abort "hostName is required";
system = "x86_64-linux";
username = common.username;
version = common.system.version;
wayland.enable = true;
nvidia.enable = false;
}; };
knownSystems = [
{
# Samsung S23 FE
hostName = "localhost-y4maoyqm";
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII7SSjiqnjif1Kko60iXVTKJ7a1/lRlR8TFNtoclNcnQ";
}
{
# OnePlus 8
hostName = "localhost-4izgka9k";
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIALtulVgLrUEpKnpfPFQTHjaEXTxs2Q818NC18eLx0bj";
}
];
in in
{ {
# #
@@ -125,75 +80,81 @@
# #
# ========= Host Configurations ========= # ========= Host Configurations =========
# #
nixosConfigurations = builtins.listToAttrs ( nixosConfigurations = builtins.mapAttrs (
builtins.map ( hostName:
{ {
hostName, system,
system, username,
username, nixos,
... ...
}@systemConfig: }@systemConfig:
{ let
name = hostName; pkgs = if nixos.channel == "stable" then nixpkgs else nixpkgs-unstable;
value = nixpkgs.lib.nixosSystem { hm = if nixos.channel == "stable" then home-manager else home-manager-unstable;
inherit system; # ========== Extend lib with lib.custom ==========
specialArgs = { # NOTE: This approach allows lib.custom to propagate into hm
inherit # see: https://github.com/nix-community/home-manager/pull/3454
outputs customLib = (_self: _super: { custom = import ./lib { inherit (pkgs) lib; }; });
inputs lib = pkgs.lib.extend customLib;
common libHm = hm.lib.extend customLib;
theme in
lib pkgs.lib.nixosSystem {
systemConfig inherit system;
systems specialArgs = {
knownSystems inherit
; outputs
isDarwin = false; inputs
common
theme
lib
hostName
systemConfig
systems
;
isDarwin = false;
};
modules = [
./hosts/${hostName}
hm.nixosModules.home-manager
{
home-manager = {
# Backups conflicting files in case of error
backupFileExtension = "bkp";
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit
inputs
common
theme
libHm
systemConfig
systems
;
};
users.${username} = import ./hosts/${hostName}/home-manager;
}; };
modules = [ }
./hosts/${hostName} {
home-manager.nixosModules.home-manager nixpkgs.overlays = [
{ # TODO temp fix for tailscale: https://github.com/tailscale/tailscale/issues/16966#issuecomment-3239543750
home-manager = { (_: prev: {
# Backups conflicting files in case of error tailscale = prev.tailscale.overrideAttrs (old: {
backupFileExtension = "bkp"; checkFlags = builtins.map (
useGlobalPkgs = true; flag:
useUserPackages = true; if prev.lib.hasPrefix "-skip=" flag then
extraSpecialArgs = { flag + "|^TestGetList$|^TestIgnoreLocallyBoundPorts$|^TestPoller$"
inherit else
inputs flag
common ) old.checkFlags;
theme });
libHm })
systemConfig
systems
;
};
users.${username} = import ./hosts/${hostName}/home-manager;
};
}
{
nixpkgs.overlays = [
# TODO temp fix for tailscale: https://github.com/tailscale/tailscale/issues/16966#issuecomment-3239543750
(_: prev: {
tailscale = prev.tailscale.overrideAttrs (old: {
checkFlags = builtins.map (
flag:
if prev.lib.hasPrefix "-skip=" flag then
flag + "|^TestGetList$|^TestIgnoreLocallyBoundPorts$|^TestPoller$"
else
flag
) old.checkFlags;
});
})
];
}
]; ];
}; }
} ];
) systems }
); ) systems;
# #
# ========= Formatting ========= # ========= Formatting =========

View File

@@ -9,6 +9,4 @@
./hyprpaper.nix ./hyprpaper.nix
./settings.nix ./settings.nix
]; ];
programs.git.signing.key = "706F53DD087A91DE";
} }

6
hosts/nidaros/boot.nix Normal file
View File

@@ -0,0 +1,6 @@
{
boot.loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
}

16
hosts/nidaros/default.nix Normal file
View File

@@ -0,0 +1,16 @@
{ lib, ... }:
{
imports = with lib.custom; [
(relativeToBase "modules")
./boot.nix
./forgejo.nix
./hardware.nix
./keycloak.nix
./podman.nix
./postgres.nix
./security
];
programs.nh.flake = lib.mkForce null;
}

74
hosts/nidaros/forgejo.nix Normal file
View File

@@ -0,0 +1,74 @@
{
config,
pkgs,
lib,
common,
...
}:
let
domain = "beta.code.${common.domain}";
passwordKey = "forgejo/admin-pass";
runnerTokenKey = "forgejo/runner-token";
in
{
services = {
forgejo = {
enable = true;
package = pkgs.forgejo;
database.type = "postgres";
# Enable support for Git Large File Storage
lfs.enable = true;
settings = {
server = {
DOMAIN = domain;
# You need to specify this to remove the port from URLs in the web UI.
ROOT_URL = "https://${domain}/";
HTTP_PORT = 8002;
};
# You can temporarily allow registration to create an admin user.
service.DISABLE_REGISTRATION = true;
# Add support for actions, based on act: https://github.com/nektos/act
actions = {
ENABLED = true;
DEFAULT_ACTIONS_URL = "github";
};
# TODO set up mailer
};
};
gitea-actions-runner = {
package = pkgs.forgejo-actions-runner;
instances.default = {
enable = true;
name = "monolith";
url = "https://${domain}";
# Obtaining the path to the runner token file may differ
# tokenFile should be in format TOKEN=<secret>, since it's EnvironmentFile for systemd
tokenFile = config.sops.secrets.${runnerTokenKey}.path;
labels = [
"docker:docker://node:22-bullseye"
"native:host"
];
};
};
};
sops.secrets = {
${passwordKey}.owner = "forgejo";
${runnerTokenKey}.owner = "forgejo";
};
# Create a single admin user / update password if exists
systemd.services.forgejo.preStart =
let
adminCmd = "${lib.getExe config.services.forgejo.package} admin user";
pwd = config.sops.secrets.${passwordKey};
user = "martin"; # Note, Forgejo doesn't allow creation of an account named "admin"
email = "git@${common.domain}";
in
''
${adminCmd} create --admin --email "${email}" --username ${user} --password "$(tr -d '\n' < ${pwd.path})" || true
## Alter an existing user. Will prompt new password on login
# ${adminCmd} change-password --username ${user} --password "$(tr -d '\n' < ${pwd.path})" || true
'';
}

View File

@@ -0,0 +1,53 @@
# 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,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [
"xhci_pci"
"ahci"
"nvme"
"usb_storage"
"usbhid"
"sd_mod"
];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" = {
device = "/dev/disk/by-uuid/dfade67a-9cbe-4002-990a-2cd22b8e57fa";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/66F7-BE0A";
fsType = "vfat";
options = [
"fmask=0077"
"dmask=0077"
];
};
swapDevices = [ ];
# 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.eno1.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View File

@@ -0,0 +1,7 @@
{ lib, ... }:
{
imports = with lib.custom; [
(relativeToBase "home-manager")
];
}

View File

@@ -0,0 +1,27 @@
{ config, common, ... }:
let
port = 8081;
domain = "iam.${common.domain}";
dbPassKey = "keycloak/database-pass";
in
{
services = {
keycloak = {
enable = true;
settings = {
hostname = "https://${domain}";
http-port = port;
http-enabled = true;
};
database = {
type = "postgresql";
createLocally = true;
port = config.services.postgresql.settings.port;
passwordFile = config.sops.secrets.${dbPassKey}.path;
};
initialAdminPassword = "changeme";
};
};
sops.secrets.${dbPassKey} = { };
}

23
hosts/nidaros/podman.nix Normal file
View File

@@ -0,0 +1,23 @@
{ pkgs, ... }:
{
virtualisation = {
# Enable common container config files in /etc/containers
containers.enable = true;
podman = {
enable = true;
# Create a `docker` alias for podman, to use it as a drop-in replacement
dockerCompat = true;
# Required for containers under podman-compose to be able to talk to each other.
defaultNetwork.settings.dns_enabled = true;
};
};
# Useful other development tools
environment.systemPackages = with pkgs; [
podman-tui # status of containers in the terminal
podman-compose # start group of containers for dev
];
}

View File

@@ -0,0 +1,13 @@
{ pkgs, ... }:
{
services.postgresql = {
enable = true;
authentication = pkgs.lib.mkOverride 10 ''
#type database DBuser url auth-method
local all all trust
# ipv4
host all all 127.0.0.1/32 trust
'';
};
}

View File

@@ -0,0 +1,22 @@
{ systemConfig, ... }:
{
imports = [
./firewall.nix
];
security.sudo.extraRules = [
{
users = [ systemConfig.username ];
runAs = "ALL:ALL";
commands = [
{
command = "ALL";
options = [ "NOPASSWD" ];
}
];
}
];
services.pcscd.enable = true;
}

View File

@@ -0,0 +1,17 @@
{ common, ... }:
{
networking = {
firewall = {
enable = true;
allowedTCPPorts = [
80
443
];
extraInputRules = ''
ip saddr ${common.localIpRange} accept
'';
};
nftables.enable = true;
};
}

View File

@@ -7,10 +7,10 @@
./boot.nix ./boot.nix
./caddy.nix ./caddy.nix
./ddclient.nix ./ddclient.nix
./forgejo.nix # ./forgejo.nix
./hardware.nix ./hardware.nix
./headscale.nix ./headscale.nix
./home-assitant.nix # ./home-assitant.nix
./keycloak.nix ./keycloak.nix
./mailserver.nix ./mailserver.nix
./nextcloud.nix ./nextcloud.nix

View File

@@ -4,6 +4,4 @@
imports = with lib.custom; [ imports = with lib.custom; [
(relativeToBase "home-manager") (relativeToBase "home-manager")
]; ];
programs.git.signing.key = "E3FA0E995C0D0E5E";
} }

View File

@@ -1,14 +1,8 @@
{ { config, common, ... }:
config,
common,
pkgs,
...
}:
let let
port = 8086; port = 8086;
domain = "beta.auth.${common.domain}"; domain = "beta.auth.${common.domain}";
dbPassKey = "keycloak/database-pass"; dbPassKey = "keycloak/database-pass";
forgejoClientSecretKey = "keycloak/realms/forgejo/client/secret";
in in
{ {
@@ -27,97 +21,6 @@ in
passwordFile = config.sops.secrets.${dbPassKey}.path; passwordFile = config.sops.secrets.${dbPassKey}.path;
}; };
initialAdminPassword = "changeme"; initialAdminPassword = "changeme";
realmFiles = [
# (
# let
# name = "Default";
# in
# pkgs.writeText "${name}.json" (
# builtins.toJSON {
# realm = name;
# enabled = true;
# clients = [
# rec {
# enabled = true;
# clientId = "forgejo";
# name = "Forgejo Beta";
# description = "";
# rootUrl = "https://${config.services.forgejo.settings.server.DOMAIN}";
# adminUrl = rootUrl;
# baseUrl = rootUrl;
# surrogateAuthRequired = false;
# alwaysDisplayInConsole = true;
# clientAuthenticatorType = "client-secret";
# # secret = readFile config.sops.secrets.${forgejoClientSecretKey}.path;
# redirectUris = [ "${rootUrl}/*" ];
# webOrigins = [ rootUrl ];
# notBefore = 0;
# bearerOnly = false;
# consentRequired = false;
# standardFlowEnabled = true;
# implicitFlowEnabled = false;
# directAccessGrantsEnabled = false;
# serviceAccountsEnabled = false;
# publicClient = false;
# frontchannelLogout = true;
# protocol = "openid-connect";
# attributes = {
# "realm_client" = "false";
# "oidc.ciba.grant.enabled" = "false";
# "client.secret.creation.time" = "1758824229";
# "backchannel.logout.session.required" = "true";
# "standard.token.exchange.enabled" = "false";
# "frontchannel.logout.session.required" = "true";
# "display.on.consent.screen" = "false";
# "oauth2.device.authorization.grant.enabled" = "false";
# "backchannel.logout.revoke.offline.tokens" = "false";
# };
# authenticationFlowBindingOverrides = { };
# fullScopeAllowed = true;
# nodeReRegistrationTimeout = -1;
# defaultClientScopes = [
# "web-origins"
# "offline_access"
# "profile"
# "roles"
# "basic"
# "email"
# ];
# optionalClientScopes = [
# "acr"
# "address"
# "phone"
# "organization"
# "microprofile-jwt"
# ];
# access = {
# view = true;
# configure = true;
# manage = true;
# };
# }
# ];
# users = [
# {
# enabled = true;
# firstName = "Christian";
# lastName = "Bauer";
# username = "cbauer";
# email = "cbauer@localhost";
# credentials = [
# {
# type = "password";
# temporary = false;
# value = "changeme";
# }
# ];
# }
# ];
# }
# )
# )
];
}; };
nginx.virtualHosts.${domain} = { nginx.virtualHosts.${domain} = {
@@ -126,8 +29,5 @@ in
locations."/".proxyPass = "http://localhost:${toString port}"; locations."/".proxyPass = "http://localhost:${toString port}";
}; };
}; };
sops.secrets = { sops.secrets.${dbPassKey} = { };
${dbPassKey} = { };
${forgejoClientSecretKey} = { };
};
} }

View File

@@ -15,7 +15,9 @@ let
inherit locations; inherit locations;
}; };
homelab = "http://${common.localIpAddr 231}"; homelab = "http://${common.localIpAddr 231}";
homelabProxy = proxyTo homelab; # TODO get homelab local ip from systems nidaros = "http://${common.localIpAddr 228}";
homelabProxy = proxyTo homelab; # TODO get local ip from systems attrSet
nidarosProxy = proxyTo nidaros;
redirect = subdomain: { redirect = subdomain: {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
@@ -38,6 +40,7 @@ in
"kitchenowl.${domain}" = redirect "grocery"; "kitchenowl.${domain}" = redirect "grocery";
# Gitea # Gitea
"code.${domain}" = homelabProxy 3000; "code.${domain}" = homelabProxy 3000;
"beta.code.${domain}" = nidarosProxy 8002;
# Nextcloud # Nextcloud
"nextcloud.${domain}" = proxyLocations { "nextcloud.${domain}" = proxyLocations {
"/".proxyPass = "${homelab}:11000"; "/".proxyPass = "${homelab}:11000";
@@ -85,6 +88,7 @@ in
# Donetick # Donetick
"chore.${domain}" = homelabProxy 2021; "chore.${domain}" = homelabProxy 2021;
"recurring-events-api.${domain}" = homelabProxy 8095; "recurring-events-api.${domain}" = homelabProxy 8095;
"iam.${domain}" = nidarosProxy 8081;
}; };
}; };

View File

@@ -9,6 +9,4 @@
./hyprland ./hyprland
./zen ./zen
]; ];
programs.git.signing.key = "848D71DE0590C199";
} }

View File

@@ -69,11 +69,11 @@ generate-ssh:
# Generate a new age key from an existing ssh key (without passphrase) # Generate a new age key from an existing ssh key (without passphrase)
generate-age-from-ssh: generate-age-from-ssh:
mkdir -p ~/.config/sops/age mkdir -p ~/.config/sops/age
nix run nixpkgs#ssh-to-age -- -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt nix run nixpkgs#ssh-to-age --experimental-features 'nix-command flakes' -- -private-key -i ~/.ssh/id_ed25519 > ~/.config/sops/age/keys.txt
# Get a public age key from an existing age private key # Get a public age key from an existing age private key
get-public-age-key: get-public-age-key:
nix shell nixpkgs#age -c age-keygen -y ~/.config/sops/age/keys.txt nix shell nixpkgs#age --experimental-features 'nix-command flakes' -c age-keygen -y ~/.config/sops/age/keys.txt
# Get the public ssh key from the current user # Get the public ssh key from the current user
get-public-ssh-key: get-public-ssh-key:
@@ -81,7 +81,7 @@ get-public-ssh-key:
# Edit the SOPS secrets file # Edit the SOPS secrets file
edit-secrets: edit-secrets:
nix run nixpkgs#sops -- shared/secrets/secrets.yaml nix run nixpkgs#sops --experimental-features 'nix-command flakes' -- shared/secrets/secrets.yaml
# Hash a string using the mkpasswd command # Hash a string using the mkpasswd command
hash PASS: hash PASS:

View File

@@ -1,4 +1,9 @@
{ pkgs, common, ... }: {
pkgs,
common,
systemConfig,
...
}:
{ {
home.packages = with pkgs; [ home.packages = with pkgs; [
@@ -23,9 +28,14 @@
p = "push"; p = "push";
}; };
signing.signByDefault = true; signing = {
signByDefault = true;
key = systemConfig.git.signing.key;
};
extraConfig = { extraConfig = {
init.defaultBranch = "main";
advice.defaultBranchName = false;
pull.rebase = true; pull.rebase = true;
push.autoSetupRemote = true; push.autoSetupRemote = true;
safe.directory = "/etc/nixos"; safe.directory = "/etc/nixos";

View File

@@ -5,28 +5,24 @@
common, common,
... ...
}: }:
with builtins;
{ {
programs.ssh = { programs.ssh = {
enable = true; enable = true;
matchBlocks = listToAttrs ( matchBlocks = builtins.mapAttrs (
map (system: { hostName: system:
name = system.hostName; let
value = _hostName =
let if (system ? address && system.address ? tailnet) then
hostName = system.address.tailnet
if (system ? address && system.address ? tailnet) then else
system.address.tailnet common.tailnetAddr hostName;
else in
common.tailnetAddr system.hostName; {
in port = 22;
{ user = systemConfig.username;
port = 22; hostname = _hostName;
user = systemConfig.username; }
hostname = hostName; ) systems;
};
}) systems
);
}; };
} }

View File

@@ -1,4 +1,4 @@
{ pkgs, systemConfig, ... }: { pkgs, hostName, ... }:
{ {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
@@ -7,7 +7,7 @@
networking = { networking = {
networkmanager.enable = true; networkmanager.enable = true;
hostName = systemConfig.hostName; hostName = hostName;
}; };
programs.ssh.enableAskPassword = false; programs.ssh.enableAskPassword = false;

View File

@@ -1,33 +1,15 @@
# /nix/store/<hash>/etc/ssh/ssh_config & /nix/store/<hash>/etc/ssh/authorized_keys # /nix/store/<hash>/etc/ssh/ssh_config & /nix/store/<hash>/etc/ssh/authorized_keys
{ {
lib,
systemConfig, systemConfig,
systems, systems,
knownSystems,
common,
... ...
}: }:
with builtins;
let
allSystems = knownSystems ++ systems;
in
{ {
programs.ssh.knownHosts = listToAttrs ( programs.ssh.knownHosts = builtins.mapAttrs (hostName: system: {
map (system: { publicKey = system.ssh.publicKey;
name = system.hostName; }) systems;
value = {
extraHostNames = [
(
if (system ? address && system.address ? tailnet) then
system.address.tailnet
else
common.tailnetAddr system.hostName
)
];
publicKey = system.ssh.publicKey;
};
}) allSystems
);
users.users.${systemConfig.username}.openssh.authorizedKeys.keys = ( users.users.${systemConfig.username}.openssh.authorizedKeys.keys = (
map (system: system.ssh.publicKey) allSystems lib.mapAttrsToList (_hostName: system: system.ssh.publicKey) systems
); );
} }

View File

@@ -1,50 +1,55 @@
cloudflare: cloudflare:
api-token: ENC[AES256_GCM,data:UfTphnoN4REAue0bP5JKPfgvq36Jlxndl7dD46BKwg7ygW2Mj4mm4w==,iv:vS223ZAqACt1ZHJHCeztCVm+BghMhVYJfTuvBlySf+o=,tag:mxf6jL7/ItsxPOHb7S5upQ==,type:str] api-token: ENC[AES256_GCM,data:vmmPUCCJJPa1ElN9njBHKjESGrE34oycJIjTmZfScN+zI3VpYeNi0A==,iv:P3m6zrFMdPSiPJn5sdCTw/2vr+R4s98tycyO7I/qKZU=,tag:zuqrLvkjV7v5iO5tA+Rq+A==,type:str]
forgejo: forgejo:
admin-pass: ENC[AES256_GCM,data:RGTOw0Yo5rJGEVLGsQgyk9Wc,iv:SuN770eAgFIVd4pJ6vmPIvVCMqTW/2sBUYUbqym2cHo=,tag:YlyNR/fFchdBwzCuIsWGMA==,type:str] admin-pass: ENC[AES256_GCM,data:7QSF0usRgM59fTV8pf3pJdDA,iv:51Eud+ge4AXVOUNubXaY6hPYAbEL8Ue+aGlnWoJUO1g=,tag:VYtxk39yJ1NS8V3EMvZFAw==,type:str]
#ENC[AES256_GCM,data:oMpYBQ30sdCTtgxEZvYxTd9oi9QM0bYp5NisMdQHYT/nF2k=,iv:H9/g7XttJScVXV38+yHdbgWNFDhBYyudjK5BKHTt5wo=,tag:FNfkKfkKWDBUAXiGXkDchw==,type:comment] #ENC[AES256_GCM,data:QcBVOZQp1IZIICQMvYxn9NrbifM7iSvxslZWsuA6nfL/lw4=,iv:hZ0tRwf3GNCQ1+lolOdIEgXhAN2N4W4V9jV9hsDJ0iA=,tag:4TsivDKERKez8GPYPqzGaw==,type:comment]
runner-token: ENC[AES256_GCM,data:xbULBWrqosktW7XHViLH7Sk76upH31RFQNsBcXWWN7bpRadF3tpBA/hksMyEdg==,iv:v3vzUb5wsWeKWRYWT+ks4ZWGXQRhZ+td3N3bpuwoVc8=,tag:rEVoEw/QOSs8puujsRBxXQ==,type:str] runner-token: ENC[AES256_GCM,data:w2yAo3cgEm7sjnobIgPmc80THJY+RKawcKuE4wlWTzmxa+2RSObW/baEKPNI4g==,iv:E024Qu9rEc8hdW0seAwkGEB8cX+sEvQ+IPJ0vGU0Mxk=,tag:zgNidYP/zUGwSf456Fbu2w==,type:str]
keycloak: keycloak:
database-pass: ENC[AES256_GCM,data:+1lXS/wmBg/klmRqmSW3bZiZ,iv:iFYNIrBzYPBwjusHlPJj6EKDmGgGFmDLhiL+SEq6gHE=,tag:8CoF/94nyhaTHpkij59NGQ==,type:str] database-pass: ENC[AES256_GCM,data:DkJPELSSrFDb4CkKCP3l+yWy,iv:y8U+31rPGDygl8HSnKyzgSGjZ7KiIw5nFA6C349nHFc=,tag:7IiU+GJAjHJjNHg//2TjYw==,type:str]
realms: password-hash: ENC[AES256_GCM,data:vauLFR3MW4gkQdSxZiGEp+0ZN2mZH+xPGZmwqR8BgLIRBmjx6Ufq3rQwtefEwJDGTw+/fvOeaUFtj1bphKnyTf0448D2L+Uytg==,iv:45l7Vvr0ycDQScADihDuou9FJrdUgC5PxOmsIqB2J0U=,tag:/KBo0CcGYsrmkGxOR8QqTQ==,type:str]
forgejo:
client:
secret: ENC[AES256_GCM,data:CkjdtBemZd+JryPNoLA6MsGJKvYeoziOITJlZG1YhPA=,iv:yXi55RDYiwfwFde8W0EiNuo5T+ZNuuJdTOT2ydEpIXc=,tag:epXzDVifVGdasN6uHqmV+g==,type:str]
password-hash: ENC[AES256_GCM,data:FsGHBAw/z4tcBRObVlo//UotWHyHns0+vdJVgt2lfGiIfQG+1I60g2Tzgv/O+gz3oz41NIwAYf61SR9AfXhpnc1AxiZRlCBwMQ==,iv:oiJndSVZQ+00UPz0TuJXV+T8x9mtecrNDUaablOGffU=,tag:wQuow7C8KqelJOE9KqCxMA==,type:str]
mailserver: mailserver:
password-hash: ENC[AES256_GCM,data:H5PlCVuwUxIjtWbNsxb/ROkY2KiNhSwvWDvTLBfR596ijRTkaH0xtltsvHiiNHmfKERfcAXKO9EyGNHc,iv:qev1fs0PPydz8cm9D7hLp6ULgUEQJm+E0Pg86bor1to=,tag:zFnJ23NDCXeur+kvNSQV6w==,type:str] password-hash: ENC[AES256_GCM,data:zQ242cSWVoGgN92oo1NSGkfUGpQ1vnwbAunFH18fwj36FgtrMgpFNKVhijB4az4LOQPYafat9XAoOpDc,iv:e7I3l0SLIoQbQs2fvFG3iyfiFP5zfo1egebkZMcaADM=,tag:jUww/lsREg4tbzqk9j7eUA==,type:str]
nextcloud: nextcloud:
admin-pass: ENC[AES256_GCM,data:RBuuNc7J/CCJXG8n73B5cw==,iv:uKNj40SdJn6LbZoV1i9fq+5TGmRDPYVhCxAUghV4vqs=,tag:wUHBPo5T+2tyjsQFlUXDEQ==,type:str] admin-pass: ENC[AES256_GCM,data:K/rdgJ3sp96RoLsTIvcWjA==,iv:E7P+kvX1FnY09EyLdRtLw+pQEuAQKpnxsY7qOpOQJXA=,tag:XPbHOnwIN3HZrkZSuaIhvg==,type:str]
sops: sops:
age: age:
- recipient: age1j66v6z6hlsgqjfv5fz7fldm5q9jay4j5v5du6ymfda6hv40nsqesg89g7p - recipient: age1j66v6z6hlsgqjfv5fz7fldm5q9jay4j5v5du6ymfda6hv40nsqesg89g7p
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyMHl6emFJdE4rVGduT2V1 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRMXVLK0Z3ZXBnUm9DR09v
Y1hFdlRxVHJ1NlV0R2JRZm5SMVVzVmpRQlM0CjhUN0dqajNpQXg4a29Ca1VLMDJ1 Q3JTODkrbkcvS0I0WUF1NWkwdGpjSEgxUTJjCmowUUNYRTUyVjBMQlM4TjF1cGxG
UmpsMFRJd254TlpGNzdDV2ZQTU9icDAKLS0tIG0wSVppUmU5TVdlMHhsQ3pMNDhJ dGZHZm5hU2FYa2JMbWIvbVYwOVNkR28KLS0tIGVwVlJMTjYrSjlYRlphSkZhTTJI
TFkrWitpb3h3UDhFNUN5Yi80YXlLbjQKxdG0m3CZ+elvzSNC9+aD15AOejkT5hJR T0dGQW9rRTUzRytYcGVjRW9wTExvUDQKKM8nkeIHJ7RKj1/8Qvmvck+dkln+bWEn
hhjtn+aUF8JvAIgggLqE1qU1XYIkbzk5//TWz5FaKeszinv9x8plvA== dsob0NlalJQGqNOeM7vib4MV/CAjP4Sq7nU4u9PQ3r/Y1FZ6Tg1l3Q==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w - recipient: age1fxr5s6d6ar0xy5pr63kpq93tk7jha5k96jcxnyquj6s2mw8mmcpss8w29w
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzRGNSYjM2Qkx5M294QWVS YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0QzlmM1hBU21iWkFWRTlz
ZkJzR0VuTzdOR1FIc2c2bWx0akVPZVB0T1hvCmxuMjZWWlVmSUhKUys0QlMxMDV3 NXFEWjdlMzNpa1hmWFNnWHhwUGE2RGphK1JnCnUzYWt6NE5HK1RKeTc0YXdab254
ZCt1ZjJNZlV5K0Zpd3NGcldhWDFDcjgKLS0tIG9mSHA1Um5Hb2NtVm5XRFdvVHVT Y1NYMUdaNFlMVVcyeEQzelZiU3ZQdHcKLS0tIExmcFk3akN6K3NZWVZtdmgvUjU5
NHp1WThrcU1hOEI5RExCbVlnV2VYNlEKV4DSgHYs/zhF34h14RX2rvVXNo2uxCpD bms3SG1hdDJsLzdDZmgycDM1cjJVbDAKnF+v5T1deA4z2er2hk4G2Kk56KapEgI+
uUiwU4and1T5Q09MOjqdbs2e7QM+VjKB4P/w34KkcqXTkJeR/IBF/g== n2e4yi4A5Uv0oJG2lp8ya1PZeK5z4LFi3HnYqNsCZtjzG6hsAVmvLQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1xlnprpvshv93eerthxzg6cahklsfc4efh8dd6u8dte9u6cl0u5qsz48qlt - recipient: age1xlnprpvshv93eerthxzg6cahklsfc4efh8dd6u8dte9u6cl0u5qsz48qlt
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1c3p0N0c2RGJZMmxzcUgw YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRaVJxOGsrR2tkME9md0Qz
bHZhcnlnWlczSGJRMVJRNitqVmV6YThIRWlBCitWUzVCN25JbzhJeG9haEVORUk5 c0xDMDBVYWhBMzBRRWZybXN6THIwbXl4em1RCmoxenJKYVBMNThtNzFaS1NLS2l3
QmhIc0R0c0diNmNPc0dYM2YyNVdScVUKLS0tIG1waU1QYXNVMXU4bC9rNUxwUDIz bXBnMlEvZklSZ1hnTCtDSFhSYUVOMlUKLS0tIEFJdCt2S0dBMmZic29ReGxZK0Ji
SGdNMnVlQlNEeVJkWmZEM1FRT2JJMGMKbZ/znJM6tFhzhHariRXMLgH/4CRZZKrb WkNIdzh5cERpN0JpMzVRME54bmdleXMKr6+azEKtBSSk+RzMRjrmedIEDnkr5rBY
YtmSdeL/Pd5YIecCpjDHDn4vQ0TBAmLaX+zVbNbRKmMZoY7777ywfA== /gWNWadyu6zGHGnaEsHy4ikQx3++tGfB6O3MjN2mncKLCICO6vCSYg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-09-30T16:56:04Z" - recipient: age1sf8tspnmyj2cn6gmzdfuh2vt00tmeqa0vf23rn5s44s9avafsd7sz6wgql
mac: ENC[AES256_GCM,data:BFdEyBs/0hhgldAKVJ/E9gldpU8nyvNuRPP/Ye/ke3aqk+oWvcXJn9oOX47sFwaDQAlrM4E97/baygzIJFH+jkOPZYhlAxLA31KumB+d5WQedPP+yWrHfzwQCIIs6ye9Hl6VljVkMP8OMjGD+oNrm2XqfUkBL+Y3Mxpi0zdksFc=,iv:WXGVtK9EBIS2F1JNr3Nk0hy2fUsNlKkhpRJFR5u/H9U=,tag:JouBIk5rK5ZDdTvw2WWW1g==,type:str] enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmb0xmcDNqS0V0N3hGbjNK
anRIWElhWDBUbFd2TFpsMVNZTTBqZEtzTVZvCklvSEJ0dWNwYnR5NkNZVnJRTFhL
MVZDdWE4bEhSdVlpRTRDTlRWYmJaeU0KLS0tIEp2NjVUVFBPME1VNFVuQ3FSdVBY
YldpMnlOQWpvQ3NNVkJ3a043WGwybWsKnvMrgShgLuorobePyJii5AbZZ9L37Zwc
OjLaX7UhBx/gLUjDXKUJML0iulCWjPCrCdcd+UD2/Rk7t1G3SSMlQw==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-10-18T12:57:58Z"
mac: ENC[AES256_GCM,data:eDvOR6u6/hPIAqQG2ryIj70B3Tix6RHbQQtNzsjZPgRvrCjgByioi7PhzPYPLKtp80mtYWH/SUQ8IAsRS6TAdiJRDbbdbQYuWtg187pZ3xj2QP50C8AzGnI/EI3z3/ZMmwFY4MtJzKaZh6K6PLU3uk87Adg/x5H5P7wIqf37gqk=,iv:zC+EuMVwBmC5icNpI29/ZJQLx8kijwLLT7D8NClbHOM=,tag:VssTqTZ7AZKPQKIaO66SvQ==,type:str]
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted
version: 3.10.2 version: 3.10.2

51
systems.nix Normal file
View File

@@ -0,0 +1,51 @@
{ common, ... }:
# TODO add type, desktop, server, ...?
let
defaultConfig = {
system = "x86_64-linux";
username = common.username;
version = common.system.version;
wayland.enable = true;
nvidia.enable = false;
nixos.channel = "stable"; # stable | unstable
};
in
builtins.mapAttrs (_hostName: systemConfig: defaultConfig // systemConfig) {
desktop = {
nvidia.enable = true;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMSzXyTuQyTrWsfORQbvgrqt/33+hfSUDXeMg6D1T2wz";
git.signing.key = "706F53DD087A91DE";
};
thinkpad = {
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNlHKE/BD8kKfhJD7GBk1A3whZf3gTjk9VEgGAj3qsH";
git.signing.key = "848D71DE0590C199";
};
pi4 = {
system = "aarch64-linux";
wayland.enable = false;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJE9m7YiITe1sDqSZ7Pa8luIw3WToLsypixZEqE4wCQE";
address.private = common.localIpAddr 188;
git.signing.key = "E3FA0E995C0D0E5E";
};
homelab = {
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIARDv5nRlfPDXdV+Db4FaqeSJZ3/3MO0frYGzuVeqYAl";
address.private = common.localIpAddr 231;
address.tailnet = common.tailnetAddr "admin";
};
nidaros = {
wayland.enable = false;
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILw1iNuPnX9NGt+UAvBDzkk26d1e4nF+XX2FMm+IRWtt";
address.private = common.localIpAddr 228;
git.signing.key = "4E323F914029E976";
nixos.channel = "unstable";
version = "25.11";
};
# Samsung S23 FE
localhost-y4maoyqm = {
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII7SSjiqnjif1Kko60iXVTKJ7a1/lRlR8TFNtoclNcnQ";
};
# OnePlus 8
localhost-4izgka9k = {
ssh.publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIALtulVgLrUEpKnpfPFQTHjaEXTxs2Q818NC18eLx0bj";
};
}