refactor: move ark into dentritic pattern
|
Before Width: | Height: | Size: 263 KiB After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 696 KiB |
|
Before Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 366 KiB |
|
Before Width: | Height: | Size: 11 MiB |
@@ -1,18 +0,0 @@
|
|||||||
{ pkgs, pkgs-unstable, ... }:
|
|
||||||
let
|
|
||||||
scripts = import ./hyprland/scripts/default.nix { inherit pkgs; };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
(import ./hyprland/hyprland.nix { inherit pkgs scripts pkgs-unstable; })
|
|
||||||
(import ./hyprland/wallpaper.nix { inherit pkgs scripts; })
|
|
||||||
(import ./hyprland/hyprlock.nix { inherit pkgs scripts; })
|
|
||||||
(import ./hyprland/hypridle.nix { inherit pkgs scripts; })
|
|
||||||
./hyprland/notifications.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
{ pkgs, pkgs-unstable, scripts, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./hyprland/performance.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
wayland.windowManager.hyprland = {
|
|
||||||
enable = true;
|
|
||||||
systemd.enable = false;
|
|
||||||
|
|
||||||
plugins = with pkgs; [
|
|
||||||
(hyprlandPlugins.mkHyprlandPlugin {
|
|
||||||
pluginName = "hyprselect";
|
|
||||||
version = "0.1";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "jmanc3";
|
|
||||||
repo = "hyprselect";
|
|
||||||
rev = "f9651b5fd64c730ee164a6fee6a08d0398dcbe0a";
|
|
||||||
hash = "sha256-tY8EdfsjlUOuQ9v/POqpyLlkRO5wqEVSE9UeHfXuaGk=";
|
|
||||||
};
|
|
||||||
|
|
||||||
inherit (hyprland) nativeBuildInputs;
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
homepage = "https://github.com/jmanc3/hyprselect";
|
|
||||||
description = "A plugin that adds a completely useless desktop selection box to Hyprland";
|
|
||||||
license = licenses.unlicense;
|
|
||||||
platforms = platforms.linux;
|
|
||||||
};
|
|
||||||
})
|
|
||||||
hyprlandPlugins.hyprscrolling
|
|
||||||
hyprlandPlugins.hyprbars
|
|
||||||
];
|
|
||||||
|
|
||||||
settings = {
|
|
||||||
source = [
|
|
||||||
"~/.config/koonos/current/performance/hyprland.conf"
|
|
||||||
];
|
|
||||||
|
|
||||||
"$terminal" = "${pkgs.uwsm}/bin/uwsm-app -- ${pkgs.alacritty}/bin/alacritty";
|
|
||||||
"$fileManager" = "${pkgs.uwsm}/bin/uwsm-app -- ${pkgs.pcmanfm}/bin/pcmanfm";
|
|
||||||
"$browser" = "${pkgs.uwsm}/bin/uwsm-app -- zen-beta";
|
|
||||||
"$menu" = "${pkgs.walker}/bin/walker";
|
|
||||||
"$player" = "${pkgs.playerctl}/bin/playerctl";
|
|
||||||
|
|
||||||
monitor = [
|
|
||||||
"eDP-1,preferred,1721x1080,auto"
|
|
||||||
"HDMI-A-1,preferred,1450x0,auto"
|
|
||||||
];
|
|
||||||
|
|
||||||
exec-once = [
|
|
||||||
"${pkgs.uwsm}/bin/uwsm-app -- ${pkgs.hypridle}/bin/hypridle"
|
|
||||||
"${pkgs.uwsm}/bin/uwsm-app -- ${pkgs.waybar}/bin/waybar"
|
|
||||||
"${pkgs.uwsm}/bin/uwsm-app -- ${pkgs.hyprpaper}/bin/hyprpaper"
|
|
||||||
"sleep 2 && pw-play --volume=0 ~/Downloads/empty.wav"
|
|
||||||
];
|
|
||||||
|
|
||||||
env = [
|
|
||||||
"HYPRCURSOR_THEME,macOS"
|
|
||||||
"HYPRCURSOR_SIZE,20"
|
|
||||||
];
|
|
||||||
|
|
||||||
# env = [
|
|
||||||
# "XCURSOR_SIZE,20"
|
|
||||||
# "XCURSOR_THEME,macOS"
|
|
||||||
# ];
|
|
||||||
|
|
||||||
general = {
|
|
||||||
gaps_in = 0;
|
|
||||||
gaps_out = 0;
|
|
||||||
|
|
||||||
border_size = 2;
|
|
||||||
|
|
||||||
"col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
|
|
||||||
"col.inactive_border" = "rgba(595959aa)";
|
|
||||||
|
|
||||||
# Set to true enable resizing windows by clicking and dragging on borders and gaps
|
|
||||||
resize_on_border = true;
|
|
||||||
|
|
||||||
# Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
|
|
||||||
allow_tearing = false;
|
|
||||||
|
|
||||||
layout = "scrolling";
|
|
||||||
};
|
|
||||||
|
|
||||||
decoration = {
|
|
||||||
# rounding = 10
|
|
||||||
# rounding_power = 2
|
|
||||||
|
|
||||||
# Change transparency of focused and unfocused windows
|
|
||||||
active_opacity = 1.0;
|
|
||||||
inactive_opacity = 1.0;
|
|
||||||
|
|
||||||
shadow = {
|
|
||||||
# enabled = false;
|
|
||||||
range = 4;
|
|
||||||
render_power = 3;
|
|
||||||
color = "rgba(1a1a1aee)";
|
|
||||||
};
|
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#blur
|
|
||||||
blur = {
|
|
||||||
# enabled = false;
|
|
||||||
size = 3;
|
|
||||||
passes = 1;
|
|
||||||
|
|
||||||
vibrancy = 0.1696;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#animations
|
|
||||||
animations = {
|
|
||||||
enabled = true;
|
|
||||||
|
|
||||||
# Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
|
|
||||||
bezier = [
|
|
||||||
"easeOutQuint,0.23,1,0.32,1"
|
|
||||||
"easeInOutCubic,0.65,0.05,0.36,1"
|
|
||||||
"linear,0,0,1,1"
|
|
||||||
"almostLinear,0.5,0.5,0.75,1.0"
|
|
||||||
"quick,0.15,0,0.1,1"
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
animation = [
|
|
||||||
"global, 1, 10, default"
|
|
||||||
"border, 0, 5.39, easeOutQuint"
|
|
||||||
"windows, 1, 4.79, easeOutQuint"
|
|
||||||
"windowsIn, 1, 4.1, easeOutQuint, popin 87%"
|
|
||||||
"windowsOut, 1, 1.49, linear, popin 87%"
|
|
||||||
"fadeIn, 1, 1.73, almostLinear"
|
|
||||||
"fadeOut, 1, 1.46, almostLinear"
|
|
||||||
"fade, 1, 3.03, quick"
|
|
||||||
"layers, 1, 3.81, easeOutQuint"
|
|
||||||
"layersIn, 1, 4, easeOutQuint, fade"
|
|
||||||
"layersOut, 1, 1.5, linear, fade"
|
|
||||||
"fadeLayersIn, 1, 1.79, almostLinear"
|
|
||||||
"fadeLayersOut, 1, 1.39, almostLinear"
|
|
||||||
"workspaces, 0, 1.94, almostLinear, fade"
|
|
||||||
"workspacesIn, 0, 1.21, almostLinear, fade"
|
|
||||||
"workspacesOut, 0, 1.94, almostLinear, fade"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
dwindle = {
|
|
||||||
pseudotile = true; # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
|
|
||||||
preserve_split = true; # You probably want this
|
|
||||||
};
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
|
|
||||||
master = {
|
|
||||||
new_status = "master";
|
|
||||||
};
|
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#misc
|
|
||||||
misc = {
|
|
||||||
force_default_wallpaper = 0; # Set to 0 or 1 to disable the anime mascot wallpapers
|
|
||||||
disable_hyprland_logo = true;
|
|
||||||
disable_splash_rendering = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#############
|
|
||||||
### INPUT ###
|
|
||||||
#############
|
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#input
|
|
||||||
input = {
|
|
||||||
kb_layout = "us";
|
|
||||||
# kb_variant =
|
|
||||||
# kb_model =
|
|
||||||
kb_options = "caps:swapescape";
|
|
||||||
# kb_rules =
|
|
||||||
|
|
||||||
follow_mouse = 1;
|
|
||||||
|
|
||||||
sensitivity = 0; # -1.0 - 1.0, 0 means no modification.
|
|
||||||
repeat_rate = 35;
|
|
||||||
repeat_delay = 300;
|
|
||||||
|
|
||||||
touchpad = {
|
|
||||||
natural_scroll = true;
|
|
||||||
tap-to-click = false;
|
|
||||||
clickfinger_behavior = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# https://wiki.hyprland.org/Configuring/Variables/#gestures
|
|
||||||
# gestures = {
|
|
||||||
# workspace_swipe = true;
|
|
||||||
# };
|
|
||||||
|
|
||||||
# See https://wiki.hyprland.org/Configuring/Keywords/
|
|
||||||
"$mainMod" = "SUPER"; # Sets "Windows" key as main modifier
|
|
||||||
bind = [
|
|
||||||
|
|
||||||
# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
|
|
||||||
"$mainMod, return, exec, $terminal"
|
|
||||||
"$mainMod, W, killactive,"
|
|
||||||
# bind = $mainMod, M, exit,
|
|
||||||
"$mainMod, E, exec, $fileManager"
|
|
||||||
"$mainMod, B, exec, $browser"
|
|
||||||
|
|
||||||
"$mainMod, M, exec, $terminal -e ${pkgs-unstable.gurk-rs}/bin/gurk"
|
|
||||||
"$mainMod, P, exec, $terminal -e ${pkgs.ncmpcpp}/bin/ncmpcpp"
|
|
||||||
"$mainMod SHIFT, B, exec, $terminal -e \"$EDITOR\" /home/max/bible.txt -R"
|
|
||||||
"$mainMod SHIFT, R, exec, ${pkgs.hyprshot}/bin/hyprshot -m region --clipboard-only"
|
|
||||||
|
|
||||||
# "$mainMod, V, togglefloating,"
|
|
||||||
"$mainMod, space, exec, $menu"
|
|
||||||
# "$mainMod, P, pseudo, # dwindle"
|
|
||||||
"$mainMod, F, fullscreen"
|
|
||||||
# bind = $mainMod, J, togglesplit, # dwindle
|
|
||||||
|
|
||||||
"$mainMod SHIFT, Q, exec, ${scripts.lock}"
|
|
||||||
|
|
||||||
# Move focus with mainMod + arrow keys
|
|
||||||
"$mainMod, H, movefocus, l"
|
|
||||||
"$mainMod, L, movefocus, r"
|
|
||||||
"$mainMod, K, movefocus, u"
|
|
||||||
"$mainMod, J, movefocus, d"
|
|
||||||
|
|
||||||
# Swap window with mainMod + shift + arrow keys
|
|
||||||
"$mainMod SHIFT, H, swapwindow, l"
|
|
||||||
"$mainMod SHIFT, L, swapwindow, r"
|
|
||||||
"$mainMod SHIFT, K, swapwindow, u"
|
|
||||||
"$mainMod SHIFT, J, swapwindow, d"
|
|
||||||
|
|
||||||
# "$mainMod ALT, H, resizeactive, -40 0"
|
|
||||||
# "$mainMod ALT, L, resizeactive, 40 0"
|
|
||||||
|
|
||||||
# Switch workspaces with mainMod + [0-9]
|
|
||||||
"$mainMod, 1, workspace, 1"
|
|
||||||
"$mainMod, 2, workspace, 2"
|
|
||||||
"$mainMod, 3, workspace, 3"
|
|
||||||
"$mainMod, 4, workspace, 4"
|
|
||||||
"$mainMod, 5, workspace, 5"
|
|
||||||
"$mainMod, 6, workspace, 6"
|
|
||||||
"$mainMod, 7, workspace, 7"
|
|
||||||
"$mainMod, 8, workspace, 8"
|
|
||||||
"$mainMod, 9, workspace, 9"
|
|
||||||
"$mainMod, 0, workspace, 10"
|
|
||||||
|
|
||||||
# Move active window to a workspace with mainMod + SHIFT + [0-9]
|
|
||||||
"$mainMod SHIFT, 1, movetoworkspace, 1"
|
|
||||||
"$mainMod SHIFT, 2, movetoworkspace, 2"
|
|
||||||
"$mainMod SHIFT, 3, movetoworkspace, 3"
|
|
||||||
"$mainMod SHIFT, 4, movetoworkspace, 4"
|
|
||||||
"$mainMod SHIFT, 5, movetoworkspace, 5"
|
|
||||||
"$mainMod SHIFT, 6, movetoworkspace, 6"
|
|
||||||
"$mainMod SHIFT, 7, movetoworkspace, 7"
|
|
||||||
"$mainMod SHIFT, 8, movetoworkspace, 8"
|
|
||||||
"$mainMod SHIFT, 9, movetoworkspace, 9"
|
|
||||||
"$mainMod SHIFT, 0, movetoworkspace, 10"
|
|
||||||
|
|
||||||
# Example special workspace (scratchpad)
|
|
||||||
"$mainMod, S, togglespecialworkspace, magic"
|
|
||||||
"$mainMod SHIFT, S, movetoworkspace, special:magic"
|
|
||||||
|
|
||||||
# Scroll through existing workspaces with mainMod + scroll
|
|
||||||
# "$mainMod, mouse_down, workspace, e+1"
|
|
||||||
# "$mainMod, mouse_up, workspace, e-1"
|
|
||||||
|
|
||||||
", Prior, exec, ${pkgs.ydotool}/bin/ydotool click --next-delay 0 0x40"
|
|
||||||
", Next, exec, ${pkgs.ydotool}/bin/ydotool click --next-delay 0 0x41"
|
|
||||||
];
|
|
||||||
|
|
||||||
bindr = [
|
|
||||||
", Prior, exec, ${pkgs.ydotool}/bin/ydotool click --next-delay 0 0x80"
|
|
||||||
", Next, exec, ${pkgs.ydotool}/bin/ydotool click --next-delay 0 0x81"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Move/resize windows with mainMod + LMB/RMB and dragging
|
|
||||||
bindm = [
|
|
||||||
"$mainMod, mouse:272, movewindow"
|
|
||||||
"$mainMod, mouse:273, resizewindow"
|
|
||||||
];
|
|
||||||
|
|
||||||
"$osdclient" = "swayosd-client --monitor \"$(hyprctl monitors -j | ${pkgs.jq}/bin/jq -r '.[] | select(.focused == true).name')\"";
|
|
||||||
|
|
||||||
bindel = [
|
|
||||||
# Laptop multimedia keys for volume and LCD brightness
|
|
||||||
# bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
|
|
||||||
# bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
|
||||||
",XF86AudioRaiseVolume, exec, $osdclient --output-volume=raise"
|
|
||||||
",XF86AudioLowerVolume, exec, $osdclient --output-volume=lower"
|
|
||||||
",XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
|
|
||||||
",XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
|
|
||||||
# bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
|
|
||||||
# bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
|
|
||||||
",XF86MonBrightnessUp, exec, $osdclient --brightness=raise"
|
|
||||||
",XF86MonBrightnessDown, exec, $osdclient --brightness=lower"
|
|
||||||
];
|
|
||||||
|
|
||||||
bindl = [
|
|
||||||
# Requires playerctl
|
|
||||||
", XF86AudioNext, exec, $player next"
|
|
||||||
", XF86AudioPause, exec, $player play-pause"
|
|
||||||
", XF86AudioPlay, exec, $player play-pause"
|
|
||||||
", XF86AudioPrev, exec, $player previous"
|
|
||||||
];
|
|
||||||
|
|
||||||
bindd = [
|
|
||||||
"$mainMod, C, Universal copy, sendshortcut, CTRL, Insert,"
|
|
||||||
"$mainMod, V, Universal paste, sendshortcut, SHIFT, Insert,"
|
|
||||||
"$mainMod, X, Universal cut, sendshortcut, CTRL, X,"
|
|
||||||
"$mainMod, A, Universal select all, sendshortcut, CTRL, A,"
|
|
||||||
"$mainMod, T, Universal new tab, sendshortcut, CTRL, T,"
|
|
||||||
|
|
||||||
"$mainMod ALT, H, Universal left, sendshortcut, , Left,"
|
|
||||||
"$mainMod ALT, J, Universal down, sendshortcut, , Down,"
|
|
||||||
"$mainMod ALT, K, Universal up, sendshortcut, , Up,"
|
|
||||||
"$mainMod ALT, L, Universal right, sendshortcut, , Right,"
|
|
||||||
|
|
||||||
"$mainMod SHIFT ALT, H, Universal left, sendshortcut, SHIFT, Left,"
|
|
||||||
"$mainMod SHIFT ALT, J, Universal down, sendshortcut, SHIFT, Down,"
|
|
||||||
"$mainMod SHIFT ALT, K, Universal up, sendshortcut, SHIFT, Up,"
|
|
||||||
"$mainMod SHIFT ALT, L, Universal right, sendshortcut, SHIFT, Right,"
|
|
||||||
];
|
|
||||||
|
|
||||||
windowrule = [
|
|
||||||
# Just dash of opacity by default
|
|
||||||
"opacity 0.97 0.9, class:.*"
|
|
||||||
|
|
||||||
# Ignore maximize requests from apps. You'll probably like this.
|
|
||||||
"suppressevent maximize, class:.*"
|
|
||||||
|
|
||||||
# Fix some dragging issues with XWayland
|
|
||||||
"nofocus,class:^$,title:^$,xwayland:1,floating:1,fullscreen:0,pinned:0"
|
|
||||||
];
|
|
||||||
|
|
||||||
plugin = {
|
|
||||||
hyprselect = {
|
|
||||||
"col.main" = "rgba(ffffff25)";
|
|
||||||
"col.border" = "rgba(ffffff88)";
|
|
||||||
|
|
||||||
fade_time_ms = 165.0;
|
|
||||||
|
|
||||||
border_size = 1.0;
|
|
||||||
};
|
|
||||||
hyprscrolling = {
|
|
||||||
fullscreen_on_one_column = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
hyprbars = {
|
|
||||||
enabled = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
{ pkgs, lib, ... }:
|
|
||||||
let
|
|
||||||
normal = {
|
|
||||||
decoration = {
|
|
||||||
blur.enabled = true;
|
|
||||||
shadow.enabled = true;
|
|
||||||
};
|
|
||||||
misc.vfr = false;
|
|
||||||
};
|
|
||||||
battery-saver = {
|
|
||||||
decoration = {
|
|
||||||
blur.enabled = false;
|
|
||||||
shadow.enabled = false;
|
|
||||||
};
|
|
||||||
misc.vfr = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
normal-file = pkgs.writeText "hyprland.conf.normal" (lib.hm.generators.toHyprconf { attrs = normal; });
|
|
||||||
battery-saver-file = pkgs.writeText "hyprland.conf.battery" (lib.hm.generators.toHyprconf { attrs = battery-saver; });
|
|
||||||
|
|
||||||
switchScript = pkgs.writeShellScriptBin "switch-config" ''
|
|
||||||
TARGET="$HOME/.config/koonos/current/performance/hyprland.conf"
|
|
||||||
|
|
||||||
if [ "$(readlink "$TARGET")" = "${normal-file}" ]; then
|
|
||||||
ln -sf ${battery-saver-file} "$TARGET"
|
|
||||||
echo "Switched to battery saver"
|
|
||||||
else
|
|
||||||
ln -sf ${normal-file} "$TARGET"
|
|
||||||
echo "Switched to normal mode"
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
in
|
|
||||||
{
|
|
||||||
home.file.".config/koonos/current/performance/hyprland.conf".source = normal-file;
|
|
||||||
|
|
||||||
home.packages = [ switchScript ];
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{ pkgs }:
|
|
||||||
{
|
|
||||||
lock =
|
|
||||||
pkgs.writeShellScript "koonos-lock-screen" ''
|
|
||||||
${pkgs.hyprlock}/bin/hyprlock
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }: {
|
|
||||||
imports = [
|
|
||||||
./hardware-configuration.nix
|
|
||||||
./options.nix
|
|
||||||
../common/core/default.nix
|
|
||||||
./user.nix
|
|
||||||
./sops.nix
|
|
||||||
|
|
||||||
./service/audio.nix
|
|
||||||
./service/auth.nix
|
|
||||||
./service/docs.nix
|
|
||||||
./service/git.nix
|
|
||||||
./service/home.nix
|
|
||||||
./service/photos.nix
|
|
||||||
./service/radicale.nix
|
|
||||||
./service/wakapi.nix
|
|
||||||
|
|
||||||
# ./service/elytra.nix
|
|
||||||
./service/money.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# Use the systemd-boot EFI boot loader.
|
|
||||||
boot.loader.systemd-boot.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = true;
|
|
||||||
|
|
||||||
networking.hostName = "ark";
|
|
||||||
networking.nameservers = [ "8.8.8.8" "1.1.1.1" ];
|
|
||||||
services.tailscale = {
|
|
||||||
enable = true;
|
|
||||||
useRoutingFeatures = "both";
|
|
||||||
extraUpFlags = [ "--accept-dns=false" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
oauth.name = "KoonFamily";
|
|
||||||
oauth.secrets = import ./oauth-secrets.nix;
|
|
||||||
|
|
||||||
security.sudo.wheelNeedsPassword = false;
|
|
||||||
|
|
||||||
services.cloudflared = {
|
|
||||||
enable = true;
|
|
||||||
tunnels = {
|
|
||||||
"91d31395-fbc7-45a1-ae13-148957b32ecd" = {
|
|
||||||
credentialsFile = config.sops.secrets.tunnel-credentials.path;
|
|
||||||
ingress = {
|
|
||||||
"auth.koon.us" = "http://localhost:1411";
|
|
||||||
"photos.koon.us" = "http://localhost:2283";
|
|
||||||
"home.koon.us" = "http://localhost:8123";
|
|
||||||
"docs.koon.us" = "http://localhost:3004";
|
|
||||||
"git.koon.us" = "http://localhost:3000";
|
|
||||||
"ssh.koon.us" = "ssh://localhost:2222";
|
|
||||||
"audio.koon.us" = "http://localhost:8021";
|
|
||||||
"radicale.koon.us" = "http://localhost:5232";
|
|
||||||
"waka.koon.us" = "http://localhost:3006";
|
|
||||||
# "ride.koon.us" = "http://localhost:3007";
|
|
||||||
# "ride-api.koon.us" = "http://localhost:8080";
|
|
||||||
|
|
||||||
"money.koon.us" = "http://localhost:3160";
|
|
||||||
"zero.koon.us" = "http://localhost:4848";
|
|
||||||
"money-api.koon.us" = "http://localhost:3161";
|
|
||||||
|
|
||||||
};
|
|
||||||
default = "http_status:404";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
fileSystems."/mnt/hdd" = {
|
|
||||||
device = "/dev/sdb";
|
|
||||||
fsType = "ext4";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.openssh.enable = true;
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ 8123 22 ];
|
|
||||||
|
|
||||||
system.stateVersion = "25.05"; # Did you read the comment?
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{ lib, ... }: {
|
|
||||||
options.oauth = {
|
|
||||||
name = lib.mkOption { type = lib.types.str; };
|
|
||||||
secrets = lib.mkOption { type = lib.types.attrs; };
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{ ... }: {
|
|
||||||
services.audiobookshelf = {
|
|
||||||
enable = true;
|
|
||||||
port = 8021;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
{ config, pkgs, ... }: {
|
|
||||||
services.pocket-id = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
APP_URL = "https://auth.koon.us";
|
|
||||||
TRUST_PROXY = true;
|
|
||||||
ANALYTICS_DISABLED = true;
|
|
||||||
|
|
||||||
UI_CONFIG_DISABLED = true;
|
|
||||||
|
|
||||||
APP_NAME = config.oauth.name;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
credentials = {
|
|
||||||
ENCRYPTION_KEY = config.sops.secrets."pocket-id-encryption-key".path;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
{ config, lib, pkgs, ... }: {
|
|
||||||
nixpkgs.config.allowUnfree = true;
|
|
||||||
|
|
||||||
services.outline = {
|
|
||||||
enable = true;
|
|
||||||
publicUrl = "https://docs.koon.us";
|
|
||||||
port = 3004;
|
|
||||||
forceHttps = true;
|
|
||||||
storage.storageType = "local";
|
|
||||||
logo = "https://i.imgur.com/fKJ1I63.png";
|
|
||||||
oidcAuthentication = {
|
|
||||||
authUrl = "https://auth.koon.us/authorize";
|
|
||||||
tokenUrl = "https://auth.koon.us/api/oidc/token";
|
|
||||||
userinfoUrl = "https://auth.koon.us/api/oidc/userinfo";
|
|
||||||
clientId = "";
|
|
||||||
clientSecretFile = config.sops.secrets."docs/clientSecret".path;
|
|
||||||
scopes = [ "openid" "email" "profile" ];
|
|
||||||
usernameClaim = "preferred_username";
|
|
||||||
displayName = config.oauth.name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.outline = {
|
|
||||||
script =
|
|
||||||
let
|
|
||||||
localPostgresqlUrl = "postgres://localhost/outline?host=/run/postgresql";
|
|
||||||
cfg = config.services.outline;
|
|
||||||
in lib.mkForce ''
|
|
||||||
export SECRET_KEY="$(head -n1 ${lib.escapeShellArg cfg.secretKeyFile})"
|
|
||||||
export UTILS_SECRET="$(head -n1 ${lib.escapeShellArg cfg.utilsSecretFile})"
|
|
||||||
${lib.optionalString (cfg.storage.storageType == "s3") ''
|
|
||||||
export AWS_SECRET_ACCESS_KEY="$(head -n1 ${lib.escapeShellArg cfg.storage.secretKeyFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.slackAuthentication != null) ''
|
|
||||||
export SLACK_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.slackAuthentication.secretFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.googleAuthentication != null) ''
|
|
||||||
export GOOGLE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.googleAuthentication.clientSecretFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.azureAuthentication != null) ''
|
|
||||||
export AZURE_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.azureAuthentication.clientSecretFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.oidcAuthentication != null) ''
|
|
||||||
export OIDC_CLIENT_SECRET="$(head -n1 ${lib.escapeShellArg cfg.oidcAuthentication.clientSecretFile})"
|
|
||||||
export OIDC_CLIENT_ID="$(cat ${config.sops.secrets."docs/clientId".path})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.sslKeyFile != null) ''
|
|
||||||
export SSL_KEY="$(head -n1 ${lib.escapeShellArg cfg.sslKeyFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.sslCertFile != null) ''
|
|
||||||
export SSL_CERT="$(head -n1 ${lib.escapeShellArg cfg.sslCertFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.slackIntegration != null) ''
|
|
||||||
export SLACK_VERIFICATION_TOKEN="$(head -n1 ${lib.escapeShellArg cfg.slackIntegration.verificationTokenFile})"
|
|
||||||
''}
|
|
||||||
${lib.optionalString (cfg.smtp != null) ''
|
|
||||||
export SMTP_PASSWORD="$(head -n1 ${lib.escapeShellArg cfg.smtp.passwordFile})"
|
|
||||||
''}
|
|
||||||
|
|
||||||
${
|
|
||||||
if (cfg.databaseUrl == "local") then
|
|
||||||
''
|
|
||||||
export DATABASE_URL=${lib.escapeShellArg localPostgresqlUrl}
|
|
||||||
export PGSSLMODE=disable
|
|
||||||
''
|
|
||||||
else
|
|
||||||
''
|
|
||||||
export DATABASE_URL=${lib.escapeShellArg cfg.databaseUrl}
|
|
||||||
''
|
|
||||||
}
|
|
||||||
|
|
||||||
${cfg.package}/bin/outline-server
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,112 +0,0 @@
|
|||||||
{ secrets, config, pkgs, elytrarides, ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
users.users.elytra-web = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "elytra-web";
|
|
||||||
description = "Elytra Rides web service user";
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users.backend = {
|
|
||||||
isSystemUser = true;
|
|
||||||
home = "/var/lib/elytra-backend";
|
|
||||||
createHome = true;
|
|
||||||
group = "backend";
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.elytra-web = {};
|
|
||||||
users.groups.backend = {};
|
|
||||||
|
|
||||||
systemd.services.elytra-web = {
|
|
||||||
description = "Elytra Rides Next.js Web Application";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
PORT = "3007";
|
|
||||||
HOST = "127.0.0.1";
|
|
||||||
NODE_ENV = "production";
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "simple";
|
|
||||||
User = "elytra-web";
|
|
||||||
Group = "elytra-web";
|
|
||||||
|
|
||||||
WorkingDirectory = "${pkgs.web}/lib/node_modules/web";
|
|
||||||
ExecStart =
|
|
||||||
"${pkgs.nodejs}/bin/node ${pkgs.web}/lib/node_modules/web/node_modules/next/dist/bin/next start";
|
|
||||||
EnvironmentFile = config.sops.secrets."elytra-frontend-env".path;
|
|
||||||
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 10;
|
|
||||||
|
|
||||||
# Security hardening
|
|
||||||
NoNewPrivileges = true;
|
|
||||||
PrivateTmp = true;
|
|
||||||
ProtectSystem = "strict";
|
|
||||||
ProtectHome = true;
|
|
||||||
|
|
||||||
StateDirectory = "elytra-web";
|
|
||||||
StateDirectoryMode = "0750";
|
|
||||||
|
|
||||||
StandardOutput = "journal";
|
|
||||||
StandardError = "journal";
|
|
||||||
SyslogIdentifier = "elytra-web";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.postgresql = {
|
|
||||||
enable = true;
|
|
||||||
ensureDatabases = [ "backend" ];
|
|
||||||
ensureUsers = [
|
|
||||||
{
|
|
||||||
name = "backend";
|
|
||||||
ensureDBOwnership = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
services.redis = {
|
|
||||||
enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
(final: prev: {
|
|
||||||
web = elytrarides.packages.${pkgs.system}.web.overrideAttrs (old: {
|
|
||||||
buildPhase = ''
|
|
||||||
export NEXT_PUBLIC_GOOGLE_MAPS_API_KEY="${config.environment.sessionVariables.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY}"
|
|
||||||
${old.buildPhase or "runHook preBuild; npm run build --if-present; runHook postBuild"}
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
environment.sessionVariables.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY = secrets.ark.elytra.google-maps-api-key;
|
|
||||||
|
|
||||||
systemd.services.elytra-backend = {
|
|
||||||
description = "Elytra Rides Backend Service";
|
|
||||||
after = [ "network.target" "postgresql.service" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
|
|
||||||
ExecStart = "${elytrarides.packages.${pkgs.system}.backend}/bin/nujade_backend";
|
|
||||||
ExecStartPre = [
|
|
||||||
"${pkgs.diesel-cli}/bin/diesel --database-url=\"postgresql:///backend?user=backend\" migration run --migration-dir=${elytrarides.packages.${pkgs.system}.backend}/migrations"
|
|
||||||
];
|
|
||||||
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = 5;
|
|
||||||
User = "backend";
|
|
||||||
WorkingDirectory = "/var/lib/elytra-backend";
|
|
||||||
Environment = "RUST_LOG=info";
|
|
||||||
EnvironmentFile = config.sops.secrets."elytra-backend-env".path;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
DATABASE_URL="postgresql:///backend?user=backend";
|
|
||||||
};
|
|
||||||
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
{ lib, config, pkgs, ... }: {
|
|
||||||
|
|
||||||
services.openssh = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
# hostKeys = [
|
|
||||||
# { path = "/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; }
|
|
||||||
# { path = "/etc/ssh/ssh_host_rsa_key"; type = "rsa"; bits = 4096; }
|
|
||||||
# ];
|
|
||||||
|
|
||||||
settings = {
|
|
||||||
# explicitly allow post-quantum KEX
|
|
||||||
KexAlgorithms = [
|
|
||||||
"mlkem768x25519-sha256"
|
|
||||||
"sntrup761x25519-sha512"
|
|
||||||
"curve25519-sha256"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.gitea = {
|
|
||||||
enable = true;
|
|
||||||
user = "git";
|
|
||||||
group = "git";
|
|
||||||
database = {
|
|
||||||
user = "git";
|
|
||||||
name = "git";
|
|
||||||
type = "postgres";
|
|
||||||
};
|
|
||||||
settings = {
|
|
||||||
server = {
|
|
||||||
DOMAIN = "git.koon.us";
|
|
||||||
ROOT_URL = "https://git.koon.us";
|
|
||||||
HTTP_PORT = 3000;
|
|
||||||
LANDING_PAGE = "/max";
|
|
||||||
SSH_DOMAIN = "ssh.koon.us";
|
|
||||||
SSH_PORT = 2222;
|
|
||||||
START_SSH_SERVER = true;
|
|
||||||
};
|
|
||||||
oauth2_client = {
|
|
||||||
ACCOUNT_LINKING = "auto";
|
|
||||||
ENABLE_AUTO_REGISTRATION = true;
|
|
||||||
UPDATE_AVATAR = true;
|
|
||||||
USERNAME = "email";
|
|
||||||
};
|
|
||||||
service = {
|
|
||||||
DISABLE_REGISTRATION = true;
|
|
||||||
ENABLE_PASSWORD_SIGNIN_FORM = false;
|
|
||||||
ENABLE_PASSKEY_AUTHENTICATION = false;
|
|
||||||
|
|
||||||
SHOW_MILESTONES_DASHBOARD_PAGE = false;
|
|
||||||
};
|
|
||||||
"service.explore" = {
|
|
||||||
DISABLE_USERS_PAGE = true;
|
|
||||||
DISABLE_ORGANIZATIONS_PAGE = true;
|
|
||||||
DISABLE_CODE_PAGE = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users.git = {
|
|
||||||
isSystemUser = true;
|
|
||||||
group = "git";
|
|
||||||
home = "/var/lib/gitea";
|
|
||||||
description = "Git server (Gitea)";
|
|
||||||
createHome = true;
|
|
||||||
};
|
|
||||||
users.groups.git = { };
|
|
||||||
|
|
||||||
systemd.services.gitea = {
|
|
||||||
serviceConfig = {
|
|
||||||
RestartSec = "60"; # Retry every minute
|
|
||||||
};
|
|
||||||
preStart = let
|
|
||||||
exe = lib.getExe config.services.gitea.package;
|
|
||||||
|
|
||||||
clientIdPath = config.sops.secrets."git/clientId".path;
|
|
||||||
clientSecretPath = config.sops.secrets."git/clientSecret".path;
|
|
||||||
|
|
||||||
args = lib.escapeShellArgs (lib.concatLists [
|
|
||||||
[ "--name" config.oauth.name ]
|
|
||||||
[ "--provider" "openidConnect" ]
|
|
||||||
# [ "--key" config.oauth.secrets.git.clientId ]
|
|
||||||
[
|
|
||||||
"--auto-discover-url"
|
|
||||||
"https://auth.koon.us/.well-known/openid-configuration"
|
|
||||||
]
|
|
||||||
[ "--scopes" "email" ]
|
|
||||||
[ "--scopes" "profile" ]
|
|
||||||
[ "--group-claim-name" "groups" ]
|
|
||||||
[ "--admin-group" "admin" ]
|
|
||||||
[ "--skip-local-2fa" ]
|
|
||||||
]);
|
|
||||||
in lib.mkAfter ''
|
|
||||||
CLIENT_ID=$(cat ${clientIdPath})
|
|
||||||
CLIENT_SECRET=$(cat ${clientSecretPath})
|
|
||||||
|
|
||||||
provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${config.oauth.name}' | cut -f1)
|
|
||||||
|
|
||||||
if [[ -z "$provider_id" ]]; then
|
|
||||||
${exe} admin auth add-oauth ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
|
|
||||||
else
|
|
||||||
${exe} admin auth update-oauth --id "$provider_id" ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir -p /var/lib/gitea/custom/public/assets/img/
|
|
||||||
|
|
||||||
ln -sf ${
|
|
||||||
./git/assets/img/logo.svg
|
|
||||||
} /var/lib/gitea/custom/public/assets/img/logo.svg
|
|
||||||
ln -sf ${
|
|
||||||
./git/assets/img/favicon.svg
|
|
||||||
} /var/lib/gitea/custom/public/assets/img/favicon.svg
|
|
||||||
|
|
||||||
mkdir -p /var/lib/gitea/custom/templates/base/
|
|
||||||
ln -sf ${
|
|
||||||
./git/templates/base/head_navbar.tmpl
|
|
||||||
} /var/lib/gitea/custom/templates/base/head_navbar.tmpl
|
|
||||||
ln -sf ${
|
|
||||||
./git/templates/base/footer_content.tmpl
|
|
||||||
} /var/lib/gitea/custom/templates/base/footer_content.tmpl
|
|
||||||
|
|
||||||
mkdir -p /var/lib/gitea/custom/templates/custom/
|
|
||||||
ln -sf ${
|
|
||||||
./git/templates/custom/header.tmpl
|
|
||||||
} /var/lib/gitea/custom/templates/custom/header.tmpl
|
|
||||||
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
services.restic.backups = {
|
|
||||||
git-local = {
|
|
||||||
repository = "/mnt/hdd/restic/git";
|
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
|
||||||
initialize = true;
|
|
||||||
paths = [ "/var/lib/gitea/repositories" "/var/backup/git" ];
|
|
||||||
backupPrepareCommand = ''
|
|
||||||
mkdir -p /var/backup/git
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
|
||||||
--clean \
|
|
||||||
--if-exists \
|
|
||||||
--dbname=git > /var/backup/git/postgres.sql
|
|
||||||
'';
|
|
||||||
backupCleanupCommand = ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
git-remote = {
|
|
||||||
repository = "rest:http://m1:8000/git";
|
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
|
||||||
initialize = true;
|
|
||||||
paths = [ "/var/lib/gitea/repositories" "/var/backup/git" ];
|
|
||||||
backupPrepareCommand = ''
|
|
||||||
mkdir -p /var/backup/git
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
|
||||||
--clean \
|
|
||||||
--if-exists \
|
|
||||||
--dbname=git > /var/backup/git/postgres.sql
|
|
||||||
'';
|
|
||||||
backupCleanupCommand = ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs;
|
|
||||||
let
|
|
||||||
scripts = with pkgs; {
|
|
||||||
restore_git_pg = writeShellScriptBin "restore_git_pg" ''
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres psql --dbname=git < /var/backup/git/postgres.sql
|
|
||||||
'';
|
|
||||||
restore_git = writeShellScriptBin "restore_git" ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/git restore latest --target /
|
|
||||||
|
|
||||||
${scripts.restore_git_pg}/bin/restore_git_pg
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in [ scripts.restore_git_pg scripts.restore_git ];
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{ pkgs, ... }: {
|
|
||||||
virtualisation.oci-containers = let
|
|
||||||
hass_config = pkgs.writeText "configuration.yaml" ''
|
|
||||||
# Discovery
|
|
||||||
default_config:
|
|
||||||
|
|
||||||
# Web Server configuration
|
|
||||||
http:
|
|
||||||
server_host: 127.0.0.1
|
|
||||||
use_x_forwarded_for: true
|
|
||||||
trusted_proxies: 127.0.0.1
|
|
||||||
'';
|
|
||||||
in {
|
|
||||||
backend = "podman";
|
|
||||||
containers.homeassistant = {
|
|
||||||
volumes = [
|
|
||||||
"home-assistant:/config"
|
|
||||||
# "/data/docker/hass:/config"
|
|
||||||
"${hass_config}:/config/configuration.yaml"
|
|
||||||
# "/run/secrets/home-assistant:/config/secrets.yaml"
|
|
||||||
];
|
|
||||||
environment.TZ = "America/New_York";
|
|
||||||
image =
|
|
||||||
"ghcr.io/home-assistant/home-assistant:stable"; # Warning: if the tag does not change, the image will not be updated
|
|
||||||
extraOptions = [ "--network=host" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
{ pkgs, config, ... }:
|
|
||||||
|
|
||||||
let
|
|
||||||
|
|
||||||
src = pkgs.fetchgit {
|
|
||||||
url = "https://git.koon.us/max/money.git";
|
|
||||||
hash = "sha256-TPUeYuffR8U0M3Wnc3yGmqDhEjWIhRRFaKDkhTBsNG8=";
|
|
||||||
};
|
|
||||||
|
|
||||||
expoWeb = pkgs.stdenv.mkDerivation (finalAttrs: {
|
|
||||||
pname = "expo-web";
|
|
||||||
version = "1.0.0";
|
|
||||||
src = src;
|
|
||||||
pnpm = pkgs.pnpm_10;
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pkgs.nodejs
|
|
||||||
finalAttrs.pnpm.configHook
|
|
||||||
];
|
|
||||||
pnpmDeps = finalAttrs.pnpm.fetchDeps {
|
|
||||||
inherit (finalAttrs) pname version src;
|
|
||||||
fetcherVersion = 2;
|
|
||||||
hash = "sha256-x2zCFeMU0VfkVRILrLReEOFNrcd7aJp57v4fMGBE2dI=";
|
|
||||||
};
|
|
||||||
pnpmInstallFlags = [ "--frozen-lockfile" ];
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
pnpm run build
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out
|
|
||||||
cp -r dist/* $out/
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
api = pkgs.stdenv.mkDerivation (finalAttrs: {
|
|
||||||
pname = "koon-money-api";
|
|
||||||
version = "1.0.1";
|
|
||||||
src = src;
|
|
||||||
pnpm = pkgs.pnpm_10;
|
|
||||||
nativeBuildInputs = [
|
|
||||||
pkgs.nodejs
|
|
||||||
finalAttrs.pnpm.configHook
|
|
||||||
pkgs.python3 # Required for node-gyp
|
|
||||||
pkgs.nodePackages.node-gyp # For building native modules
|
|
||||||
pkgs.pkg-config
|
|
||||||
pkgs.gnumake
|
|
||||||
pkgs.gcc
|
|
||||||
];
|
|
||||||
buildInputs = [
|
|
||||||
pkgs.sqlite
|
|
||||||
pkgs.sqlite.dev
|
|
||||||
pkgs.readline
|
|
||||||
pkgs.ncurses
|
|
||||||
pkgs.libbsd
|
|
||||||
];
|
|
||||||
pnpmDeps = finalAttrs.pnpm.fetchDeps {
|
|
||||||
inherit (finalAttrs) pname version src;
|
|
||||||
fetcherVersion = 2;
|
|
||||||
hash = "sha256-x2zCFeMU0VfkVRILrLReEOFNrcd7aJp57v4fMGBE2dI=";
|
|
||||||
};
|
|
||||||
NIX_CFLAGS_COMPILE = "-D_GNU_SOURCE";
|
|
||||||
pnpmInstallFlags = [ "--frozen-lockfile" ];
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
runHook preBuild
|
|
||||||
cd node_modules/@rocicorp/zero-sqlite3
|
|
||||||
node-gyp rebuild --build-from-source
|
|
||||||
cd -
|
|
||||||
runHook postBuild
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out
|
|
||||||
cp -r . $out/
|
|
||||||
'';
|
|
||||||
});
|
|
||||||
|
|
||||||
api-port = "3161";
|
|
||||||
in
|
|
||||||
{
|
|
||||||
|
|
||||||
services.nginx = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
virtualHosts."money.koon.us" = {
|
|
||||||
root = "${expoWeb}";
|
|
||||||
listen = [
|
|
||||||
{ addr = "127.0.0.1"; port = 3160; }
|
|
||||||
];
|
|
||||||
locations."/" = {
|
|
||||||
tryFiles = "$uri /index.html";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
virtualisation.oci-containers = {
|
|
||||||
backend = "podman";
|
|
||||||
containers = {
|
|
||||||
zero = {
|
|
||||||
image = "rocicorp/zero:0.23.2025101600";
|
|
||||||
ports = ["127.0.0.1:4848:4848"];
|
|
||||||
volumes = [ "/run/postgresql:/run/postgresql" ];
|
|
||||||
environment = {
|
|
||||||
|
|
||||||
ZERO_UPSTREAM_DB = "postgresql://postgres@127.0.0.1/money";
|
|
||||||
ZERO_REPLICA_FILE = "/tmp/zync-replica.db";
|
|
||||||
ZERO_GET_QUERIES_URL = "http://localhost:${api-port}/api/zero/get-queries";
|
|
||||||
ZERO_GET_QUERIES_FORWARD_COOKIES = "true";
|
|
||||||
|
|
||||||
ZERO_MUTATE_URL = "http://localhost:${api-port}/api/zero/mutate";
|
|
||||||
ZERO_MUTATE_FORWARD_COOKIES = "true";
|
|
||||||
};
|
|
||||||
extraOptions = [ "--network=host" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.postgresql = {
|
|
||||||
enable = true;
|
|
||||||
ensureDatabases = [ "money" ];
|
|
||||||
ensureUsers = [
|
|
||||||
{
|
|
||||||
name = "money";
|
|
||||||
ensureDBOwnership = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
authentication = ''
|
|
||||||
# TYPE DATABASE USER ADDRESS METHOD
|
|
||||||
local all postgres peer
|
|
||||||
host all all 127.0.0.1/32 trust
|
|
||||||
host all all ::1/128 trust
|
|
||||||
'';
|
|
||||||
settings = {
|
|
||||||
wal_level = "logical";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.money-api = {
|
|
||||||
description = "Money API";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network.target" ];
|
|
||||||
|
|
||||||
environment = {
|
|
||||||
ZERO_UPSTREAM_DB = "postgresql://postgres@127.0.0.1/money";
|
|
||||||
PORT = api-port;
|
|
||||||
NODE_ENV = "production";
|
|
||||||
BETTER_AUTH_SECRET = "burger";
|
|
||||||
DEBUG = "*";
|
|
||||||
NODE_OPTIONS = "--trace-warnings --trace-uncaught";
|
|
||||||
OAUTH_DISCOVERY_URL = "https://auth.koon.us/.well-known/openid-configuration";
|
|
||||||
PLAID_ENV = "production";
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceConfig = {
|
|
||||||
Type = "simple";
|
|
||||||
User = "money";
|
|
||||||
Group = "money";
|
|
||||||
WorkingDirectory = "${api}/shared";
|
|
||||||
|
|
||||||
ExecStartPre = "${api}/node_modules/.bin/drizzle-kit push --config=${api}/shared/drizzle.config.ts";
|
|
||||||
|
|
||||||
ExecStart = pkgs.writeShellScript "money-api-start" ''
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
export OAUTH_CLIENT_ID="$(cat ${config.sops.secrets."money/clientId".path})"
|
|
||||||
export OAUTH_CLIENT_SECRET="$(cat ${config.sops.secrets."money/clientSecret".path})"
|
|
||||||
|
|
||||||
exec ${api}/node_modules/.bin/tsx ${api}/api/src/index.ts
|
|
||||||
'';
|
|
||||||
|
|
||||||
EnvironmentFile = config.sops.secrets."money-env".path;
|
|
||||||
|
|
||||||
Restart = "on-failure";
|
|
||||||
RestartSec = 10;
|
|
||||||
|
|
||||||
SyslogIdentifier = "money-api";
|
|
||||||
StandardOutput = "journal";
|
|
||||||
StandardError = "journal";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
users.users.money = {
|
|
||||||
isSystemUser = true;
|
|
||||||
home = "/var/lib/money";
|
|
||||||
createHome = true;
|
|
||||||
group = "money";
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.money = {};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
{ lib, config, pkgs, ... }: {
|
|
||||||
sops = {
|
|
||||||
templates = {
|
|
||||||
"immich-config.json" = {
|
|
||||||
content = builtins.toJSON {
|
|
||||||
passwordLogin.enabled = false;
|
|
||||||
|
|
||||||
# We will do this ourselves
|
|
||||||
backup.database.enabled = false;
|
|
||||||
|
|
||||||
oauth = {
|
|
||||||
enabled = true;
|
|
||||||
autoLaunch = true;
|
|
||||||
autoRegister = true;
|
|
||||||
buttonText =
|
|
||||||
lib.strings.concatStrings [ "Login To " config.oauth.name ];
|
|
||||||
clientId = config.sops.placeholder."photos/clientId";
|
|
||||||
clientSecret = config.sops.placeholder."photos/clientSecret";
|
|
||||||
issuerUrl = "https://auth.koon.us/.well-known/openid-configuration";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
owner = config.users.users.immich.name;
|
|
||||||
mode = "0400";
|
|
||||||
restartUnits = [ "immich-server.service" "pocket-id.service" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.immich = {
|
|
||||||
enable = true;
|
|
||||||
port = 2283;
|
|
||||||
environment.IMMICH_CONFIG_FILE = config.sops.templates."immich-config.json".path;
|
|
||||||
accelerationDevices = null;
|
|
||||||
|
|
||||||
machine-learning.environment = {
|
|
||||||
HF_XET_CACHE = "/var/cache/immich/huggingface-xet";
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
users.users.immich = {
|
|
||||||
home = "/var/lib/immich";
|
|
||||||
createHome = true;
|
|
||||||
extraGroups = [ "video" "render" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware.graphics = {
|
|
||||||
enable = true;
|
|
||||||
extraPackages = with pkgs; [ intel-media-driver ];
|
|
||||||
};
|
|
||||||
environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };
|
|
||||||
|
|
||||||
services.restic.backups = {
|
|
||||||
immich-local = {
|
|
||||||
repository = "/mnt/hdd/restic/immich";
|
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
|
||||||
initialize = true;
|
|
||||||
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
|
|
||||||
backupPrepareCommand = ''
|
|
||||||
mkdir -p /var/backup/immich
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
|
||||||
--clean \
|
|
||||||
--if-exists \
|
|
||||||
--dbname=immich > /var/backup/immich/postgres.sql
|
|
||||||
'';
|
|
||||||
backupCleanupCommand = ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
immich-remote = {
|
|
||||||
repository = "rest:http://m1:8000/immich";
|
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
|
||||||
initialize = true;
|
|
||||||
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
|
|
||||||
backupPrepareCommand = ''
|
|
||||||
mkdir -p /var/backup/immich
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
|
||||||
--clean \
|
|
||||||
--if-exists \
|
|
||||||
--dbname=immich > /var/backup/immich/postgres.sql
|
|
||||||
'';
|
|
||||||
backupCleanupCommand = ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs;
|
|
||||||
let
|
|
||||||
scripts = with pkgs; {
|
|
||||||
restore_immich_pg = writeShellScriptBin "restore_immich_pg" ''
|
|
||||||
${pkgs.sudo}/bin/sudo -u postgres psql --dbname=immich < /var/backup/immich/postgres.sql
|
|
||||||
'';
|
|
||||||
restore_immich = writeShellScriptBin "restore_immich" ''
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/immich restore latest --target /
|
|
||||||
|
|
||||||
${scripts.restore_immich_pg}/bin/restore_immich_pg
|
|
||||||
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
|
||||||
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in [ scripts.restore_immich_pg scripts.restore_immich ];
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{ ... }: {
|
|
||||||
services.radicale = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
auth.type = "none";
|
|
||||||
server.hosts = [ "0.0.0.0:5232" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
|
|
||||||
nixpkgs.overlays = [
|
|
||||||
(final: prev: let
|
|
||||||
version = "2.15.0";
|
|
||||||
in {
|
|
||||||
|
|
||||||
wakapi = (prev.buildGoModule.override { go = prev.go_1_25; }) {
|
|
||||||
pname = "wakapi";
|
|
||||||
version = version;
|
|
||||||
|
|
||||||
src = final.fetchFromGitHub {
|
|
||||||
owner = "k2on";
|
|
||||||
repo = "wakapi";
|
|
||||||
rev = "koon-fork";
|
|
||||||
hash = "sha256-FYGtoJmbqUD02/JKvON1RqpjkrDkAOkfPwMAUZ2MSE4=";
|
|
||||||
};
|
|
||||||
|
|
||||||
vendorHash = "sha256-912x6LwitYXdjWpP75Xoc56JXadeLQZuESSyLoaJcU0=";
|
|
||||||
|
|
||||||
excludedPackages = [ "scripts" ];
|
|
||||||
|
|
||||||
postPatch = ''echo ${version} > version.txt'';
|
|
||||||
|
|
||||||
ldflags = [ "-s" "-w" ];
|
|
||||||
|
|
||||||
passthru = {
|
|
||||||
nixos = prev.nixosTests.wakapi;
|
|
||||||
updateScript = prev.nix-update-script { };
|
|
||||||
};
|
|
||||||
|
|
||||||
meta = prev.wakapi.meta // {
|
|
||||||
version = version;
|
|
||||||
mainProgram = "wakapi";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
services.wakapi = {
|
|
||||||
enable = true;
|
|
||||||
passwordSaltFile = config.sops.secrets."waka-password-salt".path;
|
|
||||||
settings = {
|
|
||||||
server.port = 3006;
|
|
||||||
app.avatar_url_template = "https://auth.koon.us/api/users/fbffa48a-faf7-4230-a89f-0da184f5948c/profile-picture.png";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
{ config, ... }:
|
|
||||||
{
|
|
||||||
sops = {
|
|
||||||
|
|
||||||
defaultSopsFile = ../../secrets/sops/host/ark/default.yaml;
|
|
||||||
validateSopsFiles = false;
|
|
||||||
|
|
||||||
age.keyFile = if builtins.pathExists /var/lib/sops-nix/key.txt then
|
|
||||||
"/var/lib/sops-nix/key.txt"
|
|
||||||
else
|
|
||||||
"/home/admin/.config/sops/age/keys.txt" # temp decrypt key
|
|
||||||
;
|
|
||||||
|
|
||||||
secrets = {
|
|
||||||
"host_age_key" = {
|
|
||||||
path = "/var/lib/sops-nix/key.txt";
|
|
||||||
};
|
|
||||||
|
|
||||||
"restic-password" = {};
|
|
||||||
"tunnel-credentials" = {};
|
|
||||||
"admin-password" = {};
|
|
||||||
|
|
||||||
"pocket-id-encryption-key" = {
|
|
||||||
owner = config.services.pocket-id.user;
|
|
||||||
};
|
|
||||||
|
|
||||||
"waka-password-salt" = {
|
|
||||||
owner = config.users.users.wakapi.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
"money-env" = {
|
|
||||||
owner = config.users.users.money.name;
|
|
||||||
};
|
|
||||||
|
|
||||||
"photos/clientId" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
};
|
|
||||||
"photos/clientSecret" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
};
|
|
||||||
|
|
||||||
"git/clientId" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.services.gitea.user;
|
|
||||||
};
|
|
||||||
"git/clientSecret" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.services.gitea.user;
|
|
||||||
};
|
|
||||||
|
|
||||||
"docs/clientId" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.services.outline.user;
|
|
||||||
};
|
|
||||||
"docs/clientSecret" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.services.outline.user;
|
|
||||||
};
|
|
||||||
"money/clientId" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.users.users.money.name;
|
|
||||||
};
|
|
||||||
"money/clientSecret" = {
|
|
||||||
sopsFile = ../../secrets/sops/host/ark/oauth.yaml;
|
|
||||||
owner = config.users.users.money.name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{ pkgs, config, ... }: {
|
|
||||||
|
|
||||||
sops.secrets.admin-password.neededForUsers = true;
|
|
||||||
users.mutableUsers = false;
|
|
||||||
|
|
||||||
users.users.admin = {
|
|
||||||
isNormalUser = true;
|
|
||||||
extraGroups = [ "wheel" ];
|
|
||||||
hashedPasswordFile = config.sops.secrets.admin-password.path;
|
|
||||||
packages = with pkgs; [ tree vim tmux restic ];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
{ pkgs, pkgs-unstable, ... }:
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./hardware-configuration.nix
|
|
||||||
../common/core/default.nix
|
|
||||||
./user.nix
|
|
||||||
./work.nix
|
|
||||||
./sops.nix
|
|
||||||
./tailscale.nix
|
|
||||||
|
|
||||||
../common/optional/desktop/hyprland.nix
|
|
||||||
../common/optional/font.nix
|
|
||||||
../common/optional/yubikey.nix
|
|
||||||
../common/optional/browser.nix
|
|
||||||
../common/optional/locale.nix
|
|
||||||
../common/optional/email.nix
|
|
||||||
../common/optional/proton.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
# Use the systemd-boot EFI boot loader.
|
|
||||||
boot.loader.systemd-boot.enable = true;
|
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
|
||||||
|
|
||||||
boot.m1n1CustomLogo = ../../assets/logo.png;
|
|
||||||
|
|
||||||
hardware = {
|
|
||||||
asahi = {
|
|
||||||
peripheralFirmwareDirectory = ./firmware;
|
|
||||||
setupAsahiSound = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware.opengl = {
|
|
||||||
enable = true;
|
|
||||||
extraPackages = with pkgs; [
|
|
||||||
mesa.opencl
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.upower.enable = true;
|
|
||||||
services.logind.settings.Login.HandlePowerKey = "ignore";
|
|
||||||
|
|
||||||
networking.networkmanager = {
|
|
||||||
enable = true;
|
|
||||||
plugins = with pkgs; [
|
|
||||||
networkmanager-openconnect
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
hardware.bluetooth = {
|
|
||||||
enable = true;
|
|
||||||
powerOnBoot = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
environment.variables = {
|
|
||||||
XDG_DATA_HOME = "/home/max/.local/share";
|
|
||||||
GSK_RENDERER = "ngl";
|
|
||||||
EDITOR = "nvim";
|
|
||||||
};
|
|
||||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
|
||||||
|
|
||||||
programs.kdeconnect.enable = true;
|
|
||||||
|
|
||||||
environment.systemPackages = with pkgs; [
|
|
||||||
networkmanager
|
|
||||||
|
|
||||||
vim
|
|
||||||
git
|
|
||||||
wget
|
|
||||||
file
|
|
||||||
just
|
|
||||||
|
|
||||||
libreoffice-qt
|
|
||||||
|
|
||||||
pkgs-unstable.signal-desktop
|
|
||||||
pkgs-unstable.gurk-rs
|
|
||||||
|
|
||||||
gnupg
|
|
||||||
|
|
||||||
(pass.withExtensions (exts: [ exts.pass-otp ]))
|
|
||||||
|
|
||||||
pinentry-curses
|
|
||||||
pinentry-qt
|
|
||||||
|
|
||||||
fzf
|
|
||||||
zip
|
|
||||||
jq
|
|
||||||
ffmpeg
|
|
||||||
ripgrep
|
|
||||||
unzip
|
|
||||||
zbar
|
|
||||||
tt
|
|
||||||
sc-im
|
|
||||||
libqalculate
|
|
||||||
librespeed-cli
|
|
||||||
|
|
||||||
gparted
|
|
||||||
|
|
||||||
tea
|
|
||||||
|
|
||||||
cloudflared
|
|
||||||
# gcc
|
|
||||||
|
|
||||||
prismlauncher
|
|
||||||
|
|
||||||
gimp
|
|
||||||
inkscape
|
|
||||||
|
|
||||||
# arm support
|
|
||||||
pkgs-unstable.sparrow
|
|
||||||
|
|
||||||
|
|
||||||
(writeShellScriptBin "radio" ''
|
|
||||||
list="
|
|
||||||
WIOP http://s4.yesstreaming.net:7119/;audio.mp3
|
|
||||||
FamilyAlter https://usa17.fastcast4u.com/proxy/roloffev?mp=/1
|
|
||||||
"
|
|
||||||
|
|
||||||
choice=$(echo "$list" | awk '{print $1}' | ${fzf}/bin/fzf)
|
|
||||||
|
|
||||||
if [[ -n "$choice" ]]; then
|
|
||||||
url=$(echo "$list" | awk -v name="$choice" '$1==name {print $2}')
|
|
||||||
${mpg123}/bin/mpg123 "$url"
|
|
||||||
fi
|
|
||||||
'')
|
|
||||||
|
|
||||||
(pkgs.writeShellScriptBin "battery-graph" ''
|
|
||||||
${pkgs.coreutils}/bin/tail -n 20 /var/lib/upower/history-charge-bq40z651-69-F8Y3262H468Q1LTA1.dat | ${pkgs.coreutils}/bin/cut -f1,2 | RUBYOPT='-W0' ${pkgs.youplot}/bin/uplot line -w 70
|
|
||||||
'')
|
|
||||||
|
|
||||||
(pkgs.writeShellScriptBin "ocr-clip" ''
|
|
||||||
${pkgs.grimblast}/bin/grimblast -f save area - | ${pkgs.tesseract}/bin/tesseract stdin stdout | ${pkgs.wl-clipboard}/bin/wl-copy
|
|
||||||
'')
|
|
||||||
];
|
|
||||||
|
|
||||||
programs.zsh.enable = true;
|
|
||||||
|
|
||||||
programs.gnupg.agent = {
|
|
||||||
enable = true;
|
|
||||||
pinentryPackage = pkgs.pinentry-qt;
|
|
||||||
enableSSHSupport = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
system.stateVersion = "25.05";
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
{ ... }:
|
|
||||||
|
|
||||||
{
|
|
||||||
imports = [
|
|
||||||
./home/sops.nix
|
|
||||||
./home/ssh.nix
|
|
||||||
./home/git.nix
|
|
||||||
|
|
||||||
./home/browser.nix
|
|
||||||
./home/image-viewer.nix
|
|
||||||
|
|
||||||
../../home/common/optional/desktop/hyprland.nix
|
|
||||||
|
|
||||||
./home/nvim.nix
|
|
||||||
./home/terminal.nix
|
|
||||||
./home/zathura.nix
|
|
||||||
./home/music.nix
|
|
||||||
];
|
|
||||||
|
|
||||||
gtk = {
|
|
||||||
enable = true;
|
|
||||||
colorScheme = "dark";
|
|
||||||
};
|
|
||||||
|
|
||||||
home.username = "max";
|
|
||||||
home.homeDirectory = "/home/max";
|
|
||||||
home.stateVersion = "25.05";
|
|
||||||
}
|
|
||||||
9
justfile
@@ -29,7 +29,14 @@ rebuild-ark:
|
|||||||
just add-secrets
|
just add-secrets
|
||||||
|
|
||||||
git add .
|
git add .
|
||||||
nixos-rebuild --flake '.?submodules=1#ark' --build-host admin@192.168.1.192 --target-host admin@192.168.1.192 --use-remote-sudo --fast switch
|
nixos-rebuild --flake '.?submodules=1#koonArk' --build-host ark --target-host ark --use-remote-sudo --fast switch
|
||||||
|
|
||||||
|
|
||||||
|
rebuild-ark-boot:
|
||||||
|
just add-secrets
|
||||||
|
|
||||||
|
git add .
|
||||||
|
nixos-rebuild --flake '.?submodules=1#koonArk' --build-host ark --target-host ark --use-remote-sudo --fast boot
|
||||||
|
|
||||||
push-secrets:
|
push-secrets:
|
||||||
just add-secrets
|
just add-secrets
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{ self, ... }: {
|
{ self, ... }: {
|
||||||
flake.homeModules.commonFeatureWallpaper = { ... }:
|
flake.homeModules.commonFeatureWallpaper = { ... }:
|
||||||
let
|
let
|
||||||
wallpaper = builtins.toString "${self}/assets/wallpaper2.jpg";
|
wallpaper = builtins.toString "${self}/assets/wallpaper.jpg";
|
||||||
in {
|
in {
|
||||||
services.hyprpaper = {
|
services.hyprpaper = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
77
modules/koon/host/ark/configuration.nix
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
{ self, ... }: {
|
||||||
|
flake.nixosModules.koonArkConfiguration = { config, ... }: {
|
||||||
|
imports = [
|
||||||
|
./_hardware-configuration.nix
|
||||||
|
self.nixosModules.koonArkUser
|
||||||
|
self.nixosModules.koonArkSops
|
||||||
|
|
||||||
|
self.nixosModules.koonArkServiceAudio
|
||||||
|
self.nixosModules.koonArkServiceAuth
|
||||||
|
self.nixosModules.koonArkServiceGit
|
||||||
|
self.nixosModules.koonArkServiceHome
|
||||||
|
self.nixosModules.koonArkServicePhotos
|
||||||
|
self.nixosModules.koonArkServiceRadicale
|
||||||
|
self.nixosModules.koonArkServiceWakapi
|
||||||
|
];
|
||||||
|
|
||||||
|
# Use the systemd-boot EFI boot loader.
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
boot.loader.efi.canTouchEfiVariables = true;
|
||||||
|
|
||||||
|
networking.hostName = "ark";
|
||||||
|
networking.nameservers = [ "8.8.8.8" "1.1.1.1" ];
|
||||||
|
|
||||||
|
services.tailscale = {
|
||||||
|
enable = true;
|
||||||
|
useRoutingFeatures = "both";
|
||||||
|
extraUpFlags = [ "--accept-dns=false" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# oauth.name = "KoonFamily";
|
||||||
|
# oauth.secrets = import ./oauth-secrets.nix;
|
||||||
|
|
||||||
|
security.sudo.wheelNeedsPassword = false;
|
||||||
|
|
||||||
|
services.cloudflared = {
|
||||||
|
enable = true;
|
||||||
|
tunnels = {
|
||||||
|
"91d31395-fbc7-45a1-ae13-148957b32ecd" = {
|
||||||
|
credentialsFile = config.sops.secrets.tunnel-credentials.path;
|
||||||
|
ingress = {
|
||||||
|
"auth.koon.us" = "http://localhost:1411";
|
||||||
|
"photos.koon.us" = "http://localhost:2283";
|
||||||
|
"home.koon.us" = "http://localhost:8123";
|
||||||
|
"docs.koon.us" = "http://localhost:3004";
|
||||||
|
"git.koon.us" = "http://localhost:3000";
|
||||||
|
"ssh.koon.us" = "ssh://localhost:2222";
|
||||||
|
"audio.koon.us" = "http://localhost:8021";
|
||||||
|
"radicale.koon.us" = "http://localhost:5232";
|
||||||
|
"waka.koon.us" = "http://localhost:3006";
|
||||||
|
# "ride.koon.us" = "http://localhost:3007";
|
||||||
|
# "ride-api.koon.us" = "http://localhost:8080";
|
||||||
|
|
||||||
|
"money.koon.us" = "http://localhost:3160";
|
||||||
|
"zero.koon.us" = "http://localhost:4848";
|
||||||
|
"money-api.koon.us" = "http://localhost:3161";
|
||||||
|
|
||||||
|
};
|
||||||
|
default = "http_status:404";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fileSystems."/mnt/hdd" = {
|
||||||
|
device = "/dev/sdb";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.openssh.enable = true;
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 8123 22 ];
|
||||||
|
|
||||||
|
time.timeZone = "America/New_York";
|
||||||
|
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||||
|
|
||||||
|
system.stateVersion = "25.05"; # Did you read the comment?
|
||||||
|
};
|
||||||
|
}
|
||||||
8
modules/koon/host/ark/default.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ self, inputs, ... }: {
|
||||||
|
flake.nixosConfigurations.koonArk = inputs.nixpkgs-unstable.lib.nixosSystem {
|
||||||
|
modules = [
|
||||||
|
self.inputs.sops-nix.nixosModules.sops
|
||||||
|
self.nixosModules.koonArkConfiguration
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
||||||
8
modules/koon/host/ark/service/audio.nix
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceAudio = { ... }: {
|
||||||
|
services.audiobookshelf = {
|
||||||
|
enable = true;
|
||||||
|
port = 8021;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
21
modules/koon/host/ark/service/auth.nix
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceAuth = { config, ... }: {
|
||||||
|
services.pocket-id = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
APP_URL = "https://auth.koon.us";
|
||||||
|
TRUST_PROXY = true;
|
||||||
|
ANALYTICS_DISABLED = true;
|
||||||
|
|
||||||
|
UI_CONFIG_DISABLED = true;
|
||||||
|
|
||||||
|
APP_NAME = "KoonFamily";
|
||||||
|
};
|
||||||
|
|
||||||
|
credentials = {
|
||||||
|
ENCRYPTION_KEY = config.sops.secrets."pocket-id-encryption-key".path;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
193
modules/koon/host/ark/service/git.nix
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceGit = { config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
oauthName = "KoonFamily";
|
||||||
|
in {
|
||||||
|
services.openssh = {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# hostKeys = [
|
||||||
|
# { path = "/etc/ssh/ssh_host_ed25519_key"; type = "ed25519"; }
|
||||||
|
# { path = "/etc/ssh/ssh_host_rsa_key"; type = "rsa"; bits = 4096; }
|
||||||
|
# ];
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
# explicitly allow post-quantum KEX
|
||||||
|
KexAlgorithms = [
|
||||||
|
"mlkem768x25519-sha256"
|
||||||
|
"sntrup761x25519-sha512"
|
||||||
|
"curve25519-sha256"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.gitea = {
|
||||||
|
enable = true;
|
||||||
|
user = "git";
|
||||||
|
group = "git";
|
||||||
|
database = {
|
||||||
|
user = "git";
|
||||||
|
name = "git";
|
||||||
|
type = "postgres";
|
||||||
|
};
|
||||||
|
settings = {
|
||||||
|
server = {
|
||||||
|
DOMAIN = "git.koon.us";
|
||||||
|
ROOT_URL = "https://git.koon.us";
|
||||||
|
HTTP_PORT = 3000;
|
||||||
|
LANDING_PAGE = "/max";
|
||||||
|
SSH_DOMAIN = "ssh.koon.us";
|
||||||
|
SSH_PORT = 2222;
|
||||||
|
START_SSH_SERVER = true;
|
||||||
|
};
|
||||||
|
oauth2_client = {
|
||||||
|
ACCOUNT_LINKING = "auto";
|
||||||
|
ENABLE_AUTO_REGISTRATION = true;
|
||||||
|
UPDATE_AVATAR = true;
|
||||||
|
USERNAME = "email";
|
||||||
|
};
|
||||||
|
service = {
|
||||||
|
DISABLE_REGISTRATION = true;
|
||||||
|
ENABLE_PASSWORD_SIGNIN_FORM = false;
|
||||||
|
ENABLE_PASSKEY_AUTHENTICATION = false;
|
||||||
|
|
||||||
|
SHOW_MILESTONES_DASHBOARD_PAGE = false;
|
||||||
|
};
|
||||||
|
"service.explore" = {
|
||||||
|
DISABLE_USERS_PAGE = true;
|
||||||
|
DISABLE_ORGANIZATIONS_PAGE = true;
|
||||||
|
DISABLE_CODE_PAGE = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.git = {
|
||||||
|
isSystemUser = true;
|
||||||
|
group = "git";
|
||||||
|
home = "/var/lib/gitea";
|
||||||
|
description = "Git server (Gitea)";
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
users.groups.git = { };
|
||||||
|
|
||||||
|
systemd.services.gitea = {
|
||||||
|
serviceConfig = {
|
||||||
|
RestartSec = "60"; # Retry every minute
|
||||||
|
};
|
||||||
|
preStart = let
|
||||||
|
exe = lib.getExe config.services.gitea.package;
|
||||||
|
|
||||||
|
clientIdPath = config.sops.secrets."oauth/git/clientId".path;
|
||||||
|
clientSecretPath = config.sops.secrets."oauth/git/clientSecret".path;
|
||||||
|
|
||||||
|
args = lib.escapeShellArgs (lib.concatLists [
|
||||||
|
[ "--name" oauthName ]
|
||||||
|
[ "--provider" "openidConnect" ]
|
||||||
|
# [ "--key" config.oauth.secrets.git.clientId ]
|
||||||
|
[
|
||||||
|
"--auto-discover-url"
|
||||||
|
"https://auth.koon.us/.well-known/openid-configuration"
|
||||||
|
]
|
||||||
|
[ "--scopes" "email" ]
|
||||||
|
[ "--scopes" "profile" ]
|
||||||
|
[ "--group-claim-name" "groups" ]
|
||||||
|
[ "--admin-group" "admin" ]
|
||||||
|
[ "--skip-local-2fa" ]
|
||||||
|
]);
|
||||||
|
in lib.mkAfter ''
|
||||||
|
CLIENT_ID=$(cat ${clientIdPath})
|
||||||
|
CLIENT_SECRET=$(cat ${clientSecretPath})
|
||||||
|
|
||||||
|
provider_id=$(${exe} admin auth list | ${pkgs.gnugrep}/bin/grep -w '${oauthName}' | cut -f1)
|
||||||
|
|
||||||
|
if [[ -z "$provider_id" ]]; then
|
||||||
|
${exe} admin auth add-oauth ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
|
||||||
|
else
|
||||||
|
${exe} admin auth update-oauth --id "$provider_id" ${args} --key "$CLIENT_ID" --secret "$CLIENT_SECRET"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p /var/lib/gitea/custom/public/assets/img/
|
||||||
|
|
||||||
|
ln -sf ${
|
||||||
|
./git/assets/img/logo.svg
|
||||||
|
} /var/lib/gitea/custom/public/assets/img/logo.svg
|
||||||
|
ln -sf ${
|
||||||
|
./git/assets/img/favicon.svg
|
||||||
|
} /var/lib/gitea/custom/public/assets/img/favicon.svg
|
||||||
|
|
||||||
|
mkdir -p /var/lib/gitea/custom/templates/base/
|
||||||
|
ln -sf ${
|
||||||
|
./git/templates/base/head_navbar.tmpl
|
||||||
|
} /var/lib/gitea/custom/templates/base/head_navbar.tmpl
|
||||||
|
ln -sf ${
|
||||||
|
./git/templates/base/footer_content.tmpl
|
||||||
|
} /var/lib/gitea/custom/templates/base/footer_content.tmpl
|
||||||
|
|
||||||
|
mkdir -p /var/lib/gitea/custom/templates/custom/
|
||||||
|
ln -sf ${
|
||||||
|
./git/templates/custom/header.tmpl
|
||||||
|
} /var/lib/gitea/custom/templates/custom/header.tmpl
|
||||||
|
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups = {
|
||||||
|
git-local = {
|
||||||
|
repository = "/mnt/hdd/restic/git";
|
||||||
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
|
initialize = true;
|
||||||
|
paths = [ "/var/lib/gitea/repositories" "/var/backup/git" ];
|
||||||
|
backupPrepareCommand = ''
|
||||||
|
mkdir -p /var/backup/git
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--dbname=git > /var/backup/git/postgres.sql
|
||||||
|
'';
|
||||||
|
backupCleanupCommand = ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
git-remote = {
|
||||||
|
repository = "rest:http://m1:8000/git";
|
||||||
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
|
initialize = true;
|
||||||
|
paths = [ "/var/lib/gitea/repositories" "/var/backup/git" ];
|
||||||
|
backupPrepareCommand = ''
|
||||||
|
mkdir -p /var/backup/git
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--dbname=git > /var/backup/git/postgres.sql
|
||||||
|
'';
|
||||||
|
backupCleanupCommand = ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs;
|
||||||
|
let
|
||||||
|
scripts = with pkgs; {
|
||||||
|
restore_git_pg = writeShellScriptBin "restore_git_pg" ''
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres psql --dbname=git < /var/backup/git/postgres.sql
|
||||||
|
'';
|
||||||
|
restore_git = writeShellScriptBin "restore_git" ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop gitea
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/git restore latest --target /
|
||||||
|
|
||||||
|
${scripts.restore_git_pg}/bin/restore_git_pg
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start gitea
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in [ scripts.restore_git_pg scripts.restore_git ];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
|
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
38
modules/koon/host/ark/service/home.nix
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceHome = { pkgs, ... }: {
|
||||||
|
|
||||||
|
virtualisation.oci-containers = let
|
||||||
|
hass_config = pkgs.writeText "configuration.yaml" ''
|
||||||
|
# Discovery
|
||||||
|
default_config:
|
||||||
|
|
||||||
|
# Web Server configuration
|
||||||
|
http:
|
||||||
|
server_host: 127.0.0.1
|
||||||
|
use_x_forwarded_for: true
|
||||||
|
trusted_proxies: 127.0.0.1
|
||||||
|
sonos:
|
||||||
|
media_player:
|
||||||
|
hosts:
|
||||||
|
- 10.0.0.77
|
||||||
|
- 10.0.0.186
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
backend = "podman";
|
||||||
|
containers.homeassistant = {
|
||||||
|
volumes = [
|
||||||
|
"home-assistant:/config"
|
||||||
|
# "/data/docker/hass:/config"
|
||||||
|
"${hass_config}:/config/configuration.yaml"
|
||||||
|
# "/run/secrets/home-assistant:/config/secrets.yaml"
|
||||||
|
];
|
||||||
|
environment.TZ = "America/New_York";
|
||||||
|
image =
|
||||||
|
"ghcr.io/home-assistant/home-assistant:stable"; # Warning: if the tag does not change, the image will not be updated
|
||||||
|
extraOptions = [ "--network=host" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall.allowedTCPPorts = [ 1400 ];
|
||||||
|
};
|
||||||
|
}
|
||||||
123
modules/koon/host/ark/service/photos.nix
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServicePhotos = { config, lib, pkgs, ... }:
|
||||||
|
let
|
||||||
|
oauthName = "KoonFamily";
|
||||||
|
in {
|
||||||
|
sops = {
|
||||||
|
templates = {
|
||||||
|
"immich-config.json" = {
|
||||||
|
content = builtins.toJSON {
|
||||||
|
passwordLogin.enabled = false;
|
||||||
|
|
||||||
|
# We will do this ourselves
|
||||||
|
backup.database.enabled = false;
|
||||||
|
|
||||||
|
oauth = {
|
||||||
|
enabled = true;
|
||||||
|
autoLaunch = true;
|
||||||
|
autoRegister = true;
|
||||||
|
buttonText =
|
||||||
|
lib.strings.concatStrings [ "Login To " oauthName ];
|
||||||
|
clientId = config.sops.placeholder."oauth/photos/clientId";
|
||||||
|
clientSecret = config.sops.placeholder."oauth/photos/clientSecret";
|
||||||
|
issuerUrl = "https://auth.koon.us/.well-known/openid-configuration";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
owner = config.users.users.immich.name;
|
||||||
|
mode = "0400";
|
||||||
|
restartUnits = [ "immich-server.service" "pocket-id.service" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.immich = {
|
||||||
|
enable = true;
|
||||||
|
port = 2283;
|
||||||
|
environment.IMMICH_CONFIG_FILE = config.sops.templates."immich-config.json".path;
|
||||||
|
accelerationDevices = null;
|
||||||
|
|
||||||
|
machine-learning.environment = {
|
||||||
|
HF_XET_CACHE = "/var/cache/immich/huggingface-xet";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.immich = {
|
||||||
|
home = "/var/lib/immich";
|
||||||
|
createHome = true;
|
||||||
|
extraGroups = [ "video" "render" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
hardware.graphics = {
|
||||||
|
enable = true;
|
||||||
|
extraPackages = with pkgs; [ intel-media-driver ];
|
||||||
|
};
|
||||||
|
environment.sessionVariables = { LIBVA_DRIVER_NAME = "iHD"; };
|
||||||
|
|
||||||
|
services.restic.backups = {
|
||||||
|
immich-local = {
|
||||||
|
repository = "/mnt/hdd/restic/immich";
|
||||||
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
|
initialize = true;
|
||||||
|
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
|
||||||
|
backupPrepareCommand = ''
|
||||||
|
mkdir -p /var/backup/immich
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--dbname=immich > /var/backup/immich/postgres.sql
|
||||||
|
'';
|
||||||
|
backupCleanupCommand = ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
immich-remote = {
|
||||||
|
repository = "rest:http://m1:8000/immich";
|
||||||
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
|
initialize = true;
|
||||||
|
paths = [ "/var/lib/immich/upload" "/var/backup/immich" ];
|
||||||
|
backupPrepareCommand = ''
|
||||||
|
mkdir -p /var/backup/immich
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres ${pkgs.postgresql}/bin/pg_dump \
|
||||||
|
--clean \
|
||||||
|
--if-exists \
|
||||||
|
--dbname=immich > /var/backup/immich/postgres.sql
|
||||||
|
'';
|
||||||
|
backupCleanupCommand = ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.systemPackages = with pkgs;
|
||||||
|
let
|
||||||
|
scripts = with pkgs; {
|
||||||
|
restore_immich_pg = writeShellScriptBin "restore_immich_pg" ''
|
||||||
|
${pkgs.sudo}/bin/sudo -u postgres psql --dbname=immich < /var/backup/immich/postgres.sql
|
||||||
|
'';
|
||||||
|
restore_immich = writeShellScriptBin "restore_immich" ''
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl stop immich-machine-learning
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${restic}/bin/restic -r /mnt/hdd/restic/immich restore latest --target /
|
||||||
|
|
||||||
|
${scripts.restore_immich_pg}/bin/restore_immich_pg
|
||||||
|
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-server
|
||||||
|
${pkgs.sudo}/bin/sudo ${pkgs.systemd}/bin/systemctl start immich-machine-learning
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in [ scripts.restore_immich_pg scripts.restore_immich ];
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
11
modules/koon/host/ark/service/radicale.nix
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceRadicale = { ... }: {
|
||||||
|
services.radicale = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
auth.type = "none";
|
||||||
|
server.hosts = [ "0.0.0.0:5232" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
50
modules/koon/host/ark/service/wakapi.nix
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkServiceWakapi = { config, ... }: {
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(final: prev: let
|
||||||
|
version = "2.15.0";
|
||||||
|
in {
|
||||||
|
|
||||||
|
wakapi = (prev.buildGoModule.override { go = prev.go_1_25; }) {
|
||||||
|
pname = "wakapi";
|
||||||
|
version = version;
|
||||||
|
|
||||||
|
src = final.fetchFromGitHub {
|
||||||
|
owner = "k2on";
|
||||||
|
repo = "wakapi";
|
||||||
|
rev = "koon-fork";
|
||||||
|
hash = "sha256-FYGtoJmbqUD02/JKvON1RqpjkrDkAOkfPwMAUZ2MSE4=";
|
||||||
|
};
|
||||||
|
|
||||||
|
vendorHash = "sha256-912x6LwitYXdjWpP75Xoc56JXadeLQZuESSyLoaJcU0=";
|
||||||
|
|
||||||
|
excludedPackages = [ "scripts" ];
|
||||||
|
|
||||||
|
postPatch = ''echo ${version} > version.txt'';
|
||||||
|
|
||||||
|
ldflags = [ "-s" "-w" ];
|
||||||
|
|
||||||
|
passthru = {
|
||||||
|
nixos = prev.nixosTests.wakapi;
|
||||||
|
updateScript = prev.nix-update-script { };
|
||||||
|
};
|
||||||
|
|
||||||
|
meta = prev.wakapi.meta // {
|
||||||
|
version = version;
|
||||||
|
mainProgram = "wakapi";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
services.wakapi = {
|
||||||
|
enable = true;
|
||||||
|
# passwordSaltFile = config.sops.secrets."waka-password-salt".path;
|
||||||
|
settings = {
|
||||||
|
server.port = 3006;
|
||||||
|
app.avatar_url_template = "https://auth.koon.us/api/users/fbffa48a-faf7-4230-a89f-0da184f5948c/profile-picture.png";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
34
modules/koon/host/ark/sops.nix
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{ self, ... }: {
|
||||||
|
flake.nixosModules.koonArkSops = { config, ... }: {
|
||||||
|
sops = {
|
||||||
|
age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
||||||
|
|
||||||
|
defaultSopsFile = "${self}/secrets/koon/ark/default.yaml";
|
||||||
|
|
||||||
|
validateSopsFiles = false;
|
||||||
|
|
||||||
|
secrets = {
|
||||||
|
"restic-password" = {};
|
||||||
|
"tunnel-credentials" = {};
|
||||||
|
"admin-password" = {};
|
||||||
|
|
||||||
|
"pocket-id-encryption-key" = {
|
||||||
|
owner = config.services.pocket-id.user;
|
||||||
|
};
|
||||||
|
|
||||||
|
"waka-password-salt" = {
|
||||||
|
owner = config.users.users.wakapi.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
"oauth/photos/clientId" = {};
|
||||||
|
"oauth/photos/clientSecret" = {};
|
||||||
|
"oauth/git/clientId" = {
|
||||||
|
owner = config.services.gitea.user;
|
||||||
|
};
|
||||||
|
"oauth/git/clientSecret" = {
|
||||||
|
owner = config.services.gitea.user;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
13
modules/koon/host/ark/user.nix
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{ ... }: {
|
||||||
|
flake.nixosModules.koonArkUser = { pkgs, config, ... }: {
|
||||||
|
sops.secrets.admin-password.neededForUsers = true;
|
||||||
|
users.mutableUsers = false;
|
||||||
|
|
||||||
|
users.users.admin = {
|
||||||
|
isNormalUser = true;
|
||||||
|
extraGroups = [ "wheel" ];
|
||||||
|
hashedPasswordFile = config.sops.secrets.admin-password.path;
|
||||||
|
packages = with pkgs; [ tree vim tmux restic ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -8,4 +8,3 @@
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||