Merge branch 'main' into main
This commit is contained in:
commit
28a962d712
118 changed files with 6316 additions and 971 deletions
41
README.md
41
README.md
|
@ -7,19 +7,19 @@ nix multi user, multi system, configuration with `sops` secret management, `home
|
||||||
# Hosts
|
# Hosts
|
||||||
|
|
||||||
## Host Map
|
## Host Map
|
||||||
| Hostname | Device Description | Primary User | Role |
|
| Hostname | Device Description | Primary User | Role | Provisioned | Using Nix |
|
||||||
| :---------: | :------------------------: | :--------------: | :-------: |
|
| :---------: | :------------------------: | :--------------: | :-------: | :---------: | :-------: |
|
||||||
| `twilight` | Desktop Computer | Leyla | Desktop |
|
| `twilight` | Desktop Computer | Leyla | Desktop | ✅ | ✅ |
|
||||||
| `horizon` | 13 inch Framework Laptop | Leyla | Laptop |
|
| `horizon` | 13 inch Framework Laptop | Leyla | Laptop | ✅ | ✅ |
|
||||||
| `defiant` | NAS Server | Leyla | Server |
|
| `defiant` | NAS Server | Leyla | Server | ✅ | ✅ |
|
||||||
| `hesperium` | Mac | ????? | ??? |
|
| `hesperium` | Mac | ????? | Mac | ❌ | ❌ |
|
||||||
| `emergent` | Desktop Computer | Eve | Desktop |
|
| `emergent` | Desktop Computer | Eve | Desktop | ✅ | ✅ |
|
||||||
| `threshold` | Laptop | Eve | Laptop |
|
| `threshold` | Laptop | Eve | Laptop | ❌ | ❌ |
|
||||||
| `wolfram` | Steam Deck | House | Handheld |
|
| `wolfram` | Steam Deck | House | Handheld | ✅ | ❌ |
|
||||||
| `ceder` | A5 Tablet (not using nix) | Leyla | Tablet |
|
| `ceder` | A5 Tablet | Leyla | Tablet | ✅ | ❌ |
|
||||||
| `skate` | A6 Tablet (not using nix) | Leyla | Tablet |
|
| `skate` | A6 Tablet | Leyla | Tablet | ❌ | ❌ |
|
||||||
| `shale` | A6 Tablet (not using nix) | Eve | Tablet |
|
| `shale` | A6 Tablet | Eve | Tablet | ✅ | ❌ |
|
||||||
| `coven` | Pixel 8 (not using nix) | Leyla | Android |
|
| `coven` | Pixel 8 | Leyla | Android | ✅ | ❌ |
|
||||||
|
|
||||||
# Tooling
|
# Tooling
|
||||||
## Rebuilding
|
## Rebuilding
|
||||||
|
@ -43,7 +43,6 @@ 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 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/
|
- Look into this for npins https://jade.fyi/blog/pinning-nixos-with-npins/
|
||||||
- https://nixos-and-flakes.thiscute.world/
|
- https://nixos-and-flakes.thiscute.world/
|
||||||
- nix config mcp https://github.com/utensils/mcp-nixos
|
|
||||||
|
|
||||||
# Tasks:
|
# Tasks:
|
||||||
|
|
||||||
|
@ -67,4 +66,16 @@ nix multi user, multi system, configuration with `sops` secret management, `home
|
||||||
- rotate sops encryption keys periodically (and somehow sync between devices?)
|
- rotate sops encryption keys periodically (and somehow sync between devices?)
|
||||||
- wake on LAN for updates
|
- wake on LAN for updates
|
||||||
- remote distributed builds - https://nix.dev/tutorials/nixos/distributed-builds-setup.html
|
- 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
|
- 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
|
||||||
|
|
|
@ -8,5 +8,6 @@
|
||||||
in {
|
in {
|
||||||
leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla);
|
leyla = lib.mkIf users.leyla.isNormalUser (import ./leyla);
|
||||||
eve = lib.mkIf users.eve.isNormalUser (import ./eve);
|
eve = lib.mkIf users.eve.isNormalUser (import ./eve);
|
||||||
|
ivy = lib.mkIf users.ivy.isNormalUser (import ./ivy);
|
||||||
git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git);
|
git = lib.mkIf (osConfig.services.forgejo.enable or false) (import ./git);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ in {
|
||||||
# See https://search.nixos.org/packages for all options
|
# See https://search.nixos.org/packages for all options
|
||||||
home.packages = lib.lists.optionals userConfig.isDesktopUser (
|
home.packages = lib.lists.optionals userConfig.isDesktopUser (
|
||||||
with pkgs; [
|
with pkgs; [
|
||||||
ungoogled-chromium
|
|
||||||
gnomeExtensions.dash-to-panel
|
gnomeExtensions.dash-to-panel
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
@ -61,6 +60,7 @@ in {
|
||||||
steam.enable = true;
|
steam.enable = true;
|
||||||
piper.enable = hardware.piperMouse.enable;
|
piper.enable = hardware.piperMouse.enable;
|
||||||
krita.enable = true;
|
krita.enable = true;
|
||||||
|
ungoogled-chromium.enable = true;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
55
configurations/home-manager/ivy/default.nix
Normal file
55
configurations/home-manager/ivy/default.nix
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{osConfig, ...}: let
|
||||||
|
userConfig = osConfig.host.users.ivy;
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
./packages.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
home = {
|
||||||
|
username = userConfig.name;
|
||||||
|
homeDirectory = osConfig.users.users.ivy.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/ivy/etc/profile.d/hm-session-vars.sh
|
||||||
|
#
|
||||||
|
sessionVariables = {
|
||||||
|
# EDITOR = "emacs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
73
configurations/home-manager/ivy/packages.nix
Normal file
73
configurations/home-manager/ivy/packages.nix
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = {
|
||||||
|
nixpkgs.config = {
|
||||||
|
allowUnfree = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Programs that need to be installed with some extra configuration
|
||||||
|
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;
|
||||||
|
# userName = "Ivy";
|
||||||
|
# userEmail = "ivy@example.com"; # Update this with actual email
|
||||||
|
# extraConfig.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;
|
||||||
|
mutableExtensionsDir = false;
|
||||||
|
|
||||||
|
profiles.default = {
|
||||||
|
enableUpdateCheck = false;
|
||||||
|
enableExtensionUpdateCheck = false;
|
||||||
|
|
||||||
|
extraExtensions = {
|
||||||
|
# Cline extension (Claude AI assistant)
|
||||||
|
claudeDev.enable = true;
|
||||||
|
# Auto Rename Tag
|
||||||
|
autoRenameTag.enable = true;
|
||||||
|
# Live Server
|
||||||
|
liveServer.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
extensions = let
|
||||||
|
extension-pkgs = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
|
||||||
|
in (
|
||||||
|
with extension-pkgs.open-vsx; [
|
||||||
|
streetsidesoftware.code-spell-checker
|
||||||
|
]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
firefox.enable = true;
|
||||||
|
discord.enable = true;
|
||||||
|
signal-desktop-bin.enable = true;
|
||||||
|
claude-code.enable = true;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -37,6 +37,12 @@ in {
|
||||||
dbeaver-bin.enable = true;
|
dbeaver-bin.enable = true;
|
||||||
bruno.enable = true;
|
bruno.enable = true;
|
||||||
piper.enable = hardware.piperMouse.enable;
|
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;
|
||||||
|
davinci-resolve.enable = hardware.graphicsAcceleration.enable;
|
||||||
|
mfoc.enable = true;
|
||||||
})
|
})
|
||||||
(lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) {
|
(lib.mkIf (hardware.directAccess.enable && config.user.isDesktopUser) {
|
||||||
anki.enable = true;
|
anki.enable = true;
|
||||||
|
@ -50,6 +56,22 @@ in {
|
||||||
firefox.enable = true;
|
firefox.enable = true;
|
||||||
steam.enable = true;
|
steam.enable = true;
|
||||||
krita.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;
|
||||||
|
tor-browser.enable = true;
|
||||||
|
gdx-liftoff.enable = true;
|
||||||
|
# polycule package is now working with Flutter 3.29
|
||||||
|
polycule.enable = true;
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -66,53 +88,6 @@ in {
|
||||||
nixpkgs.config = {
|
nixpkgs.config = {
|
||||||
allowUnfree = true;
|
allowUnfree = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = (
|
|
||||||
(with pkgs; [
|
|
||||||
proxmark3
|
|
||||||
])
|
|
||||||
++ (
|
|
||||||
lib.lists.optionals hardware.directAccess.enable (with pkgs; [
|
|
||||||
#foss platforms
|
|
||||||
ungoogled-chromium
|
|
||||||
libreoffice
|
|
||||||
inkscape
|
|
||||||
gimp
|
|
||||||
freecad
|
|
||||||
# cura
|
|
||||||
# kicad-small
|
|
||||||
onionshare
|
|
||||||
# rhythmbox
|
|
||||||
|
|
||||||
# wireshark
|
|
||||||
# rpi-imager
|
|
||||||
# fritzing
|
|
||||||
mfoc
|
|
||||||
tor-browser
|
|
||||||
pdfarranger
|
|
||||||
picard
|
|
||||||
|
|
||||||
gdx-liftoff
|
|
||||||
|
|
||||||
# proprietary platforms
|
|
||||||
(lib.mkIf hardware.graphicsAcceleration.enable davinci-resolve)
|
|
||||||
|
|
||||||
# development tools
|
|
||||||
# androidStudioPackages.canary
|
|
||||||
qFlipper
|
|
||||||
|
|
||||||
# system tools
|
|
||||||
openvpn
|
|
||||||
noisetorch
|
|
||||||
|
|
||||||
# hardware management tools
|
|
||||||
(lib.mkIf hardware.openRGB.enable openrgb)
|
|
||||||
(lib.mkIf hardware.viaKeyboard.enable via)
|
|
||||||
|
|
||||||
(lib.mkIf osConfig.host.ai.enable claude-code)
|
|
||||||
])
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,13 +71,47 @@ in {
|
||||||
claudeDev = lib.mkIf ai-tooling-enabled {
|
claudeDev = lib.mkIf ai-tooling-enabled {
|
||||||
enable = true;
|
enable = true;
|
||||||
mcp = {
|
mcp = {
|
||||||
nixos.enable = true;
|
nixos = {
|
||||||
eslint.enable = true;
|
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
|
# misc extensions
|
||||||
evenBetterToml.enable = true;
|
evenBetterToml.enable = true;
|
||||||
|
direnv.enable = config.programs.direnv.enable;
|
||||||
|
conventionalCommits.enable = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
extensions = let
|
extensions = let
|
||||||
|
|
|
@ -132,23 +132,24 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# "20-wg0" = {
|
"20-wg0" = {
|
||||||
# netdevConfig = {
|
netdevConfig = {
|
||||||
# Kind = "wireguard";
|
Kind = "wireguard";
|
||||||
# Name = "wg0";
|
Name = "wg0";
|
||||||
# };
|
};
|
||||||
# wireguardConfig = {
|
wireguardConfig = {
|
||||||
# PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path;
|
PrivateKeyFile = config.sops.secrets."vpn-keys/proton-wireguard/defiant-p2p".path;
|
||||||
# ListenPort = 51820;
|
ListenPort = 51820;
|
||||||
# };
|
};
|
||||||
# wireguardPeers = [
|
wireguardPeers = [
|
||||||
# {
|
{
|
||||||
# PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0=";
|
PublicKey = "rRO6yJim++Ezz6scCLMaizI+taDjU1pzR2nfW6qKbW0=";
|
||||||
# Endpoint = "185.230.126.146:51820";
|
Endpoint = "185.230.126.146:51820";
|
||||||
# AllowedIPs = ["0.0.0.0/0"];
|
# Allow all traffic but use policy routing to prevent system-wide VPN
|
||||||
# }
|
AllowedIPs = ["0.0.0.0/0"];
|
||||||
# ];
|
}
|
||||||
# };
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
networks = {
|
networks = {
|
||||||
"40-bond0" = {
|
"40-bond0" = {
|
||||||
|
@ -163,36 +164,67 @@
|
||||||
"192.168.1.10/32"
|
"192.168.1.10/32"
|
||||||
];
|
];
|
||||||
|
|
||||||
gateway = ["192.168.1.1"];
|
# 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"];
|
dns = ["192.168.1.1"];
|
||||||
};
|
};
|
||||||
|
|
||||||
# For some reason this isn't working. It looks like traffic goes out and comes back but doesn't get correctly routed back to the wg interface on the return trip
|
"50-wg0" = {
|
||||||
# debugging steps:
|
matchConfig.Name = "wg0";
|
||||||
# try sending data on the interface `ping -I wg0 8.8.8.8`
|
networkConfig = {
|
||||||
# view all traffic on the interface `sudo tshark -i wg0`
|
DHCP = "no";
|
||||||
# see what applications are listening to port 14666 (thats what we currently have qbittorent set up to use) `ss -tuln | grep 14666`
|
};
|
||||||
# "50-wg0" = {
|
address = [
|
||||||
# matchConfig.Name = "wg0";
|
"10.2.0.2/32"
|
||||||
# networkConfig = {
|
];
|
||||||
# DHCP = "no";
|
# Configure routing for application binding
|
||||||
# };
|
routingPolicyRules = [
|
||||||
# address = [
|
{
|
||||||
# "10.2.0.2/32"
|
# Route traffic from VPN interface through VPN table
|
||||||
# ];
|
From = "10.2.0.2/32";
|
||||||
# # routes = [
|
Table = 200;
|
||||||
# # {
|
Priority = 100;
|
||||||
# # Destination = "10.2.0.2/32";
|
}
|
||||||
# # Gateway = "10.2.0.1";
|
];
|
||||||
# # }
|
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
|
# 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"];
|
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 = {
|
services = {
|
||||||
# temp enable desktop environment for setup
|
# temp enable desktop environment for setup
|
||||||
# Enable the X11 windowing system.
|
# Enable the X11 windowing system.
|
||||||
|
@ -306,12 +338,35 @@
|
||||||
passwordFile = config.sops.secrets."services/paperless_password".path;
|
passwordFile = config.sops.secrets."services/paperless_password".path;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
panoramax = {
|
||||||
|
enable = false;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
|
||||||
qbittorrent = {
|
qbittorrent = {
|
||||||
enable = true;
|
enable = true;
|
||||||
mediaDir = "/srv/qbittorent";
|
mediaDir = "/srv/qbittorent";
|
||||||
openFirewall = true;
|
openFirewall = true;
|
||||||
webuiPort = 8084;
|
webuiPort = 8084;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
filebot-cleanup = {
|
||||||
|
enable = true;
|
||||||
|
licenseFile = "/srv/jellyfin/filebot_license.psm";
|
||||||
|
};
|
||||||
|
|
||||||
|
sonarr = {
|
||||||
|
enable = false;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
radarr = {
|
||||||
|
enable = false;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
|
bazarr = {
|
||||||
|
enable = false;
|
||||||
|
openFirewall = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# disable computer sleeping
|
# disable computer sleeping
|
||||||
|
|
|
@ -3,5 +3,7 @@
|
||||||
imports = [
|
imports = [
|
||||||
./hardware-configuration.nix
|
./hardware-configuration.nix
|
||||||
./configuration.nix
|
./configuration.nix
|
||||||
|
./packages.nix
|
||||||
|
./filebot.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
82
configurations/nixos/defiant/filebot.nix
Normal file
82
configurations/nixos/defiant/filebot.nix
Normal 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";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
9
configurations/nixos/defiant/packages.nix
Normal file
9
configurations/nixos/defiant/packages.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{pkgs, ...}: {
|
||||||
|
environment.systemPackages = with pkgs; [
|
||||||
|
ffsubsync
|
||||||
|
sox
|
||||||
|
yt-dlp
|
||||||
|
ffmpeg
|
||||||
|
imagemagick
|
||||||
|
];
|
||||||
|
}
|
|
@ -32,6 +32,7 @@
|
||||||
isPrincipleUser = true;
|
isPrincipleUser = true;
|
||||||
};
|
};
|
||||||
eve.isDesktopUser = true;
|
eve.isDesktopUser = true;
|
||||||
|
ivy.isDesktopUser = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
hardware = {
|
hardware = {
|
||||||
|
|
177
flake.lock
generated
177
flake.lock
generated
|
@ -25,11 +25,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756733629,
|
"lastModified": 1758287904,
|
||||||
"narHash": "sha256-dwWGlDhcO5SMIvMSTB4mjQ5Pvo2vtxvpIknhVnSz2I8=",
|
"narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "disko",
|
"repo": "disko",
|
||||||
"rev": "a5c4f2ab72e3d1ab43e3e65aa421c6f2bd2e12a1",
|
"rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -46,11 +46,11 @@
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"dir": "pkgs/firefox-addons",
|
"dir": "pkgs/firefox-addons",
|
||||||
"lastModified": 1756699417,
|
"lastModified": 1759403080,
|
||||||
"narHash": "sha256-rpRy5ae5ijEGaK+Cr66NqCQJ6ZeUE5Zi8gUWgKhesto=",
|
"narHash": "sha256-EteyL8KyG9R5xzqyOBzyag4n2cSemu61VFrl3opJSqE=",
|
||||||
"owner": "rycee",
|
"owner": "rycee",
|
||||||
"repo": "nur-expressions",
|
"repo": "nur-expressions",
|
||||||
"rev": "007b803d1eff595d25e7886e83054dbd038bf029",
|
"rev": "8af6dfcbcbf1115a4f5aeed77ff0db5d3c02caf0",
|
||||||
"type": "gitlab"
|
"type": "gitlab"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -111,6 +111,39 @@
|
||||||
"type": "github"
|
"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,
|
||||||
|
"narHash": "sha256-FhGIEU93VHAChKEXx905TSiPZKga69bWl1VB37FK//I=",
|
||||||
|
"owner": "lf-",
|
||||||
|
"repo": "flakey-profile",
|
||||||
|
"rev": "243c903fd8eadc0f63d205665a92d4df91d42d9d",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lf-",
|
||||||
|
"repo": "flakey-profile",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"home-manager": {
|
"home-manager": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
@ -118,11 +151,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756734952,
|
"lastModified": 1759337100,
|
||||||
"narHash": "sha256-H6jmduj4QIncLPAPODPSG/8ry9lpr1kRq6fYytU52qU=",
|
"narHash": "sha256-CcT3QvZ74NGfM+lSOILcCEeU+SnqXRvl1XCRHenZ0Us=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "29ab63bbb3d9eee4a491f7ce701b189becd34068",
|
"rev": "004753ae6b04c4b18aa07192c1106800aaacf6c3",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -146,20 +179,57 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mcp-nixos": {
|
"lix": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1759624822,
|
||||||
|
"narHash": "sha256-cf40qfsfpxJU/BnQ9PEj027LdPINNSsJqm+C6Ug93BA=",
|
||||||
|
"rev": "57333a0e600c5e096a609410a2f1059b97194b1e",
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://git.lix.systems/api/v1/repos/lix-project/lix/archive/57333a0e600c5e096a609410a2f1059b97194b1e.tar.gz"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://git.lix.systems/lix-project/lix/archive/main.tar.gz"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lix-module": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"devshell": "devshell",
|
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
|
"flakey-profile": "flakey-profile",
|
||||||
|
"lix": "lix",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755372538,
|
"lastModified": 1756511062,
|
||||||
"narHash": "sha256-iWhsf1Myk6RyQ7IuNf4bWI3Sqq9pgmhKvEisCXtkxyw=",
|
"narHash": "sha256-IgD1JR7scSEwlK/YAbmrcTWpAYT30LPldCUHdzXkaMs=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "3f09a5eb772e02d98bb8878ab687d5b721f00d16",
|
||||||
|
"revCount": 162,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.lix.systems/lix-project/nixos-module.git"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.lix.systems/lix-project/nixos-module.git"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mcp-nixos": {
|
||||||
|
"inputs": {
|
||||||
|
"devshell": "devshell",
|
||||||
|
"flake-utils": "flake-utils_2",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1759342933,
|
||||||
|
"narHash": "sha256-mdlUFcrOfvT0Pm+Hko/6aR3xf1ao5JA2iem4KsEVjP4=",
|
||||||
"owner": "utensils",
|
"owner": "utensils",
|
||||||
"repo": "mcp-nixos",
|
"repo": "mcp-nixos",
|
||||||
"rev": "46b4d4d3d6421bfbadc415532ef74433871e1cda",
|
"rev": "50b02bcba32b941d2ec48fedef68641702ca5b0f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -175,11 +245,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1755825449,
|
"lastModified": 1758805352,
|
||||||
"narHash": "sha256-XkiN4NM9Xdy59h69Pc+Vg4PxkSm9EWl6u7k6D5FZ5cM=",
|
"narHash": "sha256-BHdc43Lkayd+72W/NXRKHzX5AZ+28F3xaUs3a88/Uew=",
|
||||||
"owner": "LnL7",
|
"owner": "LnL7",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "8df64f819698c1fee0c2969696f54a843b2231e8",
|
"rev": "c48e963a5558eb1c3827d59d21c5193622a1477c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -211,17 +281,17 @@
|
||||||
},
|
},
|
||||||
"nix-vscode-extensions": {
|
"nix-vscode-extensions": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_3",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756692643,
|
"lastModified": 1759369908,
|
||||||
"narHash": "sha256-SVos3AYuLvF6bD8Y0b6EiLABoEaiAOa4M/fTCBe0FV8=",
|
"narHash": "sha256-IIhaE6jAge64z+fIyi/8Vtu0JdTtapbp4CvwiuIkZ1E=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nix-vscode-extensions",
|
"repo": "nix-vscode-extensions",
|
||||||
"rev": "2f1d16db96f1ce8ee3c893ea9dc49c0035846988",
|
"rev": "a66ad2141b1440a838ead278c6edfe8a4ce75e6c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -232,11 +302,11 @@
|
||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756245047,
|
"lastModified": 1759261527,
|
||||||
"narHash": "sha256-9bHzrVbjAudbO8q4vYFBWlEkDam31fsz0J7GB8k4AsI=",
|
"narHash": "sha256-wPd5oGvBBpUEzMF0kWnXge0WITNsITx/aGI9qLHgJ4g=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "a65b650d6981e23edd1afa1f01eb942f19cdcbb7",
|
"rev": "e087756cf4abbe1a34f3544c480fc1034d68742f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -264,11 +334,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756542300,
|
"lastModified": 1759381078,
|
||||||
"narHash": "sha256-tlOn88coG5fzdyqz6R93SQL5Gpq+m/DsWpekNFhqPQk=",
|
"narHash": "sha256-gTrEEp5gEspIcCOx9PD8kMaF1iEmfBcTbO0Jag2QhQs=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "d7600c775f877cd87b4f5a831c28aa94137377aa",
|
"rev": "7df7ff7d8e00218376575f0acdcc5d66741351ee",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -285,6 +355,7 @@
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"impermanence": "impermanence",
|
"impermanence": "impermanence",
|
||||||
|
"lix-module": "lix-module",
|
||||||
"mcp-nixos": "mcp-nixos",
|
"mcp-nixos": "mcp-nixos",
|
||||||
"nix-darwin": "nix-darwin",
|
"nix-darwin": "nix-darwin",
|
||||||
"nix-syncthing": "nix-syncthing",
|
"nix-syncthing": "nix-syncthing",
|
||||||
|
@ -292,18 +363,17 @@
|
||||||
"nixos-hardware": "nixos-hardware",
|
"nixos-hardware": "nixos-hardware",
|
||||||
"nixpkgs": "nixpkgs_2",
|
"nixpkgs": "nixpkgs_2",
|
||||||
"secrets": "secrets",
|
"secrets": "secrets",
|
||||||
"sops-nix": "sops-nix",
|
"sops-nix": "sops-nix"
|
||||||
"steam-fetcher": "steam-fetcher"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"secrets": {
|
"secrets": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1752531440,
|
"lastModified": 1759945215,
|
||||||
"narHash": "sha256-04tQ3EUrtmZ7g6fVUkZC4AbAG+Z7lng79qU3jsiqWJY=",
|
"narHash": "sha256-xmUzOuhJl6FtTjR5++OQvSoAnXe7/VA5QFCZDyFwBXo=",
|
||||||
"ref": "refs/heads/main",
|
"ref": "refs/heads/main",
|
||||||
"rev": "f016767c13aa36dde91503f7a9f01bdd02468045",
|
"rev": "444229a105445339fb028d15a8d866063c5f8141",
|
||||||
"revCount": 20,
|
"revCount": 21,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git"
|
"url": "ssh://git@git.jan-leila.com/jan-leila/nix-config-secrets.git"
|
||||||
},
|
},
|
||||||
|
@ -319,11 +389,11 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754988908,
|
"lastModified": 1759188042,
|
||||||
"narHash": "sha256-t+voe2961vCgrzPFtZxha0/kmFSHFobzF00sT8p9h0U=",
|
"narHash": "sha256-f9QC2KKiNReZDG2yyKAtDZh0rSK2Xp1wkPzKbHeQVRU=",
|
||||||
"owner": "Mic92",
|
"owner": "Mic92",
|
||||||
"repo": "sops-nix",
|
"repo": "sops-nix",
|
||||||
"rev": "3223c7a92724b5d804e9988c6b447a0d09017d48",
|
"rev": "9fcfabe085281dd793589bdc770a2e577a3caa5d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -332,26 +402,6 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"steam-fetcher": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1714795926,
|
|
||||||
"narHash": "sha256-PkgC9jqoN6cJ8XYzTA2PlrWs7aPJkM3BGiTxNqax0cA=",
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "steam-fetcher",
|
|
||||||
"rev": "12f66eafb7862d91b3e30c14035f96a21941bd9c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-community",
|
|
||||||
"repo": "steam-fetcher",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
|
@ -381,6 +431,21 @@
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"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",
|
"root": "root",
|
||||||
|
|
13
flake.nix
13
flake.nix
|
@ -5,10 +5,10 @@
|
||||||
# base packages
|
# base packages
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
# lix-module = {
|
lix-module = {
|
||||||
# url = "https://git.lix.systems/lix-project/nixos-module/archive/2.93.3-1.tar.gz";
|
url = "git+https://git.lix.systems/lix-project/nixos-module.git";
|
||||||
# inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
# };
|
};
|
||||||
|
|
||||||
# secret encryption
|
# secret encryption
|
||||||
sops-nix = {
|
sops-nix = {
|
||||||
|
@ -72,11 +72,6 @@
|
||||||
url = "github:edolstra/flake-compat";
|
url = "github:edolstra/flake-compat";
|
||||||
};
|
};
|
||||||
|
|
||||||
steam-fetcher = {
|
|
||||||
url = "github:nix-community/steam-fetcher";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
# MCP NixOS server for Claude Dev
|
# MCP NixOS server for Claude Dev
|
||||||
mcp-nixos = {
|
mcp-nixos = {
|
||||||
url = "github:utensils/mcp-nixos";
|
url = "github:utensils/mcp-nixos";
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# this folder is for derivation overlays
|
# this folder is for derivation overlays
|
||||||
{inputs, ...}: {
|
{inputs, ...}: {
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
inputs.steam-fetcher.overlays.default
|
|
||||||
inputs.nix-vscode-extensions.overlays.default
|
inputs.nix-vscode-extensions.overlays.default
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
{pkgs, ...}: {
|
{pkgs, ...}: {
|
||||||
|
imports = [
|
||||||
|
./python
|
||||||
|
];
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
nixpkgs.overlays = [
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
webtoon-dl =
|
webtoon-dl =
|
||||||
|
@ -6,7 +10,6 @@
|
||||||
./webtoon-dl.nix
|
./webtoon-dl.nix
|
||||||
{};
|
{};
|
||||||
})
|
})
|
||||||
# TODO: this package always needs to be called with the --in-process-gpu flag for some reason, can we automate that?
|
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
prostudiomasters =
|
prostudiomasters =
|
||||||
pkgs.callPackage
|
pkgs.callPackage
|
||||||
|
@ -22,5 +25,21 @@
|
||||||
(final: prev: {
|
(final: prev: {
|
||||||
codium-extensions = pkgs.callPackage ./codium-extensions {};
|
codium-extensions = pkgs.callPackage ./codium-extensions {};
|
||||||
})
|
})
|
||||||
|
(final: prev: {
|
||||||
|
mapillary-uploader = pkgs.callPackage ./mapillary-uploader.nix {};
|
||||||
|
})
|
||||||
|
(final: prev: {
|
||||||
|
panoramax = pkgs.python3.pkgs.callPackage ./panoramax.nix {};
|
||||||
|
})
|
||||||
|
(final: prev: {
|
||||||
|
sgblur = pkgs.python3.pkgs.callPackage ./sgblur.nix {};
|
||||||
|
})
|
||||||
|
(final: prev: {
|
||||||
|
# Override h3 C library to version 4.3.0
|
||||||
|
h3 = pkgs.callPackage ./h3-c-lib.nix {};
|
||||||
|
})
|
||||||
|
(final: prev: {
|
||||||
|
polycule = pkgs.callPackage ./polycule {};
|
||||||
|
})
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
36
modules/common-modules/pkgs/h3-c-lib.nix
Normal file
36
modules/common-modules/pkgs/h3-c-lib.nix
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
fetchFromGitHub,
|
||||||
|
cmake,
|
||||||
|
doxygen,
|
||||||
|
}:
|
||||||
|
stdenv.mkDerivation rec {
|
||||||
|
pname = "h3";
|
||||||
|
version = "4.3.0";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "uber";
|
||||||
|
repo = "h3";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-DUILKZ1QvML6qg+WdOxir6zRsgTvk+En6yjeFf6MQBg=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
cmake
|
||||||
|
doxygen
|
||||||
|
];
|
||||||
|
|
||||||
|
cmakeFlags = [
|
||||||
|
"-DBUILD_SHARED_LIBS=ON"
|
||||||
|
"-DBUILD_TESTING=OFF"
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
homepage = "https://github.com/uber/h3";
|
||||||
|
description = "Hexagonal hierarchical geospatial indexing system";
|
||||||
|
license = licenses.asl20;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
42
modules/common-modules/pkgs/mapillary-uploader.nix
Normal file
42
modules/common-modules/pkgs/mapillary-uploader.nix
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchurl,
|
||||||
|
appimageTools,
|
||||||
|
}: let
|
||||||
|
pname = "mapillary-uploader";
|
||||||
|
version = "4.7.2";
|
||||||
|
|
||||||
|
src = fetchurl {
|
||||||
|
url = "http://tools.mapillary.com/uploader/download/linux/${version}";
|
||||||
|
name = "mapillary-uploader.AppImage";
|
||||||
|
sha256 = "sha256-Oyx7AIdA/2mwBaq7UzXOoyq/z2SU2sViMN40sY2RCQw=";
|
||||||
|
};
|
||||||
|
|
||||||
|
appimageContents = appimageTools.extractType2 {
|
||||||
|
inherit pname version src;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
appimageTools.wrapType2 {
|
||||||
|
inherit pname version src;
|
||||||
|
|
||||||
|
extraInstallCommands = ''
|
||||||
|
# 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}'
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Mapillary Desktop Uploader - Upload street-level imagery to Mapillary";
|
||||||
|
homepage = "https://www.mapillary.com/";
|
||||||
|
license = licenses.unfree; # Mapillary's license terms
|
||||||
|
maintainers = [];
|
||||||
|
platforms = ["x86_64-linux"];
|
||||||
|
sourceProvenance = with sourceTypes; [binaryNativeCode];
|
||||||
|
};
|
||||||
|
}
|
105
modules/common-modules/pkgs/panoramax.nix
Normal file
105
modules/common-modules/pkgs/panoramax.nix
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitLab,
|
||||||
|
buildPythonPackage,
|
||||||
|
flit-core,
|
||||||
|
flask,
|
||||||
|
pillow,
|
||||||
|
requests,
|
||||||
|
python-dotenv,
|
||||||
|
authlib,
|
||||||
|
sentry-sdk,
|
||||||
|
python-dateutil,
|
||||||
|
dateparser,
|
||||||
|
croniter,
|
||||||
|
pydantic,
|
||||||
|
flask-cors,
|
||||||
|
flask-compress,
|
||||||
|
flask-babel,
|
||||||
|
flasgger,
|
||||||
|
yoyo-migrations,
|
||||||
|
psycopg,
|
||||||
|
psycopg-pool,
|
||||||
|
tzdata,
|
||||||
|
email-validator,
|
||||||
|
pydantic-extra-types,
|
||||||
|
python-multipart,
|
||||||
|
fs,
|
||||||
|
fs-s3fs,
|
||||||
|
geopic-tag-reader,
|
||||||
|
pygeofilter,
|
||||||
|
pygeoif,
|
||||||
|
rfeed,
|
||||||
|
geojson-pydantic,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "geovisio";
|
||||||
|
version = "2.10.0";
|
||||||
|
repo = fetchFromGitLab {
|
||||||
|
owner = "panoramax";
|
||||||
|
repo = "server/api";
|
||||||
|
rev = version;
|
||||||
|
hash = "sha256-kCLcrOe7jJdIfmWWOmxQ5dOj8ZG2B7s0qFpHXs02B/E=";
|
||||||
|
};
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = repo;
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
flit-core
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
flask
|
||||||
|
pillow
|
||||||
|
requests
|
||||||
|
python-dotenv
|
||||||
|
authlib
|
||||||
|
sentry-sdk
|
||||||
|
python-dateutil
|
||||||
|
dateparser
|
||||||
|
croniter
|
||||||
|
pydantic
|
||||||
|
flask-cors
|
||||||
|
flask-compress
|
||||||
|
flask-babel
|
||||||
|
flasgger
|
||||||
|
yoyo-migrations
|
||||||
|
psycopg
|
||||||
|
psycopg-pool
|
||||||
|
tzdata
|
||||||
|
email-validator
|
||||||
|
pydantic-extra-types
|
||||||
|
python-multipart
|
||||||
|
fs
|
||||||
|
fs-s3fs
|
||||||
|
geopic-tag-reader
|
||||||
|
pygeofilter
|
||||||
|
pygeoif
|
||||||
|
rfeed
|
||||||
|
geojson-pydantic
|
||||||
|
# Missing from nixpkgs - may need custom packages:
|
||||||
|
# flask-executor
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require network access or specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check as many dependencies are not available in nixpkgs
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
# Disable imports check as many dependencies are not available in nixpkgs
|
||||||
|
pythonImportsCheck = [];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Panoramax API client and tools for street-level imagery platform";
|
||||||
|
homepage = "https://gitlab.com/panoramax/server/api";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
149
modules/common-modules/pkgs/polycule/default.nix
Normal file
149
modules/common-modules/pkgs/polycule/default.nix
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
flutter332,
|
||||||
|
fetchFromGitLab,
|
||||||
|
pkg-config,
|
||||||
|
wrapGAppsHook,
|
||||||
|
gtk3,
|
||||||
|
glib,
|
||||||
|
glib-networking,
|
||||||
|
webkitgtk_4_1,
|
||||||
|
libsecret,
|
||||||
|
libnotify,
|
||||||
|
dbus,
|
||||||
|
sqlcipher,
|
||||||
|
openssl,
|
||||||
|
mpv,
|
||||||
|
alsa-lib,
|
||||||
|
libass,
|
||||||
|
ffmpeg-full,
|
||||||
|
libplacebo,
|
||||||
|
libunwind,
|
||||||
|
shaderc,
|
||||||
|
vulkan-headers,
|
||||||
|
vulkan-loader,
|
||||||
|
lcms2,
|
||||||
|
libdovi,
|
||||||
|
libdvdnav,
|
||||||
|
libdvdread,
|
||||||
|
mujs,
|
||||||
|
libbluray,
|
||||||
|
lua,
|
||||||
|
rubberband,
|
||||||
|
libuchardet,
|
||||||
|
zimg,
|
||||||
|
openal,
|
||||||
|
pipewire,
|
||||||
|
libpulseaudio,
|
||||||
|
libcaca,
|
||||||
|
libdrm,
|
||||||
|
libdisplay-info,
|
||||||
|
libgbm,
|
||||||
|
xorg,
|
||||||
|
nv-codec-headers-11,
|
||||||
|
libva,
|
||||||
|
libvdpau,
|
||||||
|
}:
|
||||||
|
flutter332.buildFlutterApplication rec {
|
||||||
|
pname = "polycule";
|
||||||
|
version = "0.3.4";
|
||||||
|
|
||||||
|
src = fetchFromGitLab {
|
||||||
|
owner = "polycule_client";
|
||||||
|
repo = "polycule";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-RUu8DKuX2NUU5Ce5WLHtDaORkn7CSrgTj3KhM/z+yHc=";
|
||||||
|
};
|
||||||
|
|
||||||
|
pubspecLock = lib.importJSON ./polycule-pubspec.lock.json;
|
||||||
|
|
||||||
|
gitHashes = {
|
||||||
|
matrix = "sha256-w/QB5nYJ9Lh77TcYKEN/DnNQjWfp+9NX0dwQ9GOzWE8=";
|
||||||
|
media_kit = "sha256-1sVX+aHFLFJBtrNZrR6tWkb80vFELW2N9EejyQKlBPg=";
|
||||||
|
media_kit_libs_android_video = "sha256-N6QoktM8u9NYF8MAXLsxM9RlV8nICM4NbnmABHTRkZg=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
wrapGAppsHook
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
gtk3
|
||||||
|
glib
|
||||||
|
glib-networking
|
||||||
|
webkitgtk_4_1
|
||||||
|
libsecret
|
||||||
|
libnotify
|
||||||
|
dbus
|
||||||
|
sqlcipher
|
||||||
|
openssl
|
||||||
|
mpv
|
||||||
|
alsa-lib
|
||||||
|
libass
|
||||||
|
ffmpeg-full
|
||||||
|
libplacebo
|
||||||
|
libunwind
|
||||||
|
shaderc
|
||||||
|
vulkan-headers
|
||||||
|
vulkan-loader
|
||||||
|
lcms2
|
||||||
|
libdovi
|
||||||
|
libdvdnav
|
||||||
|
libdvdread
|
||||||
|
mujs
|
||||||
|
libbluray
|
||||||
|
lua
|
||||||
|
rubberband
|
||||||
|
libuchardet
|
||||||
|
zimg
|
||||||
|
openal
|
||||||
|
pipewire
|
||||||
|
libpulseaudio
|
||||||
|
libcaca
|
||||||
|
libdrm
|
||||||
|
libdisplay-info
|
||||||
|
libgbm
|
||||||
|
xorg.libXScrnSaver
|
||||||
|
xorg.libXpresent
|
||||||
|
nv-codec-headers-11
|
||||||
|
libva
|
||||||
|
libvdpau
|
||||||
|
];
|
||||||
|
|
||||||
|
flutterBuildFlags = [
|
||||||
|
"--release"
|
||||||
|
"--target"
|
||||||
|
"lib/main.dart"
|
||||||
|
"--dart-define=POLYCULE_VERSION=v${version}"
|
||||||
|
"--dart-define=POLYCULE_IS_STABLE=true"
|
||||||
|
"--no-tree-shake-icons"
|
||||||
|
];
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
# Install desktop files and icons from the source
|
||||||
|
install -Dm644 linux/business.braid.polycule.desktop $out/share/applications/polycule.desktop
|
||||||
|
install -Dm644 assets/logo/logo-circle.png $out/share/pixmaps/polycule.png
|
||||||
|
|
||||||
|
# Update desktop file to use correct executable name
|
||||||
|
substituteInPlace $out/share/applications/polycule.desktop \
|
||||||
|
--replace 'Exec=business.braid.polycule' 'Exec=polycule'
|
||||||
|
|
||||||
|
# Create a symlink with the expected name
|
||||||
|
ln -sf $out/bin/polycule $out/bin/business.braid.polycule
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A geeky and efficient [matrix] client for power users";
|
||||||
|
longDescription = ''
|
||||||
|
Polycule is a modern Matrix client built with Flutter, designed for power users
|
||||||
|
who want a fast, efficient, and feature-rich Matrix experience.
|
||||||
|
'';
|
||||||
|
homepage = "https://polycule.im/";
|
||||||
|
license = licenses.eupl12;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = ["x86_64-linux" "aarch64-linux"];
|
||||||
|
sourceProvenance = with sourceTypes; [fromSource];
|
||||||
|
mainProgram = "polycule";
|
||||||
|
};
|
||||||
|
}
|
2459
modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json
Normal file
2459
modules/common-modules/pkgs/polycule/polycule-pubspec.lock.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
fetchurl,
|
fetchurl,
|
||||||
appimageTools,
|
appimageTools,
|
||||||
|
writeShellScript,
|
||||||
}: let
|
}: let
|
||||||
pname = "prostudiomasters";
|
pname = "prostudiomasters";
|
||||||
version = "2.5.6";
|
version = "2.5.6";
|
||||||
|
@ -8,7 +9,25 @@
|
||||||
url = "https://download.prostudiomasters.com/linux/ProStudioMasters-${version}.AppImage";
|
url = "https://download.prostudiomasters.com/linux/ProStudioMasters-${version}.AppImage";
|
||||||
hash = "sha256-7owOwdcucFfl+JsVj+Seau2KOz0J4P/ep7WrBSNSmbs=";
|
hash = "sha256-7owOwdcucFfl+JsVj+Seau2KOz0J4P/ep7WrBSNSmbs=";
|
||||||
};
|
};
|
||||||
in
|
|
||||||
appimageTools.wrapType2 {
|
# Create the base AppImage wrapper
|
||||||
|
baseApp = appimageTools.wrapType2 {
|
||||||
inherit pname version src;
|
inherit pname version src;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
# Create a wrapper script that automatically adds the --in-process-gpu flag
|
||||||
|
wrapper = writeShellScript "prostudiomasters-wrapper" ''
|
||||||
|
exec ${baseApp}/bin/prostudiomasters --in-process-gpu "$@"
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
# Override the base app to use our wrapper script
|
||||||
|
baseApp.overrideAttrs (oldAttrs: {
|
||||||
|
buildCommand =
|
||||||
|
oldAttrs.buildCommand
|
||||||
|
+ ''
|
||||||
|
# Replace the original binary with our wrapper
|
||||||
|
rm $out/bin/prostudiomasters
|
||||||
|
cp ${wrapper} $out/bin/prostudiomasters
|
||||||
|
chmod +x $out/bin/prostudiomasters
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
|
18
modules/common-modules/pkgs/python/default.nix
Normal file
18
modules/common-modules/pkgs/python/default.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{...}: {
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: {
|
||||||
|
python3 = prev.python3.override {
|
||||||
|
packageOverrides = pythonPrev: pythonFinal: {
|
||||||
|
h3 = pythonPrev.callPackage ./h3.nix {h3 = final.h3;};
|
||||||
|
pygeofilter = pythonPrev.callPackage ./pygeofilter.nix {};
|
||||||
|
pygeoif = pythonPrev.callPackage ./pygeoif.nix {};
|
||||||
|
rfeed = pythonPrev.callPackage ./rfeed.nix {};
|
||||||
|
pyexiv2 = pythonPrev.callPackage ./pyexiv2.nix {};
|
||||||
|
geojson-pydantic = pythonPrev.callPackage ./geojson-pydantic.nix {};
|
||||||
|
geopic-tag-reader = pythonPrev.callPackage ./geopic-tag-reader.nix {};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
python3Packages = final.python3.pkgs;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
48
modules/common-modules/pkgs/python/geojson-pydantic.nix
Normal file
48
modules/common-modules/pkgs/python/geojson-pydantic.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchPypi,
|
||||||
|
buildPythonPackage,
|
||||||
|
flit-core,
|
||||||
|
pydantic,
|
||||||
|
geojson,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "geojson_pydantic";
|
||||||
|
version = "2.0.0";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-ti6LRFAt0a1Ri19zkDWoGSSnb5gMvbOk6JFu+RO+JC4=";
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
flit-core
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
pydantic
|
||||||
|
geojson
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
# Basic imports check
|
||||||
|
pythonImportsCheck = ["geojson_pydantic"];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Pydantic models for GeoJSON objects";
|
||||||
|
homepage = "https://github.com/developmentseed/geojson-pydantic";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
70
modules/common-modules/pkgs/python/geopic-tag-reader.nix
Normal file
70
modules/common-modules/pkgs/python/geopic-tag-reader.nix
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitLab,
|
||||||
|
buildPythonPackage,
|
||||||
|
flit-core,
|
||||||
|
typer,
|
||||||
|
xmltodict,
|
||||||
|
timezonefinder,
|
||||||
|
pytz,
|
||||||
|
types-pytz,
|
||||||
|
types-python-dateutil,
|
||||||
|
rtree,
|
||||||
|
python-dateutil,
|
||||||
|
pyexiv2,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "geopic-tag-reader";
|
||||||
|
version = "1.8.0";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchFromGitLab {
|
||||||
|
owner = "panoramax";
|
||||||
|
repo = "server/geo-picture-tag-reader";
|
||||||
|
rev = version;
|
||||||
|
sha256 = "0lzf5xxxcdqmq28bpvgpkxf5jxmh2nawwa4rl4yg04bdsi16rf1j";
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
flit-core
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
typer
|
||||||
|
xmltodict
|
||||||
|
pyexiv2
|
||||||
|
timezonefinder
|
||||||
|
pytz
|
||||||
|
types-pytz
|
||||||
|
types-python-dateutil
|
||||||
|
rtree
|
||||||
|
];
|
||||||
|
|
||||||
|
optional-dependencies = {
|
||||||
|
write-exif = [
|
||||||
|
python-dateutil
|
||||||
|
types-python-dateutil
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Skip tests as they may require network access or specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check as some dependencies might have issues
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
# Disable imports check initially to avoid dependency issues
|
||||||
|
pythonImportsCheck = [];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "GeoPic Tag Reader - Python library to read and write standardized metadata from geolocated pictures EXIF metadata";
|
||||||
|
homepage = "https://gitlab.com/panoramax/server/geo-picture-tag-reader";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
81
modules/common-modules/pkgs/python/h3.nix
Normal file
81
modules/common-modules/pkgs/python/h3.nix
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
{
|
||||||
|
autoPatchelfHook,
|
||||||
|
buildPythonPackage,
|
||||||
|
cmake,
|
||||||
|
cython,
|
||||||
|
fetchFromGitHub,
|
||||||
|
h3,
|
||||||
|
lib,
|
||||||
|
ninja,
|
||||||
|
numpy,
|
||||||
|
pytestCheckHook,
|
||||||
|
pytest-cov-stub,
|
||||||
|
scikit-build-core,
|
||||||
|
stdenv,
|
||||||
|
}:
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "h3";
|
||||||
|
version = "4.3.1";
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
# pypi version does not include tests
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "uber";
|
||||||
|
repo = "h3-py";
|
||||||
|
tag = "v${version}";
|
||||||
|
hash = "sha256-zt7zbBgSp2P9q7mObZeQZpW9Szip62dAYdPZ2cGTmi4=";
|
||||||
|
};
|
||||||
|
|
||||||
|
dontConfigure = true;
|
||||||
|
|
||||||
|
nativeCheckInputs = [
|
||||||
|
pytestCheckHook
|
||||||
|
pytest-cov-stub
|
||||||
|
];
|
||||||
|
|
||||||
|
build-system =
|
||||||
|
[
|
||||||
|
scikit-build-core
|
||||||
|
cmake
|
||||||
|
cython
|
||||||
|
ninja
|
||||||
|
]
|
||||||
|
++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||||
|
# On Linux the .so files ends up referring to libh3.so instead of the full
|
||||||
|
# Nix store path. I'm not sure why this is happening! On Darwin it works
|
||||||
|
# fine.
|
||||||
|
autoPatchelfHook
|
||||||
|
];
|
||||||
|
|
||||||
|
# This is not needed per-se, it's only added for autoPatchelfHook to work
|
||||||
|
# correctly. See the note above ^^
|
||||||
|
buildInputs = lib.optionals stdenv.hostPlatform.isLinux [h3];
|
||||||
|
|
||||||
|
dependencies = [numpy];
|
||||||
|
|
||||||
|
# The following prePatch replaces the h3lib compilation with using the h3 packaged in nixpkgs.
|
||||||
|
#
|
||||||
|
# - Remove the h3lib submodule.
|
||||||
|
# - Patch CMakeLists to avoid building h3lib, and use h3 instead.
|
||||||
|
prePatch = let
|
||||||
|
cmakeCommands = ''
|
||||||
|
include_directories(${lib.getDev h3}/include/h3)
|
||||||
|
link_directories(${h3}/lib)
|
||||||
|
'';
|
||||||
|
in ''
|
||||||
|
rm -r src/h3lib
|
||||||
|
substituteInPlace CMakeLists.txt \
|
||||||
|
--replace-fail "add_subdirectory(src/h3lib)" "${cmakeCommands}" \
|
||||||
|
--replace-fail "\''${CMAKE_CURRENT_BINARY_DIR}/src/h3lib/src/h3lib/include/h3api.h" "${lib.getDev h3}/include/h3/h3api.h"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Extra check to make sure we can import it from Python
|
||||||
|
pythonImportsCheck = ["h3"];
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
homepage = "https://github.com/uber/h3-py";
|
||||||
|
description = "Hierarchical hexagonal geospatial indexing system";
|
||||||
|
license = lib.licenses.asl20;
|
||||||
|
maintainers = [lib.maintainers.kalbasit];
|
||||||
|
};
|
||||||
|
}
|
49
modules/common-modules/pkgs/python/pyexiv2.nix
Normal file
49
modules/common-modules/pkgs/python/pyexiv2.nix
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitHub,
|
||||||
|
buildPythonPackage,
|
||||||
|
exiv2,
|
||||||
|
boost,
|
||||||
|
pybind11,
|
||||||
|
setuptools,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "pyexiv2";
|
||||||
|
version = "2.15.3";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
build-system = [setuptools];
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "LeoHsiao1";
|
||||||
|
repo = "pyexiv2";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-83bFMaoXncvhRJNcCgkkC7B29wR5pjuLO/EdkQdqxxo=";
|
||||||
|
};
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
exiv2
|
||||||
|
boost
|
||||||
|
];
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pybind11
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require specific test images
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check initially
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Python binding to the library exiv2";
|
||||||
|
homepage = "https://github.com/LeoHsiao1/pyexiv2";
|
||||||
|
license = licenses.gpl3Plus;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.linux;
|
||||||
|
};
|
||||||
|
}
|
52
modules/common-modules/pkgs/python/pygeofilter.nix
Normal file
52
modules/common-modules/pkgs/python/pygeofilter.nix
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchPypi,
|
||||||
|
buildPythonPackage,
|
||||||
|
setuptools,
|
||||||
|
wheel,
|
||||||
|
lark,
|
||||||
|
python-dateutil,
|
||||||
|
shapely,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "pygeofilter";
|
||||||
|
version = "0.3.1";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-+SvAYiCZ+H/os23nq92GBZ1hWontYIInNwgiI6V44VA=";
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
setuptools
|
||||||
|
wheel
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
lark
|
||||||
|
python-dateutil
|
||||||
|
shapely
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
# Basic imports check
|
||||||
|
pythonImportsCheck = ["pygeofilter"];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A pure Python parser implementation of OGC filtering standards";
|
||||||
|
homepage = "https://github.com/geopython/pygeofilter";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
48
modules/common-modules/pkgs/python/pygeoif.nix
Normal file
48
modules/common-modules/pkgs/python/pygeoif.nix
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchPypi,
|
||||||
|
buildPythonPackage,
|
||||||
|
setuptools,
|
||||||
|
wheel,
|
||||||
|
typing-extensions,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pname = "pygeoif";
|
||||||
|
version = "1.5.1";
|
||||||
|
in
|
||||||
|
buildPythonPackage {
|
||||||
|
inherit pname version;
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-8nprah7Lh66swrUbzFnKeb5w7RKgEE3oYBR4shPdXYE=";
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
setuptools
|
||||||
|
wheel
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
typing-extensions
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# Disable runtime dependencies check
|
||||||
|
dontCheckRuntimeDeps = true;
|
||||||
|
|
||||||
|
# Basic imports check
|
||||||
|
pythonImportsCheck = ["pygeoif"];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A basic implementation of the __geo_interface__";
|
||||||
|
homepage = "https://github.com/cleder/pygeoif";
|
||||||
|
license = licenses.lgpl21Plus;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
40
modules/common-modules/pkgs/python/rfeed.nix
Normal file
40
modules/common-modules/pkgs/python/rfeed.nix
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchPypi,
|
||||||
|
buildPythonPackage,
|
||||||
|
setuptools,
|
||||||
|
python-dateutil,
|
||||||
|
}:
|
||||||
|
buildPythonPackage rec {
|
||||||
|
pname = "rfeed";
|
||||||
|
version = "1.1.1";
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-qpUG8oZrdPWjItOUoUpjwZpoJcLZR1X/GdRt0eJDSBk=";
|
||||||
|
};
|
||||||
|
|
||||||
|
build-system = [
|
||||||
|
setuptools
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
python-dateutil
|
||||||
|
];
|
||||||
|
|
||||||
|
# No tests available in the package
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
pythonImportsCheck = [
|
||||||
|
"rfeed"
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "RSS feed generation library for Python";
|
||||||
|
homepage = "https://pypi.org/project/rfeed/";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.all;
|
||||||
|
};
|
||||||
|
}
|
65
modules/common-modules/pkgs/sgblur.nix
Normal file
65
modules/common-modules/pkgs/sgblur.nix
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
python3Packages,
|
||||||
|
fetchFromGitHub,
|
||||||
|
pkg-config,
|
||||||
|
libjpeg_turbo,
|
||||||
|
exiftran ? libjpeg_turbo,
|
||||||
|
}:
|
||||||
|
python3Packages.buildPythonPackage {
|
||||||
|
pname = "sgblur";
|
||||||
|
version = "1.0.0";
|
||||||
|
|
||||||
|
pyproject = true;
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "cquest";
|
||||||
|
repo = "sgblur";
|
||||||
|
rev = "master";
|
||||||
|
hash = "sha256-17wpif2sa021kaa1pbkry4l1967la1qd7knhngvxblrvd7jqqz4y=";
|
||||||
|
};
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
buildInputs = [
|
||||||
|
libjpeg_turbo
|
||||||
|
exiftran
|
||||||
|
];
|
||||||
|
|
||||||
|
build-system = with python3Packages; [
|
||||||
|
setuptools
|
||||||
|
wheel
|
||||||
|
];
|
||||||
|
|
||||||
|
dependencies = with python3Packages; [
|
||||||
|
# Core dependencies from pyproject.toml
|
||||||
|
ultralytics
|
||||||
|
# pyturbojpeg # May need special handling
|
||||||
|
pillow
|
||||||
|
# uuid # Built into Python
|
||||||
|
# exifread
|
||||||
|
python-multipart
|
||||||
|
fastapi
|
||||||
|
uvicorn
|
||||||
|
requests
|
||||||
|
# piexif
|
||||||
|
pydantic-settings
|
||||||
|
pydantic
|
||||||
|
];
|
||||||
|
|
||||||
|
# Skip tests as they may require GPU or specific setup
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
# The package may have import issues due to system dependencies
|
||||||
|
pythonImportsCheck = [];
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Panoramax Speedy Gonzales Blurring Algorithm - AI-powered face and license plate blurring API";
|
||||||
|
homepage = "https://github.com/cquest/sgblur";
|
||||||
|
license = licenses.mit;
|
||||||
|
maintainers = [];
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
|
}
|
30
modules/home-manager-modules/programs/davinci-resolve.nix
Normal file
30
modules/home-manager-modules/programs/davinci-resolve.nix
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.davinci-resolve = {
|
||||||
|
enable = lib.mkEnableOption "enable davinci-resolve";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.davinci-resolve.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
davinci-resolve
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.dataHome}/DaVinciResolve"
|
||||||
|
"${config.xdg.configHome}/blackmagic"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
|
@ -19,5 +19,25 @@
|
||||||
./dbeaver.nix
|
./dbeaver.nix
|
||||||
./steam.nix
|
./steam.nix
|
||||||
./vscode
|
./vscode
|
||||||
|
./ungoogled-chromium.nix
|
||||||
|
./libreoffice.nix
|
||||||
|
./mapillary-uploader.nix
|
||||||
|
./inkscape.nix
|
||||||
|
./gimp.nix
|
||||||
|
./proxmark3.nix
|
||||||
|
./freecad.nix
|
||||||
|
./onionshare.nix
|
||||||
|
./mfoc.nix
|
||||||
|
./pdfarranger.nix
|
||||||
|
./picard.nix
|
||||||
|
./qflipper.nix
|
||||||
|
./openvpn.nix
|
||||||
|
./noisetorch.nix
|
||||||
|
./openrgb.nix
|
||||||
|
./via.nix
|
||||||
|
./davinci-resolve.nix
|
||||||
|
./gdx-liftoff.nix
|
||||||
|
./tor-browser.nix
|
||||||
|
./polycule.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
29
modules/home-manager-modules/programs/freecad.nix
Normal file
29
modules/home-manager-modules/programs/freecad.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.freecad = {
|
||||||
|
enable = lib.mkEnableOption "enable freecad";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.freecad.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
freecad
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/FreeCAD"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
17
modules/home-manager-modules/programs/gdx-liftoff.nix
Normal file
17
modules/home-manager-modules/programs/gdx-liftoff.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.gdx-liftoff = {
|
||||||
|
enable = lib.mkEnableOption "enable gdx-liftoff";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.gdx-liftoff.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
gdx-liftoff
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
29
modules/home-manager-modules/programs/gimp.nix
Normal file
29
modules/home-manager-modules/programs/gimp.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.gimp = {
|
||||||
|
enable = lib.mkEnableOption "enable gimp";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.gimp.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
gimp
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/GIMP"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
29
modules/home-manager-modules/programs/inkscape.nix
Normal file
29
modules/home-manager-modules/programs/inkscape.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.inkscape = {
|
||||||
|
enable = lib.mkEnableOption "enable inkscape";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.inkscape.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
inkscape
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/inkscape"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
29
modules/home-manager-modules/programs/libreoffice.nix
Normal file
29
modules/home-manager-modules/programs/libreoffice.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.libreoffice = {
|
||||||
|
enable = lib.mkEnableOption "enable libreoffice";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.libreoffice.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
libreoffice
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/libreoffice"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
17
modules/home-manager-modules/programs/mapillary-uploader.nix
Normal file
17
modules/home-manager-modules/programs/mapillary-uploader.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
with lib; let
|
||||||
|
cfg = config.programs.mapillary-uploader;
|
||||||
|
in {
|
||||||
|
options.programs.mapillary-uploader = {
|
||||||
|
enable = mkEnableOption "Mapillary Desktop Uploader";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
home.packages = [pkgs.mapillary-uploader];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/mfoc.nix
Normal file
17
modules/home-manager-modules/programs/mfoc.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.mfoc = {
|
||||||
|
enable = lib.mkEnableOption "enable mfoc";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.mfoc.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
mfoc
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/noisetorch.nix
Normal file
17
modules/home-manager-modules/programs/noisetorch.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.noisetorch = {
|
||||||
|
enable = lib.mkEnableOption "enable noisetorch";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.noisetorch.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
noisetorch
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/onionshare.nix
Normal file
17
modules/home-manager-modules/programs/onionshare.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.onionshare = {
|
||||||
|
enable = lib.mkEnableOption "enable onionshare";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.onionshare.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
onionshare
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/openrgb.nix
Normal file
17
modules/home-manager-modules/programs/openrgb.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.openrgb = {
|
||||||
|
enable = lib.mkEnableOption "enable openrgb";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.openrgb.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
openrgb
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/openvpn.nix
Normal file
17
modules/home-manager-modules/programs/openvpn.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.openvpn = {
|
||||||
|
enable = lib.mkEnableOption "enable openvpn";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.openvpn.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
openvpn
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
17
modules/home-manager-modules/programs/pdfarranger.nix
Normal file
17
modules/home-manager-modules/programs/pdfarranger.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.pdfarranger = {
|
||||||
|
enable = lib.mkEnableOption "enable pdfarranger";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.pdfarranger.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
pdfarranger
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
29
modules/home-manager-modules/programs/picard.nix
Normal file
29
modules/home-manager-modules/programs/picard.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.picard = {
|
||||||
|
enable = lib.mkEnableOption "enable picard";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.picard.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
picard
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/MusicBrainz"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
32
modules/home-manager-modules/programs/polycule.nix
Normal file
32
modules/home-manager-modules/programs/polycule.nix
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.polycule = {
|
||||||
|
enable = lib.mkEnableOption "enable polycule matrix client";
|
||||||
|
package = lib.mkPackageOption pkgs "polycule" {};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.polycule.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = [
|
||||||
|
config.programs.polycule.package
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
# TODO: check that these are actually the correct folders
|
||||||
|
# directories = [
|
||||||
|
# "${config.xdg.configHome}/polycule"
|
||||||
|
# "${config.xdg.dataHome}/polycule"
|
||||||
|
# "${config.xdg.cacheHome}/polycule"
|
||||||
|
# ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
17
modules/home-manager-modules/programs/proxmark3.nix
Normal file
17
modules/home-manager-modules/programs/proxmark3.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.proxmark3 = {
|
||||||
|
enable = lib.mkEnableOption "enable proxmark3";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.proxmark3.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
proxmark3
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
29
modules/home-manager-modules/programs/qflipper.nix
Normal file
29
modules/home-manager-modules/programs/qflipper.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.qflipper = {
|
||||||
|
enable = lib.mkEnableOption "enable qflipper";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.qflipper.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
qFlipper
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/qFlipper"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
29
modules/home-manager-modules/programs/tor-browser.nix
Normal file
29
modules/home-manager-modules/programs/tor-browser.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.tor-browser = {
|
||||||
|
enable = lib.mkEnableOption "enable tor-browser";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.tor-browser.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
tor-browser
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.dataHome}/torbrowser"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
29
modules/home-manager-modules/programs/ungoogled-chromium.nix
Normal file
29
modules/home-manager-modules/programs/ungoogled-chromium.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.ungoogled-chromium = {
|
||||||
|
enable = lib.mkEnableOption "enable ungoogled-chromium";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.ungoogled-chromium.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
ungoogled-chromium
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf osConfig.host.impermanence.enable {
|
||||||
|
home.persistence."/persist${config.home.homeDirectory}" = {
|
||||||
|
directories = [
|
||||||
|
"${config.xdg.configHome}/chromium"
|
||||||
|
];
|
||||||
|
allowOther = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
17
modules/home-manager-modules/programs/via.nix
Normal file
17
modules/home-manager-modules/programs/via.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.programs.via = {
|
||||||
|
enable = lib.mkEnableOption "enable via";
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.programs.via.enable {
|
||||||
|
home.packages = with pkgs; [
|
||||||
|
via
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -10,10 +10,6 @@
|
||||||
|
|
||||||
mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
mcp-nixos = inputs.mcp-nixos.packages.${pkgs.stdenv.hostPlatform.system}.default;
|
||||||
|
|
||||||
mcp-eslint = pkgs.writeShellScriptBin "mcp-eslint" ''
|
|
||||||
${pkgs.nodejs}/bin/npx --yes @modelcontextprotocol/server-eslint "$@"
|
|
||||||
'';
|
|
||||||
|
|
||||||
anyProfileHasMcpNixos = lib.any (
|
anyProfileHasMcpNixos = lib.any (
|
||||||
profile:
|
profile:
|
||||||
profile.extraExtensions.claudeDev.enable
|
profile.extraExtensions.claudeDev.enable
|
||||||
|
@ -25,6 +21,44 @@
|
||||||
profile.extraExtensions.claudeDev.enable
|
profile.extraExtensions.claudeDev.enable
|
||||||
&& profile.extraExtensions.claudeDev.mcp.eslint.enable
|
&& profile.extraExtensions.claudeDev.mcp.eslint.enable
|
||||||
) (lib.attrValues config.programs.vscode.profiles);
|
) (lib.attrValues config.programs.vscode.profiles);
|
||||||
|
|
||||||
|
anyProfileHasMcpVitest = lib.any (
|
||||||
|
profile:
|
||||||
|
profile.extraExtensions.claudeDev.enable
|
||||||
|
&& profile.extraExtensions.claudeDev.mcp.vitest.enable
|
||||||
|
) (lib.attrValues config.programs.vscode.profiles);
|
||||||
|
|
||||||
|
anyProfileHasMcpSleep = lib.any (
|
||||||
|
profile:
|
||||||
|
profile.extraExtensions.claudeDev.enable
|
||||||
|
&& profile.extraExtensions.claudeDev.mcp.sleep.enable
|
||||||
|
) (lib.attrValues config.programs.vscode.profiles);
|
||||||
|
|
||||||
|
anyProfileHasMcp = anyProfileHasMcpNixos || anyProfileHasMcpEslint || anyProfileHasMcpVitest || anyProfileHasMcpSleep;
|
||||||
|
|
||||||
|
getMcpTimeout = serverName:
|
||||||
|
lib.findFirst (timeout: timeout != null) null (map (
|
||||||
|
profile:
|
||||||
|
if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable
|
||||||
|
then profile.extraExtensions.claudeDev.mcp.${serverName}.timeout
|
||||||
|
else null
|
||||||
|
) (lib.attrValues config.programs.vscode.profiles));
|
||||||
|
|
||||||
|
getMcpAutoApprove = serverName:
|
||||||
|
lib.foldl' (
|
||||||
|
acc: profile:
|
||||||
|
if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable
|
||||||
|
then acc // profile.extraExtensions.claudeDev.mcp.${serverName}.autoApprove
|
||||||
|
else acc
|
||||||
|
) {} (lib.attrValues config.programs.vscode.profiles);
|
||||||
|
|
||||||
|
getMcpPackage = serverName:
|
||||||
|
lib.findFirst (package: package != null) null (map (
|
||||||
|
profile:
|
||||||
|
if profile.extraExtensions.claudeDev.enable && profile.extraExtensions.claudeDev.mcp.${serverName}.enable
|
||||||
|
then profile.extraExtensions.claudeDev.mcp.${serverName}.package
|
||||||
|
else null
|
||||||
|
) (lib.attrValues config.programs.vscode.profiles));
|
||||||
in {
|
in {
|
||||||
options.programs.vscode.profiles = lib.mkOption {
|
options.programs.vscode.profiles = lib.mkOption {
|
||||||
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
|
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
|
||||||
|
@ -38,9 +72,66 @@ in {
|
||||||
mcp = {
|
mcp = {
|
||||||
nixos = {
|
nixos = {
|
||||||
enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev";
|
enable = lib.mkEnableOption "enable NixOS MCP server for Claude Dev";
|
||||||
|
autoApprove = {
|
||||||
|
nixos_search = lib.mkEnableOption "should the nixos_search tool be auto approved for the nixos MCP server";
|
||||||
|
nixos_info = lib.mkEnableOption "should the nixos_info tool be auto approved for the nixos MCP server";
|
||||||
|
home_manager_search = lib.mkEnableOption "should the home_manager_search tool be auto approved for the nixos MCP server";
|
||||||
|
home_manager_info = lib.mkEnableOption "should the home_manager_info tool be auto approved for the nixos MCP server";
|
||||||
|
darwin_search = lib.mkEnableOption "should the darwin_search tool be auto approved for the nixos MCP server";
|
||||||
|
darwin_info = lib.mkEnableOption "should the darwin_info tool be auto approved for the nixos MCP server";
|
||||||
|
nixos_flakes_search = lib.mkEnableOption "should the nixos_flakes_search tool be auto approved for the nixos MCP server";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
eslint = {
|
eslint = {
|
||||||
enable = lib.mkEnableOption "enable ESLint MCP server for Claude Dev";
|
enable = lib.mkEnableOption "enable ESLint MCP server for Claude Dev";
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "@eslint/mcp@latest";
|
||||||
|
description = "NPM package to use for ESLint MCP server";
|
||||||
|
};
|
||||||
|
timeout = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.int;
|
||||||
|
default = null;
|
||||||
|
description = "Timeout in seconds for ESLint MCP server operations";
|
||||||
|
};
|
||||||
|
autoApprove = {
|
||||||
|
lint-files = lib.mkEnableOption "Should the lint-files tool be auto approved for ESLint MCP server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
vitest = {
|
||||||
|
enable = lib.mkEnableOption "enable Vitest MCP server for Claude Dev";
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "@djankies/vitest-mcp";
|
||||||
|
description = "NPM package to use for Vitest MCP server";
|
||||||
|
};
|
||||||
|
timeout = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.int;
|
||||||
|
default = null;
|
||||||
|
description = "Timeout in seconds for Vitest MCP server operations";
|
||||||
|
};
|
||||||
|
autoApprove = {
|
||||||
|
list_tests = lib.mkEnableOption "Should the list_tests tool be auto approved for Vitest MCP server";
|
||||||
|
run_tests = lib.mkEnableOption "Should the run_tests tool be auto approved for Vitest MCP server";
|
||||||
|
analyze_coverage = lib.mkEnableOption "Should the analyze_coverage tool be auto approved for Vitest MCP server";
|
||||||
|
set_project_root = lib.mkEnableOption "Should the set_project_root tool be auto approved for Vitest MCP server";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
sleep = {
|
||||||
|
enable = lib.mkEnableOption "enable Sleep MCP server for Claude Dev";
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "sleep-mcp";
|
||||||
|
description = "NPM package to use for Sleep MCP server";
|
||||||
|
};
|
||||||
|
timeout = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.int;
|
||||||
|
default = null;
|
||||||
|
description = "Timeout in seconds for Sleep MCP server operations";
|
||||||
|
};
|
||||||
|
autoApprove = {
|
||||||
|
sleep = lib.mkEnableOption "Should the sleep tool be auto approved for Sleep MCP server";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -60,14 +151,7 @@ in {
|
||||||
];
|
];
|
||||||
})
|
})
|
||||||
|
|
||||||
(lib.mkIf anyProfileHasMcpEslint {
|
(lib.mkIf anyProfileHasMcp {
|
||||||
home.packages = [
|
|
||||||
mcp-eslint
|
|
||||||
pkgs.eslint
|
|
||||||
];
|
|
||||||
})
|
|
||||||
|
|
||||||
(lib.mkIf (anyProfileHasMcpNixos || anyProfileHasMcpEslint) {
|
|
||||||
home.file."${config.xdg.configHome}/VSCodium/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" = {
|
home.file."${config.xdg.configHome}/VSCodium/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" = {
|
||||||
text = builtins.toJSON {
|
text = builtins.toJSON {
|
||||||
mcpServers =
|
mcpServers =
|
||||||
|
@ -77,9 +161,43 @@ in {
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
// (lib.optionalAttrs anyProfileHasMcpEslint {
|
// (lib.optionalAttrs anyProfileHasMcpEslint {
|
||||||
eslint = {
|
eslint =
|
||||||
command = "${mcp-eslint}/bin/mcp-eslint";
|
{
|
||||||
};
|
command = "${pkgs.nodejs}/bin/npx";
|
||||||
|
args = ["-y" (getMcpPackage "eslint")];
|
||||||
|
}
|
||||||
|
// (lib.optionalAttrs ((getMcpTimeout "eslint") != null) {
|
||||||
|
timeout = getMcpTimeout "eslint";
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs ((getMcpAutoApprove "eslint") != {}) {
|
||||||
|
autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "eslint"));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs anyProfileHasMcpVitest {
|
||||||
|
vitest =
|
||||||
|
{
|
||||||
|
command = "${pkgs.nodejs}/bin/npx";
|
||||||
|
args = ["-y" (getMcpPackage "vitest")];
|
||||||
|
}
|
||||||
|
// (lib.optionalAttrs ((getMcpTimeout "vitest") != null) {
|
||||||
|
timeout = getMcpTimeout "vitest";
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs ((getMcpAutoApprove "vitest") != {}) {
|
||||||
|
autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "vitest"));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs anyProfileHasMcpSleep {
|
||||||
|
sleep-mcp =
|
||||||
|
{
|
||||||
|
command = "${pkgs.nodejs}/bin/npx";
|
||||||
|
args = ["-y" (getMcpPackage "sleep")];
|
||||||
|
}
|
||||||
|
// (lib.optionalAttrs ((getMcpTimeout "sleep") != null) {
|
||||||
|
timeout = getMcpTimeout "sleep";
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs ((getMcpAutoApprove "sleep") != {}) {
|
||||||
|
autoApprove = builtins.attrNames (lib.filterAttrs (_: v: v) (getMcpAutoApprove "sleep"));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
force = true;
|
force = true;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
|
||||||
|
pkgsRepository = pkgsRepositories.vscode-marketplace;
|
||||||
|
in {
|
||||||
|
options.programs.vscode.profiles = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
|
||||||
|
options = {
|
||||||
|
extraExtensions.conventionalCommits = {
|
||||||
|
enable = lib.mkEnableOption "Enable VSCode Conventional Commits extension";
|
||||||
|
extension = lib.mkPackageOption pkgsRepository "conventional-commits" {
|
||||||
|
default = ["vivaxy" "vscode-conventional-commits"];
|
||||||
|
};
|
||||||
|
|
||||||
|
gitmoji = lib.mkEnableOption "should emoji be prompted for as a part of the commit message./";
|
||||||
|
|
||||||
|
promptScopes = lib.mkEnableOption "prompting for scopes in conventional commits";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf config.extraExtensions.conventionalCommits.enable {
|
||||||
|
extensions = [config.extraExtensions.conventionalCommits.extension];
|
||||||
|
|
||||||
|
userSettings = {
|
||||||
|
"conventionalCommits.gitmoji" = config.extraExtensions.conventionalCommits.gitmoji;
|
||||||
|
"conventionalCommits.promptScopes" = config.extraExtensions.conventionalCommits.promptScopes;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
|
@ -21,5 +21,7 @@
|
||||||
./claudeDev.nix
|
./claudeDev.nix
|
||||||
./nearley.nix
|
./nearley.nix
|
||||||
./vitest.nix
|
./vitest.nix
|
||||||
|
./direnv.nix
|
||||||
|
./conventionalCommits.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
25
modules/home-manager-modules/programs/vscode/direnv.nix
Normal file
25
modules/home-manager-modules/programs/vscode/direnv.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
pkgsRepositories = pkgs.nix-vscode-extensions.forVSCodeVersion config.programs.vscode.package.version;
|
||||||
|
pkgsRepository = pkgsRepositories.vscode-marketplace;
|
||||||
|
in {
|
||||||
|
options.programs.vscode.profiles = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
|
||||||
|
options = {
|
||||||
|
extraExtensions.direnv = {
|
||||||
|
enable = lib.mkEnableOption "Enable direnv extension";
|
||||||
|
extension = lib.mkPackageOption pkgsRepository "direnv" {
|
||||||
|
default = ["mkhl" "direnv"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
config = lib.mkIf config.extraExtensions.direnv.enable {
|
||||||
|
extensions = [config.extraExtensions.direnv.extension];
|
||||||
|
};
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
dataDirectory = "/var/lib/actual/";
|
|
||||||
in {
|
|
||||||
options.services.actual = {
|
|
||||||
subdomain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "actual";
|
|
||||||
description = "subdomain of base domain that actual will be hosted at";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.services.actual.enable (lib.mkMerge [
|
|
||||||
{
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${dataDirectory} 2770 actual actual"
|
|
||||||
];
|
|
||||||
host = {
|
|
||||||
reverse_proxy.subdomains.${config.services.actual.subdomain} = {
|
|
||||||
target = "http://localhost:${toString config.services.actual.settings.port}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.actual = {
|
|
||||||
settings = {
|
|
||||||
ACTUAL_DATA_DIR = dataDirectory;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(lib.mkIf config.services.fail2ban.enable {
|
|
||||||
# TODO: configuration for fail2ban for actual
|
|
||||||
})
|
|
||||||
(lib.mkIf config.host.impermanence.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory;
|
|
||||||
message = "actual data location does not match persistence";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
environment.persistence."/persist/system/root" = {
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = dataDirectory;
|
|
||||||
user = "actual";
|
|
||||||
group = "actual";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
3
modules/nixos-modules/server/actual/const.nix
Normal file
3
modules/nixos-modules/server/actual/const.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
dataDirectory = "/var/lib/actual/";
|
||||||
|
}
|
26
modules/nixos-modules/server/actual/default.nix
Normal file
26
modules/nixos-modules/server/actual/default.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
const = import ./const.nix;
|
||||||
|
dataDirectory = const.dataDirectory;
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
./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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
9
modules/nixos-modules/server/actual/fail2ban.nix
Normal file
9
modules/nixos-modules/server/actual/fail2ban.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf (config.services.actual.enable && config.services.fail2ban.enable) {
|
||||||
|
# TODO: configuration for fail2ban for actual
|
||||||
|
};
|
||||||
|
}
|
26
modules/nixos-modules/server/actual/impermanence.nix
Normal file
26
modules/nixos-modules/server/actual/impermanence.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
const = import ./const.nix;
|
||||||
|
dataDirectory = const.dataDirectory;
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (config.services.actual.enable && config.host.impermanence.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.actual.settings.ACTUAL_DATA_DIR == dataDirectory;
|
||||||
|
message = "actual data location does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
environment.persistence."/persist/system/root" = {
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = dataDirectory;
|
||||||
|
user = "actual";
|
||||||
|
group = "actual";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
21
modules/nixos-modules/server/actual/proxy.nix
Normal file
21
modules/nixos-modules/server/actual/proxy.nix
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.services.actual = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "actual";
|
||||||
|
description = "subdomain of base domain that actual will be hosted at";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
6
modules/nixos-modules/server/bazarr/default.nix
Normal file
6
modules/nixos-modules/server/bazarr/default.nix
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{...}: {
|
||||||
|
imports = [
|
||||||
|
./proxy.nix
|
||||||
|
./impermanence.nix
|
||||||
|
];
|
||||||
|
}
|
26
modules/nixos-modules/server/bazarr/impermanence.nix
Normal file
26
modules/nixos-modules/server/bazarr/impermanence.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
bazarr_data_directory = "/var/lib/bazarr";
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (config.services.bazarr.enable && config.host.impermanence.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.bazarr.dataDir == bazarr_data_directory;
|
||||||
|
message = "bazarr data directory does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.persistence."/persist/system/root" = {
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = bazarr_data_directory;
|
||||||
|
user = "bazarr";
|
||||||
|
group = "bazarr";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
28
modules/nixos-modules/server/bazarr/proxy.nix
Normal file
28
modules/nixos-modules/server/bazarr/proxy.nix
Normal 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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,18 +1,23 @@
|
||||||
{...}: {
|
{...}: {
|
||||||
imports = [
|
imports = [
|
||||||
./fail2ban.nix
|
|
||||||
./network_storage
|
|
||||||
./reverse_proxy.nix
|
./reverse_proxy.nix
|
||||||
|
./fail2ban.nix
|
||||||
./postgres.nix
|
./postgres.nix
|
||||||
|
./network_storage
|
||||||
./podman.nix
|
./podman.nix
|
||||||
./jellyfin.nix
|
|
||||||
./forgejo.nix
|
./actual
|
||||||
./searx.nix
|
./bazarr
|
||||||
./home-assistant.nix
|
./forgejo
|
||||||
./wyoming.nix
|
./home-assistant
|
||||||
./immich.nix
|
./immich
|
||||||
|
./jellyfin
|
||||||
|
./panoramax
|
||||||
|
./paperless
|
||||||
./qbittorent.nix
|
./qbittorent.nix
|
||||||
./paperless.nix
|
./radarr
|
||||||
./actual.nix
|
./searx
|
||||||
|
./sonarr
|
||||||
|
./wyoming.nix
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
forgejoPort = 8081;
|
|
||||||
stateDir = "/var/lib/forgejo";
|
|
||||||
db_user = "forgejo";
|
|
||||||
sshPort = 22222;
|
|
||||||
in {
|
|
||||||
options.services.forgejo = {
|
|
||||||
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.enable (lib.mkMerge [
|
|
||||||
{
|
|
||||||
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";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
host = {
|
|
||||||
reverse_proxy.subdomains.${config.services.forgejo.subdomain} = {
|
|
||||||
target = "http://localhost:${toString forgejoPort}";
|
|
||||||
};
|
|
||||||
postgres = {
|
|
||||||
enable = true;
|
|
||||||
extraUsers = {
|
|
||||||
${db_user} = {
|
|
||||||
isClient = true;
|
|
||||||
createUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraDatabases = {
|
|
||||||
${db_user} = {
|
|
||||||
name = db_user;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = forgejoPort;
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
config.services.forgejo.settings.server.SSH_LISTEN_PORT
|
|
||||||
];
|
|
||||||
}
|
|
||||||
(lib.mkIf config.services.fail2ban.enable {
|
|
||||||
environment.etc = {
|
|
||||||
"fail2ban/filter.d/forgejo.local".text = lib.mkIf config.services.forgejo.enable (
|
|
||||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
|
||||||
[Definition]
|
|
||||||
failregex = ".*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>"
|
|
||||||
'')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
services.fail2ban = {
|
|
||||||
jails = {
|
|
||||||
forgejo-iptables.settings = lib.mkIf config.services.forgejo.enable {
|
|
||||||
enabled = true;
|
|
||||||
filter = "forgejo";
|
|
||||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
|
||||||
logpath = "${config.services.forgejo.settings.log.ROOT_PATH}/*.log";
|
|
||||||
backend = "auto";
|
|
||||||
findtime = 600;
|
|
||||||
bantime = 600;
|
|
||||||
maxretry = 5;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf config.host.impermanence.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.forgejo.stateDir == stateDir;
|
|
||||||
message = "forgejo state directory does not match persistence";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
environment.persistence."/persist/system/root" = {
|
|
||||||
enable = true;
|
|
||||||
hideMounts = true;
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = stateDir;
|
|
||||||
user = "forgejo";
|
|
||||||
group = "forgejo";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
4
modules/nixos-modules/server/forgejo/const.nix
Normal file
4
modules/nixos-modules/server/forgejo/const.nix
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
httpPort = 8081;
|
||||||
|
sshPort = 22222;
|
||||||
|
}
|
41
modules/nixos-modules/server/forgejo/database.nix
Normal file
41
modules/nixos-modules/server/forgejo/database.nix
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf config.services.forgejo.enable (
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
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";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
53
modules/nixos-modules/server/forgejo/default.nix
Normal file
53
modules/nixos-modules/server/forgejo/default.nix
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
const = import ./const.nix;
|
||||||
|
httpPort = const.httpPort;
|
||||||
|
sshPort = const.sshPort;
|
||||||
|
db_user = "forgejo";
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
./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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
32
modules/nixos-modules/server/forgejo/fail2ban.nix
Normal file
32
modules/nixos-modules/server/forgejo/fail2ban.nix
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
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 ''
|
||||||
|
[Definition]
|
||||||
|
failregex = ".*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>"
|
||||||
|
'')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
services.fail2ban = {
|
||||||
|
jails = {
|
||||||
|
forgejo-iptables.settings = lib.mkIf config.services.forgejo.enable {
|
||||||
|
enabled = true;
|
||||||
|
filter = "forgejo";
|
||||||
|
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||||
|
logpath = "${config.services.forgejo.settings.log.ROOT_PATH}/*.log";
|
||||||
|
backend = "auto";
|
||||||
|
findtime = 600;
|
||||||
|
bantime = 600;
|
||||||
|
maxretry = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
28
modules/nixos-modules/server/forgejo/impermanence.nix
Normal file
28
modules/nixos-modules/server/forgejo/impermanence.nix
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
stateDir = "/var/lib/forgejo";
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (config.services.forgejo.enable && config.host.impermanence.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.forgejo.stateDir == stateDir;
|
||||||
|
message = "forgejo state directory does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.persistence."/persist/system/root" = {
|
||||||
|
enable = true;
|
||||||
|
hideMounts = true;
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = stateDir;
|
||||||
|
user = "forgejo";
|
||||||
|
group = "forgejo";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
26
modules/nixos-modules/server/forgejo/proxy.nix
Normal file
26
modules/nixos-modules/server/forgejo/proxy.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
const = import ./const.nix;
|
||||||
|
httpPort = const.httpPort;
|
||||||
|
in {
|
||||||
|
options.services.forgejo = {
|
||||||
|
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.enable && config.host.reverse_proxy.enable) {
|
||||||
|
host.reverse_proxy.subdomains.${config.services.forgejo.subdomain} = {
|
||||||
|
target = "http://localhost:${toString httpPort}";
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
config.services.forgejo.settings.server.SSH_LISTEN_PORT
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,229 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
configDir = "/var/lib/hass";
|
|
||||||
dbUser = "hass";
|
|
||||||
in {
|
|
||||||
options.services.home-assistant = {
|
|
||||||
subdomain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = "subdomain of base domain that home-assistant will be hosted at";
|
|
||||||
default = "home-assistant";
|
|
||||||
};
|
|
||||||
|
|
||||||
database = lib.mkOption {
|
|
||||||
type = lib.types.enum [
|
|
||||||
"builtin"
|
|
||||||
"postgres"
|
|
||||||
];
|
|
||||||
description = "what database do we want to use";
|
|
||||||
default = "builtin";
|
|
||||||
};
|
|
||||||
|
|
||||||
extensions = {
|
|
||||||
sonos = {
|
|
||||||
enable = lib.mkEnableOption "enable the sonos plugin";
|
|
||||||
port = lib.mkOption {
|
|
||||||
type = lib.types.int;
|
|
||||||
default = 1400;
|
|
||||||
description = "what port to use for sonos discovery";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
jellyfin = {
|
|
||||||
enable = lib.mkEnableOption "enable the jellyfin plugin";
|
|
||||||
};
|
|
||||||
wyoming = {
|
|
||||||
enable = lib.mkEnableOption "enable wyoming";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [
|
|
||||||
{
|
|
||||||
host = {
|
|
||||||
reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = {
|
|
||||||
target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
|
|
||||||
|
|
||||||
websockets.enable = true;
|
|
||||||
forwardHeaders.enable = true;
|
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
add_header Upgrade $http_upgrade;
|
|
||||||
add_header Connection \"upgrade\";
|
|
||||||
|
|
||||||
proxy_buffering off;
|
|
||||||
|
|
||||||
proxy_read_timeout 90;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.home-assistant = {
|
|
||||||
configDir = configDir;
|
|
||||||
extraComponents = [
|
|
||||||
"default_config"
|
|
||||||
"esphome"
|
|
||||||
"met"
|
|
||||||
"radio_browser"
|
|
||||||
"isal"
|
|
||||||
"zha"
|
|
||||||
"webostv"
|
|
||||||
"tailscale"
|
|
||||||
"syncthing"
|
|
||||||
"analytics_insights"
|
|
||||||
"unifi"
|
|
||||||
"openweathermap"
|
|
||||||
"ollama"
|
|
||||||
"mobile_app"
|
|
||||||
"logbook"
|
|
||||||
"ssdp"
|
|
||||||
"usb"
|
|
||||||
"webhook"
|
|
||||||
"bluetooth"
|
|
||||||
"dhcp"
|
|
||||||
"energy"
|
|
||||||
"history"
|
|
||||||
"backup"
|
|
||||||
"assist_pipeline"
|
|
||||||
"conversation"
|
|
||||||
"sun"
|
|
||||||
"zeroconf"
|
|
||||||
"cpuspeed"
|
|
||||||
];
|
|
||||||
config = {
|
|
||||||
http = {
|
|
||||||
server_port = 8123;
|
|
||||||
use_x_forwarded_for = true;
|
|
||||||
trusted_proxies = ["127.0.0.1" "::1"];
|
|
||||||
ip_ban_enabled = true;
|
|
||||||
login_attempts_threshold = 10;
|
|
||||||
};
|
|
||||||
homeassistant = {
|
|
||||||
external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}";
|
|
||||||
# internal_url = "http://192.168.1.2:8123";
|
|
||||||
};
|
|
||||||
recorder.db_url = "postgresql://@/${dbUser}";
|
|
||||||
"automation manual" = [];
|
|
||||||
"automation ui" = "!include automations.yaml";
|
|
||||||
mobile_app = {};
|
|
||||||
};
|
|
||||||
extraPackages = python3Packages:
|
|
||||||
with python3Packages; [
|
|
||||||
hassil
|
|
||||||
numpy
|
|
||||||
gtts
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
# TODO: configure /var/lib/hass/secrets.yaml via sops
|
|
||||||
|
|
||||||
networking.firewall.allowedUDPPorts = [
|
|
||||||
1900
|
|
||||||
];
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
(lib.mkIf (config.services.home-assistant.extensions.sonos.enable) {
|
|
||||||
services.home-assistant.extraComponents = ["sonos"];
|
|
||||||
networking.firewall.allowedTCPPorts = [
|
|
||||||
config.services.home-assistant.extensions.sonos.port
|
|
||||||
];
|
|
||||||
})
|
|
||||||
(lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) {
|
|
||||||
services.home-assistant.extraComponents = ["jellyfin"];
|
|
||||||
# TODO: configure port, address, and login information here
|
|
||||||
})
|
|
||||||
(lib.mkIf (config.services.home-assistant.extensions.wyoming.enable) {
|
|
||||||
services.home-assistant.extraComponents = ["wyoming"];
|
|
||||||
services.wyoming.enable = true;
|
|
||||||
})
|
|
||||||
(lib.mkIf (config.services.home-assistant.database == "postgres") {
|
|
||||||
host = {
|
|
||||||
postgres = {
|
|
||||||
enable = true;
|
|
||||||
extraUsers = {
|
|
||||||
${dbUser} = {
|
|
||||||
isClient = true;
|
|
||||||
createUser = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraDatabases = {
|
|
||||||
${dbUser} = {
|
|
||||||
name = dbUser;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.home-assistant = {
|
|
||||||
extraPackages = python3Packages:
|
|
||||||
with python3Packages; [
|
|
||||||
psycopg2
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.home-assistant = {
|
|
||||||
requires = [
|
|
||||||
config.systemd.services.postgresql.name
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf config.services.fail2ban.enable {
|
|
||||||
environment.etc = {
|
|
||||||
"fail2ban/filter.d/hass.local".text = lib.mkIf config.services.home-assistant.enable (
|
|
||||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
|
||||||
[INCLUDES]
|
|
||||||
before = common.conf
|
|
||||||
|
|
||||||
[Definition]
|
|
||||||
failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
|
|
||||||
|
|
||||||
ignoreregex =
|
|
||||||
|
|
||||||
[Init]
|
|
||||||
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
|
|
||||||
'')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
services.fail2ban = {
|
|
||||||
jails = {
|
|
||||||
home-assistant-iptables.settings = lib.mkIf config.services.home-assistant.enable {
|
|
||||||
enabled = true;
|
|
||||||
filter = "hass";
|
|
||||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
|
||||||
logpath = "${config.services.home-assistant.configDir}/*.log";
|
|
||||||
backend = "auto";
|
|
||||||
findtime = 600;
|
|
||||||
bantime = 600;
|
|
||||||
maxretry = 5;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf config.host.impermanence.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.home-assistant.configDir == configDir;
|
|
||||||
message = "home assistant config directory does not match persistence";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
environment.persistence."/persist/system/root" = {
|
|
||||||
enable = true;
|
|
||||||
hideMounts = true;
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = configDir;
|
|
||||||
user = "hass";
|
|
||||||
group = "hass";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
56
modules/nixos-modules/server/home-assistant/database.nix
Normal file
56
modules/nixos-modules/server/home-assistant/database.nix
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
dbUser = "hass";
|
||||||
|
in {
|
||||||
|
config = lib.mkIf config.services.home-assistant.enable (
|
||||||
|
lib.mkMerge [
|
||||||
|
{
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.home-assistant.database == "postgres";
|
||||||
|
message = "Home Assistant database type must be postgres";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(lib.mkIf config.host.postgres.enable {
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
extraUsers = {
|
||||||
|
${dbUser} = {
|
||||||
|
isClient = true;
|
||||||
|
createUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
extraDatabases = {
|
||||||
|
${dbUser} = {
|
||||||
|
name = dbUser;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.home-assistant = {
|
||||||
|
extraPackages = python3Packages:
|
||||||
|
with python3Packages; [
|
||||||
|
psycopg2
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.home-assistant = {
|
||||||
|
requires = [
|
||||||
|
config.systemd.services.postgresql.name
|
||||||
|
];
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
112
modules/nixos-modules/server/home-assistant/default.nix
Normal file
112
modules/nixos-modules/server/home-assistant/default.nix
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
imports = [
|
||||||
|
./proxy.nix
|
||||||
|
./database.nix
|
||||||
|
./fail2ban.nix
|
||||||
|
./impermanence.nix
|
||||||
|
./extensions
|
||||||
|
];
|
||||||
|
|
||||||
|
options.services.home-assistant = {
|
||||||
|
database = lib.mkOption {
|
||||||
|
type = lib.types.enum [
|
||||||
|
"builtin"
|
||||||
|
"postgres"
|
||||||
|
];
|
||||||
|
description = "what database do we want to use";
|
||||||
|
default = "builtin";
|
||||||
|
};
|
||||||
|
|
||||||
|
extensions = {
|
||||||
|
sonos = {
|
||||||
|
enable = lib.mkEnableOption "enable the sonos plugin";
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.int;
|
||||||
|
default = 1400;
|
||||||
|
description = "what port to use for sonos discovery";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
jellyfin = {
|
||||||
|
enable = lib.mkEnableOption "enable the jellyfin plugin";
|
||||||
|
};
|
||||||
|
wyoming = {
|
||||||
|
enable = lib.mkEnableOption "enable wyoming";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.home-assistant.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
services.home-assistant = {
|
||||||
|
configDir = "/var/lib/hass";
|
||||||
|
extraComponents = [
|
||||||
|
"default_config"
|
||||||
|
"esphome"
|
||||||
|
"met"
|
||||||
|
"radio_browser"
|
||||||
|
"isal"
|
||||||
|
"zha"
|
||||||
|
"webostv"
|
||||||
|
"tailscale"
|
||||||
|
"syncthing"
|
||||||
|
"analytics_insights"
|
||||||
|
"unifi"
|
||||||
|
"openweathermap"
|
||||||
|
"ollama"
|
||||||
|
"mobile_app"
|
||||||
|
"logbook"
|
||||||
|
"ssdp"
|
||||||
|
"usb"
|
||||||
|
"webhook"
|
||||||
|
"bluetooth"
|
||||||
|
"dhcp"
|
||||||
|
"energy"
|
||||||
|
"history"
|
||||||
|
"backup"
|
||||||
|
"assist_pipeline"
|
||||||
|
"conversation"
|
||||||
|
"sun"
|
||||||
|
"zeroconf"
|
||||||
|
"cpuspeed"
|
||||||
|
];
|
||||||
|
config = {
|
||||||
|
http = {
|
||||||
|
server_port = 8123;
|
||||||
|
use_x_forwarded_for = true;
|
||||||
|
trusted_proxies = ["127.0.0.1" "::1"];
|
||||||
|
ip_ban_enabled = true;
|
||||||
|
login_attempts_threshold = 10;
|
||||||
|
};
|
||||||
|
homeassistant = {
|
||||||
|
external_url = "https://${config.services.home-assistant.subdomain}.${config.host.reverse_proxy.hostname}";
|
||||||
|
# internal_url = "http://192.168.1.2:8123";
|
||||||
|
};
|
||||||
|
recorder.db_url = "postgresql://@/${config.services.home-assistant.configDir}";
|
||||||
|
"automation manual" = [];
|
||||||
|
"automation ui" = "!include automations.yaml";
|
||||||
|
mobile_app = {};
|
||||||
|
};
|
||||||
|
extraPackages = python3Packages:
|
||||||
|
with python3Packages; [
|
||||||
|
hassil
|
||||||
|
numpy
|
||||||
|
gtts
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: configure /var/lib/hass/secrets.yaml via sops
|
||||||
|
|
||||||
|
networking.firewall.allowedUDPPorts = [
|
||||||
|
1900
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"f ${config.services.home-assistant.configDir}/automations.yaml 0755 hass hass"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
imports = [
|
||||||
|
./sonos.nix
|
||||||
|
./jellyfin.nix
|
||||||
|
./wyoming.nix
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
lib.mkIf (config.services.home-assistant.extensions.jellyfin.enable) {
|
||||||
|
services.home-assistant.extraComponents = ["jellyfin"];
|
||||||
|
# TODO: configure port, address, and login information here
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
lib.mkIf (config.services.home-assistant.extensions.sonos.enable) {
|
||||||
|
services.home-assistant.extraComponents = ["sonos"];
|
||||||
|
networking.firewall.allowedTCPPorts = [
|
||||||
|
config.services.home-assistant.extensions.sonos.port
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
lib.mkIf (config.services.home-assistant.extensions.wyoming.enable) {
|
||||||
|
services.home-assistant.extraComponents = ["wyoming"];
|
||||||
|
services.wyoming.enable = true;
|
||||||
|
}
|
39
modules/nixos-modules/server/home-assistant/fail2ban.nix
Normal file
39
modules/nixos-modules/server/home-assistant/fail2ban.nix
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
lib.mkIf (config.services.fail2ban.enable && config.services.home-assistant.enable) {
|
||||||
|
environment.etc = {
|
||||||
|
"fail2ban/filter.d/hass.local".text = (
|
||||||
|
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||||
|
[INCLUDES]
|
||||||
|
before = common.conf
|
||||||
|
|
||||||
|
[Definition]
|
||||||
|
failregex = ^%(__prefix_line)s.*Login attempt or request with invalid authentication from <HOST>.*$
|
||||||
|
|
||||||
|
ignoreregex =
|
||||||
|
|
||||||
|
[Init]
|
||||||
|
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
|
||||||
|
'')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
services.fail2ban = {
|
||||||
|
jails = {
|
||||||
|
home-assistant-iptables.settings = {
|
||||||
|
enabled = true;
|
||||||
|
filter = "hass";
|
||||||
|
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||||
|
logpath = "${config.services.home-assistant.configDir}/*.log";
|
||||||
|
backend = "auto";
|
||||||
|
findtime = 600;
|
||||||
|
bantime = 600;
|
||||||
|
maxretry = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
26
modules/nixos-modules/server/home-assistant/impermanence.nix
Normal file
26
modules/nixos-modules/server/home-assistant/impermanence.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
configDir = "/var/lib/hass";
|
||||||
|
in
|
||||||
|
lib.mkIf (config.host.impermanence.enable && config.services.home-assistant.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.home-assistant.configDir == configDir;
|
||||||
|
message = "home assistant config directory does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
environment.persistence."/persist/system/root" = {
|
||||||
|
enable = true;
|
||||||
|
hideMounts = true;
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = configDir;
|
||||||
|
user = "hass";
|
||||||
|
group = "hass";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
33
modules/nixos-modules/server/home-assistant/proxy.nix
Normal file
33
modules/nixos-modules/server/home-assistant/proxy.nix
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.services.home-assistant = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "subdomain of base domain that home-assistant will be hosted at";
|
||||||
|
default = "home-assistant";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (config.host.reverse_proxy.enable && config.services.home-assistant.enable) {
|
||||||
|
host = {
|
||||||
|
reverse_proxy.subdomains.${config.services.home-assistant.subdomain} = {
|
||||||
|
target = "http://localhost:${toString config.services.home-assistant.config.http.server_port}";
|
||||||
|
|
||||||
|
websockets.enable = true;
|
||||||
|
forwardHeaders.enable = true;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
add_header Upgrade $http_upgrade;
|
||||||
|
add_header Connection \"upgrade\";
|
||||||
|
|
||||||
|
proxy_buffering off;
|
||||||
|
|
||||||
|
proxy_read_timeout 90;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,95 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
mediaLocation = "/var/lib/immich";
|
|
||||||
in {
|
|
||||||
options.services.immich = {
|
|
||||||
subdomain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = "subdomain of base domain that immich will be hosted at";
|
|
||||||
default = "immich";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.services.immich.enable (lib.mkMerge [
|
|
||||||
{
|
|
||||||
host = {
|
|
||||||
reverse_proxy.subdomains.${config.services.immich.subdomain} = {
|
|
||||||
target = "http://localhost:${toString config.services.immich.port}";
|
|
||||||
|
|
||||||
websockets.enable = true;
|
|
||||||
forwardHeaders.enable = true;
|
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
# allow large file uploads
|
|
||||||
client_max_body_size 50000M;
|
|
||||||
|
|
||||||
# set timeout
|
|
||||||
proxy_read_timeout 600s;
|
|
||||||
proxy_send_timeout 600s;
|
|
||||||
send_timeout 600s;
|
|
||||||
proxy_redirect off;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
postgres = {
|
|
||||||
enable = true;
|
|
||||||
extraUsers = {
|
|
||||||
${config.services.immich.database.user} = {
|
|
||||||
isClient = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.interfaces.${config.services.tailscale.interfaceName} = {
|
|
||||||
allowedUDPPorts = [
|
|
||||||
config.services.immich.port
|
|
||||||
];
|
|
||||||
allowedTCPPorts = [
|
|
||||||
config.services.immich.port
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
(lib.mkIf config.services.fail2ban.enable {
|
|
||||||
environment.etc = {
|
|
||||||
"fail2ban/filter.d/immich.local".text = lib.mkIf config.services.immich.enable (
|
|
||||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
|
||||||
[Definition]
|
|
||||||
failregex = immich-server.*Failed login attempt for user.+from ip address\s?<ADDR>
|
|
||||||
journalmatch = CONTAINER_TAG=immich-server
|
|
||||||
'')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
services.fail2ban = {
|
|
||||||
jails = {
|
|
||||||
immich-iptables.settings = lib.mkIf config.services.immich.enable {
|
|
||||||
enabled = true;
|
|
||||||
filter = "immich";
|
|
||||||
backend = "systemd";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf config.host.impermanence.enable {
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.immich.mediaLocation == mediaLocation;
|
|
||||||
message = "immich media location does not match persistence";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
environment.persistence."/persist/system/root" = {
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = mediaLocation;
|
|
||||||
user = "immich";
|
|
||||||
group = "immich";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
}
|
|
26
modules/nixos-modules/server/immich/database.nix
Normal file
26
modules/nixos-modules/server/immich/database.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf config.services.immich.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(lib.mkIf config.host.postgres.enable {
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
extraUsers = {
|
||||||
|
${config.services.immich.database.user} = {
|
||||||
|
isClient = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
20
modules/nixos-modules/server/immich/default.nix
Normal file
20
modules/nixos-modules/server/immich/default.nix
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{...}: {
|
||||||
|
imports = [
|
||||||
|
./proxy.nix
|
||||||
|
./database.nix
|
||||||
|
./fail2ban.nix
|
||||||
|
./impermanence.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
# NOTE: This shouldn't be needed now that we are out of testing
|
||||||
|
# config = lib.mkIf config.services.immich.enable {
|
||||||
|
# networking.firewall.interfaces.${config.services.tailscale.interfaceName} = {
|
||||||
|
# allowedUDPPorts = [
|
||||||
|
# config.services.immich.port
|
||||||
|
# ];
|
||||||
|
# allowedTCPPorts = [
|
||||||
|
# config.services.immich.port
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
}
|
26
modules/nixos-modules/server/immich/fail2ban.nix
Normal file
26
modules/nixos-modules/server/immich/fail2ban.nix
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf (config.services.fail2ban.enable && config.services.immich.enable) {
|
||||||
|
environment.etc = {
|
||||||
|
"fail2ban/filter.d/immich.local".text = pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||||
|
[Definition]
|
||||||
|
failregex = immich-server.*Failed login attempt for user.+from ip address\s?<ADDR>
|
||||||
|
journalmatch = CONTAINER_TAG=immich-server
|
||||||
|
'');
|
||||||
|
};
|
||||||
|
|
||||||
|
services.fail2ban = {
|
||||||
|
jails = {
|
||||||
|
immich-iptables.settings = {
|
||||||
|
enabled = true;
|
||||||
|
filter = "immich";
|
||||||
|
backend = "systemd";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
25
modules/nixos-modules/server/immich/impermanence.nix
Normal file
25
modules/nixos-modules/server/immich/impermanence.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
mediaLocation = "/var/lib/immich";
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (config.services.immich.enable && config.host.impermanence.enable) {
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.immich.mediaLocation == mediaLocation;
|
||||||
|
message = "immich media location does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
environment.persistence."/persist/system/root" = {
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = mediaLocation;
|
||||||
|
user = "immich";
|
||||||
|
group = "immich";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
35
modules/nixos-modules/server/immich/proxy.nix
Normal file
35
modules/nixos-modules/server/immich/proxy.nix
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.services.immich = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "subdomain of base domain that immich will be hosted at";
|
||||||
|
default = "immich";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (config.services.immich.enable && config.host.reverse_proxy.enable) {
|
||||||
|
host = {
|
||||||
|
reverse_proxy.subdomains.${config.services.immich.subdomain} = {
|
||||||
|
target = "http://localhost:${toString config.services.immich.port}";
|
||||||
|
|
||||||
|
websockets.enable = true;
|
||||||
|
forwardHeaders.enable = true;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
# allow large file uploads
|
||||||
|
client_max_body_size 50000M;
|
||||||
|
|
||||||
|
# set timeout
|
||||||
|
proxy_read_timeout 600s;
|
||||||
|
proxy_send_timeout 600s;
|
||||||
|
send_timeout 600s;
|
||||||
|
proxy_redirect off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,145 +0,0 @@
|
||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
config,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
jellyfinPort = 8096;
|
|
||||||
dlanPort = 1900;
|
|
||||||
jellyfin_data_directory = "/var/lib/jellyfin";
|
|
||||||
jellyfin_cache_directory = "/var/cache/jellyfin";
|
|
||||||
in {
|
|
||||||
options.services.jellyfin = {
|
|
||||||
subdomain = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = "subdomain of base domain that jellyfin will be hosted at";
|
|
||||||
default = "jellyfin";
|
|
||||||
};
|
|
||||||
extraSubdomains = lib.mkOption {
|
|
||||||
type = lib.types.listOf lib.types.str;
|
|
||||||
description = "ex subdomain of base domain that jellyfin will be hosted at";
|
|
||||||
default = [];
|
|
||||||
};
|
|
||||||
media_directory = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
description = "directory jellyfin media will be hosted at";
|
|
||||||
default = "/srv/jellyfin/media";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf config.services.jellyfin.enable (
|
|
||||||
lib.mkMerge [
|
|
||||||
{
|
|
||||||
host.reverse_proxy.subdomains.jellyfin = {
|
|
||||||
target = "http://localhost:${toString jellyfinPort}";
|
|
||||||
|
|
||||||
subdomain = config.services.jellyfin.subdomain;
|
|
||||||
extraSubdomains = config.services.jellyfin.extraSubdomains;
|
|
||||||
|
|
||||||
forwardHeaders.enable = true;
|
|
||||||
|
|
||||||
extraConfig = ''
|
|
||||||
client_max_body_size 20M;
|
|
||||||
add_header X-Content-Type-Options "nosniff";
|
|
||||||
|
|
||||||
proxy_buffering off;
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
environment.systemPackages = [
|
|
||||||
pkgs.jellyfin
|
|
||||||
pkgs.jellyfin-web
|
|
||||||
pkgs.jellyfin-ffmpeg
|
|
||||||
];
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort];
|
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
|
||||||
"d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media"
|
|
||||||
"A ${config.services.jellyfin.media_directory} - - - - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-"
|
|
||||||
];
|
|
||||||
}
|
|
||||||
(lib.mkIf config.services.fail2ban.enable {
|
|
||||||
environment.etc = {
|
|
||||||
"fail2ban/filter.d/jellyfin.local".text = (
|
|
||||||
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
|
||||||
[Definition]
|
|
||||||
failregex = "^.*Authentication request for .* has been denied \\\(IP: \"<ADDR>\"\\\)\\\."
|
|
||||||
'')
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
services.fail2ban = {
|
|
||||||
jails = {
|
|
||||||
jellyfin-iptables.settings = {
|
|
||||||
enabled = true;
|
|
||||||
filter = "jellyfin";
|
|
||||||
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
|
||||||
logpath = "${config.services.jellyfin.dataDir}/log/*.log";
|
|
||||||
backend = "auto";
|
|
||||||
findtime = 600;
|
|
||||||
bantime = 600;
|
|
||||||
maxretry = 5;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
(lib.mkIf config.host.impermanence.enable {
|
|
||||||
fileSystems."/persist/system/jellyfin".neededForBoot = true;
|
|
||||||
|
|
||||||
host.storage.pool.extraDatasets = {
|
|
||||||
# sops age key needs to be available to pre persist for user generation
|
|
||||||
"persist/system/jellyfin" = {
|
|
||||||
type = "zfs_fs";
|
|
||||||
mountpoint = "/persist/system/jellyfin";
|
|
||||||
options = {
|
|
||||||
atime = "off";
|
|
||||||
relatime = "off";
|
|
||||||
canmount = "on";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
assertions = [
|
|
||||||
{
|
|
||||||
assertion = config.services.jellyfin.dataDir == jellyfin_data_directory;
|
|
||||||
message = "jellyfin data directory does not match persistence";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory;
|
|
||||||
message = "jellyfin cache directory does not match persistence";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.persistence = {
|
|
||||||
"/persist/system/root" = {
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = jellyfin_data_directory;
|
|
||||||
user = "jellyfin";
|
|
||||||
group = "jellyfin";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
directory = jellyfin_cache_directory;
|
|
||||||
user = "jellyfin";
|
|
||||||
group = "jellyfin";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
"/persist/system/jellyfin" = {
|
|
||||||
enable = true;
|
|
||||||
hideMounts = true;
|
|
||||||
directories = [
|
|
||||||
{
|
|
||||||
directory = config.services.jellyfin.media_directory;
|
|
||||||
user = "jellyfin";
|
|
||||||
group = "jellyfin_media";
|
|
||||||
mode = "1770";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
38
modules/nixos-modules/server/jellyfin/default.nix
Normal file
38
modules/nixos-modules/server/jellyfin/default.nix
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
jellyfinPort = 8096;
|
||||||
|
dlanPort = 1900;
|
||||||
|
in {
|
||||||
|
imports = [
|
||||||
|
./proxy.nix
|
||||||
|
./fail2ban.nix
|
||||||
|
./impermanence.nix
|
||||||
|
];
|
||||||
|
|
||||||
|
options.services.jellyfin = {
|
||||||
|
media_directory = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "directory jellyfin media will be hosted at";
|
||||||
|
default = "/srv/jellyfin/media";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.jellyfin.enable {
|
||||||
|
environment.systemPackages = [
|
||||||
|
pkgs.jellyfin
|
||||||
|
pkgs.jellyfin-web
|
||||||
|
pkgs.jellyfin-ffmpeg
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [jellyfinPort dlanPort];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d ${config.services.jellyfin.media_directory} 2770 jellyfin jellyfin_media"
|
||||||
|
"A ${config.services.jellyfin.media_directory} - - - - u:jellyfin:rwX,g:jellyfin_media:rwX,o::-"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
32
modules/nixos-modules/server/jellyfin/fail2ban.nix
Normal file
32
modules/nixos-modules/server/jellyfin/fail2ban.nix
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf (config.services.jellyfin.enable && config.services.fail2ban.enable) {
|
||||||
|
environment.etc = {
|
||||||
|
"fail2ban/filter.d/jellyfin.local".text = (
|
||||||
|
pkgs.lib.mkDefault (pkgs.lib.mkAfter ''
|
||||||
|
[Definition]
|
||||||
|
failregex = "^.*Authentication request for .* has been denied \\\\\\(IP: \\\"<ADDR>\\\"\\\\\\)\\\\\\."
|
||||||
|
'')
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
services.fail2ban = {
|
||||||
|
jails = {
|
||||||
|
jellyfin-iptables.settings = {
|
||||||
|
enabled = true;
|
||||||
|
filter = "jellyfin";
|
||||||
|
action = ''iptables-multiport[name=HTTP, port="http,https"]'';
|
||||||
|
logpath = "${config.services.jellyfin.dataDir}/log/*.log";
|
||||||
|
backend = "auto";
|
||||||
|
findtime = 600;
|
||||||
|
bantime = 600;
|
||||||
|
maxretry = 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
66
modules/nixos-modules/server/jellyfin/impermanence.nix
Normal file
66
modules/nixos-modules/server/jellyfin/impermanence.nix
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
jellyfin_data_directory = "/var/lib/jellyfin";
|
||||||
|
jellyfin_cache_directory = "/var/cache/jellyfin";
|
||||||
|
in {
|
||||||
|
config = lib.mkIf (config.services.jellyfin.enable && config.host.impermanence.enable) {
|
||||||
|
fileSystems."/persist/system/jellyfin".neededForBoot = true;
|
||||||
|
|
||||||
|
host.storage.pool.extraDatasets = {
|
||||||
|
# sops age key needs to be available to pre persist for user generation
|
||||||
|
"persist/system/jellyfin" = {
|
||||||
|
type = "zfs_fs";
|
||||||
|
mountpoint = "/persist/system/jellyfin";
|
||||||
|
options = {
|
||||||
|
atime = "off";
|
||||||
|
relatime = "off";
|
||||||
|
canmount = "on";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
assertions = [
|
||||||
|
{
|
||||||
|
assertion = config.services.jellyfin.dataDir == jellyfin_data_directory;
|
||||||
|
message = "jellyfin data directory does not match persistence";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
assertion = config.services.jellyfin.cacheDir == jellyfin_cache_directory;
|
||||||
|
message = "jellyfin cache directory does not match persistence";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
environment.persistence = {
|
||||||
|
"/persist/system/root" = {
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = jellyfin_data_directory;
|
||||||
|
user = "jellyfin";
|
||||||
|
group = "jellyfin";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
directory = jellyfin_cache_directory;
|
||||||
|
user = "jellyfin";
|
||||||
|
group = "jellyfin";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
"/persist/system/jellyfin" = {
|
||||||
|
enable = true;
|
||||||
|
hideMounts = true;
|
||||||
|
directories = [
|
||||||
|
{
|
||||||
|
directory = config.services.jellyfin.media_directory;
|
||||||
|
user = "jellyfin";
|
||||||
|
group = "jellyfin_media";
|
||||||
|
mode = "1770";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
38
modules/nixos-modules/server/jellyfin/proxy.nix
Normal file
38
modules/nixos-modules/server/jellyfin/proxy.nix
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
jellyfinPort = 8096;
|
||||||
|
in {
|
||||||
|
options.services.jellyfin = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "subdomain of base domain that jellyfin will be hosted at";
|
||||||
|
default = "jellyfin";
|
||||||
|
};
|
||||||
|
extraSubdomains = lib.mkOption {
|
||||||
|
type = lib.types.listOf lib.types.str;
|
||||||
|
description = "ex subdomain of base domain that jellyfin will be hosted at";
|
||||||
|
default = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (config.services.jellyfin.enable && config.host.reverse_proxy.enable) {
|
||||||
|
host.reverse_proxy.subdomains.jellyfin = {
|
||||||
|
target = "http://localhost:${toString jellyfinPort}";
|
||||||
|
|
||||||
|
subdomain = config.services.jellyfin.subdomain;
|
||||||
|
extraSubdomains = config.services.jellyfin.extraSubdomains;
|
||||||
|
|
||||||
|
forwardHeaders.enable = true;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
client_max_body_size 20M;
|
||||||
|
add_header X-Content-Type-Options "nosniff";
|
||||||
|
|
||||||
|
proxy_buffering off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
34
modules/nixos-modules/server/panoramax/database.nix
Normal file
34
modules/nixos-modules/server/panoramax/database.nix
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(
|
||||||
|
lib.mkIf config.host.postgres.enable {
|
||||||
|
host = {
|
||||||
|
postgres = {
|
||||||
|
extraUsers = {
|
||||||
|
${config.services.panoramax.database.user} = {
|
||||||
|
isClient = true;
|
||||||
|
createUser = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
extraDatabases = {
|
||||||
|
${config.services.panoramax.database.name} = {
|
||||||
|
name = config.services.panoramax.database.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
}
|
9
modules/nixos-modules/server/panoramax/default.nix
Normal file
9
modules/nixos-modules/server/panoramax/default.nix
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{...}: {
|
||||||
|
imports = [
|
||||||
|
./proxy.nix
|
||||||
|
./fail2ban.nix
|
||||||
|
./impermanence.nix
|
||||||
|
./panoramax.nix
|
||||||
|
./database.nix
|
||||||
|
];
|
||||||
|
}
|
11
modules/nixos-modules/server/panoramax/fail2ban.nix
Normal file
11
modules/nixos-modules/server/panoramax/fail2ban.nix
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf (config.services.panoramax.enable && config.services.fail2ban.enable) {
|
||||||
|
# TODO: configure options for fail2ban
|
||||||
|
# This is a placeholder - panoramax fail2ban configuration would need to be defined
|
||||||
|
# based on the specific log patterns and security requirements
|
||||||
|
};
|
||||||
|
}
|
14
modules/nixos-modules/server/panoramax/impermanence.nix
Normal file
14
modules/nixos-modules/server/panoramax/impermanence.nix
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
osConfig,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
config = lib.mkIf (config.services.panoramax.enable && osConfig.host.impermanence.enable) {
|
||||||
|
# TODO: configure impermanence for panoramax data
|
||||||
|
# This would typically include directories like:
|
||||||
|
# - /var/lib/panoramax
|
||||||
|
# - panoramax storage directories
|
||||||
|
# - any cache or temporary directories that need to persist
|
||||||
|
};
|
||||||
|
}
|
359
modules/nixos-modules/server/panoramax/panoramax.nix
Normal file
359
modules/nixos-modules/server/panoramax/panoramax.nix
Normal file
|
@ -0,0 +1,359 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.services = {
|
||||||
|
panoramax = {
|
||||||
|
enable = lib.mkEnableOption "panoramax";
|
||||||
|
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.panoramax;
|
||||||
|
description = "The panoramax package to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "The user panoramax should run as.";
|
||||||
|
};
|
||||||
|
|
||||||
|
group = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "The group panoramax should run as.";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Host to bind the panoramax service to";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.port;
|
||||||
|
default = 5000;
|
||||||
|
description = "Port for the panoramax service";
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to open the panoramax port in the firewall";
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
urlScheme = lib.mkOption {
|
||||||
|
type = lib.types.enum ["http" "https"];
|
||||||
|
default = "https";
|
||||||
|
description = "URL scheme for the application";
|
||||||
|
};
|
||||||
|
|
||||||
|
storage = {
|
||||||
|
fsUrl = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = "/var/lib/panoramax/storage";
|
||||||
|
description = "File system URL for storage";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
infrastructure = {
|
||||||
|
nbProxies = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.int;
|
||||||
|
default = 1;
|
||||||
|
description = "Number of proxies in front of the application";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
flask = {
|
||||||
|
secretKey = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Flask secret key for session security";
|
||||||
|
};
|
||||||
|
|
||||||
|
sessionCookieDomain = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "Flask session cookie domain";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
api = {
|
||||||
|
pictures = {
|
||||||
|
licenseSpdxId = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "SPDX license identifier for API pictures";
|
||||||
|
};
|
||||||
|
|
||||||
|
licenseUrl = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = null;
|
||||||
|
description = "License URL for API pictures";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extraEnvironment = lib.mkOption {
|
||||||
|
type = lib.types.attrsOf lib.types.str;
|
||||||
|
default = {};
|
||||||
|
description = "Additional environment variables";
|
||||||
|
example = {
|
||||||
|
CUSTOM_SETTING = "value";
|
||||||
|
DEBUG = "true";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
createDB = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Whether to automatically create the database and user";
|
||||||
|
};
|
||||||
|
|
||||||
|
name = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "The name of the panoramax database";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = "/run/postgresql";
|
||||||
|
description = "Hostname or address of the postgresql server. If an absolute path is given here, it will be interpreted as a unix socket path.";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.port;
|
||||||
|
default = 5432;
|
||||||
|
description = "Port of the postgresql server.";
|
||||||
|
};
|
||||||
|
|
||||||
|
user = lib.mkOption {
|
||||||
|
type = lib.types.nullOr lib.types.str;
|
||||||
|
default = "panoramax";
|
||||||
|
description = "The database user for panoramax.";
|
||||||
|
};
|
||||||
|
|
||||||
|
# TODO: password file for external database
|
||||||
|
};
|
||||||
|
|
||||||
|
sgblur = {
|
||||||
|
# TODO: configs to bind to sgblur
|
||||||
|
};
|
||||||
|
};
|
||||||
|
sgblur = {
|
||||||
|
enable = lib.mkOption {
|
||||||
|
type = lib.types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Whether to enable sgblur integration for face and license plate blurring";
|
||||||
|
};
|
||||||
|
|
||||||
|
package = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.sgblur;
|
||||||
|
description = "The sgblur package to use";
|
||||||
|
};
|
||||||
|
|
||||||
|
port = lib.mkOption {
|
||||||
|
type = lib.types.port;
|
||||||
|
default = 8080;
|
||||||
|
description = "Port for the sgblur service";
|
||||||
|
};
|
||||||
|
|
||||||
|
host = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "127.0.0.1";
|
||||||
|
description = "Host to bind the sgblur service to";
|
||||||
|
};
|
||||||
|
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "http://127.0.0.1:8080";
|
||||||
|
description = "URL where sgblur service is accessible";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf config.services.panoramax.enable (lib.mkMerge [
|
||||||
|
{
|
||||||
|
# Create panoramax user and group
|
||||||
|
users.users.${config.services.panoramax.user} = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = config.services.panoramax.group;
|
||||||
|
home = "/var/lib/panoramax";
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.${config.services.panoramax.group} = {};
|
||||||
|
|
||||||
|
# Ensure storage directory exists with correct permissions
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '${config.services.panoramax.settings.storage.fsUrl}' 0755 ${config.services.panoramax.user} ${config.services.panoramax.group} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.panoramax-api = {
|
||||||
|
description = "Panoramax API server (self hosted map street view)";
|
||||||
|
after = ["network.target" "postgresql.service"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
environment =
|
||||||
|
{
|
||||||
|
# Core Flask configuration
|
||||||
|
FLASK_APP = "geovisio";
|
||||||
|
|
||||||
|
# Storage configuration
|
||||||
|
FS_URL = config.services.panoramax.settings.storage.fsUrl;
|
||||||
|
|
||||||
|
# Infrastructure configuration
|
||||||
|
INFRA_NB_PROXIES = toString config.services.panoramax.settings.infrastructure.nbProxies;
|
||||||
|
|
||||||
|
# Application configuration
|
||||||
|
PORT = toString config.services.panoramax.port;
|
||||||
|
|
||||||
|
# Python path to include the panoramax package
|
||||||
|
PYTHONPATH = "${config.services.panoramax.package}/${pkgs.python3.sitePackages}";
|
||||||
|
}
|
||||||
|
// (
|
||||||
|
if config.services.panoramax.database.host == "/run/postgresql"
|
||||||
|
then {
|
||||||
|
DB_URL = "postgresql://${config.services.panoramax.database.user}@/${config.services.panoramax.database.name}?host=/run/postgresql";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DB_HOST = config.services.panoramax.database.host;
|
||||||
|
DB_PORT = toString config.services.panoramax.database.port;
|
||||||
|
DB_USERNAME = config.services.panoramax.database.user;
|
||||||
|
DB_NAME = config.services.panoramax.database.name;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
// (lib.optionalAttrs (config.services.panoramax.settings.flask.secretKey != null) {
|
||||||
|
FLASK_SECRET_KEY = config.services.panoramax.settings.flask.secretKey;
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs (config.services.panoramax.settings.flask.sessionCookieDomain != null) {
|
||||||
|
FLASK_SESSION_COOKIE_DOMAIN = config.services.panoramax.settings.flask.sessionCookieDomain;
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs (config.services.panoramax.settings.api.pictures.licenseSpdxId != null) {
|
||||||
|
API_PICTURES_LICENSE_SPDX_ID = config.services.panoramax.settings.api.pictures.licenseSpdxId;
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs (config.services.panoramax.settings.api.pictures.licenseUrl != null) {
|
||||||
|
API_PICTURES_LICENSE_URL = config.services.panoramax.settings.api.pictures.licenseUrl;
|
||||||
|
})
|
||||||
|
// (lib.optionalAttrs config.services.sgblur.enable {
|
||||||
|
SGBLUR_API_URL = config.services.sgblur.url;
|
||||||
|
})
|
||||||
|
// config.services.panoramax.settings.extraEnvironment;
|
||||||
|
|
||||||
|
path = with pkgs; [
|
||||||
|
(python3.withPackages (ps: with ps; [config.services.panoramax.package waitress]))
|
||||||
|
];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.python3.withPackages (ps: with ps; [config.services.panoramax.package waitress])}/bin/waitress-serve --port ${toString config.services.panoramax.port} --call geovisio:create_app";
|
||||||
|
User = config.services.panoramax.user;
|
||||||
|
Group = config.services.panoramax.group;
|
||||||
|
WorkingDirectory = "/var/lib/panoramax";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = 5;
|
||||||
|
|
||||||
|
# Security hardening
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHome = true;
|
||||||
|
ReadWritePaths = [
|
||||||
|
"/var/lib/panoramax"
|
||||||
|
config.services.panoramax.settings.storage.fsUrl
|
||||||
|
];
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Open firewall if requested
|
||||||
|
networking.firewall.allowedTCPPorts = lib.mkIf config.services.panoramax.openFirewall [
|
||||||
|
config.services.panoramax.port
|
||||||
|
];
|
||||||
|
}
|
||||||
|
(lib.mkIf config.services.sgblur.enable {
|
||||||
|
# SGBlur service configuration
|
||||||
|
systemd.services.sgblur = {
|
||||||
|
description = "SGBlur face and license plate blurring service";
|
||||||
|
after = ["network.target"];
|
||||||
|
wantedBy = ["multi-user.target"];
|
||||||
|
|
||||||
|
path = with pkgs; [
|
||||||
|
config.services.sgblur.package
|
||||||
|
python3
|
||||||
|
python3Packages.waitress
|
||||||
|
];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.python3Packages.waitress}/bin/waitress-serve --host ${config.services.sgblur.host} --port ${toString config.services.sgblur.port} src.detect.detect_api:app";
|
||||||
|
WorkingDirectory = "${config.services.sgblur.package}";
|
||||||
|
Restart = "always";
|
||||||
|
RestartSec = 5;
|
||||||
|
|
||||||
|
# Basic security hardening
|
||||||
|
PrivateTmp = true;
|
||||||
|
ProtectSystem = "strict";
|
||||||
|
ProtectHome = true;
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateDevices = true;
|
||||||
|
ProtectKernelTunables = true;
|
||||||
|
ProtectKernelModules = true;
|
||||||
|
ProtectControlGroups = true;
|
||||||
|
RestrictSUIDSGID = true;
|
||||||
|
RestrictRealtime = true;
|
||||||
|
RestrictNamespaces = true;
|
||||||
|
LockPersonality = true;
|
||||||
|
MemoryDenyWriteExecute = true;
|
||||||
|
SystemCallArchitectures = "native";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = lib.mkIf config.services.panoramax.openFirewall [
|
||||||
|
config.services.sgblur.port
|
||||||
|
];
|
||||||
|
})
|
||||||
|
(lib.mkIf config.services.panoramax.database.createDB {
|
||||||
|
services.postgresql = {
|
||||||
|
enable = true;
|
||||||
|
ensureDatabases = lib.mkIf config.services.panoramax.database.createDB [config.services.panoramax.database.name];
|
||||||
|
ensureUsers = lib.mkIf config.services.panoramax.database.createDB [
|
||||||
|
{
|
||||||
|
name = config.services.panoramax.database.user;
|
||||||
|
ensureDBOwnership = true;
|
||||||
|
ensureClauses.login = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
extensions = ps: with ps; [postgis];
|
||||||
|
};
|
||||||
|
systemd.services.postgresql.serviceConfig.ExecStartPost = let
|
||||||
|
sqlFile = pkgs.writeText "panoramax-postgis-setup.sql" ''
|
||||||
|
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||||
|
|
||||||
|
-- TODO: how can we ensure that this runs after the databases have been created
|
||||||
|
-- ALTER DATABASE ${config.services.panoramax.database.name} SET TIMEZONE TO 'UTC';
|
||||||
|
|
||||||
|
GRANT SET ON PARAMETER session_replication_role TO ${config.services.panoramax.database.user};
|
||||||
|
'';
|
||||||
|
in [
|
||||||
|
''
|
||||||
|
${lib.getExe' config.services.postgresql.package "psql"} -d "${config.services.panoramax.database.user}" -f "${sqlFile}"
|
||||||
|
''
|
||||||
|
];
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
}
|
35
modules/nixos-modules/server/panoramax/proxy.nix
Normal file
35
modules/nixos-modules/server/panoramax/proxy.nix
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
options.services.panoramax = {
|
||||||
|
subdomain = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "subdomain of base domain that panoramax will be hosted at";
|
||||||
|
default = "panoramax";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf (config.services.panoramax.enable && config.host.reverse_proxy.enable) {
|
||||||
|
host = {
|
||||||
|
reverse_proxy.subdomains.${config.services.panoramax.subdomain} = {
|
||||||
|
target = "http://localhost:${toString config.services.panoramax.port}";
|
||||||
|
|
||||||
|
websockets.enable = true;
|
||||||
|
forwardHeaders.enable = true;
|
||||||
|
|
||||||
|
extraConfig = ''
|
||||||
|
# allow large file uploads for panoramic images
|
||||||
|
client_max_body_size 100M;
|
||||||
|
|
||||||
|
# set timeout for image processing
|
||||||
|
proxy_read_timeout 300s;
|
||||||
|
proxy_send_timeout 300s;
|
||||||
|
send_timeout 300s;
|
||||||
|
proxy_redirect off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue