feat: nucnix
This commit is contained in:
parent
1d2e32b8b0
commit
d4e2805a87
55
config/support/server.nix
Normal file
55
config/support/server.nix
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
environment = {
|
||||||
|
# Print the URL instead on servers
|
||||||
|
variables.BROWSER = "echo";
|
||||||
|
# Don't install the /lib/ld-linux.so.2 and /lib64/ld-linux-x86-64.so.2
|
||||||
|
# stubs. Server users should know what they are doing.
|
||||||
|
stub-ld.enable = false;
|
||||||
|
};
|
||||||
|
# Given that our systems are headless, emergency mode is useless.
|
||||||
|
# We prefer the system to attempt to continue booting so
|
||||||
|
# that we can hopefully still access it remotely.
|
||||||
|
boot.initrd.systemd.suppressedUnits = [
|
||||||
|
"emergency.service"
|
||||||
|
"emergency.target"
|
||||||
|
];
|
||||||
|
# Given that our systems are headless, emergency mode is useless.
|
||||||
|
# We prefer the system to attempt to continue booting so
|
||||||
|
# that we can hopefully still access it remotely.
|
||||||
|
systemd.enableEmergencyMode = false;
|
||||||
|
|
||||||
|
documentation.nixos.enable = false;
|
||||||
|
|
||||||
|
# No need for fonts on a server
|
||||||
|
fonts.fontconfig.enable = false;
|
||||||
|
|
||||||
|
programs.command-not-found.enable = false;
|
||||||
|
|
||||||
|
# freedesktop xdg files
|
||||||
|
xdg.autostart.enable = false;
|
||||||
|
xdg.icons.enable = false;
|
||||||
|
xdg.menus.enable = false;
|
||||||
|
xdg.mime.enable = false;
|
||||||
|
xdg.sounds.enable = false;
|
||||||
|
|
||||||
|
systemd = {
|
||||||
|
|
||||||
|
# For more detail, see:
|
||||||
|
# https://0pointer.de/blog/projects/watchdog.html
|
||||||
|
watchdog = {
|
||||||
|
# systemd will send a signal to the hardware watchdog at half
|
||||||
|
# the interval defined here, so every 7.5s.
|
||||||
|
# If the hardware watchdog does not get a signal for 15s,
|
||||||
|
# it will forcefully reboot the system.
|
||||||
|
runtimeTime = "15s";
|
||||||
|
# Forcefully reboot if the final stage of the reboot
|
||||||
|
# hangs without progress for more than 30s.
|
||||||
|
# For more info, see:
|
||||||
|
# https://utcc.utoronto.ca/~cks/space/blog/linux/SystemdShutdownWatchdog
|
||||||
|
rebootTime = "30s";
|
||||||
|
# Forcefully reboot when a host hangs after kexec.
|
||||||
|
# This may be the case when the firmware does not support kexec.
|
||||||
|
kexecTime = "1m";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1642,11 +1642,11 @@
|
||||||
"treefmt-nix": "treefmt-nix_3"
|
"treefmt-nix": "treefmt-nix_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1733348844,
|
"lastModified": 1734202825,
|
||||||
"narHash": "sha256-glufwHZDCoXjPrfvYSw8PrwQLyFVsg933gt/Gg4hlLE=",
|
"narHash": "sha256-/9r2lRpVLG81uF7zxuk4LDnPZN0kk93tTclMA5KQK0E=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "3052ba7b255b8e3c333fcb318e79ce15c88dd2a7",
|
"rev": "09fb938cb462681aaf6d7016e35a90d4995aad8c",
|
||||||
"revCount": 22,
|
"revCount": 23,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://forge.lel.lol/patrick/nixp-meta.git"
|
"url": "https://forge.lel.lol/patrick/nixp-meta.git"
|
||||||
},
|
},
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
../../config/support/initrd-ssh.nix
|
../../config/support/initrd-ssh.nix
|
||||||
../../config/support/physical.nix
|
../../config/support/physical.nix
|
||||||
../../config/support/secureboot.nix
|
../../config/support/secureboot.nix
|
||||||
|
../../config/support/server.nix
|
||||||
../../config/support/zfs.nix
|
../../config/support/zfs.nix
|
||||||
|
|
||||||
./net.nix
|
./net.nix
|
||||||
|
@ -28,58 +29,5 @@
|
||||||
};
|
};
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
|
|
||||||
# Given that our systems are headless, emergency mode is useless.
|
|
||||||
# We prefer the system to attempt to continue booting so
|
|
||||||
# that we can hopefully still access it remotely.
|
|
||||||
boot.initrd.systemd.suppressedUnits = [
|
|
||||||
"emergency.service"
|
|
||||||
"emergency.target"
|
|
||||||
];
|
|
||||||
environment = {
|
|
||||||
# Print the URL instead on servers
|
|
||||||
variables.BROWSER = "echo";
|
|
||||||
# Don't install the /lib/ld-linux.so.2 and /lib64/ld-linux-x86-64.so.2
|
|
||||||
# stubs. Server users should know what they are doing.
|
|
||||||
stub-ld.enable = false;
|
|
||||||
};
|
|
||||||
# Given that our systems are headless, emergency mode is useless.
|
|
||||||
# We prefer the system to attempt to continue booting so
|
|
||||||
# that we can hopefully still access it remotely.
|
|
||||||
systemd.enableEmergencyMode = false;
|
|
||||||
|
|
||||||
documentation.nixos.enable = false;
|
|
||||||
|
|
||||||
# No need for fonts on a server
|
|
||||||
fonts.fontconfig.enable = false;
|
|
||||||
|
|
||||||
programs.command-not-found.enable = false;
|
|
||||||
|
|
||||||
# freedesktop xdg files
|
|
||||||
xdg.autostart.enable = false;
|
|
||||||
xdg.icons.enable = false;
|
|
||||||
xdg.menus.enable = false;
|
|
||||||
xdg.mime.enable = false;
|
|
||||||
xdg.sounds.enable = false;
|
|
||||||
|
|
||||||
systemd = {
|
|
||||||
|
|
||||||
# For more detail, see:
|
|
||||||
# https://0pointer.de/blog/projects/watchdog.html
|
|
||||||
watchdog = {
|
|
||||||
# systemd will send a signal to the hardware watchdog at half
|
|
||||||
# the interval defined here, so every 7.5s.
|
|
||||||
# If the hardware watchdog does not get a signal for 15s,
|
|
||||||
# it will forcefully reboot the system.
|
|
||||||
runtimeTime = "15s";
|
|
||||||
# Forcefully reboot if the final stage of the reboot
|
|
||||||
# hangs without progress for more than 30s.
|
|
||||||
# For more info, see:
|
|
||||||
# https://utcc.utoronto.ca/~cks/space/blog/linux/SystemdShutdownWatchdog
|
|
||||||
rebootTime = "30s";
|
|
||||||
# Forcefully reboot when a host hangs after kexec.
|
|
||||||
# This may be the case when the firmware does not support kexec.
|
|
||||||
kexecTime = "1m";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
topology.self.interfaces.lan.network = "home";
|
topology.self.interfaces.lan.network = "home";
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,14 +20,6 @@
|
||||||
MulticastDNS = true;
|
MulticastDNS = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
"40-lan01" = {
|
|
||||||
dhcpV6Config.UseDNS = false;
|
|
||||||
dhcpV4Config.UseDNS = false;
|
|
||||||
ipv6AcceptRAConfig.UseDNS = false;
|
|
||||||
networkConfig = {
|
|
||||||
MulticastDNS = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
boot.initrd.systemd.network = {
|
boot.initrd.systemd.network = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
31
hosts/nucnix/default.nix
Normal file
31
hosts/nucnix/default.nix
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
minimal,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
inputs.nixos-hardware.nixosModules.common-pc
|
||||||
|
inputs.nixos-hardware.nixosModules.common-pc-ssd
|
||||||
|
inputs.nixos-hardware.nixosModules.common-cpu-intel
|
||||||
|
|
||||||
|
../../config/basic
|
||||||
|
|
||||||
|
../../config/support/initrd-ssh.nix
|
||||||
|
../../config/support/physical.nix
|
||||||
|
../../config/support/zfs.nix
|
||||||
|
../../config/support/server.nix
|
||||||
|
|
||||||
|
./net.nix
|
||||||
|
./fs.nix
|
||||||
|
] ++ lib.lists.optionals (!minimal) [ ./guests.nix ];
|
||||||
|
services.xserver = {
|
||||||
|
xkb = {
|
||||||
|
layout = "de";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nixpkgs.hostPlatform = "x86_64-linux";
|
||||||
|
|
||||||
|
topology.self.interfaces.lan.network = "home";
|
||||||
|
}
|
91
hosts/nucnix/fs.nix
Normal file
91
hosts/nucnix/fs.nix
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
disko.devices = {
|
||||||
|
disk = {
|
||||||
|
ssd = rec {
|
||||||
|
type = "disk";
|
||||||
|
device = "/dev/disk/by-id/${config.secrets.secrets.local.disko.nvme}";
|
||||||
|
content = with lib.disko.gpt; {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
boot = (partEfi "1G") // {
|
||||||
|
device = "${device}-part1";
|
||||||
|
};
|
||||||
|
rpool = (partLuksZfs "ssd" "rpool" "100%") // {
|
||||||
|
device = "${device}-part2";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
zpool = with lib.disko.zfs; {
|
||||||
|
rpool = mkZpool { datasets = impermanenceZfsDatasets; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
boot.kernel.sysctl."fs.inotify.max_user_instances" = 1024;
|
||||||
|
|
||||||
|
services.zrepl = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
global = {
|
||||||
|
logging = [
|
||||||
|
{
|
||||||
|
type = "syslog";
|
||||||
|
level = "info";
|
||||||
|
format = "human";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
# TODO Monitoring
|
||||||
|
};
|
||||||
|
jobs = [
|
||||||
|
#{
|
||||||
|
# type = "push";
|
||||||
|
# name = "push-to-remote";
|
||||||
|
#}
|
||||||
|
{
|
||||||
|
type = "snap";
|
||||||
|
name = "mach-schnipp-schusss";
|
||||||
|
filesystems = {
|
||||||
|
"rpool/local/state<" = true;
|
||||||
|
"rpool/local/guests<" = true;
|
||||||
|
"rpool/safe<" = true;
|
||||||
|
};
|
||||||
|
snapshotting = {
|
||||||
|
type = "periodic";
|
||||||
|
prefix = "zrepl-";
|
||||||
|
interval = "10m";
|
||||||
|
timestamp_format = "iso-8601";
|
||||||
|
};
|
||||||
|
pruning = {
|
||||||
|
keep = [
|
||||||
|
{
|
||||||
|
type = "regex";
|
||||||
|
regex = "^zrepl-.*$";
|
||||||
|
negate = true;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
type = "grid";
|
||||||
|
grid = lib.concatStringsSep " | " [
|
||||||
|
"1x1d(keep=all)"
|
||||||
|
"142x1h(keep=2)"
|
||||||
|
"90x1d(keep=2)"
|
||||||
|
"500x7d"
|
||||||
|
];
|
||||||
|
regex = "^zrepl-.*$";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/state".neededForBoot = true;
|
||||||
|
fileSystems."/persist".neededForBoot = true;
|
||||||
|
}
|
182
hosts/nucnix/guests.nix
Normal file
182
hosts/nucnix/guests.nix
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
stateVersion,
|
||||||
|
inputs,
|
||||||
|
lib,
|
||||||
|
minimal,
|
||||||
|
nodes,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
domainOf =
|
||||||
|
hostName:
|
||||||
|
let
|
||||||
|
domains =
|
||||||
|
{
|
||||||
|
};
|
||||||
|
in
|
||||||
|
"${domains.${hostName}}.${config.secrets.secrets.global.domains.web}";
|
||||||
|
# TODO hard coded elisabeth nicht so schön
|
||||||
|
ipOf = hostName: nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
services.nginx =
|
||||||
|
let
|
||||||
|
blockOf =
|
||||||
|
hostName:
|
||||||
|
{
|
||||||
|
virtualHostExtraConfig ? "",
|
||||||
|
maxBodySize ? "500M",
|
||||||
|
port ? 3000,
|
||||||
|
upstream ? hostName,
|
||||||
|
protocol ? "http",
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
upstreams.${hostName} = {
|
||||||
|
servers."${ipOf upstream}:${toString port}" = { };
|
||||||
|
extraConfig = ''
|
||||||
|
zone ${hostName} 64k ;
|
||||||
|
keepalive 5 ;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
virtualHosts.${domainOf hostName} = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEHost = "web";
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "${protocol}://${hostName}";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
X-Frame-Options = "SAMEORIGIN";
|
||||||
|
};
|
||||||
|
extraConfig =
|
||||||
|
''
|
||||||
|
client_max_body_size ${maxBodySize} ;
|
||||||
|
''
|
||||||
|
+ virtualHostExtraConfig;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
proxyProtect =
|
||||||
|
hostName: cfg: allowedGroup:
|
||||||
|
lib.mkMerge [
|
||||||
|
(blockOf hostName cfg)
|
||||||
|
{
|
||||||
|
virtualHosts.${domainOf hostName} = {
|
||||||
|
locations."/".extraConfig = ''
|
||||||
|
auth_request /oauth2/auth;
|
||||||
|
error_page 401 = /oauth2/sign_in;
|
||||||
|
|
||||||
|
# pass information via X-User and X-Email headers to backend,
|
||||||
|
# requires running with --set-xauthrequest flag
|
||||||
|
auth_request_set $user $upstream_http_x_auth_request_preferred_username;
|
||||||
|
# Set the email to our own domain in case user change their mail
|
||||||
|
auth_request_set $email "''${upstream_http_x_auth_request_preferred_username}@${config.secrets.secrets.global.domains.web}";
|
||||||
|
proxy_set_header X-User $user;
|
||||||
|
proxy_set_header X-Email $email;
|
||||||
|
|
||||||
|
# if you enabled --cookie-refresh, this is needed for it to work with auth_request
|
||||||
|
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
||||||
|
add_header Set-Cookie $auth_cookie;
|
||||||
|
'';
|
||||||
|
locations."/oauth2/" = {
|
||||||
|
proxyPass = "http://oauth2-proxy";
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_set_header X-Scheme $scheme;
|
||||||
|
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
locations."= /oauth2/auth" = {
|
||||||
|
proxyPass =
|
||||||
|
"http://oauth2-proxy/oauth2/auth"
|
||||||
|
+ lib.optionalString allowedGroup "?allowed_groups=${hostName}_access";
|
||||||
|
extraConfig = ''
|
||||||
|
internal;
|
||||||
|
|
||||||
|
proxy_set_header X-Scheme $scheme;
|
||||||
|
# nginx auth_request includes headers but not body
|
||||||
|
proxy_set_header Content-Length "";
|
||||||
|
proxy_pass_request_body off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
in
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
enable = false;
|
||||||
|
recommendedSetup = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
guests =
|
||||||
|
let
|
||||||
|
mkGuest = guestName: {
|
||||||
|
autostart = true;
|
||||||
|
zfs."/state" = {
|
||||||
|
pool = "rpool";
|
||||||
|
dataset = "local/guests/${guestName}";
|
||||||
|
};
|
||||||
|
zfs."/persist" = {
|
||||||
|
pool = "rpool";
|
||||||
|
dataset = "safe/guests/${guestName}";
|
||||||
|
};
|
||||||
|
modules = [
|
||||||
|
../../config/basic
|
||||||
|
../../config/services/${guestName}.nix
|
||||||
|
{
|
||||||
|
node.secretsDir = config.node.secretsDir + "/${guestName}";
|
||||||
|
networking.nftables.firewall.zones.untrusted.interfaces = [
|
||||||
|
config.guests.${guestName}.networking.mainLinkName
|
||||||
|
];
|
||||||
|
systemd.network.networks."10-${config.guests.${guestName}.networking.mainLinkName}" = {
|
||||||
|
DHCP = lib.mkForce "no";
|
||||||
|
address = [
|
||||||
|
(lib.net.cidr.hostCidr
|
||||||
|
config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName}"
|
||||||
|
config.secrets.secrets.global.net.privateSubnetv4
|
||||||
|
)
|
||||||
|
(lib.net.cidr.hostCidr
|
||||||
|
config.secrets.secrets.global.net.ips."${config.guests.${guestName}.nodeName}"
|
||||||
|
config.secrets.secrets.global.net.privateSubnetv6
|
||||||
|
)
|
||||||
|
];
|
||||||
|
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
mkMicrovm = guestName: cfg: {
|
||||||
|
${guestName} = mkGuest guestName cfg // {
|
||||||
|
backend = "microvm";
|
||||||
|
microvm = {
|
||||||
|
system = "x86_64-linux";
|
||||||
|
macvtap = "lan";
|
||||||
|
baseMac = config.secrets.secrets.local.networking.interfaces.lan01.mac;
|
||||||
|
};
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit (inputs.self) nodes;
|
||||||
|
inherit (inputs.self.pkgs.x86_64-linux) lib;
|
||||||
|
inherit inputs minimal stateVersion;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
mkContainer = guestName: cfg: {
|
||||||
|
${guestName} = mkGuest guestName cfg // {
|
||||||
|
backend = "container";
|
||||||
|
container.macvlan = "lan";
|
||||||
|
extraSpecialArgs = {
|
||||||
|
inherit
|
||||||
|
lib
|
||||||
|
nodes
|
||||||
|
inputs
|
||||||
|
minimal
|
||||||
|
stateVersion
|
||||||
|
;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{ };
|
||||||
|
}
|
54
hosts/nucnix/net.nix
Normal file
54
hosts/nucnix/net.nix
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
networking = {
|
||||||
|
inherit (config.secrets.secrets.local.networking) hostId;
|
||||||
|
};
|
||||||
|
systemd.network.networks = {
|
||||||
|
"10-lan01" = {
|
||||||
|
address = [
|
||||||
|
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name}
|
||||||
|
config.secrets.secrets.global.net.privateSubnetv4
|
||||||
|
)
|
||||||
|
];
|
||||||
|
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
|
||||||
|
#matchConfig.MACAddress = config.secrets.secrets.local.networking.interfaces.lan01.mac;
|
||||||
|
matchConfig.Name = "lan";
|
||||||
|
dhcpV6Config.UseDNS = false;
|
||||||
|
dhcpV4Config.UseDNS = false;
|
||||||
|
ipv6AcceptRAConfig.UseDNS = false;
|
||||||
|
networkConfig = {
|
||||||
|
MulticastDNS = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
boot.initrd.systemd.network = {
|
||||||
|
enable = true;
|
||||||
|
networks = {
|
||||||
|
# redo the network cause the livesystem has macvlans
|
||||||
|
"10-lan01" = {
|
||||||
|
address = [
|
||||||
|
(lib.net.cidr.hostCidr config.secrets.secrets.global.net.ips.${config.node.name}
|
||||||
|
config.secrets.secrets.global.net.privateSubnetv4
|
||||||
|
)
|
||||||
|
];
|
||||||
|
gateway = [ (lib.net.cidr.host 1 config.secrets.secrets.global.net.privateSubnetv4) ];
|
||||||
|
matchConfig.MACAddress = config.secrets.secrets.local.networking.interfaces.lan01.mac;
|
||||||
|
dhcpV6Config.UseDNS = false;
|
||||||
|
dhcpV4Config.UseDNS = false;
|
||||||
|
ipv6AcceptRAConfig.UseDNS = false;
|
||||||
|
networkConfig = {
|
||||||
|
IPv6PrivacyExtensions = "yes";
|
||||||
|
MulticastDNS = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.nftables.firewall.zones.untrusted.interfaces = [ "lan" ];
|
||||||
|
|
||||||
|
# To be able to ping containers from the host, it is necessary
|
||||||
|
# to create a macvlan on the host on the VLAN 1 network.
|
||||||
|
networking.macvlans.lan = {
|
||||||
|
interface = "lan01";
|
||||||
|
mode = "bridge";
|
||||||
|
};
|
||||||
|
}
|
BIN
hosts/nucnix/secrets/generated/initrd_host_ed25519_key.age
Normal file
BIN
hosts/nucnix/secrets/generated/initrd_host_ed25519_key.age
Normal file
Binary file not shown.
1
hosts/nucnix/secrets/host.pub
Normal file
1
hosts/nucnix/secrets/host.pub
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDS0gxZD8aIAAKBtt7gyMHZ2KloQPlHxS+LsQY/62SzE
|
BIN
hosts/nucnix/secrets/secrets.nix.age
Normal file
BIN
hosts/nucnix/secrets/secrets.nix.age
Normal file
Binary file not shown.
|
@ -21,6 +21,7 @@ in
|
||||||
name = "Home-manager options for the main user";
|
name = "Home-manager options for the main user";
|
||||||
merge = _loc: defs: (map (x: x.value) defs);
|
merge = _loc: defs: (map (x: x.value) defs);
|
||||||
};
|
};
|
||||||
|
default = { };
|
||||||
};
|
};
|
||||||
hm-all = mkOption {
|
hm-all = mkOption {
|
||||||
description = "Home-manager options for the primary User and root.";
|
description = "Home-manager options for the primary User and root.";
|
||||||
|
@ -28,6 +29,7 @@ in
|
||||||
name = "Home-manager options for the all users";
|
name = "Home-manager options for the all users";
|
||||||
merge = _loc: defs: (map (x: x.value) defs);
|
merge = _loc: defs: (map (x: x.value) defs);
|
||||||
};
|
};
|
||||||
|
default = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
config.home-manager.users = mkMerge [
|
config.home-manager.users = mkMerge [
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
inherit (lib)
|
|
||||||
getExe
|
|
||||||
mkEnableOption
|
|
||||||
mkIf
|
|
||||||
mkOption
|
|
||||||
mkPackageOption
|
|
||||||
types
|
|
||||||
;
|
|
||||||
|
|
||||||
cfg = config.services.actual;
|
|
||||||
configFile = formatType.generate "config.json" cfg.settings;
|
|
||||||
dataDir = "/var/lib/actual";
|
|
||||||
|
|
||||||
formatType = pkgs.formats.json { };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
options.services.actual = {
|
|
||||||
enable = mkEnableOption "actual, a privacy focused app for managing your finances";
|
|
||||||
package = mkPackageOption pkgs "actual-server" { };
|
|
||||||
|
|
||||||
user = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "actual";
|
|
||||||
description = ''
|
|
||||||
User to run actual as.
|
|
||||||
|
|
||||||
::: {.note}
|
|
||||||
If left as the default value this user will automatically be created
|
|
||||||
on system activation, otherwise the sysadmin is responsible for
|
|
||||||
ensuring the user exists.
|
|
||||||
:::
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
group = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
default = "actual";
|
|
||||||
description = ''
|
|
||||||
Group under which to run.
|
|
||||||
|
|
||||||
::: {.note}
|
|
||||||
If left as the default value this group will automatically be created
|
|
||||||
on system activation, otherwise the sysadmin is responsible for
|
|
||||||
ensuring the user exists.
|
|
||||||
:::
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
openFirewall = mkOption {
|
|
||||||
default = false;
|
|
||||||
type = types.bool;
|
|
||||||
description = "Whether to open the firewall for the specified port.";
|
|
||||||
};
|
|
||||||
|
|
||||||
settings = mkOption {
|
|
||||||
default = { };
|
|
||||||
description = "Server settings, refer to (the documentation)[https://actualbudget.org/docs/config/] for available options.";
|
|
||||||
type = types.submodule {
|
|
||||||
freeformType = formatType.type;
|
|
||||||
|
|
||||||
options = {
|
|
||||||
hostname = mkOption {
|
|
||||||
type = types.str;
|
|
||||||
description = "The address to listen on";
|
|
||||||
default = "::";
|
|
||||||
};
|
|
||||||
|
|
||||||
port = mkOption {
|
|
||||||
type = types.port;
|
|
||||||
description = "The port to listen on";
|
|
||||||
default = 3000;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = {
|
|
||||||
serverFiles = "${dataDir}/server-files";
|
|
||||||
userFiles = "${dataDir}/user-files";
|
|
||||||
inherit dataDir;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
|
||||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.port ];
|
|
||||||
|
|
||||||
users.groups = mkIf (cfg.group == "actual") {
|
|
||||||
${cfg.group} = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users = mkIf (cfg.user == "actual") {
|
|
||||||
${cfg.user} = {
|
|
||||||
isSystemUser = true;
|
|
||||||
inherit (cfg) group;
|
|
||||||
home = dataDir;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.actual = {
|
|
||||||
description = "Actual server, a local-first personal finance app";
|
|
||||||
after = [ "network.target" ];
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
environment.ACTUAL_CONFIG_PATH = configFile;
|
|
||||||
serviceConfig = {
|
|
||||||
ExecStart = getExe cfg.package;
|
|
||||||
User = cfg.user;
|
|
||||||
Group = cfg.group;
|
|
||||||
StateDirectory = "actual";
|
|
||||||
WorkingDirectory = dataDir;
|
|
||||||
LimitNOFILE = "1048576";
|
|
||||||
PrivateTmp = true;
|
|
||||||
PrivateDevices = true;
|
|
||||||
StateDirectoryMode = "0700";
|
|
||||||
Restart = "always";
|
|
||||||
|
|
||||||
# Hardening
|
|
||||||
CapabilityBoundingSet = "";
|
|
||||||
LockPersonality = true;
|
|
||||||
#MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT
|
|
||||||
PrivateUsers = true;
|
|
||||||
ProtectClock = true;
|
|
||||||
ProtectControlGroups = true;
|
|
||||||
ProtectHome = true;
|
|
||||||
ProtectHostname = true;
|
|
||||||
ProtectKernelLogs = true;
|
|
||||||
ProtectKernelModules = true;
|
|
||||||
ProtectKernelTunables = true;
|
|
||||||
ProtectProc = "invisible";
|
|
||||||
ProcSubset = "pid";
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
RestrictAddressFamilies = [
|
|
||||||
"AF_INET"
|
|
||||||
"AF_INET6"
|
|
||||||
"AF_NETLINK"
|
|
||||||
];
|
|
||||||
RestrictNamespaces = true;
|
|
||||||
RestrictRealtime = true;
|
|
||||||
SystemCallArchitectures = "native";
|
|
||||||
SystemCallFilter = [
|
|
||||||
"@system-service"
|
|
||||||
"@pkey"
|
|
||||||
];
|
|
||||||
UMask = "0077";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
Binary file not shown.
Loading…
Reference in a new issue