Compare commits
2 commits
6fa99bd855
...
f918dfda8c
Author | SHA1 | Date | |
---|---|---|---|
Patrick | f918dfda8c | ||
Patrick | 41710c109b |
19
README.md
19
README.md
|
@ -17,15 +17,14 @@ This showcases my end user setup, which I dailydrive on all my hosts.
|
||||||
| | Programm | Description
|
| | Programm | Description
|
||||||
---|---|---
|
---|---|---
|
||||||
🐚 Shell | [ZSH](./users/common/shells/zsh/default.nix) & [Starship](./users/common/shells/starfish.nix) | ZSH with FZF autocomplete, starship prompt, sqlite history and histdb-skim for fancy reverse search
|
🐚 Shell | [ZSH](./users/common/shells/zsh/default.nix) & [Starship](./users/common/shells/starfish.nix) | ZSH with FZF autocomplete, starship prompt, sqlite history and histdb-skim for fancy reverse search
|
||||||
🪟 WM | [Sway](./users/common/graphical/wayland/sway.nix) & [i3](./users/common/graphical/Xorg/i3.nix) | Tiling window managers with similar behaviour for wayland and xorg
|
🪟 WM | [Hyprland](./users/patrick/wayland/hyprland.nix) | Tiling window manager
|
||||||
🖼️ Styling | [Stylix](./modules/graphical/default.nix) | globally consistent styling
|
🖼️ Styling | [Stylix](./users/patrick/theme.nix) | globally consistent styling
|
||||||
📝 Editor | [NeoVim](./users/common/programs/nvim/default.nix) | Extensively configured neovim
|
📝 Editor | [NeoVim](./users/patrick/programs/nvim/default.nix) | Extensively configured neovim
|
||||||
🎮 Gaming | [Bottles](./users/common/programs/bottles.nix) & [Steam](./modules/optional/steam.nix) | Pew, Pew and such
|
🎮 Gaming | [Bottles](./users/patrick/programs/bottles.nix) & [Steam](./users/patrick/programs/steam.nix) | Pew, Pew and such
|
||||||
🌐 Browser | [Firefox](./users/patrick/firefox.nix) | Heavily configured Firefox to still my privacy and security needs
|
🌐 Browser | [Firefox](./users/patrick/firefox.nix) | Heavily configured Firefox to still my privacy and security needs
|
||||||
💻 Terminal | [Kitty](./users/common/programs/kitty.nix) | fast terminal
|
💻 Terminal | [Kitty](./users/patrick/programs/kitty.nix) | fast terminal
|
||||||
🎵 Music | [Spotify](./users/common/programs/spicetify.nix) | Fancy looking spotify using spicetify
|
🎵 Music | [Spotify](./users/patrick/programs/spicetify.nix) | Fancy looking spotify using spicetify
|
||||||
📫 Mail | [Thunderbird](./users/common/programs/thunderbird.nix) | Best email client there is
|
📫 Mail | [Thunderbird](./users/common/programs/thunderbird.nix) | Best email client there is
|
||||||
🎛️ StreamDeck | [StreamDeck](./users/patrick/streamdeck.nix) | More hotkeys = more better
|
|
||||||
|
|
||||||
## Service Configuration
|
## Service Configuration
|
||||||
These are services I've set up
|
These are services I've set up
|
||||||
|
@ -64,7 +63,7 @@ These are notable external flakes which this config depend upon
|
||||||
[impermanence](https://github.com/nix-community/impermanence) | stateless filesystem
|
[impermanence](https://github.com/nix-community/impermanence) | stateless filesystem
|
||||||
[lanzaboote](https://github.com/nix-community/lanzaboote) | Secure Boot
|
[lanzaboote](https://github.com/nix-community/lanzaboote) | Secure Boot
|
||||||
[stylix](https://github.com/danth/stylix) | theming
|
[stylix](https://github.com/danth/stylix) | theming
|
||||||
[spicetify](https://github.com/the-argus/spicetify-nix) | spotify looking fancy
|
[spicetify](https://github.com/Gerg-l/spicetify-nix) | spotify looking fancy
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,9 +81,9 @@ These are notable external flakes which this config depend upon
|
||||||
- This might take multiple minutes(~10)
|
- This might take multiple minutes(~10)
|
||||||
- Alternatively boot an official nixos image connect with password
|
- Alternatively boot an official nixos image connect with password
|
||||||
3. Copy ISO to usb using dd
|
3. Copy ISO to usb using dd
|
||||||
3. After booting copy the installer to the live system using `nix copy --to <target> .#nodes.<target-system>.config.system.build.installFromLive`
|
3. After booting copy the installer to the live system using `nix copy --to <target> .#minimalConfigurations.<target-system>.config.system.build.installFromLive`
|
||||||
4. Run the installer script from the nix store of the live system
|
4. Run the installer script from the nix store of the live system
|
||||||
- you can get the path using `nix path-info .#nodes.<target-system>.config.system.build.installFromLive`
|
- you can get the path using `nix path-info .#minimalConfigurations.<target-system>.config.system.build.installFromLive`
|
||||||
4. Export all zpools and reboot into system
|
4. Export all zpools and reboot into system
|
||||||
6. Retrieve hostkeys using `ssh-keyscan <host> | grep -o 'ssh-ed25519.*' > host/<target>/secrets/host.pub`
|
6. Retrieve hostkeys using `ssh-keyscan <host> | grep -o 'ssh-ed25519.*' > host/<target>/secrets/host.pub`
|
||||||
5. Deploy system
|
5. Deploy system
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
./net.nix
|
./net.nix
|
||||||
./nftables.nix
|
./nftables.nix
|
||||||
./nix.nix
|
./nix.nix
|
||||||
|
./secrets.nix
|
||||||
./ssh.nix
|
./ssh.nix
|
||||||
./system.nix
|
./system.nix
|
||||||
./users.nix
|
./users.nix
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
inputs.agenix.nixosModules.default
|
inputs.agenix.nixosModules.default
|
||||||
inputs.disko.nixosModules.disko
|
inputs.disko.nixosModules.disko
|
||||||
inputs.home-manager.nixosModules.default
|
inputs.home-manager.nixosModules.default
|
||||||
|
inputs.idmail.nixosModules.default
|
||||||
inputs.impermanence.nixosModules.impermanence
|
inputs.impermanence.nixosModules.impermanence
|
||||||
inputs.lanzaboote.nixosModules.lanzaboote
|
inputs.lanzaboote.nixosModules.lanzaboote
|
||||||
inputs.nix-topology.nixosModules.default
|
inputs.nix-topology.nixosModules.default
|
||||||
|
|
21
config/basic/secrets.nix
Normal file
21
config/basic/secrets.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
age.generators.argon2id =
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
decrypt,
|
||||||
|
deps,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
dep = builtins.head deps;
|
||||||
|
in
|
||||||
|
''
|
||||||
|
echo " -> Deriving argon2id hash from [32m"${lib.escapeShellArg dep.host}":[m[33m"${lib.escapeShellArg dep.name}"[m" >&2
|
||||||
|
${decrypt} ${lib.escapeShellArg dep.file} \
|
||||||
|
| tr -d '\n' \
|
||||||
|
| ${pkgs.libargon2}/bin/argon2 "$(${pkgs.openssl}/bin/openssl rand -base64 16)" -id -e \
|
||||||
|
|| die "Failure while generating argon2id hash"
|
||||||
|
'';
|
||||||
|
|
||||||
|
}
|
|
@ -40,6 +40,8 @@
|
||||||
signal = uidGid 228;
|
signal = uidGid 228;
|
||||||
netbird-main = uidGid 229;
|
netbird-main = uidGid 229;
|
||||||
paperless = uidGid 315;
|
paperless = uidGid 315;
|
||||||
|
stalwart-mail = uidGid 316;
|
||||||
|
build = uidGid 317;
|
||||||
systemd-oom = uidGid 300;
|
systemd-oom = uidGid 300;
|
||||||
systemd-coredump = uidGid 301;
|
systemd-coredump = uidGid 301;
|
||||||
patrick = uidGid 1000;
|
patrick = uidGid 1000;
|
||||||
|
|
92
config/services/idmail.nix
Normal file
92
config/services/idmail.nix
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
{
|
||||||
|
inputs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
domain = config.secrets.secrets.global.domains.mail_public;
|
||||||
|
idmailDomain = "alias.${domain}";
|
||||||
|
priv_domain = config.secrets.secrets.global.domains.mail_private;
|
||||||
|
|
||||||
|
mkRandomSecret = {
|
||||||
|
generator.script = "alnum";
|
||||||
|
mode = "000";
|
||||||
|
intermediary = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
mkArgon2id = secret: {
|
||||||
|
generator.dependencies = [ config.age.secrets.${secret} ];
|
||||||
|
generator.script = "argon2id";
|
||||||
|
mode = "440";
|
||||||
|
group = "stalwart-mail";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
environment.persistence."/persist".directories = [
|
||||||
|
{
|
||||||
|
directory = config.services.idmail.dataDir;
|
||||||
|
user = "stalwart-mail";
|
||||||
|
group = "stalwart-mail";
|
||||||
|
mode = "4770";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
age.secrets = {
|
||||||
|
idmail-user-pw_admin = mkRandomSecret;
|
||||||
|
idmail-user-hash_admin = mkArgon2id "idmail-user-pw_admin";
|
||||||
|
idmail-mailbox-pw_catch-all = mkRandomSecret;
|
||||||
|
idmail-mailbox-hash_catch-all = mkArgon2id "idmail-mailbox-pw_catch-all";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.idmail = {
|
||||||
|
package = inputs.idmail.packages."aarch64-linux".default;
|
||||||
|
enable = true;
|
||||||
|
# Stalwart will change permissions due to SQLite implementation.
|
||||||
|
# Therefore, run as stalwart-mail since we don't allow reading
|
||||||
|
# stalwarts folder anyway (sandboxing is on).
|
||||||
|
user = "stalwart-mail";
|
||||||
|
provision = {
|
||||||
|
enable = true;
|
||||||
|
users.admin = {
|
||||||
|
admin = true;
|
||||||
|
password_hash = "%{file:${config.age.secrets.idmail-user-hash_admin.path}}%";
|
||||||
|
};
|
||||||
|
domains = {
|
||||||
|
"${domain}" = {
|
||||||
|
owner = "admin";
|
||||||
|
catch_all = "catch-all@${domain}";
|
||||||
|
public = true;
|
||||||
|
};
|
||||||
|
"${priv_domain}" = {
|
||||||
|
owner = "admin";
|
||||||
|
catch_all = "catch-all@${domain}";
|
||||||
|
public = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
mailboxes."catch-all@${domain}" = {
|
||||||
|
password_hash = "%{file:${config.age.secrets.idmail-mailbox-hash_catch-all.path}}%";
|
||||||
|
owner = "admin";
|
||||||
|
};
|
||||||
|
# XXX: create mailboxes for git@ vaultwarden@ and simultaneously alias them to the catch all for a send only mail.
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.services.idmail.serviceConfig.RestartSec = "60"; # Retry every minute
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
upstreams.idmail = {
|
||||||
|
servers."127.0.0.1:3000" = { };
|
||||||
|
extraConfig = ''
|
||||||
|
zone idmail 64k;
|
||||||
|
keepalive 2;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
virtualHosts.${idmailDomain} = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEWildcardHost = true;
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://idmail";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
662
config/services/stalwart.nix
Normal file
662
config/services/stalwart.nix
Normal file
|
@ -0,0 +1,662 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
priv_domain = config.secrets.secrets.global.domains.mail_private;
|
||||||
|
domain = config.secrets.secrets.global.domains.mail_public;
|
||||||
|
mailDomains = [
|
||||||
|
priv_domain
|
||||||
|
domain
|
||||||
|
];
|
||||||
|
mailBackupDir = "/var/cache/mail-backup";
|
||||||
|
dataDir = "/var/lib/stalwart-mail";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
age.secrets.resticpasswd = {
|
||||||
|
generator.script = "alnum";
|
||||||
|
};
|
||||||
|
age.secrets.stalwartHetznerSshKey = {
|
||||||
|
generator.script = "ssh-ed25519";
|
||||||
|
};
|
||||||
|
services.restic.backups = {
|
||||||
|
main = {
|
||||||
|
user = "root";
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "06:00";
|
||||||
|
Persistent = true;
|
||||||
|
RandomizedDelaySec = "3h";
|
||||||
|
};
|
||||||
|
initialize = true;
|
||||||
|
passwordFile = config.age.secrets.resticpasswd.path;
|
||||||
|
hetznerStorageBox = {
|
||||||
|
enable = true;
|
||||||
|
inherit (config.secrets.secrets.global.hetzner) mainUser;
|
||||||
|
inherit (config.secrets.secrets.global.hetzner.users.stalwart-mail) subUid path;
|
||||||
|
sshAgeSecret = "stalwartHetznerSshKey";
|
||||||
|
};
|
||||||
|
paths = [
|
||||||
|
mailBackupDir
|
||||||
|
];
|
||||||
|
#pruneOpts = [
|
||||||
|
# "--keep-daily 10"
|
||||||
|
# "--keep-weekly 7"
|
||||||
|
# "--keep-monthly 12"
|
||||||
|
# "--keep-yearly 75"
|
||||||
|
#];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.services.backup-mail = {
|
||||||
|
description = "Mail backup";
|
||||||
|
environment = {
|
||||||
|
STALWART_DATA = dataDir;
|
||||||
|
IDMAIL_DATA = config.services.idmail.dataDir;
|
||||||
|
BACKUP_DIR = mailBackupDir;
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
SyslogIdentifier = "backup-mail";
|
||||||
|
Type = "oneshot";
|
||||||
|
User = "stalwart-mail";
|
||||||
|
Group = "stalwart-mail";
|
||||||
|
ExecStart = lib.getExe (
|
||||||
|
pkgs.writeShellApplication {
|
||||||
|
name = "backup-mail";
|
||||||
|
runtimeInputs = [ pkgs.sqlite ];
|
||||||
|
text = ''
|
||||||
|
sqlite3 "$STALWART_DATA/database.sqlite3" ".backup '$BACKUP_DIR/database.sqlite3'"
|
||||||
|
sqlite3 "$IDMAIL_DATA/database.sqlite3" ".backup '$BACKUP_DIR/idmail.db'"
|
||||||
|
cp -r "$STALWART_DATA/dkim" "$BACKUP_DIR/"
|
||||||
|
'';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ReadWritePaths = [
|
||||||
|
dataDir
|
||||||
|
config.services.idmail.dataDir
|
||||||
|
mailBackupDir
|
||||||
|
];
|
||||||
|
Restart = "no";
|
||||||
|
};
|
||||||
|
requiredBy = [ "restic-backups-main.service" ];
|
||||||
|
before = [ "restic-backups-main.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets.stalwart-admin-pw = {
|
||||||
|
generator.script = "alnum";
|
||||||
|
mode = "000";
|
||||||
|
intermediary = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
age.secrets.stalwart-admin-hash = {
|
||||||
|
generator.dependencies = [ config.age.secrets.stalwart-admin-pw ];
|
||||||
|
generator.script = "argon2id";
|
||||||
|
mode = "440";
|
||||||
|
group = "stalwart-mail";
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.acme.members = [ "stalwart-mail" ];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
25 # smtp
|
||||||
|
465 # submission tls
|
||||||
|
# 587 # submission starttls
|
||||||
|
993 # imap tls
|
||||||
|
# 143 # imap starttls
|
||||||
|
4190 # manage sieve
|
||||||
|
];
|
||||||
|
environment.persistence."/persist".directories = [
|
||||||
|
{
|
||||||
|
directory = dataDir;
|
||||||
|
user = "stalwart-mail";
|
||||||
|
group = "stalwart-mail";
|
||||||
|
mode = "0700";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# Needed so we don't run out of tmpfs space for large backups.
|
||||||
|
# Technically this could be cleared each boot but whatever.
|
||||||
|
environment.persistence."/state".directories = [
|
||||||
|
{
|
||||||
|
directory = mailBackupDir;
|
||||||
|
user = "stalwart-mail";
|
||||||
|
group = "stalwart-mail";
|
||||||
|
mode = "0700";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services.nginx = {
|
||||||
|
upstreams.stalwart = {
|
||||||
|
servers."127.0.0.1:8080" = { };
|
||||||
|
extraConfig = ''
|
||||||
|
zone stalwart 64k;
|
||||||
|
keepalive 2;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
virtualHosts =
|
||||||
|
{
|
||||||
|
${domain} = {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEWildcardHost = true;
|
||||||
|
extraConfig = ''
|
||||||
|
client_max_body_size 512M;
|
||||||
|
'';
|
||||||
|
locations."/" = {
|
||||||
|
proxyPass = "http://stalwart";
|
||||||
|
proxyWebsockets = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// lib.genAttrs
|
||||||
|
[
|
||||||
|
"autoconfig.${domain}"
|
||||||
|
"autodiscover.${domain}"
|
||||||
|
"mta-sts.${domain}"
|
||||||
|
]
|
||||||
|
(_: {
|
||||||
|
forceSSL = true;
|
||||||
|
useACMEWildcardHost = true;
|
||||||
|
locations."/".proxyPass = "http://stalwart";
|
||||||
|
});
|
||||||
|
};
|
||||||
|
systemd.services.stalwart-mail =
|
||||||
|
let
|
||||||
|
cfg = config.services.stalwart-mail;
|
||||||
|
configFormat = pkgs.formats.toml { };
|
||||||
|
configFile = configFormat.generate "stalwart-mail.toml" cfg.settings;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
preStart = lib.mkAfter (
|
||||||
|
''
|
||||||
|
cat ${configFile} > /run/stalwart-mail/config.toml
|
||||||
|
cat ${config.age.secrets.stalwart-admin-hash.path} \
|
||||||
|
| tr -d '\n' > /run/stalwart-mail/admin-hash
|
||||||
|
|
||||||
|
mkdir -p /var/lib/stalwart-mail/dkim
|
||||||
|
''
|
||||||
|
# Generate DKIM keys if necessary
|
||||||
|
+ lib.concatLines (
|
||||||
|
lib.forEach mailDomains (domain: ''
|
||||||
|
if [[ ! -e /var/lib/stalwart-mail/dkim/rsa-${domain}.key ]]; then
|
||||||
|
echo "Generating DKIM key for ${domain} (rsa)"
|
||||||
|
${lib.getExe pkgs.openssl} genrsa -traditional -out /var/lib/stalwart-mail/dkim/rsa-${domain}.key 2048
|
||||||
|
fi
|
||||||
|
if [[ ! -e /var/lib/stalwart-mail/dkim/ed25519-${domain}.key ]]; then
|
||||||
|
echo "Generating DKIM key for ${domain} (ed25519)"
|
||||||
|
${lib.getExe pkgs.openssl} genpkey -algorithm ed25519 -out /var/lib/stalwart-mail/dkim/ed25519-${domain}.key
|
||||||
|
fi
|
||||||
|
'')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
RuntimeDirectory = "stalwart-mail";
|
||||||
|
ReadWritePaths = [ config.services.idmail.dataDir ];
|
||||||
|
ExecStart = lib.mkForce [
|
||||||
|
""
|
||||||
|
"${cfg.package}/bin/stalwart-mail --config=/run/stalwart-mail/config.toml"
|
||||||
|
];
|
||||||
|
RestartSec = "60"; # Retry every minute
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.stalwart-mail = {
|
||||||
|
enable = true;
|
||||||
|
settings =
|
||||||
|
let
|
||||||
|
case = field: check: value: data: {
|
||||||
|
"if" = field;
|
||||||
|
${check} = value;
|
||||||
|
"then" = data;
|
||||||
|
};
|
||||||
|
ifthen = field: data: {
|
||||||
|
"if" = field;
|
||||||
|
"then" = data;
|
||||||
|
};
|
||||||
|
otherwise = value: { "else" = value; };
|
||||||
|
is-smtp = case "listener" "eq" "smtp";
|
||||||
|
is-authenticated = data: {
|
||||||
|
"if" = "!is_empty(authenticated_as)";
|
||||||
|
"then" = data;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
lib.mkForce {
|
||||||
|
config.local-keys = [
|
||||||
|
"store.*"
|
||||||
|
"directory.*"
|
||||||
|
"tracer.*"
|
||||||
|
"server.*"
|
||||||
|
"!server.blocked-ip.*"
|
||||||
|
"!server.allowed-ip.*"
|
||||||
|
"authentication.fallback-admin.*"
|
||||||
|
"cluster.node-id"
|
||||||
|
"storage.data"
|
||||||
|
"storage.blob"
|
||||||
|
"storage.lookup"
|
||||||
|
"storage.fts"
|
||||||
|
"storage.directory"
|
||||||
|
"lookup.default.hostname"
|
||||||
|
"certificate.*"
|
||||||
|
"auth.dkim.*"
|
||||||
|
"signature.*"
|
||||||
|
];
|
||||||
|
|
||||||
|
authentication.fallback-admin = {
|
||||||
|
user = "admin";
|
||||||
|
secret = "%{file:/run/stalwart-mail/admin-hash}%";
|
||||||
|
};
|
||||||
|
|
||||||
|
tracer.stdout = {
|
||||||
|
# Do not use the built-in journal tracer, as it shows much less auxiliary
|
||||||
|
# information for the same loglevel
|
||||||
|
type = "stdout";
|
||||||
|
level = "info";
|
||||||
|
ansi = false; # no colour markers to journald
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
store.db = {
|
||||||
|
type = "sqlite";
|
||||||
|
path = "${dataDir}/database.sqlite3";
|
||||||
|
};
|
||||||
|
|
||||||
|
store.idmail = {
|
||||||
|
type = "sqlite";
|
||||||
|
path = "${config.services.idmail.dataDir}/idmail.db";
|
||||||
|
query =
|
||||||
|
let
|
||||||
|
# Remove comments from SQL and make it single-line
|
||||||
|
toSingleLineSql =
|
||||||
|
sql:
|
||||||
|
lib.concatStringsSep " " (
|
||||||
|
lib.forEach (lib.flatten (lib.split "\n" sql)) (
|
||||||
|
line: lib.optionalString (builtins.match "^[[:space:]]*--.*" line == null) line
|
||||||
|
)
|
||||||
|
);
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# "SELECT name, type, secret, description, quota FROM accounts WHERE name = ?1 AND active = true";
|
||||||
|
name = toSingleLineSql ''
|
||||||
|
SELECT
|
||||||
|
m.address AS name,
|
||||||
|
'individual' AS type,
|
||||||
|
m.password_hash AS secret,
|
||||||
|
m.address AS description,
|
||||||
|
0 AS quota
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN domains AS d ON m.domain = d.domain
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.address = ?1
|
||||||
|
AND m.active = true
|
||||||
|
AND d.active = true
|
||||||
|
AND u.active = true
|
||||||
|
'';
|
||||||
|
# "SELECT member_of FROM group_members WHERE name = ?1";
|
||||||
|
members = "";
|
||||||
|
# "SELECT name FROM emails WHERE address = ?1";
|
||||||
|
recipients = toSingleLineSql ''
|
||||||
|
-- It is important that we return only one value here, but in theory three UNIONed
|
||||||
|
-- queries are guaranteed to be distinct. This is because a mailbox address
|
||||||
|
-- and alias address can never be the same, their cross-table uniqueness is guaranteed on insert.
|
||||||
|
-- The catch-all union can also only return something if @domain.tld is given as a parameter,
|
||||||
|
-- which is invalid for aliases and mailboxes.
|
||||||
|
--
|
||||||
|
-- Nonetheless, it may be beneficial to allow an alias to override an existing mailbox,
|
||||||
|
-- so we can have send-only mailboxes which have their incoming mail redirected somewhere else.
|
||||||
|
-- Therefore, we make sure to order the query by (aliases -> mailboxes -> catch all) and only return the
|
||||||
|
-- highest priority one.
|
||||||
|
SELECT name FROM (
|
||||||
|
-- Select the target of a matching alias (if any)
|
||||||
|
-- but make sure that all related parts are active.
|
||||||
|
SELECT a.target AS name, 1 AS rowOrder
|
||||||
|
FROM aliases AS a
|
||||||
|
JOIN domains AS d ON a.domain = d.domain
|
||||||
|
JOIN (
|
||||||
|
-- To check whether the owner is active we need to make a subquery
|
||||||
|
-- because the owner could be a user or mailbox
|
||||||
|
SELECT username
|
||||||
|
FROM users
|
||||||
|
WHERE active = true
|
||||||
|
UNION
|
||||||
|
SELECT m.address AS username
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
) AS u ON a.owner = u.username
|
||||||
|
WHERE a.address = ?1
|
||||||
|
AND a.active = true
|
||||||
|
AND d.active = true
|
||||||
|
-- Select the primary mailbox address if it matches and
|
||||||
|
-- all related parts are active.
|
||||||
|
UNION
|
||||||
|
SELECT m.address AS name, 2 AS rowOrder
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN domains AS d ON m.domain = d.domain
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.address = ?1
|
||||||
|
AND m.active = true
|
||||||
|
AND d.active = true
|
||||||
|
AND u.active = true
|
||||||
|
-- Finally, select any catch_all address that would catch this.
|
||||||
|
-- Again make sure everything is active.
|
||||||
|
UNION
|
||||||
|
SELECT d.catch_all AS name, 3 AS rowOrder
|
||||||
|
FROM domains AS d
|
||||||
|
JOIN mailboxes AS m ON d.catch_all = m.address
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE ?1 = ('@' || d.domain)
|
||||||
|
AND d.active = true
|
||||||
|
AND m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
ORDER BY rowOrder, name ASC
|
||||||
|
LIMIT 1
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
# "SELECT address FROM emails WHERE name = ?1 AND type != 'list' ORDER BY type DESC, address ASC";
|
||||||
|
emails = toSingleLineSql ''
|
||||||
|
-- Return first the primary address, then any aliases.
|
||||||
|
SELECT address FROM (
|
||||||
|
-- Select primary address, if active
|
||||||
|
SELECT m.address AS address, 1 AS rowOrder
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN domains AS d ON m.domain = d.domain
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.address = ?1
|
||||||
|
AND m.active = true
|
||||||
|
AND d.active = true
|
||||||
|
AND u.active = true
|
||||||
|
-- Select any active aliases
|
||||||
|
UNION
|
||||||
|
SELECT a.address AS address, 2 AS rowOrder
|
||||||
|
FROM aliases AS a
|
||||||
|
JOIN domains AS d ON a.domain = d.domain
|
||||||
|
JOIN (
|
||||||
|
-- To check whether the owner is active we need to make a subquery
|
||||||
|
-- because the owner could be a user or mailbox
|
||||||
|
SELECT username
|
||||||
|
FROM users
|
||||||
|
WHERE active = true
|
||||||
|
UNION
|
||||||
|
SELECT m.address AS username
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
) AS u ON a.owner = u.username
|
||||||
|
WHERE a.target = ?1
|
||||||
|
AND a.active = true
|
||||||
|
AND d.active = true
|
||||||
|
-- Select the catch-all marker, if we are the target.
|
||||||
|
UNION
|
||||||
|
-- Order 2 is correct, it counts as an alias
|
||||||
|
SELECT ('@' || d.domain) AS address, 2 AS rowOrder
|
||||||
|
FROM domains AS d
|
||||||
|
JOIN mailboxes AS m ON d.catch_all = m.address
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE d.catch_all = ?1
|
||||||
|
AND d.active = true
|
||||||
|
AND m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
ORDER BY rowOrder, address ASC
|
||||||
|
)
|
||||||
|
'';
|
||||||
|
# "SELECT address FROM emails WHERE address LIKE '%' || ?1 || '%' AND type = 'primary' ORDER BY address LIMIT 5";
|
||||||
|
verify = toSingleLineSql ''
|
||||||
|
SELECT m.address AS address
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN domains AS d ON m.domain = d.domain
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.address LIKE '%' || ?1 || '%'
|
||||||
|
AND m.active = true
|
||||||
|
AND d.active = true
|
||||||
|
AND u.active = true
|
||||||
|
UNION
|
||||||
|
SELECT a.address AS address
|
||||||
|
FROM aliases AS a
|
||||||
|
JOIN domains AS d ON a.domain = d.domain
|
||||||
|
JOIN (
|
||||||
|
-- To check whether the owner is active we need to make a subquery
|
||||||
|
-- because the owner could be a user or mailbox
|
||||||
|
SELECT username
|
||||||
|
FROM users
|
||||||
|
WHERE active = true
|
||||||
|
UNION
|
||||||
|
SELECT m.address AS username
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
) AS u ON a.owner = u.username
|
||||||
|
WHERE a.address LIKE '%' || ?1 || '%'
|
||||||
|
AND a.active = true
|
||||||
|
AND d.active = true
|
||||||
|
ORDER BY address
|
||||||
|
LIMIT 5
|
||||||
|
'';
|
||||||
|
# "SELECT p.address FROM emails AS p JOIN emails AS l ON p.name = l.name WHERE p.type = 'primary' AND l.address = ?1 AND l.type = 'list' ORDER BY p.address LIMIT 50";
|
||||||
|
# XXX: We don't actually expand, but return the same address if it exists since we don't support mailing lists
|
||||||
|
expand = toSingleLineSql ''
|
||||||
|
SELECT m.address AS address
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN domains AS d ON m.domain = d.domain
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.address = ?1
|
||||||
|
AND m.active = true
|
||||||
|
AND d.active = true
|
||||||
|
AND u.active = true
|
||||||
|
UNION
|
||||||
|
SELECT a.address AS address
|
||||||
|
FROM aliases AS a
|
||||||
|
JOIN domains AS d ON a.domain = d.domain
|
||||||
|
JOIN (
|
||||||
|
-- To check whether the owner is active we need to make a subquery
|
||||||
|
-- because the owner could be a user or mailbox
|
||||||
|
SELECT username
|
||||||
|
FROM users
|
||||||
|
WHERE active = true
|
||||||
|
UNION
|
||||||
|
SELECT m.address AS username
|
||||||
|
FROM mailboxes AS m
|
||||||
|
JOIN users AS u ON m.owner = u.username
|
||||||
|
WHERE m.active = true
|
||||||
|
AND u.active = true
|
||||||
|
) AS u ON a.owner = u.username
|
||||||
|
WHERE a.address = ?1
|
||||||
|
AND a.active = true
|
||||||
|
AND d.active = true
|
||||||
|
ORDER BY address
|
||||||
|
LIMIT 50
|
||||||
|
'';
|
||||||
|
# "SELECT 1 FROM emails WHERE address LIKE '%@' || ?1 LIMIT 1";
|
||||||
|
domains = toSingleLineSql ''
|
||||||
|
SELECT domain
|
||||||
|
FROM domains
|
||||||
|
WHERE domain = ?1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
storage = {
|
||||||
|
data = "db";
|
||||||
|
fts = "db";
|
||||||
|
lookup = "db";
|
||||||
|
blob = "db";
|
||||||
|
directory = "idmail";
|
||||||
|
};
|
||||||
|
|
||||||
|
directory.idmail = {
|
||||||
|
type = "sql";
|
||||||
|
store = "idmail";
|
||||||
|
columns = {
|
||||||
|
name = "name";
|
||||||
|
description = "description";
|
||||||
|
secret = "secret";
|
||||||
|
email = "email";
|
||||||
|
#quota = "quota";
|
||||||
|
class = "type";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
resolver = {
|
||||||
|
type = "system";
|
||||||
|
public-suffix = [
|
||||||
|
"file://${pkgs.publicsuffix-list}/share/publicsuffix/public_suffix_list.dat"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
config.resource.spam-filter = "file://${config.services.stalwart-mail.package}/etc/stalwart/spamfilter.toml";
|
||||||
|
config.resource.webadmin = "file://${config.services.stalwart-mail.package.webadmin}/webadmin.zip";
|
||||||
|
webadmin.path = "/var/cache/stalwart-mail";
|
||||||
|
|
||||||
|
certificate.default = {
|
||||||
|
cert = "%{file:${config.security.acme.certs.${domain}.directory}/fullchain.pem}%";
|
||||||
|
private-key = "%{file:${config.security.acme.certs.${domain}.directory}/key.pem}%";
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
lookup.default.hostname = domain;
|
||||||
|
server = {
|
||||||
|
tls = {
|
||||||
|
certificate = "default";
|
||||||
|
ignore-client-order = true;
|
||||||
|
};
|
||||||
|
socket = {
|
||||||
|
nodelay = true;
|
||||||
|
reuse-addr = true;
|
||||||
|
};
|
||||||
|
listener = {
|
||||||
|
smtp = {
|
||||||
|
protocol = "smtp";
|
||||||
|
bind = "[::]:25";
|
||||||
|
};
|
||||||
|
submissions = {
|
||||||
|
protocol = "smtp";
|
||||||
|
bind = "[::]:465";
|
||||||
|
tls.implicit = true;
|
||||||
|
};
|
||||||
|
imaps = {
|
||||||
|
protocol = "imap";
|
||||||
|
bind = "[::]:993";
|
||||||
|
tls.implicit = true;
|
||||||
|
};
|
||||||
|
http = {
|
||||||
|
# jmap, web interface
|
||||||
|
protocol = "http";
|
||||||
|
bind = "[::]:8080";
|
||||||
|
url = "https://${domain}";
|
||||||
|
use-x-forwarded = true;
|
||||||
|
};
|
||||||
|
sieve = {
|
||||||
|
protocol = "managesieve";
|
||||||
|
bind = "[::]:4190";
|
||||||
|
tls.implicit = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
imap = {
|
||||||
|
request.max-size = 52428800;
|
||||||
|
auth = {
|
||||||
|
max-failures = 3;
|
||||||
|
allow-plain-text = false;
|
||||||
|
};
|
||||||
|
timeout = {
|
||||||
|
authentication = "30m";
|
||||||
|
anonymous = "1m";
|
||||||
|
idle = "30m";
|
||||||
|
};
|
||||||
|
rate-limit = {
|
||||||
|
requests = "20000/1m";
|
||||||
|
concurrent = 32;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
auth.dkim.sign = [
|
||||||
|
(ifthen "is_local_domain('*', sender_domain)" "['rsa-' + sender_domain, 'ed25519-' + sender_domain]")
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
|
||||||
|
signature = lib.mergeAttrsList (
|
||||||
|
lib.forEach mailDomains (domain: {
|
||||||
|
"ed25519-${domain}" = {
|
||||||
|
private-key = "%{file:/var/lib/stalwart-mail/dkim/ed25519-${domain}.key}%";
|
||||||
|
inherit domain;
|
||||||
|
selector = "ed_default";
|
||||||
|
headers = [
|
||||||
|
"From"
|
||||||
|
"To"
|
||||||
|
"Date"
|
||||||
|
"Subject"
|
||||||
|
"Message-ID"
|
||||||
|
];
|
||||||
|
algorithm = "ed25519-sha256";
|
||||||
|
canonicalization = "relaxed/relaxed";
|
||||||
|
set-body-length = false;
|
||||||
|
report = true;
|
||||||
|
};
|
||||||
|
"rsa-${domain}" = {
|
||||||
|
private-key = "%{file:/var/lib/stalwart-mail/dkim/rsa-${domain}.key}%";
|
||||||
|
inherit domain;
|
||||||
|
selector = "rsa_default";
|
||||||
|
headers = [
|
||||||
|
"From"
|
||||||
|
"To"
|
||||||
|
"Date"
|
||||||
|
"Subject"
|
||||||
|
"Message-ID"
|
||||||
|
];
|
||||||
|
algorithm = "rsa-sha256";
|
||||||
|
canonicalization = "relaxed/relaxed";
|
||||||
|
set-body-length = false;
|
||||||
|
report = true;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
session.extensions = {
|
||||||
|
pipelining = true;
|
||||||
|
chunking = true;
|
||||||
|
requiretls = true;
|
||||||
|
no-soliciting = "";
|
||||||
|
dsn = false;
|
||||||
|
expn = [
|
||||||
|
(is-authenticated true)
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
vrfy = [
|
||||||
|
(is-authenticated true)
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
future-release = [
|
||||||
|
(is-authenticated "30d")
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
deliver-by = [
|
||||||
|
(is-authenticated "365d")
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
mt-priority = [
|
||||||
|
(is-authenticated "mixer")
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
session.ehlo = {
|
||||||
|
require = true;
|
||||||
|
reject-non-fqdn = [
|
||||||
|
(is-smtp true)
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
session.rcpt = {
|
||||||
|
catch-all = true;
|
||||||
|
relay = [
|
||||||
|
(is-authenticated true)
|
||||||
|
(otherwise false)
|
||||||
|
];
|
||||||
|
max-recipients = 25;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
646
flake.lock
646
flake.lock
File diff suppressed because it is too large
Load diff
|
@ -4,6 +4,10 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
nixp-meta.url = "git+https://forge.lel.lol/patrick/nixp-meta.git";
|
nixp-meta.url = "git+https://forge.lel.lol/patrick/nixp-meta.git";
|
||||||
|
idmail = {
|
||||||
|
url = "github:oddlama/idmail/";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
nixpkgs-octoprint.url = "github:patrickdag/nixpkgs/octoprint-update";
|
nixpkgs-octoprint.url = "github:patrickdag/nixpkgs/octoprint-update";
|
||||||
nixpkgs-wayland = {
|
nixpkgs-wayland = {
|
||||||
|
|
|
@ -37,10 +37,10 @@
|
||||||
services.xserver.xkb = {
|
services.xserver.xkb = {
|
||||||
layout = "de";
|
layout = "de";
|
||||||
};
|
};
|
||||||
services.logkeys = {
|
# services.logkeys = {
|
||||||
enable = true;
|
# enable = true;
|
||||||
device = "/dev/input/event15";
|
# device = "/dev/input/event15";
|
||||||
};
|
# };
|
||||||
|
|
||||||
boot.binfmt.emulatedSystems = [
|
boot.binfmt.emulatedSystems = [
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
|
|
|
@ -38,7 +38,8 @@ let
|
||||||
ipOf =
|
ipOf =
|
||||||
hostName:
|
hostName:
|
||||||
if hostName == "octoprint" then
|
if hostName == "octoprint" then
|
||||||
nodes.testienix.config.wireguard.elisabeth.ipv4
|
#nodes.testienix.config.wireguard.elisabeth.ipv4
|
||||||
|
"0.0.0.0"
|
||||||
else
|
else
|
||||||
nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4;
|
nodes."elisabeth-${hostName}".config.wireguard.elisabeth.ipv4;
|
||||||
in
|
in
|
||||||
|
|
27
hosts/mailnix/default.nix
Normal file
27
hosts/mailnix/default.nix
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
imports = [
|
||||||
|
../../config/basic
|
||||||
|
../../config/support/initrd-ssh.nix
|
||||||
|
../../config/support/zfs.nix
|
||||||
|
../../config/services/idmail.nix
|
||||||
|
../../config/services/stalwart.nix
|
||||||
|
|
||||||
|
./net.nix
|
||||||
|
./fs.nix
|
||||||
|
];
|
||||||
|
boot = {
|
||||||
|
initrd.availableKernelModules = [
|
||||||
|
"virtio_pci"
|
||||||
|
"virtio_net"
|
||||||
|
"virtio_scsi"
|
||||||
|
"virtio_blk"
|
||||||
|
"virtio_gpu"
|
||||||
|
];
|
||||||
|
kernelParams = [ "console=tty" ];
|
||||||
|
loader = {
|
||||||
|
systemd-boot.enable = true;
|
||||||
|
efi.canTouchEfiVariables = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nixpkgs.hostPlatform = "aarch64-linux";
|
||||||
|
}
|
32
hosts/mailnix/fs.nix
Normal file
32
hosts/mailnix/fs.nix
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
disko.devices = {
|
||||||
|
disk = {
|
||||||
|
drive = rec {
|
||||||
|
type = "disk";
|
||||||
|
device = "/dev/disk/by-id/${config.secrets.secrets.local.disko.drive}";
|
||||||
|
content = with lib.disko.gpt; {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
boot = (partEfi "256M") // {
|
||||||
|
device = "${device}-part1";
|
||||||
|
};
|
||||||
|
rpool = (partLuksZfs "drive" "rpool" "100%") // {
|
||||||
|
device = "${device}-part2";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
zpool = with lib.disko.zfs; {
|
||||||
|
rpool = mkZpool { datasets = impermanenceZfsDatasets; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/state".neededForBoot = true;
|
||||||
|
fileSystems."/persist".neededForBoot = true;
|
||||||
|
boot.initrd.systemd.services."zfs-import-panzer".after = [ "cryptsetup.target" ];
|
||||||
|
boot.initrd.systemd.services."zfs-import-rpool".after = [ "cryptsetup.target" ];
|
||||||
|
|
||||||
|
}
|
73
hosts/mailnix/net.nix
Normal file
73
hosts/mailnix/net.nix
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
{
|
||||||
|
networking.hostId = config.secrets.secrets.local.networking.hostId;
|
||||||
|
networking.domain = config.secrets.secrets.global.domains.mail_public;
|
||||||
|
|
||||||
|
boot.initrd.systemd.network = {
|
||||||
|
enable = true;
|
||||||
|
networks = {
|
||||||
|
inherit (config.systemd.network.networks) "lan01";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.network.networks = {
|
||||||
|
"lan01" =
|
||||||
|
let
|
||||||
|
icfg = config.secrets.secrets.local.networking.interfaces.lan01;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
address = [
|
||||||
|
icfg.hostCidrv4
|
||||||
|
(lib.net.cidr.hostCidr 1 icfg.hostCidrv6)
|
||||||
|
];
|
||||||
|
gateway = [ "fe80::1" ];
|
||||||
|
routes = [
|
||||||
|
{ Destination = "172.31.1.1"; }
|
||||||
|
{
|
||||||
|
Gateway = "172.31.1.1";
|
||||||
|
GatewayOnLink = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
matchConfig.MACAddress = icfg.mac;
|
||||||
|
networkConfig.IPv6PrivacyExtensions = "yes";
|
||||||
|
linkConfig.RequiredForOnline = "routable";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
age.secrets.cloudflare_token_acme = {
|
||||||
|
rekeyFile = ./secrets/cloudflare_api_token.age;
|
||||||
|
mode = "440";
|
||||||
|
group = "acme";
|
||||||
|
};
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults = {
|
||||||
|
email = config.secrets.secrets.global.devEmail;
|
||||||
|
dnsProvider = "cloudflare";
|
||||||
|
dnsPropagationCheck = true;
|
||||||
|
reloadServices = [ "nginx" ];
|
||||||
|
credentialFiles = {
|
||||||
|
"CF_DNS_API_TOKEN_FILE" = config.age.secrets.cloudflare_token_acme.path;
|
||||||
|
"CF_ZONE_API_TOKEN_FILE" = config.age.secrets.cloudflare_token_acme.path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
networking.nftables.firewall.zones.untrusted.interfaces = [ "lan01" ];
|
||||||
|
security.acme.certs = {
|
||||||
|
"${config.secrets.secrets.global.domains.mail_public}" = {
|
||||||
|
domain = config.secrets.secrets.global.domains.mail_public;
|
||||||
|
extraDomainNames = [ "*.${config.secrets.secrets.global.domains.mail_public}" ];
|
||||||
|
};
|
||||||
|
"${config.secrets.secrets.global.domains.mail_private}" = {
|
||||||
|
domain = config.secrets.secrets.global.domains.mail_private;
|
||||||
|
extraDomainNames = [ "*.${config.secrets.secrets.global.domains.mail_private}" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
environment.persistence."/state".directories = [
|
||||||
|
{
|
||||||
|
directory = "/var/lib/acme";
|
||||||
|
user = "acme";
|
||||||
|
group = "acme";
|
||||||
|
mode = "0755";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
15
hosts/mailnix/secrets/cloudflare_api_token.age
Normal file
15
hosts/mailnix/secrets/cloudflare_api_token.age
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 uhnRibm92XSz2UcJWT43CrsZfOrSzUyqVFU8nWiYEXs
|
||||||
|
QNxh6YGDCgSSoCWLthZlou7F7i9OJpunB+/6J4ogk2k
|
||||||
|
-> piv-p256 XTQkUA AzTDTMXLU5jTp54ysvnVIDo5lIb5ED1zkP8659tTH2JJ
|
||||||
|
VLO6rtfY5poFGVH/eeD+T/xrlNdPGnlLQ6mK1HytT8A
|
||||||
|
-> piv-p256 ZFgiIw AnwL/t0GNZI3/y7KlatHLebToW1pJLfOasODGQ7ogriz
|
||||||
|
Wl7xm6+a1qmqLeTZszpO0XG96BcDRO5l8wvpc0atW0Y
|
||||||
|
-> piv-p256 5vmPtQ AzC3t9sPdKF/IPkJSqhldnx3Mnkc84DCD13l8tYqZIWd
|
||||||
|
GaNzRxPoSOy/kEuLzbXpiRDo5F2hZT8KriXpgqZkQ5Y
|
||||||
|
-> piv-p256 ZFgiIw ApFdJVoW4zoWq38fE27TR/OFEDs4Wub1g3q6RiF+fDTR
|
||||||
|
IypnQqeluntk31gez5I6eYtlKiY/8sy+dXNkpWhdwPs
|
||||||
|
-> wX-grease
|
||||||
|
neAQttCOcpQWsfSpI38jdOjODJYK8uOhqjWsZOLWlHZaRUQtoyXI
|
||||||
|
--- r44AgWizs6H92oY6hKMs67ARXqr8Je0Z0cIJr9xidBg
|
||||||
|
°ß¦Ñ¨â<>Ÿî̪øÙ¤Ph\œdv_µúí¥]’ÀÓšÆÜŠÚ˜ùÄE<C384>ʃ´¯‹æewI’é‡t.¬²WÃÂ6ZFi
|
|
@ -0,0 +1,17 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 7NpA9hDsF1TwTVRvAKHpovHSUCr0Gg11mzsubZemyDs
|
||||||
|
3eE/PWJizZWIDMr3Dt6012F6db/nlmhpM8y06eLO48s
|
||||||
|
-> piv-p256 ZFgiIw Alb1ynSHX7YiSZkhDbId9MGoQeRacJJ9Mv4a64WVxXdE
|
||||||
|
gTRZ2XC+K6bZ9my7B28oXJGfQ2fvHFZHDTGWfjzQMdA
|
||||||
|
-> piv-p256 XTQkUA AhrEyyEHX3BxETBIWDmbK5pfzmfcFCmTWX2psLAzGhYS
|
||||||
|
XFR2JtZJikRDATiZ8eflzShfvrrUMLp00s2+0N54tiI
|
||||||
|
-> piv-p256 ZFgiIw A/MHWK7H85OTk0JLH8y0t7QHcG4xRNwYwEuWPuVBLojT
|
||||||
|
Vbwyekt8SwUfJzfyualAekCf/MGW+Igs/ZALTydd9Qc
|
||||||
|
-> piv-p256 5vmPtQ Av/BlH1sZh++RL4fh2NS2HN7yipM9nLfT90OiRh9Flbj
|
||||||
|
kzi2VBRvIxbBbze4iBahMGROtnSOKznXzCNS0PR9TG0
|
||||||
|
-> N"-grease p, Pb+NMCL ^
|
||||||
|
BeBdV3XQgNJVO309KZx1hphkECZLRrCqPmEoR3pEzB4I3L8Q6ur+4ALEy2mLjmSp
|
||||||
|
Mir7Hdy3Pg
|
||||||
|
--- Klvxozur3RYybVYWbakGVXiTymaTfOoFXcwnj7hsEAY
|
||||||
|
믰zéR¼õÍÅx-›rŽ@ß`Ö«? ka´L53<35>öܘ°}B<>Ê¡ü7 -6B»t¤h릂öá$<24>h·‡ò&ÐBƒ.™7O„ä„Þ.ßëk±g·m5Û
|
||||||
|
¸PÚ<EFBFBD>kѱW<EFBFBD>‰4Ûâ1GyÔâ1%È<ù°ê›?z<>7êÿéfûXcgMaÝnn!
|
|
@ -0,0 +1,18 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 Ud9UzEUeDmMIb90vOTWVkdDvIcebEwSzI4Ii8M5jAUI
|
||||||
|
4rloQ7OzT0voyVboOaWLvOxvrlYxtcOY91dt1lq6wtg
|
||||||
|
-> piv-p256 ZFgiIw Aro3d4Lv0WTRa1OiE1f0hROViqhes5elbt5a+uKCS0y7
|
||||||
|
UZFViBihW5si4+JbzN1OyzWDuWiFwWfoVls+EH+EUmk
|
||||||
|
-> piv-p256 XTQkUA A0mE5ni66UlnsafkVu3MK0N6aTX2UtV+jADROmg4M1aN
|
||||||
|
cYqc/9CCT1PC3inzqfQvK59MCHHNEtIhpvOvqL7E2nA
|
||||||
|
-> piv-p256 ZFgiIw AnFFxNY3lsY4fsze7Hm4vAmK7zZKGA4qEfSUH5aIkQ4j
|
||||||
|
1OwdPteTYQCWrt4IkRhflolMXJ+FUMm91n3p7icqnsc
|
||||||
|
-> piv-p256 5vmPtQ Amg+62BwmCb9ZQmZ74PzT0/FheaK2OzfyGgbHYcyo5Cl
|
||||||
|
OnlF+hKq6p91i3Jk+iwYQ2ByRTgmZX57mIAIpMRoCD8
|
||||||
|
-> >aAO.fE-grease ' 7nl% c#t R]j<n
|
||||||
|
pC7HsBXeonXLPKBlbzkYZepNa2/RDKAwF9UvfnYPbw6ouLI6wuwmYO1moo2ERk4c
|
||||||
|
D7yBUPkIdFKD
|
||||||
|
--- 9oExlogv7s/uU+7/UeLOrs0v26TpK6fW1E7Y4hT4umc
|
||||||
|
G¥É¶ÒdMç*óùThrm¾÷®ÜPÙW{
|
||||||
|
‘kŸÌ¦Z<áñ†h¡þ,¬nxnúE‹€
|
||||||
|
Uoè¶QßÙï§S&õÇ·ÿ™ÓéÁ>w•
|
BIN
hosts/mailnix/secrets/generated/idmail-user-hash_admin.age
Normal file
BIN
hosts/mailnix/secrets/generated/idmail-user-hash_admin.age
Normal file
Binary file not shown.
16
hosts/mailnix/secrets/generated/idmail-user-pw_admin.age
Normal file
16
hosts/mailnix/secrets/generated/idmail-user-pw_admin.age
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 wbI8kJZQwT22oltbFeQSWX/Kdb+QPGy/yq5FWi4tURE
|
||||||
|
QkCRyLTSekF7e+9tFhlr36Rn0vmEZ4Ad7nmYFyDrUIE
|
||||||
|
-> piv-p256 ZFgiIw AnlFacrcAVmYBv6lWsStu/GyihNjZxqBiRArNYuD6UOk
|
||||||
|
L8kywowjuGRQ7YshqlitmhvD5DlTKtnhdh0ufeybyEw
|
||||||
|
-> piv-p256 XTQkUA Anc9FjiKfMpMqjgLBF3gyTdTpdOkmQisBWNSQLPkn7qa
|
||||||
|
Nc6+wZvNadzIo1pI0Q1xV0LEuWZ5nLMC6e3PwtpviX8
|
||||||
|
-> piv-p256 ZFgiIw Aqym6w/aiUpbfE44JfxlV0eAS/naenJCHZNWqzwypHLN
|
||||||
|
ppB2QXwm0i64LaQnyG9NxjT2MRaI7v6Xj8L3KxB7s8E
|
||||||
|
-> piv-p256 5vmPtQ ArYm0jb3ONfijVVVWJHVUXfPm+hOJAIVn2+RUAXmIW0e
|
||||||
|
/rijgC2Iok8VcAbBTeWgQ7KB2u9T7TA03WfE9Ju3UP4
|
||||||
|
-> M^g-grease P Jl/S]j
|
||||||
|
DY4S+rVP2pA38O2f+JWEC5ODoxEXnRdO37COHof6cB85a7a64+FWT1QcAI+P+CEx
|
||||||
|
Y6FiZ2sYbqwePti5qjUxjg
|
||||||
|
--- KfDaVg+3cbtTkC/1i2dIORAEjPLrwS5ot4szuOMqMZ0
|
||||||
|
u2eN}ÍÅ5éW¡’<C2A1>¯Ø¨>|‚×øéP)æ¿„XF'l¢˜€ó°˜<C2B0>O×ÞQZµ!ò[>Y÷þùÙ–—¢Ö£Æ¹cÏ@íW;q ?'ç¦Mæ
|
18
hosts/mailnix/secrets/generated/initrd_host_ed25519_key.age
Normal file
18
hosts/mailnix/secrets/generated/initrd_host_ed25519_key.age
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 ddFv+EKlJUwePVA7CiwFOA/mECyJ9pC328u5r9Bjhz4
|
||||||
|
5c05Nlc1ADOpUq5MugDuHJqSz4OW4Yupl0UBl9DxyDk
|
||||||
|
-> piv-p256 ZFgiIw AgiBCvmbqRaShnyh+NuDFFESQ9Q5sZZ/YjYXelOzCYyV
|
||||||
|
/6/igWsiKPwTlydwiAR1ZECyURFkBiJWCppdXP5GDRk
|
||||||
|
-> piv-p256 XTQkUA An4etg/KtGFdnw74QM+QW9vRkrAxEZmMjhexLKENVnV3
|
||||||
|
m8UleuJcvy/OZhlZrOEguL+0hWo5n2Ykgboq8BqFrdU
|
||||||
|
-> piv-p256 ZFgiIw A1vxQkA8CeZGrXNcvBZo57iL82PiTPm0hP3KODzWnU/z
|
||||||
|
USt8rTNK7l9VUUyAiSnDiLVQgLZiFZQgcy04lWdk+nM
|
||||||
|
-> piv-p256 5vmPtQ AnAB3M/AWePGjmIUdoH0rSHg+gDnxg62RPy9qgHAgIIN
|
||||||
|
7PPd5p4sXrbDvZBITS3zMnG7qNmlj61hdHPlVo5cJDQ
|
||||||
|
-> qtLMz'K-grease ?Rtv +~4H. vh
|
||||||
|
ZBK1Zs8LKTiGvOSxH/dacE3yc1ouqSylHM5Ahv+HmR89RQX/JR4y3Gtec+G2W0Ty
|
||||||
|
Dh9z2wVbCDlJTTt+N+9sLvV/b5+wETpwhPmiSWbh92yvNYH1yLQ
|
||||||
|
--- jynsWcgTRZR51+fu9nqHP5yTxxz1BovM1s2YY+0uL2I
|
||||||
|
ìS€Ó¿Þ4}°NTÀ (Ú뮃+
¬e9•_³qÛã2OÚÂ)=òw¸»/¼/D|šv`ÓàŒ6æXI³/™®””ˆ‹îw^ÆÇ+hñ¨ˆÃÀ<11>6núrÒå˜q†²ü¢<>@Îf—2
ÇlîÞ/¤Ý“z—7,ôrFÇPÈ6ÎÓ€‰e1Nè4‡F»SÒ©¹<C2A9>ª8»Ì·¯g…]iϳ}n)ÒM×D¬ªH%ë^28(…«8\Ç`AñCƒÐ½/û•<÷%ûØ8°ú©ÀÚÔ\eÑäÿ=¹ýâ(*6§a ß“‘V\G³ôuIÕø›ÓÓ|•´gÝ—™Õ#<23>²v&@ÞæóÑ…
‡æÉHâ´IhþXÀìñ÷îšÓÈY9ƒÐøÎÛM5%‡ËeÆ6?2º¿<C2BF>—"„¥
|
||||||
|
Y<EFBFBD>æíM<EFBFBD>#Žñã‘L*6*!ùJMœ&
Gó%C3ô4s<34>ÇÙ‚<C399>©mÑÛA?—€³9|þMȺ¿OSrÍÍ+ó3†ÇQeþãRLK—Âue–?{=‡ýíîöš™€-±¼[⾊ˆüôëm
|
||||||
|
Û•øœ>¦QT7‰œ™–ô1‹z
|
16
hosts/mailnix/secrets/generated/resticpasswd.age
Normal file
16
hosts/mailnix/secrets/generated/resticpasswd.age
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 PdEHSeb3vou1ceHtkrlTbsu5BGWZ2onVCXPCwmW8znk
|
||||||
|
q8UKSDCiI+oZp+iODHddauFYFbLdc82tEo+Bsu2bgbo
|
||||||
|
-> piv-p256 ZFgiIw AnZuTRltFip1RHFY1dr+uTJPGbAYFzWpU/HEiZYuMIgz
|
||||||
|
r0nxJt1eZsXsnCnQ0Ls+kYqyz/PJCUjef9uvziqMqls
|
||||||
|
-> piv-p256 XTQkUA Au50Oa5SpTyUFjF4W6ETiofTruRqQItE94SmHRPzR4Y2
|
||||||
|
T9m1cYYtJr8TQuZYquoJUM+uDeim8llDiMVk3N+kDqk
|
||||||
|
-> piv-p256 ZFgiIw A/6WS2AnElPTKjwYT6K7CWnL8bolB6HNlQnuqjQ8lKt+
|
||||||
|
/0StgIwLSpVT7NyOJLxsPJz9TtfAOZU+qWls8gYkkFE
|
||||||
|
-> piv-p256 5vmPtQ A92v/hxaXEVRNqrsNhFuKCn5TllPrJCGk1e726IDBVo+
|
||||||
|
+yCS8ZD3uO4UWwMhk9xqWSWZ3UGgmBkIAqAtBGKF8Nw
|
||||||
|
-> a^_IFyLy-grease
|
||||||
|
smwxe0ZqF7Qc1wsp0rYM20J5FjFiTQV2UpYfUUgt3edM0+iMmBzHG9EPxKjGNmt9
|
||||||
|
yogZ0dRKId6mKtaNJeLHUDaCMhIsYAcrhNVGDvG9JOPdhRx9Og0
|
||||||
|
--- sG4CDChcMPfQS4gtEDGd+bH/WKNXi5ohWX4NTNkaAi0
|
||||||
|
⹎¹Öod‡6îí?áõK<C3B5>ç¾|¤ë$ýØd(Ó@)Ó·îÑ<1B>ùèø#ëE©™qÈá(¼!jYš`ôhlL<>ñµÃ!›_§õ¥®
|
BIN
hosts/mailnix/secrets/generated/stalwart-admin-hash.age
Normal file
BIN
hosts/mailnix/secrets/generated/stalwart-admin-hash.age
Normal file
Binary file not shown.
15
hosts/mailnix/secrets/generated/stalwart-admin-pw.age
Normal file
15
hosts/mailnix/secrets/generated/stalwart-admin-pw.age
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 GPymk3LLzkZtbBTHtb5BryUrBoDLImS86IoNS78OqlE
|
||||||
|
YrRCbTE595ZhRw6VxiBS9lTWB9yP4kijFqSFFdIiUpQ
|
||||||
|
-> piv-p256 ZFgiIw AsaTyNrw7YuguAOnLv5BFyU2lW61yY++gJmgNq2M+0wq
|
||||||
|
VGtlEXVaKpzomsLzjEiBtFE3q0emFLHsiWdahPS/WJU
|
||||||
|
-> piv-p256 XTQkUA A+Jsj+fWxo26HKlA5TOM2nB5WggS6TVRyfhKzNFQxpI2
|
||||||
|
RwQp5jlvHByeXPPsov5wMEuZ2pED/iFpVBVXVrKshH4
|
||||||
|
-> piv-p256 ZFgiIw A6HBCYbgWEEBsBQpJfiRwu672I9QOI2JF9eSeCztlBKJ
|
||||||
|
LOcgLvCIGWvs9Vhc1VuvGlYWKbnkJdngVhBDbdoMSLs
|
||||||
|
-> piv-p256 5vmPtQ A1VVL35NHnMdTROSGAKYG6V32v2D7KVo9eHuRPqejzas
|
||||||
|
WvdUexTb/Di4mv5owD/3ug2nn8Le/TMgJ+hZYbuED6c
|
||||||
|
-> M$iT~z2-grease SDOB\mE" Zxfxg kZ\' LB@$4
|
||||||
|
|
||||||
|
--- 2KhnAceJmwDjVhuEx3saTPzXbDOAjFcpp4DH2lgqsZE
|
||||||
|
Q¿ÞIu{¦¶ôþº¿ÎʼEvé†Ý7ês°¸Þ^éeLÁ%A‰kiÆé¹çhµ_ïû$•÷Ôr"z0AI‚¼ÝqÖ*¾½áS<C3A1>cL
|
16
hosts/mailnix/secrets/generated/stalwartHetznerSshKey.age
Normal file
16
hosts/mailnix/secrets/generated/stalwartHetznerSshKey.age
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
age-encryption.org/v1
|
||||||
|
-> X25519 rLdYm0p5eFCwaK8u7dz/Qco//mCdnylMwhLo6nX28R4
|
||||||
|
0XcnRiSWtCyxn1YISgdt/zVIFKPBPbKOueh+L1f62Fc
|
||||||
|
-> piv-p256 ZFgiIw A6fWtzhy3ylrbXZG4xjSGRh3Qrk7ZwMS7Fawt0XZvESm
|
||||||
|
wAMOQQvRnMCJ5DriuLHRsc9zJe5UazJBVvNNy97jJos
|
||||||
|
-> piv-p256 XTQkUA ArhoKZeRdRGXbHOcLiPcT1AruJEE7hckq7QiGKLfcm9d
|
||||||
|
YXh4slVMY/U+DfCBW6V/4Uf60Zb8RPyd0PrAHHB8xDE
|
||||||
|
-> piv-p256 ZFgiIw AsjeXhDC4x+6TPG902gZSlW9qFC0JVoznTVmnpQgip9f
|
||||||
|
ZxDSKVSBiGCGVE1w+8yZwEJx59DkdFy/6Iq1tbHQ41I
|
||||||
|
-> piv-p256 5vmPtQ AmlUti+62DpPs4k9HN+ZdKry9pwPjS1HAtnTq9xm1zT1
|
||||||
|
zTmFw+xHDQSLkDyVXC8MtlxD5cw/tQ1yK5zlYoDKv8Y
|
||||||
|
-> w0-grease /mVZ/4hd jq'R
|
||||||
|
fvJoC6ucvHgsXQysHHQhXQQ3TMUhFIPpSHwOURHSHn/+9qFVd02Ey0DWl9LujA
|
||||||
|
--- 5VjQP6nmIwBXtA/0+zL+EQt9eZHtyp6oD6u5IPgW1s8
|
||||||
|
0ös¤(Âî(ÍÙ‰ñ·í’XÎÞ5UJ —³p›ÁŽ·‡ùÏ}:ÔyˆAr÷¨_ã6÷
|
||||||
|
XDæ¬Fá9ÖŸ?1¿‡ä]ŒÐ4{½EhÆ<68>±ê”¿ë&~SÝAèÖS² dVJËeÏSüˆ0/öWG½€ºèp^ßfÉŒ÷ú”‰<E2809D>Bê"^ìøÿÀÓ¶ÀÔ‚<C394>¯N×:ÒçEiBÞ·lK4I1<49>ï'ðˆK2à>^îìàݽ÷L)x¶§ë\«qè.Ýè#´¸.Yþ¢rÌ8‹sc‰NRQ66ºŠªxÍZ<C38D>)<29>¡Ø¹Bv)ÒíÊž<C38A>¥³4½¯–"$õK dØÏMp*=¯<>Ρ³åž«OØâsÁÅñ¼úä3CE#;¸!.Á.‘4ITäÄ÷{¢€f<E282AC>Tˆl”Ѻ ¥Ö{¶éÚëàÕ±™bxHn7^×Ë<C397>_%¡5Òfq¾ãPL‡lŒ`×Á0‰?-!ä½íuEJ™[•%bŽENWíÖùC,øE¹1´1a1ü€{EƸPcÇõã<C3B5>XÎTsB¸ ³m]RH"#v§aßóñXA(Œ‚ŒóqœàcÀ`ÕŸ¹&<26>”OaÓÖù„p%º`‡½
|
1
hosts/mailnix/secrets/host.pub
Normal file
1
hosts/mailnix/secrets/host.pub
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGFqG1mU7UX0uNATdPaodHdSm9YYDV4grqmf266D0ajO
|
BIN
hosts/mailnix/secrets/secrets.nix.age
Normal file
BIN
hosts/mailnix/secrets/secrets.nix.age
Normal file
Binary file not shown.
|
@ -1,26 +0,0 @@
|
||||||
{
|
|
||||||
inputs,
|
|
||||||
lib,
|
|
||||||
minimal,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
inputs.nixos-hardware.nixosModules.common-pc
|
|
||||||
inputs.nixos-hardware.nixosModules.common-pc-ssd
|
|
||||||
|
|
||||||
../../config/basic
|
|
||||||
|
|
||||||
../../config/support/initrd-ssh.nix
|
|
||||||
../../config/support/physical.nix
|
|
||||||
../../config/support/zfs.nix
|
|
||||||
|
|
||||||
./net.nix
|
|
||||||
./fs.nix
|
|
||||||
] ++ lib.lists.optionals (!minimal) [ ../../config/services/octoprint.nix ];
|
|
||||||
services.xserver.xkb = {
|
|
||||||
layout = "de";
|
|
||||||
};
|
|
||||||
services.thermald.enable = lib.mkForce false;
|
|
||||||
nixpkgs.hostPlatform = "x86_64-linux";
|
|
||||||
}
|
|
|
@ -1,83 +0,0 @@
|
||||||
{ config, lib, ... }:
|
|
||||||
{
|
|
||||||
disko.devices = {
|
|
||||||
disk = {
|
|
||||||
internal-hdd = {
|
|
||||||
type = "disk";
|
|
||||||
device = "/dev/disk/by-id/${config.secrets.secrets.local.disko.internal-hdd}";
|
|
||||||
content = with lib.disko.gpt; {
|
|
||||||
type = "gpt";
|
|
||||||
partitions = {
|
|
||||||
boot = partEfi "1G";
|
|
||||||
swap = partSwap "16G";
|
|
||||||
rpool = lib.attrsets.recursiveUpdate (partLuksZfs "rpool" "rpool" "100%") {
|
|
||||||
content.extraFormatArgs = [ "--pbkdf pbkdf2" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
zpool = with lib.disko.zfs; {
|
|
||||||
rpool = mkZpool { datasets = impermanenceZfsDatasets; };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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/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;
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
networking = {
|
|
||||||
inherit (config.secrets.secrets.local.networking) hostId;
|
|
||||||
};
|
|
||||||
networking.nftables.firewall.zones.untrusted.interfaces = [ "lan01" ];
|
|
||||||
systemd.network.networks = {
|
|
||||||
"lan01" = {
|
|
||||||
address = [ "192.168.178.32/24" ];
|
|
||||||
gateway = [ "192.168.178.1" ];
|
|
||||||
matchConfig.MACAddress = config.secrets.secrets.local.networking.interfaces.lan01.mac;
|
|
||||||
networkConfig = {
|
|
||||||
IPv6PrivacyExtensions = "yes";
|
|
||||||
MulticastDNS = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMTiFpqpCiJaFOcSjFrJWk7YPBiZLwoJRbyy1JgZWFmN
|
|
Binary file not shown.
|
@ -6,6 +6,7 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
inherit (lib)
|
inherit (lib)
|
||||||
|
any
|
||||||
mkOption
|
mkOption
|
||||||
types
|
types
|
||||||
flip
|
flip
|
||||||
|
@ -64,42 +65,48 @@ in
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
imports = [
|
imports =
|
||||||
{
|
let
|
||||||
environment.systemPackages = [ pkgs.cifs-utils ];
|
existingCfg = flip any (attrNames config.home-manager.users) (
|
||||||
fileSystems = mkMerge (
|
user: (config.home-manager.users.${user}.home.smb != [ ])
|
||||||
flip concatMap (attrNames config.home-manager.users) (
|
|
||||||
user:
|
|
||||||
let
|
|
||||||
parentPath = "/home/${user}/smb";
|
|
||||||
cfg = config.home-manager.users.${user}.home.smb;
|
|
||||||
inherit (config.users.users.${user}) uid;
|
|
||||||
inherit (config.users.groups.${user}) gid;
|
|
||||||
in
|
|
||||||
flip map cfg (cfg: {
|
|
||||||
"${parentPath}/${cfg.localPath}" =
|
|
||||||
let
|
|
||||||
options =
|
|
||||||
baseOptions
|
|
||||||
++ [
|
|
||||||
"uid=${toString uid}"
|
|
||||||
"gid=${toString gid}"
|
|
||||||
"file_mode=0600"
|
|
||||||
"dir_mode=0700"
|
|
||||||
"credentials=${cfg.credentials}"
|
|
||||||
"x-systemd.automount"
|
|
||||||
"_netdev"
|
|
||||||
]
|
|
||||||
++ (optional (!cfg.automatic) "noauto");
|
|
||||||
in
|
|
||||||
{
|
|
||||||
inherit options;
|
|
||||||
device = "//${cfg.address}/${cfg.remotePath}";
|
|
||||||
fsType = "cifs";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
in
|
||||||
];
|
[
|
||||||
|
{
|
||||||
|
environment.systemPackages = lib.optional existingCfg pkgs.cifs-utils;
|
||||||
|
fileSystems = mkMerge (
|
||||||
|
flip concatMap (attrNames config.home-manager.users) (
|
||||||
|
user:
|
||||||
|
let
|
||||||
|
parentPath = "/home/${user}/smb";
|
||||||
|
cfg = config.home-manager.users.${user}.home.smb;
|
||||||
|
inherit (config.users.users.${user}) uid;
|
||||||
|
inherit (config.users.groups.${user}) gid;
|
||||||
|
in
|
||||||
|
flip map cfg (cfg: {
|
||||||
|
"${parentPath}/${cfg.localPath}" =
|
||||||
|
let
|
||||||
|
options =
|
||||||
|
baseOptions
|
||||||
|
++ [
|
||||||
|
"uid=${toString uid}"
|
||||||
|
"gid=${toString gid}"
|
||||||
|
"file_mode=0600"
|
||||||
|
"dir_mode=0700"
|
||||||
|
"credentials=${cfg.credentials}"
|
||||||
|
"x-systemd.automount"
|
||||||
|
"_netdev"
|
||||||
|
]
|
||||||
|
++ (optional (!cfg.automatic) "noauto");
|
||||||
|
in
|
||||||
|
{
|
||||||
|
inherit options;
|
||||||
|
device = "//${cfg.address}/${cfg.remotePath}";
|
||||||
|
fsType = "cifs";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -40,6 +40,10 @@
|
||||||
hostname = config.secrets.secrets.global.user.hetzner_ip;
|
hostname = config.secrets.secrets.global.user.hetzner_ip;
|
||||||
user = "root";
|
user = "root";
|
||||||
};
|
};
|
||||||
|
"mailnix" = {
|
||||||
|
hostname = config.secrets.secrets.global.user.mailnix_ip;
|
||||||
|
user = "root";
|
||||||
|
};
|
||||||
|
|
||||||
"desktopnix" = {
|
"desktopnix" = {
|
||||||
hostname = "desktopnix.local";
|
hostname = "desktopnix.local";
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
config,
|
config,
|
||||||
|
lib,
|
||||||
|
minimal,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
|
@ -10,12 +12,10 @@
|
||||||
# Patrick
|
# Patrick
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDZixkix0KfKuq7Q19whS5FQQg51/AJGB5BiNF/7h/LM"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDZixkix0KfKuq7Q19whS5FQQg51/AJGB5BiNF/7h/LM"
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxD4GOrwrBTG4/qQhm5hoSB2CP7W9g1LPWP11oLGOjQ"
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHxD4GOrwrBTG4/qQhm5hoSB2CP7W9g1LPWP11oLGOjQ"
|
||||||
# Simon old yubikey
|
|
||||||
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFmees72GMKG/rsQQRhs2I/lQnJa0uW5KmZlNBeriCh0"
|
|
||||||
];
|
];
|
||||||
hashedPassword = config.secrets.secrets.global.users.root.passwordHash;
|
hashedPassword = config.secrets.secrets.global.users.root.passwordHash;
|
||||||
};
|
};
|
||||||
imports = [
|
imports = lib.optionals (!minimal) [
|
||||||
|
|
||||||
../patrick/alias.nix
|
../patrick/alias.nix
|
||||||
../patrick/theme.nix
|
../patrick/theme.nix
|
||||||
|
|
Loading…
Reference in a new issue