refactor: added flake parts

This commit is contained in:
Leyla Becker 2026-04-06 22:18:17 -05:00
parent db7ac35613
commit 88041e86bd
66 changed files with 3538 additions and 2163 deletions

View file

@ -0,0 +1,18 @@
{...}: {
flake.darwinModules.hesperiumConfiguration = {...}: {
host = {
users = {
leyla = {
isDesktopUser = true;
isTerminalUser = true;
isPrincipleUser = true;
};
eve.isNormalUser = false;
};
};
system.stateVersion = 5;
nixpkgs.hostPlatform = "aarch64-darwin";
};
}

View file

@ -0,0 +1,15 @@
# leyla macbook
{
inputs,
config,
...
}: {
flake.darwinConfigurations.hesperium = inputs.nix-darwin.lib.darwinSystem {
system = "aarch64-darwin";
modules = [
config.flake.darwinModules.darwinModules
config.flake.darwinModules.hesperiumConfiguration
];
specialArgs = {inherit inputs;};
};
}

View file

@ -0,0 +1,53 @@
{...}: {
flake.homeModules.eveBaseConfiguration = {osConfig, ...}: let
userConfig = osConfig.host.users.eve;
in {
home = {
username = userConfig.name;
homeDirectory = osConfig.users.users.eve.home;
# This value determines the Home Manager release that your configuration is
# compatible with. This helps avoid breakage when a new Home Manager release
# introduces backwards incompatible changes.
#
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
stateVersion = "23.11"; # Please read the comment before changing.
# Home Manager is pretty good at managing dotfiles. The primary way to manage
# plain files is through 'home.file'.
file = {
# # Building this configuration will create a copy of 'dotfiles/screenrc' in
# # the Nix store. Activating the configuration will then make '~/.screenrc' a
# # symlink to the Nix store copy.
# ".screenrc".source = dotfiles/screenrc;
# # You can also set the file content immediately.
# ".gradle/gradle.properties".text = ''
# org.gradle.console=verbose
# org.gradle.daemon.idletimeout=3600000
# '';
};
# Home Manager can also manage your environment variables through
# 'home.sessionVariables'. If you don't want to manage your shell through Home
# Manager then you have to manually source 'hm-session-vars.sh' located at
# either
#
# ~/.nix-profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# /etc/profiles/per-user/leyla/etc/profile.d/hm-session-vars.sh
#
sessionVariables = {
# EDITOR = "emacs";
};
};
};
}

View file

@ -0,0 +1,11 @@
{config, ...}: let
hm = config.flake.homeModules;
in {
flake.homeModules.eveConfiguration = {...}: {
imports = [
hm.eveBaseConfiguration
hm.eveGnomeconf
hm.evePackages
];
};
}

View file

@ -0,0 +1,41 @@
{...}: {
flake.homeModules.eveGnomeconf = {
osConfig,
lib,
...
}: {
config = {
gnome = lib.mkMerge [
{
colorScheme = "prefer-dark";
accentColor = "slate";
clockFormat = "24h";
nightLight = {
enable = true;
automatic = false;
fromTime = 12.0;
toTime = 11.999999999999;
temperature = 2700;
};
extraWindowControls = true;
extensions = {
dash-to-panel = {
enable = true;
};
};
}
(lib.mkIf (osConfig.networking.hostName == "horizon") {
displayScaling = 125;
experimentalFeatures = {
scaleMonitorFramebuffer = true;
};
})
];
dconf = {
enable = true;
};
};
};
}

View file

@ -0,0 +1,93 @@
{...}: {
flake.homeModules.evePackages = {
lib,
pkgs,
config,
osConfig,
...
}: let
userConfig = osConfig.host.users.eve;
hardware = osConfig.host.hardware;
in {
config = {
nixpkgs.config = {
allowUnfree = true;
};
# Packages that can be installed without any extra configuration
# See https://search.nixos.org/packages for all options
home.packages = lib.lists.optionals userConfig.isDesktopUser (
with pkgs; [
gnomeExtensions.dash-to-panel
claude-code
friture
]
);
# Packages that need to be installed with some extra configuration
# See https://home-manager-options.extranix.com/ for all options
programs = lib.mkMerge [
{
# Let Home Manager install and manage itself.
home-manager.enable = true;
}
(lib.mkIf (config.user.isDesktopUser || config.user.isTerminalUser) {
git = {
enable = true;
signing.format = "openpgp";
settings = {
user.name = "Eve";
user.email = "evesnrobins@gmail.com";
init.defaultBranch = "main";
};
};
openssh = {
enable = true;
hostKeys = [
{
type = "ed25519";
path = "${config.home.username}_${osConfig.networking.hostName}_ed25519";
}
];
};
})
(lib.mkIf config.user.isDesktopUser {
vscode = {
enable = true;
package = pkgs.vscodium;
};
firefox.enable = true;
bitwarden.enable = true;
discord.enable = true;
makemkv.enable = true;
signal-desktop.enable = true;
steam.enable = true;
piper.enable = hardware.piperMouse.enable;
krita.enable = true;
ungoogled-chromium.enable = true;
inkscape.enable = true;
obsidian.enable = true;
obs-studio.enable = true;
kdenlive.enable = true;
tor-browser.enable = true;
olympus.enable = true;
libreoffice.enable = true;
noita-entangled-worlds.enable = true;
opencode.enable = osConfig.host.ai.enable;
e621-downloader.enable = true;
# Windows applications that we need to figure out how to install
guild-wars-2.enable = false;
vortex.enable = false;
dungeon-draft.enable = false;
vmware-workstation.enable = true;
})
];
};
};
}

View file

@ -0,0 +1,24 @@
{...}: {
flake.homeModules.gitConfiguration = {osConfig, ...}: {
impermanence.fallbackPersistence.enable = false;
home = {
username = osConfig.users.users.git.name;
homeDirectory = osConfig.users.users.git.home;
# This value determines the Home Manager release that your configuration is
# compatible with. This helps avoid breakage when a new Home Manager release
# introduces backwards incompatible changes.
#
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
stateVersion = "23.11"; # Please read the comment before changing.
};
programs.ssh.extraConfig = ''
AuthorizedKeysFile
/var/lib/forgejo/.ssh/authorized_keys
'';
};
}

View file

@ -0,0 +1,90 @@
{...}: {
flake.homeModules.leylaBaseConfiguration = {
pkgs,
config,
osConfig,
...
}: {
config = {
impermanence.enable = osConfig.storage.impermanence.enable;
# Home Manager needs a bit of information about you and the paths it should
# manage.
home = {
username = osConfig.host.users.leyla.name;
homeDirectory = osConfig.users.users.leyla.home;
# This value determines the Home Manager release that your configuration is
# compatible with. This helps avoid breakage when a new Home Manager release
# introduces backwards incompatible changes.
#
# You should not change this value, even if you update Home Manager. If you do
# want to update the value, then make sure to first check the Home Manager
# release notes.
stateVersion = "23.11"; # Please read the comment before changing.
# Home Manager is pretty good at managing dotfiles. The primary way to manage
# plain files is through 'home.file'.
file = {
# # Building this configuration will create a copy of 'dotfiles/screenrc' in
# # the Nix store. Activating the configuration will then make '~/.screenrc' a
# # symlink to the Nix store copy.
# ".screenrc".source = dotfiles/screenrc;
# # You can also set the file content immediately.
# ".gradle/gradle.properties".text = ''
# org.gradle.console=verbose
# org.gradle.daemon.idletimeout=3600000
# '';
"${config.xdg.configHome}/user-dirs.dirs" = {
force = true;
text = ''
# This file is written by xdg-user-dirs-update
# If you want to change or add directories, just edit the line you're
# interested in. All local changes will be retained on the next run.
# Format is XDG_xxx_DIR="$HOME/yyy", where yyy is a shell-escaped
# homedir-relative path, or XDG_xxx_DIR="/yyy", where /yyy is an
# absolute path. No other format is supported.
#
XDG_DESKTOP_DIR="$HOME/desktop"
XDG_DOWNLOAD_DIR="$HOME/downloads"
XDG_DOCUMENTS_DIR="$HOME/documents"
XDG_TEMPLATES_DIR="$HOME/documents/templates"
XDG_MUSIC_DIR="$HOME/documents/music"
XDG_PICTURES_DIR="$HOME/documents/photos"
XDG_VIDEOS_DIR="$HOME/documents/videos"
XDG_PUBLICSHARE_DIR="$HOME/documents/public"
'';
};
};
keyboard.layout = "us,it,de";
# Home Manager can also manage your environment variables through
# 'home.sessionVariables'. If you don't want to manage your shell through Home
# Manager then you have to manually source 'hm-session-vars.sh' located at
# either
#
# ~/.nix-profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
#
# or
#
# /etc/profiles/per-user/leyla/etc/profile.d/hm-session-vars.sh
#
sessionVariables = {
# EDITOR = "emacs";
};
};
# TODO: move this into a fonts module
home.packages = with pkgs; [
aileron
];
fonts.fontconfig.enable = true;
};
};
}

View file

@ -0,0 +1,49 @@
{...}: {
flake.homeModules.leylaDconf = {...}: {
config = {
gnome = {
extraWindowControls = true;
colorScheme = "prefer-dark";
clockFormat = "24h";
nightLight = {
enable = true;
automatic = false;
fromTime = 12.0;
toTime = 11.999999999999;
temperature = 2700;
};
extensions = {
dash-to-dock = {
enable = true;
options = {
"dock-position" = "LEFT";
"intellihide-mode" = "ALL_WINDOWS";
"show-trash" = false;
"require-pressure-to-show" = false;
"show-mounts" = false;
};
};
};
hotkeys = {
"Open Terminal" = {
binding = "<Super>t";
command = "kgx";
};
"Open Firefox" = {
binding = "<Super>f";
command = "firefox";
};
};
};
dconf = {
enable = true;
settings = {
"org/gnome/shell" = {
favorite-apps = ["org.gnome.Nautilus.desktop" "firefox.desktop" "codium.desktop" "steam.desktop" "org.gnome.Console.desktop"];
};
};
};
};
};
}

View file

@ -0,0 +1,23 @@
{config, ...}: let
hm = config.flake.homeModules;
in {
flake.homeModules.leylaConfiguration = {...}: {
imports = [
hm.leylaBaseConfiguration
hm.leylaDconf
hm.leylaI18n
hm.leylaImpermanence
hm.leylaPackages
hm.leylaDirenv
hm.leylaGit
hm.leylaMakemkv
hm.leylaOpenssh
hm.leylaFirefox
hm.leylaFirefoxProfile
hm.leylaFirefoxBookmarks
hm.leylaFirefoxHarden
hm.leylaVscode
hm.leylaVscodeUserWords
];
};
}

