add caldav/carddav server & redo some htpasswd stuff
This commit is contained in:
parent
ab830d4469
commit
65165b4a9d
3
home/apps/thunderbird.nix
Normal file
3
home/apps/thunderbird.nix
Normal file
|
@ -0,0 +1,3 @@
|
|||
{pkgs, ...}: {
|
||||
home.packages = with pkgs; [thunderbird];
|
||||
}
|
58
hosts/hetzner-arm/containers/caldav/default.nix
Normal file
58
hosts/hetzner-arm/containers/caldav/default.nix
Normal file
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
self,
|
||||
hostPath,
|
||||
tree,
|
||||
inputs,
|
||||
config,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
|
||||
hostIP = containerAddresses.host;
|
||||
containerIP = containerAddresses.containers.caldav;
|
||||
in {
|
||||
containers.caldav = {
|
||||
autoStart = true;
|
||||
privateNetwork = true;
|
||||
hostAddress = hostIP;
|
||||
localAddress = containerIP;
|
||||
|
||||
specialArgs = {
|
||||
inherit inputs;
|
||||
inherit tree;
|
||||
inherit self;
|
||||
inherit hostPath;
|
||||
};
|
||||
|
||||
config = {...}: {
|
||||
nixpkgs.pkgs = pkgs;
|
||||
|
||||
imports = with tree;
|
||||
[
|
||||
presets.nixos.containerBase
|
||||
./secrets.nix
|
||||
|
||||
#./profiles/postgres.nix
|
||||
#./profiles/restic.nix
|
||||
]
|
||||
++ (with hosts.hetzner-arm.containers.caldav.profiles; [
|
||||
radicale
|
||||
restic
|
||||
]);
|
||||
|
||||
networking.firewall.allowedTCPPorts = [5232];
|
||||
|
||||
home-manager.users.root.home.stateVersion = "23.05";
|
||||
system.stateVersion = "23.05";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
virtualHosts."radicale.owo.monster" = {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/".proxyPass = "http://${containerIP}:5232";
|
||||
};
|
||||
};
|
||||
}
|
31
hosts/hetzner-arm/containers/caldav/profiles/radicale.nix
Normal file
31
hosts/hetzner-arm/containers/caldav/profiles/radicale.nix
Normal file
|
@ -0,0 +1,31 @@
|
|||
{config, ...}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
services.radicale = {
|
||||
enable = true;
|
||||
settings = {
|
||||
server = {
|
||||
hosts = ["0.0.0.0:5232" "[::]:5232"];
|
||||
};
|
||||
auth = {
|
||||
type = "htpasswd";
|
||||
htpasswd_filename = "${secrets.radicale_htpasswd.path}";
|
||||
htpasswd_encryption = "bcrypt";
|
||||
};
|
||||
rights = {
|
||||
type = "owner_only";
|
||||
};
|
||||
storage = {
|
||||
filesystem_folder = "/var/lib/radicale/collections";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
users.users.radicale.uid = 1000;
|
||||
users.groups.radicale.gid = 1000;
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/radicale - radicale radicale"
|
||||
"d /var/lib/radicale/collections - radicale radicale"
|
||||
];
|
||||
}
|
39
hosts/hetzner-arm/containers/caldav/profiles/restic.nix
Normal file
39
hosts/hetzner-arm/containers/caldav/profiles/restic.nix
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
restic
|
||||
(pkgs.writeShellScriptBin "restic-caldav" ''
|
||||
env \
|
||||
RESTIC_PASSWORD_FILE=${secrets.restic_password.path} \
|
||||
$(cat ${secrets.restic_env.path}) \
|
||||
${pkgs.restic}/bin/restic $@
|
||||
'')
|
||||
];
|
||||
|
||||
services.restic.backups.caldav = {
|
||||
user = "root";
|
||||
paths = [
|
||||
"/var/lib/radicale"
|
||||
];
|
||||
|
||||
# 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/CalDAV";
|
||||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = [
|
||||
"--keep-last 50"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "4h";
|
||||
};
|
||||
};
|
||||
}
|
60
hosts/hetzner-arm/containers/caldav/secrets.nix
Normal file
60
hosts/hetzner-arm/containers/caldav/secrets.nix
Normal file
|
@ -0,0 +1,60 @@
|
|||
{pkgs, ...}: {
|
||||
services.secrets = {
|
||||
enable = true;
|
||||
|
||||
packages = with pkgs; [
|
||||
apacheHttpd
|
||||
];
|
||||
|
||||
vaultLogin = {
|
||||
enable = true;
|
||||
loginUsername = "hetzner-arm-container-caldav";
|
||||
};
|
||||
|
||||
autoSecrets = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
requiredVaultPaths = [
|
||||
"api-keys/data/caldav"
|
||||
"api-keys/data/storage/restic/CalDAV"
|
||||
"private-public-keys/data/restic/CalDAV"
|
||||
];
|
||||
|
||||
secrets = {
|
||||
vault_password = {
|
||||
manual = true;
|
||||
};
|
||||
|
||||
radicale_htpasswd = {
|
||||
user = "radicale";
|
||||
group = "radicale";
|
||||
fetchScript = ''
|
||||
if [ -f "$secretFile" ]; then
|
||||
rm "$secretFile"
|
||||
fi
|
||||
|
||||
touch "$secretFile"
|
||||
|
||||
data=$(kv_get "/api-keys/caldav" | base64)
|
||||
for username in $(echo "$data" | base64 -d | jq -r ".data.data | keys | .[]"); do
|
||||
password=$(echo "$data" | base64 -d | jq -r ".data.data.\"$username\"")
|
||||
htpasswd -bB "$secretFile" "$username" "$password" 2>/dev/null
|
||||
done
|
||||
'';
|
||||
};
|
||||
|
||||
restic_password = {
|
||||
fetchScript = ''
|
||||
simple_get "/private-public-keys/restic/CalDAV" .password > "$secretFile"
|
||||
'';
|
||||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/CalDAV" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/CalDAV" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
{pkgs, ...}: {
|
||||
{...}: {
|
||||
services.secrets = {
|
||||
enable = true;
|
||||
|
||||
|
@ -16,10 +16,6 @@
|
|||
"private-public-keys/data/restic/Forgejo"
|
||||
];
|
||||
|
||||
packages = with pkgs; [
|
||||
apacheHttpd
|
||||
];
|
||||
|
||||
secrets = {
|
||||
vault_password = {
|
||||
manual = true;
|
||||
|
@ -32,9 +28,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Forgejo" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Forgejo" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Forgejo" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Forgejo" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/Forgejo" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
@ -36,9 +36,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Mail" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Mail" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Mail" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Mail" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/Mail" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
private_mail_aliases = {
|
||||
|
|
|
@ -47,14 +47,13 @@ in {
|
|||
inherit backupPrepareCommand;
|
||||
};
|
||||
|
||||
services.postgresqlBackup = {
|
||||
services.postgreSQLRemoteBackup = {
|
||||
enable = true;
|
||||
backupAll = false;
|
||||
backupUser = "postgres";
|
||||
databases = [
|
||||
"piped"
|
||||
"gotosocial"
|
||||
"quassel"
|
||||
];
|
||||
compression = "zstd";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/PostgreSQL" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/PostgreSQL" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/PostgreSQL" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/PostgreSQL" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/PostgreSQL" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
@ -28,9 +28,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Quassel" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Quassel" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Quassel" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Quassel" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/Quassel" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,9 +31,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Social" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Social" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Social" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Social" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/Social" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
env_secrets = {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
rclone_serve_webdav_main = 4200;
|
||||
rclone_serve_webdav_media = 4201;
|
||||
rclone_serve_webdav_music_ro = 4202;
|
||||
rclone_serve_webdav_public = 4202;
|
||||
rclone_serve_webdav_uploads = 4202;
|
||||
|
||||
rclone_serve_restic_music = 4210;
|
||||
rclone_serve_restic_vault = 4211;
|
||||
|
@ -10,7 +12,9 @@
|
|||
rclone_serve_restic_postgresql = 4214;
|
||||
rclone_serve_restic_mail = 4215;
|
||||
rclone_serve_restic_forgejo = 4216;
|
||||
rclone_serve_restic_caldav = 4217;
|
||||
|
||||
rclone_serve_http_music = 4220;
|
||||
rclone_serve_http_public = 4221;
|
||||
rclone_serve_http_uploads_public = 4221;
|
||||
}
|
||||
|
|
|
@ -69,6 +69,7 @@ in {
|
|||
"/Main/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_webdav_main}";
|
||||
"/Media/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_webdav_media}";
|
||||
"/MusicRO/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_webdav_music_ro}";
|
||||
"/Uploads/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_webdav_uploads}";
|
||||
};
|
||||
extraConfig = ''
|
||||
client_max_body_size ${clientMaxBodySize};
|
||||
|
@ -81,6 +82,7 @@ in {
|
|||
locations = {
|
||||
"/Music/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_http_music}";
|
||||
"/Public/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_http_public}";
|
||||
"/Uploads/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_http_uploads_public}";
|
||||
};
|
||||
extraConfig = ''
|
||||
client_max_body_size ${clientMaxBodySize};
|
||||
|
@ -98,6 +100,7 @@ in {
|
|||
"/PostgreSQL/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_postgresql}";
|
||||
"/Mail/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_mail}";
|
||||
"/Forgejo/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_forgejo}";
|
||||
"/CalDAV/".proxyPass = "http://${containerIP}:${toString ports.rclone_serve_restic_caldav}";
|
||||
};
|
||||
extraConfig = ''
|
||||
client_max_body_size ${clientMaxBodySize};
|
||||
|
|
|
@ -56,6 +56,27 @@ in {
|
|||
"--baseurl=/MusicRO/"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "public";
|
||||
remote = "StorageBox:Public";
|
||||
type = "webdav";
|
||||
extraArgs = [
|
||||
"--addr=0.0.0.0:${toString ports.rclone_serve_webdav_public}"
|
||||
"--htpasswd=${secrets.webdav_media_htpasswd.path}"
|
||||
"--baseurl=/Public/"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "uploads";
|
||||
remote = "StorageBox:Uploads";
|
||||
type = "webdav";
|
||||
extraArgs = [
|
||||
"--addr=0.0.0.0:${toString ports.rclone_serve_webdav_uploads}"
|
||||
"--htpasswd=${secrets.webdav_uploads_htpasswd.path}"
|
||||
"--baseurl=/Uploads/"
|
||||
];
|
||||
}
|
||||
|
||||
{
|
||||
id = "music-ro";
|
||||
remote = "StorageBox:Music";
|
||||
|
@ -76,6 +97,16 @@ in {
|
|||
"--read-only"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "uploads-public";
|
||||
remote = "StorageBox:Uploads/Public";
|
||||
type = "http";
|
||||
extraArgs = [
|
||||
"--addr=0.0.0.0:${toString ports.rclone_serve_http_uploads_public}"
|
||||
"--baseurl=/Uploads/"
|
||||
"--read-only"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "restic-music";
|
||||
remote = "StorageBox:Backups/Restic/Music";
|
||||
|
@ -126,6 +157,16 @@ in {
|
|||
"--baseurl=/PostgreSQL/"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "restic-caldav";
|
||||
remote = "StorageBox:Backups/Restic/CalDAV";
|
||||
type = "restic";
|
||||
extraArgs = [
|
||||
"--addr=0.0.0.0:${toString ports.rclone_serve_restic_caldav}"
|
||||
"--htpasswd=${secrets.restic_caldav_htpasswd.path}"
|
||||
"--baseurl=/CalDAV/"
|
||||
];
|
||||
}
|
||||
{
|
||||
id = "restic-mail";
|
||||
remote = "StorageBox:Backups/Restic/Mail";
|
||||
|
|
|
@ -31,9 +31,11 @@
|
|||
"api-keys/data/storage/restic/PostgreSQL"
|
||||
"api-keys/data/storage/restic/Mail"
|
||||
"api-keys/data/storage/restic/Forgejo"
|
||||
"api-keys/data/storage/restic/CalDAV"
|
||||
|
||||
"api-keys/data/storage/webdav/main"
|
||||
"api-keys/data/storage/webdav/media"
|
||||
"api-keys/data/storage/webdav/Main"
|
||||
"api-keys/data/storage/webdav/Media"
|
||||
"api-keys/data/storage/webdav/Public"
|
||||
|
||||
"private-public-keys/data/rclone/Chaos-Media-Crypt"
|
||||
];
|
||||
|
@ -75,36 +77,46 @@
|
|||
sed -i "s/$replace_password/$password/" "$3"
|
||||
sed -i "s/$replace_salt/$salt/" "$3"
|
||||
}
|
||||
|
||||
simple_get_htpasswd() {
|
||||
if [ -f "$2" ]; then
|
||||
rm "$2"
|
||||
fi
|
||||
|
||||
touch "$2"
|
||||
|
||||
data=$(kv_get "$1" | base64)
|
||||
for username in $(echo "$data" | base64 -d | jq -r ".data.data | keys | .[]"); do
|
||||
password=$(echo "$data" | base64 -d | jq -r ".data.data.\"$username\"")
|
||||
htpasswd -b "$2" "$username" "$password" 2>/dev/null
|
||||
done
|
||||
}
|
||||
'';
|
||||
|
||||
secrets = {
|
||||
vault_password = {manual = true;};
|
||||
vault_password = {
|
||||
manual = true;
|
||||
};
|
||||
|
||||
restic_music_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Music" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Music" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Music" "$secretFile"
|
||||
'';
|
||||
};
|
||||
restic_vault_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Vault" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Vault" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Vault" "$secretFile"
|
||||
'';
|
||||
};
|
||||
restic_social_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Social" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Social" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Social" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -112,9 +124,7 @@
|
|||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Quassel" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Quassel" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Quassel" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -122,9 +132,7 @@
|
|||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/PostgreSQL" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/PostgreSQL" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/PostgreSQL" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -132,9 +140,7 @@
|
|||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Mail" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Mail" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Mail" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -142,9 +148,15 @@
|
|||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/restic/Forgejo" .username)
|
||||
password=$(simple_get "/api-keys/storage/restic/Forgejo" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/restic/Forgejo" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
restic_caldav_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
simple_get_htpasswd "/api-keys/storage/restic/CalDAV" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
@ -152,18 +164,28 @@
|
|||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/webdav/main" .username)
|
||||
password=$(simple_get "/api-keys/storage/webdav/main" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/webdav/Main" "$secretFile"
|
||||
'';
|
||||
};
|
||||
webdav_media_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/storage/webdav/media" .username)
|
||||
password=$(simple_get "/api-keys/storage/webdav/media" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
simple_get_htpasswd "/api-keys/storage/webdav/Media" "$secretFile"
|
||||
'';
|
||||
};
|
||||
webdav_public_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
simple_get_htpasswd "/api-keys/storage/webdav/Public" "$secretFile"
|
||||
'';
|
||||
};
|
||||
webdav_uploads_htpasswd = {
|
||||
user = "storage";
|
||||
group = "storage";
|
||||
fetchScript = ''
|
||||
simple_get_htpasswd "/api-keys/storage/webdav/Uploads" "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
@ -8,5 +8,6 @@
|
|||
forgejo = "10.0.1.6";
|
||||
postgresql = "10.0.1.7";
|
||||
piped-fi = "10.0.1.8";
|
||||
caldav = "10.0.1.9";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ in {
|
|||
"piped-fi"
|
||||
"mail"
|
||||
"forgejo"
|
||||
"caldav"
|
||||
] (name: ./containers + "/${name}"))
|
||||
++ (with hosts.hetzner-arm.profiles; [
|
||||
staticSites
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
restic_music_env = {
|
||||
user = "chaos";
|
||||
fetchScript = ''
|
||||
api_username=$(simple_get "/api-keys/storage/restic/Music" .username)
|
||||
api_password=$(simple_get "/api-keys/storage/restic/Music" .password)
|
||||
api_username=restic
|
||||
api_password=$(simple_get "/api-keys/storage/restic/Music" ".$api_username")
|
||||
restic_password=$(simple_get "/private-public-keys/restic/Music" .password)
|
||||
|
||||
echo > "$secretFile"
|
||||
echo "RESTIC_REPOSITORY=rest:https://''${api_username}:''${api_password}@storage-restic.owo.monster/Music" >> "$secretFile"
|
||||
echo "RESTIC_REPOSITORY=rest:https://$api_username:$api_password@storage-restic.owo.monster/Music" >> "$secretFile"
|
||||
echo "RESTIC_PASSWORD=''${restic_password}" >> "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
tree.modules.nixos.rcloneServe
|
||||
tree.modules.nixos.rcloneSync
|
||||
tree.modules.nixos.secrets
|
||||
tree.modules.nixos.postgreSQLRemoteBackup
|
||||
];
|
||||
|
||||
nixosUnstableSystem = nixpkgs-unstable.lib.nixosSystem;
|
||||
|
|
|
@ -65,9 +65,8 @@
|
|||
};
|
||||
restic_env = {
|
||||
fetchScript = ''
|
||||
RESTIC_USERNAME=$(simple_get "/api-keys/storage/restic/Vault" .username)
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Vault" .password)
|
||||
echo "RESTIC_REPOSITORY=rest:https://$RESTIC_USERNAME:$RESTIC_PASSWORD@storage-restic.owo.monster/Vault" > "$secretFile"
|
||||
RESTIC_PASSWORD=$(simple_get "/api-keys/storage/restic/Vault" .restic)
|
||||
echo "RESTIC_REPOSITORY=rest:https://restic:$RESTIC_PASSWORD@storage-restic.owo.monster/Vault" > "$secretFile"
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
165
modules/nixos/postgreSQLRemoteBackup.nix
Normal file
165
modules/nixos/postgreSQLRemoteBackup.nix
Normal file
|
@ -0,0 +1,165 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (builtins) listToAttrs getAttr;
|
||||
inherit (lib.modules) mkIf mkMerge;
|
||||
inherit (lib.options) mkOption mkEnableOption mdDoc;
|
||||
inherit (lib.strings) optionalString;
|
||||
inherit (lib.attrsets) attrValues;
|
||||
inherit (lib) types;
|
||||
|
||||
cfg = config.services.postgreSQLRemoteBackup;
|
||||
in {
|
||||
options = {
|
||||
# TODO: add host, port, user options
|
||||
services.postgreSQLRemoteBackup = {
|
||||
enable = mkEnableOption (mdDoc "PostgreSQL database dumps");
|
||||
|
||||
keepPrev = mkOption {
|
||||
default = true;
|
||||
type = types.bool;
|
||||
description = mdDoc ''
|
||||
Keep the previous run's backups but rename them to $name.prev
|
||||
'';
|
||||
};
|
||||
|
||||
startAt = mkOption {
|
||||
default = "4h";
|
||||
type = with types; either (listOf str) str;
|
||||
description = mdDoc ''
|
||||
This option defines (see `systemd.time` for format) when the
|
||||
databases should be dumped.
|
||||
The default is run every 4 hours.
|
||||
'';
|
||||
};
|
||||
|
||||
backupUser = mkOption {
|
||||
default = "root";
|
||||
type = types.str;
|
||||
description = mdDoc ''
|
||||
User which will be used for backup job and files
|
||||
'';
|
||||
};
|
||||
|
||||
databases = mkOption {
|
||||
default = [];
|
||||
type = types.listOf types.str;
|
||||
description = mdDoc ''
|
||||
List of database names to dump.
|
||||
'';
|
||||
};
|
||||
|
||||
location = mkOption {
|
||||
default = "/var/backup/postgresql";
|
||||
type = types.path;
|
||||
description = mdDoc ''
|
||||
Path of directory where the PostgreSQL database dumps will be placed.
|
||||
'';
|
||||
};
|
||||
|
||||
pgdumpOptions = mkOption {
|
||||
type = types.separatedString " ";
|
||||
default = "-C";
|
||||
description = mdDoc ''
|
||||
Command line options for pg_dump.
|
||||
'';
|
||||
};
|
||||
|
||||
compression = mkOption {
|
||||
type = types.enum ["none" "zstd"];
|
||||
default = "zstd";
|
||||
description = mdDoc ''
|
||||
The type of compression to use on the generated database dump.
|
||||
'';
|
||||
};
|
||||
|
||||
compressionLevel = mkOption {
|
||||
type = types.int;
|
||||
default = 9;
|
||||
description = mdDoc ''
|
||||
The compression level used when compression is enabled.
|
||||
zstd accepts levels 1 to 19.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkMerge [
|
||||
(mkIf cfg.enable {
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.location}' 0700 ${cfg.backupUser} - - -"
|
||||
];
|
||||
})
|
||||
(mkIf (cfg.enable) {
|
||||
systemd.services = listToAttrs (map (db: {
|
||||
name = "remotePostgreSQLBackup-${db}";
|
||||
value = let
|
||||
compressSuffixes = {
|
||||
"none" = "";
|
||||
"zstd" = ".zstd";
|
||||
};
|
||||
compressSuffix = getAttr cfg.compression compressSuffixes;
|
||||
|
||||
compressCmd = getAttr cfg.compression {
|
||||
"none" = "cat";
|
||||
"zstd" = "${pkgs.zstd}/bin/zstd -c -${toString cfg.compressionLevel}";
|
||||
};
|
||||
|
||||
mkSqlPath = prefix: suffix: "${cfg.location}/${db}${prefix}.sql${suffix}";
|
||||
curFile = mkSqlPath "" compressSuffix;
|
||||
prevFile = mkSqlPath ".prev" compressSuffix;
|
||||
prevFiles = map (mkSqlPath ".prev") (attrValues compressSuffixes);
|
||||
inProgressFile = mkSqlPath ".in-progress" compressSuffix;
|
||||
in {
|
||||
enable = true;
|
||||
|
||||
description = "Backup of ${db} database(s)";
|
||||
|
||||
requires = mkIf (config.services.postgresql.enable) [
|
||||
"postgresql.service"
|
||||
];
|
||||
|
||||
path = [
|
||||
pkgs.coreutils
|
||||
(let
|
||||
pgCfg = config.services.postgresql;
|
||||
in
|
||||
if pgCfg.enable
|
||||
then pgCfg.package
|
||||
else pkgs.postgresql)
|
||||
];
|
||||
|
||||
script = ''
|
||||
set -e -o pipefail
|
||||
|
||||
umask 0077 # ensure backup is only readable by backup user
|
||||
|
||||
${optionalString (cfg.keepPrev) ''
|
||||
if [ -e ${curFile} ]; then
|
||||
rm -f ${toString prevFiles}
|
||||
mv ${curFile} ${prevFile}
|
||||
fi
|
||||
''}
|
||||
|
||||
pg_dump ${cfg.pgdumpOptions} ${db} \
|
||||
| ${compressCmd} \
|
||||
> ${inProgressFile}
|
||||
|
||||
mv ${inProgressFile} ${curFile}
|
||||
'';
|
||||
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = cfg.backupUser;
|
||||
};
|
||||
|
||||
startAt = cfg.startAt;
|
||||
};
|
||||
})
|
||||
cfg.databases);
|
||||
})
|
||||
];
|
||||
}
|
|
@ -141,7 +141,7 @@ in
|
|||
# All machines/containers with secrets.nix
|
||||
machines = rec {
|
||||
"hetzner-arm" = {
|
||||
containers = ["storage" "music" "quassel" "social" "mail" "postgresql" "piped-fi" "forgejo"];
|
||||
containers = ["storage" "music" "quassel" "social" "mail" "postgresql" "piped-fi" "forgejo" "caldav"];
|
||||
sshAddress = "hetzner-arm.servers.genderfucked.monster";
|
||||
};
|
||||
"vault" = {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
modules.nixos.rcloneServe
|
||||
modules.nixos.rcloneSync
|
||||
modules.nixos.secrets
|
||||
modules.nixos.postgreSQLRemoteBackup
|
||||
])
|
||||
++ [
|
||||
# Default modules which are usually included in nixos.nix
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
home.apps.firefox
|
||||
home.apps.telegram
|
||||
home.apps.thunderbird
|
||||
home.apps.quassel
|
||||
home.apps.session
|
||||
home.apps.toot-cli
|
||||
|
|
|
@ -22,8 +22,7 @@ in {
|
|||
config = {
|
||||
allowUnfree = true;
|
||||
|
||||
permittedInsecurePackages = [
|
||||
];
|
||||
permittedInsecurePackages = [];
|
||||
};
|
||||
overlays = [
|
||||
(import ../../overlay)
|
||||
|
|
Loading…
Reference in a new issue