initial refactoring

This commit is contained in:
Noah Masur
2025-01-20 22:35:40 -05:00
parent a4b5e05f8f
commit c7933f8502
209 changed files with 5998 additions and 5308 deletions

View File

@ -0,0 +1,41 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.betterlockscreen;
lockCmd = "${pkgs.betterlockscreen}/bin/betterlockscreen --lock --display 1 --blur 0.5 --span";
in
{
options.services.betterlockscreen.enable = lib.mkEnableOption "Betterlockscreen X server display lock";
config = lib.mkIf cfg.enable {
# Ref: https://github.com/betterlockscreen/betterlockscreen/blob/next/system/betterlockscreen%40.service
systemd.services.lock = {
enable = true;
description = "Lock the screen on resume from suspend";
before = [
"sleep.target"
"suspend.target"
];
serviceConfig = {
User = config.user;
Type = "simple";
Environment = "DISPLAY=:0";
TimeoutSec = "infinity";
ExecStart = lockCmd;
ExecStartPost = "${pkgs.coreutils-full}/bin/sleep 1";
};
wantedBy = [
"sleep.target"
"suspend.target"
];
};
};
}

View File

@ -0,0 +1,53 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.cloudflare-dyndns-no-proxy;
in
{
options.services.cloudflare-dyndns-no-proxy.enable = lib.mkEnableOption "Cloudflare dyndns client without proxying";
config = lib.mkIf cfg.enable {
# Run a second copy of dyn-dns for non-proxied domains
# Adapted from: https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/networking/cloudflare-dyndns.nix
systemd.services.cloudflare-dyndns-noproxy =
lib.mkIf ((builtins.length config.cloudflare.noProxyDomains) > 0)
{
description = "CloudFlare Dynamic DNS Client (no proxy)";
after = [
"network.target"
"cloudflare-api-secret.service"
];
requires = [ "cloudflare-api-secret.service" ];
wantedBy = [ "multi-user.target" ];
startAt = "*:0/5";
environment = {
CLOUDFLARE_DOMAINS = toString config.cloudflare.noProxyDomains;
};
serviceConfig = {
Type = "simple";
DynamicUser = true;
StateDirectory = "cloudflare-dyndns-noproxy";
EnvironmentFile = config.services.cloudflare-dyndns.apiTokenFile;
ExecStart =
let
args =
[ "--cache-file /var/lib/cloudflare-dyndns-noproxy/ip.cache" ]
++ (if config.services.cloudflare-dyndns.ipv4 then [ "-4" ] else [ "-no-4" ])
++ (if config.services.cloudflare-dyndns.ipv6 then [ "-6" ] else [ "-no-6" ])
++ lib.optional config.services.cloudflare-dyndns.deleteMissing "--delete-missing";
in
"${pkgs.cloudflare-dyndns}/bin/cloudflare-dyndns ${toString args}";
};
};
};
}

View File

@ -0,0 +1,64 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.filebrowser;
dataDir = "/var/lib/filebrowser";
settings = {
port = 8020;
baseURL = "";
address = "";
log = "stdout";
database = "${dataDir}/filebrowser.db";
root = "";
"auth.method" = "json";
username = config.user;
# Generate password: htpasswd -nBC 10 "" | tr -d ':\n'
password = "$2y$10$ze1cMob0k6pnXRjLowYfZOVZWg4G.dsPtH3TohbUeEbI0sdkG9.za";
};
in
{
options.services.filebrowser = {
enable = lib.mkEnableOption "Filebrowser private files";
passwordHash = lib.mkOption {
type = lib.types.str;
description = ''Hashed password created from htpasswd -nBC 10 "" | tr -d ':\n' '';
};
};
config = lib.mkIf cfg.enable {
environment.etc."filebrowser/.filebrowser.json".text = builtins.toJSON settings;
systemd.services.filebrowser = lib.mkIf config.filebrowser.enable {
description = "Filebrowser cloud file services";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
startLimitIntervalSec = 14400;
startLimitBurst = 10;
serviceConfig = {
ExecStart = "${pkgs.filebrowser}/bin/filebrowser";
DynamicUser = true;
Group = "shared";
ReadWritePaths = [ dataDir ];
StateDirectory = [ "filebrowser" ];
Restart = "on-failure";
RestartPreventExitStatus = 1;
RestartSec = "5s";
};
path = [ pkgs.getent ]; # Fix: getent not found in $PATH
};
# Configure Cloudflare DNS to point to this machine
services.cloudflare-dyndns.domains = [ config.hostnames.files ];
};
}