View file

@ -0,0 +1,14 @@
{...}: {
flake.homeModules.leylaI18n = {...}: {
i18n = {
defaultLocale = "en_IE.UTF-8";
extraLocaleSettings = {
# LC_ADDRESS = "en_IE.UTF-8"; # lets just get used to this one now
# LC_TELEPHONE = "en_IE.UTF-8"; # lets just get used to this one now
LC_MONETARY = "en_US.UTF-8"; # to be changed once I move
LC_PAPER = "en_US.UTF-8"; # convenient for american printers until I move
};
};
};
}

View file

@ -0,0 +1,21 @@
{...}: {
flake.homeModules.leylaImpermanence = {
lib,
config,
...
}: {
config = lib.mkIf (config.impermanence.enable) {
home.persistence."${config.impermanence.persistencePath}" = {
directories = [
"desktop"
"downloads"
"documents"
];
files = [
".bash_history" # keep shell history around
"${config.xdg.dataHome}/recently-used.xbel" # gnome recently viewed files
];
};
};
};
}

View file

@ -0,0 +1,91 @@
{...}: {
flake.homeModules.leylaPackages = {
lib,
pkgs,
config,
osConfig,
...
}: let
hardware = osConfig.host.hardware;
in {
config = lib.mkMerge [
{
programs = lib.mkMerge [
{
# Let Home Manager install and manage itself.
home-manager.enable = true;
}
(lib.mkIf (config.user.isTerminalUser || config.user.isDesktopUser) {
bash.enable = true;
git.enable = true;
openssh.enable = true;
})
(lib.mkIf config.user.isDesktopUser {
bitwarden.enable = true;
obs-studio.enable = hardware.graphicsAcceleration.enable;
qbittorrent.enable = true;
prostudiomasters.enable = true;
protonvpn-gui.enable = true;
dbeaver-bin.enable = true;
bruno.enable = true;
piper.enable = hardware.piperMouse.enable;
proxmark3.enable = true;
openrgb.enable = hardware.openRGB.enable;
via.enable = hardware.viaKeyboard.enable;
claude-code.enable = osConfig.host.ai.enable;
opencode.enable = osConfig.host.ai.enable;
davinci-resolve.enable = hardware.graphicsAcceleration.enable;
mfoc.enable = true;
})
(lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) {
anki.enable = true;
android-studio.enable = true;
makemkv.enable = true;
discord.enable = true;
signal-desktop.enable = true;
calibre.enable = true;
obsidian.enable = true;
jetbrains.idea-oss.enable = true;
vscode.enable = true;
firefox.enable = true;
steam.enable = true;
krita.enable = true;
ungoogled-chromium.enable = true;
libreoffice.enable = true;
mapillary-uploader.enable = true;
inkscape.enable = true;
gimp.enable = true;
freecad.enable = true;
onionshare.enable = true;
pdfarranger.enable = true;
picard.enable = true;
qflipper.enable = true;
openvpn.enable = true;
noisetorch.enable = true;
noita-entangled-worlds.enable = true;
tor-browser.enable = true;
gdx-liftoff.enable = true;
proton-mail-pwa.enable = true;
proton-calendar-pwa.enable = true;
matrix-cyberia-pwa.enable = true;
kicad.enable = true;
})
];
}
(lib.mkIf config.user.isTerminalUser {
home.packages = with pkgs; [
# command line tools
sox
yt-dlp
ffmpeg
imagemagick
];
})
(lib.mkIf config.user.isDesktopUser {
nixpkgs.config = {
allowUnfree = true;
};
})
];
};
}

View file

@ -0,0 +1,24 @@
{...}: {
flake.homeModules.leylaDirenv = {
lib,
config,
osConfig,
...
}: let
userConfig = osConfig.host.users.leyla;
in {
config = lib.mkIf userConfig.isDesktopUser {
programs = {
direnv = {
enable = true;
enableBashIntegration = true;
nix-direnv.enable = true;
config = {
global.hide_env_diff = true;
whitelist.exact = ["${config.home.homeDirectory}/documents/code/nix-config"];
};
};
};
};
};
}

View file

@ -0,0 +1,163 @@
{...}: {
flake.homeModules.leylaFirefoxBookmarks = {...}: {
programs.firefox = {
profiles.leyla = {
bookmarks = {
force = true;
settings = [
# Personal Services
{
name = "Media";
url = "https://media.jan-leila.com/";
keyword = "";
tags = [""];
}
{
name = "Photos";
url = "https://photos.jan-leila.com";
keyword = "";
tags = [""];
}
{
name = "Git";
url = "https://git.jan-leila.com/";
keyword = "";
tags = [""];
}
{
name = "Home Automation";
url = "https://home.jan-leila.com/";
keyword = "";
tags = [""];
}
{
name = "Search";
url = "https://search.jan-leila.com/";
keyword = "";
tags = [""];
}
{
name = "Budget";
url = "https://search.jan-leila.com/";
keyword = "";
tags = [""];
}
{
name = "Documents";
url = "https://documents.jan-leila.com/";
keyword = "";
tags = [""];
}
# Defiant Server Services
{
name = "QBittorrent";
url = "http://defiant:8084";
keyword = "";
tags = ["defiant"];
}
{
name = "Sonarr";
url = "http://defiant:8989";
keyword = "";
tags = ["defiant"];
}
{
name = "Radarr";
url = "http://defiant:7878";
keyword = "";
tags = ["defiant"];
}
{
name = "Bazarr";
url = "http://defiant:6767";
keyword = "";
tags = ["defiant"];
}
{
name = "Lidarr";
url = "http://defiant:8686";
keyword = "";
tags = ["defiant"];
}
{
name = "Jackett";
url = "http://defiant:9117";
keyword = "";
tags = ["defiant"];
}
{
name = "Crab-hole DNS";
url = "http://defiant:8085";
keyword = "";
tags = ["defiant"];
}
# External Services
{
name = "Mail";
url = "https://mail.protonmail.com";
keyword = "";
tags = [""];
}
{
name = "Open Street Map";
url = "https://www.openstreetmap.org/";
keyword = "";
tags = [""];
}
{
name = "Password Manager";
url = "https://vault.bitwarden.com/";
keyword = "";
tags = [""];
}
{
name = "Mastodon";
url = "https://mspsocial.net";
keyword = "";
tags = [""];
}
{
name = "Linked In";
url = "https://www.linkedin.com/";
keyword = "";
tags = [""];
}
{
name = "Job Search";
url = "https://www.jobsinnetwork.com/?state=cleaned_history&language%5B%5D=en&query=react&locations.countryCode%5B%5D=IT&locations.countryCode%5B%5D=DE&locations.countryCode%5B%5D=NL&experience%5B%5D=medior&experience%5B%5D=junior&page=1";
keyword = "";
tags = [""];
}
{
name = "React Docs";
url = "https://react.dev/";
keyword = "";
tags = [""];
}
{
name = "Cyberia Matrix";
url = "https://chat.cyberia.club";
keyword = "";
tags = [""];
}
{
name = "Cyberia Git";
url = "https://git.cyberia.club";
keyword = "";
tags = [""];
}
# Template
# {
# name = "";
# url = "";
# keyword = "";
# tags = [""];
# }
];
};
};
};
};
}

View file

@ -0,0 +1,9 @@
{...}: {
flake.homeModules.leylaFirefox = {...}: {
config = {
programs.firefox = {
enable = true;
};
};
};
}

View file

@ -0,0 +1,193 @@
{...}: {
flake.homeModules.leylaFirefoxProfile = {
lib,
pkgs,
inputs,
...
}: {
programs.firefox = {
profiles.leyla = {
settings = {
"browser.search.defaultenginename" = "Searx";
"browser.search.order.1" = "Searx";
};
search = {
force = true;
default = "Searx";
engines = {
"Nix Packages" = {
urls = [
{
template = "https://search.nixos.org/packages";
params = [
{
name = "type";
value = "packages";
}
{
name = "query";
value = "{searchTerms}";
}
];
}
];
icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
definedAliases = ["@np"];
};
"NixOS Wiki" = {
urls = [{template = "https://nixos.wiki/index.php?search={searchTerms}";}];
icon = "https://nixos.wiki/favicon.png";
updateInterval = 24 * 60 * 60 * 1000; # every day
definedAliases = ["@nw"];
};
"Searx" = {
urls = [{template = "https://search.jan-leila.com/?q={searchTerms}";}];
icon = "https://nixos.wiki/favicon.png";
updateInterval = 24 * 60 * 60 * 1000; # every day
definedAliases = ["@searx"];
};
};
};
extensions.packages = with inputs.firefox-addons.packages.${pkgs.stdenv.hostPlatform.system}; [
bitwarden
terms-of-service-didnt-read
multi-account-containers
shinigami-eyes
ublock-origin
sponsorblock
dearrow
df-youtube
return-youtube-dislikes
privacy-badger
decentraleyes
clearurls
localcdn
snowflake
pkgs.firefox-extensions.deutsch-de-language-pack
dictionary-german
tab-session-manager
pkgs.firefox-extensions.italiano-it-language-pack
pkgs.firefox-extensions.dizionario-italiano
];
settings = {
# Disable irritating first-run stuff
"browser.disableResetPrompt" = true;
"browser.download.panel.shown" = true;
"browser.feeds.showFirstRunUI" = false;
"browser.messaging-system.whatsNewPanel.enabled" = false;
"browser.rights.3.shown" = true;
"browser.shell.checkDefaultBrowser" = false;
"browser.shell.defaultBrowserCheckCount" = 1;
"browser.startup.homepage_override.mstone" = "ignore";
"browser.uitour.enabled" = false;
"startup.homepage_override_url" = "";
"trailhead.firstrun.didSeeAboutWelcome" = true;
"browser.bookmarks.restore_default_bookmarks" = false;
"browser.bookmarks.addedImportButton" = true;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
# Usage Experience
"browser.startup.homepage" = "about:home";
"browser.download.useDownloadDir" = false;
"browser.uiCustomization.state" = builtins.toJSON {
"currentVersion" = 20;
"newElementCount" = 6;
"dirtyAreaCache" = [
"nav-bar"
"PersonalToolbar"
"toolbar-menubar"
"TabsToolbar"
"unified-extensions-area"
"vertical-tabs"
];
"placements" = {
"widget-overflow-fixed-list" = [];
"unified-extensions-area" = [
# bitwarden
"_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action"
"ublock0_raymondhill_net-browser-action"
"sponsorblocker_ajay_app-browser-action"
"dearrow_ajay_app-browser-action"
"jid1-mnnxcxisbpnsxq_jetpack-browser-action"
"_testpilot-containers-browser-action"
"addon_simplelogin-browser-action"
"_74145f27-f039-47ce-a470-a662b129930a_-browser-action"
"jid1-bofifl9vbdl2zq_jetpack-browser-action"
"dfyoutube_example_com-browser-action"
"_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action"
"_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action"
"_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browse-action"
"jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action"
];
"nav-bar" = [
"back-button"
"forward-button"
"stop-reload-button"
"urlbar-container"
"downloads-button"
"unified-extensions-button"
"reset-pbm-toolbar-button"
];
"toolbar-menubar" = [
"menubar-items"
];
"TabsToolbar" = [
"firefox-view-button"
"tabbrowser-tabs"
"new-tab-button"
"alltabs-button"
];
"vertical-tabs" = [];
"PersonalToolbar" = [
"import-button"
"personal-bookmarks"
];
};
"seen" = [
"save-to-pocket-button"
"developer-button"
"privacy_privacy_com-browser-action"
"sponsorblocker_ajay_app-browser-action"
"ublock0_raymondhill_net-browser-action"
"addon_simplelogin-browser-action"
"dearrow_ajay_app-browser-action"
"_446900e4-71c2-419f-a6a7-df9c091e268b_-browser-action"
"_74145f27-f039-47ce-a470-a662b129930a_-browser-action"
"jid1-bofifl9vbdl2zq_jetpack-browser-action"
"dfyoutube_example_com-browser-action"
"_testpilot-containers-browser-action"
"_b86e4813-687a-43e6-ab65-0bde4ab75758_-browser-action"
"jid1-mnnxcxisbpnsxq_jetpack-browser-action"
"_762f9885-5a13-4abd-9c77-433dcd38b8fd_-browser-action"
"_b11bea1f-a888-4332-8d8a-cec2be7d24b9_-browser-action"
"jid0-3guet1r69sqnsrca5p8kx9ezc3u_jetpack-browser-action"
];
};
"browser.newtabpage.activity-stream.feeds.topsites" = false;
"browser.newtabpage.activity-stream.showSponsoredTopSites" = false;
"browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts" = false;
"browser.newtabpage.blocked" = lib.genAttrs [
# Facebook
"4gPpjkxgZzXPVtuEoAL9Ig=="
# Reddit
"gLv0ja2RYVgxKdp0I5qwvA=="
# Amazon
"K00ILysCaEq8+bEqV/3nuw=="
# Twitter
"T9nJot5PurhJSy8n038xGA=="
] (_: 1);
"identity.fxaccounts.enabled" = false;
};
};
};
};
}

View file

@ -0,0 +1,52 @@
{...}: {
flake.homeModules.leylaFirefoxHarden = {...}: {
programs.firefox = {
profiles.leyla = {
settings = {
# Security
"privacy.trackingprotection.enabled" = true;
"dom.security.https_only_mode" = true;
"dom.security.https_only_mode_pbm" = true;
"dom.security.https_only_mode_error_page_user_suggestions" = true;
# Privacy & Data Protection
"extensions.formautofill.addresses.enabled" = false;
"extensions.formautofill.creditCards.enabled" = false;
"signon.rememberSignons" = false;
"privacy.sanitize.sanitizeOnShutdown" = true;
"privacy.clearOnShutdown_v2.cache" = true;
"privacy.clearOnShutdown_v2.cookiesAndStorage" = true;
"privacy.clearOnShutdown_v2.historyFormDataAndDownloads" = true;
"urlclassifier.trackingSkipURLs" = "";
"urlclassifier.features.socialtracking.skipURLs" = "";
# Disable telemetry and data collection
"app.shield.optoutstudies.enabled" = false;
"browser.discovery.enabled" = false;
"browser.newtabpage.activity-stream.feeds.telemetry" = false;
"browser.newtabpage.activity-stream.telemetry" = false;
"browser.ping-centre.telemetry" = false;
"datareporting.healthreport.service.enabled" = false;
"datareporting.healthreport.uploadEnabled" = false;
"datareporting.policy.dataSubmissionEnabled" = false;
"datareporting.sessions.current.clean" = true;
"devtools.onboarding.telemetry.logged" = false;
"toolkit.telemetry.archive.enabled" = false;
"toolkit.telemetry.bhrPing.enabled" = false;
"toolkit.telemetry.enabled" = false;
"toolkit.telemetry.firstShutdownPing.enabled" = false;
"toolkit.telemetry.hybridContent.enabled" = false;
"toolkit.telemetry.newProfilePing.enabled" = false;
"toolkit.telemetry.prompted" = 2;
"toolkit.telemetry.rejected" = true;
"toolkit.telemetry.reportingpolicy.firstRun" = false;
"toolkit.telemetry.server" = "";
"toolkit.telemetry.shutdownPingSender.enabled" = false;
"toolkit.telemetry.unified" = false;
"toolkit.telemetry.unifiedIsOptIn" = false;
"toolkit.telemetry.updatePing.enabled" = false;
};
};
};
};
}

View file

@ -0,0 +1,16 @@
{...}: {
flake.homeModules.leylaGit = {...}: {
config = {
programs = {
git = {
signing.format = "openpgp";
settings = {
user.name = "Leyla Becker";
user.email = "git@jan-leila.com";
init.defaultBranch = "main";
};
};
};
};
};
}

View file

@ -0,0 +1,19 @@
{...}: {
flake.homeModules.leylaMakemkv = {
config,
inputs,
...
}: {
config = {
sops.secrets = {
"application-keys/makemkv" = {
sopsFile = "${inputs.secrets}/application-keys.yaml";
};
};
programs.makemkv = {
appKeyFile = config.sops.placeholder."application-keys/makemkv";
destinationDir = "/home/leyla/downloads/makemkv";
};
};
};
}

View file

@ -0,0 +1,25 @@
{...}: {
flake.homeModules.leylaOpenssh = {
config,
osConfig,
...
}: {
config = {
programs = {
openssh = {
authorizedKeys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJHeItmt8TRW43uNcOC+eIurYC7Eunc0V3LGocQqLaYj leyla@horizon"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIILimFIW2exEH/Xo7LtXkqgE04qusvnPNpPWSCeNrFkP leyla@defiant"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKBiZkg1c2aaNHiieBX4cEziqvJVj9pcDfzUrKU/mO0I leyla@twilight"
];
hostKeys = [
{
type = "ed25519";
path = "${config.home.username}_${osConfig.networking.hostName}_ed25519";
}
];
};
};
};
};
}

View file

@ -0,0 +1,140 @@
{...}: {
flake.homeModules.leylaVscode = {
lib,
pkgs,
config,
osConfig,
...
}: let
nix-development-enabled = osConfig.host.nix-development.enable;
ai-tooling-enabled = osConfig.host.ai.enable;
in {
config = lib.mkIf config.user.isDesktopUser {
programs = {
bash.shellAliases = {
code = "codium";
};
vscode = {
package = pkgs.vscodium;
mutableExtensionsDir = false;
profiles.default = {
enableUpdateCheck = false;
enableExtensionUpdateCheck = false;
userSettings = lib.mkMerge [
{
"javascript.updateImportsOnFileMove.enabled" = "always";
"editor.tabSize" = 2;
"editor.insertSpaces" = false;
# "terminal.integrated.fontFamily" = "'Droid Sans Mono', 'monospace', monospace";
}
];
extraExtensions = {
# vs code feel
oneDark.enable = true;
atomKeybindings.enable = true;
openRemoteSsh.enable = true;
# openDyslexicFont.enable = false;
# html development
autoRenameTag.enable = true;
liveServer.enable = true;
# js development
es7ReactJsSnippets.enable = true;
tauriVscode.enable = true;
vscodeEslint.enable = true;
vscodeJest.enable = true;
vitest.enable = true;
vscodeStandard.enable = true;
vscodeStylelint.enable = true;
nearley.enable = true;
# graphql
graphql.enable = true;
# astro development
vscodeMdx.enable = true;
astroVscode.enable = true;
# nix development
alejandra.enable = nix-development-enabled;
nixIde.enable = nix-development-enabled;
# go development
go.enable = true;
# rust development
rustAnalyzer.enable = true;
# arduino development
platformIO.enable = false;
# claude development
claudeDev = lib.mkIf ai-tooling-enabled {
enable = false;
mcp = {
nixos = {
enable = true;
autoApprove = {
nixos_search = true;
nixos_info = true;
home_manager_search = true;
home_manager_info = true;
darwin_search = true;
darwin_info = true;
nixos_flakes_search = true;
};
};
eslint = {
enable = true;
autoApprove = {
lint-files = true;
};
};
vitest = {
enable = true;
autoApprove = {
list_tests = true;
run_tests = true;
analyze_coverage = true;
set_project_root = true;
};
};
sleep = {
enable = true;
timeout = 18000; # 5 hours to match claude codes timeout
autoApprove = {
sleep = true;
};
};
};
};
# misc extensions
evenBetterToml.enable = true;
direnv.enable = config.programs.direnv.enable;
conventionalCommits.enable = true;
};
extensions = let
extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
in (
with extension-pkgs.open-vsx; [
# vs code feel extensions
streetsidesoftware.code-spell-checker
streetsidesoftware.code-spell-checker-german
streetsidesoftware.code-spell-checker-italian
]
);
};
};
};
};
};
}

View file

@ -0,0 +1,129 @@
{...}: {
flake.homeModules.leylaVscodeUserWords = {
pkgs,
lib,
...
}: {
config.programs.vscode.profiles.default.userSettings = {
"cSpell.userWords" = [
"leyla"
"Cyberia"
];
"cSpell.languageSettings" = [
{
"languageId" = "nix";
"locale" = "*";
"dictionaries" = [
"applications"
"ai-words"
"nix-words"
# We need to include all other dictionaries in the nix language settings because they exist in this file
# TODO: see if there is a way to make this only apply for this file
"js-words"
];
}
{
"languageId" = "javascript,typescript,js,ts";
"locale" = "*";
"dictionaries" = [
"js-words"
];
}
];
"cSpell.customDictionaries" = {
applications = {
name = "applications";
description = "application names";
path = pkgs.writeText "applications.txt" (lib.strings.concatLines [
"ollama"
"syncthing"
"immich"
"sonos"
"makemkv"
"hass"
"qbittorent"
"prostudiomasters"
"protonmail"
"pulseaudio"
]);
};
ai-words = {
name = "ai-words";
description = "common words used for ai development";
path = pkgs.writeText "ai-words.txt" (lib.strings.concatLines [
"ollama"
"deepseek"
"qwen"
]);
};
nix-words = {
name = "nix-words";
description = "words used in nix configurations";
path = pkgs.writeText "nix-words.txt" (lib.strings.concatLines [
"pname"
"direnv"
"tmpfiles"
"Networkd"
"networkmanager"
"dialout"
"adbusers"
"authkey"
"netdevs"
"atomix"
"geary"
"gedit"
"hitori"
"iagno"
"alsa"
"timezoned"
"pipewire"
"rtkit"
"disko"
"ashift"
"autotrim"
"canmount"
"mountpoint"
"xattr"
"acltype"
"relatime"
"keyformat"
"keylocation"
"vdevs"
# codium extensions
"akamud"
"onedark"
"jeanp"
"dsznajder"
"dbaeumer"
"orta"
"tauri"
"unifiedjs"
"tamasfe"
"pinage"
"jnoortheen"
"kamadorueda"
"karyfoundation"
"nearley"
# nix.optimise is spelled wrong
"optimise"
]);
};
js-words = {
name = "js-words";
description = "words used in js development";
path = pkgs.writeText "js-words.txt" (lib.strings.concatLines [
"webdav"
]);
};
};
};
};
}

View file

@ -0,0 +1,454 @@
{...}: {
# server nas
flake.nixosModules.defiantConfiguration = {
inputs,
config,
...
}: {
sops.secrets = {
"vpn-keys/tailscale-authkey/defiant" = {
sopsFile = "${inputs.secrets}/vpn-keys.yaml";
};
"vpn-keys/proton-wireguard/defiant-p2p" = {
sopsFile = "${inputs.secrets}/vpn-keys.yaml";
mode = "0640";
owner = "root";
group = "systemd-network";
};
"services/zfs_smtp_token" = {
sopsFile = "${inputs.secrets}/defiant-services.yaml";
};
"services/paperless_password" = {
sopsFile = "${inputs.secrets}/defiant-services.yaml";
mode = "0700";
owner = "paperless";
group = "paperless";
};
};
host = {
users = {
leyla = {
isDesktopUser = true;
isTerminalUser = true;
isPrincipleUser = true;
};
};
network_storage = {
enable = true;
directories = [
{
folder = "leyla_documents";
user = "leyla";
group = "leyla";
bind = "/home/leyla/documents";
}
{
folder = "eve_documents";
user = "eve";
group = "eve";
}
{
folder = "users_documents";
user = "root";
group = "users";
}
{
folder = "media";
user = "jellyfin";
group = "jellyfin_media";
bind = config.services.jellyfin.media_directory;
}
];
nfs = {
enable = true;
directories = ["leyla_documents" "eve_documents" "users_documents" "media"];
};
};
};
storage = {
zfs = {
enable = true;
notifications = {
enable = true;
host = "smtp.protonmail.ch";
port = 587;
to = "leyla@jan-leila.com";
user = "noreply@jan-leila.com";
tokenFile = config.sops.secrets."services/zfs_smtp_token".path;
};
pool = {
encryption = {
enable = true;
};
vdevs = [
[
"ata-ST18000NE000-3G6101_ZVTCXVEB"
"ata-ST18000NE000-3G6101_ZVTCXWSC"
"ata-ST18000NE000-3G6101_ZVTD10EH"
"ata-ST18000NT001-3NF101_ZVTE0S3Q"
"ata-ST18000NT001-3NF101_ZVTEF27J"
"ata-ST18000NE000-3G6101_ZVTJ7359"
]
[
"ata-ST4000NE001-2MA101_WS2275P3"
"ata-ST4000NE001-2MA101_WS227B9F"
"ata-ST4000NE001-2MA101_WS227CEW"
"ata-ST4000NE001-2MA101_WS227CYN"
"ata-ST4000NE001-2MA101_WS23TBWV"
"ata-ST4000NE001-2MA101_WS23TC5F"
]
];
# We are having to boot off of the nvm cache drive because I cant figure out how to boot via the HBA
cache = [
{
device = "nvme-Samsung_SSD_990_PRO_4TB_S7KGNU0X907881F";
boot = true;
}
];
};
};
impermanence = {
enable = true;
};
};
# bond0 and wg0 are managed by systemd-networkd; tell NetworkManager to
# leave them alone so NM-wait-online doesn't time out waiting for them.
networking.networkmanager.unmanaged = ["bond0" "wg0" "eno1" "eno2"];
systemd.network = {
enable = true;
netdevs = {
"10-bond0" = {
netdevConfig = {
Kind = "bond";
Name = "bond0";
};
bondConfig = {
Mode = "active-backup";
PrimaryReselectPolicy = "always";
};
};
"20-wg0" = {
netdevConfig = {
Kind = "wireguard";
Name = "wg0";
};
wireguardConfig = {
PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path;
ListenPort = 51820;
};
wireguardPeers = [
{
PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0=";
Endpoint = "185.230.126.146:51820";
# Allow all traffic but use policy routing to prevent system-wide VPN
AllowedIPs = ["0.0.0.0/0"];
PersistentKeepalive = 25;
}
];
};
};
networks = {
"40-bond0" = {
matchConfig.Name = "bond0";
linkConfig = {
RequiredForOnline = "degraded-carrier";
RequiredFamilyForOnline = "any";
};
networkConfig.DHCP = "yes";
address = [
"192.168.1.2/24"
];
# Set lower priority for default gateway to allow WireGuard interface binding
routes = [
{
Destination = "0.0.0.0/0";
Gateway = "192.168.1.1";
Metric = 100;
}
];
dns = ["192.168.1.1"];
};
"50-wg0" = {
matchConfig.Name = "wg0";
# Don't block networkd-wait-online on the VPN tunnel coming up
linkConfig.RequiredForOnline = "no";
networkConfig = {
DHCP = "no";
};
address = [
"10.2.0.2/32"
];
# Configure routing for application binding
routingPolicyRules = [
{
# Route traffic from VPN interface through VPN table
From = "10.2.0.2/32";
Table = 200;
Priority = 100;
}
];
routes = [
{
# Direct route to VPN gateway
Destination = "10.2.0.1/32";
Scope = "link";
}
{
# Route VPN subnet through VPN gateway in custom table
Destination = "10.2.0.0/16";
Gateway = "10.2.0.1";
Table = 200;
}
{
# Route all traffic through VPN gateway in custom table
Destination = "0.0.0.0/0";
Gateway = "10.2.0.1";
Table = 200;
}
];
};
};
};
# limit arc usage to 50gb because ollama doesn't play nice with zfs using up all of the memory
boot.kernelParams = ["zfs.zfs_arc_max=53687091200"];
# Enable policy routing and source routing for application-specific VPN binding
boot.kernel.sysctl = {
"net.ipv4.conf.all.rp_filter" = 2;
"net.ipv4.conf.default.rp_filter" = 2;
"net.ipv4.conf.wg0.rp_filter" = 2;
};
services = {
# PostgreSQL database server
postgresql = {
enable = true;
adminUsers = ["leyla"];
impermanence.enable = false;
};
# temp enable desktop environment for setup
# Enable the X11 windowing system.
xserver.enable = true;
# Enable the GNOME Desktop Environment.
displayManager = {
gdm.enable = true;
};
desktopManager = {
gnome.enable = true;
};
# Enable new reverse proxy system
reverseProxy = {
enable = true;
openFirewall = true;
impermanence.enable = false;
acme = {
enable = true;
email = "jan-leila@protonmail.com";
};
};
ollama = {
enable = true;
exposePort = true;
impermanence.enable = false;
environmentVariables = {
OLLAMA_KEEP_ALIVE = "24h";
};
loadModels = [
# conversation models
"llama3.1:8b"
"deepseek-r1:8b"
"deepseek-r1:32b"
"deepseek-r1:70b"
# auto complete models
"qwen2.5-coder:1.5b-base"
"qwen2.5-coder:7b"
"deepseek-coder:6.7b"
"deepseek-coder:33b"
# agent models
"qwen3:8b"
"qwen3:32b"
"qwen3:235b-a22b"
"qwen3-coder:30b"
"qwen3-coder:30b-a3b-fp16"
# embedding models
"nomic-embed-text:latest"
];
};
tailscale = {
enable = true;
authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/defiant".path;
useRoutingFeatures = "server";
impermanence.enable = false;
extraUpFlags = [
"--advertise-exit-node"
"--advertise-routes=192.168.0.0/24"
"--accept-dns=false"
];
extraSetFlags = [
"--advertise-exit-node"
"--advertise-routes=192.168.0.0/24"
"--accept-dns=false"
];
};
syncthing = {
enable = true;
impermanence.enable = false;
};
fail2ban = {
enable = true;
impermanence.enable = false;
};
jellyfin = {
enable = true;
domain = "media.jan-leila.com";
extraDomains = ["jellyfin.jan-leila.com"];
impermanence.enable = false;
};
immich = {
enable = true;
domain = "photos.jan-leila.com";
impermanence.enable = false;
};
forgejo = {
enable = true;
reverseProxy.domain = "git.jan-leila.com";
impermanence.enable = false;
};
searx = {
enable = true;
domain = "search.jan-leila.com";
};
actual = {
enable = false;
domain = "budget.jan-leila.com";
impermanence.enable = false;
};
home-assistant = {
enable = true;
domain = "home.jan-leila.com";
openFirewall = true;
postgres.enable = true;
impermanence.enable = false;
extensions = {
sonos.enable = true;
jellyfin.enable = true;
wyoming.enable = false; # Temporarily disabled due to dependency conflict in wyoming-piper
};
};
paperless = {
enable = true;
domain = "documents.jan-leila.com";
passwordFile = config.sops.secrets."services/paperless_password".path;
impermanence.enable = false;
};
panoramax = {
enable = false;
openFirewall = true;
impermanence.enable = false;
};
crab-hole = {
enable = true;
port = 8085;
openFirewall = true;
show_doc = true;
impermanence.enable = false;
downstreams = {
host = {
enable = true;
openFirewall = true;
};
};
upstreams.cloudFlare.enable = true;
blocklists.ad_malware.enable = true;
};
qbittorrent = {
enable = true;
mediaDir = "/srv/qbittorent";
openFirewall = true;
webuiPort = 8084;
impermanence.enable = false;
};
sonarr = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
radarr = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
bazarr = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
lidarr = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
jackett = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
flaresolverr = {
enable = true;
openFirewall = true;
impermanence.enable = false;
};
};
# disable computer sleeping
systemd.targets = {
sleep.enable = false;
suspend.enable = false;
hibernate.enable = false;
hybrid-sleep.enable = false;
};
services.displayManager.gdm.autoSuspend = false;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "23.05"; # Did you read the comment?
};
}

View file

@ -0,0 +1,22 @@
# server nas
{
inputs,
config,
...
}: {
flake.nixosConfigurations.defiant = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config.flake.nixosModules.nixosModules
config.flake.nixosModules.defiantConfiguration
config.flake.nixosModules.defiantHardwareConfiguration
config.flake.nixosModules.defiantPackages
config.flake.nixosModules.defiantLegacyStorage
config.flake.nixosModules.defiantLegacyImpermanence
];
specialArgs = {
inherit inputs;
syncthingConfiguration = inputs.self.syncthingConfiguration;
};
};
}

View file

@ -0,0 +1,70 @@
{...}: {
# Do not modify this file! It was generated by 'nixos-generate-config'
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
flake.nixosModules.defiantHardwareConfiguration = {
config,
lib,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot = {
initrd = {
availableKernelModules = ["xhci_pci" "aacraid" "ahci" "usbhid" "nvme" "usb_storage" "sd_mod"];
kernelModules = [];
};
kernelModules = ["kvm-amd"];
extraModulePackages = [];
# Bootloader.
loader = {
systemd-boot.enable = true;
efi = {
canTouchEfiVariables = true;
efiSysMountPoint = "/boot";
};
};
supportedFilesystems = ["zfs"];
zfs.extraPools = ["rpool"];
};
networking = {
hostName = "defiant"; # Define your hostname.
hostId = "c51763d6";
useNetworkd = true;
};
systemd.network = {
enable = true;
networks = {
"30-eno1" = {
matchConfig.Name = "eno1";
networkConfig = {
Bond = "bond0";
PrimarySlave = true;
};
linkConfig.RequiredForOnline = "enslaved";
};
"30-eno2" = {
matchConfig.Name = "eno2";
networkConfig.Bond = "bond0";
linkConfig.RequiredForOnline = "enslaved";
};
};
};
networking.networkmanager.enable = true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware = {
# TODO: hardware graphics
cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
};
};
}

View file

@ -0,0 +1,298 @@
{...}: {
# Legacy impermanence module for defiant
# See legacy-storage.nix for the full incremental migration plan.
#
# This file is consumed in two phases:
#
# Phase 3 (after generateBase is enabled):
# Remove the SYSTEM-LEVEL entries marked [PHASE 3] below. These will be
# handled automatically by storage.nix, ssh.nix, and the impermanence module:
# - var-lib-private-permissions activation script
# - /etc/machine-id
# - SSH host keys
# - /var/lib/nixos
# - /var/lib/systemd/coredump
# - /persist/system/var/log persistence block
#
# Phase 4 (migrate services one at a time, any order):
# For each service:
# 1. Remove the service's section marked [PHASE 4] from this file
# 2. Remove `impermanence.enable = false` for that service in configuration.nix
# For jellyfin/qbittorrent, also remove the separate media persistence blocks.
#
# Phase 5: Delete this file once empty.
flake.nixosModules.defiantLegacyImpermanence = {
config,
lib,
...
}: {
config = lib.mkIf config.storage.impermanence.enable {
# [PHASE 3] Remove this activation script after enabling generateBase
system.activationScripts = {
"var-lib-private-permissions" = {
deps = ["specialfs"];
text = ''
mkdir -p /persist/system/root/var/lib/private
chmod 0700 /persist/system/root/var/lib/private
'';
};
};
environment.persistence."/persist/system/root" = {
enable = true;
hideMounts = true;
# [PHASE 3] Remove this files block after enabling generateBase
files = lib.mkMerge [
["/etc/machine-id"]
# SSH host keys
(lib.mkIf config.services.openssh.enable (
lib.lists.flatten (
builtins.map (hostKey: [
hostKey.path
"${hostKey.path}.pub"
])
config.services.openssh.hostKeys
)
))
];
directories = lib.mkMerge [
# [PHASE 3] Remove these system directories after enabling generateBase
[
"/var/lib/nixos"
"/var/lib/systemd/coredump"
]
# [PHASE 4] PostgreSQL
(lib.mkIf config.services.postgresql.enable [
{
directory = "/var/lib/postgresql/16";
user = "postgres";
group = "postgres";
}
])
# [PHASE 4] Reverse Proxy (ACME)
(lib.mkIf config.services.reverseProxy.enable [
{
directory = "/var/lib/acme";
user = "acme";
group = "acme";
}
])
# [PHASE 4] Ollama
(lib.mkIf config.services.ollama.enable [
{
directory = "/var/lib/private/ollama";
user = config.services.ollama.user;
group = config.services.ollama.group;
mode = "0700";
}
])
# [PHASE 4] Tailscale
(lib.mkIf config.services.tailscale.enable [
{
directory = "/var/lib/tailscale";
user = "root";
group = "root";
}
])
# [PHASE 4] Syncthing
(lib.mkIf config.services.syncthing.enable [
{
directory = "/mnt/sync";
user = "syncthing";
group = "syncthing";
}
{
directory = "/etc/syncthing";
user = "syncthing";
group = "syncthing";
}
])
# [PHASE 4] Fail2ban
(lib.mkIf config.services.fail2ban.enable [
{
directory = "/var/lib/fail2ban";
user = "fail2ban";
group = "fail2ban";
}
])
# [PHASE 4] Jellyfin (data/cache only - media is on separate dataset)
(lib.mkIf config.services.jellyfin.enable [
{
directory = "/var/lib/jellyfin";
user = "jellyfin";
group = "jellyfin";
}
{
directory = "/var/cache/jellyfin";
user = "jellyfin";
group = "jellyfin";
}
])
# [PHASE 4] Immich
(lib.mkIf config.services.immich.enable [
{
directory = "/var/lib/immich";
user = "immich";
group = "immich";
}
])
# [PHASE 4] Forgejo
(lib.mkIf config.services.forgejo.enable [
{
directory = "/var/lib/forgejo";
user = "forgejo";
group = "forgejo";
}
])
# [PHASE 4] Actual
(lib.mkIf config.services.actual.enable [
{
directory = "/var/lib/private/actual";
user = "actual";
group = "actual";
}
])
# [PHASE 4] Home Assistant
(lib.mkIf config.services.home-assistant.enable [
{
directory = "/var/lib/hass";
user = "hass";
group = "hass";
}
])
# [PHASE 4] Paperless
(lib.mkIf config.services.paperless.enable [
{
directory = "/var/lib/paperless";
user = "paperless";
group = "paperless";
}
])
# [PHASE 4] Crab-hole
(lib.mkIf config.services.crab-hole.enable [
{
directory = "/var/lib/private/crab-hole";
user = "crab-hole";
group = "crab-hole";
}
])
# [PHASE 4] qBittorrent (config only - media is on separate dataset)
(lib.mkIf config.services.qbittorrent.enable [
{
directory = "/var/lib/qBittorrent/";
user = "qbittorrent";
group = "qbittorrent";
}
])
# [PHASE 4] Sonarr
(lib.mkIf config.services.sonarr.enable [
{
directory = "/var/lib/sonarr/.config/NzbDrone";
user = "sonarr";
group = "sonarr";
}
])
# [PHASE 4] Radarr
(lib.mkIf config.services.radarr.enable [
{
directory = "/var/lib/radarr/.config/Radarr";
user = "radarr";
group = "radarr";
}
])
# [PHASE 4] Bazarr
(lib.mkIf config.services.bazarr.enable [
{
directory = "/var/lib/bazarr";
user = "bazarr";
group = "bazarr";
}
])
# [PHASE 4] Lidarr
(lib.mkIf config.services.lidarr.enable [
{
directory = "/var/lib/lidarr/.config/Lidarr";
user = "lidarr";
group = "lidarr";
}
])
# [PHASE 4] Jackett
(lib.mkIf config.services.jackett.enable [
{
directory = "/var/lib/jackett/.config/Jackett";
user = "jackett";
group = "jackett";
}
])
# [PHASE 4] FlareSolverr
(lib.mkIf config.services.flaresolverr.enable [
{
directory = "/var/lib/flaresolverr";
user = "flaresolverr";
group = "flaresolverr";
}
])
];
};
# [PHASE 4 - LAST] Jellyfin media on separate dataset
# Requires Phase 2 media dataset merge before migrating (several days of data copy)
environment.persistence."/persist/system/jellyfin" = lib.mkIf config.services.jellyfin.enable {
enable = true;
hideMounts = true;
directories = [
{
directory = config.services.jellyfin.media_directory;
user = "jellyfin";
group = "jellyfin_media";
mode = "1770";
}
];
};
# [PHASE 4 - LAST] qBittorrent media on separate dataset
# Requires Phase 2 media dataset merge before migrating (several days of data copy)
environment.persistence."/persist/system/qbittorrent" = lib.mkIf config.services.qbittorrent.enable {
enable = true;
hideMounts = true;
directories = [
{
directory = config.services.qbittorrent.mediaDir;
user = "qbittorrent";
group = "qbittorrent";
mode = "1775";
}
];
};
# [PHASE 3] /var/log persistence - handled by storage.nix after generateBase
environment.persistence."/persist/system/var/log" = {
enable = true;
hideMounts = true;
directories = [
"/var/log"
];
};
};
};
}

View file

@ -0,0 +1,220 @@
{...}: {
# Legacy storage configuration for defiant
# This file manually defines ZFS datasets matching the existing on-disk layout
# to allow incremental migration to the new storage module (generateBase = true).
#
# ============================================================================
# INCREMENTAL MIGRATION PLAN
# ============================================================================
#
# Current disk usage (for reference):
# rpool/local/system/nix ~26G (renamed in place, no copy)
# rpool/local/system/sops ~328K (renamed in place, no copy)
# rpool/persist/system/jellyfin ~32T (renamed in place, no copy)
# rpool/persist/system/qbittorrent ~6.5T (copied into media dataset, ~6.5T temp)
# rpool free space ~30T
#
# Phase 1: Migrate base datasets on disk (boot from live USB or rescue)
# All operations in this phase are instant renames -- no data is copied.
#
# Unlock the pool:
# zfs load-key -a
#
# Step 1a: Move nix and sops out of local/ (they go to persist/local/)
# The -p flag auto-creates the parent datasets.
#
# zfs rename -p rpool/local/system/nix rpool/persist/local/nix
# zfs rename -p rpool/local/system/sops rpool/persist/local/system/sops
#
# Step 1b: Rename local/ -> ephemeral/ (takes remaining children with it)
# zfs rename rpool/local rpool/ephemeral
# # This moves: local/system/root -> ephemeral/system/root
# # local/home/leyla -> ephemeral/home/leyla
#
# Step 1c: Recreate blank snapshots on ephemeral datasets
# zfs destroy rpool/ephemeral/system/root@blank
# zfs snapshot rpool/ephemeral/system/root@blank
# zfs destroy rpool/ephemeral/home/leyla@blank
# zfs snapshot rpool/ephemeral/home/leyla@blank
#
# Step 1d: Move persist/ children under persist/replicate/
# zfs create -o canmount=off rpool/persist/replicate
# zfs create -o canmount=off rpool/persist/replicate/system
# zfs rename rpool/persist/system/root rpool/persist/replicate/system/root
# zfs rename rpool/persist/system/var rpool/persist/replicate/system/var
# zfs rename rpool/persist/home/leyla rpool/persist/replicate/home
# # Clean up the now-empty home parent
# zfs destroy rpool/persist/home
# # NOTE: Do NOT destroy rpool/persist/system -- it still contains
# # persist/system/jellyfin and persist/system/qbittorrent which are
# # migrated in Phase 2.
#
# Verify the new layout:
# zfs list -r rpool -o name,used,mountpoint
#
# Phase 2: Merge media into a single dataset (do this last)
# Strategy: Rename the jellyfin dataset to become the shared media dataset
# (zero copy, instant), then copy qbittorrent data into it (~6.5T copy).
# This avoids duplicating the 32T jellyfin dataset.
#
# Step 2a: Rename jellyfin dataset to the shared media name
# zfs rename rpool/persist/system/jellyfin rpool/persist/replicate/system/media
#
# Step 2b: Copy qbittorrent data into the media dataset
# This copies ~6.5T and may take several hours/days depending on disk speed.
# The qbittorrent data is not critical to back up so no snapshot needed.
#
# systemctl stop qbittorrent
# rsync -avPHAX /persist/system/qbittorrent/ /persist/replicate/system/media/
#
# Step 2c: Verify the data and clean up
# ls -la /persist/replicate/system/media/
# zfs destroy rpool/persist/system/qbittorrent
# # persist/system should now be empty, clean it up:
# zfs destroy rpool/persist/system
#
# Phase 3: Enable generateBase
# In the nix config:
# - Delete this file (legacy-storage.nix) and remove its import from default.nix
# - Remove [PHASE 3] entries from legacy-impermanence.nix:
# - var-lib-private-permissions activation script
# - /etc/machine-id, SSH host keys (files block)
# - /var/lib/nixos, /var/lib/systemd/coredump (directories)
# - /persist/system/var/log persistence block
# These are now handled automatically by storage.nix and ssh.nix.
# Rebuild and verify:
# sudo nixos-rebuild switch --flake .#defiant
# # Verify mounts: findmnt -t fuse.bindfs,fuse
# # Verify persist: ls /persist/replicate/system/root/var/lib/nixos
# # Verify boot: reboot and confirm system comes up cleanly
#
# Phase 4: Migrate services (one at a time, any order)
# For each service (except jellyfin/qbittorrent):
# 1. Remove the service's [PHASE 4] section from legacy-impermanence.nix
# 2. Remove `impermanence.enable = false` for that service in configuration.nix
# 3. Rebuild: sudo nixos-rebuild switch --flake .#defiant
# 4. Verify: systemctl status <service>, check the service's data is intact
# No data migration is needed -- the data already lives on the renamed
# dataset at the new path.
#
# Migrate jellyfin and qbittorrent LAST (after Phase 2 media merge):
# 1. Remove [PHASE 4 - LAST] jellyfin entries from legacy-impermanence.nix
# 2. Remove [PHASE 4 - LAST] qbittorrent entries from legacy-impermanence.nix
# 3. Remove `impermanence.enable = false` for both in configuration.nix
# 4. Rebuild: sudo nixos-rebuild switch --flake .#defiant
# 5. Verify: systemctl status jellyfin qbittorrent
#
# Phase 5: Cleanup
# Once all services are migrated and legacy-impermanence.nix is empty:
# - Delete legacy-impermanence.nix and remove its import from default.nix
# - Rebuild: sudo nixos-rebuild switch --flake .#defiant
#
# ============================================================================
#
# Current on-disk dataset layout:
# rpool/local/ - ephemeral parent
# rpool/local/home/leyla - ephemeral user home (rolled back on boot)
# rpool/local/system/nix - nix store
# rpool/local/system/root - root filesystem (rolled back on boot)
# rpool/local/system/sops - sops age key
# rpool/persist/ - persistent parent
# rpool/persist/home/leyla - persistent user home
# rpool/persist/system/jellyfin - jellyfin media
# rpool/persist/system/qbittorrent - qbittorrent media
# rpool/persist/system/root - persistent root data
# rpool/persist/system/var/log - log persistence
flake.nixosModules.defiantLegacyStorage = {lib, ...}: {
# Disable automatic base dataset generation so we can define them manually
storage.generateBase = false;
# Manually define ZFS datasets matching main's structure
storage.zfs.datasets = {
# Ephemeral datasets (local/)
"local" = {
type = "zfs_fs";
mount = null;
};
"local/home/leyla" = {
type = "zfs_fs";
mount = "/home/leyla";
snapshot = {
blankSnapshot = true;
};
};
"local/system/nix" = {
type = "zfs_fs";
mount = "/nix";
atime = "off";
relatime = "off";
snapshot = {
autoSnapshot = false;
};
};
"local/system/root" = {
type = "zfs_fs";
mount = "/";
snapshot = {
blankSnapshot = true;
};
};
"local/system/sops" = {
type = "zfs_fs";
mount = "/var/lib/sops-nix";
};
# Persistent datasets (persist/)
"persist" = {
type = "zfs_fs";
mount = null;
};
"persist/home/leyla" = {
type = "zfs_fs";
mount = "/persist/home/leyla";
snapshot = {
autoSnapshot = true;
};
};
"persist/system/jellyfin" = {
type = "zfs_fs";
mount = "/persist/system/jellyfin";
atime = "off";
relatime = "off";
};
"persist/system/qbittorrent" = {
type = "zfs_fs";
mount = "/persist/system/qbittorrent";
atime = "off";
relatime = "off";
};
"persist/system/root" = {
type = "zfs_fs";
mount = "/persist/system/root";
snapshot = {
autoSnapshot = true;
};
};
"persist/system/var/log" = {
type = "zfs_fs";
mount = "/persist/system/var/log";
};
};
# Boot commands to rollback ephemeral root and user homes on boot
boot.initrd.postResumeCommands = lib.mkAfter ''
zfs rollback -r rpool/local/system/root@blank
zfs rollback -r rpool/local/home/leyla@blank
'';
# FileSystems needed for boot
fileSystems = {
"/".neededForBoot = true;
"/persist/system/root".neededForBoot = true;
"/persist/system/var/log".neededForBoot = true;
"/persist/system/jellyfin".neededForBoot = true;
"/persist/system/qbittorrent".neededForBoot = true;
"/var/lib/sops-nix".neededForBoot = true;
"/persist/home/leyla".neededForBoot = true;
"/home/leyla".neededForBoot = true;
};
};
}

View file

@ -0,0 +1,11 @@
{...}: {
flake.nixosModules.defiantPackages = {pkgs, ...}: {
environment.systemPackages = with pkgs; [
ffsubsync
sox
yt-dlp
ffmpeg
imagemagick
];
};
}

View file

@ -0,0 +1,183 @@
{...}: {
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page, on
# https://search.nixos.org/options and in the NixOS manual (`nixos-help`).
flake.nixosModules.emergentConfiguration = {
lib,
pkgs,
...
}: {
# Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# networking.hostName = "nixos"; # Define your hostname.
# Pick only one of the below networking options.
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
# networking.networkmanager.enable = true; # Easiest to use and most distros use this by default.
# Set your time zone.
# time.timeZone = "Europe/Amsterdam";
# Configure network proxy if necessary
# networking.proxy.default = "http://user:password@proxy:port/";
# networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";
# Select internationalisation properties.
# i18n.defaultLocale = "en_US.UTF-8";
# console = {
# font = "Lat2-Terminus16";
# keyMap = "us";
# useXkbConfig = true; # use xkb.options in tty.
# };
# Enable the X11 windowing system.
services.xserver.enable = true;
# Enable wacom touchscreen device
services.xserver.wacom.enable = true;
# installed opentabletdriver
# hardware.opentabletdriver.enable = true;
hardware.keyboard.qmk.enable = true;
# Enable the GNOME Desktop Environment.
services.displayManager.gdm.enable = true;
services.desktopManager.gnome.enable = true;
host = {
ai.enable = true;
users = {
eve = {
isDesktopUser = true;
isTerminalUser = true;
isPrincipleUser = true;
};
};
hardware = {
piperMouse.enable = true;
};
};
storage = {
zfs = {
enable = true;
pool = {
mode = "stripe";
vdevs = [
[
{
device = "wwn-0x5000039fd0cf05eb";
boot = true;
}
]
];
cache = [];
};
};
};
virtualisation.libvirtd.enable = true;
users.users.eve = {
extraGroups = ["libvirtd"];
};
services.tailscale.enable = true;
# We were having weird build errors so this is disabled right now
# error: The option `devices.emergent.folders.eve_records.path' was accessed but has no value defined. Try setting the option
services.syncthing.enable = false;
# Configure keymap in X11
# services.xserver.xkb.layout = "us";
# services.xserver.xkb.options = "eurosign:e,caps:escape";
# Enable CUPS to print documents.
# services.printing.enable = true;
# Enable sound.
# services.pulseaudio.enable = true;
# OR
# services.pipewire = {
# enable = true;
# pulse.enable = true;
# };
# Enable touchpad support (enabled default in most desktopManager).
# services.libinput.enable = true;
# Define a user account. Don't forget to set a password with passwd.
# users.users.alice = {
# isNormalUser = true;
# extraGroups = [ "wheel" ]; # Enable sudo for the user.
# packages = with pkgs; [
# tree
# ];
# };
# programs.firefox.enable = true;
nixpkgs.config.allowUnfree = true;
# Packages that can be installed without any extra configuration
# See https://search.nixos.org/packages for all options
environment.systemPackages = with pkgs; [
wget
gnome-boxes
libvirt
];
# Packages that need to be installed with some extra configuration
# See https://search.nixos.org/options for all options
programs = {};
# Some programs need SUID wrappers, can be configured further or are
# started in user sessions.
# programs.mtr.enable = true;
# programs.gnupg.agent = {
# enable = true;
# enableSSHSupport = true;
# };
# List services that you want to enable:
# Enable the OpenSSH daemon.
# services.openssh.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
networking = {
networkmanager.enable = true;
useDHCP = lib.mkDefault true;
hostId = "7e35eb97"; # arbitrary id number generated via this command: `head -c4 /dev/urandom | od -A none -t x4`
hostName = "emergent"; # Define your hostname.
};
# Copy the NixOS configuration file and link it from the resulting system
# (/run/current-system/configuration.nix). This is useful in case you
# accidentally delete configuration.nix.
# system.copySystemConfiguration = true;
# This option defines the first version of NixOS you have installed on this particular machine,
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
#
# Most users should NEVER change this value after the initial install, for any reason,
# even if you've upgraded your system to a new NixOS release.
#
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
# to actually do that.
#
# This value being lower than the current NixOS release does NOT mean your system is
# out of date, out of support, or vulnerable.
#
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
# and migrated your data accordingly.
#
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
system.stateVersion = "25.05"; # Did you read the comment?
};
}

