delete mail container

This commit is contained in:
chaos 2025-01-27 19:28:47 +00:00
parent 03a77eaff3
commit fa1396acb7
No known key found for this signature in database
12 changed files with 0 additions and 949 deletions

View file

@ -1,95 +0,0 @@
{
self,
tree,
lib,
inputs,
config,
pkgs,
...
}: let
inherit (lib.modules) mkMerge mkForce;
inherit (lib.lists) flatten;
ports = [
# SMTP
25
# Submission
587
# Submission w/ SSL
465
# IMAP
143
# IMAP w/ SSL
993
# Sieve
4190
];
sharedFiles = [
"/var/lib/acme/mail.owo.monster/fullchain.pem"
"/var/lib/acme/mail.owo.monster/key.pem"
];
in {
containers.mail = {
autoStart = true;
bindMounts = mkMerge (map (file: {
"${file}" = {
hostPath = "${file}";
};
})
sharedFiles);
specialArgs = {
inherit inputs;
inherit tree;
inherit self;
};
config = {...}: {
nixpkgs.pkgs = pkgs;
imports = flatten (with tree; [
presets.nixos.containerBase
(with hosts.hetzner-arm.containers.mail; [
modules.mailserver
profiles.mailserver
profiles.restic
])
./secrets.nix
]);
systemd.tmpfiles.rules = [
"d /var/lib/acme - root root"
"d /var/lib/acme/mail.owo.monster - root root"
];
networking.firewall = {
enable = mkForce false;
};
home-manager.users.root.home.stateVersion = "25.05";
system.stateVersion = "25.05";
};
};
# ssl for mail
services.nginx = {
enable = true;
virtualHosts."mail.owo.monster" = {
serverName = "mail.owo.monster";
serverAliases = ["owo.monster"];
forceSSL = true;
enableACME = true;
acmeRoot = "/var/lib/acme/acme-challenge";
};
};
networking.firewall = {
allowedTCPPorts = ports;
allowedUDPPorts = ports;
};
}

View file

@ -1,129 +0,0 @@
{
config,
lib,
...
}: let
inherit (lib) types;
inherit (lib.options) mkEnableOption mkOption;
cfg = config.services.mailserver;
in {
options.services.mailserver = {
enable = mkEnableOption "mailserver";
fqdn = mkOption {
type = types.str;
description = "domain used for mx records";
};
domains = mkOption {
type = types.listOf types.str;
description = "all domains for receiving mail on";
};
debugMode = mkOption {
type = types.bool;
default = false;
description = "enable debug logging on everything";
};
sslConfig = {
useACME = mkOption {
type = types.bool;
default = true;
};
cert = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/fullchain.pem";
};
key = mkOption {
type = types.str;
default = "/var/lib/acme/${cfg.fqdn}/key.pem";
};
};
spf = {
enable = mkOption {
type = types.bool;
default = true;
};
policydConfig = mkOption {
type = types.str;
default = "";
};
};
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.user}";
};
userID = mkOption {
type = types.number;
default = 5000;
};
groupID = mkOption {
type = types.number;
default = cfg.vmail.userID;
};
directory = mkOption {
type = types.str;
default = "/home/${cfg.vmail.user}";
};
};
};
}

View file

