Rewrite modules to options.

This commit is contained in:
Dmitry Voronin 2024-06-25 04:04:39 +03:00 committed by Dmitry Voronin
parent fa4b3c31b7
commit 8c7578075f
Signed by: voronind
SSH key fingerprint: SHA256:3kBb4iV2ahufEBNq+vFbUe4QYfHt98DHQjN7QaptY9k
158 changed files with 3802 additions and 3011 deletions

View file

@ -20,7 +20,7 @@
<a href="https://i.imgur.com/H943DFl.jpeg">Wallpaper link</a> <a href="https://i.imgur.com/H943DFl.jpeg">Wallpaper link</a>
</details> </details>
[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). Color theming based on wallpaper thanks to [Stylix](https://github.com/danth/stylix).

View file

@ -1,11 +1,11 @@
{ pkgs, style, util, ... }: { { pkgs, config, util, ... }: {
font = pkgs.runCommandNoCC "font" {} '' font = pkgs.runCommandNoCC "font" {} ''
cp ${pkgs.nerdfonts.override { fonts = [ "Terminus" ]; }}/share/fonts/truetype/NerdFonts/TerminessNerdFontMono-Regular.ttf $out cp ${pkgs.nerdfonts.override { fonts = [ "Terminus" ]; }}/share/fonts/truetype/NerdFonts/TerminessNerdFontMono-Regular.ttf $out
''; '';
colors = util.trimTabs '' colors = util.trimTabs ''
background=#${style.color.bg.dark} background=#${config.module.style.color.bg.dark}
foreground=#${style.color.fg.light} foreground=#${config.module.style.color.fg.light}
''; '';
initScript = util.trimTabs '' initScript = util.trimTabs ''

View file

@ -1,24 +1,48 @@
{ container, ... } @args: let { container, lib, config, ... } @args: with lib; let
cfg = container.config.change; cfg = config.container.module.change;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.change = {
]; enable = mkEnableOption "Change detection service";
address = mkOption {
containers.change = container.mkContainer cfg { default = "10.1.0.41";
bindMounts = { type = types.str;
"/var/lib/changedetection-io" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
services.changedetection-io = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
baseURL = cfg.domain; ];
behindProxy = true;
listenAddress = cfg.address; 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;
};
}; };
}; };
}; };

View file

@ -1,45 +1,72 @@
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... } @args: with lib; let
cfg = container.config.cloud; cfg = config.container.module.cloud;
in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [
"data"
];
containers.cloud = container.mkContainer cfg { postgres = config.container.module.postgres;
bindMounts = { proxy = config.container.module.proxy;
"/var/lib/nextcloud" = { in {
hostPath = "${cfg.storage}/data"; options = {
isReadOnly = false; 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 { config = mkIf cfg.enable {
environment.systemPackages = [ pkgs.postgresql ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
services.nextcloud = { "data"
enable = true; ];
# package = pkgs.nextcloud29;
hostName = cfg.domain;
# phpOptions = {
# memory_limit = lib.mkForce "20G";
# };
config = {
adminuser = "root";
adminpassFile = "${pkgs.writeText "NextcloudPassword" "root"}";
dbhost = container.config.postgres.address; containers.cloud = container.mkContainer cfg {
dbname = "nextcloud"; bindMounts = {
dbpassFile = "${pkgs.writeText "NextcloudDbPassword" "nextcloud"}"; "/var/lib/nextcloud" = {
dbtype = "pgsql"; hostPath = "${cfg.storage}/data";
dbuser = "nextcloud"; isReadOnly = false;
}; };
extraApps = { };
inherit (config.services.nextcloud.package.packages.apps) contacts calendar onlyoffice;
}; config = { config, ... }: container.mkContainerConfig cfg {
extraAppsEnable = true; environment.systemPackages = [ pkgs.postgresql ];
settings = { services.nextcloud = {
trusted_domains = [ cfg.address cfg.domain ]; enable = true;
trusted_proxies = [ container.config.proxy.address ]; # package = pkgs.nextcloud29;
allow_local_remote_servers = true; 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;
};
}; };
}; };
}; };

View file

@ -1,35 +1,53 @@
{ container, domain, ... } @args: let { container, lib, config, ... } @args: with lib; let
cfg = container.config.ddns; cfg = config.container.module.ddns;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.ddns = {
]; enable = mkEnableOption "Dynamic dns client.";
address = mkOption {
containers.ddns = container.mkContainer cfg { default = "10.1.0.31";
bindMounts = { type = types.str;
"/data" = { };
hostPath = "${cfg.storage}/data"; storage = mkOption {
isReadOnly = true; default = "${config.container.storage}/ddns";
type = types.str;
}; };
}; };
};
config = { ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
services.cloudflare-dyndns = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
apiTokenFile = "/data/token"; ];
deleteMissing = true;
ipv4 = true; containers.ddns = container.mkContainer cfg {
ipv6 = false; bindMounts = {
proxied = false; "/data" = {
domains = [ domain ] ++ map (sub: "${sub}.${domain}") [ hostPath = "${cfg.storage}/data";
"cloud" isReadOnly = true;
"git" };
"mail" };
"office"
"paste" config = { ... }: container.mkContainerConfig cfg {
"play" services.cloudflare-dyndns = {
"vpn" 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"
];
};
}; };
}; };
}; };

View file