View file

@ -0,0 +1,21 @@
# evs desktop
{
inputs,
config,
...
}: {
flake.nixosConfigurations.emergent = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config.flake.nixosModules.nixosModules
config.flake.nixosModules.emergentConfiguration
config.flake.nixosModules.emergentHardwareConfiguration
config.flake.nixosModules.emergentLegacyStorage
config.flake.nixosModules.emergentNvidiaDriver
];
specialArgs = {
inherit inputs;
syncthingConfiguration = inputs.self.syncthingConfiguration;
};
};
}

View file

@ -0,0 +1,34 @@
{...}: {
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
flake.nixosModules.emergentHardwareConfiguration = {
config,
lib,
pkgs,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" "wacom" "kvm" "kvm_amd"];
boot.initrd.kernelModules = [];
boot.kernelModules = [];
boot.extraModulePackages = [];
swapDevices = [];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp42s0.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp4s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
};
}

View file

@ -0,0 +1,53 @@
{...}: {
# Legacy storage configuration for emergent
# This file manually defines ZFS datasets matching the existing on-disk layout
# to allow incremental migration to the new storage module (generateBase = true).
#
# Current on-disk dataset layout:
# rpool/local/ - parent (canmount=off)
# rpool/local/system/nix - nix store
# rpool/local/system/root - root filesystem
#
# Migration plan:
# Phase 1: Rename datasets on disk (boot from live USB)
# zfs rename -p rpool/local/system/nix rpool/persist/local/nix
# zfs rename rpool/local rpool/persist/local
# # This moves: local/system/root -> persist/local/root (need to rename after)
# # Actually, since local/system/root needs to become persist/local/root:
# zfs rename rpool/persist/local/system/root rpool/persist/local/root
# zfs destroy rpool/persist/local/system # now empty
# # Recreate blank snapshot:
# zfs destroy rpool/persist/local/root@blank
# zfs snapshot rpool/persist/local/root@blank
#
# Phase 2: Delete this file, remove its import from default.nix, rebuild.
flake.nixosModules.emergentLegacyStorage = {...}: {
# Disable automatic base dataset generation so we can define them manually
storage.generateBase = false;
# Manually define ZFS datasets matching the existing on-disk layout
storage.zfs.datasets = {
"local" = {
type = "zfs_fs";
mount = null;
};
"local/system/nix" = {
type = "zfs_fs";
mount = "/nix";
atime = "off";
relatime = "off";
snapshot = {
autoSnapshot = false;
};
};
"local/system/root" = {
type = "zfs_fs";
mount = "/";
snapshot = {
blankSnapshot = true;
autoSnapshot = true;
};
};
};
};
}

View file

@ -0,0 +1,48 @@
{...}: {
flake.nixosModules.emergentNvidiaDriver = {config, ...}: {
# Enable OpenGL
hardware.graphics = {
enable = true;
};
# Load nvidia driver for Xorg and Wayland
services = {
xserver = {
# Load nvidia driver for Xorg and Wayland
videoDrivers = ["nvidia"];
};
# Use X instead of wayland
displayManager.gdm.wayland = true;
};
hardware.nvidia = {
# Modesetting is required.
modesetting.enable = true;
# Nvidia power management. Experimental, and can cause sleep/suspend to fail.
# Enable this if you have graphical corruption issues or application crashes after waking
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
# of just the bare essentials.
powerManagement.enable = true;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
powerManagement.finegrained = false;
# Use the NVidia open source kernel module (not to be confused with the
# independent third-party "nouveau" open source driver).
# Support is limited to the Turing and later architectures. Full list of
# supported GPUs is at:
# https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus
# Only available from driver 515.43.04+
open = true;
# Enable the Nvidia settings menu,
# accessible via `nvidia-settings`.
nvidiaSettings = true;
# Optionally, you may need to select the appropriate driver version for your specific GPU.
package = config.boot.kernelPackages.nvidiaPackages.stable;
};
};
}

View file

@ -0,0 +1,158 @@
{...}: {
flake.nixosModules.horizonConfiguration = {
lib,
pkgs,
config,
inputs,
...
}: {
imports = [
inputs.nixos-hardware.nixosModules.framework-11th-gen-intel
];
nixpkgs.config.allowUnfree = true;
boot = {
initrd = {
availableKernelModules = ["usb_storage" "sd_mod"];
};
kernelModules = ["sg"];
# Bootloader.
loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
};
host = {
users = {
leyla = {
isDesktopUser = true;
isTerminalUser = true;
isPrincipleUser = true;
};
eve.isDesktopUser = true;
};
hardware = {
directAccess.enable = true;
};
ai = {
enable = true;
models = {
"Llama 3.1 8B" = {
model = "llama3.1:8b";
roles = ["chat" "edit" "apply"];
apiBase = "http://defiant:11434";
};
"Deepseek Coder:6.7B" = {
model = "deepseek-coder:6.7b";
roles = ["chat" "edit" "apply"];
apiBase = "http://defiant:11434";
};
"Deepseek Coder:33B" = {
model = "deepseek-coder:33b";
roles = ["chat" "edit" "apply"];
apiBase = "http://defiant:11434";
};
"Deepseek r1:8B" = {
model = "deepseek-r1:8b";
roles = ["chat"];
apiBase = "http://defiant:11434";
};
"Deepseek r1:32B" = {
model = "deepseek-r1:32b";
roles = ["chat"];
apiBase = "http://defiant:11434";
};
"qwen2.5-coder:1.5b-base" = {
model = "qwen2.5-coder:1.5b-base";
roles = ["autocomplete"];
apiBase = "http://defiant:11434";
};
"nomic-embed-text:latest" = {
model = "nomic-embed-text:latest";
roles = ["embed"];
apiBase = "http://defiant:11434";
};
};
};
};
virtualisation.docker.enable = true;
environment.systemPackages = with pkgs; [
cachefilesd
webtoon-dl
android-tools
];
services.cachefilesd.enable = true;
networking = {
networkmanager.enable = true;
hostName = "horizon"; # Define your hostname.
};
powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
hardware = {
graphics.enable = true;
};
sops.secrets = {
"vpn-keys/tailscale-authkey/horizon" = {
sopsFile = "${inputs.secrets}/vpn-keys.yaml";
};
};
services = {
# sudo fprintd-enroll
fprintd = {
enable = true;
};
# firmware update tool
fwupd = {
enable = true;
};
tailscale = {
enable = true;
authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/horizon".path;
useRoutingFeatures = "client";
};
syncthing.enable = true;
ollama = {
enable = true;
loadModels = [
"llama3.1:8b"
];
};
};
# Enable network-online.target for better network dependency handling
systemd.services.NetworkManager-wait-online.enable = true;
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# Open ports in the firewall.
# networking.firewall.allowedTCPPorts = [ ... ];
# networking.firewall.allowedUDPPorts = [ ... ];
# Or disable the firewall altogether.
# networking.firewall.enable = false;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "23.05"; # Did you read the comment?
};
}

View file

@ -0,0 +1,20 @@
# leyla laptop
{
inputs,
config,
...
}: {
flake.nixosConfigurations.horizon = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config.flake.nixosModules.nixosModules
config.flake.nixosModules.horizonConfiguration
config.flake.nixosModules.horizonHardwareConfiguration
# config.flake.nixosModules.horizonNetworkMount
];
specialArgs = {
inherit inputs;
syncthingConfiguration = inputs.self.syncthingConfiguration;
};
};
}

View file

@ -0,0 +1,47 @@
{...}: {
# Do not modify this file! It was generated by 'nixos-generate-config'
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
flake.nixosModules.horizonHardwareConfiguration = {
config,
lib,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["xhci_pci" "thunderbolt" "nvme"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-intel"];
boot.extraModulePackages = [];
fileSystems = {
"/" = {
device = "/dev/disk/by-uuid/866d422b-f816-4ad9-9846-791839cb9337";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-uuid/E138-65B5";
fsType = "vfat";
};
};
swapDevices = [
{device = "/dev/disk/by-uuid/be98e952-a072-4c3a-8c12-69500b5a2fff";}
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.tailscale0.useDHCP = lib.mkDefault true;
# networking.interfaces.wlp170s0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
};
}

View file

@ -0,0 +1,78 @@
{...}: {
flake.nixosModules.horizonNetworkMount = {...}: {
boot.supportedFilesystems = ["nfs"];
fileSystems = {
"/mnt/leyla_documents" = {
device = "defiant:/exports/leyla_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr" # Allow interruption of NFS calls
"timeo=30" # 3 second timeout (30 deciseconds)
"retrans=2" # Only 2 retries before giving up
"x-systemd.idle-timeout=300" # 5 minute idle timeout for mobile
"x-systemd.device-timeout=15" # 15 second device timeout
"bg" # Background mount - don't block boot
"fsc" # Enable caching
"_netdev" # Network device - wait for network
"x-systemd.requires=network-online.target" # Require network to be online
"x-systemd.after=network-online.target" # Start after network is online
"x-systemd.mount-timeout=30" # 30 second mount timeout
];
};
"/mnt/users_documents" = {
device = "defiant:/exports/users_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"nofail"
"soft"
"intr"
"timeo=30"
"retrans=2"
"x-systemd.idle-timeout=300"
"x-systemd.device-timeout=15"
"bg"
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
"x-systemd.mount-timeout=30"
];
};
"/mnt/media" = {
device = "defiant:/exports/media";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr"
"timeo=30"
"retrans=2"
"x-systemd.idle-timeout=300"
"x-systemd.device-timeout=15"
"bg"
# Mobile-optimized read settings
"rsize=8192" # Smaller read size for mobile
"wsize=8192" # Smaller write size for mobile
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
"x-systemd.mount-timeout=30"
];
};
};
};
}

View file

