mirror of
https://github.com/nmasur/dotfiles
synced 2025-07-06 07:20:13 +00:00
initial refactoring
This commit is contained in:
41
platforms/nixos/modules/services/betterlockscreen.nix
Normal file
41
platforms/nixos/modules/services/betterlockscreen.nix
Normal 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"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
@ -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}";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
64
platforms/nixos/modules/services/filebrowser.nix
Normal file
64
platforms/nixos/modules/services/filebrowser.nix
Normal 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 ];
|
||||
|
||||
};
|
||||
|
||||
}
|
37
platforms/nixos/modules/services/identity.nix
Normal file
37
platforms/nixos/modules/services/identity.nix
Normal 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
|
||||
'';
|
||||
};
|
||||
|
||||
};
|
||||
}
|
40
platforms/nixos/modules/services/n8n.nix
Normal file
40
platforms/nixos/modules/services/n8n.nix
Normal 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}"; } ];
|
||||
}
|
||||
];
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
112
platforms/nixos/modules/services/secrets.nix
Normal file
112
platforms/nixos/modules/services/secrets.nix
Normal 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";
|
||||
# };
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user