From 8c7578075fe4f227dc8cc621eb339137176f74a9 Mon Sep 17 00:00:00 2001 From: Dmitry Voronin Date: Tue, 25 Jun 2024 04:04:39 +0300 Subject: [PATCH] Rewrite modules to options. --- Readme.md | 2 +- android/Termux.nix | 6 +- {part => android}/style/Gruvbox.nix | 0 container/Change.nix | 58 +++- container/Cloud.nix | 99 ++++-- container/Ddns.nix | 74 ++-- container/Dns.nix | 213 ++++++------ container/Download.nix | 71 ++-- container/Git.nix | 146 ++++---- container/Hdd.nix | 90 +++-- container/Home.nix | 50 ++- container/Iot.nix | 146 ++++---- container/Jobber.nix | 88 +++-- container/Mail.nix | 336 ++++++++++--------- container/Office.nix | 74 ++-- container/Paper.nix | 104 +++--- container/Pass.nix | 72 ++-- container/Paste.nix | 182 +++++----- container/Postgres.nix | 112 ++++--- container/Print.nix | 68 ++-- container/Proxy.nix | 164 +++++---- container/Rabbitmq.nix | 58 ++-- container/Read.nix | 70 ++-- container/Redis.nix | 34 +- container/Search.nix | 48 ++- container/Status.nix | 74 ++-- container/Stock.nix | 70 ++-- container/Vpn.nix | 140 ++++---- container/Watch.nix | 119 ++++--- container/Yt.nix | 68 ++-- container/default.nix | 285 +++------------- container/homer/Config.nix | 45 ++- container/homer/default.nix | 2 +- container/pastebin/Config.nix | 4 +- container/pastebin/default.nix | 2 +- container/proxy/host/Camera.nix | 20 +- container/proxy/host/Change.nix | 14 +- container/proxy/host/Cloud.nix | 14 +- container/proxy/host/Download.nix | 14 +- container/proxy/host/Git.nix | 22 +- container/proxy/host/Hdd.nix | 14 +- container/proxy/host/Home.nix | 14 +- container/proxy/host/Iot.nix | 14 +- container/proxy/host/Mail.nix | 14 +- container/proxy/host/Office.nix | 14 +- container/proxy/host/Paper.nix | 14 +- container/proxy/host/Pass.nix | 14 +- container/proxy/host/Paste.nix | 8 +- container/proxy/host/Print.nix | 14 +- container/proxy/host/Printer.nix | 22 +- container/proxy/host/Read.nix | 14 +- container/proxy/host/Router.nix | 22 +- container/proxy/host/Search.nix | 14 +- container/proxy/host/Status.nix | 16 +- container/proxy/host/Stock.nix | 14 +- container/proxy/host/Watch.nix | 14 +- container/proxy/host/Yt.nix | 14 +- flake.nix | 255 +++++--------- host/basic/default.nix | 5 - host/dasha/default.nix | 14 +- host/desktop/default.nix | 29 +- host/fsight/default.nix | 2 + host/home/Container.nix | 107 ++---- host/home/default.nix | 20 +- host/laptop/default.nix | 17 + host/live/default.nix | 4 +- host/work/default.nix | 10 + lib/Container.nix | 63 ++++ {part => lib}/Util.nix | 2 + module/AmdCompute.nix | 25 +- module/AmdCpu.nix | 30 +- module/AmdGpu.nix | 36 +- module/CapsToggle.nix | 6 - module/Docker.nix | 42 ++- module/DockerRootless.nix | 7 - module/Ftpd.nix | 44 ++- module/Gnome.nix | 48 --- module/IntelCpu.nix | 27 +- module/Ollama.nix | 75 +++-- module/Podman.nix | 24 ++ module/PowerlimitThinkpad.nix | 85 ++++- module/Powersave.nix | 73 ++++ module/PowersaveAmd.nix | 21 -- module/PowersaveIntel.nix | 18 - module/Print.nix | 22 +- module/RemoteBuild.nix | 102 ++++-- module/RemoteBuilder.nix | 37 -- {part => module}/Setting.nix | 10 + module/StrongSwan.nix | 46 +-- module/Style.nix | 91 +++++ module/Sway.nix | 43 --- module/Tablet.nix | 18 +- module/VirtManager.nix | 26 +- module/common/Apks.nix | 13 +- module/common/AutoUpdateSigned.nix | 76 +++-- module/common/Bash.nix | 2 +- module/common/Distrobox.nix | 20 +- module/common/Filesystem.nix | 1 + module/common/Kernel.nix | 131 ++++---- module/common/Keyd.nix | 176 +++++----- module/common/Network.nix | 6 +- module/common/Package.nix | 14 +- module/common/Podman.nix | 14 - module/common/Stylix.nix | 9 +- module/common/Tmux.nix | 2 +- module/common/Users.nix | 2 +- module/common/Wallpaper.nix | 18 + module/common/bash/default.nix | 2 +- module/common/bash/module/Ps1.nix | 10 +- module/common/nvim/module/plugin/lsp/Nix.nix | 12 +- module/common/tmux/default.nix | 2 +- module/common/tmux/module/Copy.nix | 6 +- module/common/tmux/module/Split.nix | 6 +- module/common/tmux/module/Status.nix | 6 +- module/desktop/App.nix | 212 ++++++++---- module/desktop/Bluetooth.nix | 18 +- module/desktop/Brightness.nix | 12 +- module/desktop/Dconf.nix | 19 +- module/desktop/DisplayManager.nix | 18 +- module/desktop/Gnome.nix | 56 ++++ module/desktop/Polkit.nix | 36 +- module/desktop/Portal.nix | 38 ++- module/desktop/Realtime.nix | 16 +- module/desktop/Sound.nix | 26 +- module/desktop/Sway.nix | 53 +++ module/desktop/Systemd.nix | 24 +- module/desktop/Waybar.nix | 17 +- module/desktop/Wayland.nix | 40 ++- module/desktop/firefox/Config.nix | 42 --- module/desktop/firefox/default.nix | 103 +++--- module/desktop/sway/default.nix | 2 +- module/desktop/sway/module/Launcher.nix | 12 +- module/desktop/sway/module/Session.nix | 4 +- module/desktop/sway/module/Style.nix | 14 +- module/desktop/sway/module/Tiling.nix | 4 +- module/desktop/sway/module/TitleBar.nix | 4 +- module/desktop/waybar/config/default.nix | 12 +- module/desktop/waybar/style/Common.nix | 8 +- module/desktop/waybar/style/Plugin.nix | 14 +- module/desktop/waybar/style/Window.nix | 10 +- module/powerlimit/Script.nix | 34 -- module/powerlimit/default.nix | 31 -- module/powersave/Script.nix | 27 -- module/powersave/default.nix | 19 -- part/Style.nix | 81 ----- part/Wallpaper.nix | 15 - {part/secret/public => secret}/Gpg.key | 0 {part/secret/public => secret}/Signers.key | 0 {part/secret/public => secret}/Ssh.key | 0 part/Secret.nix => secret/default.nix | 8 +- user/Dasha.nix | 44 +-- user/Root.nix | 6 +- user/Voronind.nix | 43 +-- user/common/default.nix | 111 +++--- user/common/foot/default.nix | 14 +- user/common/fuzzel/default.nix | 18 +- user/common/mako/default.nix | 12 +- user/common/yazi/module/Theme.nix | 16 +- 158 files changed, 3802 insertions(+), 3011 deletions(-) rename {part => android}/style/Gruvbox.nix (100%) delete mode 100644 host/basic/default.nix create mode 100644 lib/Container.nix rename {part => lib}/Util.nix (99%) delete mode 100644 module/CapsToggle.nix delete mode 100644 module/DockerRootless.nix delete mode 100644 module/Gnome.nix create mode 100644 module/Podman.nix create mode 100644 module/Powersave.nix delete mode 100644 module/PowersaveAmd.nix delete mode 100644 module/PowersaveIntel.nix delete mode 100644 module/RemoteBuilder.nix rename {part => module}/Setting.nix (84%) create mode 100644 module/Style.nix delete mode 100644 module/Sway.nix delete mode 100644 module/common/Podman.nix create mode 100644 module/common/Wallpaper.nix create mode 100644 module/desktop/Gnome.nix create mode 100644 module/desktop/Sway.nix delete mode 100644 module/desktop/firefox/Config.nix delete mode 100644 module/powerlimit/Script.nix delete mode 100644 module/powerlimit/default.nix delete mode 100644 module/powersave/Script.nix delete mode 100644 module/powersave/default.nix delete mode 100644 part/Style.nix delete mode 100644 part/Wallpaper.nix rename {part/secret/public => secret}/Gpg.key (100%) rename {part/secret/public => secret}/Signers.key (100%) rename {part/secret/public => secret}/Ssh.key (100%) rename part/Secret.nix => secret/default.nix (87%) diff --git a/Readme.md b/Readme.md index 07e538e..efee965 100644 --- a/Readme.md +++ b/Readme.md @@ -20,7 +20,7 @@ Wallpaper link -[My current wallpaper](https://git.voronind.com/voronind/nixos/src/branch/main/part/Wallpaper.nix#L2) +[My current wallpaper](https://git.voronind.com/voronind/nixos/src/branch/main/module/common/Wallpaper.nix#L2) Color theming based on wallpaper thanks to [Stylix](https://github.com/danth/stylix). diff --git a/android/Termux.nix b/android/Termux.nix index 537cd44..182ee61 100644 --- a/android/Termux.nix +++ b/android/Termux.nix @@ -1,11 +1,11 @@ -{ pkgs, style, util, ... }: { +{ pkgs, config, util, ... }: { font = pkgs.runCommandNoCC "font" {} '' cp ${pkgs.nerdfonts.override { fonts = [ "Terminus" ]; }}/share/fonts/truetype/NerdFonts/TerminessNerdFontMono-Regular.ttf $out ''; colors = util.trimTabs '' - background=#${style.color.bg.dark} - foreground=#${style.color.fg.light} + background=#${config.module.style.color.bg.dark} + foreground=#${config.module.style.color.fg.light} ''; initScript = util.trimTabs '' diff --git a/part/style/Gruvbox.nix b/android/style/Gruvbox.nix similarity index 100% rename from part/style/Gruvbox.nix rename to android/style/Gruvbox.nix diff --git a/container/Change.nix b/container/Change.nix index c3b4bd8..06ec9a2 100644 --- a/container/Change.nix +++ b/container/Change.nix @@ -1,24 +1,48 @@ -{ container, ... } @args: let - cfg = container.config.change; +{ container, lib, config, ... } @args: with lib; let + cfg = config.container.module.change; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.change = container.mkContainer cfg { - bindMounts = { - "/var/lib/changedetection-io" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.change = { + enable = mkEnableOption "Change detection service"; + address = mkOption { + default = "10.1.0.41"; + type = types.str; + }; + port = mkOption { + default = 5000; + type = types.int; + }; + domain = mkOption { + default = "change.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/change"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.changedetection-io = { - enable = true; - baseURL = cfg.domain; - behindProxy = true; - listenAddress = cfg.address; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.change = container.mkContainer cfg { + bindMounts = { + "/var/lib/changedetection-io" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.changedetection-io = { + enable = true; + baseURL = cfg.domain; + behindProxy = true; + listenAddress = cfg.address; + }; }; }; }; diff --git a/container/Cloud.nix b/container/Cloud.nix index 36f00d2..e0cf6c8 100644 --- a/container/Cloud.nix +++ b/container/Cloud.nix @@ -1,45 +1,72 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.cloud; -in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; +{ container, pkgs, lib, config, ... } @args: with lib; let + cfg = config.container.module.cloud; - containers.cloud = container.mkContainer cfg { - bindMounts = { - "/var/lib/nextcloud" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + postgres = config.container.module.postgres; + proxy = config.container.module.proxy; +in { + options = { + container.module.cloud = { + enable = mkEnableOption "File cloud service"; + address = mkOption { + default = "10.1.0.13"; + type = types.str; + }; + port = mkOption { + default = 80; + type = types.int; + }; + domain = mkOption { + default = "cloud.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/cloud"; + type = types.str; }; }; + }; - config = { config, ... }: container.mkContainerConfig cfg { - environment.systemPackages = [ pkgs.postgresql ]; - services.nextcloud = { - enable = true; - # package = pkgs.nextcloud29; - hostName = cfg.domain; - # phpOptions = { - # memory_limit = lib.mkForce "20G"; - # }; - config = { - adminuser = "root"; - adminpassFile = "${pkgs.writeText "NextcloudPassword" "root"}"; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - dbhost = container.config.postgres.address; - dbname = "nextcloud"; - dbpassFile = "${pkgs.writeText "NextcloudDbPassword" "nextcloud"}"; - dbtype = "pgsql"; - dbuser = "nextcloud"; + containers.cloud = container.mkContainer cfg { + bindMounts = { + "/var/lib/nextcloud" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; - extraApps = { - inherit (config.services.nextcloud.package.packages.apps) contacts calendar onlyoffice; - }; - extraAppsEnable = true; - settings = { - trusted_domains = [ cfg.address cfg.domain ]; - trusted_proxies = [ container.config.proxy.address ]; - allow_local_remote_servers = true; + }; + + config = { config, ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ pkgs.postgresql ]; + services.nextcloud = { + enable = true; + # package = pkgs.nextcloud29; + hostName = cfg.domain; + # phpOptions = { + # memory_limit = lib.mkForce "20G"; + # }; + config = { + adminuser = "root"; + adminpassFile = "${pkgs.writeText "NextcloudPassword" "root"}"; + + dbhost = postgres.address; + dbname = "nextcloud"; + dbpassFile = "${pkgs.writeText "NextcloudDbPassword" "nextcloud"}"; + dbtype = "pgsql"; + dbuser = "nextcloud"; + }; + extraApps = { + inherit (config.services.nextcloud.package.packages.apps) contacts calendar onlyoffice; + }; + extraAppsEnable = true; + settings = { + trusted_domains = [ cfg.address cfg.domain ]; + trusted_proxies = [ proxy.address ]; + allow_local_remote_servers = true; + }; }; }; }; diff --git a/container/Ddns.nix b/container/Ddns.nix index ac5ad2e..48cbe87 100644 --- a/container/Ddns.nix +++ b/container/Ddns.nix @@ -1,35 +1,53 @@ -{ container, domain, ... } @args: let - cfg = container.config.ddns; +{ container, lib, config, ... } @args: with lib; let + cfg = config.container.module.ddns; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.ddns = container.mkContainer cfg { - bindMounts = { - "/data" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = true; + options = { + container.module.ddns = { + enable = mkEnableOption "Dynamic dns client."; + address = mkOption { + default = "10.1.0.31"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/ddns"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.cloudflare-dyndns = { - enable = true; - apiTokenFile = "/data/token"; - deleteMissing = true; - ipv4 = true; - ipv6 = false; - proxied = false; - domains = [ domain ] ++ map (sub: "${sub}.${domain}") [ - "cloud" - "git" - "mail" - "office" - "paste" - "play" - "vpn" - ]; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.ddns = container.mkContainer cfg { + bindMounts = { + "/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = true; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.cloudflare-dyndns = { + enable = true; + apiTokenFile = "/data/token"; + deleteMissing = true; + ipv4 = true; + ipv6 = false; + proxied = false; + domains = let + domain = config.container.domain; + in [ domain ] ++ map (sub: "${sub}.${domain}") [ + "cloud" + "git" + "mail" + "office" + "paste" + "play" + "vpn" + ]; + }; }; }; }; diff --git a/container/Dns.nix b/container/Dns.nix index 2923f3e..a38ff62 100644 --- a/container/Dns.nix +++ b/container/Dns.nix @@ -1,112 +1,129 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.dns; +{ container, pkgs, lib, config, ... } @args: with lib; let + cfg = config.container.module.dns; in { - containers.dns = container.mkContainer cfg { - forwardPorts = [ - { - containerPort = 53; - hostPort = 53; - protocol = "udp"; - } { - containerPort = 53; - hostPort = 53; - protocol = "tcp"; - } - ]; + options = { + container.module.dns = { + enable = mkEnableOption "Dns server."; + address = mkOption { + default = "10.1.0.6"; + type = types.str; + }; + port = mkOption { + default = 53; + type = types.int; + }; + }; + }; - config = { lib, ... }: container.mkContainerConfig cfg { - environment.systemPackages = [ - pkgs.cloudflared + config = mkIf cfg.enable { + containers.dns = container.mkContainer cfg { + forwardPorts = [ + { + containerPort = cfg.port; + hostPort = cfg.port; + protocol = "udp"; + } { + containerPort = cfg.port; + hostPort = cfg.port; + protocol = "tcp"; + } ]; - systemd.services.cloudflared = { - description = "Cloudflare DoH server."; - enable = true; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "simple"; - ExecStart = "${lib.getExe pkgs.cloudflared} proxy-dns --port 5054"; - }; - }; + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ + pkgs.cloudflared + ]; - services.blocky = { - enable = true; - settings = { - upstream = { - default = [ - "0.0.0.0:5054" - "0.0.0.0:5054" - ]; + systemd.services.cloudflared = { + description = "Cloudflare DoH server."; + enable = true; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${getExe pkgs.cloudflared} proxy-dns --port 5054"; }; - blocking = { - blackLists = { - suspicious = [ - "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" - "https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt" - "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts" - "https://v.firebog.net/hosts/static/w3kbl.txt" - ]; - ads = [ - "https://easylist-downloads.adblockplus.org/bitblock.txt" - "https://adaway.org/hosts.txt" - "https://v.firebog.net/hosts/AdguardDNS.txt" - "https://v.firebog.net/hosts/Admiral.txt" - "https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt" - "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" - "https://v.firebog.net/hosts/Easylist.txt" - "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext" - "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts" - "https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts" - "https://github.com/easylist/ruadlist/blob/master/advblock/adservers.txt" - ]; - tracking = [ - "https://v.firebog.net/hosts/Easyprivacy.txt" - "https://v.firebog.net/hosts/Prigent-Ads.txt" - "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts" - "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" - "https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt" - ]; - malicious = [ - "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt" - "https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt" - "https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt" - "https://v.firebog.net/hosts/Prigent-Crypto.txt" - "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts" - "https://bitbucket.org/ethanr/dns-blacklists/raw/8575c9f96e5b4a1308f2f12394abd86d0927a4a0/bad_lists/Mandiant_APT1_Report_Appendix_D.txt" - "https://phishing.army/download/phishing_army_blocklist_extended.txt" - "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-malware.txt" - "https://v.firebog.net/hosts/RPiList-Malware.txt" - "https://v.firebog.net/hosts/RPiList-Phishing.txt" - "https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt" - "https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/generated/hosts" - "https://urlhaus.abuse.ch/downloads/hostfile/" - ]; - other = [ - "https://zerodot1.gitlab.io/CoinBlockerLists/hosts_browser" - ]; - }; - # whiteLists = { - # other = [ - # "/.*.vk.com/" - # ]; - # }; - clientGroupsBlock = { + }; + + services.blocky = { + enable = true; + settings = { + upstream = { default = [ - "suspicious" - "ads" - "tracking" - "malicious" - "other" + "0.0.0.0:5054" + "0.0.0.0:5054" ]; }; - }; - customDNS = { - mapping = { - "voronind.com" = "192.168.1.2"; + blocking = { + blackLists = { + suspicious = [ + "https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" + "https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts" + "https://v.firebog.net/hosts/static/w3kbl.txt" + ]; + ads = [ + "https://easylist-downloads.adblockplus.org/bitblock.txt" + "https://adaway.org/hosts.txt" + "https://v.firebog.net/hosts/AdguardDNS.txt" + "https://v.firebog.net/hosts/Admiral.txt" + "https://raw.githubusercontent.com/anudeepND/blacklist/master/adservers.txt" + "https://s3.amazonaws.com/lists.disconnect.me/simple_ad.txt" + "https://v.firebog.net/hosts/Easylist.txt" + "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=hosts&showintro=0&mimetype=plaintext" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/UncheckyAds/hosts" + "https://raw.githubusercontent.com/bigdargon/hostsVN/master/hosts" + "https://github.com/easylist/ruadlist/blob/master/advblock/adservers.txt" + ]; + tracking = [ + "https://v.firebog.net/hosts/Easyprivacy.txt" + "https://v.firebog.net/hosts/Prigent-Ads.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.2o7Net/hosts" + "https://raw.githubusercontent.com/crazy-max/WindowsSpyBlocker/master/data/hosts/spy.txt" + "https://hostfiles.frogeye.fr/firstparty-trackers-hosts.txt" + ]; + malicious = [ + "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt" + "https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt" + "https://s3.amazonaws.com/lists.disconnect.me/simple_malvertising.txt" + "https://v.firebog.net/hosts/Prigent-Crypto.txt" + "https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Risk/hosts" + "https://bitbucket.org/ethanr/dns-blacklists/raw/8575c9f96e5b4a1308f2f12394abd86d0927a4a0/bad_lists/Mandiant_APT1_Report_Appendix_D.txt" + "https://phishing.army/download/phishing_army_blocklist_extended.txt" + "https://gitlab.com/quidsup/notrack-blocklists/raw/master/notrack-malware.txt" + "https://v.firebog.net/hosts/RPiList-Malware.txt" + "https://v.firebog.net/hosts/RPiList-Phishing.txt" + "https://raw.githubusercontent.com/Spam404/lists/master/main-blacklist.txt" + "https://raw.githubusercontent.com/AssoEchap/stalkerware-indicators/master/generated/hosts" + "https://urlhaus.abuse.ch/downloads/hostfile/" + ]; + other = [ + "https://zerodot1.gitlab.io/CoinBlockerLists/hosts_browser" + ]; + }; + # whiteLists = { + # other = [ + # "/.*.vk.com/" + # ]; + # }; + clientGroupsBlock = { + default = [ + "suspicious" + "ads" + "tracking" + "malicious" + "other" + ]; + }; }; + customDNS = { + mapping = { + # All subdomains to current host. + ${config.container.domain} = config.container.host; + }; + }; + port = cfg.port; + # httpPort = "80"; }; - port = "53"; - httpPort = "80"; }; }; }; diff --git a/container/Download.nix b/container/Download.nix index ef3ed37..aa09213 100644 --- a/container/Download.nix +++ b/container/Download.nix @@ -1,29 +1,56 @@ -{ container, lib, ... } @args: let - cfg = container.config.download; - memLimit = "4G"; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.download; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.download = container.mkContainer cfg { - enableTun = true; - - bindMounts = { - "/var/lib/deluge/.config/deluge" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.download = { + enable = mkEnableOption "Downloader."; + address = mkOption { + default = "10.1.0.12"; + type = types.str; }; - } // container.attachMedia "download" cfg.download false; - - config = { ... }: container.mkContainerConfig cfg { - services.deluge = { - enable = true; - dataDir = "/var/lib/deluge"; - web.enable = true; + port = mkOption { + default = 8112; + type = types.int; }; + domain = mkOption { + default = "download.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/download"; + type = types.str; + }; + memLimit = mkOption { + default = "4G"; + type = types.str; + }; + }; + }; - systemd.services.deluged.serviceConfig.MemoryLimit = memLimit; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.download = container.mkContainer cfg { + enableTun = true; + + bindMounts = { + "/var/lib/deluge/.config/deluge" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + } // container.attachMedia "download" false; + + config = { ... }: container.mkContainerConfig cfg { + services.deluge = { + enable = true; + dataDir = "/var/lib/deluge"; + web.enable = true; + }; + + systemd.services.deluged.serviceConfig.MemoryLimit = cfg.memLimit; + }; }; }; } diff --git a/container/Git.nix b/container/Git.nix index 17b8c8f..3c9658a 100644 --- a/container/Git.nix +++ b/container/Git.nix @@ -1,73 +1,97 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.git; +{ container, pkgs, config, lib, ... }: with lib; let + cfg = config.container.module.git; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.git = container.mkContainer cfg { - bindMounts = { - "/var/lib/gitea" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.git = { + enable = mkEnableOption "Git server."; + address = mkOption { + default = "10.1.0.8"; + type = types.str; + }; + port = mkOption { + default = 3000; + type = types.int; + }; + domain = mkOption { + default = "git.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/git"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - environment.systemPackages = with pkgs; [ gitea ]; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - services.gitea = { - enable = true; - stateDir = "/var/lib/gitea"; - - database = let - postgre = container.config.postgres; - in { - type = "postgres"; - host = postgre.address; - port = postgre.port; - user = "gitea"; - createDatabase = false; + containers.git = container.mkContainer cfg { + bindMounts = { + "/var/lib/gitea" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; + }; - settings = let - gcArgs = "--aggressive --no-cruft --prune=now"; - gcTimeout = 600; - in { - "service".DISABLE_REGISTRATION = true; - "log".LEVEL = "Error"; - "server" = { - DISABLE_SSH = true; - DOMAIN = cfg.domain; - HTTP_ADDR = cfg.address; - ROOT_URL = "https://${cfg.domain}"; + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ gitea ]; + + services.gitea = { + enable = true; + stateDir = "/var/lib/gitea"; + + database = let + postgre = config.container.module.postgres; + in { + type = "postgres"; + host = postgre.address; + port = postgre.port; + user = "gitea"; + createDatabase = false; }; - "ui" = { - AMBIGUOUS_UNICODE_DETECTION = false; + + settings = let + gcArgs = "--aggressive --no-cruft --prune=now"; + gcTimeout = 600; + in { + "service".DISABLE_REGISTRATION = true; + "log".LEVEL = "Error"; + "server" = { + DISABLE_SSH = true; + DOMAIN = cfg.domain; + HTTP_ADDR = cfg.address; + ROOT_URL = "https://${cfg.domain}"; + }; + "ui" = { + AMBIGUOUS_UNICODE_DETECTION = false; + }; + "repository" = { + DEFAULT_PRIVATE = "private"; + DEFAULT_PUSH_CREATE_PRIVATE = true; + }; + "repository.pull-request".DEFAULT_MERGE_STYLE = "rebase"; + "repository.issue".MAX_PINNED = 99999; + "cron" = { + ENABLED = true; + RUN_AT_START = true; + }; + "repo-archive".ENABLED = false; + "cron.update_mirrors".SCHEDULE = "@midnight"; + "cron.cleanup_actions".ENABLED = true; + "cron.git_gc_repos" = { + ENABLED = true; + SCHEDULE = "@midnight"; + TIMEOUT = gcTimeout; + ARGS = gcArgs; + }; + "git" = { + GC_ARGS = gcArgs; + }; + "git.timeout".GC = gcTimeout; }; - "repository" = { - DEFAULT_PRIVATE = "private"; - DEFAULT_PUSH_CREATE_PRIVATE = true; - }; - "repository.pull-request".DEFAULT_MERGE_STYLE = "rebase"; - "repository.issue".MAX_PINNED = 99999; - "cron" = { - ENABLED = true; - RUN_AT_START = true; - }; - "repo-archive".ENABLED = false; - "cron.update_mirrors".SCHEDULE = "@midnight"; - "cron.cleanup_actions".ENABLED = true; - "cron.git_gc_repos" = { - ENABLED = true; - SCHEDULE = "@midnight"; - TIMEOUT = gcTimeout; - ARGS = gcArgs; - }; - "git" = { - GC_ARGS = gcArgs; - }; - "git.timeout".GC = gcTimeout; }; }; }; diff --git a/container/Hdd.nix b/container/Hdd.nix index 75f1476..accb5eb 100644 --- a/container/Hdd.nix +++ b/container/Hdd.nix @@ -1,43 +1,67 @@ # ISSUE: Broken, can't read/write sda device. -{ container, pkgs, ... } @args: let - cfg = container.config.hdd; +{ container, pkgs, config, lib, ... }: with lib; let + cfg = config.container.module.hdd; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; + options = { + container.module.hdd = { + enable = mkEnableOption "Hdd health monitor."; + address = mkOption { + default = "10.1.0.10"; + type = types.str; + }; + port = mkOption { + default = 8080; + type = types.int; + }; + domain = mkOption { + default = "hdd.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/hdd"; + type = types.str; + }; + }; + }; - containers.hdd = container.mkContainer cfg { - # bindMounts = let - # attachDrive = hostPath: { - # inherit hostPath; - # isReadOnly = false; - # }; - # in { - # "/opt/scrutiny" = { - # hostPath = "${cfg.storage}/data"; - # isReadOnly = false; - # }; - # "/dev/sda" = attachDrive "/dev/sda"; - # }; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - # allowedDevices = [ - # { - # modifier = "rwm"; - # node = "/dev/sda"; - # } - # ]; + containers.hdd = container.mkContainer cfg { + # bindMounts = let + # attachDrive = hostPath: { + # inherit hostPath; + # isReadOnly = false; + # }; + # in { + # "/opt/scrutiny" = { + # hostPath = "${cfg.storage}/data"; + # isReadOnly = false; + # }; + # "/dev/sda" = attachDrive "/dev/sda"; + # }; - # additionalCapabilities = [ "CAP_SYS_ADMIN" ]; + # allowedDevices = [ + # { + # modifier = "rwm"; + # node = "/dev/sda"; + # } + # ]; - config = { ... }: container.mkContainerConfig cfg { - environment.systemPackages = with pkgs; [ smartmontools ]; + # additionalCapabilities = [ "CAP_SYS_ADMIN" ]; - services.scrutiny = { - enable = true; - settings.web = { - listen = { - host = cfg.address; - port = cfg.port; + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ smartmontools ]; + + services.scrutiny = { + enable = true; + settings.web = { + listen = { + host = cfg.address; + port = cfg.port; + }; }; }; }; diff --git a/container/Home.nix b/container/Home.nix index 09bef96..4a2ea6f 100644 --- a/container/Home.nix +++ b/container/Home.nix @@ -1,22 +1,42 @@ -{ container, pkgs, util, ... } @args: let - cfg = container.config.home; +{ container, pkgs, util, lib, config, ... } @args: with lib; let + cfg = config.container.module.home; package = (pkgs.callPackage ./homer args); in { - containers.home = container.mkContainer cfg { - config = { ... }: container.mkContainerConfig cfg { - environment.systemPackages = [ package ]; - systemd.packages = [ package ]; + options = { + container.module.home = { + enable = mkEnableOption "Dashboard."; + address = mkOption { + default = "10.1.0.18"; + type = types.str; + }; + port = mkOption { + default = 80; + type = types.int; + }; + domain = mkOption { + default = "home.${config.container.domain}"; + type = types.str; + }; + }; + }; - services.nginx = { - enable = true; - virtualHosts.${cfg.domain} = container.mkServer { - default = true; - root = "${package}"; + config = mkIf cfg.enable { + containers.home = container.mkContainer cfg { + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ package ]; + systemd.packages = [ package ]; - locations = { - "/".extraConfig = '' - try_files $uri $uri/index.html; - ''; + services.nginx = { + enable = true; + virtualHosts.${cfg.domain} = container.mkServer { + default = true; + root = "${package}"; + + locations = { + "/".extraConfig = '' + try_files $uri $uri/index.html; + ''; + }; }; }; }; diff --git a/container/Iot.nix b/container/Iot.nix index c0d7417..641fe1a 100644 --- a/container/Iot.nix +++ b/container/Iot.nix @@ -1,69 +1,93 @@ -{ container, ... } @args: let - cfg = container.config.iot; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.iot; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; + options = { + container.module.iot = { + enable = mkEnableOption "IoT service."; + address = mkOption { + default = "10.1.0.27"; + type = types.str; + }; + port = mkOption { + default = 8123; + type = types.int; + }; + domain = mkOption { + default = "iot.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/iot"; + type = types.str; + }; + }; + }; - containers.iot = container.mkContainer cfg { - bindMounts = { - "/var/lib/hass" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; - }; - "/dev/ttyACM0" = { - hostPath = "/dev/ttyACM0"; - isReadOnly = false; - }; - "/dev/serial/by-id" = { - hostPath = "/dev/serial/by-id"; - isReadOnly = false; - }; - } // container.attachMedia "photo" cfg.photo true; - - allowedDevices = [ - { - modifier = "rwm"; - node = "/dev/ttyACM0"; - } + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" ]; - config = { ... }: container.mkContainerConfig cfg { - # Allow Hass to talk to Zigbee dongle. - users.users.hass.extraGroups = [ "dialout" "tty" ]; + containers.iot = container.mkContainer cfg { + bindMounts = { + "/var/lib/hass" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + "/dev/ttyACM0" = { + hostPath = "/dev/ttyACM0"; + isReadOnly = false; + }; + "/dev/serial/by-id" = { + hostPath = "/dev/serial/by-id"; + isReadOnly = false; + }; + } // container.attachMedia "photo" true; - services.home-assistant = { - # NOTE: Missing: hacs. Inside hacs: `card-mod`, `Clock Weather Card`, `WallPanel` and `Yandex.Station`. - enable = true; - extraComponents = [ - "caldav" - "met" - "sun" - "systemmonitor" - "zha" - ]; - extraPackages = python3Packages: with python3Packages; [ - aiodhcpwatcher - aiodiscover - aiogithubapi - async-upnp-client - ha-av - ha-ffmpeg - hassil - home-assistant-intents - mutagen - numpy - pynacl - pyturbojpeg - python-telegram-bot - zeroconf - ]; - configDir = "/var/lib/hass"; - # lovelaceConfig = { - # title = "Home IoT control center."; - # }; - # NOTE: Using imperative config because of secrets. - config = null; + allowedDevices = [ + { + modifier = "rwm"; + node = "/dev/ttyACM0"; + } + ]; + + config = { ... }: container.mkContainerConfig cfg { + # Allow Hass to talk to Zigbee dongle. + users.users.hass.extraGroups = [ "dialout" "tty" ]; + + services.home-assistant = { + # NOTE: Missing: hacs. Inside hacs: `card-mod`, `Clock Weather Card`, `WallPanel` and `Yandex.Station`. + enable = true; + extraComponents = [ + "caldav" + "met" + "sun" + "systemmonitor" + "zha" + ]; + extraPackages = python3Packages: with python3Packages; [ + aiodhcpwatcher + aiodiscover + aiogithubapi + async-upnp-client + ha-av + ha-ffmpeg + hassil + home-assistant-intents + mutagen + numpy + pynacl + pyturbojpeg + python-telegram-bot + zeroconf + ]; + configDir = "/var/lib/hass"; + # lovelaceConfig = { + # title = "Home IoT control center."; + # }; + # NOTE: Using imperative config because of secrets. + config = null; + }; }; }; }; diff --git a/container/Jobber.nix b/container/Jobber.nix index a565ebe..2c4cb07 100644 --- a/container/Jobber.nix +++ b/container/Jobber.nix @@ -1,48 +1,64 @@ -{ container, pkgsJobber, poetry2nixJobber, lib, ... } @args: let - cfg = container.config.jobber; +{ container, pkgsJobber, poetry2nixJobber, lib, config, ... }: with lib; let + cfg = config.container.module.jobber; script = import ./jobber { poetry2nix = poetry2nixJobber; pkgs = pkgsJobber; }; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.jobber = container.mkContainer cfg { - bindMounts = { - "/data" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = true; + options = { + container.module.jobber = { + enable = mkEnableOption "Button pusher Stanley."; + address = mkOption { + default = "10.1.0.32"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/jobber"; + type = types.str; }; }; + }; - enableTun = true; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - config = { lib, ... }: let - packages = [ script ] ++ (with pkgsJobber; [ - firefox - geckodriver - openvpn - python311 - ]); - in container.mkContainerConfig cfg { - networking = lib.mkForce { - nameservers = [ - "10.9.0.5" - ]; + containers.jobber = container.mkContainer cfg { + bindMounts = { + "/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = true; + }; }; - systemd.services.jobber = { - description = "My job is pushing the button."; - enable = true; - wantedBy = [ "multi-user.target" ]; - path = packages; - environment = { - PYTHONUNBUFFERED = "1"; - PYTHONDONTWRITEBYTECODE = "1"; + enableTun = true; + + config = { lib, ... }: let + packages = [ script ] ++ (with pkgsJobber; [ + firefox + geckodriver + openvpn + python311 + ]); + in container.mkContainerConfig cfg { + networking = lib.mkForce { + nameservers = [ + "10.9.0.5" + ]; }; - serviceConfig = { - Type = "simple"; - ExecStart = "${script}/bin/jobber -u"; - Restart = "on-failure"; + + systemd.services.jobber = { + description = "My job is pushing the button."; + enable = true; + wantedBy = [ "multi-user.target" ]; + path = packages; + environment = { + PYTHONUNBUFFERED = "1"; + PYTHONDONTWRITEBYTECODE = "1"; + }; + serviceConfig = { + Type = "simple"; + ExecStart = "${script}/bin/jobber -u"; + Restart = "on-failure"; + }; }; }; }; diff --git a/container/Mail.nix b/container/Mail.nix index 2b42a0e..7617bfa 100644 --- a/container/Mail.nix +++ b/container/Mail.nix @@ -1,177 +1,203 @@ # Guide: https://nixos-mailserver.readthedocs.io/en/latest/setup-guide.html -{ container, domain, pkgs, util, const, ... } @args: let cfg = container.config.mail; +{ container, pkgs, util, const, lib, config, ... }: with lib; let + cfg = config.container.module.mail; + domain = config.container.domain; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - # "data/indices" - # "data/vmail" - # "data/sieve" - # "data/dkim" - ]; - - containers.mail = container.mkContainer cfg { - forwardPorts = [ - { - containerPort = 993; - hostPort = 993; - protocol = "tcp"; - } { - containerPort = 25; - hostPort = 25; - protocol = "tcp"; - } { - containerPort = 465; - hostPort = 465; - protocol = "tcp"; - } - ]; - - bindMounts = { - "/var/lib/dovecot/indices" = { - hostPath = "${cfg.storage}/data/indices"; - isReadOnly = false; + options = { + container.module.mail = { + enable = mkEnableOption "Email server."; + address = mkOption { + default = "10.1.0.5"; + type = types.str; }; - "/var/vmail" = { - hostPath = "${cfg.storage}/data/vmail"; - isReadOnly = false; + port = mkOption { + default = 80; + type = types.int; }; - "/var/sieve" = { - hostPath = "${cfg.storage}/data/sieve"; - isReadOnly = false; + domain = mkOption { + default = "mail.${config.container.domain}"; + type = types.str; }; - "/var/dkim" = { - hostPath = "${cfg.storage}/data/dkim"; - isReadOnly = false; - }; - "/acme" = { - hostPath = "${container.config.proxy.storage}/letsencrypt"; - isReadOnly = true; + storage = mkOption { + default = "${config.container.storage}/mail"; + type = types.str; }; }; + }; - config = { config, ... }: container.mkContainerConfig cfg { - imports = [ - (builtins.fetchTarball { - url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-${const.stateVersion}/nixos-mailserver-nixos-${const.stateVersion}.tar.gz"; - sha256 = "sha256:0clvw4622mqzk1aqw1qn6shl9pai097q62mq1ibzscnjayhp278b"; - }) + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + # "data/indices" + # "data/vmail" + # "data/sieve" + # "data/dkim" + ]; + + containers.mail = container.mkContainer cfg { + forwardPorts = [ + { + containerPort = 993; + hostPort = 993; + protocol = "tcp"; + } { + containerPort = 25; + hostPort = 25; + protocol = "tcp"; + } { + containerPort = 465; + hostPort = 465; + protocol = "tcp"; + } ]; - mailserver = { - enable = true; - fqdn = cfg.domain; - domains = [ domain ]; - sendingFqdn = domain; + bindMounts = { + "/var/lib/dovecot/indices" = { + hostPath = "${cfg.storage}/data/indices"; + isReadOnly = false; + }; + "/var/vmail" = { + hostPath = "${cfg.storage}/data/vmail"; + isReadOnly = false; + }; + "/var/sieve" = { + hostPath = "${cfg.storage}/data/sieve"; + isReadOnly = false; + }; + "/var/dkim" = { + hostPath = "${cfg.storage}/data/dkim"; + isReadOnly = false; + }; + "/acme" = { + hostPath = "${config.container.module.proxy.storage}/letsencrypt"; + isReadOnly = true; + }; + }; - # Use `mkpasswd -sm bcrypt`. - loginAccounts = let - defaultQuota = "1G"; - in { - "admin@${domain}" = { - name = "admin"; - hashedPassword = "$2b$05$1O.dxXxaVshcBNybcqDRYuTlnYt3jDBwfPZWoDtP4BjOLoL0StYsi"; - quota = defaultQuota; + config = { config, ... }: container.mkContainerConfig cfg { + imports = [ + (builtins.fetchTarball { + url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-${const.stateVersion}/nixos-mailserver-nixos-${const.stateVersion}.tar.gz"; + sha256 = "sha256:0clvw4622mqzk1aqw1qn6shl9pai097q62mq1ibzscnjayhp278b"; + }) + ]; + + mailserver = { + enable = true; + domains = [ domain ]; + fqdn = cfg.domain; + sendingFqdn = domain; + + # Use `mkpasswd -sm bcrypt`. + loginAccounts = let + defaultQuota = "1G"; + in { + "admin@${domain}" = { + name = "admin"; + hashedPassword = "$2b$05$1O.dxXxaVshcBNybcqDRYuTlnYt3jDBwfPZWoDtP4BjOLoL0StYsi"; + quota = defaultQuota; + }; + "account@${domain}" = { + name = "account"; + hashedPassword = "$2b$05$sCyZHdk98KqQ1qsTIvbrUeRJlNBOwBqDgpdc1QxiSnONlEkZ8xGNO"; + quota = defaultQuota; + }; + "hi@${domain}" = { + name = "hi"; + hashedPassword = "$2b$05$6fT5hIhzIasNfp9IQr/ds.5RuxH95VKU3QJWlX3hmrAzDF3mExanq"; + quota = defaultQuota; + aliases = [ "voronind@${domain}" ]; + }; + "job@${domain}" = { + name = "job"; + hashedPassword = "$2b$05$.sUmv2.9EWPfLwJn/oZw2e1UbR7HrpNQ2THc5jjX3ysy7CY8ZWHUC"; + quota = defaultQuota; + }; + "trash@${domain}" = { + name = "trash"; + hashedPassword = "$2b$05$kn5ygZjN9NR3LXjnKKRw/.DXaZQNW.1XEottlCFIoKiDpIj.JGLJm"; + catchAll = [ domain ]; + quota = defaultQuota; + }; + "noreply@${domain}" = { + name = "noreply"; + hashedPassword = "$2b$05$TaKwoYmcmkAhsRRv6xG5wOkChcz50cB9BP6QPUDKNAcxMbrY6AeMK"; + sendOnly = true; + quota = defaultQuota; + }; }; - "account@${domain}" = { - name = "account"; - hashedPassword = "$2b$05$sCyZHdk98KqQ1qsTIvbrUeRJlNBOwBqDgpdc1QxiSnONlEkZ8xGNO"; - quota = defaultQuota; + + enableImap = true; + enableImapSsl = true; + enableSubmission = true; + enableSubmissionSsl = true; + + virusScanning = false; + + certificateScheme = "manual"; + keyFile = "/acme/live/${domain}/privkey.pem"; + certificateFile = "/acme/live/${domain}/cert.pem"; + + indexDir = "/var/lib/dovecot/indices"; + mailDirectory = "/var/vmail"; + sieveDirectory = "/var/sieve"; + dkimKeyDirectory = "/var/dkim"; + + mailboxes = { + Drafts = { + auto = "subscribe"; + specialUse = "Drafts"; + }; + Junk = { + auto = "subscribe"; + specialUse = "Junk"; + }; + Sent = { + auto = "subscribe"; + specialUse = "Sent"; + }; + Trash = { + auto = "no"; + specialUse = "Trash"; + }; }; - "hi@${domain}" = { - name = "hi"; - hashedPassword = "$2b$05$6fT5hIhzIasNfp9IQr/ds.5RuxH95VKU3QJWlX3hmrAzDF3mExanq"; - quota = defaultQuota; - aliases = [ "voronind@${domain}" ]; - }; - "job@${domain}" = { - name = "job"; - hashedPassword = "$2b$05$.sUmv2.9EWPfLwJn/oZw2e1UbR7HrpNQ2THc5jjX3ysy7CY8ZWHUC"; - quota = defaultQuota; - }; - "trash@${domain}" = { - name = "trash"; - hashedPassword = "$2b$05$kn5ygZjN9NR3LXjnKKRw/.DXaZQNW.1XEottlCFIoKiDpIj.JGLJm"; - catchAll = [ domain ]; - quota = defaultQuota; - }; - "noreply@${domain}" = { - name = "noreply"; - hashedPassword = "$2b$05$TaKwoYmcmkAhsRRv6xG5wOkChcz50cB9BP6QPUDKNAcxMbrY6AeMK"; - sendOnly = true; - quota = defaultQuota; + + dmarcReporting = { + inherit domain; + enable = true; + organizationName = "voronind"; + # email = "noreply@${domain}"; }; + + # monitoring = { + # enable = true; + # alertAddress = "admin@${domain}"; + # }; }; - enableImap = true; - enableImapSsl = true; - enableSubmission = true; - enableSubmissionSsl = true; - - virusScanning = false; - - certificateScheme = "manual"; - keyFile = "/acme/live/${domain}/privkey.pem"; - certificateFile = "/acme/live/${domain}/cert.pem"; - - indexDir = "/var/lib/dovecot/indices"; - mailDirectory = "/var/vmail"; - sieveDirectory = "/var/sieve"; - dkimKeyDirectory = "/var/dkim"; - - mailboxes = { - Drafts = { - auto = "subscribe"; - specialUse = "Drafts"; - }; - Junk = { - auto = "subscribe"; - specialUse = "Junk"; - }; - Sent = { - auto = "subscribe"; - specialUse = "Sent"; - }; - Trash = { - auto = "no"; - specialUse = "Trash"; - }; - }; - - dmarcReporting = { - inherit domain; + services.roundcube = { enable = true; - organizationName = "voronind"; - # email = "noreply@${domain}"; + dicts = with pkgs.aspellDicts; [ en ru ]; + hostName = cfg.domain; + extraConfig = '' + # starttls needed for authentication, so the fqdn required to match + # the certificate + # $config['smtp_server'] = "tls://${config.mailserver.fqdn}"; + # $config['smtp_server'] = "tls://localhost"; + $config['smtp_server'] = "localhost:25"; + $config['smtp_auth_type'] = null; + $config['smtp_user'] = ""; + $config['smtp_pass'] = ""; + # $config['smtp_user'] = "%u"; + # $config['smtp_pass'] = "%p"; + ''; }; - # monitoring = { - # enable = true; - # alertAddress = "admin@${domain}"; - # }; - }; - - services.roundcube = { - enable = true; - dicts = with pkgs.aspellDicts; [ en ru ]; - hostName = cfg.domain; - extraConfig = '' - # starttls needed for authentication, so the fqdn required to match - # the certificate - # $config['smtp_server'] = "tls://${config.mailserver.fqdn}"; - # $config['smtp_server'] = "tls://localhost"; - $config['smtp_server'] = "localhost:25"; - $config['smtp_auth_type'] = null; - $config['smtp_user'] = ""; - $config['smtp_pass'] = ""; - # $config['smtp_user'] = "%u"; - # $config['smtp_pass'] = "%p"; - ''; - }; - - services.nginx = { - virtualHosts.${cfg.domain} = { - forceSSL = false; - enableACME = false; + services.nginx = { + virtualHosts.${cfg.domain} = { + forceSSL = false; + enableACME = false; + }; }; }; }; diff --git a/container/Office.nix b/container/Office.nix index 58f588e..44fe575 100644 --- a/container/Office.nix +++ b/container/Office.nix @@ -2,39 +2,63 @@ # 1. You need to change PSQL tables owner from root to onlyoffice, too. They don't do that automatically for some reason. # 2. TODO: Generate JWT secret at /var/lib/onlyoffice/jwt, i.e. 9wLfMGha1YrfvWpb5hyYjZf8pvJQ3swS # See https://git.voronind.com/voronind/nixos/issues/74 -{ container, pkgs, util, lib, ... } @args: let - cfg = container.config.office; +{ container, pkgs, util, lib, config, ... }: with lib; let + cfg = config.container.module.office; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.office = container.mkContainer cfg { - bindMounts = { - "/var/lib/onlyoffice" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.office = { + enable = mkEnableOption "Office web suite."; + address = mkOption { + default = "10.1.0.21"; + type = types.str; + }; + port = mkOption { + default = 8000; + type = types.int; + }; + domain = mkOption { + default = "office.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/office"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.onlyoffice = let - dbName = "onlyoffice"; - in { - enable = true; - hostname = cfg.domain; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - postgresName = dbName; - postgresHost = container.config.postgres.address; - postgresUser = dbName; - postgresPasswordFile = "${pkgs.writeText "OfficeDbPassword" dbName}"; + containers.office = container.mkContainer cfg { + bindMounts = { + "/var/lib/onlyoffice" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; - jwtSecretFile = "/var/lib/onlyoffice/jwt"; + config = { ... }: container.mkContainerConfig cfg { + services.onlyoffice = let + dbName = "onlyoffice"; + in { + enable = true; + hostname = cfg.domain; - rabbitmqUrl = "amqp://guest:guest@${container.config.rabbitmq.address}:${toString container.config.rabbitmq.port}"; + postgresName = dbName; + postgresHost = config.container.module.postgres.address; + postgresUser = dbName; + postgresPasswordFile = "${pkgs.writeText "OfficeDbPassword" dbName}"; - examplePort = cfg.port; - enableExampleServer = true; + jwtSecretFile = "/var/lib/onlyoffice/jwt"; + + rabbitmqUrl = "amqp://guest:guest@${config.container.module.rabbitmq.address}:${toString config.container.module.rabbitmq.port}"; + + examplePort = cfg.port; + enableExampleServer = true; + }; }; }; }; diff --git a/container/Paper.nix b/container/Paper.nix index d21eb22..6ee42bf 100644 --- a/container/Paper.nix +++ b/container/Paper.nix @@ -1,52 +1,76 @@ -{ container, pkgs, util, lib, ... } @args: let - cfg = container.config.paper; +{ container, pkgs, util, lib, config, ... }: with lib; let + cfg = config.container.module.paper; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.paper = container.mkContainer cfg { - bindMounts = { - "/var/lib/paperless" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.paper = { + enable = mkEnableOption "Paper scans manager."; + address = mkOption { + default = "10.1.0.40"; + type = types.str; }; - "/var/lib/paperless/media" = { - hostPath = "${lib.elemAt cfg.paper 0}"; - isReadOnly = false; + port = mkOption { + default = 28981; + type = types.int; + }; + domain = mkOption { + default = "paper.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/paper"; + type = types.str; }; }; + }; - config = { lib, ... }: container.mkContainerConfig cfg { - environment.systemPackages = with pkgs; [ postgresql inetutils ]; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - services.paperless = { - enable = true; - dataDir = "/var/lib/paperless"; - # address = cfg.domain; - address = "0.0.0.0"; - port = cfg.port; - passwordFile = pkgs.writeText "PaperlessPassword" "root"; - settings = { - PAPERLESS_URL = "https://${cfg.domain}"; - PAPERLESS_ADMIN_USER = "root"; - PAPERLESS_DBHOST = container.config.postgres.address; - PAPERLESS_DBENGINE = "postgresql"; - PAPERLESS_DBNAME = "paperless"; - PAPERLESS_DBPASS = "paperless"; - PAPERLESS_DBPORT = container.config.postgres.port; - PAPERLESS_DBUSER = "paperless"; - PAPERLESS_OCR_LANGUAGE = "rus"; - PAPERLESS_REDIS = "redis://${container.config.redis.address}:${toString container.config.redis.port}"; + containers.paper = container.mkContainer cfg { + bindMounts = { + "/var/lib/paperless" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + "/var/lib/paperless/media" = { + hostPath = "${elemAt config.container.media.paper 0}"; + isReadOnly = false; }; }; - # HACK: This is required for TCP postgres connection. - systemd.services.paperless-scheduler.serviceConfig = { - PrivateNetwork = lib.mkForce false; - }; - systemd.services.paperless-consumer.serviceConfig = { - PrivateNetwork = lib.mkForce false; + config = { lib, ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ postgresql inetutils ]; + + services.paperless = { + enable = true; + dataDir = "/var/lib/paperless"; + # address = cfg.domain; + address = "0.0.0.0"; + port = cfg.port; + passwordFile = pkgs.writeText "PaperlessPassword" "root"; + settings = { + PAPERLESS_URL = "https://${cfg.domain}"; + PAPERLESS_ADMIN_USER = "root"; + PAPERLESS_DBHOST = config.container.module.postgres.address; + PAPERLESS_DBENGINE = "postgresql"; + PAPERLESS_DBNAME = "paperless"; + PAPERLESS_DBPASS = "paperless"; + PAPERLESS_DBPORT = config.container.module.postgres.port; + PAPERLESS_DBUSER = "paperless"; + PAPERLESS_OCR_LANGUAGE = "rus"; + PAPERLESS_REDIS = "redis://${config.container.module.redis.address}:${toString config.container.module.redis.port}"; + }; + }; + + # HACK: This is required for TCP postgres connection. + systemd.services.paperless-scheduler.serviceConfig = { + PrivateNetwork = lib.mkForce false; + }; + systemd.services.paperless-consumer.serviceConfig = { + PrivateNetwork = lib.mkForce false; + }; }; }; }; diff --git a/container/Pass.nix b/container/Pass.nix index ee9dfe6..2c631d6 100644 --- a/container/Pass.nix +++ b/container/Pass.nix @@ -1,31 +1,55 @@ -{ container, ... } @args: let - cfg = container.config.pass; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.pass; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.pass = container.mkContainer cfg { - bindMounts = { - "/var/lib/bitwarden_rs" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.pass = { + enable = mkEnableOption "Password manager"; + address = mkOption { + default = "10.1.0.9"; + type = types.str; + }; + port = mkOption { + default = 8000; + type = types.int; + }; + domain = mkOption { + default = "pass.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/pass"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.vaultwarden = { - enable = true; - dbBackend = "sqlite"; - environmentFile = "/var/lib/bitwarden_rs/Env"; - config = { - # DATABASE_URL = "postgresql://vaultwarden:vaultwarden@${container.config.postgres.address}:${toString container.config.postgres.port}/vaultwarden"; - DATA_FOLDER = "/var/lib/bitwarden_rs"; - DOMAIN = "http://${cfg.domain}"; - SIGNUPS_ALLOWED = false; - WEB_VAULT_ENABLED = true; - ROCKET_ADDRESS = cfg.address; - ROCKET_PORT = cfg.port; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.pass = container.mkContainer cfg { + bindMounts = { + "/var/lib/bitwarden_rs" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.vaultwarden = { + enable = true; + dbBackend = "sqlite"; + environmentFile = "/var/lib/bitwarden_rs/Env"; + config = { + # DATABASE_URL = "postgresql://vaultwarden:vaultwarden@${container.config.postgres.address}:${toString container.config.postgres.port}/vaultwarden"; + DATA_FOLDER = "/var/lib/bitwarden_rs"; + DOMAIN = "http://${cfg.domain}"; + SIGNUPS_ALLOWED = false; + WEB_VAULT_ENABLED = true; + ROCKET_ADDRESS = cfg.address; + ROCKET_PORT = cfg.port; + }; }; }; }; diff --git a/container/Paste.nix b/container/Paste.nix index 062a2f2..52cc3b7 100644 --- a/container/Paste.nix +++ b/container/Paste.nix @@ -1,100 +1,124 @@ -{ pkgs, util, container, ... } @args: let - cfg = container.config.paste; +{ pkgs, util, container, lib, config, ... } @args: with lib; let + cfg = config.container.module.paste; package = (pkgs.callPackage ./pastebin args); in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - "tmp" - "nginxtmp" - "config" - ]; - - containers.paste = container.mkContainer cfg { - bindMounts = { - "/srv/data" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.paste = { + enable = mkEnableOption "Pastebin."; + address = mkOption { + default = "10.1.0.14"; + type = types.str; }; - "/tmp" = { - hostPath = "${cfg.storage}/tmp"; - isReadOnly = false; + port = mkOption { + default = 80; + type = types.int; }; - "/var/lib/nginx/tmp" = { - hostPath = "${cfg.storage}/nginxtmp"; - isReadOnly = false; + domain = mkOption { + default = "paste.${config.container.domain}"; + type = types.str; }; - "/srv/config" = { - hostPath = "${cfg.storage}/config"; - isReadOnly = false; + storage = mkOption { + default = "${config.container.storage}/paste"; + type = types.str; }; }; + }; - config = { config, ... }: container.mkContainerConfig cfg { - environment.systemPackages = [ package ]; - systemd.packages = [ package ]; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + "tmp" + "nginxtmp" + "config" + ]; - users.users.paste = { - group = "nginx"; - isSystemUser = true; - }; - - services.phpfpm.pools.paste = { - user = "paste"; - group = "nginx"; - - phpPackage = pkgs.php; - - settings = { - "pm" = "dynamic"; - "php_admin_value[error_log]" = "stderr"; - "php_admin_flag[log_errors]" = true; - "listen.owner" = "nginx"; - "catch_workers_output" = true; - "pm.max_children" = "32"; - "pm.start_servers" = "2"; - "pm.min_spare_servers" = "2"; - "pm.max_spare_servers" = "4"; - "pm.max_requests" = "500"; + containers.paste = container.mkContainer cfg { + bindMounts = { + "/srv/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; - - phpEnv = { - # CONFIG_PATH = "${package}/cfg"; + "/tmp" = { + hostPath = "${cfg.storage}/tmp"; + isReadOnly = false; + }; + "/var/lib/nginx/tmp" = { + hostPath = "${cfg.storage}/nginxtmp"; + isReadOnly = false; + }; + "/srv/config" = { + hostPath = "${cfg.storage}/config"; + isReadOnly = false; }; }; - services.nginx = { - enable = true; - virtualHosts.${cfg.domain} = container.mkServer { - default = true; - root = "${package}"; + config = { config, ... }: container.mkContainerConfig cfg { + environment.systemPackages = [ package ]; + systemd.packages = [ package ]; - locations = { - "/".extraConfig = '' - rewrite ^ /index.php; - ''; + users.users.paste = { + group = "nginx"; + isSystemUser = true; + }; - "~ \\.php$".extraConfig = util.trimTabs '' - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_pass unix:${config.services.phpfpm.pools.paste.socket}; - include ${config.services.nginx.package}/conf/fastcgi.conf; - include ${config.services.nginx.package}/conf/fastcgi_params; - ''; + services.phpfpm.pools.paste = { + user = "paste"; + group = "nginx"; - "~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = util.trimTabs '' - add_header Cache-Control "public, max-age=15778463"; - add_header X-Content-Type-Options nosniff; - add_header X-XSS-Protection "1; mode=block"; - add_header X-Robots-Tag none; - add_header X-Download-Options noopen; - add_header X-Permitted-Cross-Domain-Policies none; - add_header Referrer-Policy no-referrer; - access_log off; - ''; + phpPackage = pkgs.php; + + settings = { + "pm" = "dynamic"; + "php_admin_value[error_log]" = "stderr"; + "php_admin_flag[log_errors]" = true; + "listen.owner" = "nginx"; + "catch_workers_output" = true; + "pm.max_children" = "32"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "2"; + "pm.max_spare_servers" = "4"; + "pm.max_requests" = "500"; }; - extraConfig = util.trimTabs '' - try_files $uri /index.php; - ''; + phpEnv = { + # CONFIG_PATH = "${package}/cfg"; + }; + }; + + services.nginx = { + enable = true; + virtualHosts.${cfg.domain} = container.mkServer { + default = true; + root = "${package}"; + + locations = { + "/".extraConfig = '' + rewrite ^ /index.php; + ''; + + "~ \\.php$".extraConfig = util.trimTabs '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${config.services.phpfpm.pools.paste.socket}; + include ${config.services.nginx.package}/conf/fastcgi.conf; + include ${config.services.nginx.package}/conf/fastcgi_params; + ''; + + "~ \\.(js|css|ttf|woff2?|png|jpe?g|svg)$".extraConfig = util.trimTabs '' + add_header Cache-Control "public, max-age=15778463"; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Robots-Tag none; + add_header X-Download-Options noopen; + add_header X-Permitted-Cross-Domain-Policies none; + add_header Referrer-Policy no-referrer; + access_log off; + ''; + }; + + extraConfig = util.trimTabs '' + try_files $uri /index.php; + ''; + }; }; }; }; diff --git a/container/Postgres.nix b/container/Postgres.nix index 55e4794..7562a6c 100644 --- a/container/Postgres.nix +++ b/container/Postgres.nix @@ -1,56 +1,76 @@ -{ container, lib, pkgs, ... } @args: let - cfg = container.config.postgres; +{ container, lib, pkgs, config, ... }: with lib; let + cfg = config.container.module.postgres; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.postgres = container.mkContainer cfg { - bindMounts = { - "/var/lib/postgresql/data" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.postgres = { + enable = mkEnableOption "Postgresql server."; + address = mkOption { + default = "10.1.0.3"; + type = types.str; + }; + port = mkOption { + default = 5432; + type = types.int; + }; + storage = mkOption { + default = "${config.container.storage}/postgres"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.postgresql = let - # Populate with services here. - configurations = with container.config; { - gitea = git; - nextcloud = cloud; - privatebin = paste; - onlyoffice = office; - paperless = paper; - invidious = yt; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.postgres = container.mkContainer cfg { + bindMounts = { + "/var/lib/postgresql/data" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; + }; - access = configurations // { - all = { address = container.host; }; + config = { ... }: container.mkContainerConfig cfg { + services.postgresql = let + # Populate with services here. + configurations = with config.container.module; { + gitea = git; + nextcloud = cloud; + privatebin = paste; + onlyoffice = office; + paperless = paper; + invidious = yt; + }; + + access = configurations // { + all = { address = config.container.host; }; + }; + + authentication = builtins.foldl' (acc: item: acc + "${item}\n") "" ( + mapAttrsToList (db: cfg: "host ${db} ${db} ${cfg.address}/32 trust") access + ); + + ensureDatabases = [ "root" ] ++ mapAttrsToList (name: _: name) configurations; + + ensureUsers = map (name: { + inherit name; + ensureClauses = if name == "root" then { + superuser = true; + createrole = true; + createdb = true; + } else {}; + ensureDBOwnership = true; + }) ensureDatabases; + in { + inherit authentication ensureDatabases ensureUsers; + + enable = true; + package = pkgs.postgresql_14; + dataDir = "/var/lib/postgresql/data/14"; + enableTCPIP = true; }; - - authentication = builtins.foldl' (acc: item: acc + "${item}\n") "" ( - lib.mapAttrsToList (db: cfg: "host ${db} ${db} ${cfg.address}/32 trust") access - ); - - ensureDatabases = [ "root" ] ++ lib.mapAttrsToList (name: _: name) configurations; - - ensureUsers = map (name: { - inherit name; - ensureClauses = if name == "root" then { - superuser = true; - createrole = true; - createdb = true; - } else {}; - ensureDBOwnership = true; - }) ensureDatabases; - in { - inherit authentication ensureDatabases ensureUsers; - - enable = true; - package = pkgs.postgresql_14; - dataDir = "/var/lib/postgresql/data/14"; - enableTCPIP = true; }; }; }; diff --git a/container/Print.nix b/container/Print.nix index 9182097..59d0230 100644 --- a/container/Print.nix +++ b/container/Print.nix @@ -2,33 +2,57 @@ # ipp://192.168.2.237 # Pantum M6500W-Series -{ container, pkgs, ... } @args: let - cfg = container.config.print; +{ container, pkgs, lib, config, ... }: with lib; let + cfg = config.container.module.print; package = pkgs.callPackage ./print args; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.print = container.mkContainer cfg { - bindMounts = { - "/var/lib/cups" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.print = { + enable = mkEnableOption "Printing server."; + address = mkOption { + default = "10.1.0.46"; + type = types.str; + }; + port = mkOption { + default = 631; + type = types.int; + }; + domain = mkOption { + default = "print.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/print"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.printing = { - enable = true; - allowFrom = [ "all" ]; - browsing = true; - defaultShared = true; - drivers = [ package ]; - listenAddresses = [ "${cfg.address}:${toString cfg.port}" ]; - startWhenNeeded = true; - stateless = false; - webInterface = true; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.print = container.mkContainer cfg { + bindMounts = { + "/var/lib/cups" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.printing = { + enable = true; + allowFrom = [ "all" ]; + browsing = true; + defaultShared = true; + drivers = [ package ]; + listenAddresses = [ "${cfg.address}:${toString cfg.port}" ]; + startWhenNeeded = true; + stateless = false; + webInterface = true; + }; }; }; }; diff --git a/container/Proxy.nix b/container/Proxy.nix index 52354f4..13d6293 100644 --- a/container/Proxy.nix +++ b/container/Proxy.nix @@ -9,95 +9,115 @@ # ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; # ``` # For certbot to generate new keys: `certbot certonly --manual --manual-public-ip-logging-ok --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory -d "*.voronind.com" -d voronind.com` -{ domain, util, container, pkgs, ... } @args: let - cfg = container.config.proxy; +{ util, container, pkgs, lib, config, ... } @args: with lib; let + cfg = config.container.module.proxy; virtualHosts = util.catSet (util.ls ./proxy/host) args; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "challenge" - "letsencrypt" - ]; - - containers.proxy = container.mkContainer cfg { - forwardPorts = [ - # { - # containerPort = 80; - # hostPort = 80; - # protocol = "tcp"; - # } { - { - containerPort = cfg.port; - hostPort = cfg.port; - protocol = "tcp"; - } - ]; - - bindMounts = { - "/etc/letsencrypt" = { - hostPath = "${cfg.storage}/letsencrypt"; - isReadOnly = true; + options = { + container.module.proxy = { + enable = mkEnableOption "Proxy server."; + address = mkOption { + default = "10.1.0.2"; + type = types.str; }; - "/var/www/.well-known" = { - hostPath = "${cfg.storage}/challenge"; - isReadOnly = false; + port = mkOption { + default = 443; + type = types.int; + }; + storage = mkOption { + default = "${config.container.storage}/proxy"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - environment.systemPackages = with pkgs; [ certbot ]; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "challenge" + "letsencrypt" + ]; - services.nginx = { - inherit virtualHosts; + containers.proxy = container.mkContainer cfg { + forwardPorts = [ + # { + # containerPort = 80; + # hostPort = 80; + # protocol = "tcp"; + # } { + { + containerPort = cfg.port; + hostPort = cfg.port; + protocol = "tcp"; + } + ]; - enable = true; - recommendedOptimisation = true; - recommendedProxySettings = true; - appendConfig = util.trimTabs '' - worker_processes 4; - ''; - eventsConfig = util.trimTabs '' - worker_connections 4096; - ''; - # TODO: Fix 80 redirect and 403 default. - appendHttpConfig = util.trimTabs '' - server { - server_name default_server; - listen 80; + bindMounts = { + "/etc/letsencrypt" = { + hostPath = "${cfg.storage}/letsencrypt"; + isReadOnly = true; + }; + "/var/www/.well-known" = { + hostPath = "${cfg.storage}/challenge"; + isReadOnly = false; + }; + }; - location / { - return 301 https://$host$request_uri; + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ certbot ]; + + services.nginx = { + inherit virtualHosts; + + enable = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + appendConfig = util.trimTabs '' + worker_processes 4; + ''; + eventsConfig = util.trimTabs '' + worker_connections 4096; + ''; + # TODO: Fix 80 redirect and 403 default. + appendHttpConfig = util.trimTabs '' + server { + server_name default_server; + listen 80; + + location / { + return 301 https://$host$request_uri; + } } - } - map $http_accept_language $resume { - default https://git.${domain}/voronind/resume/releases/download/latest/voronind_en.pdf; - ~ru https://git.${domain}/voronind/resume/releases/download/latest/voronind_ru.pdf; - } + map $http_accept_language $resume { + default https://git.${config.container.domain}/voronind/resume/releases/download/latest/voronind_en.pdf; + ~ru https://git.${config.container.domain}/voronind/resume/releases/download/latest/voronind_ru.pdf; + } - server { - server_name ${domain}; - listen 443 ssl; + server { + server_name ${config.container.domain}; + listen 443 ssl; - ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; - include /etc/letsencrypt/conf/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; - return 301 $resume; - } + return 301 $resume; + } - server { - listen 443 ssl default_server; - server_name _; + server { + listen 443 ssl default_server; + server_name _; - ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; - include /etc/letsencrypt/conf/options-ssl-nginx.conf; - ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; + ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem; + include /etc/letsencrypt/conf/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; - return 403; - } - ''; + return 403; + } + ''; + }; }; }; }; diff --git a/container/Rabbitmq.nix b/container/Rabbitmq.nix index 99e556d..4b43651 100644 --- a/container/Rabbitmq.nix +++ b/container/Rabbitmq.nix @@ -1,26 +1,46 @@ -{ container, pkgs, util, ... } @args: let - cfg = container.config.rabbitmq; +{ container, pkgs, util, lib, config, ... }: with lib; let + cfg = config.container.module.rabbitmq; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.rabbitmq = container.mkContainer cfg { - bindMounts = { - "/var/lib/rabbitmq" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.rabbitmq = { + enable = mkEnableOption "Mqtt server."; + address = mkOption { + default = "10.1.0.28"; + type = types.str; + }; + port = mkOption { + default = 5672; + type = types.int; + }; + storage = mkOption { + default = "${config.container.storage}/rabbitmq"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.rabbitmq = { - enable = true; - listenAddress = cfg.address; - port = cfg.port; - dataDir = "/var/lib/rabbitmq"; - configItems = { - "loopback_users" = "none"; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.rabbitmq = container.mkContainer cfg { + bindMounts = { + "/var/lib/rabbitmq" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.rabbitmq = { + enable = true; + listenAddress = cfg.address; + port = cfg.port; + dataDir = "/var/lib/rabbitmq"; + configItems = { + "loopback_users" = "none"; + }; }; }; }; diff --git a/container/Read.nix b/container/Read.nix index 5dbef40..ad9634d 100644 --- a/container/Read.nix +++ b/container/Read.nix @@ -1,29 +1,53 @@ -{ container, lib, pkgs, ... } @args: let - cfg = container.config.read; +{ container, lib, pkgs, config, ... }: with lib; let + cfg = config.container.module.read; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.read = container.mkContainer cfg { - bindMounts = { - "/var/lib/kavita" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.read = { + enable = mkEnableOption "Reading server."; + address = mkOption { + default = "10.1.0.39"; + type = types.str; }; - } - // container.attachMedia "book" cfg.book true - // container.attachMedia "manga" cfg.manga true - ; + port = mkOption { + default = 5000; + type = types.int; + }; + domain = mkOption { + default = "read.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/read"; + type = types.str; + }; + }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.kavita = { - enable = true; - dataDir = "/var/lib/kavita"; - tokenKeyFile = pkgs.writeText "KavitaToken" "xY19aQOa939/Ie6GCRGbubVK8zRwrgBY/20AuyMpYshUjwK1Uyl7bw1yknVh6jJIFIfwq2vAjeotOUq7NEsf9Q=="; - settings = { - IpAddresses = cfg.address; - Port = cfg.port; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.read = container.mkContainer cfg { + bindMounts = { + "/var/lib/kavita" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + } + // container.attachMedia "book" true + // container.attachMedia "manga" true + ; + + config = { ... }: container.mkContainerConfig cfg { + services.kavita = { + enable = true; + dataDir = "/var/lib/kavita"; + tokenKeyFile = pkgs.writeText "KavitaToken" "xY19aQOa939/Ie6GCRGbubVK8zRwrgBY/20AuyMpYshUjwK1Uyl7bw1yknVh6jJIFIfwq2vAjeotOUq7NEsf9Q=="; + settings = { + IpAddresses = cfg.address; + Port = cfg.port; + }; }; }; }; diff --git a/container/Redis.nix b/container/Redis.nix index 5d172e0..4a11e53 100644 --- a/container/Redis.nix +++ b/container/Redis.nix @@ -1,13 +1,29 @@ -{ container, pkgs, util, ... } @args: let - cfg = container.config.redis; +{ container, pkgs, util, lib, config, ... }: with lib; let + cfg = config.container.module.redis; in { - containers.redis = container.mkContainer cfg { - config = { ... }: container.mkContainerConfig cfg { - services.redis.servers.main = { - enable = true; - port = cfg.port; - bind = cfg.address; - extraParams = [ "--protected-mode no" ]; + options = { + container.module.redis = { + enable = mkEnableOption "Redis server."; + address = mkOption { + default = "10.1.0.38"; + type = types.str; + }; + port = mkOption { + default = 6379; + type = types.int; + }; + }; + }; + + config = mkIf cfg.enable { + containers.redis = container.mkContainer cfg { + config = { ... }: container.mkContainerConfig cfg { + services.redis.servers.main = { + enable = true; + port = cfg.port; + bind = cfg.address; + extraParams = [ "--protected-mode no" ]; + }; }; }; }; diff --git a/container/Search.nix b/container/Search.nix index d99bdba..92af1bf 100644 --- a/container/Search.nix +++ b/container/Search.nix @@ -1,16 +1,40 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.search; +{ container, pkgs, lib, config, ... }: with lib; let + cfg = config.container.module.search; in { - containers.search = container.mkContainer cfg { - config = { ... }: container.mkContainerConfig cfg { - services.searx = { - enable = true; - package = pkgs.searxng; - settings = { - server = { - bind_address = cfg.address; - port = cfg.port; - secret_key = "searxxx"; + options = { + container.module.search = { + enable = mkEnableOption "Search frontend."; + address = mkOption { + default = "10.1.0.26"; + type = types.str; + }; + port = mkOption { + default = 8080; + type = types.int; + }; + domain = mkOption { + default = "search.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/search"; + type = types.str; + }; + }; + }; + + config = mkIf cfg.enable { + containers.search = container.mkContainer cfg { + config = { ... }: container.mkContainerConfig cfg { + services.searx = { + enable = true; + package = pkgs.searxng; + settings = { + server = { + bind_address = cfg.address; + port = cfg.port; + secret_key = "searxxx"; + }; }; }; }; diff --git a/container/Status.nix b/container/Status.nix index 542726d..c1a8858 100644 --- a/container/Status.nix +++ b/container/Status.nix @@ -1,36 +1,60 @@ -{ container, ... } @args: let - cfg = container.config.status; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.status; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.status = container.mkContainer cfg { - bindMounts = { - "/var/lib/uptime-kuma" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.status = { + enable = mkEnableOption "Status monitor."; + address = mkOption { + default = "10.1.0.22"; + type = types.str; + }; + port = mkOption { + default = 3001; + type = types.int; + }; + domain = mkOption { + default = "status.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/status"; + type = types.str; }; }; + }; - config = { lib, ... }: container.mkContainerConfig cfg { - networking = { - nameservers = lib.mkForce [ - container.config.dns.address - ]; - }; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; - services.uptime-kuma = { - enable = true; - settings = { - DATA_DIR = "/var/lib/uptime-kuma/"; - HOST = cfg.address; - PORT = toString cfg.port; + containers.status = container.mkContainer cfg { + bindMounts = { + "/var/lib/uptime-kuma" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; }; - systemd.services.uptime-kuma = { - serviceConfig.DynamicUser = lib.mkForce false; + config = { lib, ... }: container.mkContainerConfig cfg { + networking = { + nameservers = mkForce [ + config.container.module.dns.address + ]; + }; + + services.uptime-kuma = { + enable = true; + settings = { + DATA_DIR = "/var/lib/uptime-kuma/"; + HOST = cfg.address; + PORT = toString cfg.port; + }; + }; + + systemd.services.uptime-kuma = { + serviceConfig.DynamicUser = mkForce false; + }; }; }; }; diff --git a/container/Stock.nix b/container/Stock.nix index e1ae73b..d57f6a3 100644 --- a/container/Stock.nix +++ b/container/Stock.nix @@ -1,31 +1,55 @@ -{ container, ... } @args: let - cfg = container.config.stock; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.stock; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - ]; - - containers.stock = container.mkContainer cfg { - bindMounts = { - "/var/lib/grocy" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; + options = { + container.module.stock = { + enable = mkEnableOption "Stock management."; + address = mkOption { + default = "10.1.0.45"; + type = types.str; + }; + port = mkOption { + default = 80; + type = types.int; + }; + domain = mkOption { + default = "stock.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/stock"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - services.grocy = { - enable = true; - dataDir = "/var/lib/grocy"; - hostName = cfg.domain; - nginx.enableSSL = false; - settings = { - calendar = { - firstDayOfWeek = 1; - showWeekNumber = true; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + ]; + + containers.stock = container.mkContainer cfg { + bindMounts = { + "/var/lib/grocy" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + }; + + config = { ... }: container.mkContainerConfig cfg { + services.grocy = { + enable = true; + dataDir = "/var/lib/grocy"; + hostName = cfg.domain; + nginx.enableSSL = false; + settings = { + calendar = { + firstDayOfWeek = 1; + showWeekNumber = true; + }; + culture = "en"; + currency = "RUB"; }; - culture = "en"; - currency = "RUB"; }; }; }; diff --git a/container/Vpn.nix b/container/Vpn.nix index d37dad0..17b2582 100644 --- a/container/Vpn.nix +++ b/container/Vpn.nix @@ -1,68 +1,90 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.vpn; -in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - "data/preshared" +{ container, pkgs, lib, config, ... }: with lib; let + cfg = config.container.module.vpn; + + wireguardPeers = let + mkPeer = name: ip: PublicKey: { + inherit PublicKey; + PresharedKeyFile = "/var/lib/wireguard/preshared/${name}"; + AllowedIPs = [ "${ip}/32" ]; + }; + in [ + (mkPeer "dashaphone" "10.1.1.3" "O/3y8+QKEY8UoLVlmbc8xdhs248L4wtQcl1MsBBfoQo=") + (mkPeer "laptop" "10.1.1.9" "xxoCNPSB86zs8L8p+wXhqaIwpNDkiZu1Yjv8sj8XhgY=") + (mkPeer "phone" "10.1.1.5" "bFmFisMqbDpIrAg3o/GiRl9XhceZEVnZtkegZDTL4yg=") + (mkPeer "tablet" "10.1.1.6" "BdslswVc9OgUpEhJd0sugDBmYw44DiS0FbUPT5EjOG0=") + (mkPeer "work" "10.1.1.2" "Pk0AASSInKO9O8RaQEmm1uNrl0cwWTJDcT8rLn7PSA0=") ]; - - boot.kernel.sysctl = { - "net.ipv4.conf.all.src_valid_mark" = 1; - }; - - containers.vpn = container.mkContainer cfg { - forwardPorts = [ - { - containerPort = cfg.port; - hostPort = cfg.port; - protocol = "udp"; - } - ]; - bindMounts = { - "/var/lib/wireguard" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; +in { + options = { + container.module.vpn = { + enable = mkEnableOption "Vpn server."; + address = mkOption { + default = "10.1.0.23"; + type = types.str; + }; + port = mkOption { + default = 51820; + type = types.int; + }; + storage = mkOption { + default = "${config.container.storage}/vpn"; + type = types.str; }; }; + }; - config = { ... }: container.mkContainerConfig cfg { - environment.systemPackages = with pkgs; [ wireguard-tools ]; - networking.useNetworkd = true; - systemd.network = { - enable = true; - netdevs = { - "50-wg0" = { - netdevConfig = { - Kind = "wireguard"; - MTUBytes = "1300"; - Name = "wg0"; - }; - wireguardConfig = { - PrivateKeyFile = "/var/lib/wireguard/privkey"; - ListenPort = cfg.port; - }; - wireguardPeers = let - mkPeer = name: ip: PublicKey: { - inherit PublicKey; - PresharedKeyFile = "/var/lib/wireguard/preshared/${name}"; - AllowedIPs = [ "${ip}/32" ]; - }; - in [ - (mkPeer "dashaphone" "10.1.1.3" "O/3y8+QKEY8UoLVlmbc8xdhs248L4wtQcl1MsBBfoQo=") - (mkPeer "laptop" "10.1.1.9" "xxoCNPSB86zs8L8p+wXhqaIwpNDkiZu1Yjv8sj8XhgY=") - (mkPeer "phone" "10.1.1.5" "bFmFisMqbDpIrAg3o/GiRl9XhceZEVnZtkegZDTL4yg=") - (mkPeer "tablet" "10.1.1.6" "BdslswVc9OgUpEhJd0sugDBmYw44DiS0FbUPT5EjOG0=") - (mkPeer "work" "10.1.1.2" "Pk0AASSInKO9O8RaQEmm1uNrl0cwWTJDcT8rLn7PSA0=") - ]; - }; + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + "data/preshared" + ]; + + boot.kernel.sysctl = { + "net.ipv4.conf.all.src_valid_mark" = 1; + }; + + containers.vpn = container.mkContainer cfg { + forwardPorts = [ + { + containerPort = cfg.port; + hostPort = cfg.port; + protocol = "udp"; + } + ]; + bindMounts = { + "/var/lib/wireguard" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; }; + }; - networks.wg0 = { - matchConfig.Name = "wg0"; - address = ["10.1.1.0/24"]; - networkConfig = { - IPForward = true; - IPMasquerade = "ipv4"; + config = { ... }: container.mkContainerConfig cfg { + environment.systemPackages = with pkgs; [ wireguard-tools ]; + networking.useNetworkd = true; + systemd.network = { + enable = true; + netdevs = { + "50-wg0" = { + netdevConfig = { + Kind = "wireguard"; + MTUBytes = "1300"; + Name = "wg0"; + }; + wireguardConfig = { + PrivateKeyFile = "/var/lib/wireguard/privkey"; + ListenPort = cfg.port; + }; + inherit wireguardPeers; + }; + }; + + networks.wg0 = { + matchConfig.Name = "wg0"; + address = ["10.1.1.0/24"]; + networkConfig = { + IPForward = true; + IPMasquerade = "ipv4"; + }; }; }; }; diff --git a/container/Watch.nix b/container/Watch.nix index f2b7f17..519bce9 100644 --- a/container/Watch.nix +++ b/container/Watch.nix @@ -1,54 +1,81 @@ -{ container, lib, ... } @args: let - cfg = container.config.watch; - memLimit = "8G"; +{ container, lib, config, ... }: with lib; let + cfg = config.container.module.watch; in { - systemd.tmpfiles.rules = container.mkContainerDir cfg [ - "data" - "cache" - ]; + options = { + container.module.watch = { + enable = mkEnableOption "Media server."; + address = mkOption { + default = "10.1.0.11"; + type = types.str; + }; + port = mkOption { + default = 8096; + type = types.int; + }; + domain = mkOption { + default = "watch.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/watch"; + type = types.str; + }; + memLimit = mkOption { + default = "8G"; + type = types.str; + }; + }; + }; - containers.watch = container.mkContainer cfg { - bindMounts = { - "/var/lib/jellyfin" = { - hostPath = "${cfg.storage}/data"; - isReadOnly = false; - }; - "/var/cache/jellyfin" = { - hostPath = "${cfg.storage}/cache"; - isReadOnly = false; - }; - "/dev/dri" = { - hostPath = "/dev/dri"; - isReadOnly = false; - }; - } - // container.attachMedia "anime" cfg.anime true - // container.attachMedia "download" cfg.download true - // container.attachMedia "movie" cfg.movie true - // container.attachMedia "music" cfg.music true - // container.attachMedia "photo" cfg.photo true - // container.attachMedia "porn" cfg.porn true - // container.attachMedia "show" cfg.show true - // container.attachMedia "study" cfg.study true - // container.attachMedia "work" cfg.work true - // container.attachMedia "youtube" cfg.youtube true - ; - - allowedDevices = [ - { - modifier = "rwm"; - node = "/dev/dri"; - } + config = mkIf cfg.enable { + systemd.tmpfiles.rules = container.mkContainerDir cfg [ + "data" + "cache" ]; - config = { ... }: container.mkContainerConfig cfg { - services.jellyfin = { - enable = true; - cacheDir = "/var/cache/jellyfin"; - dataDir = "/var/lib/jellyfin"; - }; + containers.watch = container.mkContainer cfg { + bindMounts = { + "/var/lib/jellyfin" = { + hostPath = "${cfg.storage}/data"; + isReadOnly = false; + }; + "/var/cache/jellyfin" = { + hostPath = "${cfg.storage}/cache"; + isReadOnly = false; + }; + "/dev/dri" = { + hostPath = "/dev/dri"; + isReadOnly = false; + }; + } + // container.attachMedia "anime" true + // container.attachMedia "download" true + // container.attachMedia "movie" true + // container.attachMedia "music" true + // container.attachMedia "photo" true + // container.attachMedia "porn" true + // container.attachMedia "show" true + // container.attachMedia "study" true + // container.attachMedia "work" true + // container.attachMedia "youtube" true + ; - systemd.services.jellyfin.serviceConfig.MemoryLimit = memLimit; + allowedDevices = [ + { + modifier = "rwm"; + node = "/dev/dri"; + } + ]; + + config = { ... }: container.mkContainerConfig cfg { + services.jellyfin = { + enable = true; + cacheDir = "/var/cache/jellyfin"; + dataDir = "/var/lib/jellyfin"; + }; + + systemd.services.jellyfin.serviceConfig.MemoryLimit = cfg.memLimit; + }; }; }; } diff --git a/container/Yt.nix b/container/Yt.nix index daf13e3..a61e4f5 100644 --- a/container/Yt.nix +++ b/container/Yt.nix @@ -1,26 +1,50 @@ -{ container, pkgs, ... } @args: let - cfg = container.config.yt; +{ container, pkgs, lib, config, ... }: with lib; let + cfg = config.container.module.yt; in { - containers.yt = container.mkContainer cfg { - config = { ... }: container.mkContainerConfig cfg { - services.invidious = { - enable = true; - domain = cfg.domain; - port = cfg.port; - nginx.enable = false; - database = { - port = container.config.postgres.port; - host = container.config.postgres.address; - createLocally = false; - passwordFile = "${pkgs.writeText "InvidiousDbPassword" "invidious"}"; - }; - settings = { - admins = [ "root" ]; - captcha_enabled = false; - check_tables = true; - registration_enabled = false; - external_port = 443; - https_only = true; + options = { + container.module.yt = { + enable = mkEnableOption "YouTube frontend."; + address = mkOption { + default = "10.1.0.19"; + type = types.str; + }; + port = mkOption { + default = 3000; + type = types.int; + }; + domain = mkOption { + default = "yt.${config.container.domain}"; + type = types.str; + }; + storage = mkOption { + default = "${config.container.storage}/yt"; + type = types.str; + }; + }; + }; + + config = mkIf cfg.enable { + containers.yt = container.mkContainer cfg { + config = { ... }: container.mkContainerConfig cfg { + services.invidious = { + enable = true; + domain = cfg.domain; + port = cfg.port; + nginx.enable = false; + database = { + port = config.container.module.postgres.port; + host = config.container.module.postgres.address; + createLocally = false; + passwordFile = "${pkgs.writeText "InvidiousDbPassword" "invidious"}"; + }; + settings = { + admins = [ "root" ]; + captcha_enabled = false; + check_tables = true; + registration_enabled = false; + external_port = 443; + https_only = true; + }; }; }; }; diff --git a/container/default.nix b/container/default.nix index 982542e..df2ae8d 100644 --- a/container/default.nix +++ b/container/default.nix @@ -1,246 +1,55 @@ -{ lib -, const -, host -, storage -, domain -, media -, pkgs -, ... }: { - inherit host; +{ lib, config, ... }: with lib; let + cfg = config.container; +in { + options = { + container = { + enable = mkEnableOption "Containers!!"; - # Common configuration for all the containers. - mkContainer = config: cfg: lib.recursiveUpdate { - # Start containers with the system by default. - autoStart = true; - - # IP Address of the host. This is required for container to have access to the Internet. - hostAddress = host; - - # Container's IP address. - localAddress = config.address; - - # Isolate container from other hosts. - privateNetwork = true; - } cfg; - - # Common configuration for the system inside the container. - mkContainerConfig = config: cfg: lib.recursiveUpdate { - # HACK: Do not evaluate nixpkgs inside the container. Use host's instead. - nixpkgs.pkgs = lib.mkForce pkgs; - - # Release version. - system.stateVersion = const.stateVersion; - - # Allow passwordless login as root. - users.users.root.password = ""; - users.mutableUsers = false; - - networking = { - # Default DNS servers. - nameservers = [ - "1.1.1.1" - ]; - - # HACK: Fix for upstream issue: https://github.com/NixOS/nixpkgs/issues/162686 - useHostResolvConf = lib.mkForce false; - - # Disable firewall. - firewall.enable = false; - }; - } cfg; - - # Create a directory on the host for container use. - mkContainerDir = cfg: dirs: map (path: "d '${cfg.storage}/${path}' 1777 root root - -") dirs; - - # Common configuration for Nginx server. - mkServer = cfg: lib.recursiveUpdate { - forceSSL = false; - } cfg; - - # Attach the host media directory to container. - # They will be added to /type/{0..9} - attachMedia = type: paths: ro: builtins.listToAttrs (lib.imap0 (i: path: - { - name = "/${type}/${toString i}"; - value = { - hostPath = path; - isReadOnly = ro; + autoStart = mkOption { + default = true; + type = types.bool; }; - } - ) paths); - # Range of local addresses who have access to sensitive paths like admin panels. - # Other addresses will get 403. - localAccess = "192.168.1.0/24"; + host = mkOption { + default = "0.0.0.0"; + type = types.str; + }; - # Per-container configurations. - config = { - camera = { - address = "192.168.2.249"; - domain = "camera.${domain}"; - port = "554"; + localAccess = mkOption { + default = "0.0.0.0"; + type = types.str; + }; + + storage = mkOption { + default = "/tmp/container"; + type = types.str; + }; + + domain = mkOption { + default = "local"; + type = types.str; + }; + + interface = mkOption { + default = "lo"; + type = types.str; + }; + + media = mkOption { + default = {}; + type = types.attrs; + }; }; - change = { - address = "10.1.0.41"; - port = 5000; - domain = "change.${domain}"; - storage = "${storage}/change"; - }; - cloud = { - address = "10.1.0.13"; - port = 80; - domain = "cloud.${domain}"; - storage = "${storage}/cloud"; - }; - ddns = { - address = "10.1.0.31"; - port = 53; - storage = "${storage}/ddns"; - }; - dns = { - address = "10.1.0.6"; - }; - download = { - inherit (media) download; - address = "10.1.0.12"; - port = 8112; - domain = "download.${domain}"; - storage = "${storage}/download"; - }; - git = { - address = "10.1.0.8"; - port = 3000; - domain = "git.${domain}"; - storage = "${storage}/git"; - }; - hdd = { - address = "10.1.0.10"; - port = 8080; - domain = "hdd.${domain}"; - storage = "${storage}/hdd"; - }; - home = { - address = "10.1.0.18"; - port = 80; - domain = "home.${domain}"; - }; - iot = { - inherit (media) photo; - address = "10.1.0.27"; - domain = "iot.${domain}"; - port = 8123; - storage = "${storage}/iot"; - }; - jobber = { - address = "10.1.0.32"; - storage = "${storage}/jobber"; - }; - mail = { - address = "10.1.0.5"; - domain = "mail.${domain}"; - port = 80; - storage = "${storage}/mail"; - }; - office = { - address = "10.1.0.21"; - domain = "office.${domain}"; - port = 8000; - storage = "${storage}/office"; - }; - paper = { - inherit (media) paper; - address = "10.1.0.40"; - domain = "paper.${domain}"; - port = 28981; - storage = "${storage}/paper"; - }; - pass = { - address = "10.1.0.9"; - domain = "pass.${domain}"; - port = 8000; - storage = "${storage}/pass"; - }; - paste = { - address = "10.1.0.14"; - domain = "paste.${domain}"; - port = 80; - storage = "${storage}/paste"; - }; - print = { - domain = "print.${domain}"; - address = "10.1.0.46"; - port = 631; - storage = "${storage}/print"; - }; - printer = { - address = "192.168.2.237"; - domain = "printer.${domain}"; - port = 80; - }; - proxy = { - address = "10.1.0.2"; - port = 443; - storage = "${storage}/proxy"; - }; - postgres = { - address = "10.1.0.3"; - port = 5432; - storage = "${storage}/postgres"; - }; - rabbitmq = { - address = "10.1.0.28"; - port = 5672; - storage = "${storage}/rabbitmq"; - }; - read = { - inherit (media) book manga; - address = "10.1.0.39"; - domain = "read.${domain}"; - port = 5000; - storage = "${storage}/read"; - }; - redis = { - address = "10.1.0.38"; - port = 6379; - }; - router = { - address = "192.168.1.1"; - domain = "router.${domain}"; - port = 80; - }; - search = { - address = "10.1.0.26"; - domain = "search.${domain}"; - port = 8080; - }; - status = { - address = "10.1.0.22"; - domain = "status.${domain}"; - port = 3001; - storage = "${storage}/status"; - }; - stock = { - address = "10.1.0.45"; - domain = "stock.${domain}"; - port = 80; - storage = "${storage}/stock"; - }; - vpn = { - address = "10.1.0.23"; - port = 51820; - storage = "${storage}/vpn"; - }; - watch = { - inherit (media) anime download movie music photo porn show study work youtube; - address = "10.1.0.11"; - domain = "watch.${domain}"; - port = 8096; - storage = "${storage}/watch"; - }; - yt = { - address = "10.1.0.19"; - domain = "yt.${domain}"; - port = 3000; + }; + + config = mkIf cfg.enable { + # This is the network for all the containers. + # They are not available to the external interface by default, + # instead they all expose specific ports in their configuration. + networking.nat = { + enable = true; + internalInterfaces = [ "ve-+" ]; + externalInterface = config.container.interface; }; }; } diff --git a/container/homer/Config.nix b/container/homer/Config.nix index c4c9781..90fc275 100644 --- a/container/homer/Config.nix +++ b/container/homer/Config.nix @@ -1,4 +1,4 @@ -{ pkgs, container, ... }: let +{ pkgs, config, ... }: let iconTheme = "fa-solid"; mkGroup = name: icon: items: { @@ -12,7 +12,7 @@ target = "_blank"; }; - config = { + cfg = { title = "Dashboard"; subtitle = "Home"; header = false; @@ -41,33 +41,32 @@ }; links = [ - (mkLink "Status" "fa-heartbeat" "https://status.voronind.com") + (mkLink "Status" "fa-heartbeat" "https://${config.container.module.status.domain}") ]; services = [ (mkGroup "App" "fa-server" [ - (mkLink "Change" "fa-user-secret" "https://${container.config.change.domain}") - (mkLink "Cloud" "fa-cloud" "https://${container.config.cloud.domain}") - (mkLink "Download" "fa-download" "https://${container.config.download.domain}") - (mkLink "Git" "fab fa-git-alt" "https://${container.config.download.domain}") - (mkLink "Iot" "fa-home" "https://${container.config.iot.domain}") - (mkLink "Mail" "fa-envelope" "https://${container.config.mail.domain}") - (mkLink "Paper" "fa-paperclip" "https://${container.config.paper.domain}") - (mkLink "Pass" "fa-key" "https://${container.config.pass.domain}") - (mkLink "Paste" "fa-paste" "https://${container.config.paste.domain}/s") - (mkLink "Print" "fa-print" "https://${container.config.print.domain}") - (mkLink "Read" "fa-book" "https://${container.config.read.domain}") - (mkLink "Search" "fa-search" "https://${container.config.search.domain}") - (mkLink "Stock" "fa-boxes-stacked" "https://${container.config.stock.domain}") - (mkLink "Watch" "fa-film" "https://${container.config.watch.domain}") - (mkLink "YouTube" "fab fa-youtube" "https://${container.config.yt.domain}") + (mkLink "Change" "fa-user-secret" "https://${config.container.module.change.domain}") + (mkLink "Cloud" "fa-cloud" "https://${config.container.module.cloud.domain}") + (mkLink "Download" "fa-download" "https://${config.container.module.download.domain}") + (mkLink "Git" "fab fa-git-alt" "https://${config.container.module.download.domain}") + (mkLink "Iot" "fa-home" "https://${config.container.module.iot.domain}") + (mkLink "Mail" "fa-envelope" "https://${config.container.module.mail.domain}") + (mkLink "Paper" "fa-paperclip" "https://${config.container.module.paper.domain}") + (mkLink "Pass" "fa-key" "https://${config.container.module.pass.domain}") + (mkLink "Paste" "fa-paste" "https://${config.container.module.paste.domain}/s") + (mkLink "Print" "fa-print" "https://${config.container.module.print.domain}") + (mkLink "Read" "fa-book" "https://${config.container.module.read.domain}") + (mkLink "Search" "fa-search" "https://${config.container.module.search.domain}") + (mkLink "Stock" "fa-boxes-stacked" "https://${config.container.module.stock.domain}") + (mkLink "Watch" "fa-film" "https://${config.container.module.watch.domain}") + (mkLink "YouTube" "fab fa-youtube" "https://${config.container.module.yt.domain}") ]) (mkGroup "System" "fa-shield" [ - (mkLink "Camera" "fa-camera" "https://${container.config.camera.domain}") - # (mkLink "Hdd" "fa-hard-drive" "https://${container.config.hdd.domain}") + (mkLink "Camera" "fa-camera" "https://camera.${config.container.domain}") (mkLink "NixOS Search" "fa-snowflake" "https://search.nixos.org") - (mkLink "Printer" "fa-print" "https://${container.config.printer.domain}") - (mkLink "Router" "fa-route" "https://${container.config.router.domain}") + (mkLink "Printer" "fa-print" "https://printer.${config.container.domain}") + (mkLink "Router" "fa-route" "https://router.${config.container.domain}") ]) (mkGroup "Bookmark" "fa-bookmark" [ (mkLink "2gis" "fa-map-location-dot" "https://2gis.ru") @@ -96,5 +95,5 @@ ]; }; in { - file = (pkgs.formats.yaml {}).generate "HomerConfig" config; + file = (pkgs.formats.yaml {}).generate "HomerConfig" cfg; } diff --git a/container/homer/default.nix b/container/homer/default.nix index 2d26fff..bfc1121 100644 --- a/container/homer/default.nix +++ b/container/homer/default.nix @@ -1,4 +1,4 @@ -{ stdenv, pkgs, ... } @args: let +{ stdenv, pkgs, config, ... } @args: let cfg = (import ./Config.nix args).file; in stdenv.mkDerivation (finalAttrs: { pname = "Homer"; diff --git a/container/pastebin/Config.nix b/container/pastebin/Config.nix index 4268298..fdbcc19 100644 --- a/container/pastebin/Config.nix +++ b/container/pastebin/Config.nix @@ -1,4 +1,4 @@ -{ util, container, ... }: { +{ util, config, ... }: { text = util.trimTabs '' ; ${controlFileMax} + echo ${toString cfg.offMin} > ${controlFileMin} + else + echo ${toString cfg.onMin} > ${controlFileMin} + echo ${toString cfg.onMax} > ${controlFileMax} + fi - script = pkgs.writeShellScriptBin "powerlimit" (import ./powerlimit/Script.nix { - inherit controlFileMax controlFileMin onMin onMax offMin offMax; - }).script; + true + } + + function waybar() { + status || echo -n "" + } + + function status() { + local current=$(cat ${controlFileMax}) + local enabled="${toString cfg.onMax}" + + [[ "''${current}" = "''${enabled}" ]] + } + + ''${@} + ''; in { - imports = [ - (import ./powerlimit ({ - inherit controlFileMax controlFileMin onMin onMax offMin offMax; - } // args)) - ]; + options = { + module.powerlimit.thinkpad = { + enable = mkEnableOption "Powerlimit Service"; + onMin = mkOption { + default = 40; + type = types.int; + }; + onMax = mkOption { + default = 80; + type = types.int; + }; + offMin = mkOption { + default = 90; + type = types.int; + }; + offMax = mkOption { + default = 95; + type = types.int; + }; + }; + }; - environment.systemPackages = [ script ]; + config = mkIf cfg.enable { + environment.systemPackages = [ script ]; + systemd = { + services.powerlimit = { + description = "Limit battery charge."; + enable = true; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + RemainAfterExit = "yes"; + ExecStart = "${getExe pkgs.bash} -c 'echo ${toString cfg.onMin} > ${controlFileMin}; echo ${toString cfg.onMax} > ${controlFileMax};'"; + ExecStop = "${getExe pkgs.bash} -c 'echo ${toString cfg.offMax} > ${controlFileMax}; echo ${toString cfg.offMin} > ${controlFileMin};'"; + }; + }; + + # HACK: Allow user access. + tmpfiles.rules = [ + "z ${controlFileMax} 0777 - - - -" + "z ${controlFileMin} 0777 - - - -" + ]; + }; + }; } diff --git a/module/Powersave.nix b/module/Powersave.nix new file mode 100644 index 0000000..0ed8862 --- /dev/null +++ b/module/Powersave.nix @@ -0,0 +1,73 @@ +{ lib, config, pkgs, ... }: with lib; let + cfg = config.module.powersave; + + script = pkgs.writeShellScriptBin "powersave" '' + function toggle() { + if status; then + echo ${cfg.cpu.boost.disableCmd} > ${cfg.cpu.boost.controlFile} + else + echo ${cfg.cpu.boost.enableCmd} > ${cfg.cpu.boost.controlFile} + fi + + true + } + + function waybar() { + status || echo -n "󰓅" + } + + function status() { + local current=$(cat ${cfg.cpu.boost.controlFile}) + local enabled="${cfg.cpu.boost.enableCmd}" + + [[ "''${current}" = "''${enabled}" ]] + } + + ''${@} + ''; +in { + options = { + module.powersave = { + enable = mkEnableOption "Powersave"; + cpu.boost = mkOption { + default = {}; + type = types.submodule { + options = { + disableCmd = mkOption { + default = null; + type = types.str; + }; + enableCmd = mkOption { + default = null; + type = types.str; + }; + controlFile = mkOption { + default = null; + type = types.str; + }; + }; + }; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = [ script ]; + systemd = { + services.powersave-cpu = { + description = "Disable CPU Boost"; + enable = true; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + RemainAfterExit = "yes"; + ExecStart = "${getExe pkgs.bash} -c 'echo ${cfg.cpu.boost.enableCmd} > ${cfg.cpu.boost.controlFile}'"; + ExecStop = "${getExe pkgs.bash} -c 'echo ${cfg.cpu.boost.disableCmd} > ${cfg.cpu.boost.controlFile}'"; + }; + }; + + # HACK: Allow user access. + tmpfiles.rules = [ "z ${cfg.cpu.boost.controlFile} 0777 - - - -" ]; + }; + }; +} diff --git a/module/PowersaveAmd.nix b/module/PowersaveAmd.nix deleted file mode 100644 index d8cb2eb..0000000 --- a/module/PowersaveAmd.nix +++ /dev/null @@ -1,21 +0,0 @@ -# AMD CPU boost control. -{ pkgs, ... } @args: let - controlFile = "/sys/devices/system/cpu/cpufreq/boost"; - enable = "0"; - disable = "1"; - - script = pkgs.writeShellScriptBin "powersave" (import ./powersave/Script.nix { - inherit controlFile enable disable; - }).script; -in { - # Requirements: - # CPPC (Collaborative Power Control) - Disabled. - # PSS (Cool and Quiet) - Enabled. - imports = [ - (import ./powersave ({ - inherit controlFile enable disable; - } // args)) - ]; - - environment.systemPackages = [ script ]; -} diff --git a/module/PowersaveIntel.nix b/module/PowersaveIntel.nix deleted file mode 100644 index bea3e99..0000000 --- a/module/PowersaveIntel.nix +++ /dev/null @@ -1,18 +0,0 @@ -# Intel CPU boost control. -{ pkgs, ... } @args: let - controlFile = "/sys/devices/system/cpu/intel_pstate/no_turbo"; - enable = "1"; - disable = "0"; - - script = pkgs.writeShellScriptBin "powersave" (import ./powersave/Script.nix { - inherit controlFile enable disable; - }).script; -in { - imports = [ - (import ./powersave ({ - inherit controlFile enable disable; - } // args)) - ]; - - environment.systemPackages = [ script ]; -} diff --git a/module/Print.nix b/module/Print.nix index 6c8ab38..63f579d 100644 --- a/module/Print.nix +++ b/module/Print.nix @@ -1,9 +1,17 @@ -{ ... }: { - services.printing = { - enable = true; - clientConf = '' - DigestOptions DenyMD5 - ServerName 192.168.1.2 - ''; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.print; +in { + options = { + module.print.enable = mkEnableOption "Add support for printers."; + }; + + config = mkIf cfg.enable { + services.printing = { + enable = true; + clientConf = '' + DigestOptions DenyMD5 + ServerName 192.168.1.2 + ''; + }; }; } diff --git a/module/RemoteBuild.nix b/module/RemoteBuild.nix index 2e1f27b..9191e7d 100644 --- a/module/RemoteBuild.nix +++ b/module/RemoteBuild.nix @@ -1,29 +1,79 @@ # Module that enables remote builds. This is a client configuration. -{ lib, secret, ... }: { - # NOTE: Requires host private key to be present in secret.ssh.builderKeys. - nix.buildMachines = [{ - hostName = "nixbuilder"; - protocol = "ssh-ng"; - systems = [ - "x86_64-linux" - "i686-linux" - "aarch64-linux" - ]; - maxJobs = 1; - speedFactor = 2; - mandatoryFeatures = [ ]; - supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; - }]; - nix.distributedBuilds = true; - nix.settings = let - substituters = [ "ssh-ng://nixbuilder" ]; - in { - substituters = lib.mkForce substituters; - trusted-substituters = substituters; - builders-use-substitutes = true; - max-jobs = 0; - trusted-public-keys = [ secret.ssh.builderKey ]; - # require-sigs = false; - # substitute = false; +{ pkgs, lib, config, secret, ... }: with lib; let + cfg = config.module.builder; + + serverKeyPath = "/root/.nixbuilder"; +in { + options = { + module.builder = { + server.enable = mkEnableOption "This is a builder server."; + client.enable = mkEnableOption "This is a builder client."; + }; }; + + config = mkMerge [ + (mkIf cfg.server.enable { + # Service that generates new key on boot if not present. + # Don't forget to add new key to secret.ssh.buildKeys. + systemd.services.generate-nix-cache-key = { + wantedBy = [ "multi-user.target" ]; + serviceConfig.Type = "oneshot"; + path = [ pkgs.nix ]; + script = '' + [[ -f "${serverKeyPath}/private-key" ]] && exit + mkdir ${serverKeyPath} || true + nix-store --generate-binary-cache-key "nixbuilder-1" "${serverKeyPath}/private-key" "${serverKeyPath}/public-key" + nix store sign --all -k "${serverKeyPath}/private-key" + ''; + }; + + # Add `nixbuilder` restricted user. + users.groups.nixbuilder = {}; + users.users.nixbuilder = { + openssh.authorizedKeys.keys = secret.ssh.buildKeys; + description = "Nix Remote Builder"; + isNormalUser = true; + createHome = lib.mkForce false; + uid = 1234; + home = "/"; + group = "nixbuilder"; + }; + + # Sign store automatically. + # Sign existing store with: nix store sign --all -k /path/to/secret-key-file + nix.settings = { + trusted-users = [ "nixbuilder" ]; + secret-key-files = [ "${serverKeyPath}/private-key" ]; + }; + }) + + (mkIf cfg.client.enable { + # NOTE: Requires host private key to be present in secret.ssh.builderKeys. + nix.buildMachines = [{ + hostName = "nixbuilder"; + protocol = "ssh-ng"; + systems = [ + "x86_64-linux" + "i686-linux" + "aarch64-linux" + ]; + maxJobs = 1; + speedFactor = 2; + mandatoryFeatures = [ ]; + supportedFeatures = [ "nixos-test" "benchmark" "big-parallel" "kvm" ]; + }]; + nix.distributedBuilds = true; + nix.settings = let + substituters = [ "ssh-ng://nixbuilder" ]; + in { + substituters = mkForce substituters; + trusted-substituters = substituters; + builders-use-substitutes = true; + max-jobs = 0; + trusted-public-keys = [ secret.ssh.builderKey ]; + # require-sigs = false; + # substitute = false; + }; + }) + ]; } diff --git a/module/RemoteBuilder.nix b/module/RemoteBuilder.nix deleted file mode 100644 index ea70ec7..0000000 --- a/module/RemoteBuilder.nix +++ /dev/null @@ -1,37 +0,0 @@ -# Module that enables remote builds. This is a server configuration. -{ pkgs, secret, lib, ... }: let - keyPath = "/root/.nixbuilder"; -in { - # Service that generates new key on boot if not present. - # Don't forget to add new key to secret.ssh.buildKeys. - systemd.services.generate-nix-cache-key = { - wantedBy = [ "multi-user.target" ]; - serviceConfig.Type = "oneshot"; - path = [ pkgs.nix ]; - script = '' - [[ -f "${keyPath}/private-key" ]] && exit - mkdir ${keyPath} || true - nix-store --generate-binary-cache-key "nixbuilder-1" "${keyPath}/private-key" "${keyPath}/public-key" - nix store sign --all -k "${keyPath}/private-key" - ''; - }; - - # Add `nixbuilder` restricted user. - users.groups.nixbuilder = {}; - users.users.nixbuilder = { - openssh.authorizedKeys.keys = secret.ssh.buildKeys; - description = "Nix Remote Builder"; - isNormalUser = true; - createHome = lib.mkForce false; - uid = 1234; - home = "/"; - group = "nixbuilder"; - }; - - # Sign store automatically. - # Sign existing store with: nix store sign --all -k /path/to/secret-key-file - nix.settings = { - trusted-users = [ "nixbuilder" ]; - secret-key-files = [ "${keyPath}/private-key" ]; - }; -} diff --git a/part/Setting.nix b/module/Setting.nix similarity index 84% rename from part/Setting.nix rename to module/Setting.nix index 59ce4dc..ac527eb 100644 --- a/part/Setting.nix +++ b/module/Setting.nix @@ -5,6 +5,8 @@ ,lib , ... }: { options.setting = with lib; { + # Ollama settings. + # I use the best light model by default. ollama = mkOption { default = { }; type = types.submodule { @@ -18,6 +20,7 @@ }; }; + # Default browser settings. browser = mkOption { default = { }; type = types.submodule { @@ -30,6 +33,7 @@ }; }; + # Terminal settings. terminal = mkOption { default = { }; type = types.submodule { @@ -42,16 +46,19 @@ }; }; + # Whether to use Dpi-aware setting in supported apps. dpiAware = mkOption { default = false; type = types.bool; }; + # The key used for system-related shortcuts. sysctrl = mkOption { default = "print"; type = types.str; }; + # Keyboard options. keyboard = mkOption { default = { }; type = types.submodule { @@ -68,6 +75,7 @@ }; }; + # Settings related to different refreshes, like top apps. refresh = mkOption { default = { }; type = types.submodule { @@ -80,6 +88,7 @@ }; }; + # Configure steps for different actions. step = mkOption { default = { }; type = types.submodule { @@ -100,6 +109,7 @@ }; }; + # Specify timeouts. timeout = mkOption { default = { }; type = types.submodule { diff --git a/module/StrongSwan.nix b/module/StrongSwan.nix index 085e239..0c6e947 100644 --- a/module/StrongSwan.nix +++ b/module/StrongSwan.nix @@ -1,21 +1,29 @@ -{ pkgs, ... }: { - environment.systemPackages = with pkgs; [ - networkmanager-l2tp - gnome.networkmanager-l2tp - # networkmanager_strongswan - # strongswan - # strongswanNM - ]; - networking.networkmanager.enableStrongSwan = true; - services.xl2tpd.enable = true; - services.strongswan = { - enable = true; - secrets = [ - "ipsec.d/ipsec.nm-l2tp.secrets" - ]; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.strongswan; +in { + options = { + module.strongswan.enable = mkEnableOption "StrongSwan Vpn support."; + }; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + networkmanager-l2tp + gnome.networkmanager-l2tp + # networkmanager_strongswan + # strongswan + # strongswanNM + ]; + networking.networkmanager.enableStrongSwan = true; + services.xl2tpd.enable = true; + services.strongswan = { + enable = true; + secrets = [ + "ipsec.d/ipsec.nm-l2tp.secrets" + ]; + }; + # NOTE: Try this if VPN ever breaks. + # systemd.tmpfiles.rules = [ + # "L /etc/ipsec.secrets - - - - /etc/ipsec.d/ipsec.nm-l2tp.secrets" + # ]; }; - # NOTE: Try this if VPN ever breaks. - # systemd.tmpfiles.rules = [ - # "L /etc/ipsec.secrets - - - - /etc/ipsec.d/ipsec.nm-l2tp.secrets" - # ]; } diff --git a/module/Style.nix b/module/Style.nix new file mode 100644 index 0000000..903495e --- /dev/null +++ b/module/Style.nix @@ -0,0 +1,91 @@ +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.style; +in { + options = let + mkTypeOption = default: type: mkOption { inherit default type; }; + mkStrOption = default: mkTypeOption default types.str; + mkIntOption = default: mkTypeOption default types.int; + mkFloatOption = default: mkTypeOption default types.float; + in { + module.style = { + color = { + bg = { + dark = mkStrOption config.lib.stylix.colors.base00; + light = mkStrOption config.lib.stylix.colors.base07; + regular = mkStrOption config.lib.stylix.colors.base01; + }; + fg = { + dark = mkStrOption config.lib.stylix.colors.base04; + light = mkStrOption config.lib.stylix.colors.base06; + regular = mkStrOption config.lib.stylix.colors.base05; + }; + accent = mkStrOption config.lib.stylix.colors.base0A; + heading = mkStrOption config.lib.stylix.colors.base0D; + hl = mkStrOption config.lib.stylix.colors.base03; + keyword = mkStrOption config.lib.stylix.colors.base0E; + link = mkStrOption config.lib.stylix.colors.base09; + misc = mkStrOption config.lib.stylix.colors.base0F; + negative = mkStrOption config.lib.stylix.colors.base08; + neutral = mkStrOption config.lib.stylix.colors.base0C; + positive = mkStrOption config.lib.stylix.colors.base0B; + selection = mkStrOption config.lib.stylix.colors.base02; + transparent = mkStrOption "ffffff00"; + + accent-b = mkStrOption config.lib.stylix.colors.base0A-rgb-b; + accent-g = mkStrOption config.lib.stylix.colors.base0A-rgb-g; + accent-r = mkStrOption config.lib.stylix.colors.base0A-rgb-r; + + negative-b = mkStrOption config.lib.stylix.colors.base08-rgb-b; + negative-g = mkStrOption config.lib.stylix.colors.base08-rgb-g; + negative-r = mkStrOption config.lib.stylix.colors.base08-rgb-r; + + neutral-b = mkStrOption config.lib.stylix.colors.base0C-rgb-b; + neutral-g = mkStrOption config.lib.stylix.colors.base0C-rgb-g; + neutral-r = mkStrOption config.lib.stylix.colors.base0C-rgb-r; + + positive-b = mkStrOption config.lib.stylix.colors.base0B-rgb-b; + positive-g = mkStrOption config.lib.stylix.colors.base0B-rgb-g; + positive-r = mkStrOption config.lib.stylix.colors.base0B-rgb-r; + + bg-b = mkStrOption config.lib.stylix.colors.base00-rgb-b; + bg-g = mkStrOption config.lib.stylix.colors.base00-rgb-g; + bg-r = mkStrOption config.lib.stylix.colors.base00-rgb-r; + + fg-b = mkStrOption config.lib.stylix.colors.base06-rgb-b; + fg-g = mkStrOption config.lib.stylix.colors.base06-rgb-g; + fg-r = mkStrOption config.lib.stylix.colors.base06-rgb-r; + + border = mkStrOption config.lib.stylix.colors.base01; + border-b = mkStrOption config.lib.stylix.colors.base01-rgb-b; + border-g = mkStrOption config.lib.stylix.colors.base01-rgb-g; + border-r = mkStrOption config.lib.stylix.colors.base01-rgb-r; + }; + + font = { + emoji.name = mkStrOption config.stylix.fonts.emoji.name; + monospace.name = mkStrOption config.stylix.fonts.monospace.name; + sansSerif.name = mkStrOption config.stylix.fonts.sansSerif.name; + serif.name = mkStrOption config.stylix.fonts.serif.name; + size = { + terminal = mkIntOption config.stylix.fonts.sizes.terminal; + popup = mkIntOption config.stylix.fonts.sizes.popups; + application = mkIntOption config.stylix.fonts.sizes.applications; + desktop = mkIntOption config.stylix.fonts.sizes.desktop; + }; + }; + + opacity = { + application = mkFloatOption config.stylix.opacity.applications; + desktop = mkFloatOption config.stylix.opacity.desktop; + popup = mkFloatOption config.stylix.opacity.popups; + terminal = mkFloatOption config.stylix.opacity.terminal; + hex = mkStrOption "D9"; + }; + + window = { + gap = mkIntOption 8; + border = mkIntOption 4; + }; + }; + }; +} diff --git a/module/Sway.nix b/module/Sway.nix deleted file mode 100644 index 209dfaa..0000000 --- a/module/Sway.nix +++ /dev/null @@ -1,43 +0,0 @@ -{ pkgs, lib, ... } @args: let - sway = import ./desktop/sway args; - config = pkgs.writeText "swayConfig" sway.config; - script = pkgs.writeShellScriptBin "swayscript" sway.script; -in { - imports = [ - ./desktop/App.nix - ./desktop/Bluetooth.nix - ./desktop/Brightness.nix - ./desktop/Dconf.nix - ./desktop/Portal.nix - ./desktop/Realtime.nix - ./desktop/Sound.nix - ./desktop/Waybar.nix - ./desktop/Wayland.nix - ]; - - services.gnome.gnome-keyring.enable = lib.mkForce false; - environment = { - systemPackages = with pkgs; [ - fuzzel # Application launcher. - grim slurp # Screenshot. - mako # Notification system. - networkmanagerapplet # Internet configuration. - pamixer pavucontrol pulseaudio # Audio. - playerctl # Multimedia controls. - script # My custom Sway shell scripts. - ]; - - variables.XDG_CURRENT_DESKTOP = "sway"; - }; - - programs.sway = { - enable = true; - wrapperFeatures = { - base = true; - gtk = true; - }; - extraOptions = [ - "--config=${config}" - ]; - }; -} diff --git a/module/Tablet.nix b/module/Tablet.nix index 96fad38..7940167 100644 --- a/module/Tablet.nix +++ b/module/Tablet.nix @@ -1,6 +1,14 @@ -{ pkgs, ... }: { - hardware.opentabletdriver.enable = true; - environment.systemPackages = with pkgs; [ - krita - ]; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.tablet; +in { + options = { + module.tablet.enable = mkEnableOption "Support for tables."; + }; + + config = mkIf cfg.enable { + hardware.opentabletdriver.enable = true; + environment.systemPackages = with pkgs; [ + krita + ]; + }; } diff --git a/module/VirtManager.nix b/module/VirtManager.nix index d4390fb..85c4ee9 100644 --- a/module/VirtManager.nix +++ b/module/VirtManager.nix @@ -1,11 +1,19 @@ -{ pkgs, ... }: { - virtualisation.libvirtd.enable = true; - programs.virt-manager.enable = true; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.virtmanager; +in { + options = { + module.virtmanager.enable = mkEnableOption "VM support."; + }; - # HACK: Fixes bug: https://www.reddit.com/r/NixOS/comments/1afbjiu/i_get_a_nonetype_error_when_trying_to_launch_a_vm/ - # May also need to run: `gsettings set org.gnome.desktop.interface cursor-theme "Adwaita"` - environment.systemPackages = with pkgs; [ - # glib - gnome3.adwaita-icon-theme # default gnome cursors, - ]; + config = mkIf cfg.enable { + virtualisation.libvirtd.enable = true; + programs.virt-manager.enable = true; + + # HACK: Fixes bug: https://www.reddit.com/r/NixOS/comments/1afbjiu/i_get_a_nonetype_error_when_trying_to_launch_a_vm/ + # May also need to run: `gsettings set org.gnome.desktop.interface cursor-theme "Adwaita"` + environment.systemPackages = with pkgs; [ + # glib + gnome3.adwaita-icon-theme # default gnome cursors, + ]; + }; } diff --git a/module/common/Apks.nix b/module/common/Apks.nix index 93215fa..d43f779 100644 --- a/module/common/Apks.nix +++ b/module/common/Apks.nix @@ -1,8 +1,17 @@ # I want to pull all the Apk files in their current state # so that I always have an access to clients that match # my service versions. -{ pkgs, ... } @args: let +{ pkgs, lib, config, ... } @args: with lib; let + cfg = config.module.common.apks; package = (pkgs.callPackage ./apks args); in { - environment.etc.apks.source = package; + options = { + module.common.apks = { + enable = mkEnableOption "Android Apps Apk" // { default = true; }; + }; + }; + + config = mkIf cfg.enable { + environment.etc.apks.source = package; + }; } diff --git a/module/common/AutoUpdateSigned.nix b/module/common/AutoUpdateSigned.nix index 1263489..afe1b96 100644 --- a/module/common/AutoUpdateSigned.nix +++ b/module/common/AutoUpdateSigned.nix @@ -2,41 +2,51 @@ # This is a systemd service that pulls updates every hour. # Unlike system.autoUpgrade, this script also verifies my git signature # to prevent unathorized changes to hosts. -{ const, pkgs, lib, secret, util, ... }: { - systemd.services.autoupdate = util.mkStaticSystemdService { - enable = true; - description = "Signed system auto-update."; - serviceConfig.Type = "oneshot"; - path = with pkgs; [ - bash - git - gnumake - nixos-rebuild - openssh - ]; - script = '' - pushd /tmp - rm -rf ./nixos - ${lib.getExe pkgs.git} clone --depth=1 --single-branch --branch=main ${const.url} ./nixos - pushd ./nixos - ${lib.getExe pkgs.git} verify-commit HEAD || { - echo "Verification failed." - exit 1 - }; - ${lib.getExe pkgs.gnumake} switch - ''; - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; +{ const, pkgs, lib, util, config, ... }: with lib; let + cfg = config.module.common.autoupdate; +in { + options = { + module.common.autoupdate = { + enable = mkEnableOption "System auto-updates." // { default = true; }; + }; }; - systemd.timers.autoupdate = { - enable = true; - timerConfig = { - OnCalendar = "hourly"; - Persistent = true; - Unit = "autoupdate.service"; - # RandomizedDelaySec = 60; + config = mkIf cfg.enable { + systemd.services.autoupdate = util.mkStaticSystemdService { + enable = true; + description = "Signed system auto-update."; + serviceConfig.Type = "oneshot"; + path = with pkgs; [ + bash + git + gnumake + nixos-rebuild + openssh + ]; + script = '' + pushd /tmp + rm -rf ./nixos + ${getExe pkgs.git} clone --depth=1 --single-branch --branch=main ${const.url} ./nixos + pushd ./nixos + ${getExe pkgs.git} verify-commit HEAD || { + echo "Verification failed." + exit 1 + }; + ${getExe pkgs.gnumake} switch + ''; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + }; + + systemd.timers.autoupdate = { + enable = true; + timerConfig = { + OnCalendar = "hourly"; + Persistent = true; + Unit = "autoupdate.service"; + # RandomizedDelaySec = 60; + }; + wantedBy = [ "timers.target" ]; }; - wantedBy = [ "timers.target" ]; }; } diff --git a/module/common/Bash.nix b/module/common/Bash.nix index 8d239d0..eb1d519 100644 --- a/module/common/Bash.nix +++ b/module/common/Bash.nix @@ -1,4 +1,4 @@ -{ lib, style, util, pkgs, ... } @args: let +{ lib, util, pkgs, ... } @args: let bash = import ./bash args; in { # Add my bash configuration to all *interactive* shells. diff --git a/module/common/Distrobox.nix b/module/common/Distrobox.nix index 906df39..7c38647 100644 --- a/module/common/Distrobox.nix +++ b/module/common/Distrobox.nix @@ -1,8 +1,16 @@ -{ pkgs, ... }: { - # Distrobox works best with Podman, so enable it here. - imports = [ ./Podman.nix ]; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.common.distrobox; +in { + options = { + module.common.distrobox = { + enable = mkEnableOption "Distrobox." // { default = true; }; + }; + }; - environment.systemPackages = with pkgs; [ - distrobox - ]; + config = mkIf cfg.enable { + # Distrobox works best with Podman, so enable it here. + module.podman.enable = true; + + environment.systemPackages = with pkgs; [ distrobox ]; + }; } diff --git a/module/common/Filesystem.nix b/module/common/Filesystem.nix index b5d63db..1131fe1 100644 --- a/module/common/Filesystem.nix +++ b/module/common/Filesystem.nix @@ -13,6 +13,7 @@ }; # /etc overlay. + # ISSUE: Should be fixed when you read this. Try it! # boot.initrd.systemd.enable = true; # systemd.sysusers.enable = true; # system.etc.overlay = { diff --git a/module/common/Kernel.nix b/module/common/Kernel.nix index bc3d325..47037dd 100644 --- a/module/common/Kernel.nix +++ b/module/common/Kernel.nix @@ -1,59 +1,76 @@ -{ pkgs, ... }: { - # Use latest kernel. - boot.kernelPackages = pkgs.linuxPackages_latest; - - boot.kernel.sysctl = { - # # Spoof protection. - # "net.ipv4.conf.default.rp_filter" = 1; - # "net.ipv4.conf.all.rp_filter" = 1; - - # # Packet forwarding. - # "net.ipv4.ip_forward" = 0; - # "net.ipv6.conf.all.forwarding" = 1; - - # # MITM protection. - # "net.ipv4.conf.all.accept_redirects" = 0; - # "net.ipv6.conf.all.accept_redirects" = 0; - - # # Do not send ICMP redirects (we are not a router). - # "net.ipv4.conf.all.send_redirects" = 0; - - # # Do not accept IP source route packets (we are not a router). - # "net.ipv4.conf.all.accept_source_route" = 0; - # "net.ipv6.conf.all.accept_source_route" = 0; - - # Allow sysrq. - "kernel.sysrq" = 1; - - # # Protect filesystem links. - # "fs.protected_hardlinks" = 0; - # "fs.protected_symlinks" = 0; - - # # Specify ttl. - # "net.ipv4.ip_default_ttl" = 65; - - # # Lynis config. - # "kernel.core_uses_pid" = 1; - # "kernel.kptr_restrict" = 2; - - # # IP hardening. - # "net.ipv4.conf.all.log_martians" = 1; - # "net.ipv4.conf.default.accept_redirects" = 0; - # "net.ipv4.conf.default.accept_source_route" = 0; - # "net.ipv4.conf.default.log_martians" = 0; - # "net.ipv4.tcp_timestamps" = 0; - # "net.ipv6.conf.default.accept_redirects" = 0; - - # Increase file watchers. - "fs.inotify.max_user_instances" = 9999999; - "fs.inotify.max_user_watches" = 9999999; - "fs.inotify.max_user_event" = 9999999; - # "fs.file-max" = 999999; - - # # Disable ipv6. - # "net.ipv6.conf.all.disable_ipv6" = 1; - # "net.ipv6.conf.default.disable_ipv6" = 1; - # "net.ipv6.conf.lo.disable_ipv6" = 1; - # "net.ipv6.conf.eth0.disable_ipv6" = 1; +{ pkgs, config, lib, ... }: with lib; let + cfg = config.module.common.kernel; +in { + options = { + module.common.kernel = { + latest = mkOption { + default = true; + type = types.bool; + }; + }; }; + + config = mkMerge [ + (mkIf cfg.latest { + # Use latest kernel. + boot.kernelPackages = pkgs.linuxPackages_latest; + }) + + { + boot.kernel.sysctl = { + # # Spoof protection. + # "net.ipv4.conf.default.rp_filter" = 1; + # "net.ipv4.conf.all.rp_filter" = 1; + + # # Packet forwarding. + # "net.ipv4.ip_forward" = 0; + # "net.ipv6.conf.all.forwarding" = 1; + + # # MITM protection. + # "net.ipv4.conf.all.accept_redirects" = 0; + # "net.ipv6.conf.all.accept_redirects" = 0; + + # # Do not send ICMP redirects (we are not a router). + # "net.ipv4.conf.all.send_redirects" = 0; + + # # Do not accept IP source route packets (we are not a router). + # "net.ipv4.conf.all.accept_source_route" = 0; + # "net.ipv6.conf.all.accept_source_route" = 0; + + # Allow sysrq. + "kernel.sysrq" = 1; + + # # Protect filesystem links. + # "fs.protected_hardlinks" = 0; + # "fs.protected_symlinks" = 0; + + # # Specify ttl. + # "net.ipv4.ip_default_ttl" = 65; + + # # Lynis config. + # "kernel.core_uses_pid" = 1; + # "kernel.kptr_restrict" = 2; + + # # IP hardening. + # "net.ipv4.conf.all.log_martians" = 1; + # "net.ipv4.conf.default.accept_redirects" = 0; + # "net.ipv4.conf.default.accept_source_route" = 0; + # "net.ipv4.conf.default.log_martians" = 0; + # "net.ipv4.tcp_timestamps" = 0; + # "net.ipv6.conf.default.accept_redirects" = 0; + + # Increase file watchers. + "fs.inotify.max_user_instances" = 9999999; + "fs.inotify.max_user_watches" = 9999999; + "fs.inotify.max_user_event" = 9999999; + # "fs.file-max" = 999999; + + # # Disable ipv6. + # "net.ipv6.conf.all.disable_ipv6" = 1; + # "net.ipv6.conf.default.disable_ipv6" = 1; + # "net.ipv6.conf.lo.disable_ipv6" = 1; + # "net.ipv6.conf.eth0.disable_ipv6" = 1; + }; + } + ]; } diff --git a/module/common/Keyd.nix b/module/common/Keyd.nix index a584dbd..830f488 100644 --- a/module/common/Keyd.nix +++ b/module/common/Keyd.nix @@ -1,88 +1,98 @@ -{ pkgs, config, ... }: { - environment.systemPackages = with pkgs; [ keyd ]; - - services.keyd = { - enable = true; - keyboards.default = { - ids = [ "*" ]; - settings = { - main = { - backspace = "delete"; # Delete key on backspace. - capslock = "overload(control, esc)"; # Ctrl/esc combo. - compose = "layer(layer_number)"; # Number input layer. - esc = "${config.setting.sysctrl}"; # System controls. - leftcontrol = "overload(layer_alternative, leftcontrol)"; # Alternative layer for home, end etc. - rightcontrol = "layer(layer_control)"; # Media and other controls. - rightshift = "backspace"; # Backspace. - }; - - # Alternative navigation. - layer_alternative = { - w = "pageup"; - a = "home"; - s = "pagedown"; - d = "end"; - x = "cut"; - c = "copy"; - v = "paste"; - h = "left"; - j = "down"; - k = "up"; - l = "right"; - esc = "esc"; - rightcontrol = "leftcontrol"; - capslock = "capslock"; - # space = "macro2(1, 100, macro(space))"; # NOTE: Possible bhop example. Use in per-application, not here. - }; - - # Media controls. - layer_control = { - space = "playpause"; - a = "back"; - c = "ejectcd"; - d = "forward"; - e = "nextsong"; - q = "previoussong"; - s = "volumedown"; - w = "volumeup"; - x = "stopcd"; - z = "mute"; - }; - - # Number inputs. - layer_number = { - q = "1"; - w = "2"; - e = "3"; - a = "4"; - s = "5"; - d = "6"; - z = "7"; - x = "8"; - c = "9"; - space = "0"; - "1" = "f13"; - "2" = "f14"; - "3" = "f15"; - "4" = "f16"; - "5" = "f17"; - "6" = "f18"; - "7" = "f19"; - "8" = "f20"; - "9" = "f21"; - "0" = "f22"; - "-" = "f23"; - "=" = "f24"; - enter = "kpenter"; - }; - }; +{ pkgs, config, lib, ... }: with lib; let + cfg = config.module.common.keyd; +in { + options = { + module.common.keyd = { + enable = mkEnableOption "Keyboard remaps." // { default = true; }; }; }; - # HACK: Workaround for https://github.com/NixOS/nixpkgs/issues/290161 - users.groups.keyd = {}; - systemd.services.keyd.serviceConfig.CapabilityBoundingSet = [ "CAP_SETGID" ]; + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ keyd ]; - # Debug toggle just in case I need it again. - # systemd.services.keyd.environment.KEYD_DEBUG = "1"; + services.keyd = { + enable = true; + keyboards.default = { + ids = [ "*" ]; + settings = { + main = { + backspace = "delete"; # Delete key on backspace. + capslock = "overload(control, esc)"; # Ctrl/esc combo. + compose = "layer(layer_number)"; # Number input layer. + esc = "${config.setting.sysctrl}"; # System controls. + leftcontrol = "overload(layer_alternative, leftcontrol)"; # Alternative layer for home, end etc. + rightcontrol = "layer(layer_control)"; # Media and other controls. + rightshift = "backspace"; # Backspace. + }; + + # Alternative navigation. + layer_alternative = { + w = "pageup"; + a = "home"; + s = "pagedown"; + d = "end"; + x = "cut"; + c = "copy"; + v = "paste"; + h = "left"; + j = "down"; + k = "up"; + l = "right"; + esc = "esc"; + rightcontrol = "leftcontrol"; + capslock = "capslock"; + # space = "macro2(1, 100, macro(space))"; # NOTE: Possible bhop example. Use in per-application, not here. + }; + + # Media controls. + layer_control = { + space = "playpause"; + a = "back"; + c = "ejectcd"; + d = "forward"; + e = "nextsong"; + q = "previoussong"; + s = "volumedown"; + w = "volumeup"; + x = "stopcd"; + z = "mute"; + }; + + # Number inputs. + layer_number = { + q = "1"; + w = "2"; + e = "3"; + a = "4"; + s = "5"; + d = "6"; + z = "7"; + x = "8"; + c = "9"; + space = "0"; + "1" = "f13"; + "2" = "f14"; + "3" = "f15"; + "4" = "f16"; + "5" = "f17"; + "6" = "f18"; + "7" = "f19"; + "8" = "f20"; + "9" = "f21"; + "0" = "f22"; + "-" = "f23"; + "=" = "f24"; + enter = "kpenter"; + }; + }; + }; + }; + + # HACK: Workaround for https://github.com/NixOS/nixpkgs/issues/290161 + users.groups.keyd = {}; + systemd.services.keyd.serviceConfig.CapabilityBoundingSet = [ "CAP_SETGID" ]; + + # Debug toggle just in case I need it again. + # systemd.services.keyd.environment.KEYD_DEBUG = "1"; + }; } diff --git a/module/common/Network.nix b/module/common/Network.nix index 2f4e371..ed42fca 100644 --- a/module/common/Network.nix +++ b/module/common/Network.nix @@ -1,4 +1,6 @@ { lib, ... }: { - networking.useDHCP = lib.mkDefault true; - networking.networkmanager.enable = true; + networking = { + useDHCP = lib.mkDefault true; + networkmanager.enable = true; + }; } diff --git a/module/common/Package.nix b/module/common/Package.nix index 40652a0..3bb71f2 100644 --- a/module/common/Package.nix +++ b/module/common/Package.nix @@ -50,10 +50,14 @@ ]; # Special packages. - programs.adb.enable = true; - services.udisks2.enable = true; - programs.java = { - enable = true; - package = pkgs.corretto21; + programs = { + adb.enable = true; + java = { + enable = true; + package = pkgs.corretto21; + }; + }; + services = { + udisks2.enable = true; }; } diff --git a/module/common/Podman.nix b/module/common/Podman.nix deleted file mode 100644 index 4f92f0d..0000000 --- a/module/common/Podman.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ ... }: { - virtualisation = { - podman = { - enable = true; - - # Free the 53 port ffs. - defaultNetwork.settings.dns_enabled = false; - - # Do not interfere with Docker so we can have both installed at the same time. - # Podman can't replace Docker anyway. - dockerCompat = false; - }; - }; -} diff --git a/module/common/Stylix.nix b/module/common/Stylix.nix index 43a3147..9420bf3 100644 --- a/module/common/Stylix.nix +++ b/module/common/Stylix.nix @@ -1,12 +1,11 @@ -{ pkgs, config, wallpaper, ... }: let -in { +{ pkgs, config, ... }: { # Add a permanent link for the wallpaper to /etc/wallpaper. - environment.etc.wallpaper.source = wallpaper.path; + environment.etc.wallpaper.source = config.module.common.wallpaper.path; stylix = { # NOTE: Enable this later... # enable = true; - image = wallpaper.path; + image = config.module.common.wallpaper.path; autoEnable = true; polarity = "dark"; opacity = { @@ -41,7 +40,7 @@ in { name = "Noto Color Emoji"; }; }; - override = if wallpaper.forceContrastText then { + override = if config.module.common.wallpaper.forceContrastText then { base04 = "000000"; base05 = "ffffff"; base06 = "ffffff"; diff --git a/module/common/Tmux.nix b/module/common/Tmux.nix index ca7a14b..614e29d 100644 --- a/module/common/Tmux.nix +++ b/module/common/Tmux.nix @@ -1,4 +1,4 @@ -{ pkgs, style, key, util, ... } @args: let +{ pkgs, key, util, ... } @args: let tmux = import ./tmux args; in { programs.tmux = { diff --git a/module/common/Users.nix b/module/common/Users.nix index 6f7c8ea..fd731c0 100644 --- a/module/common/Users.nix +++ b/module/common/Users.nix @@ -1,6 +1,6 @@ { ... }: { # Default UMASK. - security.loginDefs.settings.UMASK = "077"; + # security.loginDefs.settings.UMASK = "077"; # Disallow users modification outside of this config. users.mutableUsers = false; diff --git a/module/common/Wallpaper.nix b/module/common/Wallpaper.nix new file mode 100644 index 0000000..46014e0 --- /dev/null +++ b/module/common/Wallpaper.nix @@ -0,0 +1,18 @@ +{ pkgs, lib, config, ... }: with lib; let + url = "https://i.imgur.com/0RldJsX.jpeg"; + sha256 = "sha256-hbbUz9+m/bLahDiflAoio6+4H0DHfxlbh92cWSjE4R4="; + forceContrastText = false; +in { + options = { + module.common.wallpaper = { + forceContrastText = mkOption { + default = forceContrastText; + type = types.bool; + }; + path = mkOption { + default = pkgs.fetchurl { inherit url sha256; }; + type = types.path; + }; + }; + }; +} diff --git a/module/common/bash/default.nix b/module/common/bash/default.nix index 288e184..66ed743 100644 --- a/module/common/bash/default.nix +++ b/module/common/bash/default.nix @@ -1,4 +1,4 @@ -{ style, util, pkgs, ... } @args: let +{ config, util, pkgs, ... } @args: let modules = util.catText (util.ls ./module) args; modulesFile = pkgs.writeText "bashModules" modules; in { diff --git a/module/common/bash/module/Ps1.nix b/module/common/bash/module/Ps1.nix index 5a0ebff..cc5928d 100644 --- a/module/common/bash/module/Ps1.nix +++ b/module/common/bash/module/Ps1.nix @@ -1,8 +1,8 @@ -{ style, ... }: let - accent = "${style.color.accent-r};${style.color.accent-g};${style.color.accent-b}"; - negative = "${style.color.negative-r};${style.color.negative-g};${style.color.negative-b}"; - neutral = "${style.color.neutral-r};${style.color.neutral-g};${style.color.neutral-b}"; - positive = "${style.color.positive-r};${style.color.positive-g};${style.color.positive-b}"; +{ config, ... }: let + accent = "${config.module.style.color.accent-r};${config.module.style.color.accent-g};${config.module.style.color.accent-b}"; + negative = "${config.module.style.color.negative-r};${config.module.style.color.negative-g};${config.module.style.color.negative-b}"; + neutral = "${config.module.style.color.neutral-r};${config.module.style.color.neutral-g};${config.module.style.color.neutral-b}"; + positive = "${config.module.style.color.positive-r};${config.module.style.color.positive-g};${config.module.style.color.positive-b}"; in { text = '' export PROMPT_COMMAND=(__prompt_command "''${PROMPT_COMMAND[@]}") diff --git a/module/common/nvim/module/plugin/lsp/Nix.nix b/module/common/nvim/module/plugin/lsp/Nix.nix index e3f511f..de8d4ce 100644 --- a/module/common/nvim/module/plugin/lsp/Nix.nix +++ b/module/common/nvim/module/plugin/lsp/Nix.nix @@ -2,6 +2,16 @@ text = '' local lspconfig = require("lspconfig") - lspconfig.nixd.setup {} + lspconfig.nixd.setup({ + settings = { + nixd = { + diagnostic = { + suppress = { + "sema-escaping-with" + }, + }, + }, + }, + }) ''; } diff --git a/module/common/tmux/default.nix b/module/common/tmux/default.nix index fb3d44b..8e4ef1f 100644 --- a/module/common/tmux/default.nix +++ b/module/common/tmux/default.nix @@ -1,3 +1,3 @@ -{ style, key, util, config, ... } @args: { +{ key, util, config, ... } @args: { config = util.catText (util.ls ./module) args; } diff --git a/module/common/tmux/module/Copy.nix b/module/common/tmux/module/Copy.nix index 6a682b1..fe5c5ed 100644 --- a/module/common/tmux/module/Copy.nix +++ b/module/common/tmux/module/Copy.nix @@ -1,8 +1,8 @@ -{ style, ... }: let +{ config, ... }: let mod = "M"; - fg = style.color.bg.dark; - selection = style.color.selection; + fg = config.module.style.color.bg.dark; + selection = config.module.style.color.selection; in { text = '' setw -g mode-keys vi diff --git a/module/common/tmux/module/Split.nix b/module/common/tmux/module/Split.nix index 2e8fa97..39495bd 100644 --- a/module/common/tmux/module/Split.nix +++ b/module/common/tmux/module/Split.nix @@ -1,8 +1,8 @@ -{ style, ... }: let +{ config, ... }: let mod = "M"; - accent = style.color.accent; - bg = style.color.bg.regular; + accent = config.module.style.color.accent; + bg = config.module.style.color.bg.regular; # fg = style.color.fg.light; stepVertical = 1; diff --git a/module/common/tmux/module/Status.nix b/module/common/tmux/module/Status.nix index 430926c..b8e1131 100644 --- a/module/common/tmux/module/Status.nix +++ b/module/common/tmux/module/Status.nix @@ -1,9 +1,9 @@ -{ style, ... }: let +{ config, ... }: let mod = "M"; - accent = style.color.accent; + accent = config.module.style.color.accent; # bg = style.color.bg.dark; - fg = style.color.fg.light; + fg = config.module.style.color.fg.light; in { text = '' bind-key -n ${mod}-f set-option -g status; diff --git a/module/desktop/App.nix b/module/desktop/App.nix index 1fc6b1c..28d7ec0 100644 --- a/module/desktop/App.nix +++ b/module/desktop/App.nix @@ -1,84 +1,154 @@ -{ pkgs, pkgsStable, pkgsMaster, config, ... } @args: let +{ pkgs, pkgsStable, pkgsMaster, config, lib, ... } @args: with lib; let + cfg = config.module.desktop.app; + mangohud = import ./mangohud args; + firefox = import ./firefox args; in { - imports = [ - ./firefox - ]; - - xdg.mime.defaultApplications = { - # Use `file -i file.txt` to find file mime type. - # Use `xdg-mime query default "text/plain"` to find default app. - "application/pdf" = "org.gnome.Evince.desktop"; - "application/vnd.openxmlformats-officedocument.*" = "onlyoffice-desktopeditors.desktop"; - "audio/*" = "mpv.desktop"; - "image/*" = "org.gnome.Loupe.desktop"; - "text/*" = "nvim.desktop"; - "video/*" = "mpv.desktop"; + options = { + module.desktop.app.enable = mkEnableOption "Desktop Apps."; }; - hardware.opengl = let - packages = with pkgs; [ - dxvk - gamescope - pkgs.mangohud - vkd3d - ]; - in { - extraPackages = packages; - extraPackages32 = packages; - }; + config = mkIf cfg.enable { xdg.mime.defaultApplications = { + # Use `file -i file.txt` to find file mime type. + # Use `xdg-mime query default "text/plain"` to find default app. + "application/pdf" = "org.gnome.Evince.desktop"; + "application/vnd.openxmlformats-officedocument.*" = "onlyoffice-desktopeditors.desktop"; + "audio/*" = "mpv.desktop"; + "image/*" = "org.gnome.Loupe.desktop"; + "text/*" = "nvim.desktop"; + "video/*" = "mpv.desktop"; + }; - environment = { - systemPackages = with pkgs; [ - anilibria-winmaclinux # Anime! - appimage-run # Tool to run .AppImage files in NixOS. - aseprite # Pixel Art draw app. WARNING: Always builds from source. - blanket # Sounds generator. - blender-hip # Blender with HiP support. - calibre # Book library manager. - evince # Document viewer. - foot # Terminal emulator. - gimp # Image manipulation program. - gnome.adwaita-icon-theme # GTK icons. - gnome.gnome-calculator # Calculator. - gnome.gnome-font-viewer # Font viewer. - gnome.nautilus # File manager. - jellyfin-media-player # Jellyfin client (self-hosted Netflix). - loupe # Image viewer. - obs-studio # Streaming/recording app. - onlyoffice-bin # Office documents app suite. - steam-run # Run native apps in Steam environment, like Minecraft. For Windows games use Bottles. - tor-browser # Privacy browser. + hardware.opengl = let + packages = with pkgs; [ + dxvk + gamescope + pkgs.mangohud + vkd3d + ]; + in { + extraPackages = packages; + extraPackages32 = packages; + }; - android-studio jetbrains.idea-community # JetBrans IDEs. - bottles dxvk gamescope pkgs.mangohud vkd3d wine64 # Gaming! - (mpv.override {scripts = [mpvScripts.mpris];}) # Media player. - ]; + environment = { + systemPackages = with pkgs; [ + anilibria-winmaclinux # Anime! + appimage-run # Tool to run .AppImage files in NixOS. + aseprite # Pixel Art draw app. WARNING: Always builds from source. + blanket # Sounds generator. + blender-hip # Blender with HiP support. + calibre # Book library manager. + evince # Document viewer. + foot # Terminal emulator. + gimp # Image manipulation program. + gnome.adwaita-icon-theme # GTK icons. + gnome.gnome-calculator # Calculator. + gnome.gnome-font-viewer # Font viewer. + gnome.nautilus # File manager. + jellyfin-media-player # Jellyfin client (self-hosted Netflix). + loupe # Image viewer. + obs-studio # Streaming/recording app. + onlyoffice-bin # Office documents app suite. + steam-run # Run native apps in Steam environment, like Minecraft. For Windows games use Bottles. + tor-browser # Privacy browser. - variables = { - # MangoHud. - MANGOHUD = "1"; - MANGOHUD_CONFIGFILE = pkgs.writeText "mangoConfig" mangohud.config; - MANGOHUD_PRESETSFILE = pkgs.writeText "mangoPreset" mangohud.presets; + android-studio jetbrains.idea-community # JetBrans IDEs. + bottles dxvk gamescope pkgs.mangohud vkd3d wine64 # Gaming! + (mpv.override {scripts = [mpvScripts.mpris];}) # Media player. + ]; - # Proton. - WINEFSYNC = "1"; + variables = { + # MangoHud. + MANGOHUD = "1"; + MANGOHUD_CONFIGFILE = pkgs.writeText "MangoHudConfig" mangohud.config; + MANGOHUD_PRESETSFILE = pkgs.writeText "MangoHudPreset" mangohud.presets; - # GTK apps compat. - GTK_CSD = 0; + # Proton. + WINEFSYNC = "1"; - # Terminal settings. - TERM = "xterm-256color"; - TERMINAL = config.setting.terminal.bin; + # GTK apps compat. + GTK_CSD = 0; + + # Terminal settings. + TERM = "xterm-256color"; + TERMINAL = config.setting.terminal.bin; + + # Disable Firefox profile switching on rebuild. + MOZ_LEGACY_PROFILES = "1"; + }; + }; + + # File manager file previews. + services.gnome.sushi.enable = true; + + # File manager network features. + services.gvfs.enable = true; + + # Special packages. + programs.steam.enable = true; + + programs.firefox = let + mkExtension = install_url: { + inherit install_url; + installation_mode = "force_installed"; + }; + + mkBookmark = name: url: { inherit name url; }; + in { + enable = true; + package = pkgs.firefox-esr; + languagePacks = [ "en-US" "ru" ]; + autoConfig = firefox.config; + policies = { + ManagedBookmarks = [ + { toplevel_name = "Pin"; } + (mkBookmark "Dashboard" "https://home.voronind.com") + (mkBookmark "Music" "https://music.yandex.ru") + (mkBookmark "Telegram" "https://web.telegram.org/a") + (mkBookmark "Discord" "https://discord.com") + (mkBookmark "WorkMail" "https://mail.fsight.ru") + (mkBookmark "Git" "https://git.voronind.com") + (mkBookmark "WorkGit" "https://git.fmp.fsight.world") + (mkBookmark "WorkBoard" "https://support.fsight.ru") + (mkBookmark "Hass" "https://iot.voronind.com") + (mkBookmark "Cloud" "https://cloud.voronind.com") + ]; + ExtensionUpdate = true; + ExtensionSettings = { + # Block extension installation outside of this config. + "*" = { + install_sources = [ "*" ]; + installation_mode = "blocked"; + }; + "addon@darkreader.org" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi"; + "cliget@zaidabdulla.com" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/cliget/latest.xpi"; + "uBlock0@raymondhill.net" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; + "{446900e4-71c2-419f-a6a7-df9c091e268b}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi"; + "{d7742d87-e61d-4b78-b8a1-b469842139fa}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/vimium-ff/latest.xpi"; + "{e7625f06-e252-479d-ac7a-db68aeaff2cb}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/togglefonts/latest.xpi"; + "{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/user-agent-string-switcher/latest.xpi"; + # NOTE: This extension is helpful to find the required parameters for this config. + # Or find them yourself inside the `about:support`. + # "queryamoid@kaply.com" = mkExtension "https://github.com/mkaply/queryamoid/releases/download/v0.1/query_amo_addon_id-0.1-fx.xpi"; + }; + # NOTE: `firefox-esr` edition is required to change default search engine. + SearchEngines = { + Default = "Searx"; + Add = [ + { + Alias = "s"; + Description = "Searx Search"; + IconURL = "https://search.voronind.com/favicon.ico"; + Method = "POST"; + Name = "Searx"; + PostData = "q={searchTerms}"; + # SuggestURLTemplate = "https://search.voronind.com/autocomplete?q={searchTerms}"; + URLTemplate = "https://search.voronind.com/search?q=%{searchTerms}"; + } + ]; + }; + }; }; }; - - # File manager file previews. - services.gnome.sushi.enable = true; - - # File manager network features. - services.gvfs.enable = true; - - # Special packages. - programs.steam.enable = true; } diff --git a/module/desktop/Bluetooth.nix b/module/desktop/Bluetooth.nix index f5e662e..2d42897 100644 --- a/module/desktop/Bluetooth.nix +++ b/module/desktop/Bluetooth.nix @@ -1,5 +1,15 @@ -{ ... }: { - hardware.bluetooth.enable = true; - hardware.bluetooth.powerOnBoot = true; - services.blueman.enable = true; +{ lib, config, ... }: with lib; let + cfg = config.module.desktop.bluetooth; +in { + options = { + module.desktop.bluetooth.enable = mkEnableOption "Bluetooth."; + }; + + config = mkIf cfg.enable { + hardware.bluetooth = { + enable = true; + powerOnBoot = true; + }; + services.blueman.enable = true; + }; } diff --git a/module/desktop/Brightness.nix b/module/desktop/Brightness.nix index 64e91e6..6903ec3 100644 --- a/module/desktop/Brightness.nix +++ b/module/desktop/Brightness.nix @@ -1,3 +1,11 @@ -{ ... }: { - programs.light.enable = true; +{ lib, config, ... }: with lib; let + cfg = config.module.desktop.brightness; +in { + options = { + module.desktop.brightness.enable = mkEnableOption "Brightness."; + }; + + config = mkIf cfg.enable { + programs.light.enable = true; + }; } diff --git a/module/desktop/Dconf.nix b/module/desktop/Dconf.nix index e310820..0d8b814 100644 --- a/module/desktop/Dconf.nix +++ b/module/desktop/Dconf.nix @@ -1,10 +1,17 @@ -{ util, ... } @args: let +{ util, lib, config, ... } @args: with lib; let + cfg = config.module.desktop.dconf; settings = util.catSet (util.ls ./dconf) args; in { - # Gnome DE and GTK apps configuration. - programs.dconf.enable = true; - programs.dconf.profiles.user = { - enableUserDb = true; # Delete `~/.config/dconf/user` to reset user settings. - databases = [{ inherit settings; }]; + options = { + module.desktop.dconf.enable = mkEnableOption "Dconf."; + }; + + config = mkIf cfg.enable { + # Gnome DE and GTK apps configuration. + programs.dconf.enable = true; + programs.dconf.profiles.user = { + enableUserDb = true; # Delete `~/.config/dconf/user` to reset user settings. + databases = [{ inherit settings; }]; + }; }; } diff --git a/module/desktop/DisplayManager.nix b/module/desktop/DisplayManager.nix index c64e720..4c88755 100644 --- a/module/desktop/DisplayManager.nix +++ b/module/desktop/DisplayManager.nix @@ -1,7 +1,15 @@ -{ config, ... }: { - services.xserver.enable = true; - services.xserver.xkb = { - layout = config.setting.keyboard.layouts; - options = config.setting.keyboard.options; +{ config, lib, ... }: with lib; let + cfg = config.module.desktop.dm; +in { + options = { + module.desktop.dm.enable = mkEnableOption "Display Manager."; + }; + + config = mkIf cfg.enable { + services.xserver.enable = true; + services.xserver.xkb = { + layout = config.setting.keyboard.layouts; + options = config.setting.keyboard.options; + }; }; } diff --git a/module/desktop/Gnome.nix b/module/desktop/Gnome.nix new file mode 100644 index 0000000..9a5a41d --- /dev/null +++ b/module/desktop/Gnome.nix @@ -0,0 +1,56 @@ +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.desktop.gnome; +in { + options = { + module.desktop.gnome.enable = mkEnableOption "Enable GnOmE"; + }; + + config = mkIf cfg.enable { + module.desktop = { + app.enable = true; + dconf.enable = true; + dm.enable = true; + sound.enable = true; + wayland.enable = true; + }; + + services.xserver.displayManager.gdm.enable = true; + services.xserver.desktopManager.gnome.enable = true; + + environment.systemPackages = with pkgs; [ + gnome.gnome-tweaks # Gnome "hidden" settings. + openssl # It was needed for something, can't remember. + ]; + + # Disable some Gnome apps. + services.gnome.gnome-keyring.enable = mkForce false; + environment.gnome.excludePackages = with pkgs.gnome; [ + # baobab # Disk usage analyzer. + # cheese # Photo booth. + # epiphany # Web browser. + # simple-scan # Document scanner. + # totem # Video player. + # yelp # Help viewer. + # file-roller # Archive manager. + # geary # Email client. + # seahorse # Password manager. + + # gnome-calculator + # gnome-calendar + # gnome-characters + # gnome-clocks + # gnome-contacts + # gnome-font-viewer + # gnome-keyring + # gnome-logs + # gnome-maps + # gnome-music + # gnome-shell-extensions + gnome-software + # gnome-system-monitor + # gnome-weather + # gnome-disk-utility + # pkgs.gnome-text-editor + ]; + }; +} diff --git a/module/desktop/Polkit.nix b/module/desktop/Polkit.nix index b07cd3d..1aca08b 100644 --- a/module/desktop/Polkit.nix +++ b/module/desktop/Polkit.nix @@ -1,19 +1,27 @@ # Polkit agent is used by apps to ask for Root password with a popup. -{ pkgs, lib, ... }: { - security.polkit.enable = true; - systemd = { - packages = with pkgs; [ - polkit-kde-agent - ]; - user = { - services.plasma-polkit-agent = { - serviceConfig = { - Restart = "always"; - RestartSec = 2; - Slice = "session.slice"; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.desktop.polkit; +in { + options = { + module.desktop.polkit.enable = mkEnableOption "Polkit."; + }; + + config = mkIf cfg.enable { + security.polkit.enable = true; + systemd = { + packages = with pkgs; [ + polkit-kde-agent + ]; + user = { + services.plasma-polkit-agent = { + serviceConfig = { + Restart = "always"; + RestartSec = 2; + Slice = "session.slice"; + }; + environment.PATH = mkForce null; + wantedBy = [ "gui-session.target" ]; }; - environment.PATH = lib.mkForce null; - wantedBy = [ "gui-session.target" ]; }; }; }; diff --git a/module/desktop/Portal.nix b/module/desktop/Portal.nix index 484c471..836d19d 100644 --- a/module/desktop/Portal.nix +++ b/module/desktop/Portal.nix @@ -1,21 +1,27 @@ # Portals are needed for Wayland apps to select files, screen shares etc. -{ pkgs, ... }: { - xdg.portal = { - enable = true; - extraPortals = with pkgs; [ - xdg-desktop-portal-gtk - ]; - config = { - common = { - default = [ - "gtk" - "wlr" - ]; - }; - }; - wlr = { +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.desktop.portal; +in { + options = { + module.desktop.portal.enable = mkEnableOption "Portals."; + }; + + config = mkIf cfg.enable { + xdg.portal = { enable = true; + extraPortals = with pkgs; [ + xdg-desktop-portal-gtk + ]; + config = { + common = { + default = [ + "gtk" + "wlr" + ]; + }; + }; + wlr.enable = true; + xdgOpenUsePortal = false; }; - xdgOpenUsePortal = false; }; } diff --git a/module/desktop/Realtime.nix b/module/desktop/Realtime.nix index 02841fa..084d433 100644 --- a/module/desktop/Realtime.nix +++ b/module/desktop/Realtime.nix @@ -1,6 +1,14 @@ # Improve DE performance. -{ ... }: { - security.pam.loginLimits = [ - { domain = "@users"; item = "rtprio"; type = "-"; value = 1; } - ]; +{ lib, config, ... }: with lib; let + cfg = config.module.desktop.realtime; +in { + options = { + module.desktop.realtime.enable = mkEnableOption "Realtime access."; + }; + + config = mkIf cfg.enable { + security.pam.loginLimits = [ + { domain = "@users"; item = "rtprio"; type = "-"; value = 1; } + ]; + }; } diff --git a/module/desktop/Sound.nix b/module/desktop/Sound.nix index 4727883..d0805b0 100644 --- a/module/desktop/Sound.nix +++ b/module/desktop/Sound.nix @@ -1,11 +1,19 @@ -{ ... }: { - sound.enable = true; - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; +{ lib, config, ... }: with lib; let + cfg = config.module.desktop.sound; +in { + options = { + module.desktop.sound.enable = mkEnableOption "Sound."; + }; + + config = mkIf cfg.enable { + sound.enable = true; + hardware.pulseaudio.enable = false; + security.rtkit.enable = true; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; }; } diff --git a/module/desktop/Sway.nix b/module/desktop/Sway.nix new file mode 100644 index 0000000..dd40a37 --- /dev/null +++ b/module/desktop/Sway.nix @@ -0,0 +1,53 @@ +{ pkgs, lib, config, ... } @args: with lib; let + cfg = config.module.desktop.sway; + + sway = import ./sway args; + swayconfig = pkgs.writeText "SwayConfig" sway.config; + swayscript = pkgs.writeShellScriptBin "swayscript" sway.script; +in { + options = { + module.desktop.sway = { + enable = mkEnableOption "Use Sway WM."; + }; + }; + + config = mkIf cfg.enable { + module.desktop = { + app.enable = true; + bluetooth.enable = true; + brightness.enable = true; + dconf.enable = true; + portal.enable = true; + realtime.enable = true; + sound.enable = true; + waybar.enable = true; + wayland.enable = true; + }; + + services.gnome.gnome-keyring.enable = mkForce false; + environment = { + systemPackages = with pkgs; [ + fuzzel # Application launcher. + grim slurp # Screenshot. + mako # Notification system. + networkmanagerapplet # Internet configuration. + pamixer pavucontrol pulseaudio # Audio. + playerctl # Multimedia controls. + swayscript # My custom Sway shell scripts. + ]; + + variables.XDG_CURRENT_DESKTOP = "sway"; + }; + + programs.sway = { + enable = true; + wrapperFeatures = { + base = true; + gtk = true; + }; + extraOptions = [ + "--config=${swayconfig}" + ]; + }; + }; +} diff --git a/module/desktop/Systemd.nix b/module/desktop/Systemd.nix index 182b9e0..7ae4b0a 100644 --- a/module/desktop/Systemd.nix +++ b/module/desktop/Systemd.nix @@ -1,10 +1,18 @@ -{ ... }: { - # Systemd custom target for Sway. - systemd.user.targets.gui-session = { - after = [ "graphical-session-pre.target" ]; - bindsTo = [ "graphical-session.target" ]; - description = "GUI session."; - documentation = [ "man:systemd.special(7)" ]; - wants = [ "graphical-session-pre.target" ]; +{ lib, config, ... }: with lib; let + cfg = config.module.desktop.systemd; +in { + options = { + module.desktop.systemd.enable = mkEnableOption "Systemd Desktop config."; + }; + + config = mkIf cfg.enable { + # Systemd custom target for Sway. + systemd.user.targets.gui-session = { + after = [ "graphical-session-pre.target" ]; + bindsTo = [ "graphical-session.target" ]; + description = "GUI session."; + documentation = [ "man:systemd.special(7)" ]; + wants = [ "graphical-session-pre.target" ]; + }; }; } diff --git a/module/desktop/Waybar.nix b/module/desktop/Waybar.nix index e7785e5..90cef25 100644 --- a/module/desktop/Waybar.nix +++ b/module/desktop/Waybar.nix @@ -1,10 +1,17 @@ -{ pkgs, ... } @args: let +{ pkgs, lib, config, ... } @args: with lib; let + cfg = config.module.desktop.waybar; waybar = import ./waybar args; in { - programs.waybar.enable = true; + options = { + module.desktop.waybar.enable = mkEnableOption "Waybar."; + }; - environment.variables = { - WAYBAR_CONFIG = waybar.config; - WAYBAR_STYLE = waybar.style; + config = mkIf cfg.enable { + programs.waybar.enable = true; + + environment.variables = { + WAYBAR_CONFIG = waybar.config; + WAYBAR_STYLE = waybar.style; + }; }; } diff --git a/module/desktop/Wayland.nix b/module/desktop/Wayland.nix index 1813674..54920fe 100644 --- a/module/desktop/Wayland.nix +++ b/module/desktop/Wayland.nix @@ -1,20 +1,28 @@ -{ pkgs, ... }: { - environment = { - systemPackages = with pkgs; [ - wl-clipboard # CLI clipboard support. - ]; +{ pkgs, lib, config, ... }: with lib; let + cfg = config.module.desktop.wayland; +in { + options = { + module.desktop.wayland.enable = mkEnableOption "Wayland."; + }; - variables = { - # Compatibility variables. - ECORE_EVAS_ENGINE = "wayland_egl"; - ELM_ENGINE = "wayland_egl"; - GDK_BACKEND = "wayland"; - MOZ_ENABLE_WAYLAND = "1"; - QT_QPA_PLATFORM = "wayland-egl;wayland;xcb"; - QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; - SAL_USE_VCLPLUGIN = "gtk3"; - SDL_VIDEODRIVER = "wayland"; - _JAVA_AWT_WM_NONREPARENTING = "1"; + config = { + environment = { + systemPackages = with pkgs; [ + wl-clipboard # CLI clipboard support. + ]; + + variables = { + # Compatibility variables. + ECORE_EVAS_ENGINE = "wayland_egl"; + ELM_ENGINE = "wayland_egl"; + GDK_BACKEND = "wayland"; + MOZ_ENABLE_WAYLAND = "1"; + QT_QPA_PLATFORM = "wayland-egl;wayland;xcb"; + QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; + SAL_USE_VCLPLUGIN = "gtk3"; + SDL_VIDEODRIVER = "wayland"; + _JAVA_AWT_WM_NONREPARENTING = "1"; + }; }; }; } diff --git a/module/desktop/firefox/Config.nix b/module/desktop/firefox/Config.nix deleted file mode 100644 index 0939ac9..0000000 --- a/module/desktop/firefox/Config.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ util, style, ... }: { - text = util.trimTabs '' - // Bookmarks. - lockPref("browser.microsummary.enabled", true); - lockPref("browser.places.importBookmarksHTML", true); - lockPref("browser.toolbars.bookmarks.visibility", "never"); - - // Fonts. - pref("browser.display.use_document_fonts", 0); - lockPref("font.minimum-size.x-cyrillic", ${toString style.font.size.application}); - lockPref("font.minimum-size.x-unicode", ${toString style.font.size.application}); - lockPref("font.minimum-size.x-western", ${toString style.font.size.application}); - lockPref("font.name.monospace.x-cyrillic", "${style.font.monospace.name}"); - lockPref("font.name.monospace.x-unicode", "${style.font.monospace.name}"); - lockPref("font.name.monospace.x-western", "${style.font.monospace.name}"); - lockPref("font.name.sans-serif.x-cyrillic", "${style.font.sansSerif.name}"); - lockPref("font.name.sans-serif.x-unicode", "${style.font.sansSerif.name}"); - lockPref("font.name.sans-serif.x-western", "${style.font.sansSerif.name}"); - lockPref("font.name.serif.x-cyrillic", "${style.font.serif.name}"); - lockPref("font.name.serif.x-unicode", "${style.font.serif.name}"); - lockPref("font.name.serif.x-western", "${style.font.serif.name}"); - - // Animations. - lockPref("browser.fullscreen.animateUp", 0); - lockPref("browser.fullscreen.autohide", true); - - // Homepage. - lockPref("browser.newtabpage.enabled", false); - lockPref("browser.startup.homepage", "https://home.voronind.com/"); - lockPref("browser.startup.page", 3); - - // Passwords. - lockPref("signon.prefillForms", false); - lockPref("signon.rememberSignons", false); - - // Formats. - lockPref("image.jxl.enabled", true); - - // User agent. - // pref("general.useragent.override", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"); - ''; -} diff --git a/module/desktop/firefox/default.nix b/module/desktop/firefox/default.nix index afe17be..b5a0d6d 100644 --- a/module/desktop/firefox/default.nix +++ b/module/desktop/firefox/default.nix @@ -1,69 +1,42 @@ -{ pkgs, util, ... } @args: let - config = import ./Config.nix args; +{ util, config, ... }: { + config = util.trimTabs '' + // Bookmarks. + lockPref("browser.microsummary.enabled", true); + lockPref("browser.places.importBookmarksHTML", true); + lockPref("browser.toolbars.bookmarks.visibility", "never"); - mkExtension = url: { - installation_mode = "force_installed"; - install_url = url; - }; + // Fonts. + pref("browser.display.use_document_fonts", 0); + lockPref("font.minimum-size.x-cyrillic", ${toString config.module.style.font.size.application}); + lockPref("font.minimum-size.x-unicode", ${toString config.module.style.font.size.application}); + lockPref("font.minimum-size.x-western", ${toString config.module.style.font.size.application}); + lockPref("font.name.monospace.x-cyrillic", "${config.module.style.font.monospace.name}"); + lockPref("font.name.monospace.x-unicode", "${config.module.style.font.monospace.name}"); + lockPref("font.name.monospace.x-western", "${config.module.style.font.monospace.name}"); + lockPref("font.name.sans-serif.x-cyrillic", "${config.module.style.font.sansSerif.name}"); + lockPref("font.name.sans-serif.x-unicode", "${config.module.style.font.sansSerif.name}"); + lockPref("font.name.sans-serif.x-western", "${config.module.style.font.sansSerif.name}"); + lockPref("font.name.serif.x-cyrillic", "${config.module.style.font.serif.name}"); + lockPref("font.name.serif.x-unicode", "${config.module.style.font.serif.name}"); + lockPref("font.name.serif.x-western", "${config.module.style.font.serif.name}"); - mkBookmark = name: url: { inherit name url; }; -in { - # Disable profile switching on rebuild. - environment.variables.MOZ_LEGACY_PROFILES = "1"; + // Animations. + lockPref("browser.fullscreen.animateUp", 0); + lockPref("browser.fullscreen.autohide", true); - programs.firefox = { - enable = true; - package = pkgs.firefox-esr; - languagePacks = [ "en-US" "ru" ]; - autoConfig = config.text; - policies = { - ManagedBookmarks = [ - { toplevel_name = "Pin"; } - (mkBookmark "Dashboard" "https://home.voronind.com") - (mkBookmark "Music" "https://music.yandex.ru") - (mkBookmark "Telegram" "https://web.telegram.org/a") - (mkBookmark "Discord" "https://discord.com") - (mkBookmark "WorkMail" "https://mail.fsight.ru") - (mkBookmark "Git" "https://git.voronind.com") - (mkBookmark "WorkGit" "https://git.fmp.fsight.world") - (mkBookmark "WorkBoard" "https://support.fsight.ru") - (mkBookmark "Hass" "https://iot.voronind.com") - (mkBookmark "Cloud" "https://cloud.voronind.com") - ]; - ExtensionUpdate = true; - ExtensionSettings = { - # Block extension installation outside of this config. - "*" = { - install_sources = [ "*" ]; - installation_mode = "blocked"; - }; - "addon@darkreader.org" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/darkreader/latest.xpi"; - "cliget@zaidabdulla.com" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/cliget/latest.xpi"; - "uBlock0@raymondhill.net" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; - "{446900e4-71c2-419f-a6a7-df9c091e268b}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/bitwarden-password-manager/latest.xpi"; - "{d7742d87-e61d-4b78-b8a1-b469842139fa}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/vimium-ff/latest.xpi"; - "{e7625f06-e252-479d-ac7a-db68aeaff2cb}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/togglefonts/latest.xpi"; - "{a6c4a591-f1b2-4f03-b3ff-767e5bedf4e7}" = mkExtension "https://addons.mozilla.org/firefox/downloads/latest/user-agent-string-switcher/latest.xpi"; - # NOTE: This extension is helpful to find the required parameters for this config. - # Or find them yourself inside the `about:support`. - # "queryamoid@kaply.com" = mkExtension "https://github.com/mkaply/queryamoid/releases/download/v0.1/query_amo_addon_id-0.1-fx.xpi"; - }; - # NOTE: `firefox-esr` edition is required to change default search engine. - SearchEngines = { - Default = "Searx"; - Add = [ - { - Alias = "s"; - Description = "Searx Search"; - IconURL = "https://search.voronind.com/favicon.ico"; - Method = "POST"; - Name = "Searx"; - PostData = "q={searchTerms}"; - # SuggestURLTemplate = "https://search.voronind.com/autocomplete?q={searchTerms}"; - URLTemplate = "https://search.voronind.com/search?q=%{searchTerms}"; - } - ]; - }; - }; - }; + // Homepage. + lockPref("browser.newtabpage.enabled", false); + lockPref("browser.startup.homepage", "https://home.voronind.com/"); + lockPref("browser.startup.page", 3); + + // Passwords. + lockPref("signon.prefillForms", false); + lockPref("signon.rememberSignons", false); + + // Formats. + lockPref("image.jxl.enabled", true); + + // User agent. + // pref("general.useragent.override", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36"); + ''; } diff --git a/module/desktop/sway/default.nix b/module/desktop/sway/default.nix index 17697af..4ed03e1 100644 --- a/module/desktop/sway/default.nix +++ b/module/desktop/sway/default.nix @@ -1,4 +1,4 @@ -{ pkgs, wallpaper, style, util, config, ... } @args: let +{ pkgs, util, config, ... } @args: let # Order is required for Sway configuration. swayRc = util.catText [ ./module/Style.nix diff --git a/module/desktop/sway/module/Launcher.nix b/module/desktop/sway/module/Launcher.nix index 8baa16e..1a9f668 100644 --- a/module/desktop/sway/module/Launcher.nix +++ b/module/desktop/sway/module/Launcher.nix @@ -1,10 +1,10 @@ -{ style, ... }: let - fontName = style.font.serif.name; - fontSize = toString style.font.size.desktop; +{ config, ... }: let + fontName = config.module.style.font.serif.name; + fontSize = toString config.module.style.font.size.desktop; - accent = style.color.accent; - bg = style.color.bg.dark; - fg = style.color.fg.light; + accent = config.module.style.color.accent; + bg = config.module.style.color.bg.dark; + fg = config.module.style.color.fg.light; in { text = '' # Application launcher. diff --git a/module/desktop/sway/module/Session.nix b/module/desktop/sway/module/Session.nix index d20062c..1dd2d58 100644 --- a/module/desktop/sway/module/Session.nix +++ b/module/desktop/sway/module/Session.nix @@ -1,5 +1,5 @@ -{ style, ... }: let - lock = "swaylock -f -F -c 000000 -k --font \"${style.font.serif.name}\" --font-size ${toString style.font.size.desktop}"; +{ config, ... }: let + lock = "swaylock -f -F -c 000000 -k --font \"${config.module.style.font.serif.name}\" --font-size ${toString config.module.style.font.size.desktop}"; in { text = '' bindsym $mod+z exec '_twice 1 ${lock}' diff --git a/module/desktop/sway/module/Style.nix b/module/desktop/sway/module/Style.nix index 8139a7d..eb63459 100644 --- a/module/desktop/sway/module/Style.nix +++ b/module/desktop/sway/module/Style.nix @@ -1,12 +1,12 @@ -{ wallpaper, style, ... }: let - alpha = style.opacity.hex; - accent = style.color.accent + alpha; - bg = style.color.bg.dark + alpha; - border = style.color.border + alpha; - fg = style.color.fg.light; +{ config, ... }: let + alpha = config.module.style.opacity.hex; + accent = config.module.style.color.accent + alpha; + bg = config.module.style.color.bg.dark + alpha; + border = config.module.style.color.border + alpha; + fg = config.module.style.color.fg.light; in { text = '' - output * bg ${wallpaper.path} fill + output * bg ${config.module.common.wallpaper.path} fill client.focused "#${accent}" "#${bg}" "#${fg}" "#${accent}" "#${accent}" client.focused_inactive "#${border}" "#${bg}" "#${fg}" "#${border}" "#${border}" client.unfocused "#${border}" "#${bg}" "#${fg}" "#${border}" "#${border}" diff --git a/module/desktop/sway/module/Tiling.nix b/module/desktop/sway/module/Tiling.nix index 45231ce..0975abc 100644 --- a/module/desktop/sway/module/Tiling.nix +++ b/module/desktop/sway/module/Tiling.nix @@ -1,4 +1,4 @@ -{ style, ... }: { +{ config, ... }: { text = '' # Toggle tiling. bindsym $mod+shift+f floating toggle @@ -30,7 +30,7 @@ bindsym $mod+x kill # Add gaps. - gaps inner ${toString style.window.gap} + gaps inner ${toString config.module.style.window.gap} # Launch everything tiled. # for_window [all] floating disable diff --git a/module/desktop/sway/module/TitleBar.nix b/module/desktop/sway/module/TitleBar.nix index d5ed65c..4eed301 100644 --- a/module/desktop/sway/module/TitleBar.nix +++ b/module/desktop/sway/module/TitleBar.nix @@ -1,5 +1,5 @@ -{ style, ... }: let - borderSize = toString style.window.border; +{ config, ... }: let + borderSize = toString config.module.style.window.border; in { text = '' # Disable title bar. diff --git a/module/desktop/waybar/config/default.nix b/module/desktop/waybar/config/default.nix index 45e5142..6144847 100644 --- a/module/desktop/waybar/config/default.nix +++ b/module/desktop/waybar/config/default.nix @@ -1,15 +1,15 @@ -{ config, style, pkgs, ... }: let +{ config, pkgs, ... }: let refreshInterval = 2; in { file = (pkgs.formats.json {}).generate "WaybarConfig" { height = 34; layer = "top"; - margin-left = style.window.gap; - margin-right = style.window.gap; - margin-top = style.window.gap; + margin-left = config.module.style.window.gap; + margin-right = config.module.style.window.gap; + margin-top = config.module.style.window.gap; mode = "dock"; position = "top"; - spacing = 4; + # spacing = 4; start_hidden = false; output = [ "!Huawei Technologies Co., Inc. ZQE-CBA 0xC080F622" @@ -54,7 +54,7 @@ in { }; tray = { # icon-size = 21; - spacing = 1; + spacing = 8; }; clock = { # timezone = "America/New_York"; diff --git a/module/desktop/waybar/style/Common.nix b/module/desktop/waybar/style/Common.nix index 848a44a..2004eb5 100644 --- a/module/desktop/waybar/style/Common.nix +++ b/module/desktop/waybar/style/Common.nix @@ -1,9 +1,9 @@ -{ style, ... }: { +{ config, ... }: { text = '' * { - font-family: "${style.font.serif.name}", "Terminess Nerd Font Propo"; - font-size: ${toString style.font.size.desktop}px; - color: #${style.color.fg.light}; + font-family: "${config.module.style.font.serif.name}", "Terminess Nerd Font Propo"; + font-size: ${toString config.module.style.font.size.desktop}px; + color: #${config.module.style.color.fg.light}; } ''; } diff --git a/module/desktop/waybar/style/Plugin.nix b/module/desktop/waybar/style/Plugin.nix index a6915fa..fe077ad 100644 --- a/module/desktop/waybar/style/Plugin.nix +++ b/module/desktop/waybar/style/Plugin.nix @@ -1,4 +1,4 @@ -{ style, ... }: let +{ config, ... }: let paddingV = "0"; paddingH = "12px"; in { @@ -17,8 +17,8 @@ in { #scratchpad, #language { padding: ${paddingV} ${paddingH}; - border-top: ${toString style.window.border}px solid transparent; - border-bottom: ${toString style.window.border}px solid transparent; + border-top: ${toString config.module.style.window.border}px solid transparent; + border-bottom: ${toString config.module.style.window.border}px solid transparent; } #cpu { @@ -58,24 +58,24 @@ in { #tray:hover, #scratchpad:hover, #workspaces button:hover { - background-color: rgba(${style.color.border-r},${style.color.border-g},${style.color.border-b},${toString style.opacity.desktop}); + background-color: rgba(${config.module.style.color.border-r},${config.module.style.color.border-g},${config.module.style.color.border-b},${toString config.module.style.opacity.desktop}); } #pulseaudio.muted, #battery.critical, #tray.needs-attention, #custom-display.modified { - border-top: ${toString style.window.border}px solid #${style.color.accent}; + border-top: ${toString config.module.style.window.border}px solid #${config.module.style.color.accent}; } #workspaces button { padding: ${paddingV} 4px; - border-top: ${toString style.window.border}px solid transparent; + border-top: ${toString config.module.style.window.border}px solid transparent; border-radius: 0; } #workspaces button.focused { - border-top: ${toString style.window.border}px solid #${style.color.accent}; + border-top: ${toString config.module.style.window.border}px solid #${config.module.style.color.accent}; } ''; } diff --git a/module/desktop/waybar/style/Window.nix b/module/desktop/waybar/style/Window.nix index 6d4de36..428d3aa 100644 --- a/module/desktop/waybar/style/Window.nix +++ b/module/desktop/waybar/style/Window.nix @@ -1,16 +1,16 @@ -{ style, ... }: { +{ config, ... }: { text = '' window#waybar { - background-color: rgba(${style.color.bg-r},${style.color.bg-g},${style.color.bg-b},${toString style.opacity.desktop}); - border: ${toString style.window.border}px solid rgba(${style.color.border-r},${style.color.border-g},${style.color.border-b},${toString style.opacity.desktop}); + background-color: rgba(${config.module.style.color.bg-r},${config.module.style.color.bg-g},${config.module.style.color.bg-b},${toString config.module.style.opacity.desktop}); + border: ${toString config.module.style.window.border}px solid rgba(${config.module.style.color.border-r},${config.module.style.color.border-g},${config.module.style.color.border-b},${toString config.module.style.opacity.desktop}); } .modules-left > widget:first-child > #workspaces { - margin-left: ${toString style.window.border}px; + margin-left: ${toString config.module.style.window.border}px; } .modules-right > widget:last-child > #workspaces { - margin-right: ${toString style.window.border}px; + margin-right: ${toString config.module.style.window.border}px; } ''; } diff --git a/module/powerlimit/Script.nix b/module/powerlimit/Script.nix deleted file mode 100644 index 5820f49..0000000 --- a/module/powerlimit/Script.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ controlFileMax -, controlFileMin -, onMax -, onMin -, offMax -, offMin -, ... }: { - script = '' - function toggle() { - if status; then - echo ${offMax} > ${controlFileMax} - echo ${offMin} > ${controlFileMin} - else - echo ${onMin} > ${controlFileMin} - echo ${onMax} > ${controlFileMax} - fi - - true - } - - function waybar() { - status || echo -n "" - } - - function status() { - local current=$(cat ${controlFileMax}) - local enabled="${onMax}" - - [[ "''${current}" = "''${enabled}" ]] - } - - ''${@} - ''; -} diff --git a/module/powerlimit/default.nix b/module/powerlimit/default.nix deleted file mode 100644 index cd68af7..0000000 --- a/module/powerlimit/default.nix +++ /dev/null @@ -1,31 +0,0 @@ -# Control battery charge limits. Control with `powerlimit` script. -{ pkgs -, lib -, controlFileMax -, controlFileMin -, onMax -, onMin -, offMax -, offMin -, ... }: { - systemd = { - services.powerlimit = { - description = "Limit battery charge."; - enable = true; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "simple"; - RemainAfterExit = "yes"; - ExecStart = "${lib.getExe pkgs.bash} -c 'echo ${onMin} > ${controlFileMin}; echo ${onMax} > ${controlFileMax};'"; - ExecStop = "${lib.getExe pkgs.bash} -c 'echo ${offMax} > ${controlFileMax}; echo ${offMin} > ${controlFileMin};'"; - }; - }; - - # HACK: Allow user access. - tmpfiles.rules = [ - "z ${controlFileMax} 0777 - - - -" - "z ${controlFileMin} 0777 - - - -" - ]; - }; -} - diff --git a/module/powersave/Script.nix b/module/powersave/Script.nix deleted file mode 100644 index 73cc186..0000000 --- a/module/powersave/Script.nix +++ /dev/null @@ -1,27 +0,0 @@ -# Script to control CPU boost. -{ controlFile, enable, disable, ... }: { - script = '' - function toggle() { - if status; then - echo ${disable} > ${controlFile} - else - echo ${enable} > ${controlFile} - fi - - true - } - - function waybar() { - status || echo -n "󰓅" - } - - function status() { - local current=$(cat ${controlFile}) - local enabled="${enable}" - - [[ "''${current}" = "''${enabled}" ]] - } - - ''${@} - ''; -} diff --git a/module/powersave/default.nix b/module/powersave/default.nix deleted file mode 100644 index 14346ea..0000000 --- a/module/powersave/default.nix +++ /dev/null @@ -1,19 +0,0 @@ -# Disable CPU boost after boot. Control with `powersave` script. -{ lib, pkgs, controlFile, enable, disable, ... }: { - systemd = { - services.powersave = { - description = "Disable CPU Boost"; - enable = true; - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - Type = "simple"; - RemainAfterExit = "yes"; - ExecStart = "${lib.getExe pkgs.bash} -c 'echo ${enable} > ${controlFile}'"; - ExecStop = "${lib.getExe pkgs.bash} -c 'echo ${disable} > ${controlFile}'"; - }; - }; - - # HACK: Allow user access. - tmpfiles.rules = [ "z ${controlFile} 0777 - - - -" ]; - }; -} diff --git a/part/Style.nix b/part/Style.nix deleted file mode 100644 index 5f3f3eb..0000000 --- a/part/Style.nix +++ /dev/null @@ -1,81 +0,0 @@ -# Abstraction over Stylix. -{ config, ... }: { - color = { - bg = { - dark = config.lib.stylix.colors.base00; - light = config.lib.stylix.colors.base07; - regular = config.lib.stylix.colors.base01; - }; - fg = { - dark = config.lib.stylix.colors.base04; - light = config.lib.stylix.colors.base06; - regular = config.lib.stylix.colors.base05; - }; - accent = config.lib.stylix.colors.base0A; - heading = config.lib.stylix.colors.base0D; - hl = config.lib.stylix.colors.base03; - keyword = config.lib.stylix.colors.base0E; - link = config.lib.stylix.colors.base09; - misc = config.lib.stylix.colors.base0F; - negative = config.lib.stylix.colors.base08; - neutral = config.lib.stylix.colors.base0C; - positive = config.lib.stylix.colors.base0B; - selection = config.lib.stylix.colors.base02; - transparent = "ffffff00"; - - accent-b = config.lib.stylix.colors.base0A-rgb-b; - accent-g = config.lib.stylix.colors.base0A-rgb-g; - accent-r = config.lib.stylix.colors.base0A-rgb-r; - - negative-b = config.lib.stylix.colors.base08-rgb-b; - negative-g = config.lib.stylix.colors.base08-rgb-g; - negative-r = config.lib.stylix.colors.base08-rgb-r; - - neutral-b = config.lib.stylix.colors.base0C-rgb-b; - neutral-g = config.lib.stylix.colors.base0C-rgb-g; - neutral-r = config.lib.stylix.colors.base0C-rgb-r; - - positive-b = config.lib.stylix.colors.base0B-rgb-b; - positive-g = config.lib.stylix.colors.base0B-rgb-g; - positive-r = config.lib.stylix.colors.base0B-rgb-r; - - bg-b = config.lib.stylix.colors.base00-rgb-b; - bg-g = config.lib.stylix.colors.base00-rgb-g; - bg-r = config.lib.stylix.colors.base00-rgb-r; - - fg-b = config.lib.stylix.colors.base06-rgb-b; - fg-g = config.lib.stylix.colors.base06-rgb-g; - fg-r = config.lib.stylix.colors.base06-rgb-r; - - border = config.lib.stylix.colors.base01; - border-b = config.lib.stylix.colors.base01-rgb-b; - border-g = config.lib.stylix.colors.base01-rgb-g; - border-r = config.lib.stylix.colors.base01-rgb-r; - }; - - font = { - emoji.name = config.stylix.fonts.emoji.name; - monospace.name = config.stylix.fonts.monospace.name; - sansSerif.name = config.stylix.fonts.sansSerif.name; - serif.name = config.stylix.fonts.serif.name; - size = { - terminal = config.stylix.fonts.sizes.terminal; - popup = config.stylix.fonts.sizes.popups; - application = config.stylix.fonts.sizes.applications; - desktop = config.stylix.fonts.sizes.desktop; - }; - }; - - opacity = { - application = config.stylix.opacity.applications; - desktop = config.stylix.opacity.desktop; - popup = config.stylix.opacity.popups; - terminal = config.stylix.opacity.terminal; - hex = "D9"; - }; - - window = { - gap = 8; - border = 4; - }; -} diff --git a/part/Wallpaper.nix b/part/Wallpaper.nix deleted file mode 100644 index 3aa744b..0000000 --- a/part/Wallpaper.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ pkgs, ... }: let - url = "https://i.imgur.com/0RldJsX.jpeg"; - sha256 = "sha256-hbbUz9+m/bLahDiflAoio6+4H0DHfxlbh92cWSjE4R4="; - - # Sometimes stylix does not generate enough contrast for text. - # This setting forces white text to ensure contrast on dark backgrounds. - forceContrastText = false; -in { - inherit forceContrastText; - - path = pkgs.fetchurl { - url = url; - sha256 = sha256; - }; -} diff --git a/part/secret/public/Gpg.key b/secret/Gpg.key similarity index 100% rename from part/secret/public/Gpg.key rename to secret/Gpg.key diff --git a/part/secret/public/Signers.key b/secret/Signers.key similarity index 100% rename from part/secret/public/Signers.key rename to secret/Signers.key diff --git a/part/secret/public/Ssh.key b/secret/Ssh.key similarity index 100% rename from part/secret/public/Ssh.key rename to secret/Ssh.key diff --git a/part/Secret.nix b/secret/default.nix similarity index 87% rename from part/Secret.nix rename to secret/default.nix index 996f8df..e722eb7 100644 --- a/part/Secret.nix +++ b/secret/default.nix @@ -6,7 +6,7 @@ # Keys that are allowed to connect via SSH. trustedKeys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJTI4IUkHH0JSzWDKOAMbzEDbyBXOrmTHRy+tpqJ8twx nix-on-droid@nothing2" - (builtins.readFile ./secret/public/Ssh.key) + (builtins.readFile ./Ssh.key) ]; # Keys that are allowd to connect via SSH to nixbuild user for Nix remote builds. @@ -24,14 +24,14 @@ # Git commit signing. sign.git = { format = "ssh"; - key = ./secret/public/Ssh.key; - allowed = ./secret/public/Signers.key; + key = ./Ssh.key; + allowed = ./Signers.key; }; # List of accepted public keys. publicKeys = [ { - source = ./secret/public/Gpg.key; + source = ./Gpg.key; trust = 5; } ]; diff --git a/user/Dasha.nix b/user/Dasha.nix index 271c7a9..73f23fb 100644 --- a/user/Dasha.nix +++ b/user/Dasha.nix @@ -6,25 +6,29 @@ , config , key , secret -, ... } @args: { - imports = [ - (import ./common (args // { - username = "dasha"; - homeDir = "/home/dasha"; - })) - ]; - users.users.dasha = { - createHome = true; - description = "Daria Dranchak"; - hashedPassword = "$y$j9T$WGMPv/bRhGBUidcZLZ7CE/$raZhwFFdI/XvegVZVHLILJLMiBkOxSErc6gao/Cxt33"; - isNormalUser = true; - uid = 1001; - extraGroups = [ - "input" - "keyd" - "libvirtd" - "networkmanager" - "video" - ]; +, ... } @args: with lib; let + cfg = config.user.dasha; +in { + options = { + user.dasha.enable = mkEnableOption "dasha"; + }; + + config = mkIf cfg.enable { + user.common.users = [{ name = "dasha"; homeDir = "/home/dasha"; }]; + + users.users.dasha = { + createHome = true; + description = "Daria Dranchak"; + hashedPassword = "$y$j9T$WGMPv/bRhGBUidcZLZ7CE/$raZhwFFdI/XvegVZVHLILJLMiBkOxSErc6gao/Cxt33"; + isNormalUser = true; + uid = 1001; + extraGroups = [ + "input" + "keyd" + "libvirtd" + "networkmanager" + "video" + ]; + }; }; } diff --git a/user/Root.nix b/user/Root.nix index e444098..4c7b1b6 100644 --- a/user/Root.nix +++ b/user/Root.nix @@ -7,12 +7,10 @@ , secret , ... } @args: { imports = [ - (import ./common (args // { - username = "root"; - homeDir = "/root"; - })) + ./common ]; + # user.common.users = [{ name = "root"; homeDir = "/root"; }]; users.users.root.hashedPassword = secret.hashedPassword; security.sudo = { enable = false; diff --git a/user/Voronind.nix b/user/Voronind.nix index 3bdf9af..5b8446c 100644 --- a/user/Voronind.nix +++ b/user/Voronind.nix @@ -6,26 +6,29 @@ , config , key , secret -, ... } @args: { - imports = [ - (import ./common (args // { - username = "voronind"; - homeDir = "/home/voronind"; - })) - ]; +, ... } @args: with lib; let + cfg = config.user.voronind; +in { + options = { + user.voronind.enable = mkEnableOption "voronind"; + }; - users.users.voronind = { - createHome = true; - description = "Dmitry Voronin"; - hashedPassword = secret.hashedPassword; - isNormalUser = true; - uid = 1000; - extraGroups = [ - "input" - "keyd" - "libvirtd" - "networkmanager" - "video" - ]; + config = mkIf cfg.enable { + user.common.users = [{ name = "voronind"; homeDir = "/home/voronind"; }]; + + users.users.voronind = { + createHome = true; + description = "Dmitry Voronin"; + hashedPassword = secret.hashedPassword; + isNormalUser = true; + uid = 1000; + extraGroups = [ + "input" + "keyd" + "libvirtd" + "networkmanager" + "video" + ]; + }; }; } diff --git a/user/common/default.nix b/user/common/default.nix index d013f80..0932cda 100644 --- a/user/common/default.nix +++ b/user/common/default.nix @@ -8,7 +8,10 @@ , style , username , util -, ... } @args: let +, lib +, ... } @args: with lib; let + cfg = config.user.common; + # Configuration modules. btop = import ./top/btop args; editor = import ./editorconfig args; @@ -20,56 +23,70 @@ mako = import ./mako args; yazi = import ./yazi args; in { - home-manager = { - # If file exists, rename it with a new extension. - backupFileExtension = "old"; + options = { + user.common.users = mkOption { + default = [{ + name = "root"; + homeDir = "/root"; + }]; + type = types.listOf types.attrs; + }; + }; - users.${username} = { - home = { - username = username; - homeDirectory = homeDir; - stateVersion = const.stateVersion; - file = { - ".config/btop/btop.conf".text = btop.text; - ".config/foot/foot.ini".source = foot.file; - ".config/fuzzel/fuzzel.ini".source = fuzzel.file; - ".config/gtk-3.0/bookmarks".text = gtk3.bookmarks; - ".config/htop/htoprc".text = htop.text; - ".config/keyd/app.conf".text = keyd.text; - ".config/mako/config".source = mako.file; - ".config/yazi/init.lua".source = yazi.init; - ".config/yazi/keymap.toml".source = yazi.keymap; - ".config/yazi/theme.toml".source = yazi.theme; - ".config/yazi/yazi.toml".source = yazi.yazi; - ".editorconfig".source = editor.file; - ".parallel/will-cite".text = ""; - "media/template".source = ./template; - }; - }; + config = { + home-manager = { + users = builtins.foldl' (acc: user: acc // { + ${user.name} = { + home = { + username = user.name; + homeDirectory = user.homeDir; + stateVersion = const.stateVersion; + file = { + ".config/btop/btop.conf".text = btop.text; + ".config/foot/foot.ini".source = foot.file; + ".config/fuzzel/fuzzel.ini".source = fuzzel.file; + ".config/gtk-3.0/bookmarks".text = gtk3.bookmarks; + ".config/htop/htoprc".text = htop.text; + ".config/keyd/app.conf".text = keyd.text; + ".config/mako/config".source = mako.file; + ".config/yazi/init.lua".source = yazi.init; + ".config/yazi/keymap.toml".source = yazi.keymap; + ".config/yazi/theme.toml".source = yazi.theme; + ".config/yazi/yazi.toml".source = yazi.yazi; + ".editorconfig".source = editor.file; + ".parallel/will-cite".text = ""; + "media/template".source = ./template; + }; + }; - xdg.userDirs = { - enable = true; - createDirectories = true; - desktop = "${homeDir}/"; - documents = "${homeDir}/document/"; - download = "${homeDir}/download/"; - music = "${homeDir}/media/music/"; - pictures = "${homeDir}/media/picture/"; - publicShare = "${homeDir}/media/share/"; - templates = "${homeDir}/media/template/"; - videos = "${homeDir}/media/video/"; - extraConfig = { - XDG_TMP_DIR = "${homeDir}/tmp/"; - }; - }; + xdg.userDirs = { + enable = true; + createDirectories = true; + desktop = "${user.homeDir}/"; + documents = "${user.homeDir}/document/"; + download = "${user.homeDir}/download/"; + music = "${user.homeDir}/media/music/"; + pictures = "${user.homeDir}/media/picture/"; + publicShare = "${user.homeDir}/media/share/"; + templates = "${user.homeDir}/media/template/"; + videos = "${user.homeDir}/media/video/"; + extraConfig = { + XDG_TMP_DIR = "${user.homeDir}/tmp/"; + }; + }; - programs = { - home-manager.enable = true; - gpg = { - enable = true; - inherit (secret.crypto) publicKeys; + programs = { + home-manager.enable = true; + gpg = { + enable = true; + inherit (secret.crypto) publicKeys; + }; + }; }; - }; + }) {} cfg.users; + + # If file exists, rename it with a new extension. + backupFileExtension = "old"; }; }; } diff --git a/user/common/foot/default.nix b/user/common/foot/default.nix index e472b33..445e03e 100644 --- a/user/common/foot/default.nix +++ b/user/common/foot/default.nix @@ -1,22 +1,22 @@ -{ style, config, pkgs, ... }: let +{ config, pkgs, ... }: let dpiAware = if config.setting.dpiAware then "yes" else "no"; fontStep = 1; in { file = (pkgs.formats.iniWithGlobalSection {}).generate "FootConfig" { globalSection = { - font = "${style.font.monospace.name}:size=${toString style.font.size.terminal}"; + font = "${config.module.style.font.monospace.name}:size=${toString config.module.style.font.size.terminal}"; # font-bold = "${style.font.monospace.name}:size=${toString style.font.size.terminal}"; - font-italic = "${style.font.monospace.name}:size=${toString style.font.size.terminal}"; - font-bold-italic = "${style.font.monospace.name}:size=${toString style.font.size.terminal}"; + font-italic = "${config.module.style.font.monospace.name}:size=${toString config.module.style.font.size.terminal}"; + font-bold-italic = "${config.module.style.font.monospace.name}:size=${toString config.module.style.font.size.terminal}"; dpi-aware = dpiAware; font-size-adjustment = fontStep; }; sections = { colors = { - alpha = style.opacity.terminal; - background = style.color.bg.dark; - foreground = style.color.fg.light; + alpha = config.module.style.opacity.terminal; + background = config.module.style.color.bg.dark; + foreground = config.module.style.color.fg.light; }; }; }; diff --git a/user/common/fuzzel/default.nix b/user/common/fuzzel/default.nix index f819aa2..756d0ef 100644 --- a/user/common/fuzzel/default.nix +++ b/user/common/fuzzel/default.nix @@ -1,11 +1,11 @@ -{ pkgs, style, config, ... }: let +{ pkgs, config, ... }: let dpiAware = if config.setting.dpiAware then "yes" else "no"; in { file = (pkgs.formats.ini {}).generate "FuzzelConfig" { main = { dpi-aware = dpiAware; # font = "${style.font.serif.name}:size=${toString style.font.size.popup}"; - font = "Minecraftia:size=${toString style.font.size.popup}"; + font = "Minecraftia:size=${toString config.module.style.font.size.popup}"; lines = 20; prompt = "\"\""; show-actions = "yes"; @@ -20,13 +20,13 @@ in { colors = let defaultOpacity = "ff"; in { - background = style.color.bg.dark + style.opacity.hex; - border = style.color.border + style.opacity.hex; - match = style.color.fg.light + defaultOpacity; - selection = style.color.bg.regular + defaultOpacity; - selection-match = style.color.accent + defaultOpacity; - selection-text = style.color.fg.light + defaultOpacity; - text = style.color.fg.light + defaultOpacity; + background = config.module.style.color.bg.dark + config.module.style.opacity.hex; + border = config.module.style.color.border + config.module.style.opacity.hex; + match = config.module.style.color.fg.light + defaultOpacity; + selection = config.module.style.color.bg.regular + defaultOpacity; + selection-match = config.module.style.color.accent + defaultOpacity; + selection-text = config.module.style.color.fg.light + defaultOpacity; + text = config.module.style.color.fg.light + defaultOpacity; }; }; } diff --git a/user/common/mako/default.nix b/user/common/mako/default.nix index ded6a57..ace905f 100644 --- a/user/common/mako/default.nix +++ b/user/common/mako/default.nix @@ -1,17 +1,17 @@ -{ style, pkgs, config, ... }: let - alpha = style.opacity.hex; +{ pkgs, config, ... }: let + alpha = config.module.style.opacity.hex; in { file = (pkgs.formats.iniWithGlobalSection {}).generate "MakoConfig" { globalSection = { anchor = "top-center"; - background-color = "#${style.color.bg.dark}${alpha}"; - border-color = "#${style.color.border}${alpha}"; + background-color = "#${config.module.style.color.bg.dark}${alpha}"; + border-color = "#${config.module.style.color.border}${alpha}"; default-timeout = config.setting.timeout.popup; - font = "${style.font.serif.name} ${toString style.font.size.popup}"; + font = "${config.module.style.font.serif.name} ${toString config.module.style.font.size.popup}"; height = 120; icons = 0; margin = 32; - text-color = "#${style.color.fg.light}"; + text-color = "#${config.module.style.color.fg.light}"; width = 480; }; }; diff --git a/user/common/yazi/module/Theme.nix b/user/common/yazi/module/Theme.nix index 6b0a7a4..912c492 100644 --- a/user/common/yazi/module/Theme.nix +++ b/user/common/yazi/module/Theme.nix @@ -1,25 +1,25 @@ -{ pkgs, style, ... }: let +{ pkgs, config, ... }: let border = { - fg = "#${style.color.border}"; + fg = "#${config.module.style.color.border}"; }; in { file = (pkgs.formats.toml {}).generate "YaziThemeConfig" { manager = { cwd = { - fg = "#${style.color.fg.light}"; + fg = "#${config.module.style.color.fg.light}"; # bg = "#${style.color.bg.regular}"; }; hovered = { - fg = "#${style.color.fg.light}"; - bg = "#${style.color.bg.regular}"; + fg = "#${config.module.style.color.fg.light}"; + bg = "#${config.module.style.color.bg.regular}"; }; preview_hovered = { - fg = "#${style.color.fg.light}"; - bg = "#${style.color.bg.regular}"; + fg = "#${config.module.style.color.fg.light}"; + bg = "#${config.module.style.color.bg.regular}"; }; border_style = border; tab_active = { - bg = "#${style.color.accent}"; + bg = "#${config.module.style.color.accent}"; }; }; select = { inherit border; };