add modules
This commit is contained in:
parent
e913bd96d5
commit
23aa68d0fa
12 changed files with 4 additions and 3 deletions
|
@ -1,6 +0,0 @@
|
|||
_: {
|
||||
networking.useDHCP = true;
|
||||
|
||||
# Enable qemu guest agent
|
||||
services.qemuGuest.enable = true;
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{ ... }: {
|
||||
imports = [ ./meta.nix ./nginx.nix ./dns.nix ./flood.nix ./gnome ./unpackerr.nix ./vault.nix ];
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
{ config, pkgs, lib, hosts, flat_hosts, ... }:
|
||||
# DNS Module to set up Unbound DNS with all my hosts in the config
|
||||
# Used for DNS Servers and my laptop
|
||||
with lib;
|
||||
let
|
||||
inherit (builtins) filter hasAttr attrNames;
|
||||
domains = attrNames hosts;
|
||||
ipv4Host = filter (hasAttr "ip") flat_hosts;
|
||||
ipv6Hosts = filter (hasAttr "ip6") flat_hosts;
|
||||
|
||||
localData = { hostname, realm, ip, ... }: ''"${hostname}.${realm}. A ${ip}"'';
|
||||
local6Data = { hostname, realm, ip6, ... }:
|
||||
''"${hostname}.${realm}. AAAA ${ip6}"'';
|
||||
ptrData = { hostname, realm, ip, ... }: ''"${ip} ${hostname}.${realm}"'';
|
||||
ptr6Data = { hostname, realm, ip6, ... }: ''"${ip6} ${hostname}.${realm}"'';
|
||||
|
||||
cfg = config.services.v.dns;
|
||||
in {
|
||||
options.services.v.dns = {
|
||||
enable = mkEnableOption "v.dns";
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc ''
|
||||
Whether to open port 53 in the firwall for unbound dns
|
||||
And `services.prometheus.exporters.unbound.port` for metrics (if enabled).
|
||||
'';
|
||||
};
|
||||
|
||||
enableMetrics = mkOption {
|
||||
type = types.bool;
|
||||
default = cfg.mode == "server";
|
||||
description = ''
|
||||
Enable prometheus metrics
|
||||
'';
|
||||
};
|
||||
|
||||
mode = mkOption {
|
||||
type = enum [ "server" "laptop" ];
|
||||
default = "laptop";
|
||||
description = ''
|
||||
Whether to configure the DNS in server mode (listen on all interfaces) or laptop mode (just on localhost)
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ 53 ];
|
||||
allowedUDPPorts = [ 53 ];
|
||||
};
|
||||
services.prometheus.exporters.unbound = mkIf cfg.enableMetrics {
|
||||
enable = true;
|
||||
inherit (cfg) openFirewall;
|
||||
inherit (config.services.unbound) group;
|
||||
controlInterface = config.services.unbound.localControlSocketPath;
|
||||
};
|
||||
services.unbound = {
|
||||
enable = true;
|
||||
package = pkgs.v.unbound;
|
||||
localControlSocketPath =
|
||||
mkIf cfg.enableMetrics "/run/unbound/unbound.socket";
|
||||
settings = {
|
||||
server = mkMerge [
|
||||
{
|
||||
use-syslog = "yes";
|
||||
module-config = ''"validator iterator"'';
|
||||
|
||||
local-zone =
|
||||
map (localdomain: ''"${localdomain}}." transparent'') domains;
|
||||
local-data = (map localData ipv4Host) ++ (map local6Data ipv6Hosts);
|
||||
local-data-ptr = (map ptrData ipv4Host) ++ (map ptr6Data ipv6Hosts);
|
||||
|
||||
private-address = [
|
||||
"127.0.0.0/8"
|
||||
"10.0.0.0/8"
|
||||
"::ffff:a00:0/104"
|
||||
"172.16.0.0/12"
|
||||
"::ffff:ac10:0/108"
|
||||
"169.254.0.0/16"
|
||||
"::ffff:a9fe:0/112"
|
||||
"192.168.0.0/16"
|
||||
"::ffff:c0a8:0/112"
|
||||
"fd00::/8"
|
||||
"fe80::/10"
|
||||
];
|
||||
}
|
||||
(mkIf (cfg.mode == "server") {
|
||||
interface-automatic = "yes";
|
||||
interface = [ "0.0.0.0" "::0" ];
|
||||
access-control = [
|
||||
"127.0.0.1/32 allow_snoop"
|
||||
"::1 allow_snoop"
|
||||
"10.42.0.0/16 allow"
|
||||
"127.0.0.0/8 allow"
|
||||
"192.168.0.0/23 allow"
|
||||
"192.168.2.0/24 allow"
|
||||
"::1/128 allow"
|
||||
];
|
||||
})
|
||||
(mkIf (cfg.mode == "laptop") {
|
||||
interface = [ "127.0.0.1" "::1" ];
|
||||
access-control = [ "127.0.0.1/32 allow_snoop" "::1 allow_snoop" ];
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
with lib;
|
||||
let cfg = config.services.flood;
|
||||
in {
|
||||
options.services.flood = {
|
||||
enable = mkEnableOption "flood";
|
||||
|
||||
user = mkOption {
|
||||
default = "flood";
|
||||
type = types.str;
|
||||
description = ''
|
||||
User account under which flood runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "rtorrent";
|
||||
description = ''
|
||||
Group under which flood runs.
|
||||
Flood needs to have the correct permissions if accessing rtorrent through the socket.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.flood;
|
||||
defaultText = "pkgs.flood";
|
||||
description = ''
|
||||
The flood package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = types.str;
|
||||
default = "127.0.0.1";
|
||||
description = ''
|
||||
Address flood binds to.
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.port;
|
||||
default = 3000;
|
||||
description = ''
|
||||
The flood web port.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Whether to open the firewall for the port in <option>services.flood.port</option>.
|
||||
'';
|
||||
};
|
||||
|
||||
rpcSocket = mkOption {
|
||||
type = types.str;
|
||||
readOnly = true;
|
||||
default = "/run/rtorrent/rpc.sock";
|
||||
description = ''
|
||||
RPC socket path.
|
||||
(Only used when auth=none).
|
||||
'';
|
||||
};
|
||||
|
||||
dataDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/flood";
|
||||
description = ''
|
||||
The directory where flood stores its data files.
|
||||
'';
|
||||
};
|
||||
|
||||
downloadDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/rtorrent/download";
|
||||
description = ''
|
||||
Root directory for downloaded files.
|
||||
'';
|
||||
};
|
||||
|
||||
authMode = mkOption {
|
||||
type = types.str;
|
||||
default = "none";
|
||||
description = ''
|
||||
Access control and user management method.
|
||||
Either 'default' or 'none'.
|
||||
'';
|
||||
};
|
||||
|
||||
ssl = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Enable SSL.
|
||||
key.pem and fullchain.pem needed in runtime directory.
|
||||
'';
|
||||
};
|
||||
|
||||
baseURI = mkOption {
|
||||
type = types.str;
|
||||
default = "/";
|
||||
description = ''
|
||||
This URI will prefix all of Flood's HTTP requests
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Create group if set to default
|
||||
users.groups = mkIf (cfg.group == "rtorrent") { rtorrent = { }; };
|
||||
|
||||
# Create user if set to default
|
||||
users.users = mkIf (cfg.user == "flood") {
|
||||
flood = {
|
||||
inherit (cfg) group;
|
||||
shell = pkgs.bashInteractive;
|
||||
home = cfg.dataDir;
|
||||
description = "flood Daemon user";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Open firewall if option is set to do so.
|
||||
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
|
||||
|
||||
# The actual service
|
||||
systemd.services.flood = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
description = "flood system service";
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Type = "simple";
|
||||
Restart = "on-failure";
|
||||
WorkingDirectory = cfg.dataDir;
|
||||
ExecStart =
|
||||
"${cfg.package}/bin/flood --baseuri ${cfg.baseURI} --rundir ${cfg.dataDir} --host ${cfg.host} --port ${
|
||||
toString cfg.port
|
||||
} ${
|
||||
if cfg.ssl then "--ssl" else ""
|
||||
} --auth ${cfg.authMode} --rtsocket ${cfg.rpcSocket} --allowedpath ${cfg.downloadDir}";
|
||||
};
|
||||
};
|
||||
|
||||
# This is needed to create the dataDir with the correct permissions.
|
||||
systemd.tmpfiles.rules =
|
||||
[ "d '${cfg.dataDir}' 0755 ${cfg.user} ${cfg.group} -" ];
|
||||
};
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
{ config, pkgs, lib, inputs, ... }:
|
||||
with lib;
|
||||
let cfg = config.services.v.gnome;
|
||||
in {
|
||||
imports = [
|
||||
inputs.gnome-autounlock-keyring.nixosModules.default
|
||||
];
|
||||
|
||||
options.services.v.gnome = {
|
||||
enable = mkEnableOption "v.gnome";
|
||||
hm = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to enable home manager integration to set default dconf values
|
||||
'';
|
||||
};
|
||||
|
||||
auto-unlock-keyring = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = ''
|
||||
Whether to automatically unlock the keyring upon login.
|
||||
This is mostly useful if you are logging in using a fingerprint
|
||||
or FIDO device and the keyring does not automatically get unlocked.
|
||||
Make sure you have enrolled you password into the keyring unlocker.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services = {
|
||||
xserver = {
|
||||
enable = true;
|
||||
excludePackages = [ pkgs.xterm ];
|
||||
|
||||
# Configure keymap in X11
|
||||
|
||||
layout = "us";
|
||||
xkbVariant = "altgr-intl";
|
||||
|
||||
# Enable the GNOME Desktop Environment.
|
||||
displayManager.gdm.enable = true;
|
||||
desktopManager.gnome.enable = true;
|
||||
};
|
||||
udev.packages = with pkgs; [ gnome.gnome-settings-daemon ];
|
||||
dbus.enable = true;
|
||||
udisks2.enable = true;
|
||||
};
|
||||
|
||||
services.gnome-autounlock-keyring.enable = cfg.auto-unlock-keyring;
|
||||
|
||||
# Add Home-manager dconf stuff
|
||||
home-manager.sharedModules = mkIf cfg.hm [ ./hm.nix ];
|
||||
environment.gnome.excludePackages =
|
||||
(with pkgs; [ gnome-photos gnome-tour gnome-connections ])
|
||||
++ (with pkgs.gnome; [
|
||||
atomix # puzzle game
|
||||
epiphany # web browser
|
||||
geary # email reader
|
||||
gedit # text editor
|
||||
gnome-calendar
|
||||
gnome-clocks
|
||||
gnome-contacts
|
||||
gnome-maps
|
||||
gnome-music
|
||||
gnome-notes
|
||||
gnome-terminal
|
||||
gnome-weather
|
||||
hitori # sudoku game
|
||||
iagno # go game
|
||||
simple-scan # document scanner
|
||||
tali # poker game
|
||||
totem # video player
|
||||
]);
|
||||
|
||||
# Services required for gnome
|
||||
programs.dconf.enable = true;
|
||||
|
||||
# Extra gnome packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
gnome.gnome-tweaks
|
||||
gnome.gnome-boxes
|
||||
];
|
||||
};
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
{ lib, ... }:
|
||||
|
||||
with lib.hm.gvariant;
|
||||
let
|
||||
inherit (builtins) attrNames map;
|
||||
inherit (lib.attrsets) mapAttrs' nameValuePair;
|
||||
generate_custom_keybindings = binds:
|
||||
{
|
||||
"org/gnome/settings-daemon/plugins/media-keys" = {
|
||||
custom-keybindings = map (name:
|
||||
"/org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/${name}/")
|
||||
(attrNames binds);
|
||||
};
|
||||
} // mapAttrs' (name:
|
||||
nameValuePair
|
||||
"org/gnome/settings-daemon/plugins/media-keys/custom-keybindings/${name}")
|
||||
binds;
|
||||
in {
|
||||
xdg.mimeApps.enable = true;
|
||||
xdg.mimeApps.defaultApplications = {
|
||||
"text/plain" = "org.gnome.TextEditor.desktop";
|
||||
"application/pdf" = "org.gnome.Evince.desktop";
|
||||
|
||||
# Firefox
|
||||
"text/html" = "firefox.desktop";
|
||||
"x-scheme-handler/http" = "firefox.desktop";
|
||||
"x-scheme-handler/https" = "firefox.desktop";
|
||||
"x-scheme-handler/chrome" = "firefox.desktop";
|
||||
"application/x-extension-htm" = "firefox.desktop";
|
||||
"application/x-extension-shtml" = "firefox.desktop";
|
||||
"application/xhtml+xml" = "firefox.desktop";
|
||||
"application/x-extension-xhtml" = "firefox.desktop";
|
||||
"application/x-extension-xht" = "firefox.desktop";
|
||||
"application/x-extension-html" = "firefox.desktop";
|
||||
|
||||
# Images
|
||||
"image/bmp" = "org.gnome.eog.desktop";
|
||||
"image/gif" = "org.gnome.eog.desktop";
|
||||
"image/jpg" = "org.gnome.eog.desktop";
|
||||
"image/pjpeg" = "org.gnome.eog.desktop";
|
||||
"image/png" = "org.gnome.eog.desktop";
|
||||
"image/tiff" = "org.gnome.eog.desktop";
|
||||
"image/webp" = "org.gnome.eog.desktop";
|
||||
"image/x-bmp" = "org.gnome.eog.desktop";
|
||||
"image/x-gray" = "org.gnome.eog.desktop";
|
||||
"image/x-icb" = "org.gnome.eog.desktop";
|
||||
"image/x-ico" = "org.gnome.eog.desktop";
|
||||
"image/x-png" = "org.gnome.eog.desktop";
|
||||
"image/x-portable-anymap" = "org.gnome.eog.desktop";
|
||||
"image/x-portable-bitmap" = "org.gnome.eog.desktop";
|
||||
"image/x-portable-graymap" = "org.gnome.eog.desktop";
|
||||
"image/x-portable-pixmap" = "org.gnome.eog.desktop";
|
||||
"image/x-xbitmap" = "org.gnome.eog.desktop";
|
||||
"image/x-xpixmap" = "org.gnome.eog.desktop";
|
||||
"image/x-pcx" = "org.gnome.eog.desktop";
|
||||
"image/svg+xml" = "org.gnome.eog.desktop";
|
||||
"image/svg+xml-compressed" = "org.gnome.eog.desktop";
|
||||
"image/vnd.wap.wbmp" = "org.gnome.eog.desktop";
|
||||
"image/x-icns" = "org.gnome.eog.desktop";
|
||||
};
|
||||
|
||||
dconf.settings = {
|
||||
"org/gnome/desktop/input-sources" = {
|
||||
sources = [ (mkTuple [ "xkb" "us+altgr-intl" ]) ];
|
||||
xkb-options = [ "terminate:ctrl_alt_bksp" ];
|
||||
};
|
||||
|
||||
"org/gnome/desktop/peripherals/touchpad" = {
|
||||
tap-to-click = true;
|
||||
two-finger-scrolling-enabled = true;
|
||||
};
|
||||
|
||||
"org/gnome/mutter" = {
|
||||
attach-modal-dialogs = true;
|
||||
dynamic-workspaces = false;
|
||||
edge-tiling = true;
|
||||
focus-change-on-pointer-rest = true;
|
||||
workspaces-only-on-primary = true;
|
||||
};
|
||||
|
||||
"org/gnome/mutter/keybindings" = {
|
||||
toggle-tiled-left = [ "<Super>bracketleft" ];
|
||||
toggle-tiled-right = [ "<Super>bracketright" ];
|
||||
};
|
||||
|
||||
"org/gnome/shell/keybindings" = { toggle-overview = [ "<Super>d" ]; };
|
||||
|
||||
"org/gnome/desktop/interface" = { color-scheme = "prefer-dark"; };
|
||||
|
||||
"org/gnome/desktop/wm/preferences" = {
|
||||
auto-raise = false;
|
||||
num-workspaces = 6;
|
||||
focus-mode = "sloppy";
|
||||
};
|
||||
|
||||
"org/gnome/desktop/wm/keybindings" = {
|
||||
raise-or-lower = [ "<Super>s" ];
|
||||
switch-applications = [ "<Super>Tab" ];
|
||||
switch-applications-backward = [ "<Super>Tab" ];
|
||||
move-to-workspace-1 = [ "<Shift><Super>1" ];
|
||||
move-to-workspace-2 = [ "<Shift><Super>2" ];
|
||||
move-to-workspace-3 = [ "<Shift><Super>3" ];
|
||||
move-to-workspace-4 = [ "<Shift><Super>4" ];
|
||||
move-to-workspace-5 = [ "<Shift><Super>5" ];
|
||||
move-to-workspace-6 = [ "<Shift><Super>6" ];
|
||||
switch-to-workspace-1 = [ "<Super>1" ];
|
||||
switch-to-workspace-2 = [ "<Super>2" ];
|
||||
switch-to-workspace-3 = [ "<Super>3" ];
|
||||
switch-to-workspace-4 = [ "<Super>4" ];
|
||||
switch-to-workspace-5 = [ "<Super>5" ];
|
||||
switch-to-workspace-6 = [ "<Super>6" ];
|
||||
toggle-fullscreen = [ "<Super><Shift>M" ];
|
||||
toggle-maximized = [ "<Super>m" ];
|
||||
close = [ "<Super>Q" ];
|
||||
};
|
||||
|
||||
"org/gnome/tweaks" = { show-extensions-notice = false; };
|
||||
|
||||
"org/gnome/boxes" = { first-run = false; };
|
||||
} // generate_custom_keybindings {
|
||||
"terminal" = {
|
||||
binding = "<Super>Return";
|
||||
command = "kgx";
|
||||
name = "Open Terminal";
|
||||
};
|
||||
"firefox" = {
|
||||
binding = "<Super>f";
|
||||
command = "firefox";
|
||||
name = "Open Firefox";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
{ lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
exposesOpts = {
|
||||
options = {
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
example = "<name>.example.com";
|
||||
description = ''
|
||||
The domain under which this service should be available
|
||||
'';
|
||||
};
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 80;
|
||||
example = 4242;
|
||||
description = ''
|
||||
The port under which the service runs on the host
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.meta = {
|
||||
|
||||
exposes = mkOption {
|
||||
type = with types; attrsOf (submodule exposesOpts);
|
||||
description = ''
|
||||
Exposed services
|
||||
'';
|
||||
};
|
||||
|
||||
ipv4 = mkOption {
|
||||
type = types.str;
|
||||
description = ''
|
||||
Own IPv4 Address
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = { };
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
{ lib, hosts, config, ... }:
|
||||
with lib;
|
||||
let cfg = config.services.v.nginx;
|
||||
in {
|
||||
options.services.v.nginx.autoExpose =
|
||||
mkEnableOption "generate vhosts";
|
||||
|
||||
config =
|
||||
let
|
||||
|
||||
proxy = url: {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
locations."/" = {
|
||||
proxyPass = url;
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
};
|
||||
|
||||
hosts' =
|
||||
filter (hasAttr "exposes") (attrValues hosts.${config.networking.domain});
|
||||
exposes = { ip, exposes, ... }:
|
||||
map ({ domain, port ? 80 }: { inherit ip domain port; }) (attrValues exposes);
|
||||
mkVhost = { ip, domain, port }: {
|
||||
"${domain}" = proxy "http://${ip}:${toString port}";
|
||||
};
|
||||
vhosts = foldr (el: acc: acc // mkVhost el) { } (concatMap exposes hosts');
|
||||
in
|
||||
mkIf cfg.autoExpose {
|
||||
services.nginx.virtualHosts = vhosts;
|
||||
};
|
||||
}
|
|
@ -1,328 +0,0 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.unpackerr;
|
||||
mkStarrOptions = { name, url }: {
|
||||
url = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "${url}";
|
||||
description = ''
|
||||
The URL to access ${name}
|
||||
'';
|
||||
};
|
||||
apiKey = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
The API key for accessing ${name}
|
||||
'';
|
||||
};
|
||||
paths = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "/downloads,/moreDownloads";
|
||||
description = ''
|
||||
List of paths where content is downloaded for ${name}
|
||||
'';
|
||||
};
|
||||
protocols = mkOption {
|
||||
type = types.str;
|
||||
default = "torrent";
|
||||
example = "torrent,usenet";
|
||||
description = ''
|
||||
Protocols to process
|
||||
'';
|
||||
};
|
||||
timeout = mkOption {
|
||||
type = types.str;
|
||||
default = "10s";
|
||||
description = ''
|
||||
How long to wait for ${name} to respond
|
||||
'';
|
||||
};
|
||||
deleteOrginal = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Delete archives after import?
|
||||
Recommend not setting this to true
|
||||
'';
|
||||
};
|
||||
deleteDelay = mkOption {
|
||||
type = types.str;
|
||||
default = "5m";
|
||||
description = ''
|
||||
Extracts are deleted this long after import. `-1` to disable.
|
||||
'';
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
options.services.unpackerr = {
|
||||
enable = mkEnableOption "unpackerr";
|
||||
|
||||
user = mkOption {
|
||||
default = "unpackerr";
|
||||
type = types.str;
|
||||
description = ''
|
||||
User account under which unpackerr runs.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = types.str;
|
||||
default = "unpackerr";
|
||||
description = ''
|
||||
Group under which unpackerr runs.
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkOption {
|
||||
type = types.package;
|
||||
default = pkgs.unpackerr;
|
||||
defaultText = "pkgs.unpackerr";
|
||||
description = ''
|
||||
The unpackerr package to use.
|
||||
'';
|
||||
};
|
||||
|
||||
debug = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Turns on more logs.
|
||||
'';
|
||||
};
|
||||
|
||||
interval = mkOption {
|
||||
type = types.str;
|
||||
default = "2m";
|
||||
description = ''
|
||||
How often apps are polled, recommended 1m to 5m
|
||||
'';
|
||||
};
|
||||
|
||||
startDelay = mkOption {
|
||||
type = types.str;
|
||||
default = "1m";
|
||||
description = ''
|
||||
Files are queued at least this long before extraction
|
||||
'';
|
||||
};
|
||||
|
||||
retryDelay = mkOption {
|
||||
type = types.str;
|
||||
default = "5m";
|
||||
description = ''
|
||||
Failed extractions are retried after at least this long
|
||||
'';
|
||||
};
|
||||
|
||||
maxRetries = mkOption {
|
||||
type = types.int;
|
||||
default = 3;
|
||||
description = ''
|
||||
Times to retry failed extractions. `0` = unlimited.
|
||||
'';
|
||||
};
|
||||
|
||||
parallel = mkOption {
|
||||
type = types.int;
|
||||
default = 1;
|
||||
description = ''
|
||||
Concurrent extractions, 1 is recommended.
|
||||
'';
|
||||
};
|
||||
|
||||
fileMode = mkOption {
|
||||
type = types.str;
|
||||
default = "0644";
|
||||
description = ''
|
||||
Extracted files are written with this mode
|
||||
'';
|
||||
};
|
||||
|
||||
dirMode = mkOption {
|
||||
type = types.str;
|
||||
default = "0755";
|
||||
description = ''
|
||||
Extracted folders are written with this mode
|
||||
'';
|
||||
};
|
||||
|
||||
sonarr = mkStarrOptions {
|
||||
name = "Sonarr";
|
||||
url = "http://localhost:8989";
|
||||
};
|
||||
|
||||
radarr = mkStarrOptions {
|
||||
name = "Radarr";
|
||||
url = "http://localhost:7878";
|
||||
};
|
||||
|
||||
lidarr = mkStarrOptions {
|
||||
name = "Lidarr";
|
||||
url = "http://localhost:8686";
|
||||
};
|
||||
|
||||
readarr = mkStarrOptions {
|
||||
name = "Readarr";
|
||||
url = "http://localhost:8787";
|
||||
};
|
||||
|
||||
folder = {
|
||||
path = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
folder path, not for Starr apps.
|
||||
'';
|
||||
};
|
||||
extractPath = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
description = ''
|
||||
Where to extract to, Defaults to <option>services.unpackerr.folder.path</option>.
|
||||
'';
|
||||
};
|
||||
deleteAfter = mkOption {
|
||||
type = types.str;
|
||||
default = "";
|
||||
example = "10m";
|
||||
description = ''
|
||||
Delete extracted files and/or archives after this duration, `0` to disable.
|
||||
'';
|
||||
};
|
||||
deleteOrginal = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Delete archives after extraction
|
||||
'';
|
||||
};
|
||||
deleteFiles = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Delete extracted files after successful extraction
|
||||
'';
|
||||
};
|
||||
moveBack = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = ''
|
||||
Move extracted items back into original folder
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
extraConfig = mkOption {
|
||||
type = types.attrs;
|
||||
default = { };
|
||||
description = ''
|
||||
Extra environment variables
|
||||
'';
|
||||
example = { UN_WEBHOOK_0_URL = "http://example.com"; };
|
||||
};
|
||||
|
||||
environmentFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
description = lib.mdDoc ''
|
||||
Environment file (see `systemd.exec(5)`
|
||||
"EnvironmentFile=" section for the syntax) to define variables for unpackerr.
|
||||
This option can be used to safely include secret keys into the unpackerr configuration.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# Create group if set to default
|
||||
users.groups = mkIf (cfg.group == "unpackerr") { unpackerr = { }; };
|
||||
|
||||
# Create user if set to default
|
||||
users.users = mkIf (cfg.user == "unpackerr") {
|
||||
unpackerr = {
|
||||
inherit (cfg) group;
|
||||
shell = pkgs.bashInteractive;
|
||||
createHome = false;
|
||||
description = "unpackerr Daemon user";
|
||||
isSystemUser = true;
|
||||
};
|
||||
};
|
||||
|
||||
# The actual service
|
||||
systemd.services.unpackerr = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network.target" ];
|
||||
description = "unpackerr system service";
|
||||
# Filter out all unset variables else unpackerr complains
|
||||
environment = filterAttrs (_n: v: stringLength v > 0)
|
||||
{
|
||||
# General options
|
||||
UN_DEBUG = "${toString cfg.debug}";
|
||||
UN_INTERVAL = "${cfg.interval}";
|
||||
UN_START_DELAY = "${cfg.startDelay}";
|
||||
UN_RETRY_DELAY = "${cfg.retryDelay}";
|
||||
UN_MAX_RETRIES = "${toString cfg.maxRetries}";
|
||||
UN_PARALLEL = "${toString cfg.parallel}";
|
||||
UN_FILE_MODE = "${cfg.fileMode}";
|
||||
UN_DIR_MODE = "${cfg.dirMode}";
|
||||
|
||||
# Sonarr
|
||||
UN_SONARR_0_URL = "${cfg.sonarr.url}";
|
||||
UN_SONARR_0_API_KEY = "${cfg.sonarr.apiKey}";
|
||||
UN_SONARR_0_PATHS_0 = "${cfg.sonarr.paths}";
|
||||
UN_SONARR_0_PROTOCOLS = "${cfg.sonarr.protocols}";
|
||||
UN_SONARR_0_TIMEOUT = "${cfg.sonarr.timeout}";
|
||||
UN_SONARR_0_DELETE_ORIG = "${toString cfg.sonarr.deleteOrginal}";
|
||||
UN_SONARR_0_DELETE_DELAY = "${cfg.sonarr.deleteDelay}";
|
||||
|
||||
# Radarr
|
||||
UN_RADARR_0_URL = "${cfg.radarr.url}";
|
||||
UN_RADARR_0_API_KEY = "${cfg.radarr.apiKey}";
|
||||
UN_RADARR_0_PATHS_0 = "${cfg.radarr.paths}";
|
||||
UN_RADARR_0_PROTOCOLS = "${cfg.radarr.protocols}";
|
||||
UN_RADARR_0_TIMEOUT = "${cfg.radarr.timeout}";
|
||||
UN_RADARR_0_DELETE_ORIG = "${toString cfg.radarr.deleteOrginal}";
|
||||
UN_RADARR_0_DELETE_DELAY = "${cfg.radarr.deleteDelay}";
|
||||
|
||||
# Lidarr
|
||||
UN_LIDARR_0_URL = "${cfg.lidarr.url}";
|
||||
UN_LIDARR_0_API_KEY = "${cfg.lidarr.apiKey}";
|
||||
UN_LIDARR_0_PATHS_0 = "${cfg.lidarr.paths}";
|
||||
UN_LIDARR_0_PROTOCOLS = "${cfg.lidarr.protocols}";
|
||||
UN_LIDARR_0_TIMEOUT = "${cfg.lidarr.timeout}";
|
||||
UN_LIDARR_0_DELETE_ORIG = "${toString cfg.lidarr.deleteOrginal}";
|
||||
UN_LIDARR_0_DELETE_DELAY = "${cfg.lidarr.deleteDelay}";
|
||||
|
||||
# Readarr
|
||||
UN_READARR_0_URL = "${cfg.readarr.url}";
|
||||
UN_READARR_0_API_KEY = "${cfg.readarr.apiKey}";
|
||||
UN_READARR_0_PATHS_0 = "${cfg.readarr.paths}";
|
||||
UN_READARR_0_PROTOCOLS = "${cfg.readarr.protocols}";
|
||||
UN_READARR_0_TIMEOUT = "${cfg.readarr.timeout}";
|
||||
UN_READARR_0_DELETE_ORIG = "${toString cfg.readarr.deleteOrginal}";
|
||||
UN_READARR_0_DELETE_DELAY = "${cfg.readarr.deleteDelay}";
|
||||
|
||||
# Folder
|
||||
UN_FOLDER_0_PATH = "${cfg.folder.path}";
|
||||
UN_FOLDER_0_EXTRACT_PATH = "${cfg.folder.extractPath}";
|
||||
UN_FOLDER_0_DELETE_AFTER = "${cfg.folder.deleteAfter}";
|
||||
UN_FOLDER_0_DELETE_ORIGINAL = "${toString cfg.folder.deleteOrginal}";
|
||||
UN_FOLDER_0_DELETE_FILES = "${toString cfg.folder.deleteFiles}";
|
||||
UN_FOLDER_0_MOVE_BACK = "${toString cfg.folder.moveBack}";
|
||||
} // cfg.extraConfig;
|
||||
serviceConfig = {
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
Type = "simple";
|
||||
Restart = "on-failure";
|
||||
ExecStart = "${cfg.package}/bin/unpackerr";
|
||||
} // optionalAttrs (cfg.environmentFile != null) {
|
||||
EnvironmentFile = cfg.environmentFile;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
{ config, pkgs, lib, flat_hosts, inputs, ... }:
|
||||
with lib;
|
||||
let
|
||||
cfg = config.services.v.vault;
|
||||
hostIP = config.meta.ipv4;
|
||||
|
||||
# Find all vault hosts that do not have the same IP as the current host
|
||||
vault_hosts =
|
||||
filter ({ tags ? [ ], ip ? "", ... }: (elem "vault" tags) && (ip != hostIP))
|
||||
flat_hosts;
|
||||
cluster_config = concatStrings (map
|
||||
({ ip, ... }: ''
|
||||
retry_join {
|
||||
leader_api_addr = "http://${ip}:${toString cfg.port}"
|
||||
}
|
||||
'')
|
||||
vault_hosts);
|
||||
in
|
||||
{
|
||||
options.services.v.vault = {
|
||||
enable = mkEnableOption "v's vault";
|
||||
|
||||
node_id = mkOption {
|
||||
type = types.str;
|
||||
description = lib.mdDoc ''
|
||||
The cluster node id of this node
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc ''
|
||||
Whether to open port `port` and `clusterPort` in the firewall for vault
|
||||
'';
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = types.int;
|
||||
default = 8200;
|
||||
description = lib.mdDoc ''
|
||||
The port vault listens on
|
||||
**note:** this has to be the same for all nodes in a cluster
|
||||
'';
|
||||
};
|
||||
|
||||
clusterPort = mkOption {
|
||||
type = types.int;
|
||||
default = 8201;
|
||||
description = lib.mdDoc ''
|
||||
The cluster port vault listens on
|
||||
**note:** this has to be the same for all nodes in a cluster
|
||||
'';
|
||||
};
|
||||
|
||||
autoUnseal = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = lib.mdDoc ''
|
||||
Whether to auto-unseal this vault
|
||||
'';
|
||||
};
|
||||
|
||||
autoUnsealKeysFile = mkOption {
|
||||
type = types.str;
|
||||
default = null;
|
||||
example = "/var/lib/vault-unseal/keys.json";
|
||||
description = lib.mdDoc ''
|
||||
auto unseal keys to use, has to be a json file with the following structure
|
||||
```json
|
||||
{
|
||||
keys = [ key_1, ..., key_n ]
|
||||
}
|
||||
```
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [{
|
||||
assertion = cfg.autoUnseal -> (cfg.autoUnsealKeysFile != null);
|
||||
message = "If autoUnseal is enabled, a token path is required!";
|
||||
}];
|
||||
|
||||
networking.firewall.allowedTCPPorts =
|
||||
mkIf cfg.openFirewall [ cfg.port cfg.clusterPort ];
|
||||
|
||||
services.vault = {
|
||||
enable = true;
|
||||
# bin version includes the UI
|
||||
package = pkgs.vault-bin;
|
||||
address = "0.0.0.0:${toString cfg.port}";
|
||||
storageBackend = "raft";
|
||||
storagePath = "/var/lib/vault-raft";
|
||||
storageConfig = ''
|
||||
node_id = "${cfg.node_id}"
|
||||
'' + cluster_config;
|
||||
extraConfig = ''
|
||||
ui = true
|
||||
disable_mlock = true
|
||||
api_addr = "http://${hostIP}:${toString cfg.port}"
|
||||
cluster_addr = "http://${hostIP}:${toString cfg.clusterPort}"
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services.vault-unseal = mkIf cfg.autoUnseal {
|
||||
description = "Vault unseal service";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "vault.service" ];
|
||||
environment = {
|
||||
VAULT_ADDR = "http://localhost:${toString cfg.port}";
|
||||
VAULT_KEY_FILE = cfg.autoUnsealKeysFile;
|
||||
};
|
||||
serviceConfig = {
|
||||
User = "vault";
|
||||
Group = "vault";
|
||||
Type = "simple";
|
||||
Restart = "on-failure";
|
||||
ExecStart = "${
|
||||
inputs.vault-unseal.packages.${pkgs.system}.default
|
||||
}/bin/vault-unseal";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue