Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

152 changed files with 1916 additions and 3082 deletions

View file

@ -3,12 +3,4 @@
echo "restoring stashed changes"
# Find the most recent pre-commit stash and restore it
recent_stash=$(git stash list | grep "pre-commit-stash-" | head -n 1 | cut -d: -f1)
if [ -n "$recent_stash" ]; then
echo "Found recent pre-commit stash: $recent_stash"
git stash pop -q "$recent_stash"
else
echo "No pre-commit stash found to restore"
fi
git stash pop -q

View file

@ -1,32 +0,0 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash ../shell.nix
# Get current branch name
current_branch=$(git branch --show-current)
# Only perform actions if we're on main branch and a merge just completed
if [ "$current_branch" = "main" ]; then
echo "Post-merge on main branch - running nix flake check"
# Run nix flake check after merge into main
nix flake check
if [ ! $? -eq 0 ]; then
echo "Warning: nix flake check failed after merge into main"
echo "Please fix the issues as soon as possible"
else
echo "nix flake check passed after merge"
fi
# Check if there are any pre-commit stashes to restore
recent_stash=$(git stash list | grep "pre-commit-stash-" | head -n 1 | cut -d: -f1)
if [ -n "$recent_stash" ]; then
echo "Post-merge: restoring pre-commit stash on main branch"
git stash pop -q "$recent_stash"
else
echo "Post-merge: no pre-commit stash to restore on main branch"
fi
else
echo "Post-merge: no action needed on branch '$current_branch'"
fi

View file

@ -1,24 +1,14 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash ../shell.nix
# Get current branch name
current_branch=$(git branch --show-current)
echo "stashing all uncommitted changes"
git stash -q --keep-index
echo "stashing all uncommitted changes with named stash (excluding hooks)"
git stash push -q --keep-index -m "pre-commit-stash-$(date +%s)" -- ':!.hooks/'
echo "checking flakes all compile"
nix flake check
# Only run nix flake check if we're on main branch
if [ "$current_branch" = "main" ]; then
echo "On main branch - checking flakes all compile"
nix flake check
if [ ! $? -eq 0 ]; then
echo "Error: nix flake check failed on main branch"
exit 1
fi
echo "nix flake check passed"
else
echo "Not on main branch - skipping nix flake check"
if [ ! $? -eq 0 ]; then
exit 1
fi
echo "running linter"

View file

@ -1,37 +0,0 @@
#!/usr/bin/env nix-shell
#! nix-shell -i bash ../shell.nix
# Get the target branch (the branch being merged into)
target_branch=""
# Check if we're in the middle of a merge
if [ -f .git/MERGE_HEAD ]; then
# We're in a merge, check if the current branch is main
current_branch=$(git branch --show-current)
if [ "$current_branch" = "main" ]; then
target_branch="main"
fi
fi
# If we're merging into main, run nix flake check
if [ "$target_branch" = "main" ]; then
echo "Merging into main branch - running nix flake check..."
echo "stashing all uncommitted changes with named stash (excluding hooks)"
git stash push -q --keep-index -m "pre-merge-stash-$(date +%s)" -- ':!.hooks/'
echo "checking flakes all compile"
nix flake check
if [ ! $? -eq 0 ]; then
echo "Error: nix flake check failed. Merge aborted."
echo "Please fix the issues and try merging again."
exit 1
fi
echo "nix flake check passed. Merge can proceed."
else
echo "Not merging into main branch, skipping nix flake check."
fi
exit 0

View file

@ -43,65 +43,39 @@ nix multi user, multi system, configuration with `sops` secret management, `home
- Look into this for auto rotating sops keys `https://technotim.live/posts/rotate-sops-encryption-keys/`
- Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/
- https://nixos-and-flakes.thiscute.world/
- proton mail now has an smtp server we could use that for our zfs and SMART test emails
# Tasks:
## Chores:
- [ ] test out crab hole service
## Tech Debt
- [ ] monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/)
- [ ] migrate away from flakes and move to npins
## Broken things
- [ ] figure out steam vr things?
- [ ] whisper was having issues
## Data Integrity
- [ ] zfs email after scrubbing # TODO: test this
- [ ] SMART test with email results
- [ ] zfs encryption FIDO2 2fa (look into shavee)
- [ ] rotate sops encryption keys periodically (and somehow sync between devices?)
- [ ] Secure Boot - https://github.com/nix-community/lanzaboote
- [ ] auto turn off on power loss - nut
- [ ] secondary server with data sync. Maybe a Pi with a usb hdd enclosure and use rtcwake to only turn on once a week to sync data over tailscale with connection initiated from pi's side. We could probably put this at LZ. Hoping for it to draw only like $1 of power a month. Initial sync should probably be done here before we move it over because that will take a while. Data should be encrypted so that devices doesn't have access to it. Project will prob cost like $1800
## Data Access
- [ ] nfs export should be backed by the same values for server and client
- [ ] samba mounts
- [ ] offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs)
- [ ] figure out why syncthing and jellyfins permissions don't propagate downwards
- [ ] make radarr, sonarr, and bazarr accessible over vpn
- [ ] move searx, home-assistant, actual, vikunja, jellyfin, paperless, and immich to only be accessible via vpn
## Services
- [ ] vikunja service for project management
- [ ] Penpot services (need to make this custom)
- [ ] minecraft server with old world file
- [ ] Create Tor guard/relay server
- [ ] mastodon instance
- [ ] screeps server
## DevOps
- [ ] wake on LAN for updates
- [ ] remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html
- [ ] ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix
- [ ] fix panoramax package
- [ ] claude code MCP servers should bundle node with them so they work in all environments
## Observability
- [ ] graphana for dashboards
- [ ] prometheus and loki for metric and log collection
- [ ] zfs storage usage
- [ ] zfs drive health status
- [ ] service version lag
- [ ] network/cpu/ram utilization
- [ ] http latency
- [ ] postgres db load
- [ ] nginx queries
- [ ] ntfy.sh for push notifications
- [ ] kuma for uptime visualization
## Packages
- [ ] Custom private fork of MultiMC
- monitor configuration in `~/.config/monitors.xml` should be sym linked to `/run/gdm/.config/monitors.xml` (https://www.reddit.com/r/NixOS/comments/u09cz9/home_manager_create_my_own_symlinks_automatically/)
- nfs export should be backed by the same values for server and client
## New Features
- crab-hole
- figure out why syncthing and jellyfins permissions don't propagate downwards
- figure out steam vr things?
- auto turn off on power loss - nut
- zfs email after scrubbing # TODO: test this
- SMART test with email results
- samba mounts
- offline access for nfs mounts (overlay with rsync might be a good option here? https://www.spinics.net/lists/linux-unionfs/msg07105.html note about nfs4 and overlay fs)
- Create Tor guard/relay server
- migrate away from flakes and move to npins
- whisper
- zfs encryption FIDO2 2fa (look into shavee)
- Secure Boot - https://github.com/nix-community/lanzaboote
- rotate sops encryption keys periodically (and somehow sync between devices?)
- wake on LAN for updates
- remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html
- ISO target that contains authorized keys for nixos-anywhere https://github.com/diegofariasm/yggdrasil/blob/4acc43ebc7bcbf2e41376d14268e382007e94d78/hosts/bootstrap/default.nix
- panoramax instance
- mastodon instance
- rework the reverse_proxy.nix file so that it is a normally named service. Then also change it so that we can hook into it with both a base domain and a subdomain to make migrating to vpn accessible services easier
- move searx, home-assistant, actual, jellyfin, paperless, and immich to only be accessible via vpn
- make radarr, sonarr, and bazarr accessible over vpn
- create some sort of service that allows uploading files to jellyfin
- auto sort files into where they should go with some combination of filebot cli and picard cli
- graphana accessible though tailscale
- fix panoramax package
- actual instance
- intergrade radarr, sonarr, and bazarr
- claude code MCP servers should bundle node with them so they work in all environments

View file

@ -1,39 +1,12 @@
{
osConfig,
lib,
...
}: {
{pkgs, ...}: {
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;
settings = {
"org/gnome/shell".enabled-extensions = [
pkgs.gnomeExtensions.dash-to-panel.extensionUuid
];
};
};
};
}

View file

@ -18,7 +18,6 @@ in {
home.packages = lib.lists.optionals userConfig.isDesktopUser (
with pkgs; [
gnomeExtensions.dash-to-panel
claude-code
]
);
@ -32,11 +31,9 @@ in {
(lib.mkIf (config.user.isDesktopUser || config.user.isTerminalUser) {
git = {
enable = true;
settings = {
user.name = "Eve";
user.email = "evesnrobins@gmail.com";
init.defaultBranch = "main";
};
userName = "Eve";
userEmail = "evesnrobins@gmail.com";
extraConfig.init.defaultBranch = "main";
};
openssh = {
@ -64,22 +61,6 @@ in {
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;
claude-code.enable = osConfig.host.ai.enable;
# 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

@ -1,6 +1,4 @@
{osConfig, ...}: {
impermanence.fallbackPersistence.enable = false;
home = {
username = osConfig.users.users.git.name;
homeDirectory = osConfig.users.users.git.home;

View file

@ -1,43 +1,31 @@
{...}: {
{pkgs, ...}: {
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;
};
};
};
extensions = [
pkgs.gnomeExtensions.dash-to-dock
];
hotkeys = {
"Open Terminal" = {
binding = "<Super>t";
command = "kgx";
};
"Open Firefox" = {
binding = "<Super>f";
command = "firefox";
};
};
};
dconf = {
enable = true;
settings = {
"org/gnome/shell/extensions/dash-to-dock" = {
"dock-position" = "LEFT";
"intellihide-mode" = "ALL_WINDOWS";
"show-trash" = false;
"require-pressure-to-show" = false;
"show-mounts" = false;
};
"org/gnome/shell" = {
favorite-apps = ["org.gnome.Nautilus.desktop" "firefox.desktop" "codium.desktop" "steam.desktop" "org.gnome.Console.desktop"];
# app-picker-layout =

View file

@ -12,8 +12,6 @@
];
config = {
impermanence.enable = osConfig.host.impermanence.enable;
# Home Manager needs a bit of information about you and the paths it should
# manage.
home = {
@ -89,6 +87,7 @@
# TODO: move this into a fonts module
home.packages = with pkgs; [
aileron
nerd-fonts.open-dyslexic
];
fonts.fontconfig.enable = true;
};

View file

@ -1,9 +1,10 @@
{
lib,
config,
osConfig,
...
}: {
config = lib.mkIf (config.impermanence.enable) {
config = lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist/home/leyla" = {
directories = [
"desktop"

View file

@ -9,7 +9,7 @@
in {
imports = [
./vscode
./firefox
./firefox.nix
./direnv.nix
./openssh.nix
./git.nix

View file

@ -0,0 +1,344 @@
{
lib,
pkgs,
inputs,
...
}: {
config = {
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.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
deutsch-de-language-pack
dictionary-german
tab-session-manager
# (
# buildFirefoxXpiAddon rec {
# pname = "italiano-it-language-pack";
# version = "132.0.20241110.231641";
# addonId = "langpack-it@firefox.mozilla.org";
# url = "https://addons.mozilla.org/firefox/downloads/file/4392453/italiano_it_language_pack-${version}.xpi";
# sha256 = "";
# meta = with lib;
# {
# description = "Firefox Language Pack for Italiano (it) Italian";
# license = licenses.mpl20;
# mozPermissions = [];
# platforms = platforms.all;
# };
# }
# )
# (
# buildFirefoxXpiAddon rec {
# pname = "dizionario-italiano";
# version = "5.1";
# addonId = "it-IT@dictionaries.addons.mozilla.org";
# url = "https://addons.mozilla.org/firefox/downloads/file/1163874/dizionario_italiano-${version}.xpi";
# sha256 = "";
# meta = with lib;
# {
# description = "Add support for Italian to spellchecking";
# license = licenses.gpl3;
# mozPermissions = [];
# platforms = platforms.all;
# };
# }
# )
];
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;
# Security
"privacy.trackingprotection.enabled" = true;
"dom.security.https_only_mode" = true;
"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" = "";
"dom.security.https_only_mode_pbm" = true;
"dom.security.https_only_mode_error_page_user_suggestions" = true;
# Disable telemetry
"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;
};
bookmarks = {
force = true;
settings = [
{
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 = "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 = [""];
}
# Template
# {
# name = "";
# url = "";
# keyword = "";
# tags = [""];
# }
];
};
};
};
};
}

View file

@ -1,149 +0,0 @@
{...}: {
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://budget.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 = [""];
}
# Template
# {
# name = "";
# url = "";
# keyword = "";
# tags = [""];
# }
];
};
};
};
}

View file

@ -1,18 +0,0 @@
{
lib,
pkgs,
inputs,
...
}: {
imports = [
./firefox.nix
./bookmarks.nix
./harden.nix
];
config = {
programs.firefox = {
enable = true;
};
};
}

View file

@ -1,221 +0,0 @@
{
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.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
deutsch-de-language-pack
dictionary-german
tab-session-manager
# (\
# buildFirefoxXpiAddon rec {\
# pname = "italiano-it-language-pack";\
# version = "132.0.20241110.231641";\
# addonId = "langpack-it@firefox.mozilla.org";\
# url = "https://addons.mozilla.org/firefox/downloads/file/4392453/italiano_it_language_pack-${version}.xpi";\
# sha256 = "";\
# meta = with lib;\
# {\
# description = "Firefox Language Pack for Italiano (it) Italian";\
# license = licenses.mpl20;\
# mozPermissions = [];\
# platforms = platforms.all;\
# };\
# }\
# )\
# (\
# buildFirefoxXpiAddon rec {\
# pname = "dizionario-italiano";\
# version = "5.1";\
# addonId = "it-IT@dictionaries.addons.mozilla.org";\
# url = "https://addons.mozilla.org/firefox/downloads/file/1163874/dizionario_italiano-${version}.xpi";\
# sha256 = "";\
# meta = with lib;\
# {\
# description = "Add support for Italian to spellchecking";\
# license = licenses.gpl3;\
# mozPermissions = [];\
# platforms = platforms.all;\
# };\
# }\
# )\
];
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

@ -1,50 +0,0 @@
{...}: {
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

@ -2,11 +2,9 @@
config = {
programs = {
git = {
settings = {
user.name = "Leyla Becker";
user.email = "git@jan-leila.com";
init.defaultBranch = "main";
};
userName = "Leyla Becker";
userEmail = "git@jan-leila.com";
extraConfig.init.defaultBranch = "main";
};
};
};

View file

@ -32,7 +32,6 @@ in {
"javascript.updateImportsOnFileMove.enabled" = "always";
"editor.tabSize" = 2;
"editor.insertSpaces" = false;
# "terminal.integrated.fontFamily" = "'Droid Sans Mono', 'monospace', monospace";
}
];
@ -41,7 +40,6 @@ in {
oneDark.enable = true;
atomKeybindings.enable = true;
openRemoteSsh.enable = true;
# openDyslexicFont.enable = false;
# html development
autoRenameTag.enable = true;
@ -69,9 +67,6 @@ in {
# go development
go.enable = true;
# rust development
rustAnalyzer.enable = true;
# claude development
claudeDev = lib.mkIf ai-tooling-enabled {
enable = true;

View file

@ -57,6 +57,7 @@
"ata-ST18000NT001-3NF101_ZVTEF27J"
"ata-ST18000NE000-3G6101_ZVTJ7359"
]
# TODO: this needs to be configured manually
[
"ata-ST4000NE001-2MA101_WS2275P3"
"ata-ST4000NE001-2MA101_WS227B9F"
@ -102,6 +103,18 @@
directories = ["leyla_documents" "eve_documents" "users_documents" "media"];
};
};
reverse_proxy = {
enable = true;
enableACME = true;
hostname = "jan-leila.com";
};
postgres = {
extraUsers = {
leyla = {
isAdmin = true;
};
};
};
};
systemd.network = {
@ -213,12 +226,6 @@
};
services = {
# PostgreSQL database server
postgresql = {
enable = true;
adminUsers = ["leyla"];
};
# temp enable desktop environment for setup
# Enable the X11 windowing system.
xserver.enable = true;
@ -231,16 +238,6 @@
gnome.enable = true;
};
# Enable new reverse proxy system
reverseProxy = {
enable = true;
openFirewall = true;
acme = {
enable = true;
email = "jan-leila@protonmail.com";
};
};
ollama = {
enable = true;
exposePort = true;
@ -298,35 +295,35 @@
jellyfin = {
enable = true;
domain = "media.jan-leila.com";
extraDomains = ["jellyfin.jan-leila.com"];
subdomain = "media";
extraSubdomains = ["jellyfin"];
};
immich = {
enable = true;
domain = "photos.jan-leila.com";
subdomain = "photos";
};
forgejo = {
enable = true;
reverseProxy.domain = "git.jan-leila.com";
subdomain = "git";
};
searx = {
enable = true;
domain = "search.jan-leila.com";
subdomain = "search";
};
actual = {
enable = true;
domain = "budget.jan-leila.com";
enable = false;
subdomain = "budget";
};
home-assistant = {
enable = true;
domain = "home.jan-leila.com";
subdomain = "home";
openFirewall = true;
postgres.enable = true;
database = "postgres";
extensions = {
sonos.enable = true;
@ -337,7 +334,7 @@
paperless = {
enable = true;
domain = "documents.jan-leila.com";
subdomain = "documents";
passwordFile = config.sops.secrets."services/paperless_password".path;
};
@ -346,21 +343,6 @@
openFirewall = true;
};
crab-hole = {
enable = true;
port = 8085;
openFirewall = true;
show_doc = true;
downstreams = {
host = {
enable = true;
openFirewall = true;
};
};
upstreams.cloudFlare.enable = true;
blocklists.ad_malware.enable = true;
};
qbittorrent = {
enable = true;
mediaDir = "/srv/qbittorent";
@ -368,28 +350,21 @@
webuiPort = 8084;
};
sonarr = {
filebot-cleanup = {
enable = true;
licenseFile = "/srv/jellyfin/filebot_license.psm";
};
sonarr = {
enable = false;
openFirewall = true;
};
radarr = {
enable = true;
enable = false;
openFirewall = true;
};
bazarr = {
enable = true;
openFirewall = true;
};
lidarr = {
enable = true;
openFirewall = true;
};
jackett = {
enable = true;
openFirewall = true;
};
flaresolverr = {
enable = true;
enable = false;
openFirewall = true;
};
};

View file

@ -4,5 +4,6 @@
./hardware-configuration.nix
./configuration.nix
./packages.nix
./filebot.nix
];
}

View file

@ -0,0 +1,82 @@
{
config,
lib,
pkgs,
...
}:
with lib; let
cfg = config.services.filebot-cleanup;
in {
options.services.filebot-cleanup = {
enable = mkEnableOption "Filebot cleanup service";
licenseFile = mkOption {
type = types.nullOr types.path;
default = null;
description = "Path to the Filebot license file";
};
cleanupDirectory = mkOption {
type = types.str;
default = "/srv/jellyfin/filebot_cleanup";
description = "Directory where cleaned up media files are stored";
};
};
config = mkIf cfg.enable {
users.groups.filebot_cleanup = {};
users.users.filebot_cleanup = {
isSystemUser = true;
group = "filebot_cleanup";
extraGroups = ["jellyfin_media"];
home = cfg.cleanupDirectory;
createHome = true;
};
nixpkgs.config.allowUnfreePredicate = pkg:
builtins.elem (lib.getName pkg) [
"filebot"
];
environment.systemPackages = with pkgs; [
filebot
];
systemd.services.filebot-cleanup = {
description = "Filebot media cleanup service";
serviceConfig = {
Type = "simple";
User = "filebot_cleanup";
Group = "filebot_cleanup";
ExecStart = pkgs.writeShellScript "filebot-cleanup" ''
${optionalString (cfg.licenseFile != null) ''
${pkgs.filebot}/bin/filebot --license "${cfg.licenseFile}"
''}
${pkgs.filebot}/bin/filebot -rename -r "/srv/jellyfin/media/Movies/" --output "${cfg.cleanupDirectory}/" --format "{jellyfin}" -non-strict --action duplicate
${pkgs.filebot}/bin/filebot -rename -r "/srv/jellyfin/media/Shows/" --output "${cfg.cleanupDirectory}/" --format "{jellyfin}" -non-strict --action duplicate
'';
StandardOutput = "journal";
StandardError = "journal";
};
wantedBy = ["multi-user.target"];
};
environment.persistence = lib.mkIf config.host.impermanence.enable {
"/persist/system/jellyfin" = {
enable = true;
hideMounts = true;
files = [
cfg.licenseFile
];
directories = [
{
directory = cfg.cleanupDirectory;
user = "filebot_cleanup";
group = "filebot_cleanup";
mode = "1770";
}
];
};
};
};
}

View file

@ -41,14 +41,12 @@
# 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;
@ -70,9 +68,6 @@
};
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";

104
flake.lock generated
View file

@ -25,11 +25,11 @@
]
},
"locked": {
"lastModified": 1760701190,
"narHash": "sha256-y7UhnWlER8r776JsySqsbTUh2Txf7K30smfHlqdaIQw=",
"lastModified": 1758287904,
"narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
"owner": "nix-community",
"repo": "disko",
"rev": "3a9450b26e69dcb6f8de6e2b07b3fc1c288d85f5",
"rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
"type": "github"
},
"original": {
@ -46,11 +46,11 @@
},
"locked": {
"dir": "pkgs/firefox-addons",
"lastModified": 1761478231,
"narHash": "sha256-a6ROM73M0TSrooI+8/UMj5KWKOdaDFTycVeo8XJ3dk4=",
"lastModified": 1759403080,
"narHash": "sha256-EteyL8KyG9R5xzqyOBzyag4n2cSemu61VFrl3opJSqE=",
"owner": "rycee",
"repo": "nur-expressions",
"rev": "ae968708476302f8781fb5e245d53f112ed04111",
"rev": "8af6dfcbcbf1115a4f5aeed77ff0db5d3c02caf0",
"type": "gitlab"
},
"original": {
@ -111,6 +111,24 @@
"type": "github"
}
},
"flake-utils_3": {
"inputs": {
"systems": "systems_3"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flakey-profile": {
"locked": {
"lastModified": 1712898590,
@ -133,11 +151,11 @@
]
},
"locked": {
"lastModified": 1761530345,
"narHash": "sha256-+9+YCK9Lh6GThkXu/8JTxMFUnImIdZpb8ElUh6/F5Y8=",
"lastModified": 1759337100,
"narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "bbaeb9f1c29e79bb1653b32c3d73244cdf4bd888",
"rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
"type": "github"
},
"original": {
@ -164,11 +182,11 @@
"lix": {
"flake": false,
"locked": {
"lastModified": 1755787066,
"narHash": "sha256-X2UwkUEban08GRSPXRr+kz8fckHqebr3P77qSvjoeOw=",
"rev": "ac9721a92e8138d29707824dbedb484c76948493",
"lastModified": 1759624822,
"narHash": "sha256-cf40qfsfpxJU/BnQ9PEj027LdPINNSsJqm+C6Ug93BA=",
"rev": "57333a0e600c5e096a609410a2f1059b97194b1e",
"type": "tarball",
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/ac9721a92e8138d29707824dbedb484c76948493.tar.gz?rev=ac9721a92e8138d29707824dbedb484c76948493"
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/57333a0e600c5e096a609410a2f1059b97194b1e.tar.gz"
},
"original": {
"type": "tarball",
@ -185,11 +203,11 @@
]
},
"locked": {
"lastModified": 1759851320,
"narHash": "sha256-n5dRAIC3/78drQtFxmQRrBLd6TKfotUnX7GWu0mAcSg=",
"lastModified": 1756511062,
"narHash": "sha256-IgD1JR7scSEwlK/YAbmrcTWpAYT30LPldCUHdzXkaMs=",
"ref": "refs/heads/main",
"rev": "7c31a18259b8358ac196cf803a26967c0fa1d3e4",
"revCount": 163,
"rev": "3f09a5eb772e02d98bb8878ab687d5b721f00d16",
"revCount": 162,
"type": "git",
"url": "https://git.lix.systems/lix-project/nixos-module.git"
},
@ -207,11 +225,11 @@
]
},
"locked": {
"lastModified": 1760821194,
"narHash": "sha256-UCsJ8eDuHL14u2GFIYEY/drtZ6jht5zN/G/6QNlEy2g=",
"lastModified": 1759342933,
"narHash": "sha256-mdlUFcrOfvT0Pm+Hko/6aR3xf1ao5JA2iem4KsEVjP4=",
"owner": "utensils",
"repo": "mcp-nixos",
"rev": "0ae453f38d0f088c31d4678da3a12b183165986f",
"rev": "50b02bcba32b941d2ec48fedef68641702ca5b0f",
"type": "github"
},
"original": {
@ -227,11 +245,11 @@
]
},
"locked": {
"lastModified": 1761339987,
"narHash": "sha256-IUaawVwItZKi64IA6kF6wQCLCzpXbk2R46dHn8sHkig=",
"lastModified": 1758805352,
"narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=",
"owner": "LnL7",
"repo": "nix-darwin",
"rev": "7cd9aac79ee2924a85c211d21fafd394b06a38de",
"rev": "c48e963a5558eb1c3827d59d21c5193622a1477c",
"type": "github"
},
"original": {
@ -263,16 +281,17 @@
},
"nix-vscode-extensions": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1761530505,
"narHash": "sha256-SbuUyC5pfTcMa9JUqSxFyGJpCqoUsB74tboS22+lByY=",
"lastModified": 1759369908,
"narHash": "sha256-IIhaE6jAge64z+fIyi/8Vtu0JdTtapbp4CvwiuIkZ1E=",
"owner": "nix-community",
"repo": "nix-vscode-extensions",
"rev": "5a5496a7d21265e0ce7641452daf6c560f0eb7a9",
"rev": "a66ad2141b1440a838ead278c6edfe8a4ce75e6c",
"type": "github"
},
"original": {
@ -283,11 +302,11 @@
},
"nixos-hardware": {
"locked": {
"lastModified": 1760958188,
"narHash": "sha256-2m1S4jl+GEDtlt2QqeHil8Ny456dcGSKJAM7q3j/BFU=",
"lastModified": 1759261527,
"narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=",
"owner": "NixOS",
"repo": "nixos-hardware",
"rev": "d6645c340ef7d821602fd2cd199e8d1eed10afbc",
"rev": "e087756cf4abbe1a34f3544c480fc1034d68742f",
"type": "github"
},
"original": {
@ -315,11 +334,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1761373498,
"narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=",
"lastModified": 1759381078,
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce",
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
"type": "github"
},
"original": {
@ -370,11 +389,11 @@
]
},
"locked": {
"lastModified": 1760998189,
"narHash": "sha256-ee2e1/AeGL5X8oy/HXsZQvZnae6XfEVdstGopKucYLY=",
"lastModified": 1759188042,
"narHash": "sha256-f9QC2KKiNReZDG2yyKAtDZh0rSK2Xp1wkPzKbHeQVRU=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "5a7d18b5c55642df5c432aadb757140edfeb70b3",
"rev": "9fcfabe085281dd793589bdc770a2e577a3caa5d",
"type": "github"
},
"original": {
@ -412,6 +431,21 @@
"repo": "default",
"type": "github"
}
},
"systems_3": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

View file

@ -9,7 +9,7 @@
src = fetchurl {
url = "http://tools.mapillary.com/uploader/download/linux/${version}";
name = "mapillary-uploader.AppImage";
sha256 = "sha256-hpWdfeuhYylO+SFD3BsKI0s/xtObCDd5OcuJ6i/aEuI=";
sha256 = "sha256-Oyx7AIdA/2mwBaq7UzXOoyq/z2SU2sViMN40sY2RCQw=";
};
appimageContents = appimageTools.extractType2 {
@ -23,6 +23,9 @@ in
# Install desktop file
install -Dm644 ${appimageContents}/mapillary-desktop-uploader.desktop $out/share/applications/mapillary-uploader.desktop
# Install icon
install -Dm644 ${appimageContents}/usr/share/icons/hicolor/0x0/apps/mapillary-desktop-uploader.png $out/share/pixmaps/mapillary-uploader.png
# Fix desktop file paths
substituteInPlace $out/share/applications/mapillary-uploader.desktop \
--replace 'Exec=AppRun' 'Exec=${pname}'

View file

@ -5,7 +5,6 @@
./user.nix
./flipperzero.nix
./i18n.nix
./impermanence.nix
./openssh.nix
./gnome.nix
./programs

View file

@ -1,16 +1,8 @@
{
lib,
config,
pkgs,
...
}: let
enabledExtensions =
[]
++ lib.optional config.gnome.extensions.dash-to-dock.enable pkgs.gnomeExtensions.dash-to-dock
++ lib.optional config.gnome.extensions.dash-to-panel.enable pkgs.gnomeExtensions.dash-to-panel;
extensions = config.gnome.extraExtensions ++ enabledExtensions;
in {
}: {
options.gnome = {
extraWindowControls = lib.mkEnableOption "Should we add back in the minimize and maximize window controls?";
clockFormat = lib.mkOption {
@ -42,7 +34,7 @@ in {
];
default = "blue";
};
extraExtensions = lib.mkOption {
extensions = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [];
description = "The set of extensions to install and enable in the user environment.";
@ -68,80 +60,16 @@ in {
}));
default = {};
};
displayScaling = lib.mkOption {
type = lib.types.nullOr (lib.types.enum [100 125 150 175 200]);
default = null;
description = "Display scaling percentage for GNOME";
};
experimentalFeatures = lib.mkOption {
type = lib.types.submodule {
options = {
scaleMonitorFramebuffer = lib.mkEnableOption "scale-monitor-framebuffer experimental feature";
};
};
default = {};
description = "GNOME experimental features to enable";
};
nightLight = lib.mkOption {
type = lib.types.submodule {
options = {
enable = lib.mkEnableOption "night light (blue light filter)";
automatic = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to automatically schedule night light based on sunset/sunrise";
};
fromTime = lib.mkOption {
type = lib.types.float;
default = 20.0;
description = "Start time for night light in 24-hour format (e.g., 20.0 for 8:00 PM)";
};
toTime = lib.mkOption {
type = lib.types.float;
default = 6.0;
description = "End time for night light in 24-hour format (e.g., 6.0 for 6:00 AM)";
};
temperature = lib.mkOption {
type = lib.types.int;
default = 4000;
description = "Color temperature for night light (1000-10000K, lower is warmer)";
};
};
};
default = {};
description = "Night light configuration";
};
extensions = {
dash-to-dock = {
enable = lib.mkEnableOption "Dash to Dock extension";
options = lib.mkOption {
type = lib.types.nullOr lib.types.attrs;
default = null;
description = "Dash to Dock configuration options. If null, no custom configuration will be applied.";
};
};
dash-to-panel = {
enable = lib.mkEnableOption "Dash to Panel extension";
options = lib.mkOption {
type = lib.types.nullOr lib.types.attrs;
default = null;
description = "Dash to Panel configuration options. If null, no custom configuration will be applied.";
};
};
};
};
config = {
home.packages = extensions;
home.packages = config.gnome.extensions;
dconf = {
settings = lib.mkMerge [
{
"org/gnome/shell" = {
disable-user-extensions = false; # enables user extensions
enabled-extensions = builtins.map (extension: extension.extensionUuid) extensions;
enabled-extensions = builtins.map (extension: extension.extensionUuid) config.gnome.extensions;
};
"org/gnome/desktop/wm/preferences".button-layout = lib.mkIf config.gnome.extraWindowControls ":minimize,maximize,close";
@ -149,23 +77,7 @@ in {
"org/gnome/desktop/interface".color-scheme = config.gnome.colorScheme;
"org/gnome/desktop/interface".accent-color = config.gnome.accentColor;
"org/gnome/desktop/interface".clock-format = config.gnome.clockFormat;
"org/gnome/desktop/interface".text-scaling-factor = lib.mkIf (config.gnome.displayScaling != null) (config.gnome.displayScaling / 100.0);
"org/gnome/mutter".experimental-features = lib.mkIf (builtins.any (x: x) (builtins.attrValues config.gnome.experimentalFeatures)) (
lib.optional config.gnome.experimentalFeatures.scaleMonitorFramebuffer "scale-monitor-framebuffer"
);
}
# Night light configuration
(lib.mkIf config.gnome.nightLight.enable {
"org/gnome/settings-daemon/plugins/color" = {
night-light-enabled = true;
night-light-schedule-automatic = config.gnome.nightLight.automatic;
night-light-schedule-from = lib.mkIf (!config.gnome.nightLight.automatic) config.gnome.nightLight.fromTime;
night-light-schedule-to = lib.mkIf (!config.gnome.nightLight.automatic) config.gnome.nightLight.toTime;
night-light-temperature = config.gnome.nightLight.temperature;
};
})
(
lib.mkMerge (
builtins.map (value: let
@ -188,15 +100,6 @@ in {
)
)
)
# Extension configurations
(lib.mkIf (config.gnome.extensions.dash-to-dock.enable && config.gnome.extensions.dash-to-dock.options != null) {
"org/gnome/shell/extensions/dash-to-dock" = config.gnome.extensions.dash-to-dock.options;
})
(lib.mkIf (config.gnome.extensions.dash-to-panel.enable && config.gnome.extensions.dash-to-panel.options != null) {
"org/gnome/shell/extensions/dash-to-panel" = config.gnome.extensions.dash-to-panel.options;
})
];
};
};

View file

@ -1,35 +0,0 @@
{
config,
lib,
osConfig,
...
}: let
cfg = config.impermanence;
in {
options.impermanence = {
enable = lib.mkEnableOption "impermanence for home directory";
fallbackPersistence.enable = lib.mkOption {
type = lib.types.bool;
default = true;
};
};
config = lib.mkMerge [
(lib.mkIf config.impermanence.enable {
assertions = [
{
assertion = osConfig.host.impermanence.enable;
message = "impermanence can not be enabled for a user when it is not enabled for the system";
}
];
})
# If impermanence is not enabled for this user but system impermanence is enabled,
# persist the entire home directory as fallback
(lib.mkIf (osConfig.host.impermanence.enable && !cfg.enable && cfg.fallbackPersistence.enable) {
home.persistence."/persist/home/${config.home.username}" = {
directories = ["."];
allowOther = true;
};
})
];
}

View file

@ -95,7 +95,7 @@
);
}
)
(lib.mkIf config.impermanence.enable {
(lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
files = lib.lists.flatten (
builtins.map (hostKey: [".ssh/${hostKey.path}" ".ssh/${hostKey.path}.pub"]) config.programs.openssh.hostKeys

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.bitwarden = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/Bitwarden"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.bruno = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/bruno/"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.calibre = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/calibre"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.davinci-resolve = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.dataHome}/DaVinciResolve"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.dbeaver-bin = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.dataHome}/DBeaverData/"

View file

@ -12,13 +12,11 @@
./obsidian.nix
./prostudiomasters.nix
./idea.nix
./kdenlive.nix
./krita.nix
./protonvpn.nix
./calibre.nix
./bruno.nix
./dbeaver.nix
./dungeon-draft.nix
./steam.nix
./vscode
./ungoogled-chromium.nix
@ -26,7 +24,6 @@
./mapillary-uploader.nix
./inkscape.nix
./gimp.nix
./guild-wars-2.nix
./proxmark3.nix
./freecad.nix
./onionshare.nix
@ -36,14 +33,11 @@
./qflipper.nix
./openvpn.nix
./noisetorch.nix
./olympus.nix
./openrgb.nix
./via.nix
./vortex.nix
./davinci-resolve.nix
./gdx-liftoff.nix
./tor-browser.nix
./polycule.nix
./vmware-workstation.nix
];
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.discord = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/discord/"

View file

@ -1,24 +0,0 @@
{
config,
lib,
...
}: let
cfg = config.programs.dungeon-draft;
in {
options.programs.dungeon-draft = {
enable = lib.mkEnableOption "Dungeon Draft";
};
config = {
assertions = [
{
assertion = !cfg.enable;
message = ''
Dungeon Draft module is not yet fully configured.
Please download the Dungeon Draft executable (.exe) from the official website,
then configure the Wine environment and executable path as needed.
'';
}
];
};
}

View file

@ -1,6 +1,7 @@
{
lib,
config,
osConfig,
...
}: let
buildProfilePersistence = profile: {
@ -25,7 +26,7 @@
allowOther = true;
};
in {
config = lib.mkIf (config.programs.firefox.enable && config.impermanence.enable) {
config = lib.mkIf (config.programs.firefox.enable && osConfig.host.impermanence.enable) {
home.persistence."/persist${config.home.homeDirectory}" = lib.mkMerge (
(
lib.attrsets.mapAttrsToList

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.freecad = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/FreeCAD"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.gdx-liftoff = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.gimp = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/GIMP"

View file

@ -1,24 +0,0 @@
{
config,
lib,
...
}: let
cfg = config.programs.guild-wars-2;
in {
options.programs.guild-wars-2 = {
enable = lib.mkEnableOption "Guild Wars 2";
};
config = {
assertions = [
{
assertion = !cfg.enable;
message = ''
Guild Wars 2 module is not yet fully configured.
Please install Guild Wars 2 manually via Steam or the official client,
then configure the Wine environment as needed.
'';
}
];
};
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.jetbrains.idea-community = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
# configuration

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.inkscape = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/inkscape"

View file

@ -1,36 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.programs.kdenlive;
in {
options.programs.kdenlive = {
enable = lib.mkEnableOption "kdenlive";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.kdePackages.kdenlive;
description = "The kdenlive package to install.";
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
home.packages = [
cfg.package
];
}
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/kdenliverc"
"${config.xdg.dataHome}/kdenlive"
];
allowOther = true;
};
}
)
]);
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.krita = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/kritarc"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.libreoffice = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/libreoffice"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.makemkv = {
@ -29,7 +30,7 @@
home.file.".MakeMKV/settings.conf".source = config.lib.file.mkOutOfStoreSymlink config.sops.templates."MakeMKV.settings.conf".path;
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
".MakeMKV"

View file

@ -11,20 +11,7 @@ in {
enable = mkEnableOption "Mapillary Desktop Uploader";
};
config = mkIf cfg.enable (mkMerge [
{
home.packages = [pkgs.mapillary-uploader];
}
(
mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/mapillary-uploader"
"${config.xdg.dataHome}/mapillary-uploader"
];
allowOther = true;
};
}
)
]);
config = mkIf cfg.enable {
home.packages = [pkgs.mapillary-uploader];
};
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.mfoc = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.noisetorch = {

View file

@ -1,17 +1,13 @@
{
lib,
config,
osConfig,
...
}: {
config = lib.mkIf config.programs.obs-studio.enable (lib.mkMerge [
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/obs-studio"
];
allowOther = true;
};
lib.mkIf osConfig.host.impermanence.enable {
# TODO: map impermanence for obs
}
)
]);

View file

@ -1,11 +1,12 @@
{
lib,
config,
osConfig,
...
}: {
config = lib.mkIf config.programs.obsidian.enable (lib.mkMerge [
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/obsidian"

View file

@ -1,36 +0,0 @@
{
config,
lib,
pkgs,
...
}: let
cfg = config.programs.olympus;
in {
options.programs.olympus = {
enable = lib.mkEnableOption "olympus";
package = lib.mkOption {
type = lib.types.package;
default = pkgs.olympus;
description = "The olympus package to install.";
};
};
config = lib.mkIf cfg.enable (lib.mkMerge [
{
home.packages = [
cfg.package
];
}
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/olympus"
"${config.xdg.dataHome}/olympus"
];
allowOther = true;
};
}
)
]);
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.onionshare = {

View file

@ -2,27 +2,16 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.openrgb = {
enable = lib.mkEnableOption "enable openrgb";
};
config = lib.mkIf config.programs.openrgb.enable (lib.mkMerge [
{
home.packages = with pkgs; [
openrgb
];
}
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/OpenRGB"
];
allowOther = true;
};
}
)
]);
config = lib.mkIf config.programs.openrgb.enable {
home.packages = with pkgs; [
openrgb
];
};
}

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.openvpn = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.pdfarranger = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.picard = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/MusicBrainz"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.piper = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.polycule = {
@ -16,7 +17,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
# TODO: check that these are actually the correct folders
# directories = [

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.prostudiomasters = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/ProStudioMasters"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.protonvpn-gui = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/protonvpn"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.proxmark3 = {

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.qbittorrent = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/qBittorrent"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.qflipper = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/qFlipper"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.signal-desktop-bin = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/Signal"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.steam = {
@ -17,7 +18,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
{

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.tor-browser = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.dataHome}/torbrowser"

View file

@ -2,6 +2,7 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.ungoogled-chromium = {
@ -15,7 +16,7 @@
];
}
(
lib.mkIf config.impermanence.enable {
lib.mkIf osConfig.host.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/chromium"

View file

@ -2,28 +2,16 @@
lib,
pkgs,
config,
osConfig,
...
}: {
options.programs.via = {
enable = lib.mkEnableOption "enable via";
};
config = lib.mkIf config.programs.via.enable (lib.mkMerge [
{
home.packages = with pkgs; [
via
];
}
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
"${config.xdg.configHome}/via"
"${config.xdg.dataHome}/via"
];
allowOther = true;
};
}
)
]);
config = lib.mkIf config.programs.via.enable {
home.packages = with pkgs; [
via
];
};
}

View file

@ -1,37 +0,0 @@
{
lib,
pkgs,
config,
...
}: {
options.programs.vmware-workstation = {
enable = lib.mkEnableOption "enable VMware Workstation";
};
config = lib.mkIf config.programs.vmware-workstation.enable (
lib.mkMerge [
{
home.packages = with pkgs; [
vmware-workstation
];
}
(
lib.mkIf config.impermanence.enable {
home.persistence."/persist${config.home.homeDirectory}" = {
directories = [
{
directory = ".vmware";
method = "symlink";
}
{
directory = "vmware";
method = "symlink";
}
];
allowOther = true;
};
}
)
]
);
}

View file

@ -1,24 +0,0 @@
{
config,
lib,
...
}: let
cfg = config.programs.vortex;
in {
options.programs.vortex = {
enable = lib.mkEnableOption "Vortex (Nexus Mods manager)";
};
config = {
assertions = [
{
assertion = !cfg.enable;
message = ''
Vortex module is not yet fully configured.
Please download and install Vortex manually from the Nexus Mods website,
then configure the Wine environment and dependencies as needed.
'';
}
];
};
}

View file

@ -16,7 +16,6 @@
./go.nix
./evenBetterToml.nix
./openRemoteSsh.nix
./rustAnalyzer.nix
./astroVscode.nix
./vscodeMdx.nix
./claudeDev.nix
@ -24,6 +23,5 @@
./vitest.nix
./direnv.nix
./conventionalCommits.nix
./openDyslexicFont.nix
];
}

View file

@ -1,49 +0,0 @@
{
lib,
pkgs,
config,
...
}: {
options.programs.vscode.profiles = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
options = {
extraExtensions.openDyslexicFont = {
enable = lib.mkEnableOption "should OpenDyslexic font be set as the default font for VSCode";
package = lib.mkPackageOption pkgs "nerd-fonts.open-dyslexic" {
default = ["nerd-fonts" "open-dyslexic"];
};
};
};
config = lib.mkIf config.extraExtensions.openDyslexicFont.enable {
userSettings = {
"editor.fontFamily" = "'OpenDyslexicM Nerd Font Mono', Droid Sans Mono, monospace";
"editor.fontSize" = 14;
"editor.letterSpacing" = -0.3;
};
};
}));
};
config = let
enabledProfiles =
lib.filter (profile: profile.extraExtensions.openDyslexicFont.enable or false)
(lib.attrValues config.programs.vscode.profiles);
anyProfileUsesOpenDyslexicFont = enabledProfiles != [];
fontPackages = lib.unique (map (profile: profile.extraExtensions.openDyslexicFont.package) enabledProfiles);
in {
# Ensure OpenDyslexic font packages are installed when any VSCode profile uses them
home.packages = fontPackages;
fonts.fontconfig.enable = lib.mkIf anyProfileUsesOpenDyslexicFont true;
# Add assertion to ensure the fonts are available
assertions =
map (fontPkg: {
assertion = lib.elem fontPkg config.home.packages;
message = "OpenDyslexic font package '${fontPkg.name or "unknown"}' must be installed when using openDyslexicFont extension for VSCode.";
})
fontPackages;
};
}

View file

@ -1,27 +0,0 @@
{
lib,
pkgs,
config,
...
}: let
pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
pkgsRepository = pkgsRepositories.open-vsx;
in {
options.programs.vscode.profiles = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
options = {
extraExtensions.rustAnalyzer = {
enable = lib.mkEnableOption "should the rust-analyzer extension for vscode be enabled";
extension = lib.mkPackageOption pkgsRepository "rust-analyzer" {
default = ["rust-lang" "rust-analyzer"];
};
};
};
config = lib.mkIf config.extraExtensions.rustAnalyzer.enable {
extensions = [
config.extraExtensions.rustAnalyzer.extension
];
};
}));
};
}

View file

@ -1,24 +0,0 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
dataDirectory = const.dataDirectory;
in {
options.services.actual = {
port = lib.mkOption {
type = lib.types.port;
description = "The port to listen on";
default = 5006;
};
};
config = lib.mkIf config.services.actual.enable {
services.actual = {
settings = {
port = config.services.actual.port;
dataDir = dataDirectory;
};
};
};
}

View file

@ -1,3 +1,3 @@
{
dataDirectory = "/var/lib/private/actual";
dataDirectory = "/var/lib/actual/";
}

View file

@ -1,8 +1,26 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
dataDirectory = const.dataDirectory;
in {
imports = [
./actual.nix
./proxy.nix
./fail2ban.nix
./impermanence.nix
];
config = lib.mkIf config.services.actual.enable {
systemd.tmpfiles.rules = [
"d ${dataDirectory} 2770 actual actual"
];
services.actual = {
settings = {
ACTUAL_DATA_DIR = dataDirectory;
};
};
};
}

View file