View File

@ -0,0 +1,37 @@
{ config, lib, ... }:
let
cfg = config.services.wait-for-identity;
in
{
options.services.wait-for-identity = {
enable = lib.mkEnableOption "Wait for identity file oneshot";
identityFile = lib.mkOption {
type = lib.types.path;
};
};
config = lib.mkIf cfg.enable {
# Wait for secret to be placed on the machine
systemd.services.wait-for-identity = {
description = "Wait until identity file exists on the machine";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
for i in $(seq 1 10); do
if [ -f ${builtins.toString cfg.identityFile} ]; then
echo "Identity file found."
exit 0
fi
sleep 6
done
'';
};
};
}

View File

@ -0,0 +1,40 @@
# n8n is an automation integration tool for connecting data from services
# together with triggers.
{ config, lib, ... }:
{
config = lib.mkIf config.services.n8n.enable {
unfreePackages = [ "n8n" ];
services.n8n = {
webhookUrl = "https://${config.hostnames.n8n}";
settings = {
listen_address = "127.0.0.1";
port = 5678;
};
};
systemd.services.n8n.environment = {
N8N_EDITOR_BASE_URL = config.services.n8n.webhookUrl;
};
# Configure Cloudflare DNS to point to this machine
services.cloudflare-dyndns.domains = [ config.hostnames.n8n ];
# Allow web traffic to Caddy
caddy.routes = [
{
match = [ { host = [ config.hostnames.n8n ]; } ];
handle = [
{
handler = "reverse_proxy";
upstreams = [ { dial = "localhost:${builtins.toString config.services.n8n.settings.port}"; } ];
}
];
}
];
};
}

View File

@ -0,0 +1,112 @@
# Secrets management method taken from here:
# https://xeiaso.net/blog/nixos-encrypted-secrets-2021-01-20
# In my case, I pre-encrypt my secrets and commit them to git.
{
config,
pkgs,
lib,
...
}:
let
cfg = config.secrets;
in
{
options = {
secretsDirectory = lib.mkOption {
type = lib.types.path;
description = "Default path to place secrets.";
default = "/var/private";
};
secretsIdentityFile = lib.mkOption {
type = lib.types.path;
description = "Path containing decryption identity.";
};
secrets = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
source = lib.mkOption {
type = lib.types.path;
description = "Path to encrypted secret.";
};
dest = lib.mkOption {
type = lib.types.str;
description = "Resulting path for decrypted secret.";
};
owner = lib.mkOption {
default = "root";
type = lib.types.str;
description = "User to own the secret.";
};
group = lib.mkOption {
default = "root";
type = lib.types.str;
description = "Group to own the secret.";
};
permissions = lib.mkOption {
default = "0400";
type = lib.types.str;
description = "Permissions expressed as octal.";
};
prefix = lib.mkOption {
default = "";
type = lib.types.str;
description = "Prefix for secret value (for environment files).";
};
};
}
);
description = "Set of secrets to decrypt to disk.";
default = { };
};
};
config = lib.mkIf (builtins.length cfg.secrets > 0) {
# Create a default directory to place secrets
systemd.tmpfiles.rules = [ "d ${config.secretsDirectory} 0755 root wheel" ];
# Declare oneshot service to decrypt secret using SSH host key
# - Requires that the secret is already encrypted for the host
# - Encrypt secrets: nix run github:nmasur/dotfiles#encrypt-secret
systemd.services = lib.mapAttrs' (name: attrs: {
name = "${name}-secret";
value = {
description = "Decrypt secret for ${name}";
wantedBy = [ "multi-user.target" ];
bindsTo = lib.mkIf config.services.wait-for-identity.enable [ "wait-for-identity.service" ];
after = lib.mkIf config.services.wait-for-identity.enable [ "wait-for-identity.service" ];
serviceConfig.Type = "oneshot";
script = ''
echo "${attrs.prefix}$(
${pkgs.age}/bin/age --decrypt \
--identity ${config.secretsIdentityFile} ${attrs.source}
)" > ${attrs.dest}
chown '${attrs.owner}':'${attrs.group}' '${attrs.dest}'
chmod '${attrs.permissions}' '${attrs.dest}'
'';
};
}) config.secrets;
# Example declaration
# config.secrets.my-secret = {
# source = ../../private/my-secret.age;
# dest = "/var/lib/private/my-secret";
# owner = "my-app";
# group = "my-app";
# permissions = "0440";
# };
};
}