@ -1,112 +1,129 @@
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... } @args: with lib; let
cfg = container.config.dns; cfg = config.container.module.dns;
in { in {
containers.dns = container.mkContainer cfg { options = {
forwardPorts = [ container.module.dns = {
{ enable = mkEnableOption "Dns server.";
containerPort = 53; address = mkOption {
hostPort = 53; default = "10.1.0.6";
protocol = "udp"; type = types.str;
} { };
containerPort = 53; port = mkOption {
hostPort = 53; default = 53;
protocol = "tcp"; type = types.int;
} };
]; };
};
config = { lib, ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
environment.systemPackages = [ containers.dns = container.mkContainer cfg {
pkgs.cloudflared forwardPorts = [
{
containerPort = cfg.port;
hostPort = cfg.port;
protocol = "udp";
} {
containerPort = cfg.port;
hostPort = cfg.port;
protocol = "tcp";
}
]; ];
systemd.services.cloudflared = { config = { ... }: container.mkContainerConfig cfg {
description = "Cloudflare DoH server."; environment.systemPackages = [
enable = true; pkgs.cloudflared
wantedBy = [ "multi-user.target" ]; ];
serviceConfig = {
Type = "simple";
ExecStart = "${lib.getExe pkgs.cloudflared} proxy-dns --port 5054";
};
};
services.blocky = { systemd.services.cloudflared = {
enable = true; description = "Cloudflare DoH server.";
settings = { enable = true;
upstream = { wantedBy = [ "multi-user.target" ];
default = [ serviceConfig = {
"0.0.0.0:5054" Type = "simple";
"0.0.0.0:5054" ExecStart = "${getExe pkgs.cloudflared} proxy-dns --port 5054";
];
}; };
blocking = { };
blackLists = {
suspicious = [ services.blocky = {
"https://raw.githubusercontent.com/StevenBlack/hosts/master/hosts" enable = true;
"https://raw.githubusercontent.com/PolishFiltersTeam/KADhosts/master/KADhosts.txt" settings = {
"https://raw.githubusercontent.com/FadeMind/hosts.extras/master/add.Spam/hosts" upstream = {
"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 = [ default = [
"suspicious" "0.0.0.0:5054"
"ads" "0.0.0.0:5054"
"tracking"
"malicious"
"other"
]; ];
}; };
}; blocking = {
customDNS = { blackLists = {
mapping = { suspicious = [
"voronind.com" = "192.168.1.2"; "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";
}; };
}; };
}; };

View file

@ -1,29 +1,56 @@
{ container, lib, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.download; cfg = config.container.module.download;
memLimit = "4G";
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.download = {
]; enable = mkEnableOption "Downloader.";
address = mkOption {
containers.download = container.mkContainer cfg { default = "10.1.0.12";
enableTun = true; type = types.str;
bindMounts = {
"/var/lib/deluge/.config/deluge" = {
hostPath = "${cfg.storage}/data";
isReadOnly = false;
}; };
} // container.attachMedia "download" cfg.download false; port = mkOption {
default = 8112;
config = { ... }: container.mkContainerConfig cfg { type = types.int;
services.deluge = {
enable = true;
dataDir = "/var/lib/deluge";
web.enable = true;
}; };
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;
};
}; };
}; };
} }

View file

@ -1,73 +1,97 @@
{ container, pkgs, ... } @args: let { container, pkgs, config, lib, ... }: with lib; let
cfg = container.config.git; cfg = config.container.module.git;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.git = {
]; enable = mkEnableOption "Git server.";
address = mkOption {
containers.git = container.mkContainer cfg { default = "10.1.0.8";
bindMounts = { type = types.str;
"/var/lib/gitea" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [ gitea ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
"data"
];
services.gitea = { containers.git = container.mkContainer cfg {
enable = true; bindMounts = {
stateDir = "/var/lib/gitea"; "/var/lib/gitea" = {
hostPath = "${cfg.storage}/data";
database = let isReadOnly = false;
postgre = container.config.postgres;
in {
type = "postgres";
host = postgre.address;
port = postgre.port;
user = "gitea";
createDatabase = false;
}; };
};
settings = let config = { ... }: container.mkContainerConfig cfg {
gcArgs = "--aggressive --no-cruft --prune=now"; environment.systemPackages = with pkgs; [ gitea ];
gcTimeout = 600;
in { services.gitea = {
"service".DISABLE_REGISTRATION = true; enable = true;
"log".LEVEL = "Error"; stateDir = "/var/lib/gitea";
"server" = {
DISABLE_SSH = true; database = let
DOMAIN = cfg.domain; postgre = config.container.module.postgres;
HTTP_ADDR = cfg.address; in {
ROOT_URL = "https://${cfg.domain}"; 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;
}; };
}; };
}; };

View file

@ -1,43 +1,67 @@
# ISSUE: Broken, can't read/write sda device. # ISSUE: Broken, can't read/write sda device.
{ container, pkgs, ... } @args: let { container, pkgs, config, lib, ... }: with lib; let
cfg = container.config.hdd; cfg = config.container.module.hdd;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" 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 { config = mkIf cfg.enable {
# bindMounts = let systemd.tmpfiles.rules = container.mkContainerDir cfg [
# attachDrive = hostPath: { "data"
# inherit hostPath; ];
# isReadOnly = false;
# };
# in {
# "/opt/scrutiny" = {
# hostPath = "${cfg.storage}/data";
# isReadOnly = false;
# };
# "/dev/sda" = attachDrive "/dev/sda";
# };
# allowedDevices = [ containers.hdd = container.mkContainer cfg {
# { # bindMounts = let
# modifier = "rwm"; # attachDrive = hostPath: {
# node = "/dev/sda"; # 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 { # additionalCapabilities = [ "CAP_SYS_ADMIN" ];
environment.systemPackages = with pkgs; [ smartmontools ];
services.scrutiny = { config = { ... }: container.mkContainerConfig cfg {
enable = true; environment.systemPackages = with pkgs; [ smartmontools ];
settings.web = {
listen = { services.scrutiny = {
host = cfg.address; enable = true;
port = cfg.port; settings.web = {
listen = {
host = cfg.address;
port = cfg.port;
};
}; };
}; };
}; };

View file

@ -1,22 +1,42 @@
{ container, pkgs, util, ... } @args: let { container, pkgs, util, lib, config, ... } @args: with lib; let
cfg = container.config.home; cfg = config.container.module.home;
package = (pkgs.callPackage ./homer args); package = (pkgs.callPackage ./homer args);
in { in {
containers.home = container.mkContainer cfg { options = {
config = { ... }: container.mkContainerConfig cfg { container.module.home = {
environment.systemPackages = [ package ]; enable = mkEnableOption "Dashboard.";
systemd.packages = [ package ]; 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 = { config = mkIf cfg.enable {
enable = true; containers.home = container.mkContainer cfg {
virtualHosts.${cfg.domain} = container.mkServer { config = { ... }: container.mkContainerConfig cfg {
default = true; environment.systemPackages = [ package ];
root = "${package}"; systemd.packages = [ package ];
locations = { services.nginx = {
"/".extraConfig = '' enable = true;
try_files $uri $uri/index.html; virtualHosts.${cfg.domain} = container.mkServer {
''; default = true;
root = "${package}";
locations = {
"/".extraConfig = ''
try_files $uri $uri/index.html;
'';
};
}; };
}; };
}; };

View file

@ -1,69 +1,93 @@
{ container, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.iot; cfg = config.container.module.iot;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" 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 { config = mkIf cfg.enable {
bindMounts = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
"/var/lib/hass" = { "data"
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 = { ... }: container.mkContainerConfig cfg { containers.iot = container.mkContainer cfg {
# Allow Hass to talk to Zigbee dongle. bindMounts = {
users.users.hass.extraGroups = [ "dialout" "tty" ]; "/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 = { allowedDevices = [
# NOTE: Missing: hacs. Inside hacs: `card-mod`, `Clock Weather Card`, `WallPanel` and `Yandex.Station`. {
enable = true; modifier = "rwm";
extraComponents = [ node = "/dev/ttyACM0";
"caldav" }
"met" ];
"sun"
"systemmonitor" config = { ... }: container.mkContainerConfig cfg {
"zha" # Allow Hass to talk to Zigbee dongle.
]; users.users.hass.extraGroups = [ "dialout" "tty" ];
extraPackages = python3Packages: with python3Packages; [
aiodhcpwatcher services.home-assistant = {
aiodiscover # NOTE: Missing: hacs. Inside hacs: `card-mod`, `Clock Weather Card`, `WallPanel` and `Yandex.Station`.
aiogithubapi enable = true;
async-upnp-client extraComponents = [
ha-av "caldav"
ha-ffmpeg "met"
hassil "sun"
home-assistant-intents "systemmonitor"
mutagen "zha"
numpy ];
pynacl extraPackages = python3Packages: with python3Packages; [
pyturbojpeg aiodhcpwatcher
python-telegram-bot aiodiscover
zeroconf aiogithubapi
]; async-upnp-client
configDir = "/var/lib/hass"; ha-av
# lovelaceConfig = { ha-ffmpeg
# title = "Home IoT control center."; hassil
# }; home-assistant-intents
# NOTE: Using imperative config because of secrets. mutagen
config = null; 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;
};
}; };
}; };
}; };

View file

@ -1,48 +1,64 @@
{ container, pkgsJobber, poetry2nixJobber, lib, ... } @args: let { container, pkgsJobber, poetry2nixJobber, lib, config, ... }: with lib; let
cfg = container.config.jobber; cfg = config.container.module.jobber;
script = import ./jobber { poetry2nix = poetry2nixJobber; pkgs = pkgsJobber; }; script = import ./jobber { poetry2nix = poetry2nixJobber; pkgs = pkgsJobber; };
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.jobber = {
]; enable = mkEnableOption "Button pusher Stanley.";
address = mkOption {
containers.jobber = container.mkContainer cfg { default = "10.1.0.32";
bindMounts = { type = types.str;
"/data" = { };
hostPath = "${cfg.storage}/data"; storage = mkOption {
isReadOnly = true; default = "${config.container.storage}/jobber";
type = types.str;
}; };
}; };
};
enableTun = true; config = mkIf cfg.enable {
systemd.tmpfiles.rules = container.mkContainerDir cfg [
"data"
];
config = { lib, ... }: let containers.jobber = container.mkContainer cfg {
packages = [ script ] ++ (with pkgsJobber; [ bindMounts = {
firefox "/data" = {
geckodriver hostPath = "${cfg.storage}/data";
openvpn isReadOnly = true;
python311 };
]);
in container.mkContainerConfig cfg {
networking = lib.mkForce {
nameservers = [
"10.9.0.5"
];
}; };
systemd.services.jobber = { enableTun = true;
description = "My job is pushing the button.";
enable = true; config = { lib, ... }: let
wantedBy = [ "multi-user.target" ]; packages = [ script ] ++ (with pkgsJobber; [
path = packages; firefox
environment = { geckodriver
PYTHONUNBUFFERED = "1"; openvpn
PYTHONDONTWRITEBYTECODE = "1"; python311
]);
in container.mkContainerConfig cfg {
networking = lib.mkForce {
nameservers = [
"10.9.0.5"
];
}; };
serviceConfig = {
Type = "simple"; systemd.services.jobber = {
ExecStart = "${script}/bin/jobber -u"; description = "My job is pushing the button.";
Restart = "on-failure"; enable = true;
wantedBy = [ "multi-user.target" ];
path = packages;
environment = {
PYTHONUNBUFFERED = "1";
PYTHONDONTWRITEBYTECODE = "1";
};
serviceConfig = {
Type = "simple";
ExecStart = "${script}/bin/jobber -u";
Restart = "on-failure";
};
}; };
}; };
}; };

View file

@ -1,177 +1,203 @@
# Guide: https://nixos-mailserver.readthedocs.io/en/latest/setup-guide.html # 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 { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.mail = {
# "data/indices" enable = mkEnableOption "Email server.";
# "data/vmail" address = mkOption {
# "data/sieve" default = "10.1.0.5";
# "data/dkim" type = types.str;
];
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;
}; };
"/var/vmail" = { port = mkOption {
hostPath = "${cfg.storage}/data/vmail"; default = 80;
isReadOnly = false; type = types.int;
}; };
"/var/sieve" = { domain = mkOption {
hostPath = "${cfg.storage}/data/sieve"; default = "mail.${config.container.domain}";
isReadOnly = false; type = types.str;
}; };
"/var/dkim" = { storage = mkOption {
hostPath = "${cfg.storage}/data/dkim"; default = "${config.container.storage}/mail";
isReadOnly = false; type = types.str;
};
"/acme" = {
hostPath = "${container.config.proxy.storage}/letsencrypt";
isReadOnly = true;
}; };
}; };
};
config = { config, ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
imports = [ systemd.tmpfiles.rules = container.mkContainerDir cfg [
(builtins.fetchTarball { "data"
url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-${const.stateVersion}/nixos-mailserver-nixos-${const.stateVersion}.tar.gz"; # "data/indices"
sha256 = "sha256:0clvw4622mqzk1aqw1qn6shl9pai097q62mq1ibzscnjayhp278b"; # "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 = { bindMounts = {
enable = true; "/var/lib/dovecot/indices" = {
fqdn = cfg.domain; hostPath = "${cfg.storage}/data/indices";
domains = [ domain ]; isReadOnly = false;
sendingFqdn = domain; };
"/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`. config = { config, ... }: container.mkContainerConfig cfg {
loginAccounts = let imports = [
defaultQuota = "1G"; (builtins.fetchTarball {
in { url = "https://gitlab.com/simple-nixos-mailserver/nixos-mailserver/-/archive/nixos-${const.stateVersion}/nixos-mailserver-nixos-${const.stateVersion}.tar.gz";
"admin@${domain}" = { sha256 = "sha256:0clvw4622mqzk1aqw1qn6shl9pai097q62mq1ibzscnjayhp278b";
name = "admin"; })
hashedPassword = "$2b$05$1O.dxXxaVshcBNybcqDRYuTlnYt3jDBwfPZWoDtP4BjOLoL0StYsi"; ];
quota = defaultQuota;
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"; enableImap = true;
hashedPassword = "$2b$05$sCyZHdk98KqQ1qsTIvbrUeRJlNBOwBqDgpdc1QxiSnONlEkZ8xGNO"; enableImapSsl = true;
quota = defaultQuota; 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"; dmarcReporting = {
hashedPassword = "$2b$05$6fT5hIhzIasNfp9IQr/ds.5RuxH95VKU3QJWlX3hmrAzDF3mExanq"; inherit domain;
quota = defaultQuota; enable = true;
aliases = [ "voronind@${domain}" ]; organizationName = "voronind";
}; # email = "noreply@${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;
}; };
# monitoring = {
# enable = true;
# alertAddress = "admin@${domain}";
# };
}; };
enableImap = true; services.roundcube = {
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;
enable = true; enable = true;
organizationName = "voronind"; dicts = with pkgs.aspellDicts; [ en ru ];
# email = "noreply@${domain}"; 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 = { services.nginx = {
# enable = true; virtualHosts.${cfg.domain} = {
# alertAddress = "admin@${domain}"; forceSSL = false;
# }; enableACME = false;
}; };
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;
}; };
}; };
}; };

View file

@ -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. # 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 # 2. TODO: Generate JWT secret at /var/lib/onlyoffice/jwt, i.e. 9wLfMGha1YrfvWpb5hyYjZf8pvJQ3swS
# See https://git.voronind.com/voronind/nixos/issues/74 # See https://git.voronind.com/voronind/nixos/issues/74
{ container, pkgs, util, lib, ... } @args: let { container, pkgs, util, lib, config, ... }: with lib; let
cfg = container.config.office; cfg = config.container.module.office;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.office = {
]; enable = mkEnableOption "Office web suite.";
address = mkOption {
containers.office = container.mkContainer cfg { default = "10.1.0.21";
bindMounts = { type = types.str;
"/var/lib/onlyoffice" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
services.onlyoffice = let systemd.tmpfiles.rules = container.mkContainerDir cfg [
dbName = "onlyoffice"; "data"
in { ];
enable = true;
hostname = cfg.domain;
postgresName = dbName; containers.office = container.mkContainer cfg {
postgresHost = container.config.postgres.address; bindMounts = {
postgresUser = dbName; "/var/lib/onlyoffice" = {
postgresPasswordFile = "${pkgs.writeText "OfficeDbPassword" dbName}"; 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; jwtSecretFile = "/var/lib/onlyoffice/jwt";
enableExampleServer = true;
rabbitmqUrl = "amqp://guest:guest@${config.container.module.rabbitmq.address}:${toString config.container.module.rabbitmq.port}";
examplePort = cfg.port;
enableExampleServer = true;
};
}; };
}; };
}; };

View file

@ -1,52 +1,76 @@
{ container, pkgs, util, lib, ... } @args: let { container, pkgs, util, lib, config, ... }: with lib; let
cfg = container.config.paper; cfg = config.container.module.paper;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.paper = {
]; enable = mkEnableOption "Paper scans manager.";
address = mkOption {
containers.paper = container.mkContainer cfg { default = "10.1.0.40";
bindMounts = { type = types.str;
"/var/lib/paperless" = {
hostPath = "${cfg.storage}/data";
isReadOnly = false;
}; };
"/var/lib/paperless/media" = { port = mkOption {
hostPath = "${lib.elemAt cfg.paper 0}"; default = 28981;
isReadOnly = false; 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 { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [ postgresql inetutils ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
"data"
];
services.paperless = { containers.paper = container.mkContainer cfg {
enable = true; bindMounts = {
dataDir = "/var/lib/paperless"; "/var/lib/paperless" = {
# address = cfg.domain; hostPath = "${cfg.storage}/data";
address = "0.0.0.0"; isReadOnly = false;
port = cfg.port; };
passwordFile = pkgs.writeText "PaperlessPassword" "root"; "/var/lib/paperless/media" = {
settings = { hostPath = "${elemAt config.container.media.paper 0}";
PAPERLESS_URL = "https://${cfg.domain}"; isReadOnly = false;
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}";
}; };
}; };
# HACK: This is required for TCP postgres connection. config = { lib, ... }: container.mkContainerConfig cfg {
systemd.services.paperless-scheduler.serviceConfig = { environment.systemPackages = with pkgs; [ postgresql inetutils ];
PrivateNetwork = lib.mkForce false;
}; services.paperless = {
systemd.services.paperless-consumer.serviceConfig = { enable = true;
PrivateNetwork = lib.mkForce false; 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;
};
}; };
}; };
}; };

View file

@ -1,31 +1,55 @@
{ container, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.pass; cfg = config.container.module.pass;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.pass = {
]; enable = mkEnableOption "Password manager";
address = mkOption {
containers.pass = container.mkContainer cfg { default = "10.1.0.9";
bindMounts = { type = types.str;
"/var/lib/bitwarden_rs" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
services.vaultwarden = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
dbBackend = "sqlite"; ];
environmentFile = "/var/lib/bitwarden_rs/Env";
config = { containers.pass = container.mkContainer cfg {
# DATABASE_URL = "postgresql://vaultwarden:vaultwarden@${container.config.postgres.address}:${toString container.config.postgres.port}/vaultwarden"; bindMounts = {
DATA_FOLDER = "/var/lib/bitwarden_rs"; "/var/lib/bitwarden_rs" = {
DOMAIN = "http://${cfg.domain}"; hostPath = "${cfg.storage}/data";
SIGNUPS_ALLOWED = false; isReadOnly = false;
WEB_VAULT_ENABLED = true; };
ROCKET_ADDRESS = cfg.address; };
ROCKET_PORT = cfg.port;
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;
};
}; };
}; };
}; };