@ -6,22 +6,11 @@
const = import ./const.nix;
dataDirectory = const.dataDirectory;
in {
options.services.actual = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.actual.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.actual.impermanence.enable {
config = lib.mkIf (config.services.actual.enable && config.host.impermanence.enable) {
assertions = [
{
assertion = config.services.actual.settings.dataDir == dataDirectory;
message = "actual data location does not match persistence\nconfig directory: ${config.services.actual.settings.dataDir}\npersistence directory: ${dataDirectory}";
}
{
assertion = config.systemd.services.actual.serviceConfig.DynamicUser or false;
message = "actual systemd service must have DynamicUser enabled to use private directory";
assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory;
message = "actual data location does not match persistence";
}
];
environment.persistence."/persist/system/root" = {

View file

@ -4,30 +4,17 @@
...
}: {
options.services.actual = {
domain = lib.mkOption {
subdomain = lib.mkOption {
type = lib.types.str;
description = "domain that actual will be hosted at";
default = "actual.arpa";
};
extraDomains = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "extra domains that should be configured for actual";
default = [];
};
reverseProxy.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.actual.enable && config.services.reverseProxy.enable;
default = "actual";
description = "subdomain of base domain that actual will be hosted at";
};
};
config = lib.mkIf config.services.actual.reverseProxy.enable {
services.reverseProxy.services.actual = {
target = "http://localhost:${toString config.services.actual.settings.port}";
domain = config.services.actual.domain;
extraDomains = config.services.actual.extraDomains;
settings = {
forwardHeaders.enable = true;
config = lib.mkIf (config.services.actual.enable && config.host.reverse_proxy.enable) {
host = {
reverse_proxy.subdomains.${config.services.actual.subdomain} = {
target = "http://localhost:${toString config.services.actual.settings.port}";
};
};
};

View file

@ -1,5 +1,6 @@
{...}: {
imports = [
./proxy.nix
./impermanence.nix
];
}

View file

@ -5,14 +5,7 @@
}: let
bazarr_data_directory = "/var/lib/bazarr";
in {
options.services.bazarr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.bazarr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.bazarr.impermanence.enable {
config = lib.mkIf (config.services.bazarr.enable && config.host.impermanence.enable) {
assertions = [
{
assertion = config.services.bazarr.dataDir == bazarr_data_directory;

View file

@ -0,0 +1,28 @@
{
lib,
config,
...
}: {
options.services.bazarr = {
subdomain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Subdomain for reverse proxy. If null, service will be local only.";
};
extraSubdomains = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra subdomains for reverse proxy.";
};
};
config = lib.mkIf (config.services.bazarr.enable && config.services.bazarr.subdomain != null) {
host.reverse_proxy.subdomains.bazarr = {
subdomain = config.services.bazarr.subdomain;
extraSubdomains = config.services.bazarr.extraSubdomains;
target = "http://127.0.0.1:6767";
websockets.enable = true;
forwardHeaders.enable = true;
};
};
}

View file

@ -1,193 +0,0 @@
{
config,
lib,
...
}: let
cfg = config.services.crab-hole;
in {
options.services.crab-hole = {
port = lib.mkOption {
type = lib.types.port;
default = 8080;
description = "Port for the crab-hole API to listen on.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Whether to open the firewall for the crab-hole API port.";
};
listen = lib.mkOption {
type = lib.types.str;
default = "0.0.0.0";
description = "Address for the crab-hole API to listen on.";
};
show_doc = lib.mkEnableOption "OpenAPI documentation (loads content from third party websites)";
downstreams = {
host = {
enable = lib.mkEnableOption "host downstream DNS server accessible from network on all interfaces";
port = lib.mkOption {
type = lib.types.port;
default = 53;
description = "Port for the host downstream DNS server to listen on.";
};
openFirewall = lib.mkEnableOption "automatic port forwarding for the host downstream";
disableSystemdResolved = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Whether to automatically disable systemd-resolved when using port 53. Set to false if you want to handle the conflict manually.";
};
};
};
extraDownstreams = lib.mkOption {
type = lib.types.listOf (lib.types.submodule {
options = {
protocol = lib.mkOption {
type = lib.types.enum ["udp" "tcp" "tls" "https" "quic"];
description = "Protocol for the downstream server.";
};
listen = lib.mkOption {
type = lib.types.str;
description = "Address to listen on for downstream connections.";
};
port = lib.mkOption {
type = lib.types.port;
description = "Port to listen on for downstream connections.";
};
};
});
default = [];
description = "List of additional downstream DNS server configurations.";
};
upstreams = {
cloudFlare = {
enable = lib.mkEnableOption "Cloudflare DNS over TLS upstream servers (1.1.1.1 and 1.0.0.1)";
};
};
extraUpstreams = lib.mkOption {
type = lib.types.listOf (lib.types.submodule {
options = {
socket_addr = lib.mkOption {
type = lib.types.str;
description = "Socket address of the upstream DNS server (e.g., \"1.1.1.1:853\" or \"[2606:4700:4700::1111]:853\").";
};
protocol = lib.mkOption {
type = lib.types.enum ["udp" "tcp" "tls" "https" "quic"];
description = "Protocol to use for upstream DNS queries.";
};
};
});
default = [];
description = "List of additional upstream DNS server configurations.";
};
blocklists = {
ad_malware = {
enable = lib.mkEnableOption "Host file for blocking ads and malware";
url = lib.mkOption {
type = lib.types.str;
default = "http://sbc.io/hosts/hosts";
description = "URL of the ad and malware blocklist host file";
};
};
};
extraBlocklists = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Additional blocklist URLs to be added to the configuration";
};
};
config = lib.mkIf cfg.enable {
# Assertions for proper configuration
assertions = [
{
assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && config.services.resolved.enable && cfg.downstreams.host.disableSystemdResolved);
message = "crab-hole host downstream cannot use port 53 while systemd-resolved is enabled. Either disable systemd-resolved or use a different port.";
}
{
assertion = !(cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && !cfg.downstreams.host.disableSystemdResolved && config.services.resolved.enable);
message = "crab-hole host downstream is configured to use port 53 but systemd-resolved is still enabled and disableSystemdResolved is false. Set disableSystemdResolved = true or manually disable systemd-resolved.";
}
];
# Automatically disable systemd-resolved if using port 53
services.resolved.enable = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkForce false);
# Configure DNS nameservers when disabling systemd-resolved
networking.nameservers = lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.port == 53 && cfg.downstreams.host.disableSystemdResolved) (lib.mkDefault ["127.0.0.1" "1.1.1.1" "8.8.8.8"]);
services.crab-hole.settings = lib.mkMerge [
{
api = {
port = cfg.port;
listen = cfg.listen;
show_doc = cfg.show_doc;
};
downstream = cfg.extraDownstreams;
upstream.name_servers = cfg.extraUpstreams;
blocklist.lists = cfg.extraBlocklists;
}
(lib.mkIf cfg.blocklists.ad_malware.enable {
blocklist.lists = [cfg.blocklists.ad_malware.url];
})
(lib.mkIf cfg.downstreams.host.enable {
downstream = [
{
protocol = "udp";
listen = "0.0.0.0";
port = cfg.downstreams.host.port;
}
];
})
(lib.mkIf cfg.upstreams.cloudFlare.enable {
upstream.name_servers = [
{
socket_addr = "1.1.1.1:853";
protocol = "tls";
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
trust_nx_responses = false;
}
{
socket_addr = "1.0.0.1:853";
protocol = "tls";
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
trust_nx_responses = false;
}
{
socket_addr = "[2606:4700:4700::1111]:853";
protocol = "tls";
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
trust_nx_responses = false;
}
{
socket_addr = "[2606:4700:4700::1001]:853";
protocol = "tls";
tls_dns_name = "1dot1dot1dot1.cloudflare-dns.com";
trust_nx_responses = false;
}
];
})
];
# Open firewall if requested
networking.firewall = lib.mkMerge [
(lib.mkIf cfg.openFirewall {
allowedTCPPorts = [cfg.port];
})
(lib.mkIf (cfg.downstreams.host.enable && cfg.downstreams.host.openFirewall) {
allowedUDPPorts = [cfg.downstreams.host.port];
})
];
};
}

View file

@ -1,6 +0,0 @@
{...}: {
imports = [
./crab-hole.nix
./impermanence.nix
];
}

View file

@ -1,33 +0,0 @@
{
lib,
config,
...
}: let
workingDirectory = "/var/lib/private/crab-hole";
in {
options.services.crab-hole = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.crab-hole.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.crab-hole.impermanence.enable {
assertions = [
{
assertion =
config.systemd.services.crab-hole.serviceConfig.WorkingDirectory == (builtins.replaceStrings ["/private"] [""] workingDirectory);
message = "crab-hole working directory does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = workingDirectory;
user = "crab-hole";
group = "crab-hole";
}
];
};
};
}

View file

@ -1,23 +1,20 @@
{...}: {
imports = [
./reverseProxy
./fail2ban
./postgres
./reverse_proxy.nix
./fail2ban.nix
./postgres.nix
./network_storage
./podman.nix
./actual
./bazarr
./crab-hole
./flaresolverr
./forgejo
./home-assistant
./immich
./jackett
./jellyfin
./lidarr
./panoramax
./paperless
./qbittorent
./qbittorent.nix
./radarr
./searx
./sonarr

View file

@ -0,0 +1,74 @@
{
lib,
pkgs,
config,
...
}: let
dataFolder = "/var/lib/fail2ban";
dataFile = "fail2ban.sqlite3";
in {
config = lib.mkIf config.services.fail2ban.enable (lib.mkMerge [
{
environment.etc = {
"fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable (
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
[Definition]
failregex = "limiting requests, excess:.* by zone.*client: <HOST>"
'')
);
};
services.fail2ban = {
maxretry = 5;
ignoreIP = [
# Whitelist local networks
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
# tail scale tailnet
"100.64.0.0/10"
"fd7a:115c:a1e0::/48"
];
bantime = "24h"; # Ban IPs for one day on the first ban
bantime-increment = {
enable = true; # Enable increment of bantime after each violation
formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)";
maxtime = "168h"; # Do not ban for more than 1 week
overalljails = true; # Calculate the ban time based on all the violations
};
jails = {
nginx-iptables.settings = lib.mkIf config.services.nginx.enable {
enabled = true;
filter = "nginx";
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
backend = "auto";
findtime = 600;
bantime = 600;
maxretry = 5;
};
# TODO; figure out if there is any fail2ban things we can do on searx
# searx-iptables.settings = lib.mkIf config.services.searx.enable {};
};
};
}
(lib.mkIf config.host.impermanence.enable {
assertions = [
{
assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}";
message = "fail2ban data file does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = dataFolder;
user = "fail2ban";
group = "fail2ban";
}
];
};
})
]);
}

View file

@ -1,6 +0,0 @@
{...}: {
imports = [
./fail2ban.nix
./impermanence.nix
];
}

View file

