Compare commits
No commits in common. "bde2d41b9fd18706160701bf2f857fd399d7d929" and "e597fde1367d9f047013fbae55173934f333135c" have entirely different histories.
bde2d41b9f
...
e597fde136
|
@ -1,28 +0,0 @@
|
|||
rec {
|
||||
restic = let
|
||||
OnStartupSec = "5m";
|
||||
in {
|
||||
low = {
|
||||
inherit OnStartupSec;
|
||||
OnUnitActiveSec = "12h";
|
||||
};
|
||||
medium = {
|
||||
inherit OnStartupSec;
|
||||
OnUnitActiveSec = "8h";
|
||||
};
|
||||
high = {
|
||||
inherit OnStartupSec;
|
||||
OnUnitActiveSec = "2h";
|
||||
};
|
||||
};
|
||||
|
||||
music = {
|
||||
OnStartupSec = "2m";
|
||||
OnUnitActiveSec = "2h";
|
||||
};
|
||||
|
||||
remoteBackups = {
|
||||
OnStartupSec = "30m"; # Should give enough time for all to sync current data
|
||||
OnUnitActiveSec = "1h20m"; # Should give enough time to make small incremental syncs
|
||||
};
|
||||
}
|
72
flake.lock
72
flake.lock
|
@ -21,11 +21,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709126324,
|
||||
"narHash": "sha256-q6EQdSeUZOG26WelxqkmR7kArjgWCdw5sfJVHPH/7j8=",
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "d465f4819400de7c8d874d50b982301f28a84605",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -45,11 +45,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709205246,
|
||||
"narHash": "sha256-dcUTJq/zSt7Yl+9hrVDbyE25G/eoJEE9pyU51heH0XE=",
|
||||
"lastModified": 1705410953,
|
||||
"narHash": "sha256-c0IUoRKt5k2EprCbccRF7ohWEHlGTppalXAC6ZKpoNk=",
|
||||
"ref": "refs/heads/hungy",
|
||||
"rev": "a04c1a7e369c62cf288f49a6ead8685d0847dadb",
|
||||
"revCount": 59,
|
||||
"rev": "db36355ce9eba4d0898ebd2490b5b35b923ac72e",
|
||||
"revCount": 58,
|
||||
"type": "git",
|
||||
"url": "https://forgejo.owo.monster/chaos/food-site"
|
||||
},
|
||||
|
@ -65,11 +65,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709204054,
|
||||
"narHash": "sha256-U1idK0JHs1XOfSI1APYuXi4AEADf+B+ZU4Wifc0pBHk=",
|
||||
"lastModified": 1707175763,
|
||||
"narHash": "sha256-0MKHC6tQ4KEuM5rui6DjKZ/VNiSANB4E+DJ/+wPS1PU=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "2f3367769a93b226c467551315e9e270c3f78b15",
|
||||
"rev": "f99eace7c167b8a6a0871849493b1c613d0f1b80",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -89,11 +89,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709205322,
|
||||
"narHash": "sha256-UVtyjlG2hTJ/yC2PS02RHkmcWJoklEavI0pmk5zbBlI=",
|
||||
"lastModified": 1705410918,
|
||||
"narHash": "sha256-sSxVbpl0qW2Nd+iZXqurZoYoiZpHnaNy8R6h5hWyh64=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "277a37a66a4f75793853f01953c52f6ac16ee733",
|
||||
"revCount": 118,
|
||||
"rev": "d6359a1af8bed495482137dd9908e7407b8444db",
|
||||
"revCount": 117,
|
||||
"type": "git",
|
||||
"url": "https://forgejo.owo.monster/chaos/musicutil"
|
||||
},
|
||||
|
@ -115,11 +115,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709193210,
|
||||
"narHash": "sha256-gVRsIOcfo0em0TbL8HiMmVdK8bQx1QcBFq8OnNNfdb0=",
|
||||
"lastModified": 1707162675,
|
||||
"narHash": "sha256-ZojPqn5+cuuqCt/VVGo+uuRxYLtMomahHseFj9HB3O8=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NixOS-WSL",
|
||||
"rev": "f188d9f5ee2fdb0aa9c5624561d32da4743f2e9b",
|
||||
"rev": "4bb6b2e814be63caa115038e917c6c25b7fc2ac1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -130,11 +130,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709150264,
|
||||
"narHash": "sha256-HofykKuisObPUfj0E9CJVfaMhawXkYx3G8UIFR/XQ38=",
|
||||
"lastModified": 1705133751,
|
||||
"narHash": "sha256-rCIsyE80jgiOU78gCWN3A0wE0tR2GI5nH6MlS+HaaSQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9099616b93301d5cf84274b184a3a5ec69e94e08",
|
||||
"rev": "9b19f5e77dd906cb52dade0b7bd280339d2a1f3d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -146,11 +146,11 @@
|
|||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1709150264,
|
||||
"narHash": "sha256-HofykKuisObPUfj0E9CJVfaMhawXkYx3G8UIFR/XQ38=",
|
||||
"lastModified": 1707092692,
|
||||
"narHash": "sha256-ZbHsm+mGk/izkWtT4xwwqz38fdlwu7nUUKXTOmm4SyE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9099616b93301d5cf84274b184a3a5ec69e94e08",
|
||||
"rev": "faf912b086576fd1a15fca610166c98d47bc667e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -162,11 +162,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1709150264,
|
||||
"narHash": "sha256-HofykKuisObPUfj0E9CJVfaMhawXkYx3G8UIFR/XQ38=",
|
||||
"lastModified": 1705133751,
|
||||
"narHash": "sha256-rCIsyE80jgiOU78gCWN3A0wE0tR2GI5nH6MlS+HaaSQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9099616b93301d5cf84274b184a3a5ec69e94e08",
|
||||
"rev": "9b19f5e77dd906cb52dade0b7bd280339d2a1f3d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -178,11 +178,11 @@
|
|||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1709150264,
|
||||
"narHash": "sha256-HofykKuisObPUfj0E9CJVfaMhawXkYx3G8UIFR/XQ38=",
|
||||
"lastModified": 1705133751,
|
||||
"narHash": "sha256-rCIsyE80jgiOU78gCWN3A0wE0tR2GI5nH6MlS+HaaSQ=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9099616b93301d5cf84274b184a3a5ec69e94e08",
|
||||
"rev": "9b19f5e77dd906cb52dade0b7bd280339d2a1f3d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -194,11 +194,11 @@
|
|||
},
|
||||
"nur": {
|
||||
"locked": {
|
||||
"lastModified": 1709203535,
|
||||
"narHash": "sha256-yQMygggtUJ8R8gtejfTupY/F9kXJ/YcXLEKbpSoR0p4=",
|
||||
"lastModified": 1707403461,
|
||||
"narHash": "sha256-obSWLYqen4I/jArO04QLAKT2DZSLksCiskmeDRgS3bM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "NUR",
|
||||
"rev": "2b3b8752d1bd83b66b38163685f686ba8f3d1924",
|
||||
"rev": "9621e2bfc47bbfe644c0f9f64b1aa44dec1f3afc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -283,11 +283,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709205238,
|
||||
"narHash": "sha256-tT/k9ad0RkQ8P6wjKZVp+iuCWXiW9OVDccocW8eTWxM=",
|
||||
"lastModified": 1705413365,
|
||||
"narHash": "sha256-C3CvdCebHM5RiGrRF4WGQLisQ0FYrPPeJBbCWNxHGAI=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "9d86d2d6d01c93e8d60d456028ac74597c7b5eaf",
|
||||
"revCount": 465,
|
||||
"rev": "ea11dd6514c51d524b5cdded260a4632c5cf3c9c",
|
||||
"revCount": 464,
|
||||
"type": "git",
|
||||
"url": "https://forgejo.owo.monster/chaos/VaultUI"
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{...}: {
|
||||
{nixosConfig, ...}: {
|
||||
wayland.windowManager.sway.extraSessionCommands = ''
|
||||
export KITTY_CACHE_DIRECTORY="/tmp/kitty";
|
||||
'';
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
@ -29,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 50"];
|
||||
timerConfig = backupSchedules.restic.high;
|
||||
pruneOpts = [
|
||||
"--keep-last 50"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "4h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
@ -29,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 50"];
|
||||
timerConfig = backupSchedules.restic.high;
|
||||
pruneOpts = [
|
||||
"--keep-last 50"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "4h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
restic
|
||||
|
@ -29,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 30"];
|
||||
timerConfig = backupSchedules.restic.high;
|
||||
pruneOpts = [
|
||||
"--keep-last 5"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "10m";
|
||||
OnCalendar = "8h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
restic
|
||||
|
@ -29,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 10"];
|
||||
timerConfig = backupSchedules.restic.low;
|
||||
pruneOpts = [
|
||||
"--keep-last 5"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "10m";
|
||||
OnCalendar = "8h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
secrets = config.services.secrets.secrets;
|
||||
|
||||
mailConfig = config.services.mailserver;
|
||||
|
@ -33,7 +31,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 60"];
|
||||
timerConfig = backupSchedules.restic.medium;
|
||||
pruneOpts = [
|
||||
"--keep-last 100"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "8h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
pathInContainer = path: "/var/lib/nixos-containers/${containerName}" + path;
|
||||
in {
|
||||
nixpkgs.overlays = [
|
||||
(final: _prev: {
|
||||
(final: prev: {
|
||||
mpd = final.mpd-headless;
|
||||
})
|
||||
];
|
||||
|
@ -58,7 +58,7 @@ in {
|
|||
++ (with hosts.hetzner-arm.containers.music.profiles; [
|
||||
mpd
|
||||
musicSync
|
||||
#soulseek # takes up too much ram :(
|
||||
#soulseek
|
||||
]);
|
||||
|
||||
networking.firewall.allowedTCPPorts = with ports; [
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
{pkgs, ...}: let
|
||||
inherit (pkgs) writeShellScriptBin;
|
||||
inherit (builtins) toFile;
|
||||
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
|
||||
rcloneConfig = toFile "rclone.conf" ''
|
||||
[Music]
|
||||
type = webdav
|
||||
|
@ -43,7 +37,7 @@ in {
|
|||
systemd.timers.music-sync = {
|
||||
wantedBy = ["timers.target"];
|
||||
partOf = ["music-sync.service"];
|
||||
timerConfig = backupSchedules.music;
|
||||
timerConfig.OnCalendar = "hourly";
|
||||
};
|
||||
|
||||
systemd.services.mpd = {
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
@ -29,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 5"];
|
||||
timerConfig = backupSchedules.restic.low;
|
||||
pruneOpts = [
|
||||
"--keep-last 5"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "10m";
|
||||
OnCalendar = "8h";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{...}: {
|
||||
{pkgs, ...}: {
|
||||
services.secrets = {
|
||||
enable = true;
|
||||
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
{hostPath, ...}: let
|
||||
#wireguardData = import "${self}/data/wireguard/chaosInternalWireGuard.nix";
|
||||
#wireguardHosts = wireguardData.hosts;
|
||||
{
|
||||
self,
|
||||
hostPath,
|
||||
...
|
||||
}: let
|
||||
wireguardData = import "${self}/data/wireguard/chaosInternalWireGuard.nix";
|
||||
wireguardHosts = wireguardData.hosts;
|
||||
|
||||
localContainersAddresses = import "${hostPath}/data/containerAddresses.nix";
|
||||
in {
|
||||
services.postgresql = {
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
|
||||
backupPrepareCommand = "${
|
||||
(pkgs.writeShellScriptBin "backupPrepareCommand" ''
|
||||
|
@ -36,8 +34,14 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 10"];
|
||||
timerConfig = backupSchedules.restic.high;
|
||||
pruneOpts = [
|
||||
"--keep-last 5"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "daily";
|
||||
};
|
||||
|
||||
inherit backupPrepareCommand;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
|
@ -20,8 +18,6 @@ in {
|
|||
services.restic.backups.quassel = {
|
||||
user = "root";
|
||||
paths = [
|
||||
# it's only backing up initial setup / credentials
|
||||
# so no matter what DB is restored to it should work
|
||||
"/home/quassel/.config/quassel-irc.org"
|
||||
];
|
||||
|
||||
|
@ -31,7 +27,13 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 5"];
|
||||
timerConfig = backupSchedules.restic.low;
|
||||
pruneOpts = [
|
||||
"--keep-last 5"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "daily";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
|
||||
# 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
|
||||
|
@ -57,9 +55,14 @@ in {
|
|||
passwordFile = "${secrets.restic_password.path}";
|
||||
environmentFile = "${secrets.restic_env.path}";
|
||||
|
||||
pruneOpts = ["--keep-last 10"];
|
||||
# Don't want to cause too much downtime and take too long to prune media
|
||||
timerConfig = backupSchedules.restic.medium;
|
||||
pruneOpts = [
|
||||
"--keep-last 10"
|
||||
];
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "daily";
|
||||
};
|
||||
|
||||
inherit backupPrepareCommand;
|
||||
inherit backupCleanupCommand;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
{self, ...}: let
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
in {
|
||||
{...}: {
|
||||
services.rclone-sync = {
|
||||
enable = true;
|
||||
user = "storage";
|
||||
|
@ -11,7 +9,10 @@ in {
|
|||
after = ["auto-secrets.service"];
|
||||
wants = ["auto-secrets.service"];
|
||||
};
|
||||
timerConfig = backupSchedules.remoteBackups;
|
||||
timerConfig = {
|
||||
OnStartupSec = "120";
|
||||
OnCalendar = "4h";
|
||||
};
|
||||
extraArgs = [
|
||||
"--fast-list"
|
||||
"--check-first"
|
||||
|
|
9
hosts/hetzner-arm/containers/stream/music/data/ports.nix
Normal file
9
hosts/hetzner-arm/containers/stream/music/data/ports.nix
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
mpd = 6600;
|
||||
mpd-opus-low = 4242;
|
||||
mpd-opus-medium = 4243;
|
||||
mpd-opus-high = 4244;
|
||||
mpd-flac = 4245;
|
||||
slskd = 5000;
|
||||
slskd-web = 5001;
|
||||
}
|
123
hosts/hetzner-arm/containers/stream/music/default.nix
Normal file
123
hosts/hetzner-arm/containers/stream/music/default.nix
Normal file
|
@ -0,0 +1,123 @@
|
|||
{
|
||||
self,
|
||||
hostPath,
|
||||
tree,
|
||||
lib,
|
||||
inputs,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.modules) mkMerge;
|
||||
inherit (lib.lists) forEach;
|
||||
|
||||
containerName = "music";
|
||||
|
||||
containerAddresses = import "${hostPath}/data/containerAddresses.nix";
|
||||
|
||||
hostIP = containerAddresses.host;
|
||||
containerIP = containerAddresses.containers.${containerName};
|
||||
|
||||
ports = import ./data/ports.nix;
|
||||
|
||||
# these secrets should probs be in host but im lazy
|
||||
containerSecrets = config.containers.${containerName}.config.services.secrets.secrets;
|
||||
pathInContainer = path: "/var/lib/nixos-containers/${containerName}" + path;
|
||||
in {
|
||||
containers.music = {
|
||||
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
|
||||
|
||||
profiles.nginx
|
||||
profiles.firewallAllow.httpCommon
|
||||
|
||||
./secrets.nix
|
||||
]
|
||||
++ (with hosts.hetzner-arm.containers.music.profiles; [
|
||||
mpd
|
||||
musicSync
|
||||
soulseek
|
||||
]);
|
||||
|
||||
networking.firewall.allowedTCPPorts = with ports; [
|
||||
mpd
|
||||
mpd-opus-low
|
||||
mpd-opus-medium
|
||||
mpd-opus-high
|
||||
mpd-flac
|
||||
slskd
|
||||
slskd-web
|
||||
];
|
||||
|
||||
home-manager.users.root.home.stateVersion = "23.05";
|
||||
system.stateVersion = "23.05";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."soulseek.owo.monster" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations."/" = {
|
||||
proxyPass = "http://${containerIP}:${toString ports.slskd-web}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."mpd.owo.monster" = let
|
||||
extraConfig = ''
|
||||
auth_basic "Music Password";
|
||||
auth_basic_user_file ${pathInContainer containerSecrets.music_stream_passwd.path};
|
||||
'';
|
||||
in {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
locations = mkMerge [
|
||||
{
|
||||
"/flac" = {
|
||||
proxyPass = "http://${containerIP}:${toString ports.mpd-flac}";
|
||||
inherit extraConfig;
|
||||
};
|
||||
}
|
||||
(mkMerge (forEach ["low" "medium" "high"] (quality: {
|
||||
"/opus-${quality}" = {
|
||||
proxyPass = "http://${containerIP}:${toString ports."mpd-opus-${quality}"}";
|
||||
inherit extraConfig;
|
||||
};
|
||||
})))
|
||||
];
|
||||
};
|
||||
|
||||
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
|
||||
];
|
||||
};
|
||||
}
|
69
hosts/hetzner-arm/containers/stream/music/profiles/mpd.nix
Normal file
69
hosts/hetzner-arm/containers/stream/music/profiles/mpd.nix
Normal file
|
@ -0,0 +1,69 @@
|
|||
{
|
||||
lib,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
inherit (lib.strings) concatStringsSep;
|
||||
inherit (lib.lists) forEach;
|
||||
|
||||
ports = import ../data/ports.nix;
|
||||
secrets = config.services.secrets.secrets;
|
||||
in {
|
||||
environment.systemPackages = with pkgs; [
|
||||
mpc_cli
|
||||
];
|
||||
|
||||
services.mpd = {
|
||||
enable = true;
|
||||
network.listenAddress = "0.0.0.0";
|
||||
musicDirectory = "/Music";
|
||||
credentials = [
|
||||
{
|
||||
passwordFile = "${secrets.mpd_control_password.path}";
|
||||
permissions = ["read" "add" "control" "admin"];
|
||||
}
|
||||
];
|
||||
extraConfig =
|
||||
''
|
||||
host_permissions "127.0.0.1 read,add,control,admin"
|
||||
samplerate_converter "0"
|
||||
metadata_to_use "title,artist"
|
||||
auto_update "yes"
|
||||
audio_buffer_size "4096"
|
||||
replaygain "track"
|
||||
audio_output_format "44100:16:2"
|
||||
''
|
||||
+ concatStringsSep "\n" (forEach ["low" "medium" "high"] (quality: let
|
||||
bitrates = {
|
||||
"low" = "64";
|
||||
"medium" = "96";
|
||||
"high" = "128";
|
||||
};
|
||||
bitrate = bitrates.${quality};
|
||||
in ''
|
||||
audio_output {
|
||||
type "httpd"
|
||||
name "HTTP Opus ${bitrate}k"
|
||||
encoder "opus"
|
||||
port "${toString ports."mpd-opus-${quality}"}"
|
||||
bitrate "${bitrate}000"
|
||||
format "44100:16:2"
|
||||
always_on "yes"
|
||||
tags "yes"
|
||||
signal "music"
|
||||
}
|
||||
''))
|
||||
+ ''
|
||||
audio_output {
|
||||
type "httpd"
|
||||
name "HTTP FLAC"
|
||||
encoder "flac"
|
||||
port "${toString ports.mpd-flac}"
|
||||
format "44100:16:2"
|
||||
always_on "yes"
|
||||
tags "yes"
|
||||
}
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
{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 = with pkgs; [
|
||||
rclone
|
||||
(writeShellScriptBin "rclone-music" ''
|
||||
rclone --config ${rcloneConfig} "$@"
|
||||
'')
|
||||
];
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /Music - mpd mpd"
|
||||
];
|
||||
|
||||
systemd.services.music-sync = {
|
||||
wantedBy = ["multi-user.target"];
|
||||
after = ["network.target"];
|
||||
partOf = ["mpd.service"];
|
||||
|
||||
path = with pkgs; [bash rclone];
|
||||
|
||||
script = ''
|
||||
set -e
|
||||
rclone --config ${rcloneConfig} sync Music: /Music
|
||||
chown -R mpd:mpd /Music
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.timers.music-sync = {
|
||||
wantedBy = ["timers.target"];
|
||||
partOf = ["music-sync.service"];
|
||||
timerConfig.OnCalendar = "hourly";
|
||||
};
|
||||
|
||||
systemd.services.mpd = {
|
||||
after = ["music-copy.service"];
|
||||
serviceConfig = {
|
||||
ReadOnlyPaths = "/Music";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
ports = import ../data/ports.nix;
|
||||
secrets = config.services.secrets.secrets;
|
||||
|
||||
inherit (lib.modules) mkForce;
|
||||
in {
|
||||
services.slskd = {
|
||||
enable = true;
|
||||
openFirewall = true;
|
||||
environmentFile = secrets.slskd_env.path;
|
||||
settings = {
|
||||
remote_configuration = false;
|
||||
remote_file_management = true;
|
||||
soulseek = {
|
||||
username = "chaoticryptidz";
|
||||
description = "chaos's soulseek";
|
||||
listen_port = ports.slskd;
|
||||
};
|
||||
web = {
|
||||
port = ports.slskd-web;
|
||||
authentication = {
|
||||
username = "chaos";
|
||||
};
|
||||
};
|
||||
shares.directories = [
|
||||
"/Music"
|
||||
];
|
||||
};
|
||||
nginx = {
|
||||
enable = true; # I don't think this is even cheked
|
||||
domainName = "soulseek.owo.monster";
|
||||
};
|
||||
};
|
||||
|
||||
services.nginx.virtualHosts."soulseek.owo.monster" = {
|
||||
forceSSL = mkForce false;
|
||||
enableACME = mkForce false;
|
||||
};
|
||||
}
|
57
hosts/hetzner-arm/containers/stream/music/secrets.nix
Normal file
57
hosts/hetzner-arm/containers/stream/music/secrets.nix
Normal file
|
@ -0,0 +1,57 @@
|
|||
{pkgs, ...}: {
|
||||
services.secrets = {
|
||||
enable = true;
|
||||
|
||||
vaultLogin = {
|
||||
enable = true;
|
||||
loginUsername = "hetzner-arm-container-music";
|
||||
};
|
||||
|
||||
autoSecrets = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
requiredVaultPaths = [
|
||||
"api-keys/data/mpd"
|
||||
"api-keys/data/music-stream"
|
||||
"passwords/data/soulseek"
|
||||
"passwords/data/slskd"
|
||||
];
|
||||
|
||||
packages = with pkgs; [
|
||||
apacheHttpd
|
||||
];
|
||||
|
||||
secrets = {
|
||||
vault_password = {
|
||||
manual = true;
|
||||
};
|
||||
|
||||
mpd_control_password = {
|
||||
user = "mpd";
|
||||
group = "mpd";
|
||||
fetchScript = ''
|
||||
simple_get "/api-keys/mpd" .password > "$secretFile"
|
||||
'';
|
||||
};
|
||||
music_stream_passwd = {
|
||||
user = "nginx";
|
||||
group = "nginx";
|
||||
fetchScript = ''
|
||||
username=$(simple_get "/api-keys/music-stream" .username)
|
||||
password=$(simple_get "/api-keys/music-stream" .password)
|
||||
htpasswd -bc "$secretFile" "$username" "$password" 2>/dev/null
|
||||
'';
|
||||
};
|
||||
slskd_env = {
|
||||
fetchScript = ''
|
||||
soulseek_password=$(simple_get "/passwords/soulseek" .password)
|
||||
slskd_password=$(simple_get "/passwords/slskd" .password)
|
||||
echo > "$secretFile"
|
||||
echo "SLSKD_SLSK_PASSWORD=$soulseek_password" >> "$secretFile"
|
||||
echo "SLSKD_PASSWORD=$slskd_password" >> "$secretFile"
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
{
|
||||
self,
|
||||
pkgs,
|
||||
config,
|
||||
...
|
||||
}: let
|
||||
secrets = config.services.secrets.secrets;
|
||||
backupSchedules = import "${self}/data/backupSchedules.nix";
|
||||
in {
|
||||
services.restic.backups.vault = {
|
||||
user = "root";
|
||||
|
@ -13,8 +11,10 @@ in {
|
|||
"/var/lib/vault"
|
||||
"/var/lib/private/step-ca"
|
||||
];
|
||||
timerConfig = backupSchedules.restic.high;
|
||||
|
||||
timerConfig = {
|
||||
OnBootSec = "1m";
|
||||
OnCalendar = "6h";
|
||||
};
|
||||
# env contains fixed repository with auth
|
||||
repository = "rest:https://storage-restic.owo.monster/Vault";
|
||||
passwordFile = "${secrets.restic_password.path}";
|
||||
|
|
|
@ -65,8 +65,8 @@ in {
|
|||
timerConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = {
|
||||
OnStartupSec = "1m";
|
||||
OnUnitActiveSec = "2h";
|
||||
OnStartupSec = "60";
|
||||
OnCalendar = "4h";
|
||||
};
|
||||
};
|
||||
serviceConfig = mkOption {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
inherit (lib.attrsets) mergeAttrsList recursiveUpdate;
|
||||
inherit (lib.lists) foldl' forEach filter;
|
||||
inherit (lib.strings) optionalString;
|
||||
|
||||
hosts = import ./hosts inputs;
|
||||
in
|
||||
|
|
|
@ -23,7 +23,7 @@ final: prev: rec {
|
|||
# this includes a bunch of unneeded files
|
||||
# but we cba to go through the bat file
|
||||
# the author uses to figure out what all the 7z commands do)
|
||||
grocy = prev.grocy.overrideAttrs (_old: let
|
||||
grocy = prev.grocy.overrideAttrs (old: let
|
||||
version = "4.1.0";
|
||||
hash = "";
|
||||
in rec {
|
||||
|
@ -38,6 +38,51 @@ final: prev: rec {
|
|||
patches = [./grocy-env-variables.diff];
|
||||
});
|
||||
|
||||
# Remove when fixed in upstream
|
||||
jellyfin-ffmpeg =
|
||||
(prev.ffmpeg_6-headless.override {
|
||||
withAribcaption = false; # FIXME remove when updating past version 6.1
|
||||
})
|
||||
.overrideAttrs (old: rec {
|
||||
pname = "jellyfin-ffmpeg";
|
||||
version = "6.0.1-1";
|
||||
|
||||
src = final.fetchFromGitHub {
|
||||
owner = "jellyfin";
|
||||
repo = "jellyfin-ffmpeg";
|
||||
rev = "v${version}";
|
||||
hash = "sha256-LMwGxx++z6TpZLnpeRGraid4653Mp8T4pY5EP4Z7GXY=";
|
||||
};
|
||||
|
||||
patches = [];
|
||||
|
||||
buildInputs = old.buildInputs ++ [prev.chromaprint];
|
||||
|
||||
configureFlags =
|
||||
old.configureFlags
|
||||
++ [
|
||||
"--extra-version=Jellyfin"
|
||||
"--disable-ptx-compression" # https://github.com/jellyfin/jellyfin/issues/7944#issuecomment-1156880067
|
||||
"--enable-chromaprint"
|
||||
];
|
||||
|
||||
postPatch = ''
|
||||
for file in $(cat debian/patches/series); do
|
||||
patch -p1 < debian/patches/$file
|
||||
done
|
||||
|
||||
${old.postPatch or ""}
|
||||
'';
|
||||
|
||||
meta = with final.lib; {
|
||||
description = "${old.meta.description} (Jellyfin fork)";
|
||||
homepage = "https://github.com/jellyfin/jellyfin-ffmpeg";
|
||||
license = licenses.gpl3;
|
||||
maintainers = with maintainers; [justinas];
|
||||
pkgConfigModules = ["libavutil"];
|
||||
};
|
||||
});
|
||||
|
||||
mpd-headless =
|
||||
(prev.mpdWithFeatures.override {
|
||||
ffmpeg = final.ffmpeg_6-headless;
|
||||
|
@ -77,9 +122,9 @@ final: prev: rec {
|
|||
owner = "superseriousbusiness";
|
||||
repo = "gotosocial";
|
||||
|
||||
version = "0.13.3";
|
||||
source-hash = "sha256-zjmIa25veVL0ruFow4c1oV+VtgJGgWrRL99GPdaNc4g=";
|
||||
web-assets-hash = "sha256-xC1Acm/CJHXTblV8E63vZB+r/ktBH7EytL7x4eWGko8=";
|
||||
version = "0.13.2";
|
||||
source-hash = "sha256-VQnE4Xff4gtjQ6V2B42zK8UjosBWEMgcL/3Q8S0wc5Q=";
|
||||
web-assets-hash = "sha256-Iyqn0/VyigmOhlyyz1NfvNIXmWtF617QbWzM2c7jHWw=";
|
||||
|
||||
web-assets = final.fetchurl {
|
||||
url = "https://github.com/${owner}/${repo}/releases/download/v${version}/${repo}_${version}_web-assets.tar.gz";
|
||||
|
|
|
@ -35,8 +35,8 @@ in {
|
|||
systems = ["aarch64-linux"];
|
||||
supportedFeatures = ["native-arm64"];
|
||||
publicHostKey = "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUk5cGM0REU1UlV4UUp2T1pwenFOQWVac0JlRW1kcmp4OFlnV3orVXBMckcgcm9vdEBoZXR6bmVyLWFybQo=";
|
||||
maxJobs = 2;
|
||||
speedFactor = 2;
|
||||
maxJobs = 4;
|
||||
speedFactor = 3;
|
||||
}
|
||||
]))
|
||||
(mkIf (currentHostname != "vault") (mkMerge [
|
||||
|
|
Loading…
Reference in a new issue