mirror of
https://github.com/SebastianStork/nixos-config.git
synced 2026-01-21 17:31:34 +01:00
Move modules in programs/services subfolders
This commit is contained in:
parent
2ff87c8404
commit
211ca98e92
38 changed files with 0 additions and 0 deletions
55
modules/system/services/actualbudget/backups.nix
Normal file
55
modules/system/services/actualbudget/backups.nix
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
user = config.users.users.actual.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.actualbudget.backups.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.actualbudget.backups.enable {
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
extraConfig =
|
||||
let
|
||||
service = "actual.service";
|
||||
in
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
action.lookup("unit") == "${service}" &&
|
||||
subject.user == "${user}") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
};
|
||||
|
||||
custom.services.resticBackup.actual = {
|
||||
inherit user;
|
||||
healthchecks.enable = true;
|
||||
|
||||
extraConfig = {
|
||||
backupPrepareCommand = "${lib.getExe' pkgs.systemd "systemctl"} stop actual.service";
|
||||
backupCleanupCommand = "${lib.getExe' pkgs.systemd "systemctl"} start actual.service";
|
||||
paths = [ config.services.actual.settings.dataDir ];
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "actual-restore";
|
||||
text = ''
|
||||
sudo --user=${user} bash -c "
|
||||
systemctl stop actual.service
|
||||
restic-actual restore latest --target /
|
||||
systemctl start actual.service
|
||||
"
|
||||
'';
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
38
modules/system/services/actualbudget/default.nix
Normal file
38
modules/system/services/actualbudget/default.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.actualbudget;
|
||||
in
|
||||
{
|
||||
options.custom.services.actualbudget = {
|
||||
enable = lib.mkEnableOption "";
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "";
|
||||
};
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8080;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
users.groups.actual = { };
|
||||
users.users.actual = {
|
||||
isSystemUser = true;
|
||||
group = "actual";
|
||||
};
|
||||
|
||||
services.actual = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
hostname = "localhost";
|
||||
inherit (cfg) port;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
16
modules/system/services/bluetooth.nix
Normal file
16
modules/system/services/bluetooth.nix
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
options.custom.services.bluetooth.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.bluetooth.enable {
|
||||
hardware = {
|
||||
bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
};
|
||||
logitech.wireless.enable = true;
|
||||
};
|
||||
|
||||
services.blueman.enable = true;
|
||||
};
|
||||
}
|
||||
74
modules/system/services/crowdsec/default.nix
Normal file
74
modules/system/services/crowdsec/default.nix
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
config,
|
||||
inputs,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.crowdsec;
|
||||
in
|
||||
{
|
||||
imports = [ inputs.crowdsec.nixosModules.crowdsec ];
|
||||
|
||||
options.custom.services.crowdsec = {
|
||||
enable = lib.mkEnableOption "";
|
||||
apiPort = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 8080;
|
||||
};
|
||||
sources = lib.mkOption {
|
||||
type = lib.types.listOf (
|
||||
lib.types.enum [
|
||||
"iptables"
|
||||
"caddy"
|
||||
]
|
||||
);
|
||||
default = [ ];
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
nixpkgs.overlays = [ inputs.crowdsec.overlays.default ];
|
||||
|
||||
sops.secrets."crowdsec/enrollment-key".owner = config.users.users.crowdsec.name;
|
||||
|
||||
services.crowdsec = {
|
||||
enable = true;
|
||||
package = inputs.crowdsec.packages.${pkgs.system}.crowdsec;
|
||||
enrollKeyFile = config.sops.secrets."crowdsec/enrollment-key".path;
|
||||
settings = {
|
||||
api.server.listen_uri = "127.0.0.1:${toString cfg.apiPort}";
|
||||
prometheus.enabled = false;
|
||||
};
|
||||
|
||||
acquisitions = [
|
||||
(lib.mkIf (lib.elem "iptables" cfg.sources) {
|
||||
source = "journalctl";
|
||||
journalctl_filter = [ "-k" ];
|
||||
labels.type = "syslog";
|
||||
})
|
||||
(lib.mkIf (lib.elem "caddy" cfg.sources) {
|
||||
source = "journalctl";
|
||||
journalctl_filter = [ "_SYSTEMD_UNIT=caddy.service" ];
|
||||
labels.type = "syslog";
|
||||
})
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services.crowdsec.preStart =
|
||||
let
|
||||
collections = lib.flatten [
|
||||
"crowdsecurity/linux"
|
||||
(lib.optional (lib.elem "iptables" cfg.sources) "crowdsecurity/iptables")
|
||||
(lib.optional (lib.elem "caddy" cfg.sources) "crowdsecurity/caddy")
|
||||
];
|
||||
addCollection = collection: ''
|
||||
if ! cscli collections list | grep -q "${collection}"; then
|
||||
cscli collections install ${collection}
|
||||
fi
|
||||
'';
|
||||
in
|
||||
collections |> lib.map addCollection |> lib.concatLines;
|
||||
};
|
||||
}
|
||||
32
modules/system/services/crowdsec/firewall-bouncer.nix
Normal file
32
modules/system/services/crowdsec/firewall-bouncer.nix
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
config,
|
||||
inputs,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.crowdsec;
|
||||
in
|
||||
{
|
||||
imports = [ inputs.crowdsec.nixosModules.crowdsec-firewall-bouncer ];
|
||||
|
||||
options.custom.services.crowdsec.firewallBouncer.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf cfg.firewallBouncer.enable {
|
||||
services.crowdsec-firewall-bouncer = {
|
||||
enable = true;
|
||||
package = inputs.crowdsec.packages.${pkgs.system}.crowdsec-firewall-bouncer;
|
||||
settings = {
|
||||
api_key = "cs-firewall-bouncer";
|
||||
api_url = "http://127.0.0.1:${toString cfg.apiPort}";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.crowdsec.preStart = ''
|
||||
if ! cscli bouncers list | grep -q "firewall-bouncer"; then
|
||||
cscli bouncers add "firewall-bouncer" --key "cs-firewall-bouncer"
|
||||
fi
|
||||
'';
|
||||
};
|
||||
}
|
||||
57
modules/system/services/forgejo/default.nix
Normal file
57
modules/system/services/forgejo/default.nix
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.forgejo;
|
||||
|
||||
user = config.users.users.forgejo.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.forgejo = {
|
||||
enable = lib.mkEnableOption "";
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "";
|
||||
};
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 3000;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
sops.secrets."forgejo/admin-password".owner = user;
|
||||
|
||||
services.forgejo = {
|
||||
enable = true;
|
||||
lfs.enable = true;
|
||||
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = "${cfg.subdomain}.${config.networking.domain}";
|
||||
ROOT_URL = "https://${config.services.forgejo.settings.server.DOMAIN}/";
|
||||
HTTP_PORT = cfg.port;
|
||||
};
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
|
||||
# https://forgejo.org/docs/latest/admin/recommendations
|
||||
database.SQLITE_JOURNAL_MODE = "WAL";
|
||||
cache = {
|
||||
ADAPTER = "twoqueue";
|
||||
HOST = ''{"size":100, "recent_ratio":0.25, "ghost_ratio":0.5}'';
|
||||
};
|
||||
"repository.signing".DEFAULT_TRUST_MODEL = "committer";
|
||||
security.LOGIN_REMEMBER_DAYS = 365;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.forgejo.preStart =
|
||||
let
|
||||
createCmd = "${lib.getExe config.services.forgejo.package} admin user create";
|
||||
passwordPath = config.sops.secrets."forgejo/admin-password".path;
|
||||
in
|
||||
''${createCmd} --username SebastianStork --password "$(cat ${passwordPath})" --email "sebastian.stork@pm.me" --admin || true'';
|
||||
};
|
||||
}
|
||||
15
modules/system/services/gc.nix
Normal file
15
modules/system/services/gc.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
options.custom.services.gc.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.gc.enable {
|
||||
programs.nh = {
|
||||
enable = true;
|
||||
clean = {
|
||||
enable = true;
|
||||
dates = "weekly";
|
||||
extraArgs = "--keep 10 --keep-since 7d";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
15
modules/system/services/geoclue.nix
Normal file
15
modules/system/services/geoclue.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
options.custom.services.geoclue.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.geoclue.enable {
|
||||
services.geoclue2 = {
|
||||
enable = true;
|
||||
|
||||
appConfig.gammastep = {
|
||||
isAllowed = true;
|
||||
isSystem = false;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
58
modules/system/services/hedgedoc/backups.nix
Normal file
58
modules/system/services/hedgedoc/backups.nix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
user = config.users.users.hedgedoc.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.hedgedoc.backups.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.hedgedoc.backups.enable {
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
extraConfig =
|
||||
let
|
||||
service = "hedgedoc.service";
|
||||
in
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
action.lookup("unit") == "${service}" &&
|
||||
subject.user == "${user}") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
};
|
||||
|
||||
custom.services.resticBackup.hedgedoc = {
|
||||
inherit user;
|
||||
healthchecks.enable = true;
|
||||
|
||||
extraConfig = {
|
||||
backupPrepareCommand = "${lib.getExe' pkgs.systemd "systemctl"} stop hedgedoc.service";
|
||||
backupCleanupCommand = "${lib.getExe' pkgs.systemd "systemctl"} start hedgedoc.service";
|
||||
paths = with config.services.hedgedoc.settings; [
|
||||
uploadsPath
|
||||
db.storage
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "hedgedoc-restore";
|
||||
text = ''
|
||||
sudo --user=${user} bash -c "
|
||||
systemctl stop hedgedoc.service
|
||||
restic-hedgedoc restore latest --target /
|
||||
systemctl start hedgedoc.service
|
||||
"
|
||||
'';
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
82
modules/system/services/hedgedoc/default.nix
Normal file
82
modules/system/services/hedgedoc/default.nix
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.hedgedoc;
|
||||
|
||||
user = config.users.users.hedgedoc.name;
|
||||
|
||||
manage_users = "CMD_CONFIG_FILE=/run/hedgedoc/config.json NODE_ENV=production ${lib.getExe' pkgs.hedgedoc "manage_users"}";
|
||||
in
|
||||
{
|
||||
options.custom.services.hedgedoc = {
|
||||
enable = lib.mkEnableOption "";
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "";
|
||||
};
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 3000;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
sops = {
|
||||
secrets = {
|
||||
"hedgedoc/seb-password".owner = user;
|
||||
"hedgedoc/gitlab-auth-secret".owner = user;
|
||||
};
|
||||
|
||||
templates."hedgedoc/environment" = {
|
||||
owner = user;
|
||||
content = "GITLAB_CLIENTSECRET=${config.sops.placeholder."hedgedoc/gitlab-auth-secret"}";
|
||||
};
|
||||
};
|
||||
|
||||
services.hedgedoc = {
|
||||
enable = true;
|
||||
|
||||
environmentFile = config.sops.templates."hedgedoc/environment".path;
|
||||
settings = {
|
||||
domain = "${cfg.subdomain}.${config.networking.domain}";
|
||||
inherit (cfg) port;
|
||||
protocolUseSSL = true;
|
||||
allowAnonymous = false;
|
||||
allowEmailRegister = false;
|
||||
defaultPermission = "limited";
|
||||
sessionSecret = "$SESSION_SECRET";
|
||||
gitlab = {
|
||||
baseURL = "https://code.fbi.h-da.de";
|
||||
clientID = "dc71d7ec1525ce3b425d7d41d602f67e1a06cef981259605a87841a6be62cc58";
|
||||
clientSecret = "$GITLAB_CLIENTSECRET";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.hedgedoc = {
|
||||
# Ensure session-secret
|
||||
preStart = lib.mkBefore ''
|
||||
if [ ! -f /var/lib/hedgedoc/session-secret ]; then
|
||||
${lib.getExe pkgs.pwgen} -s 64 1 > /var/lib/hedgedoc/session-secret
|
||||
fi
|
||||
export SESSION_SECRET=$(cat /var/lib/hedgedoc/session-secret)
|
||||
'';
|
||||
|
||||
postStart =
|
||||
let
|
||||
manageUserSeb =
|
||||
mode:
|
||||
"${manage_users} --${mode} sebastian.stork@pm.me --pass \"$(cat ${
|
||||
config.sops.secrets."hedgedoc/seb-password".path
|
||||
})\"";
|
||||
in
|
||||
"${manageUserSeb "add"} || ${manageUserSeb "reset"}";
|
||||
};
|
||||
|
||||
environment.shellAliases.hedgedoc-manage-users = "sudo --user=${user} ${manage_users}";
|
||||
};
|
||||
}
|
||||
49
modules/system/services/nextcloud/backups.nix
Normal file
49
modules/system/services/nextcloud/backups.nix
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.nextcloud;
|
||||
|
||||
dataDir = config.services.nextcloud.home;
|
||||
user = config.users.users.nextcloud.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.nextcloud.backups.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf cfg.backups.enable {
|
||||
custom.services.resticBackup.nextcloud = {
|
||||
inherit user;
|
||||
healthchecks.enable = true;
|
||||
|
||||
extraConfig = {
|
||||
backupPrepareCommand = ''
|
||||
${lib.getExe' config.services.nextcloud.occ "nextcloud-occ"} maintenance:mode --on
|
||||
${lib.getExe' config.services.postgresql.package "pg_dump"} nextcloud --format=custom --file=${dataDir}/db.dump
|
||||
'';
|
||||
backupCleanupCommand = "${lib.getExe' config.services.nextcloud.occ "nextcloud-occ"} maintenance:mode --off";
|
||||
paths = [
|
||||
"${dataDir}/data"
|
||||
"${dataDir}/config/config.php"
|
||||
"${dataDir}/db.dump"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "nextcloud-restore";
|
||||
text = ''
|
||||
sudo --user=${user} bash -c "
|
||||
${lib.getExe' config.services.nextcloud.occ "nextcloud-occ"} maintenance:mode --on
|
||||
restic-nextcloud restore latest --target /
|
||||
pg_restore --clean --if-exists --dbname nextcloud ${dataDir}/db.dump
|
||||
${lib.getExe' config.services.nextcloud.occ "nextcloud-occ"} maintenance:mode --off
|
||||
"
|
||||
'';
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
75
modules/system/services/nextcloud/default.nix
Normal file
75
modules/system/services/nextcloud/default.nix
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
config,
|
||||
inputs,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.nextcloud;
|
||||
|
||||
user = config.users.users.nextcloud.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.nextcloud = {
|
||||
enable = lib.mkEnableOption "";
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "";
|
||||
};
|
||||
port = lib.mkOption {
|
||||
type = lib.types.port;
|
||||
default = 80;
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
sops.secrets."nextcloud/admin-password".owner = user;
|
||||
|
||||
services.nextcloud = {
|
||||
enable = true;
|
||||
package = pkgs.nextcloud31;
|
||||
hostName = "${cfg.subdomain}.${config.networking.domain}";
|
||||
|
||||
database.createLocally = true;
|
||||
config = {
|
||||
dbtype = "pgsql";
|
||||
adminuser = "admin";
|
||||
adminpassFile = config.sops.secrets."nextcloud/admin-password".path;
|
||||
};
|
||||
|
||||
https = true;
|
||||
settings = {
|
||||
overwriteProtocol = "https";
|
||||
trusted_proxies = [ "127.0.0.1" ];
|
||||
log_type = "file";
|
||||
default_phone_region = "DE";
|
||||
maintenance_window_start = "2"; # UTC
|
||||
defaultapp = "side_menu";
|
||||
};
|
||||
|
||||
configureRedis = true;
|
||||
maxUploadSize = "16G";
|
||||
phpOptions."opcache.interned_strings_buffer" = "16";
|
||||
|
||||
autoUpdateApps = {
|
||||
enable = true;
|
||||
startAt = "04:00:00";
|
||||
};
|
||||
extraApps = {
|
||||
inherit (config.services.nextcloud.package.packages.apps)
|
||||
calendar
|
||||
contacts
|
||||
;
|
||||
|
||||
twofactor_totp = pkgs.fetchNextcloudApp {
|
||||
url = inputs.nextcloud-twofactor-totp.outPath;
|
||||
sha256 = inputs.nextcloud-twofactor-totp.narHash;
|
||||
license = "agpl3Plus";
|
||||
unpack = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
15
modules/system/services/printing.nix
Normal file
15
modules/system/services/printing.nix
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
options.custom.services.printing.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.printing.enable {
|
||||
services = {
|
||||
printing.enable = true;
|
||||
avahi = {
|
||||
enable = true;
|
||||
nssmdns4 = true;
|
||||
openFirewall = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
106
modules/system/services/restic-backup.nix
Normal file
106
modules/system/services/restic-backup.nix
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
backupServices = lib.filterAttrs (_: value: value.enable) config.custom.services.resticBackup;
|
||||
|
||||
healthchecksEnable = (lib.filterAttrs (_: value: value.healthchecks.enable) backupServices) != { };
|
||||
in
|
||||
{
|
||||
options.custom.services.resticBackup = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
enable = lib.mkEnableOption "" // {
|
||||
default = true;
|
||||
};
|
||||
user = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = config.users.users.root.name;
|
||||
};
|
||||
healthchecks.enable = lib.mkEnableOption "";
|
||||
extraConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf lib.types.anything;
|
||||
default = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
|
||||
config = lib.mkIf (backupServices != { }) {
|
||||
users.groups.backup.members = builtins.filter (user: user != config.users.users.root.name) (
|
||||
lib.mapAttrsToList (_: value: value.user) backupServices
|
||||
);
|
||||
|
||||
sops.secrets =
|
||||
let
|
||||
resticPermissions = {
|
||||
mode = "440";
|
||||
group = config.users.groups.backup.name;
|
||||
};
|
||||
in
|
||||
{
|
||||
"restic/environment" = resticPermissions;
|
||||
"restic/password" = resticPermissions;
|
||||
"healthchecks-ping-key" = lib.mkIf healthchecksEnable resticPermissions;
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = lib.mapAttrsToList (
|
||||
name: value:
|
||||
"d /var/cache/restic-backups-${name} 700 ${value.user} ${config.users.groups.backup.name} -"
|
||||
) backupServices;
|
||||
|
||||
services.restic.backups = lib.mapAttrs (
|
||||
name: value:
|
||||
lib.mkMerge [
|
||||
{
|
||||
inherit (value) user;
|
||||
initialize = true;
|
||||
repository = "s3:https://s3.eu-central-003.backblazeb2.com/stork-atlas/${name}";
|
||||
environmentFile = config.sops.secrets."restic/environment".path;
|
||||
passwordFile = config.sops.secrets."restic/password".path;
|
||||
pruneOpts = [
|
||||
"--keep-daily 7"
|
||||
"--keep-weekly 5"
|
||||
"--keep-monthly 6"
|
||||
"--keep-yearly 1"
|
||||
];
|
||||
timerConfig = {
|
||||
OnCalendar = "03:00";
|
||||
RandomizedDelaySec = "1h";
|
||||
};
|
||||
}
|
||||
value.extraConfig
|
||||
]
|
||||
) backupServices;
|
||||
|
||||
systemd.services = lib.mkMerge [
|
||||
(lib.mapAttrs' (
|
||||
name: _:
|
||||
lib.nameValuePair "restic-backups-${name}" {
|
||||
wants = [ "healthcheck-ping@${name}-backup_start.service" ];
|
||||
onSuccess = [ "healthcheck-ping@${name}-backup.service" ];
|
||||
onFailure = [ "healthcheck-ping@${name}-backup_fail.service" ];
|
||||
}
|
||||
) (lib.filterAttrs (_: value: value.healthchecks.enable) backupServices))
|
||||
|
||||
(lib.mkIf healthchecksEnable {
|
||||
"healthcheck-ping@" = {
|
||||
description = "Pings healthcheck (%i)";
|
||||
serviceConfig.Type = "oneshot";
|
||||
scriptArgs = "%i";
|
||||
script = ''
|
||||
${lib.getExe pkgs.curl} --fail --silent --show-error --max-time 10 --retry 5 https://hc-ping.com/$(cat ${
|
||||
config.sops.secrets."healthchecks-ping-key".path
|
||||
})/$(echo $1 | tr _ /)
|
||||
'';
|
||||
};
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
20
modules/system/services/sound.nix
Normal file
20
modules/system/services/sound.nix
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
options.custom.services.sound.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.sound.enable {
|
||||
security.rtkit.enable = true;
|
||||
services = {
|
||||
pulseaudio.enable = false;
|
||||
pipewire = {
|
||||
enable = true;
|
||||
wireplumber.enable = true;
|
||||
pulse.enable = true;
|
||||
alsa = {
|
||||
enable = true;
|
||||
support32Bit = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
64
modules/system/services/syncthing/backups.nix
Normal file
64
modules/system/services/syncthing/backups.nix
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.syncthing;
|
||||
|
||||
user = config.users.users.syncthing.name;
|
||||
in
|
||||
{
|
||||
options.custom.services.syncthing.backups.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf cfg.backups.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.isServer;
|
||||
message = "syncthing backups can only be made on a server";
|
||||
}
|
||||
];
|
||||
|
||||
security.polkit = {
|
||||
enable = true;
|
||||
extraConfig =
|
||||
let
|
||||
service = "syncthing.service";
|
||||
in
|
||||
''
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||
action.lookup("unit") == "${service}" &&
|
||||
subject.user == "${user}") {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
'';
|
||||
};
|
||||
|
||||
custom.services.resticBackup.syncthing = {
|
||||
inherit user;
|
||||
healthchecks.enable = true;
|
||||
|
||||
extraConfig = {
|
||||
backupPrepareCommand = "${lib.getExe' pkgs.systemd "systemctl"} stop syncthing.service";
|
||||
backupCleanupCommand = "${lib.getExe' pkgs.systemd "systemctl"} start syncthing.service";
|
||||
paths = [ config.services.syncthing.dataDir ];
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [
|
||||
(pkgs.writeShellApplication {
|
||||
name = "syncthing-restore";
|
||||
text = ''
|
||||
sudo --user=${user} bash -c "
|
||||
systemctl stop syncthing.service
|
||||
restic-syncthing restore latest --target /
|
||||
systemctl start syncthing.service
|
||||
"
|
||||
'';
|
||||
})
|
||||
];
|
||||
};
|
||||
}
|
||||
73
modules/system/services/syncthing/default.nix
Normal file
73
modules/system/services/syncthing/default.nix
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
config,
|
||||
self,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.syncthing;
|
||||
in
|
||||
{
|
||||
options.custom.services.syncthing = {
|
||||
enable = lib.mkEnableOption "";
|
||||
isServer = lib.mkEnableOption "";
|
||||
deviceId = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
|
||||
user = lib.mkIf (!cfg.isServer) "seb";
|
||||
group = lib.mkIf (!cfg.isServer) "users";
|
||||
dataDir = lib.mkIf (!cfg.isServer) "/home/seb";
|
||||
|
||||
guiAddress = lib.mkIf cfg.isServer "0.0.0.0:8384";
|
||||
|
||||
settings = {
|
||||
# Get the devices and their ids from the configs of the other hosts
|
||||
devices =
|
||||
self.nixosConfigurations
|
||||
|> lib.filterAttrs (name: _: name != config.networking.hostName)
|
||||
|> lib.filterAttrs (_: value: value.config.custom.services.syncthing.enable)
|
||||
|> lib.mapAttrs (
|
||||
name: value: {
|
||||
id = value.config.custom.services.syncthing.deviceId;
|
||||
addresses = [ "tcp://${name}.${value.config.networking.domain}:22000" ];
|
||||
}
|
||||
);
|
||||
|
||||
folders =
|
||||
let
|
||||
genFolders =
|
||||
folders:
|
||||
lib.genAttrs folders (name: {
|
||||
path = "${config.services.syncthing.dataDir}/${name}";
|
||||
ignorePerms = false;
|
||||
devices = lib.attrNames config.services.syncthing.settings.devices;
|
||||
});
|
||||
in
|
||||
genFolders [
|
||||
"Documents"
|
||||
"Downloads"
|
||||
"Music"
|
||||
"Pictures"
|
||||
"Projects"
|
||||
"Videos"
|
||||
];
|
||||
|
||||
options = {
|
||||
globalAnnounceEnabled = false;
|
||||
localAnnounceEnabled = false;
|
||||
relaysEnabled = false;
|
||||
natEnabled = false;
|
||||
urAccepted = -1;
|
||||
autoUpgradeIntervalH = 0;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
66
modules/system/services/tailscale/caddy-serve.nix
Normal file
66
modules/system/services/tailscale/caddy-serve.nix
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
nodes = config.custom.services.tailscale.caddyServe |> lib.filterAttrs (_: value: value.enable);
|
||||
|
||||
caddy-tailscale = pkgs.caddy.withPlugins {
|
||||
plugins = [ "github.com/tailscale/caddy-tailscale@v0.0.0-20250207163903-69a970c84556" ];
|
||||
hash = "sha256-wt3+xCsT83RpPySbL7dKVwgqjKw06qzrP2Em+SxEPto=";
|
||||
};
|
||||
in
|
||||
{
|
||||
options.custom.services.tailscale.caddyServe = lib.mkOption {
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule (
|
||||
{ name, ... }:
|
||||
{
|
||||
options = {
|
||||
enable = lib.mkEnableOption "" // {
|
||||
default = true;
|
||||
};
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = name;
|
||||
};
|
||||
port = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.port;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
}
|
||||
)
|
||||
);
|
||||
default = { };
|
||||
};
|
||||
|
||||
config = lib.mkIf (nodes != { }) {
|
||||
sops.secrets."service-tailscale-auth-key".owner = config.services.caddy.user;
|
||||
|
||||
services.caddy = {
|
||||
enable = true;
|
||||
package = caddy-tailscale;
|
||||
enableReload = false;
|
||||
|
||||
globalConfig = ''
|
||||
tailscale {
|
||||
auth_key {file.${config.sops.secrets."service-tailscale-auth-key".path}}
|
||||
}
|
||||
'';
|
||||
|
||||
virtualHosts = lib.mapAttrs' (
|
||||
_: value:
|
||||
lib.nameValuePair "https://${value.subdomain}.${config.networking.domain}" {
|
||||
extraConfig = ''
|
||||
bind tailscale/${value.subdomain}
|
||||
tailscale_auth
|
||||
reverse_proxy localhost:${toString value.port}
|
||||
'';
|
||||
}
|
||||
) nodes;
|
||||
};
|
||||
};
|
||||
}
|
||||
70
modules/system/services/tailscale/default.nix
Normal file
70
modules/system/services/tailscale/default.nix
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
cfg = config.custom.services.tailscale;
|
||||
in
|
||||
{
|
||||
options.custom.services.tailscale = {
|
||||
enable = lib.mkEnableOption "";
|
||||
subdomain = lib.mkOption {
|
||||
type = lib.types.nonEmptyStr;
|
||||
default = config.networking.hostName;
|
||||
};
|
||||
ssh.enable = lib.mkEnableOption "";
|
||||
exitNode.enable = lib.mkEnableOption "";
|
||||
serve = {
|
||||
isFunnel = lib.mkEnableOption "";
|
||||
target = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.nonEmptyStr;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
sops.secrets."tailscale-auth-key" = { };
|
||||
|
||||
services.tailscale = {
|
||||
enable = true;
|
||||
authKeyFile = config.sops.secrets."tailscale-auth-key".path;
|
||||
openFirewall = true;
|
||||
useRoutingFeatures =
|
||||
if (cfg.exitNode.enable || (cfg.serve.target != null)) then "server" else "client";
|
||||
extraUpFlags = [ "--reset=true" ];
|
||||
extraSetFlags = [
|
||||
"--hostname=${cfg.subdomain}"
|
||||
"--ssh=${lib.boolToString cfg.ssh.enable}"
|
||||
"--advertise-exit-node=${lib.boolToString cfg.exitNode.enable}"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services =
|
||||
let
|
||||
mode = if cfg.serve.isFunnel then "funnel" else "serve";
|
||||
in
|
||||
{
|
||||
"tailscaled-${mode}" = lib.mkIf (cfg.serve.target != null) {
|
||||
after = [
|
||||
"tailscaled.service"
|
||||
"tailscaled-autoconnect.service"
|
||||
];
|
||||
wants = [ "tailscaled.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
ExecStartPre = "${lib.getExe pkgs.tailscale} cert --min-validity 120h ${cfg.subdomain}.${config.networking.domain}";
|
||||
ExecStart = "${lib.getExe pkgs.tailscale} ${mode} --bg ${cfg.serve.target}";
|
||||
ExecStop = "${lib.getExe pkgs.tailscale} ${mode} reset";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
|
||||
tailscaled-set.after = [ "tailscaled-autoconnect.service" ];
|
||||
};
|
||||
};
|
||||
}
|
||||
71
modules/system/services/wlan.nix
Normal file
71
modules/system/services/wlan.nix
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
pskSsids = [
|
||||
"WLAN-233151"
|
||||
"EW90N"
|
||||
"Fairphone4"
|
||||
"DSL_EXT"
|
||||
];
|
||||
in
|
||||
{
|
||||
options.custom.services.wlan.enable = lib.mkEnableOption "";
|
||||
|
||||
config = lib.mkIf config.custom.services.wlan.enable (
|
||||
lib.mkMerge [
|
||||
{
|
||||
networking.wireless.iwd = {
|
||||
enable = true;
|
||||
settings = {
|
||||
General.EnableNetworkConfiguration = true;
|
||||
Settings.AutoConnect = true;
|
||||
Network.NameResolvingService = "resolvconf";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = [ pkgs.iwgtk ];
|
||||
|
||||
sops = {
|
||||
secrets = {
|
||||
"wlan/eduroam/password" = { };
|
||||
"wlan/eduroam/cert" = { };
|
||||
};
|
||||
|
||||
templates."iwd/eduroam.8021x".content = ''
|
||||
[Security]
|
||||
EAP-Method=PEAP
|
||||
EAP-Identity=anonymous@h-da.de
|
||||
EAP-PEAP-CACert=${config.sops.secrets."wlan/eduroam/cert".path}
|
||||
EAP-PEAP-Phase2-Method=MSCHAPV2
|
||||
EAP-PEAP-Phase2-Identity=sebastian.stork@stud.h-da.de
|
||||
EAP-PEAP-Phase2-Password=${config.sops.placeholder."wlan/eduroam/password"}
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"C /var/lib/iwd/eduroam.8021x - - - - ${config.sops.templates."iwd/eduroam.8021x".path}"
|
||||
];
|
||||
}
|
||||
|
||||
(lib.mkMerge (
|
||||
lib.forEach pskSsids (ssid: {
|
||||
sops = {
|
||||
secrets."wlan/${ssid}/key" = { };
|
||||
templates."iwd/${ssid}.psk".content = ''
|
||||
[Security]
|
||||
Passphrase=${config.sops.placeholder."wlan/${ssid}/key"}
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"C /var/lib/iwd/${ssid}.psk - - - - ${config.sops.templates."iwd/${ssid}.psk".path}"
|
||||
];
|
||||
})
|
||||
))
|
||||
]
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue