major tidy

This commit is contained in:
chaos 2023-09-18 03:56:58 +01:00
parent 907785359f
commit 599122d3af
No known key found for this signature in database
177 changed files with 2412 additions and 3093 deletions

View file

@ -0,0 +1,29 @@
let
pubkeys = builtins.fromJSON (builtins.readFile ./chaosInternalWireGuardPubKeys.json);
in rec {
hosts = {
"hetzner-vm" = {
ip = "10.69.42.1";
public = pubkeys."hetzner-vm";
endpoint = "hetzner-vm.servers.genderfucked.monster:51820";
};
"vault" = {
ip = "10.69.42.2";
public = pubkeys."vault";
endpoint = "vault.servers.genderfucked.monster:51820";
};
#"iphone8" = {
# ip = "10.69.42.3";
# public = "PEBw7EI5uogB433cp8eSfJ5DCEiYj+YG2dZd0XkIV1c=";
#};
#"lappy-t495" = {
# ip = "10.69.42.4";
# public = "BR23xeK/nTgw8Ad001wz9wrfS6gTknTpCKZBLG9bnHM=";
#};
"raspberry" = {
ip = "10.69.42.5";
public = pubkeys."raspberry";
endpoint = "raspberry.servers.genderfucked.monster:51820";
};
};
}

View file

@ -0,0 +1,5 @@
{
"hetzner-vm": "xgOQQcZQXftPC25+A7Iyf/XK6/iSo3Osyx6kTrZKdzw=",
"vault": "u8hSeht8xR48O9AN+0cSsXPK0ZZFNcnPhOxdc+rsrlI=",
"raspberry": "Ghrs0ps2RCsg0My9seLq+8ZFZCM4NLZWE8RiY3g9/RU="
}

View file

@ -1,29 +0,0 @@
{}: rec {
all = "10.69.42.1/24";
hosts = {
hetzner-vm = {
ip = "10.69.42.1";
public = "liO33kMSEwuaaH4i6qDuorWssd9s/EfTBKBHQEbaDXE=";
endpoint = "hetzner-vm.servers.genderfucked.monster:51820";
};
vault = {
ip = "10.69.42.2";
public = "GJ/IQ5W2Ch2vSiqcciKkrBA+pVycY2cibhvF1SFzi0I=";
#endpoint = "vault.servers.genderfucked.monster:51820";
};
iphone8 = {
ip = "10.69.42.3";
public = "PEBw7EI5uogB433cp8eSfJ5DCEiYj+YG2dZd0XkIV1c=";
};
lappy-t495 = {
ip = "10.69.42.4";
public = "BR23xeK/nTgw8Ad001wz9wrfS6gTknTpCKZBLG9bnHM=";
};
raspberry = {
ip = "10.69.42.5";
public = "ld5XI4l/Gmr5JWg8r5midy7MTIgZkWVhMPsJqzIonng=";
endpoint = "raspberry.servers.genderfucked.monster:51820";
};
};
}

View file

@ -1 +0,0 @@
{}: (import ./normal_drive_data.nix {})

30
data/encryptedUSB.nix Normal file
View file

@ -0,0 +1,30 @@
rec {
# Mountpoints
mountpoint = "/usb";
# Partition Labels
encryptedPartLabel = "usb";
unencryptedLabel = "usb_unencrypted";
# Partition Filesystems
unencryptedFSType = "ext4";
# Mapper Information
mapperName = "usb_unencrypted";
preBootMapperName = "usb_unencrypted_preboot";
# FS Paths
encryptedPath = "/dev/disk/by-partlabel/${encryptedPartLabel}";
unencryptedPath = "/dev/disk/by-label/${unencryptedLabel}";
mapperPath = "/dev/mapper/${mapperName}";
preBootMapperPath = "/dev/mapper/${preBootMapperName}";
# Paths to some important files
encryptionKeysPath = "${mountpoint}/encryption-keys";
chaosAgePrivateKeyPath = "${mountpoint}/age-keys/chaoskey.priv";
chaosAgePublicKeyPath = "${mountpoint}/age-keys/chaoskey.pub";
sshPrivateKeyPath = "${mountpoint}/ssh-keys/chaos.priv";
sshPublicKeyPath = "${mountpoint}/ssh-keys/chaos.pub";
}

View file

@ -0,0 +1,23 @@
rec {
# Mountpoints
mountpoint = "/";
bootMountpoint = "/boot";
# Partition Labels
bootLabel = "nixboot";
unencryptedLabel = "nixos";
encryptedPartLabel = "nixos_encrypted";
# Partition Filesystems
unencryptedFSType = "ext4";
bootFSType = "vfat";
# Mapper Name
mapperName = "cryptroot";
# FS Paths
encryptedPath = "/dev/disk/by-partlabel/${encryptedPartLabel}";
decryptedPath = "/dev/mapper/${mapperName}";
bootPath = "/dev/disk/by-label/${bootLabel}";
}

View file

@ -1,23 +0,0 @@
{}: rec {
# Mountpoints
root_mountpoint = "/";
boot_mountpoint = "/boot";
# Partition Labels
boot_label = "nixboot";
unencrypted_root_label = "nixos";
encrypted_root_partlabel = "nixos_encrypted";
# Partition Filesystems
unencrypted_root_fs_type = "ext4";
boot_fs_type = "vfat";
# Mapper Name
root_mapper_name = "cryptroot";
# FS Paths
encrypted_root_path = "/dev/disk/by-partlabel/${encrypted_root_partlabel}";
decrypted_root_path = "/dev/mapper/${root_mapper_name}";
boot_path = "/dev/disk/by-label/${boot_label}";
}

View file

@ -0,0 +1,16 @@
rec {
encryptedLabel = "raspberry_encrypted";
unencryptedLabel = "raspberry_drive";
mapperName = "raspberry_external_drive";
mountpoint = "/external_drive";
encryptedPath = "/dev/disk/by-label/${encryptedLabel}";
unencryptedPath = "/dev/disk/by-label/${unencryptedLabel}";
mapperPath = "/dev/mapper/${mapperName}";
backupsPath = "${mountpoint}/backups";
storagePath = "${mountpoint}/storage";
extrasPath = "${mountpoint}/extras";
}

View file

@ -1,16 +0,0 @@
{}: rec {
encrypted_label = "raspberry_encrypted";
unencrypted_label = "raspberry_drive";
mapper_name = "raspberry_external_drive";
mountpoint = "/external_drive";
backups_path = "${mountpoint}/backups";
storage_path = "${mountpoint}/storage";
extras_path = "${mountpoint}/extras";
encrypted_path = "/dev/disk/by-label/${encrypted_label}";
unencrypted_path = "/dev/disk/by-label/${unencrypted_label}";
mapper_path = "/dev/mapper/${mapper_name}";
}

10
data/serverIPs.nix Normal file
View file

@ -0,0 +1,10 @@
rec {
"hetzner-vm" = {
ipv4 = "65.21.182.73";
ipv6 = "2a01:4f9:c010:8beb::1";
};
"vault" = {
ipv4 = "65.21.145.62";
ipv6 = "2a01:4f9:c010:6a89::1";
};
}

View file

@ -1,28 +0,0 @@
{}: rec {
# Mountpoints
mountpoint = "/usb";
# Partition Labels
encrypted_partlabel = "usb";
unencrypted_label = "usb_unencrypted";
# Partition Filesystems
unencrypted_fs_type = "ext4";
# Mapper Information
mapper_name = "usb_unencrypted";
# FS Paths
encrypted_path = "/dev/disk/by-partlabel/${encrypted_partlabel}";
unencrypted_path = "/dev/disk/by-label/${unencrypted_label}";
mapper_path = "/dev/mapper/${mapper_name}";
# Paths to some important files
encryption_keys_path = "${mountpoint}/encryption-keys";
chaos_age_privkey_path = "${mountpoint}/age-keys/chaoskey.priv";
chaos_age_pubkey_path = "${mountpoint}/age-keys/chaoskey.pub";
ssh_priv_path = "${mountpoint}/ssh-keys/chaos.priv";
ssh_pub_path = "${mountpoint}/ssh-keys/chaos.pub";
}

View file

@ -1,52 +0,0 @@
{
nixosConfigurations,
deploy-rs,
...
}: let
activateNixOS_x64_64-linux = deploy-rs.lib.x86_64-linux.activate.nixos;
in {
tablet = {
hostname = "tablet.internal.genderfucked.monster";
profiles.system = {
user = "root";
sshUser = "root";
path = activateNixOS_x64_64-linux nixosConfigurations.tablet;
};
};
hetzner-vm = {
hostname = "hetzner-vm.servers.genderfucked.monster";
username = "root";
profiles.system = {
user = "root";
sshUser = "root";
path = activateNixOS_x64_64-linux nixosConfigurations.hetzner-vm;
};
};
storage = {
hostname = "storage.servers.genderfucked.monster";
username = "root";
profiles.system = {
user = "root";
sshUser = "root";
path = activateNixOS_x64_64-linux nixosConfigurations.storage;
};
};
vault = {
hostname = "vault.servers.genderfucked.monster";
username = "root";
profiles.system = {
user = "root";
sshUser = "root";
path = activateNixOS_x64_64-linux nixosConfigurations.vault;
};
};
buildbox = {
hostname = "buildbox.servers.genderfucked.monster";
username = "root";
profiles.system = {
user = "root";
sshUser = "root";
path = activateNixOS_x64_64-linux nixosConfigurations.buildbox;
};
};
}

View file

@ -1,95 +0,0 @@
{
lib,
pkgs,
...
}: let
wireguard_data = import ../data/chaos_wireguard_internal.nix {};
wireguard_hosts = wireguard_data.hosts;
inherit (pkgs) writeShellScriptBin;
inherit (lib.lists) forEach filter;
inherit (builtins) hasAttr attrNames;
kvPathForHost = host: "/private-public-keys/wireguard/chaos-internal/${host}";
in rec {
initAllScript = writeShellScriptBin "wg-keys-init-all" (let
vault = "${pkgs.vault-bin}/bin/vault";
jq = "${pkgs.jq}/bin/jq";
in ''
${lib.concatStringsSep "\n" (lib.forEach (attrNames wireguard_hosts) (hostName: ''
if [ -z "$PRESHARED_ONLY" ]; then
echo "{}" | vault kv put "${kvPathForHost hostName}" - 2>/dev/null
fi
''))}
${lib.concatStringsSep "\n" (lib.forEach (attrNames wireguard_hosts) (hostName: ''
echo "Deploying keys for ${hostName}"
"${genInitScript hostName}/bin/wg-keys-init-${hostName}"
''))}
${lib.concatStringsSep "\n" (lib.forEach (attrNames wireguard_hosts) (hostName: ''
echo
PUBLIC=$(${vault} kv get -format=json "${kvPathForHost hostName}" | ${jq} .data.data.public)
echo "Public Key for ${hostName}: $PUBLIC"
''))}
'');
genInitScript = systemHostName: (writeShellScriptBin "wg-keys-init-${systemHostName}" (let
vault = "${pkgs.vault-bin}/bin/vault";
jq = "${pkgs.jq}/bin/jq";
wg = "${pkgs.wireguard-tools}/bin/wg";
sponge = "${pkgs.moreutils}/bin/sponge";
hostsWithEndpoints = filter (hostName: (hostName != systemHostName && hasAttr "endpoint" wireguard_hosts.${hostName})) (attrNames wireguard_hosts);
in ''
PRIVATE=$(${wg} genkey)
PUBLIC=$(echo "$PRIVATE" | ${wg} pubkey)
TMP_DIR=$(mktemp -d)
pushd "$TMP_DIR"
echo "{}" > currentHost.json
if [ -z "$PRESHARED_ONLY" ]; then
${jq} ".public = \"$PUBLIC\"" currentHost.json | ${sponge} currentHost.json
${jq} ".private = \"$PRIVATE\"" currentHost.json | ${sponge} currentHost.json
fi
${jq} '.preshared_keys = {}' currentHost.json | ${sponge} currentHost.json
${lib.concatStringsSep "\n" (lib.forEach hostsWithEndpoints (hostName: ''
echo "Generating preshared key for ${hostName}"
PSK=$(${wg} genpsk)
${jq} ".preshared_keys.\"${hostName}\" = \"$PSK\"" currentHost.json | ${sponge} currentHost.json
''))}
${lib.concatStringsSep "\n" (lib.forEach hostsWithEndpoints (hostName: ''
echo "Deploying preshared key for ${hostName}"
PSK=$(jq -r '.preshared_keys."${hostName}"' currentHost.json)
${vault} kv get -format=json "${kvPathForHost hostName}" 2>/dev/null | jq -r .data.data > otherHost.json
${jq} ".preshared_keys.\"${systemHostName}\" = \"$PSK\"" otherHost.json | ${sponge} otherHost.json
cat otherHost.json | vault kv put "${kvPathForHost hostName}" - 2>/dev/null
rm otherHost.json
''))}
if [ -z "$PRESHARED_ONLY" ]; then
cat currentHost.json | ${vault} kv put "${kvPathForHost systemHostName}" - 2>/dev/null
cat currentHost.json | jq
fi
rm currentHost.json
popd
rm -rf "$TMP_DIR"
echo "Public Key for ${systemHostName}: $PUBLIC"
''));
}

View file

@ -1,35 +0,0 @@
{
stdenv,
bash,
parted,
cryptsetup,
e2fsprogs,
dosfstools,
}: let
ssd_data = import ../data/dual_drive_data.nix {};
in
stdenv.mkDerivation {
name = "mk-dual-enc-ssd";
src = ./mk-dual-enc-ssd.sh;
unpackPhase = ''
for srcFile in $src; do
cp $srcFile $(stripHash $srcFile)
done
'';
inherit bash parted cryptsetup e2fsprogs dosfstools;
patchPhase = ''
substituteAllInPlace mk-dual-enc-ssd.sh
substituteInPlace mk-dual-enc-ssd.sh \
--replace "@SSD_ENCRYPTED_PARTLABEL@" "${ssd_data.encrypted_root_partlabel}" \
--replace "@SSD_UNENCRYPTED_LABEL@" "${ssd_data.unencrypted_root_label}" \
--replace "@SSD_BOOT_LABEL@" "${ssd_data.boot_label}"
'';
installPhase = ''
mkdir -p $out/bin
cp mk-dual-enc-ssd.sh $out/bin/mk-dual-enc-ssd
chmod +x $out/bin/mk-dual-enc-ssd
'';
}

View file