@ -1,51 +0,0 @@
{
lib,
pkgs,
config,
...
}: {
config = lib.mkIf config.services.fail2ban.enable {
environment.etc = {
"fail2ban/filter.d/nginx.local".text = lib.mkIf config.services.nginx.enable (
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
[Definition]
failregex = "limiting requests, excess:.* by zone.*client: <HOST>"
'')
);
};
services.fail2ban = {
maxretry = 5;
ignoreIP = [
# Whitelist local networks
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
# tail scale tailnet
"100.64.0.0/10"
"fd7a:115c:a1e0::/48"
];
bantime = "24h"; # Ban IPs for one day on the first ban
bantime-increment = {
enable = true; # Enable increment of bantime after each violation
formula = "ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)";
maxtime = "168h"; # Do not ban for more than 1 week
overalljails = true; # Calculate the ban time based on all the violations
};
jails = {
nginx-iptables.settings = lib.mkIf config.services.nginx.enable {
enabled = true;
filter = "nginx";
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
backend = "auto";
findtime = 600;
bantime = 600;
maxretry = 5;
};
# TODO; figure out if there is any fail2ban things we can do on searx
# searx-iptables.settings = lib.mkIf config.services.searx.enable {};
};
};
};
}

View file

@ -1,34 +0,0 @@
{
lib,
config,
...
}: let
dataFolder = "/var/lib/fail2ban";
dataFile = "fail2ban.sqlite3";
in {
options.services.fail2ban = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.fail2ban.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.fail2ban.impermanence.enable {
assertions = [
{
assertion = config.services.fail2ban.daemonSettings.Definition.dbfile == "${dataFolder}/${dataFile}";
message = "fail2ban data file does not match persistence";
}
];
environment.persistence."/persist/system/root" = {
directories = [
{
directory = dataFolder;
user = "fail2ban";
group = "fail2ban";
}
];
};
};
}

View file

@ -1,5 +0,0 @@
{...}: {
imports = [
./impermanence.nix
];
}

View file

@ -1,26 +0,0 @@
{
lib,
config,
...
}: {
options.services.flaresolverr = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.flaresolverr.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.flaresolverr.impermanence.enable {
# FlareSolverr typically doesn't need persistent storage as it's a proxy service
# but we'll add basic structure in case it's needed for logs or configuration
environment.persistence."/persist/system/root" = {
directories = [
{
directory = "/var/lib/flaresolverr";
user = "flaresolverr";
group = "flaresolverr";
}
];
};
};
}

View file

@ -2,31 +2,40 @@
lib,
config,
...
}: let
usingPostgres = config.services.forgejo.database.type == "postgres";
in {
config = lib.mkIf config.services.forgejo.enable {
assertions = [
}: {
config = lib.mkIf config.services.forgejo.enable (
lib.mkMerge [
{
assertion = !usingPostgres || config.services.postgresql.enable;
message = "PostgreSQL must be enabled when Forgejo database type is postgres";
}
{
assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (db: db == "forgejo") config.services.postgresql.ensureDatabases);
message = "Forgejo built-in database creation failed - expected 'forgejo' in ensureDatabases but got: ${builtins.toString config.services.postgresql.ensureDatabases}";
}
{
assertion = !(usingPostgres && config.services.forgejo.database.createDatabase) || (builtins.any (user: user.name == "forgejo") config.services.postgresql.ensureUsers);
message = "Forgejo built-in user creation failed - expected user 'forgejo' in ensureUsers but got: ${builtins.toString (builtins.map (u: u.name) config.services.postgresql.ensureUsers)}";
}
];
host = {
postgres = {
enable = true;
};
};
services.forgejo.database.createDatabase = lib.mkDefault usingPostgres;
systemd.services.forgejo = lib.mkIf usingPostgres {
requires = [
config.systemd.services.postgresql.name
];
};
};
assertions = [
{
assertion = config.services.forgejo.settings.database.DB_TYPE == "postgres";
message = "Forgejo database type must be postgres";
}
];
}
(lib.mkIf config.host.postgres.enable {
host = {
postgres = {
extraUsers = {
forgejo = {
isClient = true;
createUser = true;
};
};
extraDatabases = {
forgejo = {
name = "forgejo";
};
};
};
};
})
]
);
}

View file

@ -1,9 +1,53 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
httpPort = const.httpPort;
sshPort = const.sshPort;
db_user = "forgejo";
in {
imports = [
./forgejo.nix
./proxy.nix
./database.nix
./fail2ban.nix
./impermanence.nix
];
config = lib.mkIf config.services.forgejo.enable {
assertions = [
{
assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name;
message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name";
}
];
services.forgejo = {
database = {
type = "postgres";
socket = "/run/postgresql";
};
lfs.enable = true;
settings = {
server = {
DOMAIN = "${config.services.forgejo.subdomain}.${config.host.reverse_proxy.hostname}";
HTTP_PORT = httpPort;
START_SSH_SERVER = true;
SSH_LISTEN_PORT = sshPort;
SSH_PORT = 22;
BUILTIN_SSH_SERVER_USER = "git";
ROOT_URL = "https://git.jan-leila.com";
};
service = {
DISABLE_REGISTRATION = true;
};
database = {
DB_TYPE = "postgres";
NAME = db_user;
USER = db_user;
};
};
};
};
}

View file

@ -4,16 +4,7 @@
pkgs,
...
}: {
options.services.forgejo = {
fail2ban = {
enable = lib.mkOption {
type = lib.types.bool;
default = config.services.forgejo.enable && config.services.fail2ban.enable;
};
};
};
config = lib.mkIf config.services.forgejo.fail2ban.enable {
config = lib.mkIf (config.services.forgejo.enable && config.services.fail2ban.enable) {
environment.etc = {
"fail2ban/filter.d/forgejo.local".text = lib.mkIf config.services.forgejo.enable (
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''

View file

@ -1,46 +0,0 @@
{
lib,
config,
...
}: let
const = import ./const.nix;
httpPort = const.httpPort;
sshPort = const.sshPort;
db_user = "forgejo";
in {
config = lib.mkIf config.services.forgejo.enable {
assertions = [
{
assertion = config.services.forgejo.settings.server.BUILTIN_SSH_SERVER_USER == config.users.users.git.name;
message = "Forgejo BUILTIN_SSH_SERVER_USER hardcoded value does not match expected git user name";
}
];
services.forgejo = {
database = {
type = "postgres";
socket = "/run/postgresql";
};
lfs.enable = true;
settings = {
server = {
DOMAIN = config.services.forgejo.reverseProxy.domain;
HTTP_PORT = httpPort;
START_SSH_SERVER = true;
SSH_LISTEN_PORT = sshPort;
SSH_PORT = 22;
BUILTIN_SSH_SERVER_USER = "git";
ROOT_URL = "https://git.jan-leila.com";
};
service = {
DISABLE_REGISTRATION = true;
};
database = {
DB_TYPE = "postgres";
NAME = db_user;
USER = db_user;
};
};
};
};
}

View file

@ -5,14 +5,7 @@
}: let
stateDir = "/var/lib/forgejo";
in {
options.services.forgejo = {
impermanence.enable = lib.mkOption {
type = lib.types.bool;
default = config.services.forgejo.enable && config.host.impermanence.enable;
};
};
config = lib.mkIf config.services.forgejo.impermanence.enable {
config = lib.mkIf (config.services.forgejo.enable && config.host.impermanence.enable) {
assertions = [
{
assertion = config.services.forgejo.stateDir == stateDir;

View file

@ -7,33 +7,16 @@
httpPort = const.httpPort;
in {
options.services.forgejo = {
reverseProxy = {
enable = lib.mkOption {
type = lib.types.bool;
default = config.services.forgejo.enable && config.services.reverseProxy.enable;
};
domain = lib.mkOption {
type = lib.types.str;
description = "domain that forgejo will be hosted at";
default = "git.jan-leila.com";
};
extraDomains = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "extra domains that should be configured for forgejo";
default = [];
};
subdomain = lib.mkOption {
type = lib.types.str;
description = "subdomain of base domain that forgejo will be hosted at";
default = "forgejo";
};
};
config = lib.mkIf config.services.forgejo.reverseProxy.enable {
services.reverseProxy.services.forgejo = {
config = lib.mkIf (config.services.forgejo.enable && config.host.reverse_proxy.enable) {
host.reverse_proxy.subdomains.${config.services.forgejo.subdomain} = {
target = "http://localhost:${toString httpPort}";
domain = config.services.forgejo.reverseProxy.domain;
extraDomains = config.services.forgejo.reverseProxy.extraDomains;
settings = {
forwardHeaders.enable = true;
};
};
networking.firewall.allowedTCPPorts = [

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