Compare commits

...

10 commits

Author SHA1 Message Date
Maxiem Geldhof
8e42f81a19 Add forgejo 2025-10-31 17:35:41 +01:00
Maxiem Geldhof
5b151e7327 Ren key 2025-10-31 17:02:30 +01:00
Maxiem Geldhof
731583bcd5 Replace ren 2025-10-31 16:36:50 +01:00
Maxiem Geldhof
48143906d5 Add ren wg 2025-10-23 16:13:36 +02:00
Maxiem Geldhof
564bcc9bb8 Add selene hetzner key 2025-10-23 15:39:05 +02:00
Maxiem Geldhof
b6714ee64f Refactor the clients 2025-10-18 14:26:06 +02:00
Maxiem Geldhof
195a5e1540 Macbook updates for agenix 2025-10-18 13:59:43 +02:00
Maxiem Geldhof
648bf43f76 Fix selene 2025-10-13 22:05:16 +02:00
Maxiem Geldhof
893ec06b7c Fix selene 2025-10-13 18:55:11 +02:00
Maxiem Geldhof
4fa6f90b37 Fix selene 2025-10-13 18:50:18 +02:00
30 changed files with 441 additions and 50 deletions

17
flake.lock generated
View file

@ -87,6 +87,22 @@
"type": "github" "type": "github"
} }
}, },
"jellyfin-exporter": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"path": "./jellyfin-exporter",
"type": "path"
},
"original": {
"path": "./jellyfin-exporter",
"type": "path"
},
"parent": []
},
"nix-darwin": { "nix-darwin": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@ -128,6 +144,7 @@
"inputs": { "inputs": {
"agenix": "agenix", "agenix": "agenix",
"home-manager": "home-manager_2", "home-manager": "home-manager_2",
"jellyfin-exporter": "jellyfin-exporter",
"nix-darwin": "nix-darwin", "nix-darwin": "nix-darwin",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }

View file

@ -9,6 +9,8 @@
home-manager.inputs.nixpkgs.follows = "nixpkgs"; home-manager.inputs.nixpkgs.follows = "nixpkgs";
agenix.url = "github:ryantm/agenix"; agenix.url = "github:ryantm/agenix";
agenix.inputs.nixpkgs.follows = "nixpkgs"; agenix.inputs.nixpkgs.follows = "nixpkgs";
jellyfin-exporter.url = "path:./jellyfin-exporter";
jellyfin-exporter.inputs.nixpkgs.follows = "nixpkgs";
}; };
outputs = outputs =
@ -18,16 +20,20 @@
home-manager, home-manager,
nixpkgs, nixpkgs,
agenix, agenix,
jellyfin-exporter,
}: }:
let let
macbook = import ./systems/macbook/macbook.nix inputs; macbook = import ./systems/macbook/macbook.nix inputs;
selene = import ./systems/selene/system.nix inputs; selene = import ./systems/selene/system.nix inputs;
ren = import ./systems/ren/system.nix inputs;
in in
{ {
# Build darwin flake using: # Build darwin flake using:
# $ darwin-rebuild build --flake .#Maxiems-MacBook-Pro # $ darwin-rebuild build --flake .#Maxiems-MacBook-Pro
darwinConfigurations."Maxiems-MacBook-Pro" = macbook; darwinConfigurations."Maxiems-MacBook-Pro" = macbook;
nixosConfigurations.selene = selene; nixosConfigurations.selene = selene;
nixosConfigurations.ren = ren;
}; };
} }

View file

@ -0,0 +1,55 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
};
outputs =
{ self, nixpkgs }:
let
# The set of systems to provide outputs for
allSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
# A function that provides a system-specific Nixpkgs for the desired systems
forAllSystems =
f:
nixpkgs.lib.genAttrs allSystems (
system:
f {
pkgs = import nixpkgs { inherit system; };
}
);
in
{
packages = forAllSystems (
{ pkgs }:
{
default = pkgs.buildGoModule (finalAttrs: {
doCheck = false;
pname = "jellyfin-exporter";
version = "1.3.8";
src = pkgs.fetchFromGitHub {
owner = "rebelcore";
repo = "jellyfin_exporter";
tag = "v${finalAttrs.version}";
hash = "sha256-7fIrjcy6y/Ayj43WeuPNCx3uVJyl5Wf6bWs5ta2PpWc=";
};
# Let Nix fetch Go modules and hash them automatically
vendorHash = "sha256-JSOKDbefQyDLNy2y1oW7HUplQw8uhhOGZ+ueWyUYYQ0=";
meta = {
description = "Jellyfin exporter for Prometheus";
homepage = "https://github.com/rebelcore/jellyfin_exporter";
license = pkgs.lib.licenses.asl20;
};
});
}
);
};
}

BIN
keys/hetzner.priv Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
keys/ren.priv Normal file

Binary file not shown.

1
keys/ren.pub Normal file
View file

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIM1gLSFZSVq+5s58+pymRJY+QOWHm6SZvvhY93YDm5k ren@me.com

View file

@ -2,10 +2,16 @@ let
selene = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBEiuoUbvgZ2N03MTcWw4z+oUB9SG0jR0fy5AnTTBHym" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKcfmaqbtwSEydV2hge/aDWxfwlKOw/JJZZWy8ycjojH" ]; selene = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBEiuoUbvgZ2N03MTcWw4z+oUB9SG0jR0fy5AnTTBHym" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKcfmaqbtwSEydV2hge/aDWxfwlKOw/JJZZWy8ycjojH" ];
macbook = [ (builtins.readFile ./macbook.pub) ]; macbook = [ (builtins.readFile ./macbook.pub) ];
master = [ (builtins.readFile ./master.pub) ]; master = [ (builtins.readFile ./master.pub) ];
ren = [ (builtins.readFile ./ren.pub) ];
in in
{ {
"jellyfin-key".publicKeys = selene; "jellyfin-key".publicKeys = selene;
"google-storage-key".publicKeys = selene; "google-storage-key".publicKeys = selene;
"macbook.priv".publicKeys = macbook ++ master; "macbook.priv".publicKeys = macbook ++ master;
"master.priv".publicKeys = macbook ++ master; "master.priv".publicKeys = macbook ++ master;
"wg-selene".publicKeys = macbook ++ selene ++ master;
"wg-macbook".publicKeys = macbook ++ master;
"hetzner.priv".publicKeys = macbook ++ selene ++ master ++ ren;
"wg-ren".publicKeys = macbook++master;
"ren.priv".publicKeys = master ++ ren;
} }

8
keys/wg-macbook Normal file
View file

@ -0,0 +1,8 @@
age-encryption.org/v1
-> ssh-ed25519 M7OTMg f7fgG3DiQpjnDRSEUjSinuqgLATaK7QRN59bSimH1EU
9sKf6eQVwqVBrB553zCHwFs0uyQGRpIJkBZ0AyXPFC4
-> ssh-ed25519 CJLJQg +b+cRU3irwvMnqVBWBIV4GoRyEy+Lg3LHUxZ/httTDo
uBlqCHMXyf1Um+W6y1Bh9pY0osqdeTgFQGuR6eSHQP4
--- Ft1Ii2eVy0h8X6h7ABOW6ryT4ctxg9jS8utA7s52bBA
zÅÙÈ0¿yžÀWÏ¥4Ͱö^|
M<EFBFBD>æüuRtLµA†:µê¨ó„*ö<>œËÈh2†ìSζèkå’¬ì&è må1

1
keys/wg-macbook.pub Normal file
View file

@ -0,0 +1 @@
uFmbvJBptZsrzYDqpZM7SsibELaIRZIT91dr+lg4UTQ=

7
keys/wg-ren Normal file
View file

@ -0,0 +1,7 @@
age-encryption.org/v1
-> ssh-ed25519 M7OTMg QdJds7EpXMyyO9aKmqQg3HWmY6RQbzkQxRQw+K9fn14
/SlvfJAOmCqYvIOZm/ZSynAIWSC+2dAvPpa+5Me6I8k
-> ssh-ed25519 CJLJQg MqNRTuwFcRdZ5VFbcgXQwjRxMAHLJEdUKLuXFPtkRVc
qRaaJzGRPiW2doetErhhUKwUXitvsQ5CGl2QzGK44Ss
--- fCQGYqP7qr+S1tzDeyce5Bn4iWsXq+kIe/ojPNj0LVA
¹4µZŽÁ“Çi"Õž3ÄÞW+ï9ç8Íßž=¼<>Œ¿u°ÃnBÚÂy]@[X[]² X—„Ã5ªîÌœðîö¢íÄz°lÊ@

1
keys/wg-ren.pub Normal file
View file

@ -0,0 +1 @@
wvTFERFXOPcgziLtLtfF3LGv5zmBWikCy/yLRwSuxWA=

BIN
keys/wg-selene Normal file

Binary file not shown.

1
keys/wg-selene.pub Normal file
View file

@ -0,0 +1 @@
4N/84YKCDOPpXTkRxBDQOOUzKR2PXOy4/3gJbel1yE4=