View file

@ -1,100 +1,124 @@
{ pkgs, util, container, ... } @args: let { pkgs, util, container, lib, config, ... } @args: with lib; let
cfg = container.config.paste; cfg = config.container.module.paste;
package = (pkgs.callPackage ./pastebin args); package = (pkgs.callPackage ./pastebin args);
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.paste = {
"tmp" enable = mkEnableOption "Pastebin.";
"nginxtmp" address = mkOption {
"config" default = "10.1.0.14";
]; type = types.str;
containers.paste = container.mkContainer cfg {
bindMounts = {
"/srv/data" = {
hostPath = "${cfg.storage}/data";
isReadOnly = false;
}; };
"/tmp" = { port = mkOption {
hostPath = "${cfg.storage}/tmp"; default = 80;
isReadOnly = false; type = types.int;
}; };
"/var/lib/nginx/tmp" = { domain = mkOption {
hostPath = "${cfg.storage}/nginxtmp"; default = "paste.${config.container.domain}";
isReadOnly = false; type = types.str;
}; };
"/srv/config" = { storage = mkOption {
hostPath = "${cfg.storage}/config"; default = "${config.container.storage}/paste";
isReadOnly = false; type = types.str;
}; };
}; };
};
config = { config, ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
environment.systemPackages = [ package ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
systemd.packages = [ package ]; "data"
"tmp"
"nginxtmp"
"config"
];
users.users.paste = { containers.paste = container.mkContainer cfg {
group = "nginx"; bindMounts = {
isSystemUser = true; "/srv/data" = {
}; hostPath = "${cfg.storage}/data";
isReadOnly = false;
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";
}; };
"/tmp" = {
phpEnv = { hostPath = "${cfg.storage}/tmp";
# CONFIG_PATH = "${package}/cfg"; isReadOnly = false;
};
"/var/lib/nginx/tmp" = {
hostPath = "${cfg.storage}/nginxtmp";
isReadOnly = false;
};
"/srv/config" = {
hostPath = "${cfg.storage}/config";
isReadOnly = false;
}; };
}; };
services.nginx = { config = { config, ... }: container.mkContainerConfig cfg {
enable = true; environment.systemPackages = [ package ];
virtualHosts.${cfg.domain} = container.mkServer { systemd.packages = [ package ];
default = true;
root = "${package}";
locations = { users.users.paste = {
"/".extraConfig = '' group = "nginx";
rewrite ^ /index.php; isSystemUser = true;
''; };
"~ \\.php$".extraConfig = util.trimTabs '' services.phpfpm.pools.paste = {
fastcgi_split_path_info ^(.+\.php)(/.+)$; user = "paste";
fastcgi_pass unix:${config.services.phpfpm.pools.paste.socket}; group = "nginx";
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 '' phpPackage = pkgs.php;
add_header Cache-Control "public, max-age=15778463";
add_header X-Content-Type-Options nosniff; settings = {
add_header X-XSS-Protection "1; mode=block"; "pm" = "dynamic";
add_header X-Robots-Tag none; "php_admin_value[error_log]" = "stderr";
add_header X-Download-Options noopen; "php_admin_flag[log_errors]" = true;
add_header X-Permitted-Cross-Domain-Policies none; "listen.owner" = "nginx";
add_header Referrer-Policy no-referrer; "catch_workers_output" = true;
access_log off; "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 '' phpEnv = {
try_files $uri /index.php; # 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;
'';
};
}; };
}; };
}; };

View file

@ -1,56 +1,76 @@
{ container, lib, pkgs, ... } @args: let { container, lib, pkgs, config, ... }: with lib; let
cfg = container.config.postgres; cfg = config.container.module.postgres;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.postgres = {
]; enable = mkEnableOption "Postgresql server.";
address = mkOption {
containers.postgres = container.mkContainer cfg { default = "10.1.0.3";
bindMounts = { type = types.str;
"/var/lib/postgresql/data" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; default = 5432;
type = types.int;
};
storage = mkOption {
default = "${config.container.storage}/postgres";
type = types.str;
}; };
}; };
};
config = { ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
services.postgresql = let systemd.tmpfiles.rules = container.mkContainerDir cfg [
# Populate with services here. "data"
configurations = with container.config; { ];
gitea = git;
nextcloud = cloud; containers.postgres = container.mkContainer cfg {
privatebin = paste; bindMounts = {
onlyoffice = office; "/var/lib/postgresql/data" = {
paperless = paper; hostPath = "${cfg.storage}/data";
invidious = yt; isReadOnly = false;
}; };
};
access = configurations // { config = { ... }: container.mkContainerConfig cfg {
all = { address = container.host; }; 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;
}; };
}; };
}; };

View file

@ -2,33 +2,57 @@
# ipp://192.168.2.237 # ipp://192.168.2.237
# Pantum M6500W-Series # Pantum M6500W-Series
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... }: with lib; let
cfg = container.config.print; cfg = config.container.module.print;
package = pkgs.callPackage ./print args; package = pkgs.callPackage ./print args;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.print = {
]; enable = mkEnableOption "Printing server.";
address = mkOption {
containers.print = container.mkContainer cfg { default = "10.1.0.46";
bindMounts = { type = types.str;
"/var/lib/cups" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
services.printing = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
allowFrom = [ "all" ]; ];
browsing = true;
defaultShared = true; containers.print = container.mkContainer cfg {
drivers = [ package ]; bindMounts = {
listenAddresses = [ "${cfg.address}:${toString cfg.port}" ]; "/var/lib/cups" = {
startWhenNeeded = true; hostPath = "${cfg.storage}/data";
stateless = false; isReadOnly = false;
webInterface = true; };
};
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;
};
}; };
}; };
}; };

View file

@ -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"; # 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` # 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 { util, container, pkgs, lib, config, ... } @args: with lib; let
cfg = container.config.proxy; cfg = config.container.module.proxy;
virtualHosts = util.catSet (util.ls ./proxy/host) args; virtualHosts = util.catSet (util.ls ./proxy/host) args;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"challenge" container.module.proxy = {
"letsencrypt" enable = mkEnableOption "Proxy server.";
]; address = mkOption {
default = "10.1.0.2";
containers.proxy = container.mkContainer cfg { type = types.str;
forwardPorts = [
# {
# containerPort = 80;
# hostPort = 80;
# protocol = "tcp";
# } {
{
containerPort = cfg.port;
hostPort = cfg.port;
protocol = "tcp";
}
];
bindMounts = {
"/etc/letsencrypt" = {
hostPath = "${cfg.storage}/letsencrypt";
isReadOnly = true;
}; };
"/var/www/.well-known" = { port = mkOption {
hostPath = "${cfg.storage}/challenge"; default = 443;
isReadOnly = false; type = types.int;
};
storage = mkOption {
default = "${config.container.storage}/proxy";
type = types.str;
}; };
}; };
};
config = { ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [ certbot ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
"challenge"
"letsencrypt"
];
services.nginx = { containers.proxy = container.mkContainer cfg {
inherit virtualHosts; forwardPorts = [
# {
# containerPort = 80;
# hostPort = 80;
# protocol = "tcp";
# } {
{
containerPort = cfg.port;
hostPort = cfg.port;
protocol = "tcp";
}
];
enable = true; bindMounts = {
recommendedOptimisation = true; "/etc/letsencrypt" = {
recommendedProxySettings = true; hostPath = "${cfg.storage}/letsencrypt";
appendConfig = util.trimTabs '' isReadOnly = true;
worker_processes 4; };
''; "/var/www/.well-known" = {
eventsConfig = util.trimTabs '' hostPath = "${cfg.storage}/challenge";
worker_connections 4096; isReadOnly = false;
''; };
# TODO: Fix 80 redirect and 403 default. };
appendHttpConfig = util.trimTabs ''
server {
server_name default_server;
listen 80;
location / { config = { ... }: container.mkContainerConfig cfg {
return 301 https://$host$request_uri; 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 { map $http_accept_language $resume {
default https://git.${domain}/voronind/resume/releases/download/latest/voronind_en.pdf; default https://git.${config.container.domain}/voronind/resume/releases/download/latest/voronind_en.pdf;
~ru https://git.${domain}/voronind/resume/releases/download/latest/voronind_ru.pdf; ~ru https://git.${config.container.domain}/voronind/resume/releases/download/latest/voronind_ru.pdf;
} }
server { server {
server_name ${domain}; server_name ${config.container.domain};
listen 443 ssl; listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
return 301 $resume; return 301 $resume;
} }
server { server {
listen 443 ssl default_server; listen 443 ssl default_server;
server_name _; server_name _;
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
return 403; return 403;
} }
''; '';
};
}; };
}; };
}; };

View file

@ -1,26 +1,46 @@
{ container, pkgs, util, ... } @args: let { container, pkgs, util, lib, config, ... }: with lib; let
cfg = container.config.rabbitmq; cfg = config.container.module.rabbitmq;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.rabbitmq = {
]; enable = mkEnableOption "Mqtt server.";
address = mkOption {
containers.rabbitmq = container.mkContainer cfg { default = "10.1.0.28";
bindMounts = { type = types.str;
"/var/lib/rabbitmq" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; default = 5672;
type = types.int;
};
storage = mkOption {
default = "${config.container.storage}/rabbitmq";
type = types.str;
}; };
}; };
};
config = { ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
services.rabbitmq = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
listenAddress = cfg.address; ];
port = cfg.port;
dataDir = "/var/lib/rabbitmq"; containers.rabbitmq = container.mkContainer cfg {
configItems = { bindMounts = {
"loopback_users" = "none"; "/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";
};
}; };
}; };
}; };

View file

@ -1,29 +1,53 @@
{ container, lib, pkgs, ... } @args: let { container, lib, pkgs, config, ... }: with lib; let
cfg = container.config.read; cfg = config.container.module.read;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.read = {
]; enable = mkEnableOption "Reading server.";
address = mkOption {
containers.read = container.mkContainer cfg { default = "10.1.0.39";
bindMounts = { type = types.str;
"/var/lib/kavita" = {
hostPath = "${cfg.storage}/data";
isReadOnly = false;
}; };
} port = mkOption {
// container.attachMedia "book" cfg.book true default = 5000;
// container.attachMedia "manga" cfg.manga true 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 { config = mkIf cfg.enable {
services.kavita = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
dataDir = "/var/lib/kavita"; ];
tokenKeyFile = pkgs.writeText "KavitaToken" "xY19aQOa939/Ie6GCRGbubVK8zRwrgBY/20AuyMpYshUjwK1Uyl7bw1yknVh6jJIFIfwq2vAjeotOUq7NEsf9Q==";
settings = { containers.read = container.mkContainer cfg {
IpAddresses = cfg.address; bindMounts = {
Port = cfg.port; "/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;
};
}; };
}; };
}; };

View file

@ -1,13 +1,29 @@
{ container, pkgs, util, ... } @args: let { container, pkgs, util, lib, config, ... }: with lib; let
cfg = container.config.redis; cfg = config.container.module.redis;
in { in {
containers.redis = container.mkContainer cfg { options = {
config = { ... }: container.mkContainerConfig cfg { container.module.redis = {
services.redis.servers.main = { enable = mkEnableOption "Redis server.";
enable = true; address = mkOption {
port = cfg.port; default = "10.1.0.38";
bind = cfg.address; type = types.str;
extraParams = [ "--protected-mode no" ]; };
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" ];
};
}; };
}; };
}; };

View file

