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,
cryptsetup,
e2fsprogs,
writeShellApplication,
}: let
usb_data = import ../data/usb_data.nix {};
in
stdenv.mkDerivation {
encryptedUSBData = import ../data/encryptedUSB.nix;
in (writeShellApplication {
name = "mk-enc-usb";
src = ./mk-enc-usb.sh;
unpackPhase = ''
for srcFile in $src; do
cp $srcFile $(stripHash $srcFile)
done
'';
runtimeInputs = [
parted
cryptsetup
e2fsprogs
];
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 = ''
substituteAllInPlace mk-enc-usb.sh
substituteInPlace mk-enc-usb.sh \
--replace "@USB_ENCRYPTED_PARTLABEL@" "${usb_data.encrypted_partlabel}" \
--replace "@USB_UNENCRYPTED_LABEL@" "${usb_data.unencrypted_label}"
'';
if echo "$USB_DEVICE" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
PARTITION_SEPARATOR=""
fi
installPhase = ''
mkdir -p $out/bin
cp mk-enc-usb.sh $out/bin/mk-enc-usb
chmod +x $out/bin/mk-enc-usb
if [ "$EUID" -ne 0 ]; then
echo "Please run as root"
exit
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,
cryptsetup,
e2fsprogs,
dosfstools,
writeShellApplication,
}: let
ssd_data = import ../data/normal_drive_data.nix {};
in
stdenv.mkDerivation {
ssdData = import ../data/normalEncryptedDrive.nix;
in (writeShellApplication {
name = "mk-normal-enc-ssd";
src = ./mk-normal-enc-ssd.sh;
unpackPhase = ''
for srcFile in $src; do
cp $srcFile $(stripHash $srcFile)
done
'';
runtimeInputs = [
parted
cryptsetup
e2fsprogs
dosfstools
];
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 = ''
substituteAllInPlace mk-normal-enc-ssd.sh
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}"
'';
SSD_PATH=$1
KEY_FILE=$2
installPhase = ''
mkdir -p $out/bin
cp mk-normal-enc-ssd.sh $out/bin/mk-normal-enc-ssd
chmod +x $out/bin/mk-normal-enc-ssd
if echo "$SSD_PATH" | grep -q "[0-9]$"; then
PARTITION_SEPARATOR="p"
else
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,
cryptsetup,
btrfs-progs,
writeShellApplication,
}: let
external_drive_data = import ../data/raspberry_ext_drive.nix {};
in
stdenv.mkDerivation {
externalDriveData = import ../data/raspberryExternalDrive.nix;
in (writeShellApplication {
name = "mk-raspberry-ext-drive";
src = ./mk-raspberry-ext-drive.sh;
unpackPhase = ''
for srcFile in $src; do
cp $srcFile $(stripHash $srcFile)
done
'';
runtimeInputs = [
util-linux
cryptsetup
btrfs-progs
];
text = ''
if [ -z "''${1-}" ]; then
echo "Please specify a path to device as first argument"
exit 1
fi
patchPhase = ''
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}"
'';
DRIVE_PATH=$1
installPhase = ''
mkdir -p $out/bin
cp mk-raspberry-ext-drive.sh $out/bin/mk-raspberry-ext-drive
chmod +x $out/bin/mk-raspberry-ext-drive
if [ -z "''${2-}" ]; then
echo "Please specify a key file to use"
exit 1
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": {
"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": false,
"locked": {
@ -217,7 +191,6 @@
},
"root": {
"inputs": {
"deploy-rs": "deploy-rs",
"flake-compat": "flake-compat",
"flake-utils": "flake-utils",
"gitlab_archiver": "gitlab_archiver",

View file

@ -16,19 +16,11 @@
home-manager-unstable.url = "github:nix-community/home-manager";
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.inputs.nixpkgs.follows = "nixpkgs-unstable";
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.inputs.nixpkgs.follows = "nixpkgs-unstable";
vaultui.inputs.utils.follows = "flake-utils";

View file

@ -1,20 +1,27 @@
{
inputs,
nixosConfig,
pkgs,
...
}: let
nur = import inputs.nur {
nurpkgs = pkgs;
inherit pkgs;
};
isGnome = nixosConfig.services.xserver.desktopManager.gnome.enable;
extensions = with nixosConfig.nur; [
repos.rycee.firefox-addons.ublock-origin
repos.rycee.firefox-addons.stylus
repos.rycee.firefox-addons.tampermonkey
repos.rycee.firefox-addons.search-engines-helper
#repos.rycee.firefox-addons.search-by-image
repos.rycee.firefox-addons.offline-qr-code-generator
repos.rycee.firefox-addons.i-dont-care-about-cookies
repos.rycee.firefox-addons.don-t-fuck-with-paste
repos.rycee.firefox-addons.amp2html
repos.rycee.firefox-addons.a11ycss
extensions = with nur.repos.rycee.firefox-addons; [
ublock-origin
stylus
tampermonkey
search-engines-helper
search-by-image
offline-qr-code-generator
i-dont-care-about-cookies
don-t-fuck-with-paste
amp2html
a11ycss
];
in {
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 {
programs.ssh.enable = true;
programs.ssh.matchBlocks =
lib.mkMerge
((lib.forEach ["hetzner-vm" "vault" "raspberry" "vault-decrypt"] (hostname: {
mkMerge
((forEach ["hetzner-vm" "vault" "raspberry" "vault-decrypt"] (hostname: {
"${hostname}" = {
user = "root";
hostname = "${hostname}.servers.genderfucked.monster";
};
}))
++ (lib.forEach (lib.attrNames container-addresses.containers) (name: {
"container-${name}" = {
++ (forEach (attrNames containerAddresses.containers) (name: {
"hetzner-vm-container-${name}" = {
user = "root";
hostname = "${container-addresses.containers.${name}}";
hostname = "${containerAddresses.containers.${name}}";
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 {
home.packages = with pkgs; [eza bat ripgrep vault-bin libarchive age];
programs.zsh = {
@ -27,9 +31,9 @@ in {
log = "journalctl";
dmesg = "dmesg -HP";
hg = "history 0 | rg";
chaos_age = "age -i ${usb_data.chaos_age_privkey_path}";
chaos_age_encrypt = "age -a -e -i ${usb_data.chaos_age_privkey_path}";
chaos_pub = "cat ${usb_data.chaos_age_pubkey_path}";
chaos_age = "age -i ${encryptedUSBData.chaosAgePrivateKeyPath}";
chaos_age_encrypt = "age -a -e -i ${encryptedUSBData.chaosAgePrivateKeyPath}";
chaos_pub = "cat ${encryptedUSBData.chaosAgePublicKeyPath}";
};
envExtra = ''
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-normal-enc-ssd
mk-dual-enc-ssd
mk-raspberry-ext-drive
];
}

View file

@ -1,5 +1,5 @@
{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; [
home.dev.all.archives.common
home.dev.all.compression

View file

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

View file

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

View file

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

View file

@ -7,8 +7,8 @@
# expected to be in default locations
# Incase home.apps.manual-backup-apps is running in container which passes secrets in from host
secrets =
if builtins.elem "host_secrets" (builtins.attrNames file_inputs)
then file_inputs.host_secrets
if file_inputs ? "hostSecrets"
then file_inputs.hostSecrets
else nixosConfig.services.secrets.secrets;
in {
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 = {
enable = true;
userSettings = {
"terminal.integrated.shellIntegration.enabled" = false;
"github.gitAuthentication" = false;
"editor.fontSize" = font-size;
"editor.fontSize" = 24;
"editor.fontFamily" = "'Comic Code'";
"terminal.integrated.fontSize" = font-size;
"terminal.integrated.fontSize" = 18;
"editor.codeLensFontFamily" = "'Comic Code'";
"editor.inlayHints.fontFamily" = "'Comic Code'";
"markdown.preview.fontFamily" = "'Comic Code'";
"terminal.integrated.fontFamily" = "'Comic Code'";
"files.autoSave" = "afterDelay";
"window.zoomLevel" = zoom-level;
"window.zoomLevel" = 0;
"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: {
nixosConfigurations = import ./nixos.nix inputs;
#darwinConfigurations = import ./darwin.nix inputs;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,50 +4,56 @@
lib,
...
}: let
mail_config = config.services.mailserver;
submissionHeaderCleanupRules = pkgs.writeText "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@${mail_config.fqdn}>
inherit (lib.modules) mkIf;
inherit (lib.strings) concatStringsSep;
inherit (lib.lists) flatten optional;
inherit (lib.attrsets) mapAttrsToList;
inherit (builtins) toFile;
mailConfig = config.services.mailserver;
tls_allowed = "TLSv1.3, TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
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 {
config = mkIf (mailConfig.enable) {
systemd.tmpfiles.rules = mkIf (mailConfig.extraAliasesFile != null) [
"f ${extraAliasesCombinedFilePath} 660 root root"
];
systemd.services.postfix-extra-aliases-setup = mkIf (mailConfig.extraAliasesFile != null) {
wantedBy = ["multi-user.target"];
partOf = ["postfix.service"];
before = ["postfix-setup.service"];
script = ''
cat "${sendingReceivingAliasesFile}" > ${extraAliasesCombinedFilePath}
echo >> ${extraAliasesCombinedFilePath}
cat "${mailConfig.extraAliasesFile}" >> ${extraAliasesCombinedFilePath}
'';
};
# Merge several lookup tables. A lookup table is a attribute set where
# - 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;
services.postfix = let
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
policyd-spf = pkgs.writeText "policyd-spf.conf" mail_config.policyd_config;
sendingReceivingAliasesMappedFile = mappedFile sendingReceivingAliasesMappedName;
submissionOptions = {
smtpd_tls_security_level = "encrypt";
@ -57,61 +63,42 @@
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_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";
};
tls_allowed = "TLSv1.3, TLSv1.2, TLSv1.1, !TLSv1, !SSLv2, !SSLv3";
tls_disallow = "MD5, DES, ADH, RC4, PSD, SRP, 3DES, eNULL, aNULL";
in {
config = lib.mkIf (mail_config.enable) {
systemd.tmpfiles.rules = lib.mkIf (mail_config.extra_aliases_file != null) [
# folder to store the extra aliases file
"f /run/postfix_extra_aliases 660 root root"
];
systemd.services.postfix-extra-aliases-setup = lib.mkIf (mail_config.extra_aliases_file != null) {
wantedBy = ["multi-user.target"];
partOf = ["postfix.service"];
before = ["postfix-setup.service"];
script = ''
cat ${aliases_accounts_file} > /run/postfix_extra_aliases
echo >> /run/postfix_extra_aliases
cat ${mail_config.extra_aliases_file} >> /run/postfix_extra_aliases
'';
};
services.postfix = {
enable = true;
hostname = "${mail_config.fqdn}";
hostname = "${mailConfig.fqdn}";
networksStyle = "host";
mapFiles."aliases_accounts" =
if (mail_config.extra_aliases_file == null)
then aliases_accounts_file
else "/run/postfix_extra_aliases";
mapFiles = {
"sending_receiving_aliases" =
if (mailConfig.extraAliasesFile == null)
then sendingReceivingAliasesFile
else "${extraAliasesCombinedFilePath}";
};
sslCert = mail_config.ssl_config.cert;
sslKey = mail_config.ssl_config.key;
enableSubmission = true;
enableSubmissions = true;
sslCert = mailConfig.sslConfig.cert;
sslKey = mailConfig.sslConfig.key;
config = {
# Extra Config
mydestination = "";
recipient_delimiter = "+";
smtpd_banner = "${mail_config.fqdn} ESMTP NO UCE";
smtpd_banner = "${mailConfig.fqdn} ESMTP NO UCE";
disable_vrfy_command = true;
message_size_limit = "20971520";
virtual_uid_maps = "static:${toString mail_config.vmail_config.user_id}";
virtual_gid_maps = "static:${toString mail_config.vmail_config.group_id}";
virtual_mailbox_base = "${mail_config.vmail_config.directory}";
virtual_mailbox_domains = vhosts_file;
virtual_mailbox_maps = mappedFile "aliases_accounts";
virtual_alias_maps = mappedFile "aliases_accounts";
virtual_uid_maps = "static:${toString mailConfig.vmail.userID}";
virtual_gid_maps = "static:${toString mailConfig.vmail.groupID}";
virtual_mailbox_base = "${mailConfig.vmail.directory}";
virtual_mailbox_domains = toFile "vhosts" (concatStringsSep "\n" mailConfig.domains);
virtual_mailbox_maps = sendingReceivingAliasesMappedFile;
virtual_alias_maps = sendingReceivingAliasesMappedFile;
virtual_transport = "lmtp:unix:/run/dovecot2/dovecot-lmtp";
lmtp_destination_recipient_limit = "1";
@ -124,12 +111,10 @@ in {
"reject_unauth_destination"
];
policy-spf_time_limit = "3600s";
policy-spf_time_limit = mkIf (mailConfig.spf.enable) "3600s";
smtpd_recipient_restrictions = [
#"check_recipient_access ${mappedFile "denied_recipients"}"
#"check_recipient_access ${mappedFile "reject_recipients"}"
"check_policy_service unix:private/policy-spf"
smtpd_recipient_restrictions = flatten [
(optional mailConfig.spf.enable "check_policy_service unix:private/policy-spf")
];
smtpd_tls_security_level = "may";
@ -161,11 +146,14 @@ in {
milter_default_action = "quarantine";
smtpd_milters = [
"unix:/run/opendkim/opendkim.sock"
"unix:/run/rspamd/rspamd-milter.sock"
smtpd_milters = flatten [
(optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.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_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
args = ["flags=O"];
};
"policy-spf" = {
"policy-spf" = mkIf (mailConfig.spf.enable) {
type = "unix";
privileged = true;
chroot = false;
command = "spawn";
args = [
args = let
policydConfig = toFile "policyd-spf.conf" mailConfig.spf.policydConfig;
in [
"user=nobody"
"argv=${pkgs.pypolicyd-spf}/bin/policyd-spf"
"${policyd-spf}"
"${policydConfig}"
];
};
"submission-header-cleanup" = {
@ -197,7 +187,16 @@ in {
chroot = false;
maxproc = 0;
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,
...
}: let
mail_config = config.services.mailserver;
inherit (lib.modules) mkIf;
mailConfig = config.services.mailserver;
postfixCfg = config.services.postfix;
rspamdCfg = config.services.rspamd;
rspamdSocket = "rspamd.service";
in {
config = lib.mkIf (mail_config.enable) {
config = mkIf (mailConfig.enable && mailConfig.rspamd.enable) {
services.rspamd = {
enable = true;
debug = mail_config.debug_mode;
debug = mailConfig.debugMode;
locals = {
"milter_headers.conf" = {
text = ''
@ -21,7 +22,7 @@ in {
};
"redis.conf" = {
text = ''
servers = "127.0.0.1:${toString mail_config.rspamd_redis_port}";
servers = "127.0.0.1:${toString mailConfig.rspamd.redisPort}";
'';
};
"classifier-bayes.conf" = {
@ -82,7 +83,7 @@ in {
services.redis.servers.rspamd = {
enable = true;
port = mail_config.rspamd_redis_port;
port = mailConfig.rspamd.redisPort;
};
systemd.services.rspamd = {
@ -95,6 +96,6 @@ in {
requires = [rspamdSocket];
};
users.extraUsers.${postfixCfg.user}.extraGroups = [rspamdCfg.group];
users.extraUsers.postfix.extraGroups = [rspamdCfg.group];
};
}

View file

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

View file

@ -4,70 +4,68 @@
lib,
...
}: let
mail_config = config.services.mailserver;
inherit (lib.modules) mkIf;
inherit (lib.strings) concatStringsSep;
inherit (lib.attrsets) mapAttrsToList;
vmail_config = mail_config.vmail_config;
vmail_user = vmail_config.user;
vmail_group = vmail_config.group;
mailConfig = config.services.mailserver;
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" ''
#!${pkgs.stdenv.shell}
set -euo pipefail
# Create directory to store user sieve scripts if it doesn't exist
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))}
${concatStringsSep "\n" (mapAttrsToList (name: config: scriptForUser name config) mailConfig.accounts)}
'';
in {
config = lib.mkIf (mail_config.enable) {
users.users."${vmail_user}" = {
config = mkIf (mailConfig.enable) {
users.users."${vmailUser}" = {
isSystemUser = true;
home = vmail_config.directory;
home = vmail.directory;
createHome = true;
uid = vmail_config.user_id;
group = "${vmail_group}";
uid = vmail.userID;
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 = {
wantedBy = ["multi-user.target"];
before = ["dovecot2.service"];
serviceConfig = {ExecStart = virtualMailUsersActivationScript;};
serviceConfig.ExecStart = virtualMailUsersActivationScript;
enable = true;
};
};

View file

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

View file

@ -1,28 +1,59 @@
{
pkgs,
host_secrets,
hostSecrets,
...
}: let
secrets = host_secrets;
secrets = hostSecrets;
in {
services.mailserver = {
enable = true;
fqdn = "mail.owo.monster";
domains = ["owo.monster"];
debugMode = true;
ssl_config = {
sslConfig = {
useACME = false;
cert = "/var/lib/acme/mail.owo.monster/fullchain.pem";
key = "/var/lib/acme/mail.owo.monster/key.pem";
};
enable_roundcube = true;
force_roundcube_ssl = false;
force_roundcube_acme = false;
rspamd.enable = true;
spf.enable = false;
debug_mode = true;
accounts = {
"chaos@owo.monster" = {
passwordHashFile = "${secrets.chaos_mail_passwd.path}";
aliases = [
"all@owo.monster"
"chaoticryptidz@owo.monster"
];
};
extra_roundcube_config = ''
"system@owo.monster" = {
passwordHashFile = "${secrets.system_mail_passwd.path}";
};
"gotosocial@owo.monster" = {
passwordHashFile = "${secrets.gotosocial_mail_passwd.path}";
};
};
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";
@ -30,33 +61,6 @@ in {
$config['log_driver'] = 'syslog';
$config['smtp_debug'] = true;
'';
extra_aliases_file = "${secrets.private_mail_aliases.path}";
accounts = {
"chaos@owo.monster" = {
name = "chaos@owo.monster";
passwordFile = "${secrets.chaos_mail_passwd.path}";
aliases = [
"all@owo.monster"
"chaoticryptidz@owo.monster"
];
sieveScript = null;
};
"system@owo.monster" = {
name = "system@owo.monster";
passwordFile = "${secrets.system_mail_passwd.path}";
aliases = [];
sieveScript = null;
};
"gotosocial@owo.monster" = {
name = "gotosocial@owo.monster";
passwordFile = "${secrets.gotosocial_mail_passwd.path}";
aliases = [];
sieveScript = null;
};
};
};
@ -68,15 +72,9 @@ in {
"/var/sockets"
];
services.roundcube = {
package = pkgs.roundcube.withPlugins (_plugins:
with pkgs.roundcubePlugins; [
persistent_login
]);
plugins = ["persistent_login"];
};
services.nginx.virtualHosts."mail.owo.monster" = {
# running in privateNetwork
# required so nginx doesn't try listening on port 80
listen = [
{
addr = "127.0.0.1";

View file

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

View file

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

View file

@ -1,4 +1,6 @@
{
self,
hostPath,
tree,
lib,
inputs,
@ -6,46 +8,43 @@
pkgs,
...
}: let
container-addresses = import ../../data/container-addresses.nix {};
hostIP = container-addresses.host;
containerIP = container-addresses.containers.music;
inherit (lib.modules) mkMerge;
inherit (lib.lists) forEach;
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
secrets = config.services.secrets.secrets;
ports = import ./data/ports.nix {};
in {
networking.nat.forwardPorts = [
{
sourcePort = ports.mpd;
destination = "${containerIP}\:${toString ports.mpd}";
}
{
sourcePort = ports.slskd;
destination = "${containerIP}\:${toString ports.slskd}";
}
secretsList = [
"mpd_control_password"
"slskd_env"
];
ports = import ./data/ports.nix;
in {
containers.music = {
autoStart = true;
privateNetwork = true;
hostAddress = hostIP;
localAddress = containerIP;
bindMounts = lib.mkMerge (lib.forEach [
"mpd_control_password"
"slskd_env"
] (secret_name: let
path = "${secrets.${secret_name}.path}";
in {
"${path}" = {
hostPath = "${path}";
};
}));
bindMounts = containerLib.genBindHostsForSecrets secrets secretsList;
specialArgs = {
inherit inputs;
inherit tree;
host_secrets = secrets;
inherit self;
inherit hostPath;
hostSecrets = secrets;
};
config = {config, ...}: {
@ -53,40 +52,35 @@ in {
imports = with tree;
[
profiles.base
inputs.home-manager-unstable.nixosModules.home-manager
presets.nixos.containerBase
profiles.sshd
profiles.firewallAllow.ssh
profiles.nginx
modules.nixos.secrets
users.root
profiles.firewallAllow.httpCommon
]
++ (with hosts.hetzner-vm.containers.music; [
profiles.music-sync
profiles.mpd
profiles.musicSync
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
systemd.tmpfiles.rules = [
"d ${config.services.secrets.secretsDir} - root root"
];
networking.firewall = {
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";
home-manager.users.root.home.stateVersion = "23.05";
system.stateVersion = "23.05";
};
};
@ -108,7 +102,7 @@ in {
in {
forceSSL = true;
enableACME = true;
locations = lib.mkMerge ([
locations = mkMerge ([
{
"/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}" = {
proxyPass = "http://${containerIP}:${toString ports."mpd-opus-${quality}"}";
inherit extraConfig;
@ -126,15 +120,28 @@ in {
# For permissions of secrets
users.users."mpd" = {
uid = config.ids.uids.mpd;
uid = containerConfig.ids.uids.mpd;
group = "mpd";
};
users.groups."mpd" = {
gid = config.ids.gids.mpd;
gid = containerConfig.ids.gids.mpd;
};
networking.firewall.allowedTCPPorts = with ports; [
networking = {
nat.forwardPorts = [
{
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,
pkgs,
host_secrets,
hostSecrets,
...
}: let
ports = import ../data/ports.nix {};
secrets = host_secrets;
inherit (lib.strings) concatStringsSep;
inherit (lib.lists) forEach;
ports = import ../data/ports.nix;
secrets = hostSecrets;
in {
environment.systemPackages = with pkgs; [mpc_cli];
environment.systemPackages = with pkgs; [
mpc_cli
];
services.mpd = {
enable = true;
@ -29,7 +34,7 @@ in {
replaygain "track"
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 = {
"low" = "64";
"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 = [
"d /Music - mpd mpd"
];
@ -8,17 +24,11 @@
after = ["network.target"];
partOf = ["mpd.service"];
path = with pkgs; [bash rclone mount umount];
script = let
rclone_config = pkgs.writeText "rclone.conf" ''
[Music]
type = webdav
url = https://storage-webdav.owo.monster/MusicRO/
vendor = other
'';
in ''
path = with pkgs; [bash rclone];
script = ''
set -e
rclone --config ${rclone_config} sync Music: /Music
rclone --config ${rcloneConfig} sync Music: /Music
chown -R mpd:mpd /Music
'';
};

View file

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

View file

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

View file

@ -1,4 +1,6 @@
{
self,
hostPath,
tree,
lib,
inputs,
@ -6,18 +8,23 @@
pkgs,
...
}: let
#container-addresses = import ../../data/container-addresses.nix {};
#hostIP = container-addresses.host;
#containerIP = container-addresses.containers.piped;
containerConfig = config.containers.piped.config;
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
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
secrets = config.services.secrets.secrets;
secrets_list = [
"piped_restic_env"
"piped_restic_password"
secretsList = [
"piped_finland_restic_env"
"piped_finland_restic_password"
{
name = "piped_cockroachdb_ca_certificate";
path = "/var/lib/cockroachdb-certs/ca.crt";
@ -32,11 +39,51 @@
}
];
containerName = "piped";
pipedSocketForComponent = (
component: "/var/lib/nixos-containers/${containerName}/var/sockets/piped-${component}.sock"
);
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
systemd.tmpfiles.rules = [
"d /var/lib/nixos-containers/${containerName}/var/lib/cockroachdb-certs - root root"
@ -50,81 +97,6 @@ in {
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" = {
forceSSL = 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
ports = import ../data/ports.nix {};
piped_config = config.services.piped;
ports = import ../data/ports.nix;
pipedConfig = config.services.piped;
in {
config.services.piped = {
services.piped = {
enable = true;
frontendDomain = "piped-fi.owo.monster";
backendDomain = "backend.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";
postgresDBUsername = "piped";
postgresDBPassword = "piped";
@ -23,43 +24,54 @@ in {
# Do not set proxyNginxExtraConfig here as needs be set in outside of container
internalBackendPort = ports.piped-backend;
internalProxyPort = ports.piped-proxy;
internalBackendPort = ports.internal-piped-backend;
internalProxyPort = ports.internal-piped-proxy;
};
config.systemd.tmpfiles.rules = [
systemd.tmpfiles.rules = [
"d /var/sockets - nginx nginx"
];
config.systemd.services.nginx.serviceConfig.ReadWritePaths = [
systemd.services.nginx = {
serviceConfig.ReadWritePaths = [
"/var/sockets"
];
};
config.services.nginx.virtualHosts."${piped_config.frontendDomain}" = {
extraConfig = "listen unix:/var/sockets/piped-frontend.sock;";
systemd.services.piped-backend = {
after = ["cockroachdb.service"];
wants = ["cockroachdb.service"];
};
services.nginx.virtualHosts = let
componentPath = component: "/var/sockets/piped-${component}.sock";
in {
"${pipedConfig.frontendDomain}" = {
listen = [
{
addr = "127.0.0.1";
port = 9080;
port = 8091;
}
];
extraConfig = "listen unix:${componentPath "frontend"};";
};
config.services.nginx.virtualHosts."${piped_config.backendDomain}" = {
extraConfig = "listen unix:/var/sockets/piped-backend.sock;";
"${pipedConfig.backendDomain}" = {
extraConfig = "listen unix:${componentPath "backend"};";
listen = [
{
addr = "127.0.0.1";
port = 9080;
port = 8092;
}
];
};
config.services.nginx.virtualHosts."${piped_config.proxyDomain}" = {
extraConfig = "listen unix:/var/sockets/piped-proxy.sock;";
"${pipedConfig.proxyDomain}" = {
extraConfig = "listen unix:${componentPath "proxy"};";
listen = [
{
addr = "127.0.0.1";
port = 9080;
port = 8093;
}
];
};
};
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -2,10 +2,13 @@
pkgs,
config,
lib,
host_secrets,
hostSecrets,
...
}: 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
# and duplicate the wrapper for use in a systemd unit
@ -22,8 +25,8 @@
backupPrepareCommand = "${
(pkgs.writeShellScriptBin "backupPrepareCommand" ''
systemctl start ${
lib.concatStringsSep " "
(lib.forEach config.services.postgresqlBackup.databases
concatStringsSep " "
(forEach config.services.postgresqlBackup.databases
(db: "postgresqlBackup-${db}"))
} --wait

View file

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

View file

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

View file

@ -1,18 +1,22 @@
{
self,
hostPath,
tree,
lib,
inputs,
pkgs,
...
}: let
container-addresses = import ../../data/container-addresses.nix {};
hostIP = container-addresses.host;
containerIP = container-addresses.containers.storage;
inherit (lib.attrsets) attrValues;
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
hostIP = containerAddresses.host;
containerIP = containerAddresses.containers.storage;
# 32GB
clientMaxBodySize = "${toString (8192 * 4)}M";
ports = import ./data/ports.nix {};
ports = import ./data/ports.nix;
in {
containers.storage = {
autoStart = true;
@ -23,6 +27,8 @@ in {
specialArgs = {
inherit inputs;
inherit tree;
inherit self;
inherit hostPath;
};
config = {...}: {
@ -43,14 +49,11 @@ in {
users.root
]
++ (with hosts.hetzner-vm.containers.storage; [
profiles.auto-secrets
profiles.rclone-configs
profiles.rclone-serve
profiles.rclone-sync
# doesn't work in container
# profiles.storage-mount
profiles.users
++ (with hosts.hetzner-vm.containers.storage.profiles; [
rcloneConfigs
rcloneServe
rcloneSync
users
]);
environment.systemPackages = with pkgs; [rclone];
@ -63,7 +66,7 @@ in {
networking.firewall = {
enable = true;
allowedTCPPorts = [22] ++ lib.mapAttrsToList (_name: value: value) ports;
allowedTCPPorts = attrValues ports;
};
# 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}";
"/Social/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_social}";
"/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}";
};
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
secrets = config.services.secrets.secrets;
ports = import ../data/ports.nix {};
ports = import ../data/ports.nix;
in {
systemd.tmpfiles.rules = [
"d /caches - storage storage"
@ -8,16 +8,20 @@ in {
"d /caches/media_webdav_serve - storage storage"
];
services.rclone-serve = let
serviceConfig = {
after = ["auto-secrets.service"];
partOf = ["auto-secrets.service"];
};
in {
services.rclone-serve = {
enable = true;
remotes = [
remotes = map (remote:
{
user = "storage";
serviceConfig = {
after = ["auto-secrets.service"];
wants = ["auto-secrets.service"];
partOf = ["auto-secrets.service"];
};
}
// remote) [
{
id = "main";
remote = "StorageBox:";
type = "webdav";
extraArgs = [
@ -27,10 +31,9 @@ in {
"--cache-dir=/caches/main_webdav_serve"
"--vfs-cache-mode=full"
];
inherit serviceConfig;
}
{
user = "storage";
id = "media-combine";
remote = "Media-Combine-Serve:";
type = "webdav";
extraArgs = [
@ -42,10 +45,9 @@ in {
"--vfs-cache-max-size=5g"
"--vfs-cache-mode=full"
];
inherit serviceConfig;
}
{
user = "storage";
id = "music-ro";
remote = "StorageBox:Music";
type = "webdav";
extraArgs = [
@ -53,10 +55,9 @@ in {
"--read-only"
"--baseurl=/MusicRO/"
];
inherit serviceConfig;
}
{
user = "storage";
id = "music-ro";
remote = "StorageBox:Music";
type = "http";
extraArgs = [
@ -64,10 +65,9 @@ in {
"--baseurl=/Music/"
"--read-only"
];
inherit serviceConfig;
}
{
user = "storage";
id = "public";
remote = "StorageBox:Public";
type = "http";
extraArgs = [
@ -75,10 +75,9 @@ in {
"--baseurl=/Public/"
"--read-only"
];
inherit serviceConfig;
}
{
user = "storage";
id = "restic-music";
remote = "StorageBox:Backups/Restic/Music";
type = "restic";
extraArgs = [
@ -86,10 +85,9 @@ in {
"--htpasswd=${secrets.restic_music_htpasswd.path}"
"--baseurl=/Music/"
];
inherit serviceConfig;
}
{
user = "storage";
id = "restic-vault";
remote = "StorageBox:Backups/Restic/Vault";
type = "restic";
extraArgs = [
@ -97,10 +95,9 @@ in {
"--htpasswd=${secrets.restic_vault_htpasswd.path}"
"--baseurl=/Vault/"
];
inherit serviceConfig;
}
{
user = "storage";
id = "restic-social";
remote = "StorageBox:Backups/Restic/Social";
type = "restic";
extraArgs = [
@ -108,10 +105,9 @@ in {
"--htpasswd=${secrets.restic_social_htpasswd.path}"
"--baseurl=/Social/"
];
inherit serviceConfig;
}
{
user = "storage";
id = "restic-quassel";
remote = "StorageBox:Backups/Restic/Quassel";
type = "restic";
extraArgs = [
@ -119,21 +115,19 @@ in {
"--htpasswd=${secrets.restic_quassel_htpasswd.path}"
"--baseurl=/Quassel/"
];
inherit serviceConfig;
}
{
user = "storage";
remote = "StorageBox:Backups/Restic/Piped";
id = "restic-piped-finland";
remote = "StorageBox:Backups/Restic/Piped-Finland";
type = "restic";
extraArgs = [
"--addr=0.0.0.0:${toString ports.rclone_serve_restic_piped}"
"--htpasswd=${secrets.restic_piped_htpasswd.path}"
"--baseurl=/Piped/"
"--addr=0.0.0.0:${toString ports.rclone_serve_restic_piped_finland}"
"--htpasswd=${secrets.restic_piped_finland_htpasswd.path}"
"--baseurl=/Piped-Finland/"
];
inherit serviceConfig;
}
{
user = "storage";
id = "restic-mail";
remote = "StorageBox:Backups/Restic/Mail";
type = "restic";
extraArgs = [
@ -141,7 +135,6 @@ in {
"--htpasswd=${secrets.restic_mail_htpasswd.path}"
"--baseurl=/Mail/"
];
inherit serviceConfig;
}
];
};

View file

@ -1,7 +1,14 @@
{lib, ...}: {
services.rclone-sync = let
sync_defaults = {
serviceConfig = {after = ["auto-secrets.service"];};
{...}: {
services.rclone-sync = {
enable = true;
user = "storage";
syncJobs = map (syncJob:
syncJob
// {
serviceConfig = {
after = ["auto-secrets.service"];
wants = ["auto-secrets.service"];
};
timerConfig = {
OnStartupSec = "60";
OnCalendar = "4h";
@ -9,11 +16,7 @@
extraArgs = [
"--fast-list"
];
};
in {
enable = true;
user = "storage";
sync_jobs = map (x: lib.mkMerge [x sync_defaults]) [
}) [
# My B2
{
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,
pkgs,
...
}: {
}: let
cfg = config.services.secrets;
in {
services.secrets = {
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; [
# for music & mail passwd files
apacheHttpd
@ -94,12 +132,12 @@
'';
};
restic_piped_htpasswd = {
restic_piped_finland_htpasswd = {
user = "storage";
group = "storage";
fetchScript = ''
username=$(simple_get "/api-keys/storage/restic/Piped" .username)
password=$(simple_get "/api-keys/storage/restic/Piped" .password)
username=$(simple_get "/api-keys/storage/restic/Piped-Finland" .username)
password=$(simple_get "/api-keys/storage/restic/Piped-Finland" .password)
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
'';
};

View file

@ -1,4 +1,4 @@
{}: {
{
host = "192.168.100.10";
containers = {
storage = "192.168.100.11";
@ -6,6 +6,5 @@
music = "192.168.100.13";
quassel = "192.168.100.14";
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"];
fileSystems."/" = {
device = "/dev/sda1";
fsType = "ext4";

View file

@ -1,27 +1,25 @@
{
tree,
lib,
pkgs,
config,
...
}: {
}: let
inherit (lib.lists) forEach;
in {
imports = with tree;
[
users.root
presets.nixos.serverBase
presets.nixos.serverHetzner
profiles.base
profiles.sshd
profiles.nginx
profiles.nginx-firewall
profiles.nix-gc
profiles.cross.arm64
profiles.chaos-internal-wireguard
profiles.firewallAllow.httpCommon
profiles.cross.arm64
profiles.chaosInternalWireGuard
./networking.nix
./hardware.nix
./secrets.nix
]
++ (lib.forEach [
++ (forEach [
"social"
"storage"
"music"
@ -30,45 +28,10 @@
"mail"
] (name: ./containers + "/${name}"))
++ (with hosts.hetzner-vm.profiles; [
vaultui
gitlab-static-sites
nginx-misc
vaultUI
gitlabStaticSites
]);
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
networking.nat = {
enable = true;
@ -76,13 +39,8 @@
externalInterface = "eth0";
};
home-manager.users.root = {
imports = with tree; [home.base home.dev.small];
home.stateVersion = "23.05";
};
networking.hostName = "hetzner-vm";
time.timeZone = "Europe/London";
home-manager.users.root.home.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 = {
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; [
# for music & mail passwd files
apacheHttpd
@ -41,7 +57,7 @@ in {
"api-keys/data/storage/restic/Mail"
"api-keys/data/storage/restic/Social"
"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/gotosocial"
@ -57,12 +73,16 @@ in {
"private-public-keys/data/restic/Mail"
"private-public-keys/data/restic/Social"
"private-public-keys/data/restic/Quassel"
"private-public-keys/data/restic/Piped"
"private-public-keys/data/restic/Piped-Finland"
"infra/data/private-mail-aliases"
];
secrets = {
vault_password = {
manual = true;
};
# Used directly by server
# for fetching gitlab static sites
gitlab_env = {
@ -205,16 +225,16 @@ in {
};
# Container: piped
piped_restic_password = {
piped_finland_restic_password = {
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 = ''
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Piped" .username)
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Piped" .password)
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Piped" > "$secretFile"
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Piped-Finland" .username)
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-Finland" > "$secretFile"
'';
};
piped_cockroachdb_ca_certificate = {

View file

@ -1,4 +1,6 @@
{tree, ...}: {
imports = with tree; [presets.nixos.normalEncryptedDrive];
boot = {
loader = {
systemd-boot.enable = true;
@ -21,6 +23,4 @@
services.tlp.settings = {
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.chaos
profiles.sshd
profiles.kernels.latest
presets.nixos.desktop-sway
presets.nixos.desktopSway
presets.nixos.laptop
presets.nixos.encrypted-usb
presets.nixos.encryptedUSB
profiles.cross.arm64
#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,
lib,
...
}: {
}: let
inherit (lib.modules) mkForce;
in {
imports = with tree; [
(modulesPath + "/installer/cd-dvd/installation-cd-graphical-gnome.nix")
(modulesPath + "/installer/cd-dvd/channel.nix")
@ -12,9 +14,8 @@
users.root
profiles.base
profiles.sshd
profiles.kernels.latest
profiles.connectivity.ios
profiles.connectivity.network_manager
profiles.connectivity.iOS
profiles.connectivity.networkManager
];
# disable zfs
@ -26,18 +27,16 @@
})
];
networking.wireless.enable = lib.mkForce false;
networking.wireless.enable = mkForce false;
nixpkgs.config.allowBroken = true;
home-manager.users.root = {
imports = with tree; [home.base home.dev];
home.stateVersion = "23.05";
};
home-manager.users.nixos = {
imports = with tree; [home.base home.dev];
home.stateVersion = "23.05";
};
isoImage = {
@ -46,5 +45,5 @@
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.nur.nixosModules.nur
inputs.vaultui.nixosModules.default
inputs.gitlab_artifacts_sync.nixosModules.default
inputs.piped-flake.nixosModules.default
@ -39,90 +37,66 @@
tree.modules.nixos.rclone-serve
tree.modules.nixos.rclone-sync
tree.modules.nixos.secrets
tree.modules.nixos.cockroachdb-bin
];
nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem;
in {
tablet = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules = defaultModules ++ [./tablet/tablet.nix ./tablet/hardware.nix];
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 {
lappy-t495 = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
specialArgs =
defaultSpecialArgs
// {
hostPath = ./lappy-t495;
};
system = "x86_64-linux";
modules = defaultModules ++ [./lappy-t495/lappy-t495.nix ./lappy-t495/hardware.nix];
};
hetzner-vm = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
specialArgs =
defaultSpecialArgs
// {
hostPath = ./hetzner-vm;
};
system = "x86_64-linux";
modules = defaultModules ++ [./hetzner-vm/hetzner-vm.nix];
};
vault = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
specialArgs =
defaultSpecialArgs
// {
hostPath = ./vault;
};
system = "x86_64-linux";
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
nixos-live-x86_64 = nixosUnstableSystem {
specialArgs = defaultSpecialArgs;
system = "x86_64-linux";
modules = defaultModules ++ [./nixos-live/nixos-live.nix];
};
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);
})
];
};
nixos-live-x86_64 = nixosX86_64LiveWithExtraDepsForMachines [];
nixos-live-x86_64-laptops = nixosX86_64LiveWithExtraDepsForMachines ["lappy-t495"];
nixos-live-x86_64-servers = nixosX86_64LiveWithExtraDepsForMachines ["hetzner-vm" "vault"];
nixos-live-x86_64-all = nixosX86_64LiveWithExtraDepsForMachines ["lappy-t495" "vault" "hetzner-vm"];
# nix --no-sandbox build .#nixosConfigurations.raspberry.config.system.build.sdImage
raspberry = nixosUnstableSystem {

View file

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