@ -1,63 +0,0 @@
#! @bash@/bin/sh
set -e
# e.g /dev/nvme0n1
SSD_PATH=$1
KEY_FILE=$2
NIXOS_SIZE=$3
if echo "$SSD_PATH" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
PARTITION_SEPARATOR=""
fi
if [ -z "$SSD_PATH" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
if [ -z "$KEY_FILE" ]; then
echo "Please specify a key file to use"
exit 1
fi
if [ -z "$NIXOS_SIZE" ]; then
echo "Please specify how big to make the NixOS partition"
exit 1
fi
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
# encrypted partition label
SSD_ENCRYPTED_PARTLABEL=@SSD_ENCRYPTED_PARTLABEL@
# unencrypted filesystem label
SSD_UNENCRYPTED_LABEL=@SSD_UNENCRYPTED_LABEL@
# ssd boot label
SSD_BOOT_LABEL=@SSD_BOOT_LABEL@
echo "Creating Partitions..."
@parted@/bin/parted ${SSD_PATH} -- mklabel gpt
@parted@/bin/parted ${SSD_PATH} -- mkpart ESP fat32 1MiB 1024MiB
@parted@/bin/parted ${SSD_PATH} -- mkpart primary 1072MiB "${NIXOS_SIZE}"
@parted@/bin/parted ${SSD_PATH} -- set 1 esp on
@parted@/bin/parted ${SSD_PATH} -- name 1 "${SSD_BOOT_LABEL}"
@parted@/bin/parted ${SSD_PATH} -- name 2 "${SSD_ENCRYPTED_PARTLABEL}"
echo "Formatting boot partition"
@dosfstools@/bin/mkfs.fat -n "${SSD_BOOT_LABEL}" "${SSD_PATH}${PARTITION_SEPARATOR}1"
echo "Creating Encrypted Partition"
@cryptsetup@/bin/cryptsetup luksFormat "${SSD_PATH}${PARTITION_SEPARATOR}2" --key-file "${KEY_FILE}"
echo "Opening Encrypted Partition"
@cryptsetup@/bin/cryptsetup open "${SSD_PATH}${PARTITION_SEPARATOR}2" "mk_dual_enc_ssd" --key-file "${KEY_FILE}"
echo "Formatting Encrypted Root Filesystem"
@e2fsprogs@/bin/mkfs.ext4 -L "${SSD_UNENCRYPTED_LABEL}" /dev/mapper/mk_dual_enc_ssd
echo "mount /dev/mapper/mk_dual_enc_ssd to install"

View file

@ -1,33 +1,57 @@
{ {
stdenv,
bash,
parted, parted,
cryptsetup, cryptsetup,
e2fsprogs, e2fsprogs,
writeShellApplication,
}: let }: let
usb_data = import ../data/usb_data.nix {}; encryptedUSBData = import ../data/encryptedUSB.nix;
in in (writeShellApplication {
stdenv.mkDerivation { name = "mk-enc-usb";
name = "mk-enc-usb"; runtimeInputs = [
src = ./mk-enc-usb.sh; parted
unpackPhase = '' cryptsetup
for srcFile in $src; do e2fsprogs
cp $srcFile $(stripHash $srcFile) ];
done text = ''
''; if [ -z "''${1-}" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
inherit bash parted cryptsetup e2fsprogs; # e.g /dev/sdb
USB_DEVICE=$1
patchPhase = '' if echo "$USB_DEVICE" | grep -q "[0-9]$"; then
substituteAllInPlace mk-enc-usb.sh PARTITION_SEPARATOR="p"
substituteInPlace mk-enc-usb.sh \ else
--replace "@USB_ENCRYPTED_PARTLABEL@" "${usb_data.encrypted_partlabel}" \ PARTITION_SEPARATOR=""
--replace "@USB_UNENCRYPTED_LABEL@" "${usb_data.unencrypted_label}" fi
'';
installPhase = '' if [ "$EUID" -ne 0 ]; then
mkdir -p $out/bin echo "Please run as root"
cp mk-enc-usb.sh $out/bin/mk-enc-usb exit
chmod +x $out/bin/mk-enc-usb fi
'';
} echo "Creating Encrypted USB."
echo "Creating Partitions..."
parted "$USB_DEVICE" -- mklabel gpt
parted "$USB_DEVICE" -- mkpart primary 0% 100%
echo "Creating Encrypted Partition"
cryptsetup luksFormat "''${USB_DEVICE}''${PARTITION_SEPARATOR}1"
echo "Opening Encrypted Partition"
cryptsetup open "''${USB_DEVICE}''${PARTITION_SEPARATOR}1" "mk_enc_usb"
echo "Making Encrypted Filesystem"
mkfs.ext4 -L "${encryptedUSBData.unencryptedLabel}" /dev/mapper/mk_enc_usb
echo "Closing Encrypted Partition"
cryptsetup close "mk_enc_usb"
# Do this now so that i can run the damn script with usb-automount and stop it trying to mount
echo "Naming Partitions"
parted "$USB_DEVICE" -- name 1 ${encryptedUSBData.encryptedPartLabel}
'';
})

View file

@ -1,49 +0,0 @@
#! @bash@/bin/sh
set -e
# e.g /dev/sdb
USB_DEVICE=$1
if echo "$USB_DEVICE" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
PARTITION_SEPARATOR=""
fi
if [ -z "$USB_DEVICE" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
# encrypted partition label
USB_ENCRYPTED_PARTLABEL=@USB_ENCRYPTED_PARTLABEL@
# unencrypted filesystem label
USB_UNENCRYPTED_LABEL=@USB_UNENCRYPTED_LABEL@
echo "Creating Encrypted USB."
echo "Creating Partitions..."
@parted@/bin/parted ${USB_DEVICE} -- mklabel gpt
@parted@/bin/parted ${USB_DEVICE} -- mkpart primary 0% 100%
echo "Creating Encrypted Partition"
@cryptsetup@/bin/cryptsetup luksFormat "${USB_DEVICE}${PARTITION_SEPARATOR}1"
echo "Opening Encrypted Partition"
@cryptsetup@/bin/cryptsetup open "${USB_DEVICE}${PARTITION_SEPARATOR}1" "mk_enc_usb"
echo "Making Encrypted Filesystem"
@e2fsprogs@/bin/mkfs.ext4 -L "${USB_UNENCRYPTED_LABEL}" /dev/mapper/mk_enc_usb
echo "Closing Encrypted Partition"
@cryptsetup@/bin/cryptsetup close "mk_enc_usb"
# Do this now so that i can run the damn script with usb-automount and stop it trying to mount
echo "Naming Partitions"
@parted@/bin/parted ${USB_DEVICE} -- name 1 "${USB_ENCRYPTED_PARTLABEL}"

View file

@ -1,35 +1,64 @@
{ {
stdenv,
bash,
parted, parted,
cryptsetup, cryptsetup,
e2fsprogs, e2fsprogs,
dosfstools, dosfstools,
writeShellApplication,
}: let }: let
ssd_data = import ../data/normal_drive_data.nix {}; ssdData = import ../data/normalEncryptedDrive.nix;
in in (writeShellApplication {
stdenv.mkDerivation { name = "mk-normal-enc-ssd";
name = "mk-normal-enc-ssd"; runtimeInputs = [
src = ./mk-normal-enc-ssd.sh; parted
unpackPhase = '' cryptsetup
for srcFile in $src; do e2fsprogs
cp $srcFile $(stripHash $srcFile) dosfstools
done ];
''; text = ''
if [ -z "''${1-}" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
inherit bash parted cryptsetup e2fsprogs dosfstools; if [ -z "''${2-}" ]; then
echo "Please specify a path to key file as second argument"
exit 1
fi
patchPhase = '' SSD_PATH=$1
substituteAllInPlace mk-normal-enc-ssd.sh KEY_FILE=$2
substituteInPlace mk-normal-enc-ssd.sh \
--replace "@SSD_ENCRYPTED_PARTLABEL@" "${ssd_data.encrypted_root_partlabel}" \
--replace "@SSD_UNENCRYPTED_LABEL@" "${ssd_data.unencrypted_root_label}" \
--replace "@SSD_BOOT_LABEL@" "${ssd_data.boot_label}"
'';
installPhase = '' if echo "$SSD_PATH" | grep -q "[0-9]$"; then
mkdir -p $out/bin PARTITION_SEPARATOR="p"
cp mk-normal-enc-ssd.sh $out/bin/mk-normal-enc-ssd else
chmod +x $out/bin/mk-normal-enc-ssd PARTITION_SEPARATOR=""
''; fi
}
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
echo "Creating Partitions..."
parted "$SSD_PATH" -- mklabel gpt
parted "$SSD_PATH" -- mkpart ESP fat32 1MiB 512MiB
parted "$SSD_PATH" -- mkpart primary 620MiB -1MiB
parted "$SSD_PATH" -- set 1 esp on
parted "$SSD_PATH" -- name 1 "${ssdData.bootLabel}"
parted "$SSD_PATH" -- name 2 "${ssdData.encryptedPartLabel}"
echo "Formatting boot partition"
mkfs.fat -n "${ssdData.bootLabel}" "''${SSD_PATH}''${PARTITION_SEPARATOR}1"
echo "Creating Encrypted Partition"
cryptsetup luksFormat "''${SSD_PATH}''${PARTITION_SEPARATOR}2" --key-file "$KEY_FILE"
echo "Opening Encrypted Partition"
cryptsetup open "''${SSD_PATH}''${PARTITION_SEPARATOR}2" "mk_normal_enc_ssd" --key-file "$KEY_FILE"
echo "Formatting Encrypted Root Filesystem"
mkfs.ext4 -L "${ssdData.unencryptedLabel}" /dev/mapper/mk_normal_enc_ssd
echo "mount /dev/mapper/mk_normal_enc_ssd to install"
'';
})

View file

@ -1,57 +0,0 @@
#! @bash@/bin/sh
set -e
# e.g /dev/nvme0n1
SSD_PATH=$1
KEY_FILE=$2
if echo "$SSD_PATH" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
PARTITION_SEPARATOR=""
fi
if [ -z "$SSD_PATH" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
if [ -z "$KEY_FILE" ]; then
echo "Please specify a key file to use"
exit 1
fi
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
# encrypted partition label
SSD_ENCRYPTED_PARTLABEL=@SSD_ENCRYPTED_PARTLABEL@
# unencrypted filesystem label
SSD_UNENCRYPTED_LABEL=@SSD_UNENCRYPTED_LABEL@
# ssd boot label
SSD_BOOT_LABEL=@SSD_BOOT_LABEL@
echo "Creating Partitions..."
@parted@/bin/parted ${SSD_PATH} -- mklabel gpt
@parted@/bin/parted ${SSD_PATH} -- mkpart ESP fat32 1MiB 512MiB
@parted@/bin/parted ${SSD_PATH} -- mkpart primary 620MiB -1MiB
@parted@/bin/parted ${SSD_PATH} -- set 1 esp on
@parted@/bin/parted ${SSD_PATH} -- name 1 "${SSD_BOOT_LABEL}"
@parted@/bin/parted ${SSD_PATH} -- name 2 "${SSD_ENCRYPTED_PARTLABEL}"
echo "Formatting boot partition"
@dosfstools@/bin/mkfs.fat -n "${SSD_BOOT_LABEL}" "${SSD_PATH}${PARTITION_SEPARATOR}1"
echo "Creating Encrypted Partition"
@cryptsetup@/bin/cryptsetup luksFormat "${SSD_PATH}${PARTITION_SEPARATOR}2" --key-file "${KEY_FILE}"
echo "Opening Encrypted Partition"
@cryptsetup@/bin/cryptsetup open "${SSD_PATH}${PARTITION_SEPARATOR}2" "mk_normal_enc_ssd" --key-file "${KEY_FILE}"
echo "Formatting Encrypted Root Filesystem"
@e2fsprogs@/bin/mkfs.ext4 -L "${SSD_UNENCRYPTED_LABEL}" /dev/mapper/mk_normal_enc_ssd
echo "mount /dev/mapper/mk_normal_enc_ssd to install"

View file

@ -1,35 +1,67 @@
{ {
stdenv,
bash,
util-linux, util-linux,
cryptsetup, cryptsetup,
btrfs-progs, btrfs-progs,
writeShellApplication,
}: let }: let
external_drive_data = import ../data/raspberry_ext_drive.nix {}; externalDriveData = import ../data/raspberryExternalDrive.nix;
in in (writeShellApplication {
stdenv.mkDerivation { name = "mk-raspberry-ext-drive";
name = "mk-raspberry-ext-drive"; runtimeInputs = [
src = ./mk-raspberry-ext-drive.sh; util-linux
unpackPhase = '' cryptsetup
for srcFile in $src; do btrfs-progs
cp $srcFile $(stripHash $srcFile) ];
done text = ''
''; if [ -z "''${1-}" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
patchPhase = '' DRIVE_PATH=$1
substituteAllInPlace mk-raspberry-ext-drive.sh
substituteInPlace mk-raspberry-ext-drive.sh \
--replace "@util-linux@" "${util-linux}" \
--replace "@btrfs-progs@" "${btrfs-progs}" \
--replace "@cryptsetup@" "${cryptsetup}" \
--replace "@bash@" "${bash}" \
--replace "@ENCRYPTED_LABEL@" "${external_drive_data.encrypted_label}" \
--replace "@UNENCRYPTED_LABEL@" "${external_drive_data.unencrypted_label}"
'';
installPhase = '' if [ -z "''${2-}" ]; then
mkdir -p $out/bin echo "Please specify a key file to use"
cp mk-raspberry-ext-drive.sh $out/bin/mk-raspberry-ext-drive exit 1
chmod +x $out/bin/mk-raspberry-ext-drive fi
'';
} KEY_FILE=$2
if [ -z "''${3-}" ]; then
echo "Please specify a temp mountpoint to use"
exit 1
fi
TEMP_MOUNTPOINT=$3
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
echo "Wiping Partitions..."
wipefs --all "$DRIVE_PATH"
echo "Creating Encrypted Partition"
cryptsetup luksFormat "$DRIVE_PATH" --key-file "$KEY_FILE" --label "${externalDriveData.encryptedLabel}"
echo "Opening Encrypted Partition"
cryptsetup open "$DRIVE_PATH" "mk-raspberry-ext-drive" --key-file "$KEY_FILE"
echo "Formatting Encrypted Filesystem"
mkfs.btrfs -L "${externalDriveData.unencryptedLabel}" /dev/mapper/mk-raspberry-ext-drive
echo "Mounting Partition"
mount -t btrfs /dev/mapper/mk-raspberry-ext-drive "$TEMP_MOUNTPOINT"
echo "Creating Folders"
mkdir "$TEMP_MOUNTPOINT/backups"
mkdir "$TEMP_MOUNTPOINT/storage"
mkdir "$TEMP_MOUNTPOINT/extras"
echo "Unmounting"
umount "$TEMP_MOUNTPOINT"
echo "Closing mapper device"
cryptsetup close "mk-raspberry-ext-drive"
'';
})

View file

@ -1,65 +0,0 @@
#! @bash@/bin/sh
set -e
# e.g /dev/nvme0n1
DRIVE_PATH=$1
KEY_FILE=$2
TEMP_MOUNTPOINT=$3
if echo "$DRIVE_PATH" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
PARTITION_SEPARATOR=""
fi
if [ -z "$DRIVE_PATH" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
if [ -z "$KEY_FILE" ]; then
echo "Please specify a key file to use"
exit 1
fi
if [ -z "$TEMP_MOUNTPOINT" ]; then
echo "Please specify a temp mountpoint to use"
exit 1
fi
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
fi
# encrypted partition label
ENCRYPTED_LABEL=@ENCRYPTED_LABEL@
# unencrypted filesystem label
UNENCRYPTED_LABEL=@UNENCRYPTED_LABEL@
echo "Wiping Partitions..."
@util-linux@/bin/wipefs --all ${DRIVE_PATH}
echo "Creating Encrypted Partition"
@cryptsetup@/bin/cryptsetup luksFormat "${DRIVE_PATH}" --key-file "${KEY_FILE}" --label "${ENCRYPTED_LABEL}"
echo "Opening Encrypted Partition"
@cryptsetup@/bin/cryptsetup open "${DRIVE_PATH}" "mk-raspberry-ext-drive" --key-file "${KEY_FILE}"
echo "Formatting Encrypted Filesystem"
@btrfs-progs@/bin/mkfs.btrfs -L "${UNENCRYPTED_LABEL}" /dev/mapper/mk-raspberry-ext-drive
echo "Mounting Partition"
mount -t btrfs /dev/mapper/mk-raspberry-ext-drive "$TEMP_MOUNTPOINT"
echo "Creating Folders"
mkdir "$TEMP_MOUNTPOINT/backups"
mkdir "$TEMP_MOUNTPOINT/storage"
mkdir "$TEMP_MOUNTPOINT/extras"
echo "Unmounting"
umount "$TEMP_MOUNTPOINT"
echo "Closing mapper device"
@cryptsetup@/bin/cryptsetup close "mk-raspberry-ext-drive"

View file

@ -1,96 +0,0 @@
{
lib,
pkgs,
nixpkgs,
config,
...
}: let
wifiInterface = "shenanigans0";
wifiMac = "00:0F:55:A8:2B:8E";
usbethInterface = "shenanigans1";
usbethMac = "d0:37:45:88:9a:49";
ssid = "Shenanigans";
password = "password123";
in {
boot.extraModulePackages = with config.boot.kernelPackages; [rtl8812au];
nixpkgs.config.allowBroken = true;
services.udev.extraRules = ''
KERNEL=="wlan*", ATTR{address}=="${
lib.toLower wifiMac
}", NAME="${wifiInterface}"
KERNEL=="eth*", ACTION=="add", ATTR{address}=="${
lib.toLower usbethMac
}", NAME="${usbethInterface}"
'';
networking.interfaces."${wifiInterface}".ipv4.addresses = [
{
address = "192.168.2.1";
prefixLength = 24;
}
];
networking.interfaces."${usbethInterface}".ipv4.addresses = [
{
address = "192.168.2.1";
prefixLength = 24;
}
];
networking.networkmanager.unmanaged = [
# Wifi
"interface-name:${wifiInterface}"
"mac:${wifiMac}"
"interface-name:${usbethInterface}"
"mac:${usbethMac}"
];
systemd.services.wifi-relay = let
inherit (pkgs) iptables;
in {
description = "iptables rules for wifi-relay";
after = ["dhcpd4.service"];
wantedBy = ["multi-user.target"];
script = ''
${iptables}/bin/iptables -w -t nat -I POSTROUTING -s 192.168.2.0/24 ! -o ${wifiInterface} -j MASQUERADE
${iptables}/bin/iptables -w -I FORWARD -i ${wifiInterface} -s 192.168.2.0/24 -j ACCEPT
${iptables}/bin/iptables -w -t nat -I POSTROUTING -s 192.168.2.0/24 ! -o ${usbethInterface} -j MASQUERADE
${iptables}/bin/iptables -w -I FORWARD -i ${usbethInterface} -s 192.168.2.0/24 -j ACCEPT
#${iptables}/bin/iptables -t nat -A PREROUTING -i ${wifiInterface} -p tcp --dport 80 -j REDIRECT --to-port 8080
#${iptables}/bin/iptables -t nat -A PREROUTING -i ${wifiInterface} -p tcp --dport 443 -j REDIRECT --to-port 8080
'';
};
networking.firewall = {
trustedInterfaces = [wifiInterface usbethInterface];
checkReversePath = lib.mkForce false;
allowedTCPPorts = [53 80 443];
};
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
networking.firewall.allowedUDPPorts = [53 67];
services.hostapd = {
enable = true;
interface = wifiInterface;
inherit ssid;
wpaPassphrase = password;
};
services.dhcpd4 = {
enable = true;
interfaces = ["${usbethInterface}"];
extraConfig = ''
subnet 192.168.2.0 netmask 255.255.255.0 {
range 192.168.2.100 192.168.2.200;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.2.255;
option routers 192.168.2.1;
option domain-name-servers 192.168.2.1;
}
'';
};
}

View file

@ -1,31 +1,5 @@
{ {
"nodes": { "nodes": {
"deploy-rs": {
"inputs": {
"flake-compat": [
"flake-compat"
],
"nixpkgs": [
"nixpkgs-unstable"
],
"utils": [
"flake-utils"
]
},
"locked": {
"lastModified": 1694513707,
"narHash": "sha256-wE5kHco3+FQjc+MwTPwLVqYz4hM7uno2CgXDXUFMCpc=",
"owner": "serokell",
"repo": "deploy-rs",
"rev": "31c32fb2959103a796e07bbe47e0a5e287c343a8",
"type": "github"
},
"original": {
"owner": "serokell",
"repo": "deploy-rs",
"type": "github"
}
},
"flake-compat": { "flake-compat": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -217,7 +191,6 @@
}, },
"root": { "root": {
"inputs": { "inputs": {
"deploy-rs": "deploy-rs",
"flake-compat": "flake-compat", "flake-compat": "flake-compat",
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"gitlab_archiver": "gitlab_archiver", "gitlab_archiver": "gitlab_archiver",

View file

@ -16,19 +16,11 @@
home-manager-unstable.url = "github:nix-community/home-manager"; home-manager-unstable.url = "github:nix-community/home-manager";
home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable"; home-manager-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
#nix-darwin-unstable.url = "github:lnl7/nix-darwin/master";
#nix-darwin-unstable.inputs.nixpkgs.follows = "nixpkgs-unstable";
tree-input.url = "github:kittywitch/tree"; tree-input.url = "github:kittywitch/tree";
tree-input.inputs.nixpkgs.follows = "nixpkgs-unstable"; tree-input.inputs.nixpkgs.follows = "nixpkgs-unstable";
nur.url = "github:nix-community/NUR"; nur.url = "github:nix-community/NUR";
deploy-rs.url = "github:serokell/deploy-rs";
deploy-rs.inputs.nixpkgs.follows = "nixpkgs-unstable";
deploy-rs.inputs.utils.follows = "flake-utils";
deploy-rs.inputs.flake-compat.follows = "flake-compat";
vaultui.url = "gitlab:ChaotiCryptidz/VaultUI"; vaultui.url = "gitlab:ChaotiCryptidz/VaultUI";
vaultui.inputs.nixpkgs.follows = "nixpkgs-unstable"; vaultui.inputs.nixpkgs.follows = "nixpkgs-unstable";
vaultui.inputs.utils.follows = "flake-utils"; vaultui.inputs.utils.follows = "flake-utils";

View file

@ -1,20 +1,27 @@
{ {
inputs,
nixosConfig, nixosConfig,
pkgs, pkgs,
... ...
}: let }: let
nur = import inputs.nur {
nurpkgs = pkgs;
inherit pkgs;
};
isGnome = nixosConfig.services.xserver.desktopManager.gnome.enable; isGnome = nixosConfig.services.xserver.desktopManager.gnome.enable;
extensions = with nixosConfig.nur; [
repos.rycee.firefox-addons.ublock-origin extensions = with nur.repos.rycee.firefox-addons; [
repos.rycee.firefox-addons.stylus ublock-origin
repos.rycee.firefox-addons.tampermonkey stylus
repos.rycee.firefox-addons.search-engines-helper tampermonkey
#repos.rycee.firefox-addons.search-by-image search-engines-helper
repos.rycee.firefox-addons.offline-qr-code-generator search-by-image
repos.rycee.firefox-addons.i-dont-care-about-cookies offline-qr-code-generator
repos.rycee.firefox-addons.don-t-fuck-with-paste i-dont-care-about-cookies
repos.rycee.firefox-addons.amp2html don-t-fuck-with-paste
repos.rycee.firefox-addons.a11ycss amp2html
a11ycss
]; ];
in { in {
programs.firefox = { programs.firefox = {

View file

@ -1,19 +1,27 @@
{lib, ...}: let {
container-addresses = import ../../hosts/hetzner-vm/data/container-addresses.nix {}; self,
lib,
...
}: let
inherit (lib.modules) mkMerge;
inherit (lib.lists) forEach;
inherit (builtins) attrNames;
containerAddresses = import "${self}/hosts/hetzner-vm/data/containerAddresses.nix";
in { in {
programs.ssh.enable = true; programs.ssh.enable = true;
programs.ssh.matchBlocks = programs.ssh.matchBlocks =
lib.mkMerge mkMerge
((lib.forEach ["hetzner-vm" "vault" "raspberry" "vault-decrypt"] (hostname: { ((forEach ["hetzner-vm" "vault" "raspberry" "vault-decrypt"] (hostname: {
"${hostname}" = { "${hostname}" = {
user = "root"; user = "root";
hostname = "${hostname}.servers.genderfucked.monster"; hostname = "${hostname}.servers.genderfucked.monster";
}; };
})) }))
++ (lib.forEach (lib.attrNames container-addresses.containers) (name: { ++ (forEach (attrNames containerAddresses.containers) (name: {
"container-${name}" = { "hetzner-vm-container-${name}" = {
user = "root"; user = "root";
hostname = "${container-addresses.containers.${name}}"; hostname = "${containerAddresses.containers.${name}}";
proxyJump = "hetzner-vm"; proxyJump = "hetzner-vm";
}; };
})) }))

View file

@ -1,5 +1,9 @@
{pkgs, ...}: let {
usb_data = import ../../data/usb_data.nix {}; self,
pkgs,
...
}: let
encryptedUSBData = import "${self}/data/encryptedUSB.nix";
in { in {
home.packages = with pkgs; [eza bat ripgrep vault-bin libarchive age]; home.packages = with pkgs; [eza bat ripgrep vault-bin libarchive age];
programs.zsh = { programs.zsh = {
@ -27,9 +31,9 @@ in {
log = "journalctl"; log = "journalctl";
dmesg = "dmesg -HP"; dmesg = "dmesg -HP";
hg = "history 0 | rg"; hg = "history 0 | rg";
chaos_age = "age -i ${usb_data.chaos_age_privkey_path}"; chaos_age = "age -i ${encryptedUSBData.chaosAgePrivateKeyPath}";
chaos_age_encrypt = "age -a -e -i ${usb_data.chaos_age_privkey_path}"; chaos_age_encrypt = "age -a -e -i ${encryptedUSBData.chaosAgePrivateKeyPath}";
chaos_pub = "cat ${usb_data.chaos_age_pubkey_path}"; chaos_pub = "cat ${encryptedUSBData.chaosAgePublicKeyPath}";
}; };
envExtra = '' envExtra = ''
export VAULT_ADDR="https://vault.owo.monster" export VAULT_ADDR="https://vault.owo.monster"

View file

@ -1 +0,0 @@
{pkgs, ...}: {home.packages = with pkgs.deploy-rs; [deploy-rs];}

View file

@ -18,7 +18,6 @@
mk-enc-usb mk-enc-usb
mk-normal-enc-ssd mk-normal-enc-ssd
mk-dual-enc-ssd
mk-raspberry-ext-drive mk-raspberry-ext-drive
]; ];
} }

View file

@ -1,5 +1,5 @@
{tree, ...}: { {tree, ...}: {
# basically everything apart from home.all.dev.debugging and home.all.dev.deploy-rs and extra archives # basically everything apart from home.all.dev.debugging and extra archives
imports = with tree; [ imports = with tree; [
home.dev.all.archives.common home.dev.all.archives.common
home.dev.all.compression home.dev.all.compression

View file

@ -1,8 +1,4 @@
{ {pkgs, ...}: {
nixosConfig,
pkgs,
...
}: {
gtk = { gtk = {
enable = true; enable = true;
iconTheme = { iconTheme = {
@ -15,10 +11,7 @@
}; };
font = { font = {
name = "Comic Code"; name = "Comic Code";
size = size = 16;
if nixosConfig.networking.hostName == "tablet"
then 10
else 16;
package = pkgs.comic-code; package = pkgs.comic-code;
}; };
}; };

View file

@ -5,23 +5,19 @@
inputs, inputs,
... ...
}: let }: let
hm-lib = inputs.home-manager.lib.hm; homeManagerLib = inputs.home-manager.lib.hm;
font-sizes-all = { fontSizesAll = {
default = { default = {
small = "14"; small = "14";
medium = "16"; medium = "16";
}; };
tablet = {
small = "8";
medium = "10";
};
}; };
font-sizes = fontSizes =
if nixosConfig.networking.hostName == "tablet" if fontSizesAll ? nixosConfig.networking.hostName
then font-sizes-all.tablet then fontSizesAll.${nixosConfig.networking.hostName}
else font-sizes-all.default; else fontSizesAll.default;
in { in {
imports = with tree; [home.apps.kitty home.apps.rofi]; imports = with tree; [home.apps.kitty home.apps.rofi];
@ -54,13 +50,13 @@ in {
# TODO: Maybe do this with fontconfig too? # TODO: Maybe do this with fontconfig too?
font-antialiasing = "rgba"; font-antialiasing = "rgba";
font-hinting = "full"; font-hinting = "full";
font-name = "Comic Code ${font-sizes.medium}"; font-name = "Comic Code ${fontSizes.medium}";
monospace-font-name = "Comic Code ${font-sizes.small}"; monospace-font-name = "Comic Code ${fontSizes.small}";
color-scheme = "prefer-dark"; color-scheme = "prefer-dark";
}; };
"org/gnome/desktop/input-sources" = { "org/gnome/desktop/input-sources" = {
# TODO: see if this changes when using gnome wayland? # TODO: see if this changes when using gnome wayland?
sources = [(hm-lib.gvariant.mkTuple ["xkb" "gb"])]; sources = [(homeManagerLib.gvariant.mkTuple ["xkb" "gb"])];
per-window = false; per-window = false;
}; };
"org/gnome/desktop/media-handling" = { "org/gnome/desktop/media-handling" = {
@ -122,7 +118,7 @@ in {
}; };
"org/gnome/desktop/wm/preferences" = { "org/gnome/desktop/wm/preferences" = {
num-workspaces = 9; num-workspaces = 9;
titlebar-font = "Comic Code Medium ${font-sizes.small}"; titlebar-font = "Comic Code Medium ${fontSizes.small}";
titlebar-uses-system-font = true; titlebar-uses-system-font = true;
}; };
"org/gnome/settings-daemon/plugins/media-keys" = { "org/gnome/settings-daemon/plugins/media-keys" = {

View file

@ -4,7 +4,10 @@
lib, lib,
tree, tree,
... ...
}: { }: let
inherit (lib.modules) mkMerge;
inherit (lib.strings) escapeShellArgs;
in {
# import default terminal # import default terminal
imports = with tree; [home.apps.kitty home.apps.rofi]; imports = with tree; [home.apps.kitty home.apps.rofi];
@ -64,11 +67,11 @@
names = ["Comic Code"]; names = ["Comic Code"];
size = 14.0; size = 14.0;
}; };
statusCommand = lib.escapeShellArgs [ statusCommand = escapeShellArgs [
"/home/chaos/Projects/rustbar/target/debug/rustbar" #"/home/chaos/Projects/rustbar/target/debug/rustbar"
#"${pkgs.gobar}/bin/gobar" "${pkgs.gobar}/bin/gobar"
#"-config" "-config"
#"cpu\\|mem\\|weather\\(Leighton\\ Buzzard\\)\\|bat\\(BAT0\\)\\|time" "cpu\\|mem\\|weather\\(Leighton\\ Buzzard\\)\\|bat\\(BAT0\\)\\|time"
]; ];
} }
{command = "${pkgs.waybar}/bin/waybar";} {command = "${pkgs.waybar}/bin/waybar";}
@ -149,7 +152,7 @@
"${cfg.modifier}+r" = "mode resize"; "${cfg.modifier}+r" = "mode resize";
} }
// (lib.foldl lib.recursiveUpdate {} (map (workspace: { // (mkMerge (map (workspace: {
"${cfg.modifier}+${workspace}" = "workspace ${workspace}"; "${cfg.modifier}+${workspace}" = "workspace ${workspace}";
"${cfg.modifier}+Shift+${workspace}" = "move container to workspace ${workspace}"; "${cfg.modifier}+Shift+${workspace}" = "move container to workspace ${workspace}";
}) ["1" "2" "3" "4" "5" "6" "7" "8" "9"])); }) ["1" "2" "3" "4" "5" "6" "7" "8" "9"]));

View file

@ -7,8 +7,8 @@
# expected to be in default locations # expected to be in default locations
# Incase home.apps.manual-backup-apps is running in container which passes secrets in from host # Incase home.apps.manual-backup-apps is running in container which passes secrets in from host
secrets = secrets =
if builtins.elem "host_secrets" (builtins.attrNames file_inputs) if file_inputs ? "hostSecrets"
then file_inputs.host_secrets then file_inputs.hostSecrets
else nixosConfig.services.secrets.secrets; else nixosConfig.services.secrets.secrets;
in { in {
home.packages = with pkgs; [ home.packages = with pkgs; [

View file

@ -1,27 +1,18 @@
{nixosConfig, ...}: let {...}: {
font-size =
if nixosConfig.networking.hostName == "tablet"
then 18
else 24;
zoom-level =
if nixosConfig.networking.hostName == "tablet"
then -2
else 0;
in {
programs.vscode-mod = { programs.vscode-mod = {
enable = true; enable = true;
userSettings = { userSettings = {
"terminal.integrated.shellIntegration.enabled" = false; "terminal.integrated.shellIntegration.enabled" = false;
"github.gitAuthentication" = false; "github.gitAuthentication" = false;
"editor.fontSize" = font-size; "editor.fontSize" = 24;
"editor.fontFamily" = "'Comic Code'"; "editor.fontFamily" = "'Comic Code'";
"terminal.integrated.fontSize" = font-size; "terminal.integrated.fontSize" = 18;
"editor.codeLensFontFamily" = "'Comic Code'"; "editor.codeLensFontFamily" = "'Comic Code'";
"editor.inlayHints.fontFamily" = "'Comic Code'"; "editor.inlayHints.fontFamily" = "'Comic Code'";
"markdown.preview.fontFamily" = "'Comic Code'"; "markdown.preview.fontFamily" = "'Comic Code'";
"terminal.integrated.fontFamily" = "'Comic Code'"; "terminal.integrated.fontFamily" = "'Comic Code'";
"files.autoSave" = "afterDelay"; "files.autoSave" = "afterDelay";
"window.zoomLevel" = zoom-level; "window.zoomLevel" = 0;
"editor.tabSize" = 2; "editor.tabSize" = 2;
}; };
}; };

View file

@ -1,11 +0,0 @@
{...}: let
usb_data = import ../data/usb_data.nix {};
in {
programs.ssh.matchBlocks."*".identityFile = "${usb_data.ssh_priv_path}";
programs.git.extraConfig = {
gpg.format = "ssh";
commit.gpgsign = "true";
tag.gpgsign = "true";
user = {signingKey = "${usb_data.ssh_priv_path}";};
};
}

11
home/sshUSB.nix Normal file
View file

@ -0,0 +1,11 @@
{...}: let
encryptedUSBData = import ../data/encryptedUSB.nix;
in {
programs.ssh.matchBlocks."*".identityFile = "${encryptedUSBData.sshPrivateKeyPath}";
programs.git.extraConfig = {
gpg.format = "ssh";
commit.gpgsign = "true";
tag.gpgsign = "true";
user.signingKey = "${encryptedUSBData.sshPrivateKeyPath}";
};
}

View file

@ -1,116 +0,0 @@
{
tree,
config,
pkgs,
...
}: let
secrets = config.services.secrets.secrets;
in {
imports = with tree; [
users.root
profiles.base
profiles.sshd
profiles.nix-gc
./hardware.nix
./networking.nix
./secrets.nix
];
environment.etc."mdadm.conf".text = ''
HOMEHOST <ignore>
PROGRAM /run/current-system/sw/bin/mdadm-notify
'';
# some taken from https://github.com/hunleyd/mdadm_notify/blob/master/mdadm_notify
environment.systemPackages = [
(pkgs.writeShellScriptBin "mdadm-notify" ''
event=$1
md_device=$2
device=$3
case $event in
DegradedArray)
msg="$md_device is running in DEGRADED MODE"
;;
DeviceDisappeared)
msg="$md_device has DISAPPEARED"
;;
Fail)
msg="$md_device had an ACTIVE component FAIL ($device)"
;;
FailSpare)
msg="$md_device had a SPARE component FAIL during rebuild ($device)"
;;
MoveSpare)
msg="SPARE device $device has been MOVED to a new array ($md_device)"
;;
NewArray)
# silence NewArray
exit 0
msg="$md_device has APPEARED"
;;
Rebuild??)
msg="$md_device REBUILD is now `echo $event|sed 's/Rebuild//'`% complete"
;;
RebuildFinished)
msg="REBUILD of $md_device is COMPLETE or ABORTED"
;;
RebuildStarted)
msg="RECONSTRUCTION of $md_device has STARTED"
;;
SpareActive)
msg="$device has become an ACTIVE COMPONENT of $md_device"
;;
SparesMissing)
msg="$md_device is MISSING one or more SPARE devices"
;;
TestMessage)
msg="TEST MESSAGE generated for $md_device"
;;
esac
printf "Subject: BuildBox mdadm: $event\n\n$msg" | msmtp "all@owo.monster"
'')
];
programs.msmtp = {
enable = true;
accounts = {
default = {
auth = true;
tls = true;
protocol = "smtp";
host = "mail.owo.monster";
port = 587;
from = "system@owo.monster";
user = "system@owo.monster";
passwordeval = "cat ${secrets.system_mail_password.path}";
};
};
};
systemd.services.mdmonitor = {
requires = ["network.target"];
wantedBy = ["multi-user.target"];
path = with pkgs; [mdadm msmtp];
script = ''
exec mdadm --monitor --scan
'';
serviceConfig = {
Restart = "always";
StartLimitAction = "none";
};
};
home-manager.users.root = {
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
networking.hostName = "buildbox";
time.timeZone = "Europe/London";
system.stateVersion = "23.05";
}

View file

@ -1,25 +0,0 @@
{config, ...}: {
boot.initrd.kernelModules = ["dm-snapshot"];
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod"];
boot.kernelModules = ["kvm-amd"];
boot.initrd.services.swraid.mdadmConf =
config.environment.etc."mdadm.conf".text;
fileSystems."/" = {
device = "/dev/disk/by-label/root";
fsType = "ext4";
};
fileSystems."/boot" = {
device = "/dev/disk/by-label/boot";
fsType = "ext4";
};
boot.loader.grub = {
enable = true;
efiSupport = false;
device = "nodev";
devices = ["/dev/sda" "/dev/sdb"];
};
}

View file

@ -1,25 +0,0 @@
{lib, ...}: {
systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;
networking = {
resolvconf.useLocalResolver = false;
networkmanager.dns = "none";
};
networking.nameservers = ["1.1.1.1"];
networking.firewall.enable = true;
networking.firewall.allowPing = true;
networking.firewall.allowedTCPPorts = [22];
networking.enableIPv6 = true;
networking.usePredictableInterfaceNames = false;
networking.dhcpcd.enable = false;
systemd.network = {
enable = true;
networks.eth0 = {
name = "eth0";
address = ["144.76.97.18"];
gateway = ["144.76.97.1"];
};
};
}

View file

@ -1,15 +0,0 @@
{...}: {
services.secrets = {
enable = true;
secrets = {
system_mail_password = {
user = "root";
group = "root";
fetchScript = ''
simple_get "/api-keys/chaos_mail/system" .password > "$secretFile"
'';
};
};
};
}

View file

@ -1,35 +0,0 @@
{
nixpkgs-unstable,
nix-darwin-unstable,
tree,
...
} @ inputs: let
defaultSpecialArgs =
defaults.defaultSpecialArgs
// {
inputs =
inputs
// {
# set these to the correct versions from inputs
nixpkgs = inputs.nixpkgs-unstable;
home-manager = inputs.home-manager-unstable;
darwin = inputs.nix-darwin-unstable;
};
};
defaultModules =
defaults.defaultModules
++ [
# NO_INLINE
tree.impure.profiles.base-darwin
inputs.home-manager-unstable.darwinModules.home-manager
];
darwinSystem = nix-darwin-unstable.lib.darwinSystem;
in {
"MacMini" = darwinSystem {
specialArgs = defaultSpecialArgs;
system = "aarch64-darwin";
modules = defaultModules ++ [./macmini/default.nix];
};
}

View file

@ -1,4 +1,3 @@
{...} @ inputs: { {...} @ inputs: {
nixosConfigurations = import ./nixos.nix inputs; nixosConfigurations = import ./nixos.nix inputs;
#darwinConfigurations = import ./darwin.nix inputs;
} }

View file

@ -1,11 +1,16 @@
{ {
self,
tree, tree,
lib, lib,
inputs, inputs,
config, config,
pkgs, pkgs,
hostPath,
... ...
}: let }: let
inherit (lib.modules) mkMerge;
inherit (lib.lists) forEach;
ports = [ ports = [
# SMTP # SMTP
25 25
@ -21,9 +26,13 @@
4190 4190
]; ];
containerLib = import "${self}/lib/containerLib.nix" {
inherit lib;
};
# Using secrets from Host # Using secrets from Host
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
secrets_list = [ secretsList = [
"mail_restic_password" "mail_restic_password"
"mail_restic_env" "mail_restic_env"
"private_mail_aliases" "private_mail_aliases"
@ -31,7 +40,7 @@
"system_mail_passwd" "system_mail_passwd"
"gotosocial_mail_passwd" "gotosocial_mail_passwd"
]; ];
shared_files = [ sharedFiles = [
"/var/lib/acme/mail.owo.monster/fullchain.pem" "/var/lib/acme/mail.owo.monster/fullchain.pem"
"/var/lib/acme/mail.owo.monster/key.pem" "/var/lib/acme/mail.owo.monster/key.pem"
]; ];
@ -39,15 +48,10 @@ in {
containers.mail = { containers.mail = {
autoStart = true; autoStart = true;
bindMounts = lib.mkMerge [ bindMounts = mkMerge [
(lib.mkMerge (lib.forEach secrets_list (secret_name: let (containerLib.genBindHostsForSecrets secrets secretsList)
path = "${secrets.${secret_name}.path}";
in { (mkMerge (forEach sharedFiles (file: {
"${path}" = {
hostPath = "${path}";
};
})))
(lib.mkMerge (lib.forEach shared_files (file: {
"${file}" = { "${file}" = {
hostPath = "${file}"; hostPath = "${file}";
}; };
@ -57,7 +61,9 @@ in {
specialArgs = { specialArgs = {
inherit inputs; inherit inputs;
inherit tree; inherit tree;
host_secrets = secrets; inherit self;
inherit hostPath;
hostSecrets = secrets;
}; };
config = {config, ...}: { config = {config, ...}: {

View file

@ -1,134 +1,173 @@
{ {
config, config,
pkgs,
lib, lib,
... ...
}: }: let
with lib; let inherit (lib) types;
inherit (lib.options) mkEnableOption mkOption mkPackageOption;
cfg = config.services.mailserver; cfg = config.services.mailserver;
in { in {
options.services.mailserver = { options.services.mailserver = {
enable = mkEnableOption "mailserver"; enable = mkEnableOption "mailserver";
fqdn = mkOption {type = types.str;}; fqdn = mkOption {
type = types.str;
domains = mkOption {type = types.listOf types.str;}; description = "domain used for mx records";
ssl_config = mkOption {
type = types.submodule {
options = {
useACME = mkOption {
type = types.bool;
default = true;
};
cert = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/fullchain.pem";
};
key = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/key.pem";
};
};
};
default = {};
}; };
debug_mode = mkOption { domains = mkOption {
type = types.listOf types.str;
description = "all domains for receiving mail on";
};
debugMode = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = "enable debug logging on everything";
}; };
enable_roundcube = mkOption { sslConfig = {
type = types.bool; useACME = mkOption {
default = true; type = types.bool;
default = true;
};
cert = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/fullchain.pem";
};
key = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/key.pem";
};
}; };
roundcube_url = mkOption { roundcube = {
type = types.str; enable = mkOption {
default = "${cfg.fqdn}"; type = types.bool;
default = true;
};
package = mkPackageOption pkgs "roundcube" {};
domain = mkOption {
type = types.str;
default = "${cfg.fqdn}";
};
plugins = mkOption {
type = types.listOf types.str;
default = [];
};
extraConfig = mkOption {
type = types.lines;
default = "";
};
forceSSL = mkOption {
type = types.bool;
default = true;
};
enableACME = mkOption {
type = types.bool;
default = true;
};
}; };
force_roundcube_ssl = mkOption { spf = {
type = types.bool; enable = mkOption {
default = true; type = types.bool;
default = true;
};
policydConfig = mkOption {
type = types.str;
default = "";
};
}; };
force_roundcube_acme = mkOption { rspamd = {
type = types.bool; enable = mkOption {
default = true; type = types.bool;
default = true;
};
extraConfig = mkOption {
type = types.lines;
default = "";
};
redisPort = mkOption {
type = types.number;
default = 6380;
};
}; };
accounts = mkOption { accounts = mkOption {
# where name = email for login # where attrName = email for login
type = types.attrsOf (types.submodule ({name, ...}: { default = {};
type = types.attrsOf (types.submodule {
options = { options = {
name = mkOption { passwordHashFile = mkOption {
type = types.str; type = types.str;
default = name; description = ''
a file containing the hashed password for user, loaded at runtime
'';
};
aliases = mkOption {
type = types.listOf types.str;
default = [];
description = "a list of aliases for receiving/sending mail";
};
sieveScript = mkOption {
type = types.nullOr types.lines;
default = null;
description = "a default sieve script for filtering mail";
}; };
passwordFile = mkOption {type = types.str;};
aliases = mkOption {type = types.listOf types.str;};
sieveScript = mkOption {type = types.nullOr types.lines;};
}; };
})); });
}; };
extra_aliases_file = mkOption { extraAliasesFile = mkOption {
type = types.nullOr types.str; type = types.nullOr types.str;
default = null; default = null;
description = "file containing postfix aliases for receiving, loaded at runtime";
}; };
sieve_directory = mkOption { sieveDirectory = mkOption {
type = types.str; type = types.str;
default = "/var/sieve"; default = "/var/sieve";
description = "path used for storing sieve scripts";
}; };
dkim_directory = mkOption { dkim = {
type = types.str; enable = mkOption {
default = "/var/dkim"; type = types.bool;
}; default = true;
};
policyd_config = mkOption { directory = mkOption {
type = types.lines; type = types.str;
default = ""; default = "/var/dkim";
}; description = "path used for storing dkim signing keys, make sure to keep this backed up";
};
extra_roundcube_config = mkOption { };
type = types.lines;
default = ""; vmail = {
}; user = mkOption {
type = types.str;
rspamd_redis_port = mkOption { default = "vmail";
type = types.number; };
default = 6380; group = mkOption {
}; type = types.str;
default = "${cfg.vmail.user}";
vmail_config = mkOption { };
type = types.submodule { userID = mkOption {
options = { type = types.number;
user = mkOption { default = 5000;
type = types.str; };
default = "vmail"; groupID = mkOption {
}; type = types.number;
group = mkOption { default = cfg.vmail.userID;
type = types.str; };
default = "${cfg.vmail_config.user}"; directory = mkOption {
}; type = types.str;
user_id = mkOption { default = "/home/${cfg.vmail.user}";
type = types.number;
default = 5000;
};
group_id = mkOption {
type = types.number;
default = cfg.vmail_config.user_id;
};
directory = mkOption {
type = types.str;
default = "/home/${cfg.vmail_config.user}";
};
};
}; };
default = {};
}; };
}; };
} }

View file

@ -4,64 +4,39 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.strings) concatStringsSep optionalString;
vmail_config = mail_config.vmail_config; mailConfig = config.services.mailserver;
vmailConfig = mailConfig.vmail;
passwdDir = "/run/dovecot2";
passwdFile = "${passwdDir}/passwd";
postfixCfg = config.services.postfix; postfixCfg = config.services.postfix;
dovecotRuntimeDir = "/run/dovecot2";
passwdFile = "${dovecotRuntimeDir}/passwd";
genPasswdScript = pkgs.writeScript "generate-password-file" '' genPasswdScript = pkgs.writeScript "generate-password-file" ''
#!${pkgs.stdenv.shell} #!${pkgs.stdenv.shell}
set -euo pipefail set -euo pipefail
if (! test -d "${passwdDir}"); then ${concatStringsSep "\n" (map (userPasswdFile: ''
mkdir "${passwdDir}" if [ ! -f "${userPasswdFile}" ]; then
chmod 755 "${passwdDir}" echo "Expected password hash file ${userPasswdFile} does not exist!"
fi
for f in ${
builtins.toString
(lib.mapAttrsToList (_: value: value.passwordFile)
mail_config.accounts)
}; do
if [ ! -f "$f" ]; then
echo "Expected password hash file $f does not exist!"
exit 1 exit 1
fi fi
done '') (mapAttrsToList (_email: config: config.passwordHashFile) mailConfig.accounts))}
cat <<EOF > ${passwdFile} cat <<EOF > ${passwdFile}
${ ${concatStringsSep "\n" (mapAttrsToList (
lib.concatStringsSep "\n" email: config: "${email}:$(head -n 1 ${config.passwordHashFile})"
(lib.mapAttrsToList (name: value: "${name}:$(head -n 1 ${value.passwordFile})") mail_config.accounts) )
} mailConfig.accounts)}
EOF EOF
chmod 600 ${passwdFile}
''; '';
pipeBin = pkgs.stdenv.mkDerivation {
name = "pipe_bin";
src = ./pipe_bin;
buildInputs = with pkgs; [makeWrapper coreutils bash rspamd];
buildCommand = ''
mkdir -p $out/pipe/bin
cp $src/* $out/pipe/bin/
chmod a+x $out/pipe/bin/*
patchShebangs $out/pipe/bin
for file in $out/pipe/bin/*; do
wrapProgram $file \
--set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin"
done
'';
};
in { in {
config = lib.mkIf (mail_config.enable) { config = mkIf (mailConfig.enable) {
services.dovecot2 = { services.dovecot2 = {
enable = true; enable = true;
enableImap = true; enableImap = true;
@ -70,12 +45,12 @@ in {
enablePop3 = false; enablePop3 = false;
enablePAM = false; # Not using PAM for Auth enablePAM = false; # Not using PAM for Auth
mailUser = vmail_config.user; mailUser = vmailConfig.user;
mailGroup = vmail_config.group; mailGroup = vmailConfig.group;
mailLocation = "maildir:${vmail_config.directory}/%d/%n"; mailLocation = "maildir:${vmailConfig.directory}/%d/%n";
sslServerCert = mail_config.ssl_config.cert; sslServerCert = mailConfig.sslConfig.cert;
sslServerKey = mail_config.ssl_config.key; sslServerKey = mailConfig.sslConfig.key;
# For Sieve # For Sieve
modules = with pkgs; [dovecot_pigeonhole]; modules = with pkgs; [dovecot_pigeonhole];
@ -112,7 +87,7 @@ in {
}; };
extraConfig = '' extraConfig = ''
${lib.optionalString mail_config.debug_mode '' ${optionalString mailConfig.debugMode ''
mail_debug = yes mail_debug = yes
auth_debug = yes auth_debug = yes
verbose_ssl = yes verbose_ssl = yes
@ -152,11 +127,11 @@ in {
mail_plugins = $mail_plugins sieve mail_plugins = $mail_plugins sieve
} }
mail_access_groups = "${vmail_config.group}" mail_access_groups = "${vmailConfig.group}"
userdb { userdb {
driver = static driver = static
args = uid=${toString vmail_config.user_id} gid=${toString vmail_config.group_id} args = uid=${toString vmailConfig.userID} gid=${toString vmailConfig.groupID}
} }
passdb { passdb {
@ -181,8 +156,8 @@ in {
plugin { plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms sieve_plugins = sieve_imapsieve sieve_extprograms
sieve = file:${mail_config.sieve_directory}/%u/scripts;active=${mail_config.sieve_directory}/%u/active.sieve sieve = file:${mailConfig.sieveDirectory}/%u/scripts;active=${mailConfig.sieveDirectory}/%u/active.sieve
sieve_default = file:${mail_config.sieve_directory}/%u/default.sieve sieve_default = file:${mailConfig.sieveDirectory}/%u/default.sieve
sieve_default_name = default sieve_default_name = default
# From elsewhere to Spam folder # From elsewhere to Spam folder
@ -196,20 +171,44 @@ in {
imapsieve_mailbox2_causes = COPY imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:${./spam_sieve/report-ham.sieve} imapsieve_mailbox2_before = file:${./spam_sieve/report-ham.sieve}
sieve_pipe_bin_dir = ${pipeBin}/pipe/bin ${optionalString mailConfig.rspamd.enable (let
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment pipeBin = pkgs.stdenv.mkDerivation {
name = "pipe_bin";
src = ./pipe_bin;
buildInputs = with pkgs; [makeWrapper coreutils bash rspamd];
buildCommand = ''
mkdir -p $out/pipe/bin
cp $src/* $out/pipe/bin/
chmod a+x $out/pipe/bin/*
patchShebangs $out/pipe/bin
for file in $out/pipe/bin/*; do
wrapProgram $file \
--set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin"
done
'';
};
in ''
sieve_pipe_bin_dir = ${pipeBin}/pipe/bin
'')}
sieve_global_extensions = ${optionalString mailConfig.rspamd.enable "+vnd.dovecot.pipe"} +vnd.dovecot.environment
} }
lda_mailbox_autosubscribe = yes lda_mailbox_autosubscribe = yes
lda_mailbox_autocreate = yes lda_mailbox_autocreate = yes
''; '';
}; };
systemd.services.dovecot2 = { systemd = {
preStart = '' tmpfiles.rules = [
${genPasswdScript} "f ${passwdFile} 600 dovecot2 dovecot2"
''; ];
services = {
dovecot2.preStart = ''
${genPasswdScript}
'';
postfix.restartTriggers = [genPasswdScript];
};
}; };
systemd.services.postfix.restartTriggers = [genPasswdScript];
}; };
} }

View file

@ -3,9 +3,11 @@
config, config,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
mailConfig = config.services.mailserver;
in { in {
config = lib.mkIf mail_config.enable { config = mkIf mailConfig.enable {
networking.firewall = { networking.firewall = {
allowedTCPPorts = [ allowedTCPPorts = [
# SMTP # SMTP

View file

@ -3,82 +3,83 @@
lib, lib,
pkgs, pkgs,
... ...
}: }: let
with lib; let inherit (lib.modules) mkIf mkForce;
mail_config = config.services.mailserver; inherit (lib.trivial) flip;
dkimUser = config.services.opendkim.user; inherit (lib.strings) optionalString escapeShellArgs;
dkimGroup = config.services.opendkim.group; inherit (builtins) toFile concatStringsSep;
keyDir = mail_config.dkim_directory; mailConfig = config.services.mailserver;
opendkimConfig = config.services.opendkim;
opendkimArgs = ["-f" "-l" "-x" opendkimConfig.configFile];
dkimUser = opendkimConfig.user;
dkimGroup = opendkimConfig.group;
keyDir = mailConfig.dkim.directory;
selector = "mail"; selector = "mail";
domains = mail_config.domains; domains = mailConfig.domains;
createDomainDkimCert = dom: let createDomainDkimCert = dom: let
dkim_key = "${keyDir}/${dom}.${selector}.key"; dkimKey = "${keyDir}/${dom}.${selector}.key";
dkim_txt = "${keyDir}/${dom}.${selector}.txt"; dkimDNSFile = "${keyDir}/${dom}.${selector}.txt";
in '' in ''
if [ ! -f "${dkim_key}" ] if [ ! -f "${dkimKey}" ]
then then
${pkgs.opendkim}/bin/opendkim-genkey -s "${selector}" \ ${pkgs.opendkim}/bin/opendkim-genkey -s "${selector}" \
-d "${dom}" \ -d "${dom}" \
--bits="1024" \ --bits="1024" \
--directory="${keyDir}" --directory="${keyDir}"
mv "${keyDir}/${selector}.private" "${dkim_key}" mv "${keyDir}/${selector}.private" "${dkimKey}"
mv "${keyDir}/${selector}.txt" "${dkim_txt}" mv "${keyDir}/${selector}.txt" "${dkimDNSFile}"
echo "Generated key for domain ${dom} selector ${selector}" echo "Generated key for domain ${dom} selector ${selector}"
fi fi
''; '';
createAllCerts = createAllCerts =
concatStringsSep "\n" (map createDomainDkimCert mail_config.domains); concatStringsSep "\n" (map createDomainDkimCert mailConfig.domains);
keyTable = pkgs.writeText "opendkim-KeyTable" (concatStringsSep "\n" keyTable = toFile "opendkim-KeyTable" (concatStringsSep "\n"
(flip map domains (flip map domains
(dom: "${dom} ${dom}:${selector}:${keyDir}/${dom}.${selector}.key"))); (dom: "${dom} ${dom}:${selector}:${keyDir}/${dom}.${selector}.key")));
signingTable = signingTable =
pkgs.writeText "opendkim-SigningTable" toFile "opendkim-SigningTable"
(concatStringsSep "\n" (flip map domains (dom: "${dom} ${dom}"))); (concatStringsSep "\n" (flip map domains (dom: "${dom} ${dom}")));
dkim = config.services.opendkim;
args =
["-f" "-l"]
++ optionals (dkim.configFile != null) ["-x" dkim.configFile];
in { in {
config = mkIf (mail_config.enable) { config = mkIf (mailConfig.enable && mailConfig.dkim.enable) {
services.opendkim = { services.opendkim = {
enable = true; enable = true;
selector = selector; selector = selector;
keyPath = keyDir; keyPath = keyDir;
domains = "csl:${builtins.concatStringsSep "," domains}"; domains = "csl:${concatStringsSep "," domains}";
configFile = pkgs.writeText "opendkim.conf" ('' configFile = toFile "opendkim.conf" (''
Canonicalization relaxed/relaxed Canonicalization relaxed/relaxed
UMask 0002 UMask 0002
Socket ${dkim.socket} Socket ${opendkimConfig.socket}
KeyTable file:${keyTable} KeyTable file:${keyTable}
SigningTable file:${signingTable} SigningTable file:${signingTable}
'' ''
+ (optionalString mail_config.debug_mode '' + (optionalString mailConfig.debugMode ''
Syslog yes Syslog yes
SyslogSuccess yes SyslogSuccess yes
LogWhy yes LogWhy yes
'')); ''));
}; };
users.users = optionalAttrs (config.services.postfix.user == "postfix") { systemd.tmpfiles.rules = ["d '${keyDir}' - ${dkimUser} ${dkimGroup} - -"];
postfix.extraGroups = ["${dkimGroup}"];
}; users.users.postfix.extraGroups = ["${dkimGroup}"];
systemd.services.opendkim = { systemd.services.opendkim = {
preStart = mkForce createAllCerts; preStart = mkForce createAllCerts;
serviceConfig = { serviceConfig = {
ExecStart = ExecStart =
mkForce mkForce
"${pkgs.opendkim}/bin/opendkim ${escapeShellArgs args}"; "${pkgs.opendkim}/bin/opendkim ${escapeShellArgs opendkimArgs}";
PermissionsStartOnly = mkForce false; PermissionsStartOnly = mkForce false;
}; };
}; };
systemd.tmpfiles.rules = ["d '${keyDir}' - ${dkimUser} ${dkimGroup} - -"];
}; };
} }

View file

@ -4,114 +4,101 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
submissionHeaderCleanupRules = pkgs.writeText "submission_header_cleanup_rules" '' inherit (lib.strings) concatStringsSep;
/^Received:/ IGNORE inherit (lib.lists) flatten optional;
/^X-Originating-IP:/ IGNORE inherit (lib.attrsets) mapAttrsToList;
/^X-Mailer:/ IGNORE inherit (builtins) toFile;
/^User-Agent:/ IGNORE
/^X-Enigmail:/ IGNORE
/^Message-ID:\s+<(.*?)@.*?>/ REPLACE Message-ID: <$1@${mail_config.fqdn}>
'';
# Merge several lookup tables. A lookup table is a attribute set where mailConfig = config.services.mailserver;
# - the key is an address (user@example.com) or a domain (@example.com)
# - the value is a list of addresses
mergeLookupTables = tables: lib.zipAttrsWith (_: v: lib.flatten v) tables;
# valiases_postfix :: Map String [String]
valiases_postfix = mergeLookupTables (lib.flatten (lib.mapAttrsToList
(name: value: let
to = name;
in
map (from: {"${from}" = to;}) (value.aliases ++ lib.singleton name))
mail_config.accounts));
# all_valiases_postfix :: Map String [String]
all_valiases_postfix = mergeLookupTables [valiases_postfix];
# lookupTableToString :: Map String [String] -> String
lookupTableToString = attrs: let
valueToString = value: lib.concatStringsSep ", " value;
in
lib.concatStringsSep "\n"
(lib.mapAttrsToList (name: value: "${name} ${valueToString value}") attrs);
vhosts_file =
builtins.toFile "vhosts" (lib.concatStringsSep "\n" mail_config.domains);
aliases_accounts_file = let
content = lookupTableToString (mergeLookupTables [all_valiases_postfix]);
in
builtins.toFile "aliases_accounts" content;
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
policyd-spf = pkgs.writeText "policyd-spf.conf" mail_config.policyd_config;
submissionOptions = {
smtpd_tls_security_level = "encrypt";
smtpd_sasl_auth_enable = "yes";
smtpd_sasl_type = "dovecot";
smtpd_sasl_path = "/run/dovecot2/auth";
smtpd_sasl_security_options = "noanonymous";
smtpd_sasl_local_domain = "$myhostname";
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
smtpd_sender_login_maps = mappedFile "aliases_accounts";
smtpd_sender_restrictions = "reject_sender_login_mismatch";
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
cleanup_service_name = "submission-header-cleanup";
};
tls_allowed = "TLSv1.3, TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3"; tls_allowed = "TLSv1.3, TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
tls_disallow = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL"; tls_disallow = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
sendingReceivingAliases = concatStringsSep "\n" (flatten [
(mapAttrsToList (email: config:
map (
alias: "${alias} ${email} "
)
config.aliases)
mailConfig.accounts)
(mapAttrsToList (email: _config: [
# i dont know if this is actually needed
"${email} ${email}"
])
mailConfig.accounts)
]);
sendingReceivingAliasesMappedName = "sending_receiving_aliases";
sendingReceivingAliasesFile = toFile "${sendingReceivingAliasesMappedName}" sendingReceivingAliases;
extraAliasesCombinedFilePath = "/run/postfix_sending_receiving_aliases";
in { in {
config = lib.mkIf (mail_config.enable) { config = mkIf (mailConfig.enable) {
systemd.tmpfiles.rules = lib.mkIf (mail_config.extra_aliases_file != null) [ systemd.tmpfiles.rules = mkIf (mailConfig.extraAliasesFile != null) [
# folder to store the extra aliases file "f ${extraAliasesCombinedFilePath} 660 root root"
"f /run/postfix_extra_aliases 660 root root"
]; ];
systemd.services.postfix-extra-aliases-setup = lib.mkIf (mail_config.extra_aliases_file != null) { systemd.services.postfix-extra-aliases-setup = mkIf (mailConfig.extraAliasesFile != null) {
wantedBy = ["multi-user.target"]; wantedBy = ["multi-user.target"];
partOf = ["postfix.service"]; partOf = ["postfix.service"];
before = ["postfix-setup.service"]; before = ["postfix-setup.service"];
script = '' script = ''
cat ${aliases_accounts_file} > /run/postfix_extra_aliases cat "${sendingReceivingAliasesFile}" > ${extraAliasesCombinedFilePath}
echo >> /run/postfix_extra_aliases echo >> ${extraAliasesCombinedFilePath}
cat ${mail_config.extra_aliases_file} >> /run/postfix_extra_aliases cat "${mailConfig.extraAliasesFile}" >> ${extraAliasesCombinedFilePath}
''; '';
}; };
services.postfix = { services.postfix = let
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
sendingReceivingAliasesMappedFile = mappedFile sendingReceivingAliasesMappedName;
submissionOptions = {
smtpd_tls_security_level = "encrypt";
smtpd_sasl_auth_enable = "yes";
smtpd_sasl_type = "dovecot";
smtpd_sasl_path = "/run/dovecot2/auth";
smtpd_sasl_security_options = "noanonymous";
smtpd_sasl_local_domain = "$myhostname";
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
smtpd_sender_login_maps = sendingReceivingAliasesMappedFile;
smtpd_sender_restrictions = "reject_sender_login_mismatch";
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
cleanup_service_name = "submission-header-cleanup";
};
in {
enable = true; enable = true;
hostname = "${mail_config.fqdn}"; hostname = "${mailConfig.fqdn}";
networksStyle = "host"; networksStyle = "host";
mapFiles."aliases_accounts" = mapFiles = {
if (mail_config.extra_aliases_file == null) "sending_receiving_aliases" =
then aliases_accounts_file if (mailConfig.extraAliasesFile == null)
else "/run/postfix_extra_aliases"; then sendingReceivingAliasesFile
else "${extraAliasesCombinedFilePath}";
};
sslCert = mail_config.ssl_config.cert;
sslKey = mail_config.ssl_config.key;
enableSubmission = true; enableSubmission = true;
enableSubmissions = true; enableSubmissions = true;
sslCert = mailConfig.sslConfig.cert;
sslKey = mailConfig.sslConfig.key;
config = { config = {
# Extra Config # Extra Config
mydestination = ""; mydestination = "";
recipient_delimiter = "+"; recipient_delimiter = "+";
smtpd_banner = "${mail_config.fqdn} ESMTP NO UCE"; smtpd_banner = "${mailConfig.fqdn} ESMTP NO UCE";
disable_vrfy_command = true; disable_vrfy_command = true;
message_size_limit = "20971520"; message_size_limit = "20971520";
virtual_uid_maps = "static:${toString mail_config.vmail_config.user_id}"; virtual_uid_maps = "static:${toString mailConfig.vmail.userID}";
virtual_gid_maps = "static:${toString mail_config.vmail_config.group_id}"; virtual_gid_maps = "static:${toString mailConfig.vmail.groupID}";
virtual_mailbox_base = "${mail_config.vmail_config.directory}"; virtual_mailbox_base = "${mailConfig.vmail.directory}";
virtual_mailbox_domains = vhosts_file; virtual_mailbox_domains = toFile "vhosts" (concatStringsSep "\n" mailConfig.domains);
virtual_mailbox_maps = mappedFile "aliases_accounts"; virtual_mailbox_maps = sendingReceivingAliasesMappedFile;
virtual_alias_maps = mappedFile "aliases_accounts"; virtual_alias_maps = sendingReceivingAliasesMappedFile;
virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp"; virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
lmtp_destination_recipient_limit = "1"; lmtp_destination_recipient_limit = "1";
@ -124,12 +111,10 @@ in {
"reject_unauth_destination" "reject_unauth_destination"
]; ];
policy-spf_time_limit = "3600s"; policy-spf_time_limit = mkIf (mailConfig.spf.enable) "3600s";
smtpd_recipient_restrictions = [ smtpd_recipient_restrictions = flatten [
#"check_recipient_access ${mappedFile "denied_recipients"}" (optional mailConfig.spf.enable "check_policy_service unix:private/policy-spf")
#"check_recipient_access ${mappedFile "reject_recipients"}"
"check_policy_service unix:private/policy-spf"
]; ];
smtpd_tls_security_level = "may"; smtpd_tls_security_level = "may";
@ -161,11 +146,14 @@ in {
milter_default_action = "quarantine"; milter_default_action = "quarantine";
smtpd_milters = [ smtpd_milters = flatten [
"unix:/run/opendkim/opendkim.sock" (optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.sock")
"unix:/run/rspamd/rspamd-milter.sock" (optional mailConfig.rspamd.enable "unix:/run/rspamd/rspamd-milter.sock")
];
non_smtpd_milters = flatten [
(optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.sock")
]; ];
non_smtpd_milters = ["unix:/run/opendkim/opendkim.sock"];
milter_protocol = "6"; milter_protocol = "6";
milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}"; milter_mail_macros = "i {mail_addr} {client_addr} {client_name} {auth_type} {auth_authen} {auth_author} {mail_addr} {mail_host} {mail_mailer}";
@ -180,15 +168,17 @@ in {
# D => Delivered-To, O => X-Original-To, R => Return-Path # D => Delivered-To, O => X-Original-To, R => Return-Path
args = ["flags=O"]; args = ["flags=O"];
}; };
"policy-spf" = { "policy-spf" = mkIf (mailConfig.spf.enable) {
type = "unix"; type = "unix";
privileged = true; privileged = true;
chroot = false; chroot = false;
command = "spawn"; command = "spawn";
args = [ args = let
policydConfig = toFile "policyd-spf.conf" mailConfig.spf.policydConfig;
in [
"user=nobody" "user=nobody"
"argv=${pkgs.pypolicyd-spf}/bin/policyd-spf" "argv=${pkgs.pypolicyd-spf}/bin/policyd-spf"
"${policyd-spf}" "${policydConfig}"
]; ];
}; };
"submission-header-cleanup" = { "submission-header-cleanup" = {
@ -197,7 +187,16 @@ in {
chroot = false; chroot = false;
maxproc = 0; maxproc = 0;
command = "cleanup"; command = "cleanup";
args = ["-o" "header_checks=pcre:${submissionHeaderCleanupRules}"]; args = let
submissionHeaderCleanupRules = toFile "submission_header_cleanup_rules" ''
/^Received:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^User-Agent:/ IGNORE
/^X-Enigmail:/ IGNORE
/^Message-ID:\s+<(.*?)@.*?>/ REPLACE Message-ID: <$1@${mailConfig.fqdn}>
'';
in ["-o" "header_checks=pcre:${submissionHeaderCleanupRules}"];
}; };
}; };
}; };

View file

@ -3,16 +3,17 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
mailConfig = config.services.mailserver;
postfixCfg = config.services.postfix;
rspamdCfg = config.services.rspamd; rspamdCfg = config.services.rspamd;
rspamdSocket = "rspamd.service"; rspamdSocket = "rspamd.service";
in { in {
config = lib.mkIf (mail_config.enable) { config = mkIf (mailConfig.enable && mailConfig.rspamd.enable) {
services.rspamd = { services.rspamd = {
enable = true; enable = true;
debug = mail_config.debug_mode; debug = mailConfig.debugMode;
locals = { locals = {
"milter_headers.conf" = { "milter_headers.conf" = {
text = '' text = ''
@ -21,7 +22,7 @@ in {
}; };
"redis.conf" = { "redis.conf" = {
text = '' text = ''
servers = "127.0.0.1:${toString mail_config.rspamd_redis_port}"; servers = "127.0.0.1:${toString mailConfig.rspamd.redisPort}";
''; '';
}; };
"classifier-bayes.conf" = { "classifier-bayes.conf" = {
@ -82,7 +83,7 @@ in {
services.redis.servers.rspamd = { services.redis.servers.rspamd = {
enable = true; enable = true;
port = mail_config.rspamd_redis_port; port = mailConfig.rspamd.redisPort;
}; };
systemd.services.rspamd = { systemd.services.rspamd = {
@ -95,6 +96,6 @@ in {
requires = [rspamdSocket]; requires = [rspamdSocket];
}; };
users.extraUsers.${postfixCfg.user}.extraGroups = [rspamdCfg.group]; users.extraUsers.postfix.extraGroups = [rspamdCfg.group];
}; };
} }

View file

@ -3,22 +3,24 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
mailConfig = config.services.mailserver;
acmeRoot = "/var/lib/acme/acme-challenge"; acmeRoot = "/var/lib/acme/acme-challenge";
in { in {
config = lib.mkIf (mail_config.enable && mail_config.ssl_config.useACME) { config = mkIf (mailConfig.enable && mailConfig.sslConfig.useACME) {
services.nginx = { services.nginx = {
enable = true; enable = true;
virtualHosts."${mail_config.fqdn}" = { virtualHosts."${mailConfig.fqdn}" = {
serverName = mail_config.fqdn; serverName = mailConfig.fqdn;
serverAliases = mail_config.domains; serverAliases = mailConfig.domains;
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
acmeRoot = acmeRoot; acmeRoot = acmeRoot;
}; };
}; };
security.acme.certs."${mail_config.fqdn}" = { security.acme.certs."${mailConfig.fqdn}" = {
reloadServices = ["postfix.service" "dovecot2.service"]; reloadServices = ["postfix.service" "dovecot2.service"];
}; };
}; };

View file

@ -4,70 +4,68 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf;
inherit (lib.strings) concatStringsSep;
inherit (lib.attrsets) mapAttrsToList;
vmail_config = mail_config.vmail_config; mailConfig = config.services.mailserver;
vmail_user = vmail_config.user;
vmail_group = vmail_config.group;
sieve_directory = mail_config.sieve_directory; vmail = mailConfig.vmail;
vmailUser = vmail.user;
vmailGroup = vmail.group;
sieveDirectory = mailConfig.sieveDirectory;
scriptForUser = name: config:
if builtins.isString config.sieveScript
then ''
cat ${builtins.toFile "default.sieve" config.sieveScript} > "${sieveDirectory}/${name}/default.sieve"
chown "${vmailUser}:${vmailGroup}" "${sieveDirectory}/${name}/default.sieve"
''
else ''
if [ -f "${sieveDirectory}/${name}/default.sieve" ]; then
rm "${sieveDirectory}/${name}/default.sieve"
fi
if [ -f "${sieveDirectory}/${name}.svbin" ]; then
rm "${sieveDirectory}/${name}/default.svbin"
fi
'';
virtualMailUsersActivationScript = pkgs.writeScript "activate-virtual-mail-users" '' virtualMailUsersActivationScript = pkgs.writeScript "activate-virtual-mail-users" ''
#!${pkgs.stdenv.shell} #!${pkgs.stdenv.shell}
set -euo pipefail set -euo pipefail
# Create directory to store user sieve scripts if it doesn't exist ${concatStringsSep "\n" (mapAttrsToList (name: config: scriptForUser name config) mailConfig.accounts)}
if (! test -d "${sieve_directory}"); then
mkdir "${sieve_directory}"
chown "${vmail_user}:${vmail_group}" "${sieve_directory}"
chmod 770 "${sieve_directory}"
fi
# Copy user's sieve script to the correct location (if it exists). If it
# is null, remove the file.
${lib.concatMapStringsSep "\n" ({
name,
sieveScript,
}:
if lib.isString sieveScript
then ''
if (! test -d "${sieve_directory}/${name}"); then
mkdir -p "${sieve_directory}/${name}"
chown "${vmail_user}:${vmail_group}" "${sieve_directory}/${name}"
chmod 770 "${sieve_directory}/${name}"
fi
cat << 'EOF' > "${sieve_directory}/${name}/default.sieve"
${sieveScript}
EOF
chown "${vmail_user}:${vmail_group}" "${sieve_directory}/${name}/default.sieve"
''
else ''
if (test -f "${sieve_directory}/${name}/default.sieve"); then
rm "${sieve_directory}/${name}/default.sieve"
fi
if (test -f "${sieve_directory}/${name}.svbin"); then
rm "${sieve_directory}/${name}/default.svbin"
fi
'') (map (user: {inherit (user) name sieveScript;})
(lib.attrValues mail_config.accounts))}
''; '';
in { in {
config = lib.mkIf (mail_config.enable) { config = mkIf (mailConfig.enable) {
users.users."${vmail_user}" = { users.users."${vmailUser}" = {
isSystemUser = true; isSystemUser = true;
home = vmail_config.directory; home = vmail.directory;
createHome = true; createHome = true;
uid = vmail_config.user_id; uid = vmail.userID;
group = "${vmail_group}"; group = "${vmailGroup}";
}; };
users.groups."${vmail_group}" = {gid = vmail_config.group_id;};
users.groups."${vmailGroup}" = {
gid = vmail.groupID;
};
systemd.tmpfiles.rules =
[
"d '${sieveDirectory}' - ${vmailUser} ${vmailGroup} - -"
]
++ (map (
email: "d '${sieveDirectory}/${email}' 770 ${vmailUser} ${vmailGroup} - -"
) (builtins.attrNames mailConfig.accounts));
systemd.services.activate-virtual-mail-users = { systemd.services.activate-virtual-mail-users = {
wantedBy = ["multi-user.target"]; wantedBy = ["multi-user.target"];
before = ["dovecot2.service"]; before = ["dovecot2.service"];
serviceConfig = {ExecStart = virtualMailUsersActivationScript;}; serviceConfig.ExecStart = virtualMailUsersActivationScript;
enable = true; enable = true;
}; };
}; };

View file

@ -3,25 +3,32 @@
lib, lib,
... ...
}: let }: let
mail_config = config.services.mailserver; inherit (lib.modules) mkIf mkForce;
mailConfig = config.services.mailserver;
in { in {
config = lib.mkIf (mail_config.enable && mail_config.enable_roundcube) { config = mkIf (mailConfig.enable && mailConfig.roundcube.enable) {
services.roundcube = { services.roundcube = {
enable = true; enable = true;
hostName = "${mail_config.roundcube_url}"; package = mailConfig.roundcube.package;
plugins =
mailConfig.roundcube.plugins
++ [
"managesieve"
];
hostName = "${mailConfig.roundcube.domain}";
extraConfig = '' extraConfig = ''
$config['smtp_server'] = "tls://${mail_config.fqdn}"; $config['smtp_server'] = "tls://${mailConfig.fqdn}";
$config['smtp_user'] = "%u"; $config['smtp_user'] = "%u";
$config['smtp_pass'] = "%p"; $config['smtp_pass'] = "%p";
$config['plugins'] = ["managesieve"]; $config['managesieve_host'] = 'tls://${mailConfig.fqdn}';
$config['managesieve_host'] = 'tls://${mail_config.fqdn}'; ${mailConfig.roundcube.extraConfig}
${mail_config.extra_roundcube_config}
''; '';
}; };
services.nginx.virtualHosts."${mail_config.roundcube_url}" = { services.nginx.virtualHosts."${mailConfig.roundcube.domain}" = {
forceSSL = mail_config.force_roundcube_ssl; forceSSL = mkForce mailConfig.roundcube.forceSSL;
enableACME = mail_config.force_roundcube_acme; enableACME = mkForce mailConfig.roundcube.enableACME;
}; };
}; };
} }

View file

@ -1,63 +1,67 @@
{ {
pkgs, pkgs,
host_secrets, hostSecrets,
... ...
}: let }: let
secrets = host_secrets; secrets = hostSecrets;
in { in {
services.mailserver = { services.mailserver = {
enable = true; enable = true;
fqdn = "mail.owo.monster"; fqdn = "mail.owo.monster";
domains = ["owo.monster"]; domains = ["owo.monster"];
debugMode = true;
ssl_config = { sslConfig = {
useACME = false; useACME = false;
cert = "/var/lib/acme/mail.owo.monster/fullchain.pem"; cert = "/var/lib/acme/mail.owo.monster/fullchain.pem";
key = "/var/lib/acme/mail.owo.monster/key.pem"; key = "/var/lib/acme/mail.owo.monster/key.pem";
}; };
enable_roundcube = true; rspamd.enable = true;
force_roundcube_ssl = false; spf.enable = false;
force_roundcube_acme = false;
debug_mode = true;
extra_roundcube_config = ''
$config['session_lifetime'] = (60 * 24 * 7 * 2); # 2 Weeks
$config['product_name'] = 'Chaos Mail';
$config['username_domain'] = "owo.monster";
$config['username_domain_forced'] = true;
$config['log_driver'] = 'syslog';
$config['smtp_debug'] = true;
'';
extra_aliases_file = "${secrets.private_mail_aliases.path}";
accounts = { accounts = {
"chaos@owo.monster" = { "chaos@owo.monster" = {
name = "chaos@owo.monster"; passwordHashFile = "${secrets.chaos_mail_passwd.path}";
passwordFile = "${secrets.chaos_mail_passwd.path}";
aliases = [ aliases = [
"all@owo.monster" "all@owo.monster"
"chaoticryptidz@owo.monster" "chaoticryptidz@owo.monster"
]; ];
sieveScript = null;
}; };
"system@owo.monster" = { "system@owo.monster" = {
name = "system@owo.monster"; passwordHashFile = "${secrets.system_mail_passwd.path}";
passwordFile = "${secrets.system_mail_passwd.path}";
aliases = [];
sieveScript = null;
}; };
"gotosocial@owo.monster" = { "gotosocial@owo.monster" = {
name = "gotosocial@owo.monster"; passwordHashFile = "${secrets.gotosocial_mail_passwd.path}";
passwordFile = "${secrets.gotosocial_mail_passwd.path}";
aliases = [];
sieveScript = null;
}; };
}; };
extraAliasesFile = "${secrets.private_mail_aliases.path}";
roundcube = {
enable = true;
package = pkgs.roundcube.withPlugins (_plugins:
with pkgs.roundcubePlugins; [
persistent_login
]);
plugins = ["persistent_login"];
# running in container, passing socket to host
forceSSL = false;
enableACME = false;
extraConfig = ''
$config['session_lifetime'] = (60 * 24 * 7 * 2); # 2 Weeks
$config['product_name'] = 'Chaos Mail';
$config['username_domain'] = "owo.monster";
$config['username_domain_forced'] = true;
$config['log_driver'] = 'syslog';
$config['smtp_debug'] = true;
'';
};
}; };
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
@ -68,15 +72,9 @@ in {
"/var/sockets" "/var/sockets"
]; ];
services.roundcube = {
package = pkgs.roundcube.withPlugins (_plugins:
with pkgs.roundcubePlugins; [
persistent_login
]);
plugins = ["persistent_login"];
};
services.nginx.virtualHosts."mail.owo.monster" = { services.nginx.virtualHosts."mail.owo.monster" = {
# running in privateNetwork
# required so nginx doesn't try listening on port 80
listen = [ listen = [
{ {
addr = "127.0.0.1"; addr = "127.0.0.1";

View file

@ -1,11 +1,11 @@
{ {
pkgs, pkgs,
config, config,
host_secrets, hostSecrets,
... ...
}: let }: let
secrets = host_secrets; secrets = hostSecrets;
mail_config = config.services.mailserver; mailConfig = config.services.mailserver;
backupPrepareCommand = "${ backupPrepareCommand = "${
(pkgs.writeShellScriptBin "backupPrepareCommand" '' (pkgs.writeShellScriptBin "backupPrepareCommand" ''
systemctl start postgresqlBackup-roundcube --wait systemctl start postgresqlBackup-roundcube --wait
@ -27,9 +27,9 @@ in {
paths = [ paths = [
"/var/backup/postgresql" "/var/backup/postgresql"
mail_config.vmail_config.directory mailConfig.vmail.directory
mail_config.sieve_directory mailConfig.sieveDirectory
mail_config.dkim_directory mailConfig.dkim.directory
"/var/lib/redis-rspamd" "/var/lib/redis-rspamd"
]; ];

View file

@ -1,4 +1,4 @@
{}: { {
mpd = 6600; mpd = 6600;
mpd-opus-low = 4242; mpd-opus-low = 4242;
mpd-opus-medium = 4243; mpd-opus-medium = 4243;

View file

@ -1,4 +1,6 @@
{ {
self,
hostPath,
tree, tree,
lib, lib,
inputs, inputs,
@ -6,46 +8,43 @@
pkgs, pkgs,
... ...
}: let }: let
container-addresses = import ../../data/container-addresses.nix {}; inherit (lib.modules) mkMerge;
hostIP = container-addresses.host; inherit (lib.lists) forEach;
containerIP = container-addresses.containers.music;
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = containerAddresses.host;
containerIP = containerAddresses.containers.${containerName};
containerName = "music";
containerConfig = config.containers.${containerName}.config;
containerLib = import "${self}/lib/containerLib.nix" {
inherit lib;
};
# Using secrets from Host # Using secrets from Host
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
secretsList = [
ports = import ./data/ports.nix {}; "mpd_control_password"
in { "slskd_env"
networking.nat.forwardPorts = [
{
sourcePort = ports.mpd;
destination = "${containerIP}\:${toString ports.mpd}";
}
{
sourcePort = ports.slskd;
destination = "${containerIP}\:${toString ports.slskd}";
}
]; ];
ports = import ./data/ports.nix;
in {
containers.music = { containers.music = {
autoStart = true; autoStart = true;
privateNetwork = true; privateNetwork = true;
hostAddress = hostIP; hostAddress = hostIP;
localAddress = containerIP; localAddress = containerIP;
bindMounts = lib.mkMerge (lib.forEach [ bindMounts = containerLib.genBindHostsForSecrets secrets secretsList;
"mpd_control_password"
"slskd_env"
] (secret_name: let
path = "${secrets.${secret_name}.path}";
in {
"${path}" = {
hostPath = "${path}";
};
}));
specialArgs = { specialArgs = {
inherit inputs; inherit inputs;
inherit tree; inherit tree;
host_secrets = secrets; inherit self;
inherit hostPath;
hostSecrets = secrets;
}; };
config = {config, ...}: { config = {config, ...}: {
@ -53,40 +52,35 @@ in {
imports = with tree; imports = with tree;
[ [
profiles.base presets.nixos.containerBase
inputs.home-manager-unstable.nixosModules.home-manager
profiles.sshd profiles.sshd
profiles.firewallAllow.ssh
profiles.nginx profiles.nginx
profiles.firewallAllow.httpCommon
modules.nixos.secrets
users.root
] ]
++ (with hosts.hetzner-vm.containers.music; [ ++ (with hosts.hetzner-vm.containers.music; [
profiles.music-sync
profiles.mpd profiles.mpd
profiles.musicSync
profiles.soulseek profiles.soulseek
]); ]);
networking.firewall.allowedTCPPorts = with ports; [
mpd
mpd-opus-low
mpd-opus-medium
mpd-opus-high
mpd-flac
slskd
slskd-web
];
# For Shared Secrets # For Shared Secrets
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d ${config.services.secrets.secretsDir} - root root" "d ${config.services.secrets.secretsDir} - root root"
]; ];
networking.firewall = { home-manager.users.root.home.stateVersion = "23.05";
enable = true;
allowedTCPPorts = [22] ++ lib.mapAttrsToList (_name: value: value) ports;
};
home-manager.users.root = {
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
# Manually configure nameserver. Using resolved inside the container seems to fail
# currently
environment.etc."resolv.conf".text = "nameserver 8.8.8.8";
system.stateVersion = "23.05"; system.stateVersion = "23.05";
}; };
}; };
@ -108,7 +102,7 @@ in {
in { in {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;
locations = lib.mkMerge ([ locations = mkMerge ([
{ {
"/mpd/flac" = { "/mpd/flac" = {
proxyPass = "http://${containerIP}:${toString ports.mpd-flac}"; proxyPass = "http://${containerIP}:${toString ports.mpd-flac}";
@ -116,7 +110,7 @@ in {
}; };
} }
] ]
++ (lib.forEach ["low" "medium" "high"] (quality: { ++ (forEach ["low" "medium" "high"] (quality: {
"/mpd/opus-${quality}" = { "/mpd/opus-${quality}" = {
proxyPass = "http://${containerIP}:${toString ports."mpd-opus-${quality}"}"; proxyPass = "http://${containerIP}:${toString ports."mpd-opus-${quality}"}";
inherit extraConfig; inherit extraConfig;
@ -126,15 +120,28 @@ in {
# For permissions of secrets # For permissions of secrets
users.users."mpd" = { users.users."mpd" = {
uid = config.ids.uids.mpd; uid = containerConfig.ids.uids.mpd;
group = "mpd"; group = "mpd";
}; };
users.groups."mpd" = { users.groups."mpd" = {
gid = config.ids.gids.mpd; gid = containerConfig.ids.gids.mpd;
}; };
networking.firewall.allowedTCPPorts = with ports; [ networking = {
mpd nat.forwardPorts = [
slskd {
]; sourcePort = ports.mpd;
destination = "${containerIP}\:${toString ports.mpd}";
}
{
sourcePort = ports.slskd;
destination = "${containerIP}\:${toString ports.slskd}";
}
];
firewall.allowedTCPPorts = with ports; [
mpd
slskd
];
};
} }

View file

@ -1,13 +1,18 @@
{ {
lib, lib,
pkgs, pkgs,
host_secrets, hostSecrets,
... ...
}: let }: let
ports = import ../data/ports.nix {}; inherit (lib.strings) concatStringsSep;
secrets = host_secrets; inherit (lib.lists) forEach;
ports = import ../data/ports.nix;
secrets = hostSecrets;
in { in {
environment.systemPackages = with pkgs; [mpc_cli]; environment.systemPackages = with pkgs; [
mpc_cli
];
services.mpd = { services.mpd = {
enable = true; enable = true;
@ -29,7 +34,7 @@ in {
replaygain "track" replaygain "track"
audio_output_format "44100:16:2" audio_output_format "44100:16:2"
'' ''
+ lib.concatStringsSep "\n" (lib.forEach ["low" "medium" "high"] (quality: let + concatStringsSep "\n" (forEach ["low" "medium" "high"] (quality: let
bitrates = { bitrates = {
"low" = "64"; "low" = "64";
"medium" = "96"; "medium" = "96";

View file

@ -1,4 +1,20 @@
{pkgs, ...}: { {pkgs, ...}: let
inherit (pkgs) writeShellScriptBin;
inherit (builtins) toFile;
rcloneConfig = toFile "rclone.conf" ''
[Music]
type = webdav
url = https://storage-webdav.owo.monster/MusicRO/
vendor = other
'';
in {
environment.systemPackages = [
(writeShellScriptBin "rclone-music" ''
rclone --config ${rcloneConfig} "$@"
'')
];
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /Music - mpd mpd" "d /Music - mpd mpd"
]; ];
@ -8,17 +24,11 @@
after = ["network.target"]; after = ["network.target"];
partOf = ["mpd.service"]; partOf = ["mpd.service"];
path = with pkgs; [bash rclone mount umount]; path = with pkgs; [bash rclone];
script = let
rclone_config = pkgs.writeText "rclone.conf" '' script = ''
[Music]
type = webdav
url = https://storage-webdav.owo.monster/MusicRO/
vendor = other
'';
in ''
set -e set -e
rclone --config ${rclone_config} sync Music: /Music rclone --config ${rcloneConfig} sync Music: /Music
chown -R mpd:mpd /Music chown -R mpd:mpd /Music
''; '';
}; };

View file

@ -1,10 +1,10 @@
{ {
lib, lib,
host_secrets, hostSecrets,
... ...
}: let }: let
ports = import ../data/ports.nix {}; ports = import ../data/ports.nix;
secrets = host_secrets; secrets = hostSecrets;
inherit (lib.modules) mkForce; inherit (lib.modules) mkForce;
in { in {

View file

@ -1,6 +1,6 @@
{}: { {
piped-backend = 3012; internal-piped-backend = 3012;
piped-proxy = 3013; internal-piped-proxy = 3013;
cockroachdb = 26257; cockroachdb = 26257;
cockroachdb-http = 3014; cockroachdb-http = 3014;

View file

@ -1,4 +1,6 @@
{ {
self,
hostPath,
tree, tree,
lib, lib,
inputs, inputs,
@ -6,18 +8,23 @@
pkgs, pkgs,
... ...
}: let }: let
#container-addresses = import ../../data/container-addresses.nix {}; containerAddresses = import "${hostPath}/data/containerAddresses.nix";
#hostIP = container-addresses.host;
#containerIP = container-addresses.containers.piped;
containerConfig = config.containers.piped.config;
ports = import ./data/ports.nix {}; hostIP = containerAddresses.host;
containerIP = containerAddresses.containers.${containerName};
containerName = "piped";
containerConfig = config.containers.${containerName}.config;
containerLib = import "${self}/lib/containerLib.nix" {
inherit lib;
};
# Using secrets from Host # Using secrets from Host
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
secrets_list = [ secretsList = [
"piped_restic_env" "piped_finland_restic_env"
"piped_restic_password" "piped_finland_restic_password"
{ {
name = "piped_cockroachdb_ca_certificate"; name = "piped_cockroachdb_ca_certificate";
path = "/var/lib/cockroachdb-certs/ca.crt"; path = "/var/lib/cockroachdb-certs/ca.crt";
@ -32,11 +39,51 @@
} }
]; ];
containerName = "piped";
pipedSocketForComponent = ( pipedSocketForComponent = (
component: "/var/lib/nixos-containers/${containerName}/var/sockets/piped-${component}.sock" component: "/var/lib/nixos-containers/${containerName}/var/sockets/piped-${component}.sock"
); );
in { in {
containers.piped = {
autoStart = true;
privateNetwork = false;
hostAddress = hostIP;
localAddress = containerIP;
bindMounts = containerLib.genBindHostsForSecrets secrets secretsList;
specialArgs = {
inherit inputs;
inherit tree;
inherit self;
inherit hostPath;
hostSecrets = secrets;
};
config = {config, ...}: {
nixpkgs.pkgs = pkgs;
imports = with tree;
[
presets.nixos.containerBase
profiles.nginx
profiles.firewallAllow.httpCommon
]
++ (with hosts.hetzner-vm.containers.piped.profiles; [
piped
restic
cockroachDB
]);
# For Shared Secrets
systemd.tmpfiles.rules = [
"d ${config.services.secrets.secretsDir} - root root"
];
home-manager.users.root.home.stateVersion = "23.05";
system.stateVersion = "23.05";
};
};
# Create this directory outside the container so the bind mounts work # Create this directory outside the container so the bind mounts work
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /var/lib/nixos-containers/${containerName}/var/lib/cockroachdb-certs - root root" "d /var/lib/nixos-containers/${containerName}/var/lib/cockroachdb-certs - root root"
@ -50,81 +97,6 @@ in {
gid = containerConfig.users.groups.cockroachdb.gid; gid = containerConfig.users.groups.cockroachdb.gid;
}; };
containers.piped = {
autoStart = true;
#privateNetwork = false;
#hostAddress = hostIP;
#localAddress = containerIP;
bindMounts = lib.mkMerge (lib.forEach secrets_list (secret_item: let
secret =
if builtins.isString secret_item
then secrets.${secret_item}
else secrets.${secret_item.name};
hostPath = secret.path;
containerPath =
if builtins.isString secret_item
then hostPath
else secret_item.path;
in {
"${containerPath}" = {
inherit hostPath;
};
}));
specialArgs = {
inherit inputs;
inherit tree;
host_secrets = secrets;
};
config = {config, ...}: {
nixpkgs.pkgs = pkgs;
imports = with tree;
[
profiles.base
inputs.home-manager-unstable.nixosModules.home-manager
#profiles.sshd
profiles.nginx
profiles.cockroachdb-bin-fix
modules.nixos.secrets
inputs.piped-flake.nixosModules.default
users.root
]
++ (with hosts.hetzner-vm.containers.piped.profiles; [
piped
restic
cockroachdb
]);
# For Shared Secrets
systemd.tmpfiles.rules = [
"d ${config.services.secrets.secretsDir} - root root"
];
networking.firewall = {
enable = true;
allowedTCPPorts = [22] ++ (lib.attrValues ports);
};
home-manager.users.root = {
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
# Manually configure nameserver. Using resolved inside the container seems to fail
# currently
environment.etc."resolv.conf".text = "nameserver 8.8.8.8";
system.stateVersion = "23.05";
};
};
services.nginx.virtualHosts."piped-fi.owo.monster" = { services.nginx.virtualHosts."piped-fi.owo.monster" = {
forceSSL = true; forceSSL = true;
enableACME = true; enableACME = true;

View file

@ -0,0 +1,20 @@
{self, ...}: let
internalWireGuard = import "${self}/data/chaosInternalWireGuard.nix";
ports = import ../data/ports.nix;
in {
services.cockroachdb-bin = {
enable = true;
certsDir = "/var/lib/cockroachdb-certs";
join = "localhost:${toString ports.cockroachdb},${internalWireGuard.hosts.raspberry.ip}:26257";
# ssh -L 3014:127.0.0.1:3014 -L 26257:127.0.0.1:26257 raspberry
extraArgs = ["--advertise-addr=${internalWireGuard.hosts.hetzner-vm.ip}:26257"];
listen = {
port = ports.cockroachdb;
address = "0.0.0.0";
};
http = {
address = "0.0.0.0";
port = ports.cockroachdb-http;
};
};
}

View file

@ -1,16 +0,0 @@
{...}: let
ports = import ../data/ports.nix {};
internal_wireguard = import ../../../../../data/chaos_wireguard_internal.nix {};
in {
services.cockroachdb = {
enable = true;
certsDir = "/var/lib/cockroachdb-certs";
join = "localhost:${toString ports.cockroachdb},${internal_wireguard.hosts.raspberry.ip}:26257";
# ssh -L 3014:127.0.0.1:3014 -L 26257:127.0.0.1:26257 hetzner-vm
listen.port = ports.cockroachdb;
http = {
address = "0.0.0.0";
port = ports.cockroachdb-http;
};
};
}

View file

@ -1,15 +1,16 @@
{config, ...}: let {config, ...}: let
ports = import ../data/ports.nix {}; ports = import ../data/ports.nix;
piped_config = config.services.piped; pipedConfig = config.services.piped;
in { in {
config.services.piped = { services.piped = {
enable = true; enable = true;
frontendDomain = "piped-fi.owo.monster"; frontendDomain = "piped-fi.owo.monster";
backendDomain = "backend.piped-fi.owo.monster"; backendDomain = "backend.piped-fi.owo.monster";
proxyDomain = "proxy.piped-fi.owo.monster"; proxyDomain = "proxy.piped-fi.owo.monster";
disableRegistrations = false; disableRegistrations = true;
# TODO: change these creds to be read from file before opening DB to firewall
postgresDBName = "piped"; postgresDBName = "piped";
postgresDBUsername = "piped"; postgresDBUsername = "piped";
postgresDBPassword = "piped"; postgresDBPassword = "piped";
@ -23,43 +24,54 @@ in {
# Do not set proxyNginxExtraConfig here as needs be set in outside of container # Do not set proxyNginxExtraConfig here as needs be set in outside of container
internalBackendPort = ports.piped-backend; internalBackendPort = ports.internal-piped-backend;
internalProxyPort = ports.piped-proxy; internalProxyPort = ports.internal-piped-proxy;
}; };
config.systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /var/sockets - nginx nginx" "d /var/sockets - nginx nginx"
]; ];
config.systemd.services.nginx.serviceConfig.ReadWritePaths = [ systemd.services.nginx = {
"/var/sockets" serviceConfig.ReadWritePaths = [
]; "/var/sockets"
];
};
config.services.nginx.virtualHosts."${piped_config.frontendDomain}" = { systemd.services.piped-backend = {
extraConfig = "listen unix:/var/sockets/piped-frontend.sock;"; after = ["cockroachdb.service"];
listen = [ wants = ["cockroachdb.service"];
{
addr = "127.0.0.1";
port = 9080;
}
];
}; };
config.services.nginx.virtualHosts."${piped_config.backendDomain}" = {
extraConfig = "listen unix:/var/sockets/piped-backend.sock;"; services.nginx.virtualHosts = let
listen = [ componentPath = component: "/var/sockets/piped-${component}.sock";
{ in {
addr = "127.0.0.1"; "${pipedConfig.frontendDomain}" = {
port = 9080; listen = [
} {
]; addr = "127.0.0.1";
}; port = 8091;
config.services.nginx.virtualHosts."${piped_config.proxyDomain}" = { }
extraConfig = "listen unix:/var/sockets/piped-proxy.sock;"; ];
listen = [ extraConfig = "listen unix:${componentPath "frontend"};";
{ };
addr = "127.0.0.1"; "${pipedConfig.backendDomain}" = {
port = 9080; extraConfig = "listen unix:${componentPath "backend"};";
} listen = [
]; {
addr = "127.0.0.1";
port = 8092;
}
];
};
"${pipedConfig.proxyDomain}" = {
extraConfig = "listen unix:${componentPath "proxy"};";
listen = [
{
addr = "127.0.0.1";
port = 8093;
}
];
};
}; };
} }

View file

@ -1,36 +1,32 @@
{ {
pkgs, pkgs,
host_secrets, hostSecrets,
... ...
}: let }: let
secrets = host_secrets; secrets = hostSecrets;
#backupPrepareCommand = "${
# (pkgs.writeShellScriptBin "backupPrepareCommand" ''
# systemctl start postgresqlBackup-piped --wait
# '')
#}/bin/backupPrepareCommand";
in { in {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
restic restic
(pkgs.writeShellScriptBin "restic-piped" '' (pkgs.writeShellScriptBin "restic-piped-finland" ''
env \ env \
RESTIC_PASSWORD_FILE=${secrets.piped_restic_password.path} \ RESTIC_PASSWORD_FILE=${secrets.piped_finland_restic_password.path} \
$(cat ${secrets.piped_restic_env.path}) \ $(cat ${secrets.piped_finland_restic_env.path}) \
${pkgs.restic}/bin/restic $@ ${pkgs.restic}/bin/restic $@
'') '')
]; ];
services.restic.backups.piped = { services.restic.backups.piped-finland = {
user = "root"; user = "root";
paths = [ paths = [
#"/var/backup/postgresql" "/var/lib/cockroachdb"
"/var/lib/cockroachdb-certs"
]; ];
# repository is overrided in environmentFile to contain auth # repository is overrided in environmentFile to contain auth
# make sure to keep up to date when changing repository # make sure to keep up to date when changing repository
repository = "rest:https://storage-restic.owo.monster/Piped"; repository = "rest:https://storage-restic.owo.monster/Piped-Finland";
passwordFile = "${secrets.piped_restic_password.path}"; passwordFile = "${secrets.piped_finland_restic_password.path}";
environmentFile = "${secrets.piped_restic_env.path}"; environmentFile = "${secrets.piped_finland_restic_env.path}";
pruneOpts = [ pruneOpts = [
"--keep-last 5" "--keep-last 5"
@ -40,14 +36,5 @@ in {
OnBootSec = "1m"; OnBootSec = "1m";
OnCalendar = "daily"; OnCalendar = "daily";
}; };
#inherit backupPrepareCommand;
}; };
#services.postgresqlBackup = {
# enable = true;
# backupAll = false;
# databases = ["piped"];
# compression = "zstd";
#};
} }

View file

@ -1,4 +1,6 @@
{ {
self,
hostPath,
tree, tree,
lib, lib,
inputs, inputs,
@ -6,41 +8,34 @@
pkgs, pkgs,
... ...
}: let }: let
container-addresses = import ../../data/container-addresses.nix {}; containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = container-addresses.host; hostIP = containerAddresses.host;
containerIP = container-addresses.containers.quassel; containerIP = containerAddresses.containers.quassel;
containerLib = import "${self}/lib/containerLib.nix" {
inherit lib;
};
# Using secrets from Host # Using secrets from Host
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
secrets_list = [ secretsList = [
"quassel_restic_env" "quassel_restic_env"
"quassel_restic_password" "quassel_restic_password"
]; ];
in { in {
networking.nat.forwardPorts = [
{
sourcePort = 4242;
destination = "${containerIP}\:4242";
}
];
containers.quassel = { containers.quassel = {
autoStart = true; autoStart = true;
privateNetwork = true; privateNetwork = true;
hostAddress = hostIP; hostAddress = hostIP;
localAddress = containerIP; localAddress = containerIP;
bindMounts = lib.mkMerge (lib.forEach secrets_list (secret_name: let bindMounts = containerLib.genBindHostsForSecrets secrets secretsList;
path = "${secrets.${secret_name}.path}";
in {
"${path}" = {
hostPath = "${path}";
};
}));
specialArgs = { specialArgs = {
inherit inputs; inherit inputs;
inherit tree; inherit tree;
host_secrets = secrets; inherit self;
inherit hostPath;
hostSecrets = secrets;
}; };
config = {config, ...}: { config = {config, ...}: {
@ -48,18 +43,13 @@ in {
imports = with tree; imports = with tree;
[ [
profiles.base presets.nixos.containerBase
inputs.home-manager-unstable.nixosModules.home-manager
profiles.sshd profiles.sshd
profiles.firewallAllow.ssh
modules.nixos.secrets
users.root
] ]
++ (with hosts.hetzner-vm.containers.quassel; [ ++ (with hosts.hetzner-vm.containers.quassel.profiles; [
profiles.quassel quassel
profiles.restic restic
]); ]);
# For Shared Secrets # For Shared Secrets
@ -67,23 +57,19 @@ in {
"d ${config.services.secrets.secretsDir} - root root" "d ${config.services.secrets.secretsDir} - root root"
]; ];
networking.firewall = { networking.firewall.allowedTCPPorts = [4242];
enable = true;
allowedTCPPorts = [22 4242];
};
home-manager.users.root = { home-manager.users.root.home.stateVersion = "23.05";
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
# Manually configure nameserver. Using resolved inside the container seems to fail
# currently
environment.etc."resolv.conf".text = "nameserver 8.8.8.8";
system.stateVersion = "23.05"; system.stateVersion = "23.05";
}; };
}; };
networking.nat.forwardPorts = [
{
sourcePort = 4242;
destination = "${containerIP}\:4242";
}
];
networking.firewall.allowedTCPPorts = [4242]; networking.firewall.allowedTCPPorts = [4242];
} }

View file

@ -4,15 +4,16 @@
interfaces = ["0.0.0.0"]; interfaces = ["0.0.0.0"];
}; };
services.postgresql.enable = true; services.postgresql = {
services.postgresql.ensureDatabases = ["quassel"]; enable = true;
services.postgresql.ensureUsers = [ ensureDatabases = ["quassel"];
{ ensureUsers = [
name = "quassel"; {
ensurePermissions."DATABASE quassel" = "ALL PRIVILEGES"; name = "quassel";
} ensurePermissions."DATABASE quassel" = "ALL PRIVILEGES";
]; }
];
services.postgresql.authentication = "host quassel quassel localhost trust"; authentication = "host quassel quassel localhost trust";
networking.firewall.allowedTCPPorts = [4242]; };
} }

View file

@ -1,9 +1,9 @@
{ {
pkgs, pkgs,
host_secrets, hostSecrets,
... ...
}: let }: let
secrets = host_secrets; secrets = hostSecrets;
backupPrepareCommand = "${ backupPrepareCommand = "${
(pkgs.writeShellScriptBin "backupPrepareCommand" '' (pkgs.writeShellScriptBin "backupPrepareCommand" ''

View file

@ -1,13 +1,15 @@
{ {
self,
hostPath,
tree, tree,
inputs, inputs,
config, config,
pkgs, pkgs,
... ...
}: let }: let
container-addresses = import ../../data/container-addresses.nix {}; containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = container-addresses.host; hostIP = containerAddresses.host;
containerIP = container-addresses.containers.social; containerIP = containerAddresses.containers.social;
# Using secrets from Host # Using secrets from Host
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
@ -32,7 +34,9 @@ in {
specialArgs = { specialArgs = {
inherit inputs; inherit inputs;
inherit tree; inherit tree;
host_secrets = secrets; inherit self;
inherit hostPath;
hostSecrets = secrets;
}; };
config = {config, ...}: { config = {config, ...}: {

View file

@ -2,10 +2,13 @@
pkgs, pkgs,
config, config,
lib, lib,
host_secrets, hostSecrets,
... ...
}: let }: let
secrets = host_secrets; inherit (lib.strings) concatStringsSep;
inherit (lib.lists) forEach;
secrets = hostSecrets;
# Because gotosocial-admin isn't a seporate package we need to generate a seperate config # Because gotosocial-admin isn't a seporate package we need to generate a seperate config
# and duplicate the wrapper for use in a systemd unit # and duplicate the wrapper for use in a systemd unit
@ -22,8 +25,8 @@
backupPrepareCommand = "${ backupPrepareCommand = "${
(pkgs.writeShellScriptBin "backupPrepareCommand" '' (pkgs.writeShellScriptBin "backupPrepareCommand" ''
systemctl start ${ systemctl start ${
lib.concatStringsSep " " concatStringsSep " "
(lib.forEach config.services.postgresqlBackup.databases (forEach config.services.postgresqlBackup.databases
(db: "postgresqlBackup-${db}")) (db: "postgresqlBackup-${db}"))
} --wait } --wait

View file

@ -1,9 +1,13 @@
{host_secrets, ...}: let {
container-addresses = import ../../../data/container-addresses.nix {}; hostPath,
hostIP = container-addresses.host; hostSecrets,
containerIP = container-addresses.containers.social; ...
}: let
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = containerAddresses.host;
containerIP = containerAddresses.containers.social;
secrets = host_secrets; secrets = hostSecrets;
in { in {
services.gotosocial = { services.gotosocial = {
enable = true; enable = true;

View file

@ -1,4 +1,4 @@
{...}: { {
rclone_serve_webdav_main = 4200; rclone_serve_webdav_main = 4200;
rclone_serve_webdav_media = 4201; rclone_serve_webdav_media = 4201;
rclone_serve_webdav_music_ro = 4202; rclone_serve_webdav_music_ro = 4202;
@ -7,7 +7,7 @@
rclone_serve_restic_vault = 4211; rclone_serve_restic_vault = 4211;
rclone_serve_restic_social = 4212; rclone_serve_restic_social = 4212;
rclone_serve_restic_quassel = 4213; rclone_serve_restic_quassel = 4213;
rclone_serve_restic_piped = 4214; rclone_serve_restic_piped_finland = 4214;
rclone_serve_restic_mail = 4215; rclone_serve_restic_mail = 4215;
rclone_serve_http_music = 4220; rclone_serve_http_music = 4220;

View file

@ -1,18 +1,22 @@
{ {
self,
hostPath,
tree, tree,
lib, lib,
inputs, inputs,
pkgs, pkgs,
... ...
}: let }: let
container-addresses = import ../../data/container-addresses.nix {}; inherit (lib.attrsets) attrValues;
hostIP = container-addresses.host;
containerIP = container-addresses.containers.storage; containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = containerAddresses.host;
containerIP = containerAddresses.containers.storage;
# 32GB # 32GB
clientMaxBodySize = "${toString (8192 * 4)}M"; clientMaxBodySize = "${toString (8192 * 4)}M";
ports = import ./data/ports.nix {}; ports = import ./data/ports.nix;
in { in {
containers.storage = { containers.storage = {
autoStart = true; autoStart = true;
@ -23,6 +27,8 @@ in {
specialArgs = { specialArgs = {
inherit inputs; inherit inputs;
inherit tree; inherit tree;
inherit self;
inherit hostPath;
}; };
config = {...}: { config = {...}: {
@ -43,14 +49,11 @@ in {
users.root users.root
] ]
++ (with hosts.hetzner-vm.containers.storage; [ ++ (with hosts.hetzner-vm.containers.storage.profiles; [
profiles.auto-secrets rcloneConfigs
profiles.rclone-configs rcloneServe
profiles.rclone-serve rcloneSync
profiles.rclone-sync users
# doesn't work in container
# profiles.storage-mount
profiles.users
]); ]);
environment.systemPackages = with pkgs; [rclone]; environment.systemPackages = with pkgs; [rclone];
@ -63,7 +66,7 @@ in {
networking.firewall = { networking.firewall = {
enable = true; enable = true;
allowedTCPPorts = [22] ++ lib.mapAttrsToList (_name: value: value) ports; allowedTCPPorts = attrValues ports;
}; };
# Manually configure nameserver. Using resolved inside the container seems to fail # Manually configure nameserver. Using resolved inside the container seems to fail
@ -106,7 +109,7 @@ in {
"/Vault/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_vault}"; "/Vault/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_vault}";
"/Social/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_social}"; "/Social/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_social}";
"/Quassel/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_quassel}"; "/Quassel/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_quassel}";
"/Piped/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_piped}"; "/Piped-Finland/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_piped_finland}";
"/Mail/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_mail}"; "/Mail/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_mail}";
}; };
extraConfig = '' extraConfig = ''

View file

@ -1,21 +0,0 @@
{
pkgs,
config,
...
}: let
secrets = config.services.secrets.secrets;
in {
systemd.services.auto-secrets = {
wantedBy = ["multi-user.target"];
after = ["network.target"];
path = with pkgs; [bash vault-bin getent];
script = let
vault_username = "storage";
vault_password_file = "${secrets.vault_password.path}";
in ''
VAULT_ADDR="https://vault.owo.monster" \
vault login -no-print -method=userpass username=${vault_username} password=$(cat ${vault_password_file})
/run/current-system/sw/bin/secrets-init
'';
};
}

View file

@ -1,6 +1,6 @@
{config, ...}: let {config, ...}: let
secrets = config.services.secrets.secrets; secrets = config.services.secrets.secrets;
ports = import ../data/ports.nix {}; ports = import ../data/ports.nix;
in { in {
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /caches - storage storage" "d /caches - storage storage"
@ -8,16 +8,20 @@ in {
"d /caches/media_webdav_serve - storage storage" "d /caches/media_webdav_serve - storage storage"
]; ];
services.rclone-serve = let services.rclone-serve = {
serviceConfig = {
after = ["auto-secrets.service"];
partOf = ["auto-secrets.service"];
};
in {
enable = true; enable = true;
remotes = [ remotes = map (remote:
{ {
user = "storage"; user = "storage";
serviceConfig = {
after = ["auto-secrets.service"];
wants = ["auto-secrets.service"];
partOf = ["auto-secrets.service"];
};
}
// remote) [
{
id = "main";
remote = "StorageBox:"; remote = "StorageBox:";
type = "webdav"; type = "webdav";
extraArgs = [ extraArgs = [
@ -27,10 +31,9 @@ in {
"--cache-dir=/caches/main_webdav_serve" "--cache-dir=/caches/main_webdav_serve"
"--vfs-cache-mode=full" "--vfs-cache-mode=full"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "media-combine";
remote = "Media-Combine-Serve:"; remote = "Media-Combine-Serve:";
type = "webdav"; type = "webdav";
extraArgs = [ extraArgs = [
@ -42,10 +45,9 @@ in {
"--vfs-cache-max-size=5g" "--vfs-cache-max-size=5g"
"--vfs-cache-mode=full" "--vfs-cache-mode=full"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "music-ro";
remote = "StorageBox:Music"; remote = "StorageBox:Music";
type = "webdav"; type = "webdav";
extraArgs = [ extraArgs = [
@ -53,10 +55,9 @@ in {
"--read-only" "--read-only"
"--baseurl=/MusicRO/" "--baseurl=/MusicRO/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "music-ro";
remote = "StorageBox:Music"; remote = "StorageBox:Music";
type = "http"; type = "http";
extraArgs = [ extraArgs = [
@ -64,10 +65,9 @@ in {
"--baseurl=/Music/" "--baseurl=/Music/"
"--read-only" "--read-only"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "public";
remote = "StorageBox:Public"; remote = "StorageBox:Public";
type = "http"; type = "http";
extraArgs = [ extraArgs = [
@ -75,10 +75,9 @@ in {
"--baseurl=/Public/" "--baseurl=/Public/"
"--read-only" "--read-only"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-music";
remote = "StorageBox:Backups/Restic/Music"; remote = "StorageBox:Backups/Restic/Music";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
@ -86,10 +85,9 @@ in {
"--htpasswd=${secrets.restic_music_htpasswd.path}" "--htpasswd=${secrets.restic_music_htpasswd.path}"
"--baseurl=/Music/" "--baseurl=/Music/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-vault";
remote = "StorageBox:Backups/Restic/Vault"; remote = "StorageBox:Backups/Restic/Vault";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
@ -97,10 +95,9 @@ in {
"--htpasswd=${secrets.restic_vault_htpasswd.path}" "--htpasswd=${secrets.restic_vault_htpasswd.path}"
"--baseurl=/Vault/" "--baseurl=/Vault/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-social";
remote = "StorageBox:Backups/Restic/Social"; remote = "StorageBox:Backups/Restic/Social";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
@ -108,10 +105,9 @@ in {
"--htpasswd=${secrets.restic_social_htpasswd.path}" "--htpasswd=${secrets.restic_social_htpasswd.path}"
"--baseurl=/Social/" "--baseurl=/Social/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-quassel";
remote = "StorageBox:Backups/Restic/Quassel"; remote = "StorageBox:Backups/Restic/Quassel";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
@ -119,21 +115,19 @@ in {
"--htpasswd=${secrets.restic_quassel_htpasswd.path}" "--htpasswd=${secrets.restic_quassel_htpasswd.path}"
"--baseurl=/Quassel/" "--baseurl=/Quassel/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-piped-finland";
remote = "StorageBox:Backups/Restic/Piped"; remote = "StorageBox:Backups/Restic/Piped-Finland";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
"--addr=0.0.0.0:${toString ports.rclone_serve_restic_piped}" "--addr=0.0.0.0:${toString ports.rclone_serve_restic_piped_finland}"
"--htpasswd=${secrets.restic_piped_htpasswd.path}" "--htpasswd=${secrets.restic_piped_finland_htpasswd.path}"
"--baseurl=/Piped/" "--baseurl=/Piped-Finland/"
]; ];
inherit serviceConfig;
} }
{ {
user = "storage"; id = "restic-mail";
remote = "StorageBox:Backups/Restic/Mail"; remote = "StorageBox:Backups/Restic/Mail";
type = "restic"; type = "restic";
extraArgs = [ extraArgs = [
@ -141,7 +135,6 @@ in {
"--htpasswd=${secrets.restic_mail_htpasswd.path}" "--htpasswd=${secrets.restic_mail_htpasswd.path}"
"--baseurl=/Mail/" "--baseurl=/Mail/"
]; ];
inherit serviceConfig;
} }
]; ];
}; };

View file

@ -1,19 +1,22 @@
{lib, ...}: { {...}: {
services.rclone-sync = let services.rclone-sync = {
sync_defaults = {
serviceConfig = {after = ["auto-secrets.service"];};
timerConfig = {
OnStartupSec = "60";
OnCalendar = "4h";
};
extraArgs = [
"--fast-list"
];
};
in {
enable = true; enable = true;
user = "storage"; user = "storage";
sync_jobs = map (x: lib.mkMerge [x sync_defaults]) [ syncJobs = map (syncJob:
syncJob
// {
serviceConfig = {
after = ["auto-secrets.service"];
wants = ["auto-secrets.service"];
};
timerConfig = {
OnStartupSec = "60";
OnCalendar = "4h";
};
extraArgs = [
"--fast-list"
];
}) [
# My B2 # My B2
{ {
source = "StorageBox:Backups"; source = "StorageBox:Backups";

View file

@ -1,21 +0,0 @@
{
pkgs,
config,
...
}: let
secrets = config.services.secrets.secrets;
in {
systemd.services.storage-mount = {
wantedBy = ["multi-user.target"];
after = ["network.target" "auto-secrets.service"];
partOf = ["auto-secrets.service"];
path = with pkgs; [bash rclone mount umount];
script = ''
set -e
umount /storage -fl || true
sleep 2
rclone --config ${secrets.rclone_config.path} mount StorageBox: /storage --allow-non-empty
'';
};
}

View file

@ -2,10 +2,48 @@
config, config,
pkgs, pkgs,
... ...
}: { }: let
cfg = config.services.secrets;
in {
services.secrets = { services.secrets = {
enable = true; enable = true;
vaultLogin = {
enable = true;
loginUsername = "hetzner-vm-container-storage";
loginPasswordFile = cfg.secrets.vault_password.path;
};
autoSecrets = {
enable = true;
};
requiredVaultPaths = [
"api-keys/data/hetzner/storagebox"
"api-keys/data/putio"
"api-keys/data/backblaze/Chaos-Backups"
"api-keys/data/backblaze/Chaos-Photos"
"api-keys/data/backblaze/Chaos-Music"
"api-keys/data/backblaze/Chaos-Personal"
"api-keys/data/backblaze/Chaos-Public"
"api-keys/data/backblaze/Chaos-Media"
"api-keys/data/backblaze/Phoenix-Cryptidz-Storage"
"api-keys/data/storage/restic/Music"
"api-keys/data/storage/restic/Vault"
"api-keys/data/storage/restic/Social"
"api-keys/data/storage/restic/Quassel"
"api-keys/data/storage/restic/Piped-Finland"
"api-keys/data/storage/restic/Mail"
"api-keys/data/storage/webdav/main"
"api-keys/data/storage/webdav/media"
"private-public-keys/data/rclone/Chaos-Media-Crypt"
];
packages = with pkgs; [ packages = with pkgs; [
# for music & mail passwd files # for music & mail passwd files
apacheHttpd apacheHttpd
@ -94,12 +132,12 @@
''; '';
}; };
restic_piped_htpasswd = { restic_piped_finland_htpasswd = {
user = "storage"; user = "storage";
group = "storage"; group = "storage";
fetchScript = '' fetchScript = ''
username=$(simple_get "/api-keys/storage/restic/Piped" .username) username=$(simple_get "/api-keys/storage/restic/Piped-Finland" .username)
password=$(simple_get "/api-keys/storage/restic/Piped" .password) password=$(simple_get "/api-keys/storage/restic/Piped-Finland" .password)
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
''; '';
}; };

View file

@ -1,4 +1,4 @@
{}: { {
host = "192.168.100.10"; host = "192.168.100.10";
containers = { containers = {
storage = "192.168.100.11"; storage = "192.168.100.11";
@ -6,6 +6,5 @@
music = "192.168.100.13"; music = "192.168.100.13";
quassel = "192.168.100.14"; quassel = "192.168.100.14";
piped = "192.168.100.15"; piped = "192.168.100.15";
mail = "192.168.100.16";
}; };
} }

View file

@ -1,9 +1,13 @@
{modulesPath, ...}: { {...}: {
imports = [(modulesPath + "/profiles/qemu-guest.nix")]; boot.loader = {
grub = {
enable = true;
device = "/dev/sda";
};
};
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
boot.initrd.kernelModules = ["nvme"]; boot.initrd.kernelModules = ["nvme"];
fileSystems."/" = { fileSystems."/" = {
device = "/dev/sda1"; device = "/dev/sda1";
fsType = "ext4"; fsType = "ext4";

View file

@ -1,27 +1,25 @@
{ {
tree, tree,
lib, lib,
pkgs,
config,
... ...
}: { }: let
inherit (lib.lists) forEach;
in {
imports = with tree; imports = with tree;
[ [
users.root presets.nixos.serverBase
presets.nixos.serverHetzner
profiles.base
profiles.sshd
profiles.nginx profiles.nginx
profiles.nginx-firewall profiles.firewallAllow.httpCommon
profiles.nix-gc
profiles.cross.arm64 profiles.cross.arm64
profiles.chaos-internal-wireguard profiles.chaosInternalWireGuard
./networking.nix
./hardware.nix ./hardware.nix
./secrets.nix ./secrets.nix
] ]
++ (lib.forEach [ ++ (forEach [
"social" "social"
"storage" "storage"
"music" "music"
@ -30,45 +28,10 @@
"mail" "mail"
] (name: ./containers + "/${name}")) ] (name: ./containers + "/${name}"))
++ (with hosts.hetzner-vm.profiles; [ ++ (with hosts.hetzner-vm.profiles; [
vaultui vaultUI
gitlab-static-sites gitlabStaticSites
nginx-misc
]); ]);
boot.kernel.sysctl = {
"fs.inotify.max_user_watches" = 1024 * 64 * 4;
};
environment.systemPackages = with pkgs;
[
(pkgs.writeShellScriptBin "journalctl-vaccum-all" ''
journalctl --vacuum-size=100M
${lib.concatStringsSep "\n" (lib.forEach (lib.attrNames config.containers) (name: ''
journalctl --vacuum-size=100M --root /var/lib/nixos-containers/${name}
''))}
'')
(pkgs.writeShellScriptBin "systemctl-list-failed-all" ''
echo "Host: "
systemctl --failed
${lib.concatStringsSep "\n" (lib.forEach (lib.attrNames config.containers) (name: ''
echo "Container: ${name}"
systemctl -M ${name} --failed
''))}
'')
]
++ lib.forEach (lib.attrNames config.containers) (name: (pkgs.writeShellScriptBin "journalctl-vaccum-${name}" ''
journalctl --vacuum-size=100M --root /var/lib/nixos-containers/${name}
''))
++ lib.forEach (lib.attrNames config.containers) (name: (pkgs.writeShellScriptBin "systemctl-machine-${name}" ''
systemctl -M ${name} $@
''))
++ lib.forEach (lib.attrNames config.containers) (name: (pkgs.writeShellScriptBin "journalctl-machine-${name}" ''
journalctl -M ${name} $@
''))
++ lib.forEach (lib.attrNames config.containers) (name: (pkgs.writeShellScriptBin "shell-enter-${name}" ''
machinectl shell ${name}
''));
# For Containers # For Containers
networking.nat = { networking.nat = {
enable = true; enable = true;
@ -76,13 +39,8 @@
externalInterface = "eth0"; externalInterface = "eth0";
}; };
home-manager.users.root = {
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
networking.hostName = "hetzner-vm"; networking.hostName = "hetzner-vm";
time.timeZone = "Europe/London";
home-manager.users.root.home.stateVersion = "23.05";
system.stateVersion = "23.05"; system.stateVersion = "23.05";
} }

View file

@ -1,22 +0,0 @@
{lib, ...}: {
systemd.services.systemd-networkd-wait-online.enable = lib.mkForce false;
networking.firewall.enable = true;
networking.firewall.allowPing = true;
networking.firewall.allowedTCPPorts = [22];
services.resolved.enable = false;
environment.etc."resolv.conf".text = "nameserver 8.8.8.8";
networking.enableIPv6 = true;
networking.usePredictableInterfaceNames = false;
networking.dhcpcd.enable = true;
systemd.network = {
enable = true;
networks.eth0 = {
name = "eth0";
address = ["2a01:4f9:c010:8beb::1/64"];
gateway = ["fe80::1"];
};
};
}

View file

@ -1,12 +0,0 @@
{...}: {
services.nginx.virtualHosts."tablet-dev.owo.monster" = {
forceSSL = true;
enableACME = true;
locations = {
"/" = {
proxyPass = "http://10.69.42.2:8088";
proxyWebsockets = true;
};
};
};
}

View file

@ -13,6 +13,22 @@ in {
services.secrets = { services.secrets = {
enable = true; enable = true;
vaultLogin = {
enable = true;
loginUsername = "hetzner-vm";
};
autoSecrets = {
enable = true;
affectedSystemdServices = [
"wg-quick-wg0"
"container@music"
"container@social"
"container@quassel"
"container@piped"
];
};
packages = with pkgs; [ packages = with pkgs; [
# for music & mail passwd files # for music & mail passwd files
apacheHttpd apacheHttpd
@ -41,7 +57,7 @@ in {
"api-keys/data/storage/restic/Mail" "api-keys/data/storage/restic/Mail"
"api-keys/data/storage/restic/Social" "api-keys/data/storage/restic/Social"
"api-keys/data/storage/restic/Quassel" "api-keys/data/storage/restic/Quassel"
"api-keys/data/storage/restic/Piped" "api-keys/data/storage/restic/Piped-Finland"
"api-keys/data/chaos_mail/system" "api-keys/data/chaos_mail/system"
"api-keys/data/chaos_mail/gotosocial" "api-keys/data/chaos_mail/gotosocial"
@ -57,12 +73,16 @@ in {
"private-public-keys/data/restic/Mail" "private-public-keys/data/restic/Mail"
"private-public-keys/data/restic/Social" "private-public-keys/data/restic/Social"
"private-public-keys/data/restic/Quassel" "private-public-keys/data/restic/Quassel"
"private-public-keys/data/restic/Piped" "private-public-keys/data/restic/Piped-Finland"
"infra/data/private-mail-aliases" "infra/data/private-mail-aliases"
]; ];
secrets = { secrets = {
vault_password = {
manual = true;
};
# Used directly by server # Used directly by server
# for fetching gitlab static sites # for fetching gitlab static sites
gitlab_env = { gitlab_env = {
@ -205,16 +225,16 @@ in {
}; };
# Container: piped # Container: piped
piped_restic_password = { piped_finland_restic_password = {
fetchScript = '' fetchScript = ''
simple_get "/private-public-keys/restic/Piped" .password > "$secretFile" simple_get "/private-public-keys/restic/Piped-Finland" .password > "$secretFile"
''; '';
}; };
piped_restic_env = { piped_finland_restic_env = {
fetchScript = '' fetchScript = ''
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Piped" .username) RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Piped-Finland" .username)
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Piped" .password) RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Piped-Finland" .password)
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Piped" > "$secretFile" echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Piped-Finland" > "$secretFile"
''; '';
}; };
piped_cockroachdb_ca_certificate = { piped_cockroachdb_ca_certificate = {

View file

@ -1,4 +1,6 @@
{tree, ...}: { {tree, ...}: {
imports = with tree; [presets.nixos.normalEncryptedDrive];
boot = { boot = {
loader = { loader = {
systemd-boot.enable = true; systemd-boot.enable = true;
@ -21,6 +23,4 @@
services.tlp.settings = { services.tlp.settings = {
RUNTIME_PM_BLACKLIST = "05:00.3 05:00.4"; RUNTIME_PM_BLACKLIST = "05:00.3 05:00.4";
}; };
imports = with tree; [presets.nixos.dual-encrypted-drive];
} }

View file

@ -3,11 +3,10 @@
users.root users.root
users.chaos users.chaos
profiles.sshd profiles.sshd
profiles.kernels.latest
presets.nixos.desktop-sway presets.nixos.desktopSway
presets.nixos.laptop presets.nixos.laptop
presets.nixos.encrypted-usb presets.nixos.encryptedUSB
profiles.cross.arm64 profiles.cross.arm64
#profiles.remote-builders #profiles.remote-builders

View file

@ -1,32 +0,0 @@
{config, ...}: let
secrets = config.services.secrets.secrets;
data = import ../../../data/chaos_wireguard_internal.nix {};
in {
networking.firewall.trustedInterfaces = ["wg0"];
networking.wg-quick.interfaces = {
wg0 = {
autostart = false;
address = ["${data.hosts.lappy-t495.ip}/32"];
privateKeyFile = "${secrets.wg_priv.path}";
peers = [
# hetzner-vm
{
publicKey = "${data.hosts.hetzner-vm.public}";
presharedKeyFile = "${secrets.wg_preshared_hetzner-vm.path}";
allowedIPs = ["${data.hosts.hetzner-vm.ip}/24"];
endpoint = "${data.hosts.hetzner-vm.endpoint}";
persistentKeepalive = 25;
}
# vault
{
publicKey = "${data.hosts.vault.public}";
presharedKeyFile = "${secrets.wg_preshared_vault.path}";
allowedIPs = ["${data.hosts.vault.ip}/32"];
endpoint = "${data.hosts.vault.endpoint}";
persistentKeepalive = 25;
}
];
};
};
}

View file

@ -1,19 +0,0 @@
{tree, ...}: {
users.users.chaos = {
name = "chaos";
home = "/Users/chaos";
};
home-manager.users.chaos = {
programs.zsh.envExtra = ''
export PATH=/run/current-system/sw/bin:$PATH
'';
imports = with tree; [
# NOINLINE
home.base
home.dev
home.programming.editors.vscode
home.programming.languages.nix
home.apps.mpv
];
};
}

View file

@ -4,7 +4,9 @@
modulesPath, modulesPath,
lib, lib,
... ...
}: { }: let
inherit (lib.modules) mkForce;
in {
imports = with tree; [ imports = with tree; [
(modulesPath + "/installer/cd-dvd/installation-cd-graphical-gnome.nix") (modulesPath + "/installer/cd-dvd/installation-cd-graphical-gnome.nix")
(modulesPath + "/installer/cd-dvd/channel.nix") (modulesPath + "/installer/cd-dvd/channel.nix")
@ -12,9 +14,8 @@
users.root users.root
profiles.base profiles.base
profiles.sshd profiles.sshd
profiles.kernels.latest profiles.connectivity.iOS
profiles.connectivity.ios profiles.connectivity.networkManager
profiles.connectivity.network_manager
]; ];
# disable zfs # disable zfs
@ -26,18 +27,16 @@
}) })
]; ];
networking.wireless.enable = lib.mkForce false; networking.wireless.enable = mkForce false;
nixpkgs.config.allowBroken = true; nixpkgs.config.allowBroken = true;
home-manager.users.root = { home-manager.users.root = {
imports = with tree; [home.base home.dev]; imports = with tree; [home.base home.dev];
home.stateVersion = "23.05";
}; };
home-manager.users.nixos = { home-manager.users.nixos = {
imports = with tree; [home.base home.dev]; imports = with tree; [home.base home.dev];
home.stateVersion = "23.05";
}; };
isoImage = { isoImage = {
@ -46,5 +45,5 @@
squashfsCompression = "zstd -Xcompression-level 1"; squashfsCompression = "zstd -Xcompression-level 1";
}; };
services.openssh.settings.PermitRootLogin = lib.mkForce "yes"; services.openssh.settings.PermitRootLogin = mkForce "yes";
} }

View file

@ -30,8 +30,6 @@
inputs.home-manager-unstable.nixosModules.home-manager inputs.home-manager-unstable.nixosModules.home-manager
inputs.nur.nixosModules.nur
inputs.vaultui.nixosModules.default inputs.vaultui.nixosModules.default
inputs.gitlab_artifacts_sync.nixosModules.default inputs.gitlab_artifacts_sync.nixosModules.default
inputs.piped-flake.nixosModules.default inputs.piped-flake.nixosModules.default
@ -39,90 +37,66 @@
tree.modules.nixos.rclone-serve tree.modules.nixos.rclone-serve
tree.modules.nixos.rclone-sync tree.modules.nixos.rclone-sync
tree.modules.nixos.secrets tree.modules.nixos.secrets
tree.modules.nixos.cockroachdb-bin
]; ];
nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem; nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem;
nixosX86_64LiveWithExtraDepsForMachines = machines:
nixosUnstableSystem {
specialArgs =
defaultSpecialArgs
// {
hostPath = ./nixos-live;
};
system = "x86_64-linux";
modules =
defaultModules
++ [
./nixos-live/nixos-live.nix
({...}: {
system.extraDependencies =
forEach machines (system:
self.nixosConfigurations.${system}.config.system.build.toplevel);
})
];
};
in { in {
tablet = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules = defaultModules ++ [./tablet/tablet.nix ./tablet/hardware.nix];
};
lappy-t495 = nixosUnstableSystem { lappy-t495 = nixosUnstableSystem {
specialArgs = defaultSpecialArgs; specialArgs =
defaultSpecialArgs
// {
hostPath = ./lappy-t495;
};
system = "x86_64-linux"; system = "x86_64-linux";
modules = defaultModules ++ [./lappy-t495/lappy-t495.nix ./lappy-t495/hardware.nix]; modules = defaultModules ++ [./lappy-t495/lappy-t495.nix ./lappy-t495/hardware.nix];
}; };
hetzner-vm = nixosUnstableSystem { hetzner-vm = nixosUnstableSystem {
specialArgs = defaultSpecialArgs; specialArgs =
defaultSpecialArgs
// {
hostPath = ./hetzner-vm;
};
system = "x86_64-linux"; system = "x86_64-linux";
modules = defaultModules ++ [./hetzner-vm/hetzner-vm.nix]; modules = defaultModules ++ [./hetzner-vm/hetzner-vm.nix];
}; };
vault = nixosUnstableSystem { vault = nixosUnstableSystem {
specialArgs = defaultSpecialArgs; specialArgs =
defaultSpecialArgs
// {
hostPath = ./vault;
};
system = "x86_64-linux"; system = "x86_64-linux";
modules = defaultModules ++ [./vault/vault.nix]; modules = defaultModules ++ [./vault/vault.nix];
}; };
buildbox = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules = defaultModules ++ [./buildbox/buildbox.nix];
};
# nix build .#nixosConfigurations.nixos-live-x86_64.config.system.build.isoImage # nix build .#nixosConfigurations.nixos-live-x86_64.config.system.build.isoImage
nixos-live-x86_64 = nixosUnstableSystem { nixos-live-x86_64 = nixosX86_64LiveWithExtraDepsForMachines [];
specialArgs = defaultSpecialArgs; nixos-live-x86_64-laptops = nixosX86_64LiveWithExtraDepsForMachines ["lappy-t495"];
system = "x86_64-linux"; nixos-live-x86_64-servers = nixosX86_64LiveWithExtraDepsForMachines ["hetzner-vm" "vault"];
modules = defaultModules ++ [./nixos-live/nixos-live.nix]; nixos-live-x86_64-all = nixosX86_64LiveWithExtraDepsForMachines ["lappy-t495" "vault" "hetzner-vm"];
};
nixos-live-x86_64-laptops = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules =
defaultModules
++ [
./nixos-live/nixos-live.nix
({...}: {
system.extraDependencies =
forEach ["lappy-t495" "tablet"] (system:
self.nixosConfigurations.${system}.config.system.build.toplevel);
})
];
};
nixos-live-x86_64-servers = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules =
defaultModules
++ [
./nixos-live/nixos-live.nix
({...}: {
system.extraDependencies =
forEach ["vault" "hetzner-vm"] (system:
self.nixosConfigurations.${system}.config.system.build.toplevel);
})
];
};
nixos-live-x86_64-all = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules =
defaultModules
++ [
./nixos-live/nixos-live.nix
({...}: {
system.extraDependencies =
forEach ["lappy-t495" "tablet" "vault" "hetzner-vm"] (system:
self.nixosConfigurations.${system}.config.system.build.toplevel);
})
];
};
# nix --no-sandbox build .#nixosConfigurations.raspberry.config.system.build.sdImage # nix --no-sandbox build .#nixosConfigurations.raspberry.config.system.build.sdImage
raspberry = nixosUnstableSystem { raspberry = nixosUnstableSystem {

View file

@ -2,18 +2,30 @@
lib, lib,
pkgs, pkgs,
config, config,
modulesPath,
... ...
}: { }: let
boot.loader.grub.enable = false; inherit (lib.modules) mkForce mkDefault;
boot.loader.generic-extlinux-compatible.enable = true; inherit (builtins) toFile;
in {
imports = [
(modulesPath + "/installer/sd-card/sd-image.nix")
];
boot.consoleLogLevel = lib.mkDefault 7; boot = {
supportedFilesystems = mkForce ["vfat"];
boot.kernelParams = ["console=tty0"]; consoleLogLevel = mkDefault 7;
kernelParams = ["console=tty0"];
loader = {
grub.enable = false;
generic-extlinux-compatible.enable = true;
};
};
sdImage = { sdImage = {
compressImage = mkForce false;
populateFirmwareCommands = let populateFirmwareCommands = let
configTxt = pkgs.writeText "config.txt" '' configTxt = toFile "config.txt" ''
[pi3] [pi3]
kernel=u-boot-rpi3.bin kernel=u-boot-rpi3.bin
[pi4] [pi4]

View file

@ -1,22 +0,0 @@
[connection]
id=WIFI_ID
uuid=554e0eeb-840a-4106-84c3-01c0e9d69569
type=wifi
[wifi]
mode=infrastructure
ssid=WIFI_SSID
[wifi-security]
auth-alg=open
key-mgmt=wpa-psk
psk=WIFI_PASSWORD
[ipv4]
method=auto
[ipv6]
addr-gen-mode=default
method=auto
[proxy]

View file

@ -0,0 +1,23 @@
{self, ...}: let
internalWireGuard = import "${self}/data/chaosInternalWireGuard.nix";
in {
systemd.tmpfiles.rules = [
"d /var/lib/cockroachdb-certs - root root"
];
services.cockroachdb-bin = {
enable = true;
certsDir = "/var/lib/cockroachdb-certs";
join = "localhost:26257,${internalWireGuard.hosts.hetzner-vm.ip}:26257";
# ssh -L 8080:127.0.0.1:8080 -L 26257:127.0.0.1:26257 raspberry
extraArgs = ["--advertise-addr=${internalWireGuard.hosts.raspberry.ip}:26257"];
listen = {
port = 26257;
address = "0.0.0.0";
};
http = {
address = "0.0.0.0";
port = 8080;
};
};
}

View file

@ -1,22 +0,0 @@
{tree, ...}: let
internal_wireguard = import ../../../data/chaos_wireguard_internal.nix {};
in {
imports = with tree; [
profiles.cockroachdb-bin-fix
];
systemd.tmpfiles.rules = [
"d /var/lib/cockroachdb-certs - root root"
];
services.cockroachdb = {
enable = true;
certsDir = "/var/lib/cockroachdb-certs";
join = "localhost:26257,${internal_wireguard.hosts.hetzner-vm.ip}:26257";
# ssh -L 8080:127.0.0.1:8080 -L 26257:127.0.0.1:26257 raspberry
http = {
address = "0.0.0.0";
port = 8080;
};
};
}

Some files were not shown because too many files have changed in this diff Show more