@ -1,16 +1,40 @@
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... }: with lib; let
cfg = container.config.search; cfg = config.container.module.search;
in { in {
containers.search = container.mkContainer cfg { options = {
config = { ... }: container.mkContainerConfig cfg { container.module.search = {
services.searx = { enable = mkEnableOption "Search frontend.";
enable = true; address = mkOption {
package = pkgs.searxng; default = "10.1.0.26";
settings = { type = types.str;
server = { };
bind_address = cfg.address; port = mkOption {
port = cfg.port; default = 8080;
secret_key = "searxxx"; 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";
};
}; };
}; };
}; };

View file

@ -1,36 +1,60 @@
{ container, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.status; cfg = config.container.module.status;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.status = {
]; enable = mkEnableOption "Status monitor.";
address = mkOption {
containers.status = container.mkContainer cfg { default = "10.1.0.22";
bindMounts = { type = types.str;
"/var/lib/uptime-kuma" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
networking = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
nameservers = lib.mkForce [ "data"
container.config.dns.address ];
];
};
services.uptime-kuma = { containers.status = container.mkContainer cfg {
enable = true; bindMounts = {
settings = { "/var/lib/uptime-kuma" = {
DATA_DIR = "/var/lib/uptime-kuma/"; hostPath = "${cfg.storage}/data";
HOST = cfg.address; isReadOnly = false;
PORT = toString cfg.port;
}; };
}; };
systemd.services.uptime-kuma = { config = { lib, ... }: container.mkContainerConfig cfg {
serviceConfig.DynamicUser = lib.mkForce false; 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;
};
}; };
}; };
}; };

View file

@ -1,31 +1,55 @@
{ container, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.stock; cfg = config.container.module.stock;
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.stock = {
]; enable = mkEnableOption "Stock management.";
address = mkOption {
containers.stock = container.mkContainer cfg { default = "10.1.0.45";
bindMounts = { type = types.str;
"/var/lib/grocy" = { };
hostPath = "${cfg.storage}/data"; port = mkOption {
isReadOnly = false; 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 { config = mkIf cfg.enable {
services.grocy = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
enable = true; "data"
dataDir = "/var/lib/grocy"; ];
hostName = cfg.domain;
nginx.enableSSL = false; containers.stock = container.mkContainer cfg {
settings = { bindMounts = {
calendar = { "/var/lib/grocy" = {
firstDayOfWeek = 1; hostPath = "${cfg.storage}/data";
showWeekNumber = true; 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";
}; };
}; };
}; };

View file

@ -1,68 +1,90 @@
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... }: with lib; let
cfg = container.config.vpn; cfg = config.container.module.vpn;
in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ wireguardPeers = let
"data" mkPeer = name: ip: PublicKey: {
"data/preshared" 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=")
]; ];
in {
boot.kernel.sysctl = { options = {
"net.ipv4.conf.all.src_valid_mark" = 1; container.module.vpn = {
}; enable = mkEnableOption "Vpn server.";
address = mkOption {
containers.vpn = container.mkContainer cfg { default = "10.1.0.23";
forwardPorts = [ type = types.str;
{ };
containerPort = cfg.port; port = mkOption {
hostPort = cfg.port; default = 51820;
protocol = "udp"; type = types.int;
} };
]; storage = mkOption {
bindMounts = { default = "${config.container.storage}/vpn";
"/var/lib/wireguard" = { type = types.str;
hostPath = "${cfg.storage}/data";
isReadOnly = false;
}; };
}; };
};
config = { ... }: container.mkContainerConfig cfg { config = mkIf cfg.enable {
environment.systemPackages = with pkgs; [ wireguard-tools ]; systemd.tmpfiles.rules = container.mkContainerDir cfg [
networking.useNetworkd = true; "data"
systemd.network = { "data/preshared"
enable = true; ];
netdevs = {
"50-wg0" = { boot.kernel.sysctl = {
netdevConfig = { "net.ipv4.conf.all.src_valid_mark" = 1;
Kind = "wireguard"; };
MTUBytes = "1300";
Name = "wg0"; containers.vpn = container.mkContainer cfg {
}; forwardPorts = [
wireguardConfig = { {
PrivateKeyFile = "/var/lib/wireguard/privkey"; containerPort = cfg.port;
ListenPort = cfg.port; hostPort = cfg.port;
}; protocol = "udp";
wireguardPeers = let }
mkPeer = name: ip: PublicKey: { ];
inherit PublicKey; bindMounts = {
PresharedKeyFile = "/var/lib/wireguard/preshared/${name}"; "/var/lib/wireguard" = {
AllowedIPs = [ "${ip}/32" ]; hostPath = "${cfg.storage}/data";
}; isReadOnly = false;
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=")
];
};
}; };
};
networks.wg0 = { config = { ... }: container.mkContainerConfig cfg {
matchConfig.Name = "wg0"; environment.systemPackages = with pkgs; [ wireguard-tools ];
address = ["10.1.1.0/24"]; networking.useNetworkd = true;
networkConfig = { systemd.network = {
IPForward = true; enable = true;
IPMasquerade = "ipv4"; 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";
};
}; };
}; };
}; };

View file

@ -1,54 +1,81 @@
{ container, lib, ... } @args: let { container, lib, config, ... }: with lib; let
cfg = container.config.watch; cfg = config.container.module.watch;
memLimit = "8G";
in { in {
systemd.tmpfiles.rules = container.mkContainerDir cfg [ options = {
"data" container.module.watch = {
"cache" 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 { config = mkIf cfg.enable {
bindMounts = { systemd.tmpfiles.rules = container.mkContainerDir cfg [
"/var/lib/jellyfin" = { "data"
hostPath = "${cfg.storage}/data"; "cache"
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 = { ... }: container.mkContainerConfig cfg { containers.watch = container.mkContainer cfg {
services.jellyfin = { bindMounts = {
enable = true; "/var/lib/jellyfin" = {
cacheDir = "/var/cache/jellyfin"; hostPath = "${cfg.storage}/data";
dataDir = "/var/lib/jellyfin"; 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;
};
}; };
}; };
} }

View file

@ -1,26 +1,50 @@
{ container, pkgs, ... } @args: let { container, pkgs, lib, config, ... }: with lib; let
cfg = container.config.yt; cfg = config.container.module.yt;
in { in {
containers.yt = container.mkContainer cfg { options = {
config = { ... }: container.mkContainerConfig cfg { container.module.yt = {
services.invidious = { enable = mkEnableOption "YouTube frontend.";
enable = true; address = mkOption {
domain = cfg.domain; default = "10.1.0.19";
port = cfg.port; type = types.str;
nginx.enable = false; };
database = { port = mkOption {
port = container.config.postgres.port; default = 3000;
host = container.config.postgres.address; type = types.int;
createLocally = false; };
passwordFile = "${pkgs.writeText "InvidiousDbPassword" "invidious"}"; domain = mkOption {
}; default = "yt.${config.container.domain}";
settings = { type = types.str;
admins = [ "root" ]; };
captcha_enabled = false; storage = mkOption {
check_tables = true; default = "${config.container.storage}/yt";
registration_enabled = false; type = types.str;
external_port = 443; };
https_only = true; };
};
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;
};
}; };
}; };
}; };

View file

@ -1,246 +1,55 @@
{ lib { lib, config, ... }: with lib; let
, const cfg = config.container;
, host in {
, storage options = {
, domain container = {
, media enable = mkEnableOption "Containers!!";
, pkgs
, ... }: {
inherit host;
# Common configuration for all the containers. autoStart = mkOption {
mkContainer = config: cfg: lib.recursiveUpdate { default = true;
# Start containers with the system by default. type = types.bool;
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;
}; };
}
) paths);
# Range of local addresses who have access to sensitive paths like admin panels. host = mkOption {
# Other addresses will get 403. default = "0.0.0.0";
localAccess = "192.168.1.0/24"; type = types.str;
};
# Per-container configurations. localAccess = mkOption {
config = { default = "0.0.0.0";
camera = { type = types.str;
address = "192.168.2.249"; };
domain = "camera.${domain}";
port = "554"; 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; config = mkIf cfg.enable {
domain = "change.${domain}"; # This is the network for all the containers.
storage = "${storage}/change"; # They are not available to the external interface by default,
}; # instead they all expose specific ports in their configuration.
cloud = { networking.nat = {
address = "10.1.0.13"; enable = true;
port = 80; internalInterfaces = [ "ve-+" ];
domain = "cloud.${domain}"; externalInterface = config.container.interface;
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;
}; };
}; };
} }

View file

@ -1,4 +1,4 @@
{ pkgs, container, ... }: let { pkgs, config, ... }: let
iconTheme = "fa-solid"; iconTheme = "fa-solid";
mkGroup = name: icon: items: { mkGroup = name: icon: items: {
@ -12,7 +12,7 @@
target = "_blank"; target = "_blank";
}; };
config = { cfg = {
title = "Dashboard"; title = "Dashboard";
subtitle = "Home"; subtitle = "Home";
header = false; header = false;
@ -41,33 +41,32 @@
}; };
links = [ links = [
(mkLink "Status" "fa-heartbeat" "https://status.voronind.com") (mkLink "Status" "fa-heartbeat" "https://${config.container.module.status.domain}")
]; ];
services = [ services = [
(mkGroup "App" "fa-server" [ (mkGroup "App" "fa-server" [
(mkLink "Change" "fa-user-secret" "https://${container.config.change.domain}") (mkLink "Change" "fa-user-secret" "https://${config.container.module.change.domain}")
(mkLink "Cloud" "fa-cloud" "https://${container.config.cloud.domain}") (mkLink "Cloud" "fa-cloud" "https://${config.container.module.cloud.domain}")
(mkLink "Download" "fa-download" "https://${container.config.download.domain}") (mkLink "Download" "fa-download" "https://${config.container.module.download.domain}")
(mkLink "Git" "fab fa-git-alt" "https://${container.config.download.domain}") (mkLink "Git" "fab fa-git-alt" "https://${config.container.module.download.domain}")
(mkLink "Iot" "fa-home" "https://${container.config.iot.domain}") (mkLink "Iot" "fa-home" "https://${config.container.module.iot.domain}")
(mkLink "Mail" "fa-envelope" "https://${container.config.mail.domain}") (mkLink "Mail" "fa-envelope" "https://${config.container.module.mail.domain}")
(mkLink "Paper" "fa-paperclip" "https://${container.config.paper.domain}") (mkLink "Paper" "fa-paperclip" "https://${config.container.module.paper.domain}")
(mkLink "Pass" "fa-key" "https://${container.config.pass.domain}") (mkLink "Pass" "fa-key" "https://${config.container.module.pass.domain}")
(mkLink "Paste" "fa-paste" "https://${container.config.paste.domain}/s") (mkLink "Paste" "fa-paste" "https://${config.container.module.paste.domain}/s")
(mkLink "Print" "fa-print" "https://${container.config.print.domain}") (mkLink "Print" "fa-print" "https://${config.container.module.print.domain}")
(mkLink "Read" "fa-book" "https://${container.config.read.domain}") (mkLink "Read" "fa-book" "https://${config.container.module.read.domain}")
(mkLink "Search" "fa-search" "https://${container.config.search.domain}") (mkLink "Search" "fa-search" "https://${config.container.module.search.domain}")
(mkLink "Stock" "fa-boxes-stacked" "https://${container.config.stock.domain}") (mkLink "Stock" "fa-boxes-stacked" "https://${config.container.module.stock.domain}")
(mkLink "Watch" "fa-film" "https://${container.config.watch.domain}") (mkLink "Watch" "fa-film" "https://${config.container.module.watch.domain}")
(mkLink "YouTube" "fab fa-youtube" "https://${container.config.yt.domain}") (mkLink "YouTube" "fab fa-youtube" "https://${config.container.module.yt.domain}")
]) ])
(mkGroup "System" "fa-shield" [ (mkGroup "System" "fa-shield" [
(mkLink "Camera" "fa-camera" "https://${container.config.camera.domain}") (mkLink "Camera" "fa-camera" "https://camera.${config.container.domain}")
# (mkLink "Hdd" "fa-hard-drive" "https://${container.config.hdd.domain}")
(mkLink "NixOS Search" "fa-snowflake" "https://search.nixos.org") (mkLink "NixOS Search" "fa-snowflake" "https://search.nixos.org")
(mkLink "Printer" "fa-print" "https://${container.config.printer.domain}") (mkLink "Printer" "fa-print" "https://printer.${config.container.domain}")
(mkLink "Router" "fa-route" "https://${container.config.router.domain}") (mkLink "Router" "fa-route" "https://router.${config.container.domain}")
]) ])
(mkGroup "Bookmark" "fa-bookmark" [ (mkGroup "Bookmark" "fa-bookmark" [
(mkLink "2gis" "fa-map-location-dot" "https://2gis.ru") (mkLink "2gis" "fa-map-location-dot" "https://2gis.ru")
@ -96,5 +95,5 @@
]; ];
}; };
in { in {
file = (pkgs.formats.yaml {}).generate "HomerConfig" config; file = (pkgs.formats.yaml {}).generate "HomerConfig" cfg;
} }

View file

@ -1,4 +1,4 @@
{ stdenv, pkgs, ... } @args: let { stdenv, pkgs, config, ... } @args: let
cfg = (import ./Config.nix args).file; cfg = (import ./Config.nix args).file;
in stdenv.mkDerivation (finalAttrs: { in stdenv.mkDerivation (finalAttrs: {
pname = "Homer"; pname = "Homer";

View file

@ -1,4 +1,4 @@
{ util, container, ... }: { { util, config, ... }: {
text = util.trimTabs '' text = util.trimTabs ''
;<?php http_response_code(403); /* ;<?php http_response_code(403); /*
; config file for PrivateBin ; config file for PrivateBin
@ -220,7 +220,7 @@
; example of DB configuration for PostgreSQL ; example of DB configuration for PostgreSQL
class = Database class = Database
[model_options] [model_options]
dsn = "pgsql:host=${container.config.postgres.address};dbname=privatebin" dsn = "pgsql:host=${config.container.module.postgres.address};dbname=privatebin"
tbl = "privatebin_" ; table prefix tbl = "privatebin_" ; table prefix
usr = "privatebin" usr = "privatebin"
pwd = "privatebin" pwd = "privatebin"

View file

@ -1,4 +1,4 @@
{ php, pkgs, util, ... } @args: let { php, pkgs, util, config, ... } @args: let
cfg = pkgs.writeText "PrivateBinConfig" (import ./Config.nix args).text; cfg = pkgs.writeText "PrivateBinConfig" (import ./Config.nix args).text;
in php.buildComposerProject (finalAttrs: { in php.buildComposerProject (finalAttrs: {
pname = "PrivateBin"; pname = "PrivateBin";

View file

@ -1,20 +1,22 @@
{ domain, util, container, ... }: let { util, config, lib, container, ... }: let
cfg = container.config.camera; domain = "camera.${config.container.domain}";
address = "192.168.2.249";
port = 554;
in { in {
${cfg.domain} = container.mkServer { ${domain} = container.mkServer {
extraConfig = util.trimTabs '' extraConfig = util.trimTabs ''
listen 443 ssl; listen 443 ssl;
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
return 301 rtsp://${cfg.address}:${cfg.port}/live/main; return 301 rtsp://${address}:${toString port}/live/main;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, config, container, ... }: let
cfg = container.config.change; cfg = config.container.module.change;
name = "change"; name = "change";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,9 +8,9 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
@ -18,8 +18,8 @@ in {
add_header Referrer-Policy 'origin'; add_header Referrer-Policy 'origin';
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, config, container, ... }: let
cfg = container.config.cloud; cfg = config.container.module.cloud;
name = "cloud"; name = "cloud";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,9 +8,9 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location ~ ^/(settings/admin|settings/users|settings/apps|login|api) { location ~ ^/(settings/admin|settings/users|settings/apps|login|api) {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
@ -19,8 +19,8 @@ in {
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, config, container, ... }: let
cfg = container.config.download; cfg = config.container.module.download;
name = "download"; name = "download";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.git; cfg = config.container.module.git;
name = "git"; name = "git";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location ~ ^/(admin|api|user) { location ~ ^/(admin|api|user) {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
location /markdown { location /markdown {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_set_header Content-Type "application/json"; proxy_set_header Content-Type "application/json";
@ -29,15 +29,15 @@ in {
} }
location / { location / {
# allow ${container.localAccess}; # allow ${config.container.localAccess};
# allow ${container.config.status.address}; # allow ${config.container.module.status.address};
# allow ${container.config.vpn.address}; # allow ${config.container.module.vpn.address};
# deny all; # deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.hdd; cfg = config.container.module.hdd;
name = "hdd"; name = "hdd";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, config, container, ... }: let
cfg = container.config.home; cfg = config.container.module.home;
name = "home"; name = "home";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.iot; cfg = config.container.module.iot;
name = "iot"; name = "iot";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,9 +8,9 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -22,8 +22,8 @@ in {
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.mail; cfg = config.container.module.mail;
name = "mail"; name = "mail";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.office; cfg = config.container.module.office;
name = "office"; name = "office";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,16 +8,16 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
# allow ${container.localAccess}; # allow ${config.container.localAccess};
# allow ${container.config.status.address}; # allow ${config.container.module.status.address};
# allow ${container.config.vpn.address}; # allow ${config.container.module.vpn.address};
# deny all; # deny all;
add_header X-Forwarded-Proto https; add_header X-Forwarded-Proto https;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.paper; cfg = config.container.module.paper;
name = "paper"; name = "paper";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.pass; cfg = config.container.module.pass;
name = "pass"; name = "pass";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.paste; cfg = config.container.module.paste;
name = "paste"; name = "paste";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -15,8 +15,8 @@ in {
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.print; cfg = config.container.module.print;
name = "print"; name = "print";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,9 +8,9 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
@ -20,8 +20,8 @@ in {
proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,22 +1,24 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.printer; address = "192.168.2.237";
name = "printer"; domain = "printer.${config.container.domain}";
port = 80;
name = "printer";
in { in {
${cfg.domain} = container.mkServer { ${domain} = container.mkServer {
extraConfig = util.trimTabs '' extraConfig = util.trimTabs ''
listen 443 ssl; listen 443 ssl;
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${address}:${toString port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.read; cfg = config.container.module.read;
name = "read"; name = "read";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,22 +1,24 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.router; address = "192.168.1.1";
name = "router"; domain = "router.${config.container.domain}";
port = 80;
name = "router";
in { in {
${cfg.domain} = container.mkServer { ${domain} = container.mkServer {
extraConfig = util.trimTabs '' extraConfig = util.trimTabs ''
listen 443 ssl; listen 443 ssl;
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${address}:${toString port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.search; cfg = config.container.module.search;
name = "search"; name = "search";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.status; cfg = config.container.module.status;
name = "sstatus"; name = "sstatus";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,21 +8,21 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location ~ ^/(dashboard|settings) { location ~ ^/(dashboard|settings) {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.stock; cfg = config.container.module.stock;
name = "stock"; name = "stock";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.watch; cfg = config.container.module.watch;
name = "watch"; name = "watch";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,15 +8,15 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

View file

@ -1,5 +1,5 @@
{ domain, util, container, ... }: let { util, container, config, ... }: let
cfg = container.config.yt; cfg = config.container.module.yt;
name = "yt"; name = "yt";
in { in {
${cfg.domain} = container.mkServer { ${cfg.domain} = container.mkServer {
@ -8,9 +8,9 @@ in {
set ''$${name} ${cfg.address}:${toString cfg.port}; set ''$${name} ${cfg.address}:${toString cfg.port};
location / { location / {
allow ${container.localAccess}; allow ${config.container.localAccess};
allow ${container.config.status.address}; allow ${config.container.module.status.address};
allow ${container.config.vpn.address}; allow ${config.container.module.vpn.address};
deny all; deny all;
proxy_pass http://''$${name}$request_uri; proxy_pass http://''$${name}$request_uri;
@ -25,8 +25,8 @@ in {
proxy_hide_header X-Content-Type-Options; proxy_hide_header X-Content-Type-Options;
} }
ssl_certificate /etc/letsencrypt/live/${domain}/fullchain.pem; ssl_certificate /etc/letsencrypt/live/${config.container.domain}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${domain}/privkey.pem; ssl_certificate_key /etc/letsencrypt/live/${config.container.domain}/privkey.pem;
include /etc/letsencrypt/conf/options-ssl-nginx.conf; include /etc/letsencrypt/conf/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem; ssl_dhparam /etc/letsencrypt/conf/ssl-dhparams.pem;
''; '';

255
flake.nix
View file

@ -137,182 +137,85 @@
url = "https://git.voronind.com/voronind/nixos.git"; url = "https://git.voronind.com/voronind/nixos.git";
}; };
# Common modules used across all the hosts. nixosConfigurations = let
nixosModules.common = let # List all files in a dir.
# This function allows me to get the list of all the files from the directories I need.
# It differs from the util.ls function because it also filters out all the directories.
lsFiles = path: map (f: "${path}/${f}") ( lsFiles = path: map (f: "${path}/${f}") (
builtins.filter (i: builtins.readFileType "${path}/${i}" == "regular") ( builtins.filter (i: builtins.readFileType "${path}/${i}" == "regular") (
builtins.attrNames (builtins.readDir path) builtins.attrNames (builtins.readDir path)
) )
); );
in {
# Here I import everything from those directories.
imports = (lsFiles ./module/common) ++ (lsFiles ./overlay) ++ [
./part/Setting.nix
./user/Root.nix
];
};
# Function to create a host. It does basic setup, like adding common modules. # Function to create a host. It does basic setup, like adding common modules.
mkHost = { system, hostname, modules } @args: nixpkgs.lib.nixosSystem { mkHost = { system, hostname, modules } @args: nixpkgs.lib.nixosSystem {
# `Inherit` is just an alias for `system = system;`, which means that # `Inherit` is just an alias for `system = system;`, which means that
# keep the `system` argument as a property in a resulting set. # keep the `system` argument as a property in a resulting set.
inherit system; inherit system;
# List of modules to use by defualt for all the hosts. # List of modules to use by defualt for all the hosts.
modules = [ modules = modules ++ [
# There I put host-specific configurations. # There I put host-specific configurations.
./host/${hostname} ./host/${hostname}
# Make a device hostname match the one from this config. # Make a device hostname match the one from this config.
{ networking.hostName = hostname; } { networking.hostName = hostname; }
# Specify current release version. # Specify current release version.
{ system.stateVersion = self.const.stateVersion; } { system.stateVersion = self.const.stateVersion; }
# Add common modules. # Add modules.
inputs.self.nixosModules.common { imports =
(lsFiles ./container) ++
(lsFiles ./module) ++
(lsFiles ./module/common) ++
(lsFiles ./module/desktop) ++
(lsFiles ./overlay) ++
(lsFiles ./user);
}
# Add Home Manager module. # Add Home Manager module.
home-manager.nixosModules.home-manager home-manager.nixosModules.home-manager
# Add Stylix module. # Add Stylix module.
stylix.nixosModules.stylix stylix.nixosModules.stylix
] ];
# Also add host-specific modules from mkHost args.
++ modules;
# SpecialArgs allows you to pass objects down to other NixOS modules. # SpecialArgs allows you to pass objects down to other NixOS modules.
specialArgs = let specialArgs = let
pkgs = nixpkgs.legacyPackages.${system}.pkgs; pkgs = nixpkgs.legacyPackages.${system}.pkgs;
lib = nixpkgs.lib; lib = nixpkgs.lib;
config = self.nixosConfigurations.${hostname}.config; config = self.nixosConfigurations.${hostname}.config;
pkgsJobber = nixpkgsJobber.legacyPackages.${system}.pkgs; pkgsJobber = nixpkgsJobber.legacyPackages.${system}.pkgs;
pkgsStable = nixpkgsJobber.legacyPackages.${system}.pkgs; pkgsStable = nixpkgsJobber.legacyPackages.${system}.pkgs;
pkgsMaster = nixpkgsJobber.legacyPackages.${system}.pkgs; pkgsMaster = nixpkgsJobber.legacyPackages.${system}.pkgs;
in {
const = self.const; # Constant values.
flake = self; # This Flake itself.
inputs = inputs; # Our dependencies.
secret = import ./part/Secret.nix {}; # Secrets (public keys).
style = import ./part/Style.nix { inherit config; }; # Style abstraction.
util = import ./part/Util.nix { inherit pkgs lib; }; # Util functions.
wallpaper = import ./part/Wallpaper.nix { inherit pkgs; }; # Wallpaper.
# Stable and Master pkgs. secret = import ./secret {}; # Secrets (public keys).
inherit pkgsStable pkgsMaster; container = import ./lib/Container.nix { inherit lib pkgs config; inherit (self) const; }; # Container utils.
util = import ./lib/Util.nix { inherit pkgs lib; }; # Util functions.
in {
flake = self;
# Stuff for Jobber container, skip this part. inherit secret container util inputs;
inherit poetry2nixJobber pkgsJobber; inherit (self) const;
# Stable and Master pkgs.
inherit pkgsStable pkgsMaster;
# Stuff for Jobber container, skip this part.
inherit poetry2nixJobber pkgsJobber;
};
}; };
};
# Bellow is the list of all the hosts I currently use. mkSystem = hostname: system: modules: {
# They call the `mkHost` function that I defined above "${hostname}" = mkHost {
# with their specific parameters. inherit hostname system modules;
# You might be interested in `live` and `nixOnDroidConfiguration` };
# for Live ISO and Android configurations respectively. };
nixosConfigurations.basic = self.mkHost {
hostname = "basic"; # Hostname to use.
system = "x86_64-linux"; # System architecture.
# Host-specific modules. liveModules = [
modules = [
# Force LTS kernel.
({ pkgs, ... }: { boot.kernelPackages = nixpkgs.lib.mkForce pkgs.linuxPackages; })
];
};
nixosConfigurations.dasha = self.mkHost {
hostname = "dasha";
system = "x86_64-linux";
modules = [
./module/AmdGpu.nix
./module/CapsToggle.nix
# ./module/Gnome.nix
./module/IntelCpu.nix
./module/PowersaveIntel.nix
./module/Print.nix
./module/RemoteBuild.nix
./module/StrongSwan.nix
./module/Sway.nix
./module/Tablet.nix
./user/Dasha.nix
];
};
nixosConfigurations.desktop = self.mkHost {
hostname = "desktop";
system = "x86_64-linux";
modules = [
./module/AmdCompute.nix
./module/AmdCpu.nix
./module/AmdGpu.nix
./module/Docker.nix
./module/Ollama.nix
./module/PowersaveAmd.nix
./module/Print.nix
./module/RemoteBuild.nix
./module/Sway.nix
./module/VirtManager.nix
./user/Voronind.nix
];
};
nixosConfigurations.fsight = self.mkHost {
hostname = "fsight";
system = "x86_64-linux";
modules = [
./module/Docker.nix
];
};
nixosConfigurations.home = self.mkHost {
hostname = "home";
system = "x86_64-linux";
modules = [
./module/AmdCpu.nix
./module/AmdGpu.nix
./module/Ftpd.nix
./module/RemoteBuilder.nix
./module/Sway.nix
./user/Voronind.nix
];
};
nixosConfigurations.laptop = self.mkHost {
hostname = "laptop";
system = "x86_64-linux";
modules = [
./module/AmdCpu.nix
./module/AmdGpu.nix
./module/CapsToggle.nix
./module/Gnome.nix
./module/PowersaveAmd.nix
./module/Print.nix
./module/RemoteBuild.nix
./module/StrongSwan.nix
./module/Tablet.nix
./user/Dasha.nix
./user/Voronind.nix
];
};
# Live ISO configuration.
nixosConfigurations.live = self.mkHost {
hostname = "live";
system = "x86_64-linux";
modules = [
# Those are basic modules for Live ISO image.
# You can discover other possible base images here:
# https://github.com/NixOS/nixpkgs/tree/master/nixos/modules/installer/cd-dvd
"${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix" "${nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-minimal.nix"
"${nixpkgs}/nixos/modules/installer/cd-dvd/channel.nix" "${nixpkgs}/nixos/modules/installer/cd-dvd/channel.nix"
# This is required for Live ISO in my case because I use NetworkManager,
# but base Live images require this.
{ networking.wireless.enable = nixpkgs.lib.mkForce false; } { networking.wireless.enable = nixpkgs.lib.mkForce false; }
# Override my settings to allow SSH logins using root password. # Override my settings to allow SSH logins using root password.
@ -320,27 +223,29 @@
{ services.openssh.settings.PermitRootLogin = nixpkgs.lib.mkForce "yes"; } { services.openssh.settings.PermitRootLogin = nixpkgs.lib.mkForce "yes"; }
# Disable auto-updates as they are not possible for Live ISO. # Disable auto-updates as they are not possible for Live ISO.
{ systemd.services.autoupdate.enable = nixpkgs.lib.mkForce false; } { module.common.autoupdate.enable = false; }
{ systemd.timers.autoupdate.enable = nixpkgs.lib.mkForce false; }
# Base Live images also require the LTS kernel. # Base Live images also require the LTS kernel.
({ pkgs, ... }: { boot.kernelPackages = nixpkgs.lib.mkForce pkgs.linuxPackages; }) { module.common.kernel.latest = false; }
]; ];
};
nixosConfigurations.work = self.mkHost { x86System = hostname: mkSystem hostname "x86_64-linux" [];
hostname = "work";
system = "x86_64-linux"; x86LiveSystem = hostname: mkSystem hostname "x86_64-linux" liveModules;
modules = [ in
./module/IntelCpu.nix # Bellow is the list of all the hosts I currently use.
./module/PowerlimitThinkpad.nix # They call the `mkSystem` function that I defined above
./module/PowersaveIntel.nix # with their specific parameters.
./module/Print.nix # You might be interested in `live` and `nixOnDroidConfiguration`
./module/RemoteBuild.nix # for Live ISO and Android configurations respectively.
./module/Sway.nix (x86System "dasha") //
./user/Voronind.nix (x86System "desktop") //
]; (x86System "fsight") //
}; (x86System "home") //
(x86System "laptop") //
(x86System "work") //
(x86LiveSystem "live")
;
# Android. # Android.
nixOnDroidConfigurations.default = nix-on-droid.lib.nixOnDroidConfiguration { nixOnDroidConfigurations.default = nix-on-droid.lib.nixOnDroidConfiguration {
@ -348,9 +253,6 @@
# Android release version. # Android release version.
{ system.stateVersion = inputs.self.const.droidStateVersion; } { system.stateVersion = inputs.self.const.droidStateVersion; }
# Common settings.
./part/Setting.nix
# I put all my Android configuration there. # I put all my Android configuration there.
./android ./android
]; ];
@ -364,9 +266,8 @@
const = self.const; # Constant values. const = self.const; # Constant values.
flake = self; # This Flake itself. flake = self; # This Flake itself.
inputs = inputs; # Our dependencies. inputs = inputs; # Our dependencies.
secret = import ./part/Secret.nix {}; # Secrets (public keys). secret = import ./lib/Secret.nix {}; # Secrets (public keys).
style = import ./part/Style.nix { config = import ./part/style/Gruvbox.nix {}; }; # Style abstraction. Stylix is not available for Android so I provide static Gruvbox style. util = import ./lib/Util.nix { inherit pkgs lib; }; # Util functions.
util = import ./part/Util.nix { inherit pkgs lib; }; # Util functions.
}; };
}; };
}; };

View file

@ -1,5 +0,0 @@
# Basic host is a dummy and has no specific configuration.
# I don't really need it, this is just a failsafe that I can definitely install and run.
{ ... }: {
imports = [ ];
}

View file

@ -3,7 +3,15 @@
./Filesystem.nix ./Filesystem.nix
]; ];
# Disable keyd. user.dasha.enable = true;
# services.keyd.enable = lib.mkForce false;
# systemd.services.keyd-application-mapper.enable = lib.mkForce false; module = {
amd.gpu.enable = true;
builder.client.enable = true;
desktop.sway.enable = true;
intel.cpu.enable = true;
print.enable = true;
strongswan.enable = true;
tablet.enable = true;
};
} }

View file

@ -3,8 +3,29 @@
./Filesystem.nix ./Filesystem.nix
]; ];
# Disable docker service. user.voronind.enable = true;
systemd.services.docker-prune.enable = lib.mkForce false;
systemd.services.docker.enable = lib.mkForce false; module = {
systemd.sockets.docker.enable = lib.mkForce false; builder.client.enable = true;
desktop.sway.enable = true;
print.enable = true;
virtmanager.enable = true;
amd = {
compute.enable = true;
cpu.enable = true;
gpu.enable = true;
};
docker = {
enable = true;
autostart = false;
rootless = false;
};
ollama = {
enable = true;
models = [
"llama3"
"llama3:70b"
];
};
};
} }

View file

@ -3,4 +3,6 @@
./Grub.nix ./Grub.nix
./Root.nix ./Root.nix
]; ];
module.docker.enable = true;
} }

View file

@ -1,27 +1,40 @@
{ pkgs { ... }: {
, const container = {
, lib enable = true;
, config
, util
, poetry2nixJobber
, pkgsJobber
, pkgsMaster
, pkgsStable
, ... }: let
args = let
# Path where all the container data will be stored.
storage = "/storage/hot/container";
# Domain used to host stuff. All the services will be like `service.${domain}`. module = {
domain = "voronind.com"; change.enable = true;
cloud.enable = true;
ddns.enable = true;
dns.enable = true;
download.enable = true;
git.enable = true;
# ISSUE: hdd.enable = true;
home.enable = true;
iot.enable = true;
jobber.enable = true;
mail.enable = true;
# ISSUE: office.enable = true;
paper.enable = true;
pass.enable = true;
paste.enable = true;
postgres.enable = true;
proxy.enable = true;
rabbitmq.enable = true;
read.enable = true;
redis.enable = true;
search.enable = true;
status.enable = true;
stock.enable = true;
vpn.enable = true;
watch.enable = true;
yt.enable = true;
};
# External IP address of the host, where all the services will listen to. storage = "/storage/hot/container";
host = "192.168.1.2"; domain = "voronind.com";
host = "192.168.1.2";
# External interface where all the services will listen on. interface = "enp7s0";
externalInterface = "enp7s0";
# Paths to media content. Later they can be plugged to the containers using the `attachMedia "photo"` function.
media = { media = {
anime = [ "/storage/cold_1/media/anime" "/storage/cold_2/media/anime" ]; anime = [ "/storage/cold_1/media/anime" "/storage/cold_2/media/anime" ];
book = [ "/storage/hot/media/book" ]; book = [ "/storage/hot/media/book" ];
@ -31,59 +44,11 @@
music = [ "/storage/cold_2/media/music" ]; music = [ "/storage/cold_2/media/music" ];
paper = [ "/storage/hot/media/paper" ]; paper = [ "/storage/hot/media/paper" ];
porn = [ "/storage/cold_2/media/porn" ]; porn = [ "/storage/cold_2/media/porn" ];
photo = [ "${storage}/cloud/data/data/cakee/files/media/photo" "/storage/cold_1/backup/tmp/photo" ]; photo = [ "/storage/hot/container/cloud/data/data/cakee/files/media/photo" "/storage/cold_1/backup/tmp/photo" ];
show = [ "/storage/cold_1/media/show" "/storage/cold_2/media/show" ]; show = [ "/storage/cold_1/media/show" "/storage/cold_2/media/show" ];
study = [ "/storage/cold_1/media/study" "/storage/cold_2/media/study" ]; study = [ "/storage/cold_1/media/study" "/storage/cold_2/media/study" ];
work = [ "/storage/cold_2/media/work" ]; work = [ "/storage/cold_2/media/work" ];
youtube = [ "/storage/cold_1/media/youtube" "/storage/cold_2/media/youtube" ]; youtube = [ "/storage/cold_1/media/youtube" "/storage/cold_2/media/youtube" ];
}; };
in {
# Pass all the arguments further.
inherit storage domain host pkgs const lib config util media externalInterface;
inherit poetry2nixJobber pkgsJobber;
inherit pkgsMaster pkgsStable;
# Pass the global container configuration.
container = import ../../container args;
};
in {
# List of containers enabled on this host.
imports = [
(import ../../container/Change.nix args)
(import ../../container/Cloud.nix args)
(import ../../container/Ddns.nix args)
(import ../../container/Dns.nix args)
(import ../../container/Download.nix args)
(import ../../container/Git.nix args)
# (import ../../container/Hdd.nix args)
(import ../../container/Home.nix args)
(import ../../container/Iot.nix args)
(import ../../container/Jobber.nix args)
(import ../../container/Mail.nix args)
(import ../../container/Office.nix args)
(import ../../container/Paper.nix args)
(import ../../container/Pass.nix args)
(import ../../container/Paste.nix args)
(import ../../container/Postgres.nix args)
(import ../../container/Print.nix args)
(import ../../container/Proxy.nix args)
(import ../../container/Rabbitmq.nix args)
(import ../../container/Read.nix args)
(import ../../container/Redis.nix args)
(import ../../container/Search.nix args)
(import ../../container/Status.nix args)
(import ../../container/Stock.nix args)
(import ../../container/Vpn.nix args)
(import ../../container/Watch.nix args)
(import ../../container/Yt.nix args)
];
# 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-+" ];
inherit (args) externalInterface;
}; };
} }

View file

@ -1,4 +1,4 @@
{ lib, ... }: { { ... }: {
imports = [ imports = [
./Backup.nix ./Backup.nix
./Container.nix ./Container.nix
@ -7,7 +7,21 @@
./Photoprocess.nix ./Photoprocess.nix
]; ];
user.voronind.enable = true;
module = {
builder.server.enable = true;
desktop.sway.enable = true;
ftpd = {
enable = true;
storage = "/storage/hot/ftp";
};
amd = {
cpu.enable = true;
gpu.enable = true;
};
};
# Disable auto-switch. # Disable auto-switch.
systemd.services.autoupdate.enable = lib.mkForce false; module.common.autoupdate.enable = false;
systemd.timers.autoupdate.enable = lib.mkForce false;
} }

View file

@ -2,4 +2,21 @@
imports = [ imports = [
./Filesystem.nix ./Filesystem.nix
]; ];
user = {
dasha.enable = true;
voronind.enable = true;
};
module = {
builder.client.enable = true;
print.enable = true;
strongswan.enable = true;
tablet.enable = true;
amd = {
compute.enable = true;
cpu.enable = true;
gpu.enable = true;
};
};
} }

View file

@ -1,3 +1 @@
{ ... }: { { ... }: { }
imports = [ ];
}

View file

@ -5,4 +5,14 @@
# Keyd Print to Macro remap. # Keyd Print to Macro remap.
services.keyd.keyboards.default.settings.main.print = "layer(layer_macro)"; services.keyd.keyboards.default.settings.main.print = "layer(layer_macro)";
user.voronind.enable = true;
module = {
builder.client.enable = true;
desktop.sway.enable = true;
intel.cpu.enable = true;
powerlimit.thinkpad.enable = true;
print.enable = true;
};
} }

63
lib/Container.nix Normal file
View file

@ -0,0 +1,63 @@
{ lib, pkgs, const, config, ... }: {
mkContainer = cfg: extra: lib.recursiveUpdate {
# Start containers with the system by default.
autoStart = config.container.autoStart;
# IP Address of the host. This is required for container to have access to the Internet.
hostAddress = config.container.host;
# Container's IP address.
localAddress = cfg.address;
# Isolate container from other hosts.
privateNetwork = true;
} extra;
# Common configuration for the system inside the container.
mkContainerConfig = cfg: extra: 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 = "";
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;
};
} extra;
# 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: ro: builtins.listToAttrs (lib.imap0 (i: path:
{
name = "/${type}/${toString i}";
value = {
hostPath = path;
isReadOnly = ro;
};
}
) config.container.media.${type});
}

View file

@ -30,4 +30,6 @@
stopIfChanged = false; stopIfChanged = false;
unitConfig.X-StopOnRemoval = false; unitConfig.X-StopOnRemoval = false;
}; };
} }

View file

@ -1,10 +1,17 @@
# AMD Rocm support (for Blender). { pkgs, lib, config, ... }: with lib; let
{ nixpkgs, pkgs, ... }: { cfg = config.module.amd.compute;
nixpkgs.config.rocmSupport = true; in {
systemd.tmpfiles.rules = [ options = {
"L+ /opt/rocm/hip - - - - ${pkgs.rocmPackages.clr}" module.amd.compute.enable = mkEnableOption "Enable AMD Rocm support i.e. for Blender.";
]; };
hardware.opengl.extraPackages = with pkgs; [
rocmPackages.clr.icd config = mkIf cfg.enable {
]; nixpkgs.config.rocmSupport = true;
systemd.tmpfiles.rules = [
"L+ /opt/rocm/hip - - - - ${pkgs.rocmPackages.clr}"
];
hardware.opengl.extraPackages = with pkgs; [
rocmPackages.clr.icd
];
};
} }

View file

@ -1,5 +1,27 @@
# AMD CPU specific configuration. { pkgs, lib, config, ... }: with lib; let
{ lib, config, ... }: { cfg = config.module.amd.cpu;
boot.kernelModules = [ "kvm-amd" ];
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; controlFile = "/sys/devices/system/cpu/cpufreq/boost";
enableCmd = "0";
disableCmd = "1";
in {
options = {
module.amd.cpu = {
enable = mkEnableOption "Enable AMD Cpu support.";
powersave.enable = mkEnableOption "Enable AMD Cpu powersave." // { default = true; };
};
};
config = mkIf cfg.enable (mkMerge [
{
boot.kernelModules = [ "kvm-amd" ];
hardware.cpu.amd.updateMicrocode = mkDefault config.hardware.enableRedistributableFirmware;
}
(mkIf cfg.powersave.enable {
module.powersave = {
enable = true;
cpu.boost = { inherit controlFile enableCmd disableCmd; };
};
})
]);
} }

View file

@ -1,17 +1,23 @@
# AMD GPU specific configuration. { pkgs, lib, config, ... }: with lib; let
# No, I do not own any Nvidia/Intel GPUs, so I have no configuration for them. cfg = config.module.amd.gpu;
{ nixpkgs, pkgs, ... }: { in {
boot.initrd.kernelModules = [ "amdgpu" ]; options = {
services.xserver.videoDrivers = [ "amdgpu" ]; module.amd.gpu.enable = mkEnableOption "Enable AMD Gpu support.";
hardware.opengl.driSupport = true; };
hardware.opengl.driSupport32Bit = true;
environment.variables.AMD_VULKAN_ICD = "RADV";
# AMDVLK was broken for me (huge stuttering). So keep it disabled, at least for now. config = mkIf cfg.enable {
# hardware.opengl.extraPackages = with pkgs; [ boot.initrd.kernelModules = [ "amdgpu" ];
# amdvlk services.xserver.videoDrivers = [ "amdgpu" ];
# ]; hardware.opengl.driSupport = true;
# hardware.opengl.extraPackages32 = with pkgs; [ hardware.opengl.driSupport32Bit = true;
# driversi686Linux.amdvlk environment.variables.AMD_VULKAN_ICD = "RADV";
# ];
# AMDVLK was broken for me (huge stuttering). So keep it disabled, at least for now.
# hardware.opengl.extraPackages = with pkgs; [
# amdvlk
# ];
# hardware.opengl.extraPackages32 = with pkgs; [
# driversi686Linux.amdvlk
# ];
};
} }

View file

@ -1,6 +0,0 @@
# Toggle language with CapsLock. My wife prefers this.
{ lib, ... }: {
services.xserver.xkb = {
options = lib.mkForce "grp:caps_toggle";
};
}

View file

@ -1,3 +1,41 @@
{ ... }: { { pkgs, lib, config, ... }: with lib; let
virtualisation.docker.enable = true; cfg = config.module.docker;
in {
options = {
module.docker = {
enable = mkEnableOption "Enable Cocker";
rootless = mkOption {
default = false;
type = types.bool;
};
autostart = mkOption {
default = true;
type = types.bool;
};
};
};
config = mkIf cfg.enable {
virtualisation.docker.enable = true;
virtualisation.docker.rootless = mkIf cfg.rootless {
enable = true;
setSocketVariable = true;
};
systemd.services.docker-prune.enable = mkForce cfg.autostart;
systemd.services.docker.enable = mkForce cfg.autostart;
systemd.sockets.docker.enable = mkForce cfg.autostart;
};
# NOTE: mkMerge example.
# config = mkIf cfg.enable (mkMerge [
# { virtualisation.docker.enable = true; }
# (mkIf cfg.rootless {
# virtualisation.docker.rootless = {
# enable = true;
# setSocketVariable = true;
# };
# })
# ]);
} }

View file

@ -1,7 +0,0 @@
{ ... }: {
virtualisation.docker.enable = true;
virtualisation.docker.rootless = {
enable = true;
setSocketVariable = true;
};
}

View file

@ -1,17 +1,31 @@
{ ... }: { { pkgs, lib, config, ... }: with lib; let
services.vsftpd = { cfg = config.module.ftpd;
enable = true; in {
anonymousUser = true; options = {
anonymousUserNoPassword = true; module.ftpd = {
anonymousUploadEnable = true; enable = mkEnableOption "Enable FTP server";
anonymousMkdirEnable = true; storage = mkOption {
anonymousUmask = "000"; default = null;
anonymousUserHome = "/storage/hot/ftp"; type = types.str;
allowWriteableChroot = true; };
writeEnable = true; };
localUsers = false; };
extraConfig = ''
anon_other_write_enable=YES config = mkIf cfg.enable {
''; services.vsftpd = {
enable = true;
anonymousUser = true;
anonymousUserNoPassword = true;
anonymousUploadEnable = true;
anonymousMkdirEnable = true;
anonymousUmask = "000";
anonymousUserHome = cfg.storage;
allowWriteableChroot = true;
writeEnable = true;
localUsers = false;
extraConfig = ''
anon_other_write_enable=YES
'';
};
}; };
} }

View file

@ -1,48 +0,0 @@
{ pkgs, lib, ... }: {
imports = [
./desktop/App.nix
./desktop/Dconf.nix
./desktop/DisplayManager.nix
./desktop/Sound.nix
./desktop/Wayland.nix
];
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 = lib.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
];
}

View file

@ -1,4 +1,27 @@
# Intel CPU specific configuration. # Intel CPU specific configuration.
{ ... }: { { pkgs, lib, config, ... }: with lib; let
boot.kernelModules = [ "kvm-intel" ]; cfg = config.module.intel.cpu;
controlFile = "/sys/devices/system/cpu/intel_pstate/no_turbo";
enableCmd = "1";
disableCmd = "0";
in {
options = {
module.intel.cpu = {
enable = mkEnableOption "Support for Shintel CPUs";
powersave.enable = mkEnableOption "Enable Shintel Cpu powersave." // { default = true; };
};
};
config = mkIf cfg.enable (mkMerge [
{
boot.kernelModules = [ "kvm-intel" ];
}
(mkIf cfg.powersave.enable {
module.powersave = {
enable = true;
cpu.boost = { inherit controlFile enableCmd disableCmd; };
};
})
]);
} }

View file

@ -1,37 +1,54 @@
# https://github.com/ollama/ollama # https://github.com/ollama/ollama
{ pkgsStable, lib, config, ... }: let { pkgsStable, lib, config, ... }: with lib; let
pkgs = pkgsStable; pkgs = pkgsStable;
cfg = config.module.ollama;
in { in {
environment = { options = {
# Add Ollama CLI app. module.ollama = {
systemPackages = with pkgs; [ ollama ]; enable = mkEnableOption "Local LLM server";
primaryModel = mkOption {
# Specify default model. default = "llama3";
variables.OLLAMA_MODEL = config.setting.ollama.primaryModel; type = types.str;
};
models = mkOption {
default = [ cfg.primaryModel ];
type = types.listOf types.str;
};
};
}; };
# Enable Ollama server. config = mkIf cfg.enable {
systemd.services.ollama = { environment = {
description = "Ollama LLM server."; # Add Ollama CLI app.
wantedBy = [ "multi-user.target" ]; systemPackages = with pkgs; [ ollama ];
wants = [ "NetworkManager-wait-online.service" ];
after = [ "NetworkManager-wait-online.service" ];
serviceConfig.Type = "simple";
script = ''
HOME=/root ${lib.getExe pkgs.ollama} serve
'';
};
# Download Ollama models. # Specify default model.
systemd.services.ollamamodel = { variables.OLLAMA_MODEL = cfg.primaryModel;
description = "Ollama LLM model."; };
wantedBy = [ "multi-user.target" ];
wants = [ "ollama.service" ]; # Enable Ollama server.
after = [ "ollama.service" ]; systemd.services.ollama = {
serviceConfig.Type = "simple"; description = "Ollama LLM server.";
script = '' wantedBy = [ "multi-user.target" ];
sleep 5 wants = [ "NetworkManager-wait-online.service" ];
${lib.getExe pkgs.ollama} pull ${config.setting.ollama.primaryModel} after = [ "NetworkManager-wait-online.service" ];
''; serviceConfig.Type = "simple";
script = ''
HOME=/root ${getExe pkgs.ollama} serve
'';
};
# Download Ollama models.
systemd.services.ollamamodel = {
description = "Ollama LLM model.";
wantedBy = [ "multi-user.target" ];
wants = [ "ollama.service" ];
after = [ "ollama.service" ];
serviceConfig.Type = "simple";
script = ''
sleep 5
${getExe pkgs.ollama} pull ${concatStringsSep " " cfg.models}
'';
};
}; };
} }

24
module/Podman.nix Normal file
View file

@ -0,0 +1,24 @@
{ lib, config, ... }: with lib; let
cfg = config.module.podman;
in {
options = {
module.podman = {
enable = mkEnableOption "OCI Podman.";
};
};
config = mkIf cfg.enable {
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;
};
};
};
}

View file

@ -1,22 +1,79 @@
# ThinkPad charge limits. # ThinkPad charge limits.
{ pkgs, lib, ... } @args: let { pkgs, lib, config, ... } @args: with lib; let
cfg = config.module.powerlimit.thinkpad;
controlFileMin = "/sys/class/power_supply/BAT0/charge_control_start_threshold"; controlFileMin = "/sys/class/power_supply/BAT0/charge_control_start_threshold";
controlFileMax = "/sys/class/power_supply/BAT0/charge_control_end_threshold"; controlFileMax = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
onMin = "40"; script = pkgs.writeShellScriptBin "powerlimit" ''
onMax = "80"; function toggle() {
offMin = "90"; if status; then
offMax = "95"; echo ${toString cfg.offMax} > ${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 { true
inherit controlFileMax controlFileMin onMin onMax offMin offMax; }
}).script;
function waybar() {
status || echo -n ""
}
function status() {
local current=$(cat ${controlFileMax})
local enabled="${toString cfg.onMax}"
[[ "''${current}" = "''${enabled}" ]]
}
''${@}
'';
in { in {
imports = [ options = {
(import ./powerlimit ({ module.powerlimit.thinkpad = {
inherit controlFileMax controlFileMin onMin onMax offMin offMax; enable = mkEnableOption "Powerlimit Service";
} // args)) 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 - - - -"
];
};
};
} }

73
module/Powersave.nix Normal file
View file

@ -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 - - - -" ];
};
};
}

View file

@ -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 ];
}

View file

@ -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 ];
}

View file

@ -1,9 +1,17 @@
{ ... }: { { pkgs, lib, config, ... }: with lib; let
services.printing = { cfg = config.module.print;
enable = true; in {
clientConf = '' options = {
DigestOptions DenyMD5 module.print.enable = mkEnableOption "Add support for printers.";
ServerName 192.168.1.2 };
'';
config = mkIf cfg.enable {
services.printing = {
enable = true;
clientConf = ''
DigestOptions DenyMD5
ServerName 192.168.1.2
'';
};
}; };
} }

View file

@ -1,29 +1,79 @@
# Module that enables remote builds. This is a client configuration. # Module that enables remote builds. This is a client configuration.
{ lib, secret, ... }: { { pkgs, lib, config, secret, ... }: with lib; let
# NOTE: Requires host private key to be present in secret.ssh.builderKeys. cfg = config.module.builder;
nix.buildMachines = [{
hostName = "nixbuilder"; serverKeyPath = "/root/.nixbuilder";
protocol = "ssh-ng"; in {
systems = [ options = {
"x86_64-linux" module.builder = {
"i686-linux" server.enable = mkEnableOption "This is a builder server.";
"aarch64-linux" client.enable = mkEnableOption "This is a builder client.";
]; };
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;
}; };
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;
};
})
];
} }

View file

@ -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" ];
};
}

View file

@ -5,6 +5,8 @@
,lib ,lib
, ... }: { , ... }: {
options.setting = with lib; { options.setting = with lib; {
# Ollama settings.
# I use the best light model by default.
ollama = mkOption { ollama = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -18,6 +20,7 @@
}; };
}; };
# Default browser settings.
browser = mkOption { browser = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -30,6 +33,7 @@
}; };
}; };
# Terminal settings.
terminal = mkOption { terminal = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -42,16 +46,19 @@
}; };
}; };
# Whether to use Dpi-aware setting in supported apps.
dpiAware = mkOption { dpiAware = mkOption {
default = false; default = false;
type = types.bool; type = types.bool;
}; };
# The key used for system-related shortcuts.
sysctrl = mkOption { sysctrl = mkOption {
default = "print"; default = "print";
type = types.str; type = types.str;
}; };
# Keyboard options.
keyboard = mkOption { keyboard = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -68,6 +75,7 @@
}; };
}; };
# Settings related to different refreshes, like top apps.
refresh = mkOption { refresh = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -80,6 +88,7 @@
}; };
}; };
# Configure steps for different actions.
step = mkOption { step = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {
@ -100,6 +109,7 @@
}; };
}; };
# Specify timeouts.
timeout = mkOption { timeout = mkOption {
default = { }; default = { };
type = types.submodule { type = types.submodule {

View file

@ -1,21 +1,29 @@
{ pkgs, ... }: { { pkgs, lib, config, ... }: with lib; let
environment.systemPackages = with pkgs; [ cfg = config.module.strongswan;
networkmanager-l2tp in {
gnome.networkmanager-l2tp options = {
# networkmanager_strongswan module.strongswan.enable = mkEnableOption "StrongSwan Vpn support.";
# strongswan };
# strongswanNM
]; config = mkIf cfg.enable {
networking.networkmanager.enableStrongSwan = true; environment.systemPackages = with pkgs; [
services.xl2tpd.enable = true; networkmanager-l2tp
services.strongswan = { gnome.networkmanager-l2tp
enable = true; # networkmanager_strongswan
secrets = [ # strongswan
"ipsec.d/ipsec.nm-l2tp.secrets" # 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"
# ];
} }

91
module/Style.nix Normal file
View file

@ -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;
};
};
};
}

View file

@ -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}"
];
};
}

View file

@ -1,6 +1,14 @@
{ pkgs, ... }: { { pkgs, lib, config, ... }: with lib; let
hardware.opentabletdriver.enable = true; cfg = config.module.tablet;
environment.systemPackages = with pkgs; [ in {
krita options = {
]; module.tablet.enable = mkEnableOption "Support for tables.";
};
config = mkIf cfg.enable {
hardware.opentabletdriver.enable = true;
environment.systemPackages = with pkgs; [
krita
];
};
} }

View file

@ -1,11 +1,19 @@
{ pkgs, ... }: { { pkgs, lib, config, ... }: with lib; let
virtualisation.libvirtd.enable = true; cfg = config.module.virtmanager;
programs.virt-manager.enable = true; 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/ config = mkIf cfg.enable {
# May also need to run: `gsettings set org.gnome.desktop.interface cursor-theme "Adwaita"` virtualisation.libvirtd.enable = true;
environment.systemPackages = with pkgs; [ programs.virt-manager.enable = true;
# glib
gnome3.adwaita-icon-theme # default gnome cursors, # 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,
];
};
} }

View file

@ -1,8 +1,17 @@
# I want to pull all the Apk files in their current state # I want to pull all the Apk files in their current state
# so that I always have an access to clients that match # so that I always have an access to clients that match
# my service versions. # my service versions.
{ pkgs, ... } @args: let { pkgs, lib, config, ... } @args: with lib; let
cfg = config.module.common.apks;
package = (pkgs.callPackage ./apks args); package = (pkgs.callPackage ./apks args);
in { 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;
};
} }

View file

@ -2,41 +2,51 @@
# This is a systemd service that pulls updates every hour. # This is a systemd service that pulls updates every hour.
# Unlike system.autoUpgrade, this script also verifies my git signature # Unlike system.autoUpgrade, this script also verifies my git signature
# to prevent unathorized changes to hosts. # to prevent unathorized changes to hosts.
{ const, pkgs, lib, secret, util, ... }: { { const, pkgs, lib, util, config, ... }: with lib; let
systemd.services.autoupdate = util.mkStaticSystemdService { cfg = config.module.common.autoupdate;
enable = true; in {
description = "Signed system auto-update."; options = {
serviceConfig.Type = "oneshot"; module.common.autoupdate = {
path = with pkgs; [ enable = mkEnableOption "System auto-updates." // { default = true; };
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" ];
}; };
systemd.timers.autoupdate = { config = mkIf cfg.enable {
enable = true; systemd.services.autoupdate = util.mkStaticSystemdService {
timerConfig = { enable = true;
OnCalendar = "hourly"; description = "Signed system auto-update.";
Persistent = true; serviceConfig.Type = "oneshot";
Unit = "autoupdate.service"; path = with pkgs; [
# RandomizedDelaySec = 60; 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" ];
}; };
} }

View file

@ -1,4 +1,4 @@
{ lib, style, util, pkgs, ... } @args: let { lib, util, pkgs, ... } @args: let
bash = import ./bash args; bash = import ./bash args;
in { in {
# Add my bash configuration to all *interactive* shells. # Add my bash configuration to all *interactive* shells.

View file

@ -1,8 +1,16 @@
{ pkgs, ... }: { { pkgs, lib, config, ... }: with lib; let
# Distrobox works best with Podman, so enable it here. cfg = config.module.common.distrobox;
imports = [ ./Podman.nix ]; in {
options = {
module.common.distrobox = {
enable = mkEnableOption "Distrobox." // { default = true; };
};
};
environment.systemPackages = with pkgs; [ config = mkIf cfg.enable {
distrobox # Distrobox works best with Podman, so enable it here.
]; module.podman.enable = true;
environment.systemPackages = with pkgs; [ distrobox ];
};
} }

View file

@ -13,6 +13,7 @@
}; };
# /etc overlay. # /etc overlay.
# ISSUE: Should be fixed when you read this. Try it!
# boot.initrd.systemd.enable = true; # boot.initrd.systemd.enable = true;
# systemd.sysusers.enable = true; # systemd.sysusers.enable = true;
# system.etc.overlay = { # system.etc.overlay = {

View file

@ -1,59 +1,76 @@
{ pkgs, ... }: { { pkgs, config, lib, ... }: with lib; let
# Use latest kernel. cfg = config.module.common.kernel;
boot.kernelPackages = pkgs.linuxPackages_latest; in {
options = {
boot.kernel.sysctl = { module.common.kernel = {
# # Spoof protection. latest = mkOption {
# "net.ipv4.conf.default.rp_filter" = 1; default = true;
# "net.ipv4.conf.all.rp_filter" = 1; type = types.bool;
};
# # 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;
}; };
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;
};
}
];
} }

View file

@ -1,88 +1,98 @@
{ pkgs, config, ... }: { { pkgs, config, lib, ... }: with lib; let
environment.systemPackages = with pkgs; [ keyd ]; cfg = config.module.common.keyd;
in {
services.keyd = { options = {
enable = true; module.common.keyd = {
keyboards.default = { enable = mkEnableOption "Keyboard remaps." // { default = true; };
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 config = mkIf cfg.enable {
users.groups.keyd = {}; environment.systemPackages = with pkgs; [ keyd ];
systemd.services.keyd.serviceConfig.CapabilityBoundingSet = [ "CAP_SETGID" ];
# Debug toggle just in case I need it again. services.keyd = {
# systemd.services.keyd.environment.KEYD_DEBUG = "1"; 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";
};
} }

Some files were not shown because too many files have changed in this diff Show more