Compare commits
No commits in common. "9523a36795ee9bb86a55ffa5533b86f02a283f99" and "60d0753c1185f4fb93f061741112298ae93eeef4" have entirely different histories.
9523a36795
...
60d0753c11
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,5 +4,4 @@ result*
|
|||||||
*.bak
|
*.bak
|
||||||
*.qcow2
|
*.qcow2
|
||||||
*.raw
|
*.raw
|
||||||
*.img
|
*.img
|
||||||
*.log
|
|
695
flake.lock
generated
695
flake.lock
generated
File diff suppressed because it is too large
Load Diff
30
flake.nix
30
flake.nix
@ -4,6 +4,8 @@
|
|||||||
inputs = {
|
inputs = {
|
||||||
flake-utils-plus.url = "github:gytis-ivaskevicius/flake-utils-plus/v1.4.0";
|
flake-utils-plus.url = "github:gytis-ivaskevicius/flake-utils-plus/v1.4.0";
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
# 6.1.55 kernel breaks podman. wait for fix
|
||||||
|
nixpkgs-pinned.url = "github:nixos/nixpkgs/9eebdbb7182caf58dbbc11a4c221c23e867cca08";
|
||||||
nixpkgs-master.url = "github:nixos/nixpkgs/master";
|
nixpkgs-master.url = "github:nixos/nixpkgs/master";
|
||||||
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-23.11";
|
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-23.11";
|
||||||
flake-registry = {
|
flake-registry = {
|
||||||
@ -15,15 +17,11 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
impermanence.url = "github:nix-community/impermanence";
|
impermanence.url = "github:nix-community/impermanence";
|
||||||
aagl = {
|
aagl.url = "github:ezKEa/aagl-gtk-on-nix";
|
||||||
url = "github:ezKEa/aagl-gtk-on-nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
arkenfox-userjs = {
|
arkenfox-userjs = {
|
||||||
url = "github:arkenfox/user.js";
|
url = "github:arkenfox/user.js";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
ataraxiasjel-nur.url = "github:AtaraxiaSjel/nur";
|
|
||||||
attic.url = "github:zhaofengli/attic";
|
attic.url = "github:zhaofengli/attic";
|
||||||
base16.url = "github:AtaraxiaSjel/base16-nix";
|
base16.url = "github:AtaraxiaSjel/base16-nix";
|
||||||
base16-tokyonight-scheme = {
|
base16-tokyonight-scheme = {
|
||||||
@ -35,6 +33,7 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
deploy-rs.url = "github:serokell/deploy-rs";
|
deploy-rs.url = "github:serokell/deploy-rs";
|
||||||
|
devenv.url = "github:cachix/devenv";
|
||||||
disko = {
|
disko = {
|
||||||
url = "github:nix-community/disko";
|
url = "github:nix-community/disko";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
@ -44,7 +43,9 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs"; # MESA/OpenGL HW workaround
|
inputs.nixpkgs.follows = "nixpkgs"; # MESA/OpenGL HW workaround
|
||||||
};
|
};
|
||||||
hyprpaper = {
|
hyprpaper = {
|
||||||
url = "github:hyprwm/hyprpaper";
|
# TODO: return to upstream after fix merge
|
||||||
|
url = "github:AtaraxiaSjel/hyprpaper/fix-nix";
|
||||||
|
# url = "github:hyprwm/hyprpaper";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
mms.url = "github:mkaito/nixos-modded-minecraft-servers";
|
mms.url = "github:mkaito/nixos-modded-minecraft-servers";
|
||||||
@ -65,12 +66,20 @@
|
|||||||
url = "github:nix-community/nixos-generators";
|
url = "github:nix-community/nixos-generators";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
# nur.url = "github:nix-community/NUR";
|
nur.url = "github:nix-community/NUR";
|
||||||
prismlauncher.url = "github:AtaraxiaSjel/PrismLauncher/develop";
|
prismlauncher.url = "github:AtaraxiaSjel/PrismLauncher/develop";
|
||||||
|
rnix-lsp = {
|
||||||
|
url = "github:nix-community/rnix-lsp";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
rycee = {
|
rycee = {
|
||||||
url = "gitlab:rycee/nur-expressions";
|
url = "gitlab:rycee/nur-expressions";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
simple-nixos-mailserver = {
|
||||||
|
url = "gitlab:simple-nixos-mailserver/nixos-mailserver";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
sops-nix = {
|
sops-nix = {
|
||||||
url = "github:Mic92/sops-nix";
|
url = "github:Mic92/sops-nix";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
@ -118,10 +127,7 @@
|
|||||||
"webhooks.patch"
|
"webhooks.patch"
|
||||||
];
|
];
|
||||||
sharedOverlays = [ flake-utils-plus.overlay inputs.sops-nix.overlays.default ];
|
sharedOverlays = [ flake-utils-plus.overlay inputs.sops-nix.overlays.default ];
|
||||||
channelsConfig = {
|
channelsConfig = { allowUnfree = true; android_sdk.accept_license = true; };
|
||||||
allowUnfree = true; android_sdk.accept_license = true;
|
|
||||||
permittedInsecurePackages = [ "electron-25.9.0" ];
|
|
||||||
};
|
|
||||||
channels.unstable.input = nixpkgs;
|
channels.unstable.input = nixpkgs;
|
||||||
channels.unstable.patches = patchesPath [ "zen-kernels.patch" "ydotoold.patch" ] ++ sharedPatches;
|
channels.unstable.patches = patchesPath [ "zen-kernels.patch" "ydotoold.patch" ] ++ sharedPatches;
|
||||||
channels.stable.input = inputs.nixpkgs-stable;
|
channels.stable.input = inputs.nixpkgs-stable;
|
||||||
@ -205,7 +211,7 @@
|
|||||||
name = "aliases";
|
name = "aliases";
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
rebuild update-vscode upgrade upgrade-hyprland
|
rebuild update-vscode upgrade upgrade-hyprland
|
||||||
nixfmt-rfc-style nixpkgs-fmt statix vulnix deadnix git deploy-rs
|
nixfmt nixpkgs-fmt statix vulnix deadnix git deploy-rs
|
||||||
fup-repl ssh-to-pgp sops
|
fup-repl ssh-to-pgp sops
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
{ config, inputs, ... }: {
|
{ config, inputs, ... }: {
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.rustic ];
|
|
||||||
|
|
||||||
sops.secrets.rustic-nas-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rustic-nas-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
sops.secrets.rclone-rustic-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rclone-rustic-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
services.rustic.backups = rec {
|
services.rustic.backups = rec {
|
||||||
|
@ -21,7 +21,7 @@ in {
|
|||||||
customProfiles.hoyolab
|
customProfiles.hoyolab
|
||||||
customProfiles.inpx-web
|
customProfiles.inpx-web
|
||||||
customProfiles.it-tools
|
customProfiles.it-tools
|
||||||
# customProfiles.joplin-server
|
customProfiles.joplin-server
|
||||||
customProfiles.media-stack
|
customProfiles.media-stack
|
||||||
customProfiles.minio
|
customProfiles.minio
|
||||||
customProfiles.nginx
|
customProfiles.nginx
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
{ config, inputs, ... }: {
|
{ config, inputs, ... }: {
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.rustic ];
|
|
||||||
|
|
||||||
sops.secrets.rustic-vps-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rustic-vps-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
sops.secrets.rclone-rustic-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rclone-rustic-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
services.rustic.backups = rec {
|
services.rustic.backups = rec {
|
||||||
@ -33,7 +31,7 @@
|
|||||||
ignore-devid = true;
|
ignore-devid = true;
|
||||||
group-by = "label";
|
group-by = "label";
|
||||||
sources = [{
|
sources = [{
|
||||||
source = "/srv/marzban";
|
source = "/srv/marzban /srv/nextcloud/config /srv/nextcloud/data";
|
||||||
}];
|
}];
|
||||||
};
|
};
|
||||||
forget = {
|
forget = {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
{ config, pkgs, inputs, ... }:
|
{ config, pkgs, lib, inputs, ... }:
|
||||||
let
|
let
|
||||||
inherit (pkgs.hostPlatform) system;
|
|
||||||
cert-key = config.sops.secrets."cert.key".path;
|
cert-key = config.sops.secrets."cert.key".path;
|
||||||
cert-pem = config.sops.secrets."cert.pem".path;
|
cert-pem = config.sops.secrets."cert.pem".path;
|
||||||
nginx-conf = config.sops.secrets."nginx.conf".path;
|
nginx-conf = config.sops.secrets."nginx.conf".path;
|
||||||
@ -26,6 +25,16 @@ in {
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtualisation.oci-containers.containers = {
|
virtualisation.oci-containers.containers = {
|
||||||
|
nextcloud = {
|
||||||
|
autoStart = true;
|
||||||
|
image = "docker.io/nextcloud:stable";
|
||||||
|
ports = [ "9765:80" ];
|
||||||
|
volumes = [
|
||||||
|
"/srv/nextcloud/html:/var/www/html"
|
||||||
|
"/srv/nextcloud/config:/var/www/html/config"
|
||||||
|
"/srv/nextcloud/data:/var/www/html/data"
|
||||||
|
];
|
||||||
|
};
|
||||||
marzban = {
|
marzban = {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
image = "ghcr.io/gozargah/marzban:v0.4.1";
|
image = "ghcr.io/gozargah/marzban:v0.4.1";
|
||||||
@ -48,20 +57,10 @@ in {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.ocis = {
|
|
||||||
enable = true;
|
|
||||||
package = inputs.ataraxiasjel-nur.packages.${system}.ocis-bin;
|
|
||||||
configDir = "/srv/ocis/config";
|
|
||||||
baseDataPath = "/srv/ocis/data";
|
|
||||||
environment = {
|
|
||||||
OCIS_INSECURE = "false";
|
|
||||||
OCIS_URL = "https://cloud.ataraxiadev.com";
|
|
||||||
PROXY_HTTP_ADDR = "127.0.0.1:9200";
|
|
||||||
PROXY_TLS = "false";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
"d /srv/marzban 0755 root root -"
|
"d /srv/marzban 0755 root root -"
|
||||||
|
"d /srv/nextcloud/html 0755 33 33 -"
|
||||||
|
"d /srv/nextcloud/config 0755 33 33 -"
|
||||||
|
"d /srv/nextcloud/data 0755 33 33 -"
|
||||||
];
|
];
|
||||||
}
|
}
|
320
modules/authentik.nix
Normal file
320
modules/authentik.nix
Normal file
@ -0,0 +1,320 @@
|
|||||||
|
# Thanks for original module, anpin! https://gist.github.com/anpin/ecbdb6625400908856ef9482eca3380c
|
||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.services.authentik;
|
||||||
|
databaseActuallyCreateLocally = cfg.database.createLocally
|
||||||
|
&& cfg.database.host == "/run/postgresql";
|
||||||
|
|
||||||
|
inherit (lib)
|
||||||
|
mkIf mkEnableOption mkOption types mdDoc literalExpression optional attrsets;
|
||||||
|
inherit (attrsets) optionalAttrs;
|
||||||
|
inherit (types) str bool port submodule package nullOr path enum;
|
||||||
|
|
||||||
|
hostWithPort = h: p: "${h}:${toString p}";
|
||||||
|
|
||||||
|
authentikBaseService = {
|
||||||
|
after = [ "network.target" ]
|
||||||
|
++ optional databaseActuallyCreateLocally "postgresql.service";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
path = [ cfg.package ];
|
||||||
|
environment = let
|
||||||
|
listenAddress = hostWithPort cfg.listen.address;
|
||||||
|
in {
|
||||||
|
AUTHENTIK_REDIS__HOST = cfg.redis.host;
|
||||||
|
AUTHENTIK_REDIS__PORT = toString cfg.redis.port;
|
||||||
|
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST = cfg.database.host;
|
||||||
|
AUTHENTIK_POSTGRESQL__PORT = mkIf (cfg.database.port != null) "${toString cfg.database.port}";
|
||||||
|
AUTHENTIK_POSTGRESQL__USER = cfg.database.user;
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME = cfg.database.name;
|
||||||
|
|
||||||
|
AUTHENTIK_LISTEN__HTTP = listenAddress cfg.listen.http;
|
||||||
|
AUTHENTIK_LISTEN__HTTPS = listenAddress cfg.listen.https;
|
||||||
|
|
||||||
|
# initial password for admin user
|
||||||
|
AUTHENTIK_BOOTSTRAP_PASSWORD = cfg.defaultPassword;
|
||||||
|
|
||||||
|
# disable outbound connections
|
||||||
|
AUTHENTIK_DISABLE_UPDATE_CHECK = "true";
|
||||||
|
AUTHENTIK_ERROR_REPORTING__ENABLED = "false";
|
||||||
|
AUTHENTIK_DISABLE_STARTUP_ANALYTICS = "true";
|
||||||
|
AUTHENTIK_AVATARS = "initials";
|
||||||
|
|
||||||
|
AUTHENTIK_LOG_LEVEL = cfg.logLevel;
|
||||||
|
};
|
||||||
|
serviceConfig = {
|
||||||
|
User = "authentik";
|
||||||
|
Group = "authentik";
|
||||||
|
EnvironmentFile = cfg.environmentFile;
|
||||||
|
WorkingDirectory = cfg.package;
|
||||||
|
DynamicUser = true;
|
||||||
|
RuntimeDirectory = "authentik";
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectHome = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
SystemCallFilter= "~@cpu-emulation @keyring @module @obsolete @raw-io @reboot @swap @sync";
|
||||||
|
ConfigurationDirectory = "authentik";
|
||||||
|
StateDirectoryMode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
options.services.authentik = {
|
||||||
|
enable = mkEnableOption "Enables Authentik service";
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = package;
|
||||||
|
default = pkgs.authentik;
|
||||||
|
defaultText = literalExpression "pkgs.authentik";
|
||||||
|
description = mdDoc "Authentik package to use.";
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultPassword = mkOption {
|
||||||
|
description = mdDoc "Default admin password. Only read on first startup.";
|
||||||
|
type = str;
|
||||||
|
default = "change-me";
|
||||||
|
};
|
||||||
|
|
||||||
|
logLevel = mkOption {
|
||||||
|
description = mdDoc
|
||||||
|
"Log level for the server and worker containers. Setting the log level to trace will include sensitive details in logs, so it shouldn't be used in most cases.";
|
||||||
|
type = enum [ "trace" "debug" "info" "warning" "error" ];
|
||||||
|
default = "info";
|
||||||
|
};
|
||||||
|
|
||||||
|
listen = mkOption {
|
||||||
|
description = mdDoc "Listen ports";
|
||||||
|
default = { };
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
http = mkOption {
|
||||||
|
description = mdDoc "HTTP port.";
|
||||||
|
type = port;
|
||||||
|
default = 9000;
|
||||||
|
};
|
||||||
|
https = mkOption {
|
||||||
|
description = mdDoc "HTTPS port.";
|
||||||
|
type = port;
|
||||||
|
default = 9443;
|
||||||
|
};
|
||||||
|
address = mkOption {
|
||||||
|
description = mdDoc "Address to listen on.";
|
||||||
|
type = str;
|
||||||
|
default = "0.0.0.0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
redis = {
|
||||||
|
createLocally = mkOption {
|
||||||
|
description = mdDoc "Configure local Redis server for Authentik.";
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
description = mdDoc "Redis host.";
|
||||||
|
type = str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
description = mdDoc "Redis port.";
|
||||||
|
type = port;
|
||||||
|
default = 31637;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
ssl = {
|
||||||
|
cert = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
key = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "SSL from NIXOS";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
example = "/var/lib/authentik/secrets/db-password";
|
||||||
|
description = mdDoc ''
|
||||||
|
Environment variables including :
|
||||||
|
- Secret key used for cookie signing and unique user IDs, don't change this after the first install.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
createLocally = mkOption {
|
||||||
|
description =
|
||||||
|
mdDoc "Configure local PostgreSQL database server for authentik.";
|
||||||
|
type = bool;
|
||||||
|
default = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
host = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "/run/postgresql";
|
||||||
|
example = "192.168.23.42";
|
||||||
|
description = mdDoc "Database host address or unix socket.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = nullOr port;
|
||||||
|
default = if cfg.database.createLocally then null else 5432;
|
||||||
|
defaultText = literalExpression ''
|
||||||
|
if config.database.createLocally then null else 5432
|
||||||
|
'';
|
||||||
|
description = mdDoc "Database host port.";
|
||||||
|
};
|
||||||
|
|
||||||
|
name = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "authentik";
|
||||||
|
description = mdDoc "Database name.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = "authentik";
|
||||||
|
description = mdDoc "Database user.";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outposts = mkOption {
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
ldap = mkOption {
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
enable =
|
||||||
|
mkEnableOption (lib.mdDoc "the authentik ldap outpost");
|
||||||
|
package = mkOption {
|
||||||
|
type = path;
|
||||||
|
default = pkgs.authentik-outposts.ldap;
|
||||||
|
};
|
||||||
|
host = mkOption {
|
||||||
|
type = str;
|
||||||
|
default = if cfg.outposts.ldap.insecure then
|
||||||
|
"http://127.0.0.1:${toString cfg.listen.http}"
|
||||||
|
else
|
||||||
|
"https://127.0.0.1:${toString cfg.listen.https}";
|
||||||
|
};
|
||||||
|
insecure = mkOption {
|
||||||
|
type = bool;
|
||||||
|
default = false;
|
||||||
|
};
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = nullOr path;
|
||||||
|
default = null;
|
||||||
|
example = "/var/lib/authentik-ldap/secrets/env";
|
||||||
|
description = mdDoc ''
|
||||||
|
Environment variables including :
|
||||||
|
- API TOKEN
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
listen = mkOption {
|
||||||
|
description = mdDoc "Listen ports";
|
||||||
|
default = { };
|
||||||
|
type = submodule {
|
||||||
|
options = {
|
||||||
|
ldap = mkOption {
|
||||||
|
description = mdDoc "LDAP port.";
|
||||||
|
type = port;
|
||||||
|
default = 3389;
|
||||||
|
};
|
||||||
|
ldaps = mkOption {
|
||||||
|
description = mdDoc "LDAPS port.";
|
||||||
|
type = port;
|
||||||
|
default = 6636;
|
||||||
|
};
|
||||||
|
address = mkOption {
|
||||||
|
description = mdDoc "Address to listen on.";
|
||||||
|
type = str;
|
||||||
|
default = "0.0.0.0";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = { ldap = { enable = false; }; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
users.users.authentik = {
|
||||||
|
isSystemUser = true;
|
||||||
|
home = cfg.package;
|
||||||
|
group = "authentik";
|
||||||
|
};
|
||||||
|
users.groups.authentik = { };
|
||||||
|
|
||||||
|
services.postgresql = mkIf databaseActuallyCreateLocally {
|
||||||
|
enable = true;
|
||||||
|
ensureUsers = [{
|
||||||
|
name = cfg.database.name;
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
}];
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.redis.servers.authentik =
|
||||||
|
mkIf (cfg.redis.createLocally && cfg.redis.host == "127.0.0.1") {
|
||||||
|
enable = true;
|
||||||
|
port = cfg.redis.port;
|
||||||
|
bind = "127.0.0.1";
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.authentik-server = authentikBaseService // {
|
||||||
|
serviceConfig = authentikBaseService.serviceConfig // {
|
||||||
|
ExecStart = "${cfg.package}/bin/ak server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.authentik-worker = authentikBaseService // {
|
||||||
|
serviceConfig = authentikBaseService.serviceConfig // {
|
||||||
|
ExecStart = "${cfg.package}/bin/ak worker";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# systemd.services.authentik-ssl-import = authentikBaseService // {
|
||||||
|
# before = [ "authentik-server.service" ];
|
||||||
|
# serviceConfig = authentikBaseService.serviceConfig // {
|
||||||
|
# Type = "oneshot";
|
||||||
|
# RemainAfterExit = true;
|
||||||
|
# ExecStart = ''
|
||||||
|
# ${cfg.package}/bin/ak import_certificate --name "${cfg.ssl.name}" --certificate "${cfg.ssl.cert}" --private-key "${cfg.ssl.key}"'';
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
systemd.services.authentik-ldap-outpost = let
|
||||||
|
ldapCfg = cfg.outposts.ldap;
|
||||||
|
in mkIf ldapCfg.enable (authentikBaseService // {
|
||||||
|
description = "authentik ldap outpost";
|
||||||
|
environment = let listenAddress = hostWithPort ldapCfg.listen.address;
|
||||||
|
in {
|
||||||
|
AUTHENTIK_HOST = ldapCfg.host;
|
||||||
|
AUTHENTIK_LISTEN__LDAP = listenAddress ldapCfg.listen.ldap;
|
||||||
|
AUTHENTIK_LISTEN__LDAPS = listenAddress ldapCfg.listen.ldaps;
|
||||||
|
} // optionalAttrs ldapCfg.insecure { AUTHENTIK_INSECURE = "true"; };
|
||||||
|
serviceConfig = authentikBaseService.serviceConfig // {
|
||||||
|
ExecStart = "${cfg.outposts.ldap.package}/bin/ldap";
|
||||||
|
EnvironmentFile = ldapCfg.environmentFile;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
@ -58,13 +58,13 @@ with lib;
|
|||||||
HEADSCALE_CLI_ADDRESS = "wg.ataraxiadev.com:443";
|
HEADSCALE_CLI_ADDRESS = "wg.ataraxiadev.com:443";
|
||||||
};
|
};
|
||||||
script = ''
|
script = ''
|
||||||
while true; do
|
auth_key=$(headscale preauthkeys create -e ${cfg.expire} -u ${cfg.user} -o json ${optionalString cfg.ephemeral "--ephemeral"} | jq -r .key)
|
||||||
auth_key=$(headscale preauthkeys create -e ${cfg.expire} -u ${cfg.user} -o json ${optionalString cfg.ephemeral "--ephemeral"} | jq -r .key)
|
if [ "$auth_key" = "null" ]; then
|
||||||
[[ "$auth_key" = "null" ]] || break
|
echo "Cannot retrieve auth key." >&2
|
||||||
echo "Cannot retrieve auth key. Will try again after 5 seconds." >&2
|
exit 1
|
||||||
sleep 5
|
else
|
||||||
done
|
echo $auth_key > "${cfg.outPath}"
|
||||||
echo $auth_key > "${cfg.outPath}"
|
fi
|
||||||
'';
|
'';
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
EnvironmentFile = config.sops.secrets.headscale-api-env.path;
|
EnvironmentFile = config.sops.secrets.headscale-api-env.path;
|
||||||
|
80
modules/minio-kes.nix
Normal file
80
modules/minio-kes.nix
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.kes;
|
||||||
|
format = pkgs.formats.yaml { };
|
||||||
|
configFile = format.generate "config.yaml" cfg.settings;
|
||||||
|
port = strings.toInt (lists.last (strings.splitString ":" cfg.settings.address));
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.kes = {
|
||||||
|
enable = mkEnableOption (mdDoc "Minio's Key Managament Server");
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = mdDoc "Which package to use for the kes instance.";
|
||||||
|
default = pkgs.minio-kes;
|
||||||
|
};
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
File in the format of an EnvironmentFile as described by systemd.exec(5).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
settings = mkOption {
|
||||||
|
type = format.type;
|
||||||
|
default = { address = "0.0.0.0:7373"; };
|
||||||
|
example = literalExpression ''
|
||||||
|
{
|
||||||
|
address = "0.0.0.0:7373";
|
||||||
|
cache = {
|
||||||
|
expiry = {
|
||||||
|
any = "5m0s";
|
||||||
|
unused = "20s";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = mdDoc ''
|
||||||
|
KES Configuration.
|
||||||
|
Refer to <https://github.com/minio/kes/blob/master/server-config.yaml>
|
||||||
|
for details on supported values.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.services.kes = {
|
||||||
|
description = "KES";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
path = [ cfg.package ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "always";
|
||||||
|
ExecStart = "${cfg.package}/bin/kes server --config ${configFile}";
|
||||||
|
User = "kes";
|
||||||
|
Group = "kes";
|
||||||
|
# WorkingDirectory = "/etc/kes";
|
||||||
|
|
||||||
|
AmbientCapabilities = mkIf (port < 1024) ["CAP_NET_BIND_SERVICE"];
|
||||||
|
LimitNOFILE = 65536;
|
||||||
|
ProtectProc = "invisible";
|
||||||
|
SendSIGKILL = "no";
|
||||||
|
TasksMax = "infinity";
|
||||||
|
TimeoutStopSec = "infinity";
|
||||||
|
} // optionalAttrs (cfg.environmentFile != null) {
|
||||||
|
EnvironmentFile = cfg.environmentFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
|
users.groups.kes = { };
|
||||||
|
users.users.kes = {
|
||||||
|
description = "KES user";
|
||||||
|
group = "kes";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
159
modules/ocis.nix
Normal file
159
modules/ocis.nix
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
with lib;
|
||||||
|
let
|
||||||
|
cfg = config.services.ocis;
|
||||||
|
format = pkgs.formats.yaml { };
|
||||||
|
|
||||||
|
linkConfigs = confDir: lib.pipe cfg.settings [
|
||||||
|
(lib.attrsets.mapAttrs (n: v: format.generate "${n}.yaml" v))
|
||||||
|
(lib.mapAttrsToList (n: v: "ln -sf ${v} ${confDir}/${n}.yaml"))
|
||||||
|
(lib.concatStringsSep "\n")
|
||||||
|
];
|
||||||
|
|
||||||
|
mkExport = { arg, value }: "export ${arg}=${value}";
|
||||||
|
adminpass = {
|
||||||
|
arg = "ADMIN_PASSWORD";
|
||||||
|
value = ''"$(<"${toString cfg.adminpassFile}")"'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.ocis = {
|
||||||
|
enable = mkEnableOption (lib.mdDoc "ownCloud Infinite Scale Stack");
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
description = lib.mdDoc "Which package to use for the ocis instance.";
|
||||||
|
default = pkgs.ocis-bin;
|
||||||
|
};
|
||||||
|
configDir = mkOption {
|
||||||
|
default = "/var/lib/ocis/.config";
|
||||||
|
type = types.path;
|
||||||
|
description = lib.mdDoc "The config directory. Set OCIS_CONFIG_DIR env variable.";
|
||||||
|
};
|
||||||
|
baseDataPath = mkOption {
|
||||||
|
default = "/var/lib/ocis";
|
||||||
|
type = types.path;
|
||||||
|
description = lib.mdDoc "The base data directory. Set OCIS_BASE_DATA_PATH env variable.";
|
||||||
|
};
|
||||||
|
environment = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.str;
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
OCIS_URL = "https://localhost:9200";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc "Environment variables to pass to ocis instance.";
|
||||||
|
};
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
File in the format of an EnvironmentFile as described by systemd.exec(5).
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
adminpassFile = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
The full path to a file that contains the admin's password. Must be
|
||||||
|
readable by user `ocis`. The password is set only in the initial
|
||||||
|
setup of Ocis by the systemd service `ocis-init.service`.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
settings = mkOption {
|
||||||
|
type = with types; attrsOf format.type;
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
auth-bearer = {
|
||||||
|
tracing = {
|
||||||
|
enabled = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
proxy = {
|
||||||
|
user_oidc_claim = "preferred_username";
|
||||||
|
user_cs3_claim = "username";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
OCIS configuration. Refer to
|
||||||
|
<https://doc.owncloud.com/ocis/next/deployment/services/services.html>
|
||||||
|
for details on supported values.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '${cfg.configDir}' - ocis ocis - -"
|
||||||
|
"d '${cfg.baseDataPath}' - ocis ocis - -"
|
||||||
|
];
|
||||||
|
systemd.services.ocis-init = rec {
|
||||||
|
before = [ "ocis-server.service" ];
|
||||||
|
requiredBy = [ "ocis-server.service" ];
|
||||||
|
path = [ cfg.package ];
|
||||||
|
environment = {
|
||||||
|
OCIS_CONFIG_DIR = cfg.configDir;
|
||||||
|
OCIS_BASE_DATA_PATH = cfg.baseDataPath;
|
||||||
|
} // cfg.environment;
|
||||||
|
script = ''
|
||||||
|
${lib.optionalString (cfg.settings != { }) "${linkConfigs environment.OCIS_CONFIG_DIR}"}
|
||||||
|
if [ ! -f "$OCIS_CONFIG_DIR/ocis.yaml" ]; then
|
||||||
|
${
|
||||||
|
lib.optionalString (cfg.adminpassFile != null) ''
|
||||||
|
if [ ! -r "${cfg.adminpassFile}" ]; then
|
||||||
|
echo "adminpassFile ${cfg.adminpassFile} is not readable by ocis:ocis! Aborting..."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$(<${cfg.adminpassFile})" ]; then
|
||||||
|
echo "adminpassFile ${cfg.adminpassFile} is empty!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
${mkExport adminpass}
|
||||||
|
''
|
||||||
|
}
|
||||||
|
ocis init
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
StateDirectory = "ocis";
|
||||||
|
User = "ocis";
|
||||||
|
Group = "ocis";
|
||||||
|
} // optionalAttrs (cfg.environmentFile != null) {
|
||||||
|
EnvironmentFile = cfg.environmentFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.ocis-server = {
|
||||||
|
description = "ownCloud Infinite Scale Stack";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
path = [ cfg.package ];
|
||||||
|
environment = {
|
||||||
|
OCIS_CONFIG_DIR = cfg.configDir;
|
||||||
|
OCIS_BASE_DATA_PATH = cfg.baseDataPath;
|
||||||
|
OCIS_URL = "https://localhost:9200";
|
||||||
|
PROXY_HTTP_ADDR = "127.0.0.1:9200";
|
||||||
|
} // cfg.environment;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
Restart = "always";
|
||||||
|
ExecStart = "${cfg.package}/bin/ocis server";
|
||||||
|
User = "ocis";
|
||||||
|
Group = "ocis";
|
||||||
|
LimitNOFILE = 65536;
|
||||||
|
} // optionalAttrs (cfg.environmentFile != null) {
|
||||||
|
EnvironmentFile = cfg.environmentFile;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = [ cfg.package ];
|
||||||
|
|
||||||
|
users.groups.ocis = { };
|
||||||
|
users.users.ocis = {
|
||||||
|
description = "Ocis Daemon User";
|
||||||
|
group = "ocis";
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -19,7 +19,6 @@ with lib;
|
|||||||
}));
|
}));
|
||||||
default = { };
|
default = { };
|
||||||
};
|
};
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.rustic ];
|
|
||||||
config = mkIf (config.backups.postgresql != { }) {
|
config = mkIf (config.backups.postgresql != { }) {
|
||||||
sops.secrets.rclone-postgresql-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rclone-postgresql-backups.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
sops.secrets.rustic-postgresql-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
sops.secrets.rustic-postgresql-pass.sopsFile = inputs.self.secretsDir + /rustic.yaml;
|
||||||
|
324
modules/rustic.nix
Normal file
324
modules/rustic.nix
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
{ config, lib, pkgs, utils, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
# Type for a valid systemd unit option. Needed for correctly passing "timerConfig" to "systemd.timers"
|
||||||
|
inherit (utils.systemdUtils.unitOptions) unitOption;
|
||||||
|
settingsFormat = pkgs.formats.toml {};
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.rustic.backups = mkOption {
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Periodic backups to create with Rustic.
|
||||||
|
'';
|
||||||
|
type = types.attrsOf (types.submodule ({ config, name, ... }: {
|
||||||
|
options = {
|
||||||
|
settings = mkOption {
|
||||||
|
type = settingsFormat.type;
|
||||||
|
default = {};
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
environmentFile = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
file containing the credentials to access the repository, in the
|
||||||
|
format of an EnvironmentFile as described by systemd.exec(5)
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
extraEnvironment = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.str;
|
||||||
|
default = { };
|
||||||
|
example = lib.literalExpression ''
|
||||||
|
{
|
||||||
|
http_proxy = "http://server:12345";
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
description = lib.mdDoc "Environment variables to pass to rustic.";
|
||||||
|
};
|
||||||
|
|
||||||
|
rcloneOptions = mkOption {
|
||||||
|
type = with types; nullOr (attrsOf (oneOf [ str bool ]));
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Options to pass to rclone to control its behavior.
|
||||||
|
See <https://rclone.org/docs/#options> for
|
||||||
|
available options. When specifying option names, strip the
|
||||||
|
leading `--`. To set a flag such as
|
||||||
|
`--drive-use-trash`, which does not take a value,
|
||||||
|
set the value to the Boolean `true`.
|
||||||
|
'';
|
||||||
|
example = {
|
||||||
|
bwlimit = "10M";
|
||||||
|
drive-use-trash = "true";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
rcloneConfigFile = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Path to the file containing rclone configuration. This file
|
||||||
|
must contain configuration for the remote specified in this backup
|
||||||
|
set and also must be readable by root. Options set in
|
||||||
|
`rcloneConfig` will override those set in this
|
||||||
|
file.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
timerConfig = mkOption {
|
||||||
|
type = types.attrsOf unitOption;
|
||||||
|
default = {
|
||||||
|
OnCalendar = "daily";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
When to run the backup. See {manpage}`systemd.timer(5)` for details.
|
||||||
|
'';
|
||||||
|
example = {
|
||||||
|
OnCalendar = "00:05";
|
||||||
|
RandomizedDelaySec = "5h";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
user = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "root";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
As which user the backup should run.
|
||||||
|
'';
|
||||||
|
example = "postgresql";
|
||||||
|
};
|
||||||
|
|
||||||
|
extraBackupArgs = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Extra arguments passed to rustic backup.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"--exclude-file=/etc/nixos/rustic-ignore"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
extraOptions = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Extra extended options to be passed to the rustic --option flag.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"sftp.command='ssh backup@192.168.1.100 -i /home/user/.ssh/id_rsa -s sftp'"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
backup = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Start backup.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
prune = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Start prune.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
initialize = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Create the repository if it doesn't exist.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
initializeOpts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A list of options for 'rustic init'.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"--set-version 2"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
checkOpts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A list of options for 'rustic check', which is run after
|
||||||
|
pruning.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"--with-cache"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
pruneOpts = mkOption {
|
||||||
|
type = types.listOf types.str;
|
||||||
|
default = [ ];
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A list of options for 'rustic prune', which is run before
|
||||||
|
pruning.
|
||||||
|
'';
|
||||||
|
example = [
|
||||||
|
"--repack-cacheable-only=false"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
backupCommandPrefix = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Prefix for backup command.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
backupCommandSuffix = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Suffix for backup command.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
backupPrepareCommand = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A script that must run before starting the backup process.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
backupCleanupCommand = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
A script that must run after finishing the backup process.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
package = mkOption {
|
||||||
|
type = types.package;
|
||||||
|
default = pkgs.rustic-rs;
|
||||||
|
defaultText = literalExpression "pkgs.rustic-rs";
|
||||||
|
description = lib.mdDoc ''
|
||||||
|
Rustic package to use.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
createWrapper = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Whether to generate and add a script to the system path, that has the same environment variables set
|
||||||
|
as the systemd service. This can be used to e.g. mount snapshots or perform other opterations, without
|
||||||
|
having to manually specify most options.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
default = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
config = {
|
||||||
|
systemd.services =
|
||||||
|
mapAttrs'
|
||||||
|
(name: backup:
|
||||||
|
let
|
||||||
|
profile = settingsFormat.generate "${name}.toml" backup.settings;
|
||||||
|
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
|
||||||
|
rusticCmd = "${backup.package}/bin/rustic -P ${lib.strings.removeSuffix ".toml" profile}${extraOptions}";
|
||||||
|
# Helper functions for rclone remotes
|
||||||
|
rcloneAttrToOpt = v: "RCLONE_" + toUpper (builtins.replaceStrings [ "-" ] [ "_" ] v);
|
||||||
|
toRcloneVal = v: if lib.isBool v then lib.boolToString v else v;
|
||||||
|
in
|
||||||
|
nameValuePair "rustic-backups-${name}" ({
|
||||||
|
environment = backup.extraEnvironment // {
|
||||||
|
# not %C, because that wouldn't work in the wrapper script
|
||||||
|
RUSTIC_CACHE_DIR = "/var/cache/rustic-backups-${name}";
|
||||||
|
} // optionalAttrs (backup.rcloneConfigFile != null) {
|
||||||
|
RCLONE_CONFIG = backup.rcloneConfigFile;
|
||||||
|
} // optionalAttrs (backup.rcloneOptions != null) (mapAttrs'
|
||||||
|
(name: value:
|
||||||
|
nameValuePair (rcloneAttrToOpt name) (toRcloneVal value)
|
||||||
|
)
|
||||||
|
backup.rcloneOptions);
|
||||||
|
path = [ config.programs.ssh.package pkgs.rclone ];
|
||||||
|
restartIfChanged = false;
|
||||||
|
wants = [ "network-online.target" ];
|
||||||
|
after = [ "network-online.target" ];
|
||||||
|
script = ''
|
||||||
|
${optionalString (backup.backup) ''
|
||||||
|
${backup.backupCommandPrefix} ${rusticCmd} backup ${concatStringsSep " " backup.extraBackupArgs} ${backup.backupCommandSuffix}
|
||||||
|
''}
|
||||||
|
${optionalString (backup.prune) ''
|
||||||
|
${rusticCmd} forget --prune ${concatStringsSep " " backup.pruneOpts}
|
||||||
|
${rusticCmd} check ${concatStringsSep " " backup.checkOpts}
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
User = backup.user;
|
||||||
|
RuntimeDirectory = "rustic-backups-${name}";
|
||||||
|
CacheDirectory = "rustic-backups-${name}";
|
||||||
|
CacheDirectoryMode = "0700";
|
||||||
|
PrivateTmp = true;
|
||||||
|
} // optionalAttrs (backup.environmentFile != null) {
|
||||||
|
EnvironmentFile = backup.environmentFile;
|
||||||
|
};
|
||||||
|
} // optionalAttrs (backup.initialize || backup.backupPrepareCommand != null) {
|
||||||
|
preStart = ''
|
||||||
|
${optionalString (backup.backupPrepareCommand != null) ''
|
||||||
|
${pkgs.writeScript "backupPrepareCommand" backup.backupPrepareCommand}
|
||||||
|
''}
|
||||||
|
${optionalString (backup.initialize) ''
|
||||||
|
${rusticCmd} init ${concatStringsSep " " backup.initializeOpts} || true
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
} // optionalAttrs (backup.backupCleanupCommand != null) {
|
||||||
|
postStop = ''
|
||||||
|
${optionalString (backup.backupCleanupCommand != null) ''
|
||||||
|
${pkgs.writeScript "backupCleanupCommand" backup.backupCleanupCommand}
|
||||||
|
''}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
)
|
||||||
|
config.services.rustic.backups;
|
||||||
|
systemd.timers =
|
||||||
|
mapAttrs'
|
||||||
|
(name: backup: nameValuePair "rustic-backups-${name}" {
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = backup.timerConfig;
|
||||||
|
})
|
||||||
|
config.services.rustic.backups;
|
||||||
|
|
||||||
|
# generate wrapper scripts, as described in the createWrapper option
|
||||||
|
environment.systemPackages = lib.mapAttrsToList (name: backup: let
|
||||||
|
profile = settingsFormat.generate "${name}.toml" backup.settings;
|
||||||
|
extraOptions = concatMapStrings (arg: " -o ${arg}") backup.extraOptions;
|
||||||
|
rusticCmd = "${backup.package}/bin/rustic -P ${lib.strings.removeSuffix ".toml" profile}${extraOptions}";
|
||||||
|
in pkgs.writeShellScriptBin "rustic-${name}" ''
|
||||||
|
set -a # automatically export variables
|
||||||
|
${lib.optionalString (backup.environmentFile != null) "source ${backup.environmentFile}"}
|
||||||
|
# set same environment variables as the systemd service
|
||||||
|
${lib.pipe config.systemd.services."rustic-backups-${name}".environment [
|
||||||
|
(lib.filterAttrs (_: v: v != null))
|
||||||
|
(lib.mapAttrsToList (n: v: "${n}=${v}"))
|
||||||
|
(lib.concatStringsSep "\n")
|
||||||
|
]}
|
||||||
|
|
||||||
|
exec ${rusticCmd} $@
|
||||||
|
'') (lib.filterAttrs (_: v: v.createWrapper) config.services.rustic.backups);
|
||||||
|
};
|
||||||
|
}
|
@ -62,7 +62,6 @@ with config.deviceSpecific; {
|
|||||||
# libreoffice
|
# libreoffice
|
||||||
obs-studio
|
obs-studio
|
||||||
obs-studio-plugins.obs-vkcapture
|
obs-studio-plugins.obs-vkcapture
|
||||||
obsidian
|
|
||||||
pinta
|
pinta
|
||||||
qbittorrent
|
qbittorrent
|
||||||
sonixd
|
sonixd
|
||||||
@ -93,7 +92,6 @@ with config.deviceSpecific; {
|
|||||||
".config/kdeconnect"
|
".config/kdeconnect"
|
||||||
".config/libreoffice"
|
".config/libreoffice"
|
||||||
".config/obs-studio"
|
".config/obs-studio"
|
||||||
".config/obsidian"
|
|
||||||
".config/pcmanfm"
|
".config/pcmanfm"
|
||||||
# ".config/Pinta"
|
# ".config/Pinta"
|
||||||
".config/qBittorrent"
|
".config/qBittorrent"
|
||||||
|
@ -123,12 +123,12 @@ in
|
|||||||
"license.extension" = ".md";
|
"license.extension" = ".md";
|
||||||
"license.year" = "auto";
|
"license.year" = "auto";
|
||||||
"nix.enableLanguageServer" = true;
|
"nix.enableLanguageServer" = true;
|
||||||
"nix.formatterPath" = "${pkgs.nixfmt-rfc-style}/bin/nixfmt";
|
"nix.formatterPath" = "${pkgs.nixfmt}/bin/nixfmt";
|
||||||
"nix.serverPath" = "${pkgs.nil}/bin/nil";
|
"nix.serverPath" = "${pkgs.nil}/bin/nil";
|
||||||
"nix.serverSettings" = {
|
"nix.serverSettings" = {
|
||||||
"nil" = {
|
"nil" = {
|
||||||
"formatting" = {
|
"formatting" = {
|
||||||
"command" = ["${pkgs.nixfmt-rfc-style}/bin/nixfmt"];
|
"command" = ["${pkgs.nixfmt}/bin/nixfmt"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9,16 +9,16 @@ let
|
|||||||
config = config.nixpkgs.config;
|
config = config.nixpkgs.config;
|
||||||
localSystem = { inherit system; };
|
localSystem = { inherit system; };
|
||||||
};
|
};
|
||||||
# nur = import inputs.nur {
|
nur = import inputs.nur {
|
||||||
# nurpkgs = import inputs.nixpkgs {
|
nurpkgs = import inputs.nixpkgs {
|
||||||
# system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
# };
|
};
|
||||||
# };
|
};
|
||||||
in
|
in
|
||||||
with lib; {
|
with lib; {
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
inputs.ataraxiasjel-nur.overlays.default
|
nur.repos.ataraxiasjel.overlays.default
|
||||||
inputs.ataraxiasjel-nur.overlays.grub2-argon2
|
nur.repos.ataraxiasjel.overlays.grub2-argon2
|
||||||
inputs.deploy-rs.overlay
|
inputs.deploy-rs.overlay
|
||||||
inputs.hyprland.overlays.default
|
inputs.hyprland.overlays.default
|
||||||
(final: prev:
|
(final: prev:
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
{ config, inputs, ... }: {
|
{ config, inputs, ... }: {
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.authentik ];
|
|
||||||
|
|
||||||
sops.secrets.authentik-env.sopsFile = inputs.self.secretsDir + /home-hypervisor/authentik.yaml;
|
sops.secrets.authentik-env.sopsFile = inputs.self.secretsDir + /home-hypervisor/authentik.yaml;
|
||||||
sops.secrets.authentik-ldap.sopsFile = inputs.self.secretsDir + /home-hypervisor/authentik.yaml;
|
sops.secrets.authentik-ldap.sopsFile = inputs.self.secretsDir + /home-hypervisor/authentik.yaml;
|
||||||
sops.secrets.authentik-env.restartUnits = [ "authentik-server.service" "authentik-worker.service" ];
|
sops.secrets.authentik-env.restartUnits = [ "authentik-server.service" "authentik-worker.service" ];
|
||||||
|
@ -40,14 +40,11 @@ in {
|
|||||||
owner = "headscale";
|
owner = "headscale";
|
||||||
restartUnits = [ "headscale.service" ];
|
restartUnits = [ "headscale.service" ];
|
||||||
};
|
};
|
||||||
systemd.services.headscale = {
|
systemd.services.headscale.after = lib.mkIf config.services.authentik.enable [
|
||||||
serviceConfig.TimeoutStopSec = 10;
|
"authentik-server.service"
|
||||||
after = lib.mkIf config.services.authentik.enable [
|
"authentik-worker.service"
|
||||||
"authentik-server.service"
|
"nginx.service"
|
||||||
"authentik-worker.service"
|
];
|
||||||
"nginx.service"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
persist.state.directories = [ "/var/lib/headscale" ];
|
persist.state.directories = [ "/var/lib/headscale" ];
|
||||||
}
|
}
|
@ -1,30 +1,72 @@
|
|||||||
{ config, inputs, ... }: {
|
{ config, lib, pkgs, ... }:
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.homepage ];
|
let
|
||||||
|
backend = config.virtualisation.oci-containers.backend;
|
||||||
services.homepage-dashboard = {
|
nas-path = "/media/nas/containers";
|
||||||
enable = true;
|
pod-name = "homepage-pod";
|
||||||
listenPort = 3000;
|
pod-dns = "192.168.0.1";
|
||||||
dataDir = "/srv/homepage";
|
open-ports = [
|
||||||
|
"127.0.0.1:3000:3000/tcp"
|
||||||
|
];
|
||||||
|
in {
|
||||||
|
virtualisation.oci-containers.containers = {
|
||||||
|
homepage = {
|
||||||
|
autoStart = true;
|
||||||
|
image = "ghcr.io/gethomepage/homepage:v0.8.0";
|
||||||
|
environment = {
|
||||||
|
PUID = "1000";
|
||||||
|
PGID = "100";
|
||||||
|
};
|
||||||
|
extraOptions = [ "--pod=${pod-name}" ];
|
||||||
|
volumes = [
|
||||||
|
"${nas-path}/homepage/config:/app/config"
|
||||||
|
"${nas-path}/homepage/icons:/app/public/icons"
|
||||||
|
"${nas-path}/homepage/images:/app/public/images"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
docker-proxy = {
|
||||||
|
autoStart = true;
|
||||||
|
image = "ghcr.io/tecnativa/docker-socket-proxy:0.1.1";
|
||||||
|
environment = {
|
||||||
|
CONTAINERS = "1";
|
||||||
|
SERVICES = "0";
|
||||||
|
TASKS = "0";
|
||||||
|
POST = "0";
|
||||||
|
};
|
||||||
|
extraOptions = [ "--pod=${pod-name}" ];
|
||||||
|
volumes = [
|
||||||
|
"${nas-path}/homepage/config:/app/config"
|
||||||
|
"${nas-path}/homepage/icons:/app/public/icons"
|
||||||
|
"${nas-path}/homepage/images:/app/public/images"
|
||||||
|
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = let
|
systemd.tmpfiles.rules = [
|
||||||
cfg = config.services.homepage-dashboard;
|
"d ${nas-path}/homepage/config 0755 1000 100 -"
|
||||||
in [
|
"d ${nas-path}/homepage/icons 0755 1000 100 -"
|
||||||
"d ${cfg.dataDir} 0755 ${cfg.user} ${cfg.group} -"
|
"d ${nas-path}/homepage/images 0755 1000 100 -"
|
||||||
];
|
];
|
||||||
|
|
||||||
virtualisation.oci-containers.containers.docker-proxy = {
|
systemd.services."podman-create-${pod-name}" = let
|
||||||
autoStart = true;
|
portsMapping = lib.concatMapStrings (port: " -p " + port) open-ports;
|
||||||
image = "ghcr.io/tecnativa/docker-socket-proxy:0.1.1";
|
start = pkgs.writeShellScript "create-pod-${pod-name}" ''
|
||||||
environment = {
|
podman pod exists ${pod-name} || podman pod create -n ${pod-name} ${portsMapping} --dns ${pod-dns}
|
||||||
CONTAINERS = "1";
|
'';
|
||||||
SERVICES = "0";
|
stop = "podman pod rm -i -f ${pod-name}";
|
||||||
TASKS = "0";
|
in rec {
|
||||||
POST = "0";
|
path = [ pkgs.coreutils config.virtualisation.podman.package ];
|
||||||
};
|
before = [
|
||||||
ports = [ "127.0.0.1:2375:2375/tcp" ];
|
"${backend}-homepage.service"
|
||||||
volumes = [
|
"${backend}-docker-proxy.service"
|
||||||
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
||||||
];
|
];
|
||||||
|
requiredBy = before;
|
||||||
|
partOf = before;
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = "yes";
|
||||||
|
ExecStart = start;
|
||||||
|
ExecStop = stop;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -13,8 +13,6 @@ let
|
|||||||
restartUnits = [ "kes.service" ];
|
restartUnits = [ "kes.service" ];
|
||||||
};
|
};
|
||||||
in {
|
in {
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.kes ];
|
|
||||||
|
|
||||||
sops.secrets.minio-credentials = minio-secret;
|
sops.secrets.minio-credentials = minio-secret;
|
||||||
sops.secrets.kes-vault-env = kes-secret;
|
sops.secrets.kes-vault-env = kes-secret;
|
||||||
sops.secrets.kes-key = kes-secret;
|
sops.secrets.kes-key = kes-secret;
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
sopsFile = inputs.self.secretsDir + /home-hypervisor/ocis.yaml;
|
sopsFile = inputs.self.secretsDir + /home-hypervisor/ocis.yaml;
|
||||||
restartUnits = [ "ocis-server.service" ];
|
restartUnits = [ "ocis-server.service" ];
|
||||||
};
|
};
|
||||||
imports = [ inputs.ataraxiasjel-nur.nixosModules.ocis ];
|
|
||||||
|
|
||||||
services.ocis = {
|
services.ocis = {
|
||||||
enable = true;
|
enable = true;
|
||||||
configDir = "/var/lib/ocis";
|
configDir = "/var/lib/ocis";
|
||||||
|
@ -24,16 +24,10 @@ in {
|
|||||||
wantedBy = [ "multi-user.target" ];
|
wantedBy = [ "multi-user.target" ];
|
||||||
partOf = [ "vault.service" ];
|
partOf = [ "vault.service" ];
|
||||||
after = [ "vault.service" ];
|
after = [ "vault.service" ];
|
||||||
path = [ pkgs.curl pkgs.jq ];
|
path = [ pkgs.curl ];
|
||||||
script = ''
|
script = ''
|
||||||
set -a
|
set -aeuo pipefail
|
||||||
source ${config.sops.secrets.vault-keys-env.path}
|
source ${config.sops.secrets.vault-keys-env.path}
|
||||||
while true; do
|
|
||||||
initialized=$(curl -s ${api-addr}/v1/sys/health | jq -r '.initialized')
|
|
||||||
[[ "$initialized" = "true" ]] && break
|
|
||||||
echo "Vault has not been initialized yet. Will try again after 5 seconds." >&2
|
|
||||||
sleep 5
|
|
||||||
done
|
|
||||||
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY1\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY1\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
||||||
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY2\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY2\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
||||||
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY3\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
curl -H "Content-Type: application/json" --data "{\"key\":\"$VAULT_KEY3\"}" ${api-addr}/v1/sys/unseal >/dev/null 2>&1
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user