@ -0,0 +1,158 @@
{...}: {
flake.nixosModules.twilightConfiguration = {
inputs,
config,
pkgs,
...
}: {
nixpkgs.config.allowUnfree = true;
boot.initrd.availableKernelModules = ["usb_storage"];
boot.kernelModules = ["sg"];
boot.loader = {
systemd-boot.enable = true;
efi.canTouchEfiVariables = true;
};
sops.secrets = {
"vpn-keys/tailscale-authkey/twilight" = {
sopsFile = "${inputs.secrets}/vpn-keys.yaml";
};
};
host = {
users = {
leyla = {
isDesktopUser = true;
isTerminalUser = true;
isPrincipleUser = true;
};
eve.isDesktopUser = true;
};
hardware = {
piperMouse.enable = true;
viaKeyboard.enable = true;
openRGB.enable = true;
graphicsAcceleration.enable = true;
directAccess.enable = true;
};
ai = {
enable = true;
# TODO: benchmark twilight against defiant and prune this list of models that are faster on defiant
models = {
# conversation models
"Llama 3.1 8B" = {
model = "lamma3.1:8b";
roles = ["chat" "edit" "apply"];
};
"deepseek-r1:8b" = {
model = "deepseek-r1:8b";
roles = ["chat" "edit" "apply"];
};
"deepseek-r1:32b" = {
model = "deepseek-r1:32b";
roles = ["chat" "edit" "apply"];
};
# auto complete models
"qwen2.5-coder:1.5b-base" = {
model = "qwen2.5-coder:1.5b-base";
roles = ["autocomplete"];
};
"qwen2.5-coder:7b" = {
model = "qwen2.5-coder:7b";
roles = ["autocomplete"];
};
"deepseek-coder:6.7b" = {
model = "deepseek-coder:6.7b";
roles = ["autocomplete"];
};
"deepseek-coder:33b" = {
model = "deepseek-coder:33b";
roles = ["autocomplete"];
};
# agent models
"qwen3:32b" = {
model = "qwen3:32b";
roles = ["chat" "edit" "apply"];
};
# embedding models
"nomic-embed-text:latest" = {
model = "nomic-embed-text:latest";
roles = ["embed"];
};
};
};
};
services = {
ollama = {
enable = true;
exposePort = true;
loadModels = [
# conversation models
"llama3.1:8b"
"deepseek-r1:8b"
"deepseek-r1:32b"
# auto complete models
"qwen2.5-coder:1.5b-base"
"qwen2.5-coder:7b"
"deepseek-coder:6.7b"
"deepseek-coder:33b"
# agent models
"qwen3:32b"
# embedding models
"nomic-embed-text:latest"
];
};
tailscale = {
enable = true;
authKeyFile = config.sops.secrets."vpn-keys/tailscale-authkey/twilight".path;
useRoutingFeatures = "both";
extraUpFlags = [
"--advertise-exit-node"
"--advertise-routes=192.168.0.0/24"
];
extraSetFlags = [
"--advertise-exit-node"
"--advertise-routes=192.168.0.0/24"
];
};
syncthing.enable = true;
};
# Enable network-online.target for better network dependency handling
systemd.services.NetworkManager-wait-online.enable = true;
environment.systemPackages = with pkgs; [
cachefilesd
];
hardware.steam-hardware.enable = true; # Provides udev rules for controller, HTC vive, and Valve Index
networking = {
networkmanager.enable = true;
hostName = "twilight"; # Define your hostname.
};
# enabled virtualisation for docker
# virtualisation.docker.enable = true;
# Enable touchpad support (enabled default in most desktopManager).
# services.xserver.libinput.enable = true;
# This value determines the NixOS release from which the default
# settings for stateful data, like file locations and database versions
# on your system were taken. It's perfectly fine and recommended to leave
# this value at the release version of the first install of this system.
# Before changing this value read the documentation for this option
# (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
system.stateVersion = "23.05"; # Did you read the comment?
};
}

View file

@ -0,0 +1,21 @@
# leyla desktop
{
inputs,
config,
...
}: {
flake.nixosConfigurations.twilight = inputs.nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
config.flake.nixosModules.nixosModules
config.flake.nixosModules.twilightConfiguration
config.flake.nixosModules.twilightHardwareConfiguration
config.flake.nixosModules.twilightNvidiaDriver
# config.flake.nixosModules.twilightNetworkMount
];
specialArgs = {
inherit inputs;
syncthingConfiguration = inputs.self.syncthingConfiguration;
};
};
}

View file

@ -0,0 +1,44 @@
{...}: {
# Do not modify this file! It was generated by 'nixos-generate-config'
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
flake.nixosModules.twilightHardwareConfiguration = {
config,
lib,
modulesPath,
...
}: {
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "ahci" "usbhid" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-amd"];
boot.extraModulePackages = [];
fileSystems = {
"/" = {
device = "/dev/disk/by-id/nvme-Samsung_SSD_980_500GB_S64ENJ0RA06463Z-part2";
fsType = "ext4";
};
"/boot" = {
device = "/dev/disk/by-id/nvme-Samsung_SSD_980_500GB_S64ENJ0RA06463Z-part1";
fsType = "vfat";
options = ["fmask=0022" "dmask=0022"];
};
};
swapDevices = [];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
};
}

View file

@ -0,0 +1,74 @@
{...}: {
flake.nixosModules.twilightNetworkMount = {...}: {
boot.supportedFilesystems = ["nfs"];
fileSystems = {
"/mnt/leyla_documents" = {
device = "defiant:/exports/leyla_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr" # Allow interruption of NFS calls
"timeo=50" # 5 second timeout (50 deciseconds) - longer than mobile
"retrans=3" # 3 retries for desktop
"x-systemd.idle-timeout=600" # 10 minute idle timeout for desktop
"x-systemd.device-timeout=30" # 30 second device timeout
"bg" # Background mount - don't block boot
"fsc" # Enable caching
"_netdev" # Network device - wait for network
"x-systemd.requires=network-online.target" # Require network to be online
"x-systemd.after=network-online.target" # Start after network is online
];
};
"/mnt/users_documents" = {
device = "defiant:/exports/users_documents";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"nofail"
"soft"
"intr"
"timeo=50"
"retrans=3"
"x-systemd.idle-timeout=600"
"bg"
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
];
};
"/mnt/media" = {
device = "defiant:/exports/media";
fsType = "nfs";
options = [
"x-systemd.automount"
"noauto"
"noatime"
"nofail"
"soft"
"intr"
"timeo=50"
"retrans=3"
"x-systemd.idle-timeout=600"
"x-systemd.device-timeout=30"
"bg"
# Desktop-optimized read settings
"rsize=32768" # Larger read size for desktop
"wsize=32768" # Larger write size for desktop
"fsc"
"_netdev"
"x-systemd.requires=network-online.target"
"x-systemd.after=network-online.target"
];
};
};
};
}

View file

@ -0,0 +1,50 @@
{...}: {
flake.nixosModules.twilightNvidiaDriver = {config, ...}: {
services = {
xserver = {
# Load nvidia driver for Xorg and Wayland
videoDrivers = ["nvidia"];
};
# Temporarily enable wayland to fix boot issue
# TODO: Investigate proper X11 session generation for gaming
displayManager.gdm.wayland = true;
};
hardware = {
# Enable OpenGL
graphics.enable = true;
# install graphics drivers
nvidia = {
# Modesetting is required.
modesetting.enable = true;
# Nvidia power management. Experimental, and can cause sleep/suspend to fail.
# Enable this if you have graphical corruption issues or application crashes after waking
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
# of just the bare essentials.
powerManagement.enable = true;
# Fine-grained power management. Turns off GPU when not in use.
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
powerManagement.finegrained = false;
# Use the NVidia open source kernel module (not to be confused with the
# independent third-party "nouveau" open source driver).
# Support is limited to the Turing and later architectures. Full list of
# supported GPUs is at:
# https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus
# Only available from driver 515.43.04+
# Currently alpha-quality/buggy, so false is currently the recommended setting.
open = true;
# Enable the Nvidia settings menu,
# accessible via `nvidia-settings`.
nvidiaSettings = true;
# Optionally, you may need to select the appropriate driver version for your specific GPU.
package = config.boot.kernelPackages.nvidiaPackages.production;
};
};
};
}

118
modules/parts.nix Normal file
View file

@ -0,0 +1,118 @@
{inputs, ...}: let
home-manager = inputs.home-manager;
sops-nix = inputs.sops-nix;
nix-syncthing = inputs.nix-syncthing;
disko = inputs.disko;
impermanence = inputs.impermanence;
common-modules = [
../legacy-modules/common-modules
];
home-manager-modules =
common-modules
++ [
sops-nix.homeManagerModules.sops
../legacy-modules/home-manager-modules
];
home-manager-base = _: {
home-manager.useUserPackages = true;
home-manager.backupFileExtension = "backup";
home-manager.extraSpecialArgs = {
inherit inputs;
};
home-manager.sharedModules = home-manager-modules;
};
system-modules =
common-modules
++ [
home-manager-base
../legacy-modules/system-modules
];
in {
systems = ["x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin"];
flake.homeModules.homeModules = {imports = home-manager-modules;};
flake.nixosModules.nixosModules = {
imports =
system-modules
++ [
sops-nix.nixosModules.sops
nix-syncthing.nixosModules.syncthing
impermanence.nixosModules.impermanence
home-manager.nixosModules.home-manager
disko.nixosModules.disko
# lix-module.nixosModules.default
../legacy-modules/nixos-modules
({
lib,
config,
...
}: {
home-manager.users = {
leyla = lib.mkIf config.host.users.leyla.isNormalUser inputs.self.homeModules.leylaConfiguration;
eve = lib.mkIf config.host.users.eve.isNormalUser inputs.self.homeModules.eveConfiguration;
git = lib.mkIf (config.services.forgejo.enable or false) inputs.self.homeModules.gitConfiguration;
};
})
];
};
flake.darwinModules.darwinModules = {
imports =
system-modules
++ [
sops-nix.darwinModules.sops
home-manager.darwinModules.home-manager
../legacy-modules/darwin-modules
({
lib,
config,
...
}: {
home-manager.users = {
leyla = lib.mkIf config.host.users.leyla.isNormalUser inputs.self.homeModules.leylaConfiguration;
eve = lib.mkIf config.host.users.eve.isNormalUser inputs.self.homeModules.eveConfiguration;
};
})
];
};
perSystem = {
pkgs,
system,
...
}: {
formatter = pkgs.alejandra;
devShells.default = pkgs.mkShell {
packages = with pkgs; [
# for version controlling this repo
git
# for formatting code in this repo
alejandra
# for editing secrets in the secrets repo
sops
# for viewing configuration options defined in this repo
nix-inspect
# for installing flakes from this repo onto other systems
nixos-anywhere
# for updating disko configurations
pkgs.disko
# for viewing dconf entries
dconf-editor
# for MCP NixOS server support in development
inputs.mcp-nixos.packages.${system}.default
];
SOPS_AGE_KEY_DIRECTORY = import ../const/sops_age_key_directory.nix;
shellHook = ''
git config core.hooksPath .hooks
'';
};
};
}