View file

@ -0,0 +1,36 @@
{
lib,
pkgs,
config,
...
}:
let
cfg = config.services.forgejo;
srv = cfg.settings.server;
in
{
services.forgejo = {
enable = true;
database.type = "postgres";
# Enable support for Git Large File Storage
lfs.enable = true;
settings = {
server = {
DOMAIN = "git.maxiemgeldhof.com";
# You need to specify this to remove the port from URLs in the web UI.
ROOT_URL = "https://${srv.DOMAIN}/";
HTTP_PORT = 3028;
};
# 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 = false;
};
metrics = {
ENABLED = true;
};
};
};
}

View file

@ -18,7 +18,7 @@
}; };
age.secrets.jellyfin-key = { age.secrets.jellyfin-key = {
file = ./secrets/jellyfin-key; file = ../../../keys/jellyfin-key;
owner = "jellyfin"; owner = "jellyfin";
}; };

View file

@ -1,5 +1,4 @@
{ rootdomain }: rootdomain: {
{
systemd.services.nginx.serviceConfig.ReadWritePaths = [ "/logs/nginx" ]; systemd.services.nginx.serviceConfig.ReadWritePaths = [ "/logs/nginx" ];
services.nginx.enable = true; services.nginx.enable = true;
services.nginx.commonHttpConfig = '' services.nginx.commonHttpConfig = ''
@ -21,7 +20,6 @@
''; '';
}; };
services.nginx.virtualHosts."grafana.${rootdomain}" = { services.nginx.virtualHosts."grafana.${rootdomain}" = {
enableACME = true; enableACME = true;
forceSSL = true; forceSSL = true;
@ -68,9 +66,34 @@
defaults.email = "admin@${rootdomain}"; defaults.email = "admin@${rootdomain}";
}; };
services.nginx.virtualHosts."git.${rootdomain}" = {
enableACME = true;
forceSSL = true;
locations."/" = {
proxyPass = "http://127.0.0.1:3028";
recommendedProxySettings = true;
};
locations."/metrics" = {
proxyPass = "http://127.0.0.1:3028/metrics";
recommendedProxySettings = true;
extraConfig = ''
allow 127.0.0.1;
allow 192.168.0.0/16;
allow 10.0.0.0/8;
allow 172.16.0.0/12;
deny all;
'';
};
extraConfig = ''
access_log /logs/nginx/nginx-access.log myformat;
'';
};
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
# Type Path Mode User Group Age Argument # Type Path Mode User Group Age Argument
"d /logs/nginx 0755 nginx nginx - -" "d /logs/nginx 0755 nginx nginx - -"
] ];
} }

View file

@ -1,4 +1,4 @@
{ pkgs, ... }: { pkgs, config, ... }:
{ {
environment.systemPackages = [ environment.systemPackages = [
pkgs.git pkgs.git
@ -8,7 +8,7 @@
pkgs.tmux pkgs.tmux
]; ];
age.secrets.google-storage-key = { age.secrets.google-storage-key = {
file = ./secrets/google-storage-key; file = ../../keys/google-storage-key;
owner = "root"; owner = "root";
}; };
environment.variables.GOOGLE_APPLICATION_CREDENTIALS = config.age.secrets."google-storage-key".path; environment.variables.GOOGLE_APPLICATION_CREDENTIALS = config.age.secrets."google-storage-key".path;

View file

@ -0,0 +1,72 @@
let
allowedIPs = [ "10.100.0.1/24" ];
port = 51820;
publicIp = "37.27.207.39";
in
{
serverModule =
{
pkgs,
config,
...
}:
{
# enable NAT
networking.nat.enable = true;
networking.nat.externalInterface = "eth0";
networking.nat.internalInterfaces = [ "wg0" ];
networking.firewall = {
allowedUDPPorts = [ port ];
};
age.secrets.wg-selene = {
file = ../../../keys/wg-selene;
owner = "selene";
};
networking.wireguard.interfaces = {
# "wg0" is the network interface name. You can name the interface arbitrarily.
wg0 = {
# Determines the IP address and subnet of the server's end of the tunnel interface.
ips = allowedIPs;
# The port that WireGuard listens to. Must be accessible by the client.
listenPort = port;
# This allows the wireguard server to route your traffic to the internet and hence be like a VPN
# For this to work you have to set the dnsserver IP of your router (or dnsserver of choice) in your clients
# postSetup = ''
# ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
# '';
# # This undoes the above command
# postShutdown = ''
# ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.100.0.0/24 -o eth0 -j MASQUERADE
# '';
# Path to the private key file.
#
# Note: The private key can also be included inline via the privateKey option,
# but this makes the private key world-readable; thus, using privateKeyFile is
# recommended.
privateKeyFile = config.age.secrets.wg-selene.path;
peers = [
# List of allowed peers.
(import ../../../systems/macbook/wireguard.nix).peerConfig
{
publicKey = (builtins.readFile ../../../keys/wg-ren.pub);
allowedIPs = [ "10.100.0.3/32" ];
}
];
};
};
};
infoForClients = {
endpoint = "${publicIp}:${builtins.toString port}";
allowedIPs = allowedIPs;
publicKey = builtins.readFile ../../../keys/wg-selene.pub;
persistentKeepalive = 25;
};
}

View file

@ -2,7 +2,7 @@ self:
{ pkgs, agenix, ... }: { { pkgs, agenix, ... }: {
# List packages installed in system profile. To search by name, run: # List packages installed in system profile. To search by name, run:
# $ nix-env -qaP | grep wget # $ nix-env -qaP | grep wget
environment.systemPackages = [ pkgs.vim pkgs.vscode pkgs.git pkgs.nixfmt-rfc-style agenix.packages.aarch64-darwin.default pkgs.python3]; environment.systemPackages = [ pkgs.vim pkgs.vscode pkgs.git pkgs.nixfmt-rfc-style agenix.packages.aarch64-darwin.default pkgs.python3 pkgs.wireguard-tools];
# Necessary for using flakes on this system. # Necessary for using flakes on this system.
nix.settings.experimental-features = "nix-command flakes"; nix.settings.experimental-features = "nix-command flakes";

View file

@ -1,11 +1,18 @@
{ nix-darwin, home-manager, agenix, self, ... }: {
nix-darwin,
home-manager,
agenix,
self,
...
}:
nix-darwin.lib.darwinSystem { nix-darwin.lib.darwinSystem {
modules = [ modules = [
agenix.darwinModules.default
{ system.primaryUser = "maxiemgeldhof"; } { system.primaryUser = "maxiemgeldhof"; }
(import ../../modules/usermodules/darwinsettings.nix self) (import ../../modules/usermodules/darwinsettings.nix self)
home-manager.darwinModules.home-manager home-manager.darwinModules.home-manager
(import ./users.nix) ./users.nix
agenix.darwinModules.default (import ./wireguard.nix).systemModule
]; ];
specialArgs = { specialArgs = {

View file

@ -13,6 +13,10 @@ let
programs.zsh = (import ../../modules/usermodules/zsh.nix).programs.zsh; programs.zsh = (import ../../modules/usermodules/zsh.nix).programs.zsh;
programs.git = (import ../../modules/usermodules/git.nix).programs.git; programs.git = (import ../../modules/usermodules/git.nix).programs.git;
programs.ssh.matchBlocks.ren = {
};
}; };
in in
{ {
@ -20,4 +24,5 @@ in
home-manager.useUserPackages = true; home-manager.useUserPackages = true;
home-manager.users.maxiemgeldhof = userconfig; home-manager.users.maxiemgeldhof = userconfig;
users.users.maxiemgeldhof.home = "/Users/maxiemgeldhof"; users.users.maxiemgeldhof.home = "/Users/maxiemgeldhof";
age.identityPaths = [ "/Users/maxiemgeldhof/.ssh/id_ed25519" ];
} }

View file

@ -0,0 +1,32 @@
let
ip = "10.100.0.2/32";
publicKey = (builtins.readFile ../../keys/wg-macbook.pub);
in
{
systemModule = { config, ... }: {
age.secrets.wg-private.file = ../../keys/wg-macbook;
networking.wg-quick.interfaces.wg-selene = {
privateKeyFile = config.age.secrets.wg-private.path;
# The internal IP address assigned to this client by the server.
# The /24 subnet mask is important for knowing the VPN's local network.
address = [ ip ];
# DNS server(s) to use when the tunnel is active.
# This is critical for resolving hostnames when all traffic is routed.
dns = [
"1.1.1.1"
"1.0.0.1"
]; # Cloudflare DNS, or use your preferred one like 8.8.8.8
peers = [
(import ../../modules/servermodules/wireguard/wireguard-server.nix).infoForClients
];
};
};
peerConfig = {
publicKey = publicKey;
allowedIPs = [ip];
};
}

30
systems/ren/hardware.nix Normal file
View file

@ -0,0 +1,30 @@
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/profiles/qemu-guest.nix") ];
boot.loader.grub = {
efiSupport = true;
efiInstallAsRemovable = true;
device = "nodev";
};
fileSystems."/boot" = {
device = "/dev/disk/by-uuid/0683-2D32";
fsType = "vfat";
};
boot.initrd.availableKernelModules = [
"ata_piix"
"uhci_hcd"
"xen_blkfront"
"vmw_pvscsi"
];
boot.initrd.kernelModules = [ "nvme" ];
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";
};
system.stateVersion = "23.11";
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
}

37
systems/ren/system.nix Normal file
View file

@ -0,0 +1,37 @@
{
agenix,
jellyfin-exporter,
nixpkgs,
self,
...
}:
let
system = "x86_64-linux";
in
nixpkgs.lib.nixosSystem {
system = system;
specialArgs = {
# This selects the package for the current system and passes it
exporter-pkg = jellyfin-exporter.packages.${system}.default;
system = system;
};
modules = [
{
boot.tmp.cleanOnBoot = true;
zramSwap.enable = true;
networking.hostName = "Ren";
networking.domain = "";
services.openssh.enable = true;
networking.firewall = {
enable = true;
allowedTCPPorts = [
22
];
};
}
./users.nix
./hardware.nix
agenix.nixosModules.default
];
}

28
systems/ren/users.nix Normal file
View file

@ -0,0 +1,28 @@
{
users.users.ren = {
isNormalUser = true;
home = "/home/ren";
hashedPassword = "$y$j9T$KjOwguW/7P9GvbNg6Yy.k/$8xf3aqnJ909HSjxtpe854RKdiXiPpbOLt.aiuJSfeC0";
openssh.authorizedKeys.keys = [
(builtins.readFile ../../keys/hetzner.pub)
(builtins.readFile ../../keys/asus.pub)
(builtins.readFile ../../keys/macbook.pub)
];
extraGroups = [
"wheel"
"networkmanager"
];
};
age.secrets.hetzner-key = {
file = ../../keys/hetzner.priv;
owner = "ren";
};
users.users.root.openssh.authorizedKeys.keys = [
(builtins.readFile ../../keys/hetzner.pub)
];
age.identityPaths = [ "/home/ren/.ssh/id_ed25519" ];
}

View file

@ -1,7 +1,7 @@
{ ... }: { ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix ./hardware.nix
./networking.nix # generated at runtime by nixos-infect ./networking.nix # generated at runtime by nixos-infect
]; ];

View file

@ -1,19 +1,31 @@
{ agenix, jellyfin-exporter, nixpkgs, ... }: {
agenix,
jellyfin-exporter,
nixpkgs,
self,
...
}:
let
system = "aarch64-linux";
in
nixpkgs.lib.nixosSystem { nixpkgs.lib.nixosSystem {
system = system; system = system;
specialArgs = { specialArgs = {
# This selects the package for the current system and passes it # This selects the package for the current system and passes it
exporter-pkg = jellyfin-exporter.packages.${system}.default; exporter-pkg = jellyfin-exporter.packages.${system}.default;
system = system;
}; };
modules = [ modules = [
./basesettings.nix ./basesettings.nix
./users.nix ./users.nix
../../modules/servermodules/packages.nix ../../modules/servermodules/packages.nix
(import ./nginx.nix "maxiemgeldhof.com") (import ../../modules/servermodules/nginx.nix "maxiemgeldhof.com")
../../modules/servermodules/grafana.nix ../../modules/servermodules/grafana/grafana.nix
../../modules/servermodules/jellyfin.nix ../../modules/servermodules/jellyfin/jellyfin.nix
(import ../../modules/servermodules/wireguard/wireguard-server.nix).serverModule
./volumes.nix ./volumes.nix
../../modules/servermodules/forgejo/forgejo.nix
agenix.nixosModules.default agenix.nixosModules.default
]; ];
} }

View file

@ -6,7 +6,7 @@
openssh.authorizedKeys.keys = [ openssh.authorizedKeys.keys = [
(builtins.readFile ../../keys/hetzner.pub) (builtins.readFile ../../keys/hetzner.pub)
(builtins.readFile ../../keys/asus.pub) (builtins.readFile ../../keys/asus.pub)
(builtins.readFile "../../keys/pacbook.pub") (builtins.readFile ../../keys/macbook.pub)
]; ];
extraGroups = [ extraGroups = [
@ -14,4 +14,10 @@
"networkmanager" "networkmanager"
]; ];
}; };
age.secrets.hetzner-key = {
file = ../../keys/hetzner.priv;
owner = "selene";
};
} }