@ -1,172 +0,0 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib.modules) mkIf;
inherit (lib.attrsets) mapAttrsToList;
inherit (lib.strings) concatStringsSep optionalString;
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
${concatStringsSep "\n" (map (userPasswdFile: ''
if [ ! -f "${userPasswdFile}" ]; then
echo "Expected password hash file ${userPasswdFile} does not exist!"
exit 1
fi
'') (mapAttrsToList (_email: config: config.passwordHashFile) mailConfig.accounts))}
cat <<EOF > ${passwdFile}
${concatStringsSep "\n" (mapAttrsToList (
email: config: "${email}:$(head -n 1 ${config.passwordHashFile})"
)
mailConfig.accounts)}
EOF
'';
in {
config = mkIf mailConfig.enable {
services.dovecot2 = {
enable = true;
enableImap = true;
enableLmtp = true;
enableQuota = true;
enablePop3 = false;
enablePAM = false; # Not using PAM for Auth
mailUser = vmailConfig.user;
mailGroup = vmailConfig.group;
mailLocation = "maildir:${vmailConfig.directory}/%d/%n";
sslServerCert = mailConfig.sslConfig.cert;
sslServerKey = mailConfig.sslConfig.key;
# For Sieve
modules = with pkgs; [
dovecot_pigeonhole
];
protocols = ["sieve"];
mailboxes = {
Trash = {
auto = "no";
specialUse = "Trash";
};
Junk = {
auto = "subscribe";
specialUse = "Junk";
};
Drafts = {
auto = "subscribe";
specialUse = "Drafts";
};
Sent = {
auto = "subscribe";
specialUse = "Sent";
};
};
extraConfig = ''
${optionalString mailConfig.debugMode ''
mail_debug = yes
auth_debug = yes
verbose_ssl = yes
''}
service imap-login {
inet_listener imap {
port = 143
}
inet_listener imaps {
port = 993
ssl = yes
}
}
protocol imap {
mail_max_userip_connections = 100
mail_plugins = $mail_plugins imap_sieve
}
ssl = required
ssl_min_protocol = TLSv1.2
ssl_prefer_server_ciphers = yes
service lmtp {
unix_listener dovecot-lmtp {
group = ${postfixCfg.group}
mode = 0600
user = ${postfixCfg.user}
}
}
recipient_delimiter = "+"
lmtp_save_to_detail_mailbox = "no"
protocol lmtp {
mail_plugins = $mail_plugins sieve
}
mail_access_groups = "${vmailConfig.group}"
userdb {
driver = static
args = uid=${toString vmailConfig.userID} gid=${toString vmailConfig.groupID}
}
passdb {
driver = passwd-file
args = ${passwdFile}
}
service auth {
unix_listener auth {
mode = 0660
user = ${postfixCfg.user}
group = ${postfixCfg.group}
}
}
auth_mechanisms = plain login
namespace inbox {
separator = "."
inbox = yes
}
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
sieve = file:${mailConfig.sieveDirectory}/%u/scripts;active=${mailConfig.sieveDirectory}/%u/active.sieve
sieve_default = file:${mailConfig.sieveDirectory}/%u/default.sieve
sieve_default_name = default
sieve_global_extensions = +vnd.dovecot.environment
}
lda_mailbox_autosubscribe = yes
lda_mailbox_autocreate = yes
'';
};
systemd = {
tmpfiles.rules = [
"f ${passwdFile} 600 dovecot2 dovecot2"
];
services = {
dovecot2.preStart = ''
${genPasswdScript}
'';
postfix.restartTriggers = [genPasswdScript];
};
};
};
}

View file

@ -1,28 +0,0 @@
{
lib,
config,
...
}: let
inherit (lib.modules) mkIf;
mailConfig = config.services.mailserver;
in {
config = mkIf mailConfig.enable {
networking.firewall = {
allowedTCPPorts = [
# SMTP
25
# Submission
587
# Submission w/ SSL
465
# IMAP
143
# IMAP w/ SSL
993
# Sieve
4190
];
};
};
}

View file

@ -1,85 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
inherit (lib.modules) mkIf mkForce;
inherit (lib.trivial) flip;
inherit (lib.strings) optionalString escapeShellArgs;
inherit (builtins) toFile concatStringsSep;
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";
inherit (mailConfig) domains;
createDomainDkimCert = dom: let
dkimKey = "${keyDir}/${dom}.${selector}.key";
dkimDNSFile = "${keyDir}/${dom}.${selector}.txt";
in ''
if [ ! -f "${dkimKey}" ]
then
${pkgs.opendkim}/bin/opendkim-genkey -s "${selector}" \
-d "${dom}" \
--bits="1024" \
--directory="${keyDir}"
mv "${keyDir}/${selector}.private" "${dkimKey}"
mv "${keyDir}/${selector}.txt" "${dkimDNSFile}"
echo "Generated key for domain ${dom} selector ${selector}"
fi
'';
createAllCerts =
concatStringsSep "\n" (map createDomainDkimCert mailConfig.domains);
keyTable = toFile "opendkim-KeyTable" (concatStringsSep "\n"
(flip map domains
(dom: "${dom} ${dom}:${selector}:${keyDir}/${dom}.${selector}.key")));
signingTable =
toFile "opendkim-SigningTable"
(concatStringsSep "\n" (flip map domains (dom: "${dom} ${dom}")));
in {
config = mkIf (mailConfig.enable && mailConfig.dkim.enable) {
services.opendkim = {
enable = true;
inherit selector;
keyPath = keyDir;
domains = "csl:${concatStringsSep "," domains}";
configFile = toFile "opendkim.conf" (''
Canonicalization relaxed/relaxed
UMask 0002
Socket ${opendkimConfig.socket}
KeyTable file:${keyTable}
SigningTable file:${signingTable}
''
+ (optionalString mailConfig.debugMode ''
Syslog yes
SyslogSuccess yes
LogWhy yes
''));
};
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 opendkimArgs}";
PermissionsStartOnly = mkForce false;
};
};
};
}

View file

@ -1,203 +0,0 @@
{
config,
pkgs,
lib,
...
}: let
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}
'';
};
services.postfix = let
mappedFile = name: "hash:/var/lib/postfix/conf/${name}";
sendingReceivingAliasesMappedFile = mappedFile sendingReceivingAliasesMappedName;
submissionOptions = {
smtpd_tls_security_level = "encrypt";
smtpd_sasl_auth_enable = "yes";
smtpd_sasl_type = "dovecot";
smtpd_sasl_path = "/run/dovecot2/auth";
smtpd_sasl_security_options = "noanonymous";
smtpd_sasl_local_domain = "$myhostname";
smtpd_client_restrictions = "permit_sasl_authenticated,reject";
smtpd_sender_login_maps = sendingReceivingAliasesMappedFile;
smtpd_sender_restrictions = "reject_sender_login_mismatch";
smtpd_recipient_restrictions = "reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject";
cleanup_service_name = "submission-header-cleanup";
};
in {
enable = true;
hostname = "${mailConfig.fqdn}";
networksStyle = "host";
mapFiles = {
"sending_receiving_aliases" =
if (mailConfig.extraAliasesFile == null)
then sendingReceivingAliasesFile
else "${extraAliasesCombinedFilePath}";
};
enableSubmission = true;
enableSubmissions = true;
sslCert = mailConfig.sslConfig.cert;
sslKey = mailConfig.sslConfig.key;
config = {
# Extra Config
mydestination = "";
recipient_delimiter = "+";
smtpd_banner = "${mailConfig.fqdn} ESMTP NO UCE";
disable_vrfy_command = true;
message_size_limit = "20971520";
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";
smtpd_sasl_type = "dovecot";
smtpd_sasl_path = "/run/dovecot2/auth";
smtpd_sasl_auth_enable = true;
smtpd_relay_restrictions = [
"permit_mynetworks"
"permit_sasl_authenticated"
"reject_unauth_destination"
];
policy-spf_time_limit = mkIf mailConfig.spf.enable "3600s";
smtpd_recipient_restrictions = flatten [
(optional mailConfig.spf.enable "check_policy_service unix:private/policy-spf")
];
smtpd_tls_security_level = "may";
smtpd_tls_eecdh_grade = "ultra";
# Only Alow Modern TLS
smtp_tls_protocols = tls_allowed;
smtpd_tls_protocols = tls_allowed;
smtp_tls_mandatory_protocols = tls_allowed;
smtpd_tls_mandatory_protocols = tls_allowed;
# Disable Old Ciphers
smtp_tls_exclude_ciphers = tls_disallow;
smtpd_tls_exclude_ciphers = tls_disallow;
smtp_tls_mandatory_exclude_ciphers = tls_disallow;
smtpd_tls_mandatory_exclude_ciphers = tls_disallow;
smtp_tls_ciphers = "high";
smtpd_tls_ciphers = "high";
smtp_tls_mandatory_ciphers = "high";
smtpd_tls_mandatory_ciphers = "high";
tls_preempt_cipherlist = true;
smtpd_tls_auth_only = true;
smtpd_tls_loglevel = "1";
tls_random_source = "dev:/dev/urandom";
milter_default_action = "quarantine";
smtpd_milters = flatten [
(optional mailConfig.dkim.enable "unix:/run/opendkim/opendkim.sock")
];
non_smtpd_milters = flatten [
(optional mailConfig.dkim.enable "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}";
};
inherit submissionOptions;
submissionsOptions = submissionOptions;
masterConfig = {
"lmtp" = {
# Add headers when delivering, see http://www.postfix.org/smtp.8.html
# D => Delivered-To, O => X-Original-To, R => Return-Path
args = ["flags=O"];
};
"policy-spf" = mkIf mailConfig.spf.enable {
type = "unix";
privileged = true;
chroot = false;
command = "spawn";
args = let
policydConfig = toFile "policyd-spf.conf" mailConfig.spf.policydConfig;
in [
"user=nobody"
"argv=${pkgs.pypolicyd-spf}/bin/policyd-spf"
"${policydConfig}"
];
};
"submission-header-cleanup" = {
type = "unix";
private = false;
chroot = false;
maxproc = 0;
command = "cleanup";
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

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

View file

@ -1,72 +0,0 @@
{
config,
pkgs,
lib,
...
}: let
inherit (lib.modules) mkIf;
inherit (lib.strings) concatStringsSep;
inherit (lib.attrsets) mapAttrsToList;
mailConfig = config.services.mailserver;
inherit (mailConfig) vmail;
vmailUser = vmail.user;
vmailGroup = vmail.group;
inherit (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
${concatStringsSep "\n" (mapAttrsToList (name: config: scriptForUser name config) mailConfig.accounts)}
'';
in {
config = mkIf mailConfig.enable {
users.users."${vmailUser}" = {
isSystemUser = true;
home = vmail.directory;
createHome = true;
uid = vmail.userID;
group = "${vmailGroup}";
};
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;
enable = true;
};
};
}

View file

@ -1,38 +0,0 @@
{config, ...}: let
inherit (config.services.secrets) secrets;
in {
services.mailserver = {
enable = true;
fqdn = "mail.owo.monster";
domains = ["owo.monster"];
debugMode = true;
sslConfig = {
useACME = false;
cert = "/var/lib/acme/mail.owo.monster/fullchain.pem";
key = "/var/lib/acme/mail.owo.monster/key.pem";
};
spf.enable = false;
accounts = {
"chaos@owo.monster" = {
passwordHashFile = "${secrets.chaos_mail_passwd.path}";
aliases = [
"all@owo.monster"
"chaoticryptidz@owo.monster"
];
};
"system@owo.monster" = {
passwordHashFile = "${secrets.system_mail_passwd.path}";
};
"gotosocial@owo.monster" = {
passwordHashFile = "${secrets.gotosocial_mail_passwd.path}";
};
};
extraAliasesFile = "${secrets.private_mail_aliases.path}";
};
}

View file

@ -1,27 +0,0 @@
{
self,
config,
...
}: let
backupSchedules = import "${self}/data/backupSchedules.nix";
inherit (config.services.secrets) secrets;
mailConfig = config.services.mailserver;
in {
services.restic.backups.mail = {
user = "root";
paths = [
mailConfig.vmail.directory
mailConfig.sieveDirectory
mailConfig.dkim.directory
];
repository = "s3:s3.eu-central-003.backblazeb2.com/Chaos-Restic/Mail";
passwordFile = "${secrets.restic_password.path}";
environmentFile = "${secrets.restic_env.path}";
createWrapper = true;
pruneOpts = ["--keep-last 60"];
timerConfig = backupSchedules.restic.medium;
};
}

View file

@ -1,72 +0,0 @@
{pkgs, ...}: {
services.secrets = {
enable = true;
vaultLogin = {
enable = true;
loginUsername = "hetzner-arm-container-mail";
};
requiredVaultPaths = [
"api-keys/data/backblaze/Backblaze"
"api-keys/data/chaos_mail/system"
"api-keys/data/chaos_mail/gotosocial"
"passwords/data/mail"
"private-public-keys/data/restic/Mail"
"infra/data/private-mail-aliases"
];
packages = with pkgs; [
apacheHttpd
];
secrets = {
vault_password = {
manual = true;
};
restic_password = {
fetchScript = ''
simple_get "/private-public-keys/restic/Mail" .password > "$secretFile"
'';
};
restic_env = {
fetchScript = ''
cat << EOF > "$secretFile"
AWS_ACCESS_KEY_ID=$(simple_get "/api-keys/backblaze/Backblaze" .keyID)
AWS_SECRET_ACCESS_KEY=$(simple_get "/api-keys/backblaze/Backblaze" .applicationKey)
EOF
'';
};
private_mail_aliases = {
fetchScript = ''
kv_get "/infra/private-mail-aliases" | jq .data.data | jq -r 'to_entries|map("\(.key) \(.value.to)")[]' > "$secretFile"
'';
};
chaos_mail_passwd = {
user = "dovecot2";
group = "dovecot2";
fetchScript = ''
password=$(simple_get "/passwords/mail" .password)
htpasswd -nbB "" "$password" 2>/dev/null | cut -d: -f2 > "$secretFile"
'';
};
system_mail_passwd = {
user = "dovecot2";
group = "dovecot2";
fetchScript = ''
password=$(simple_get "/api-keys/chaos_mail/system" .password)
htpasswd -nbB "" "$password" 2>/dev/null | cut -d: -f2 > "$secretFile"
'';
};
gotosocial_mail_passwd = {
user = "dovecot2";
group = "dovecot2";
fetchScript = ''
password=$(simple_get "/api-keys/chaos_mail/gotosocial" .password)
htpasswd -nbB "" "$password" 2>/dev/null | cut -d: -f2 > "$secretFile"
'';
};
};
};
}

View file

@ -17,7 +17,6 @@ in {
(forEach [
"storage"
"mail"
] (name: ./containers + "/${name}/${name}.nix"))
(with hosts.hetzner-arm.profiles; [