Compare commits
91 Commits
f8378354fb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 383c7bb15e | |||
| a4bb91e68e | |||
| 13f301c4fb | |||
| 114a1ae125 | |||
| 9a4ab98506 | |||
| bf0d4a11d2 | |||
| 0950758532 | |||
| 31907ff47b | |||
| a985e8a0da | |||
| 8add79d14c | |||
| 93523c54f2 | |||
| c07dfe4259 | |||
| 978b7ac2b7 | |||
| d1ccaa1c57 | |||
| 1c098a032b | |||
| b951779a92 | |||
| 889d0b1057 | |||
| 64cac2b167 | |||
| 2f278b5ecb | |||
| a0448def04 | |||
| edb0f18989 | |||
| cfde735570 | |||
| 9bbb4aa2dc | |||
| 9818771f7c | |||
| f7af96c497 | |||
| 499b0f4334 | |||
| 879ad11d96 | |||
| 640eaec8a1 | |||
| 898e1bdde0 | |||
| a6d4c40beb | |||
| a13e8cea19 | |||
| 3b8e38e702 | |||
| 05c001081e | |||
| 3e2e3aca21 | |||
| 1837a545a4 | |||
| 5c7649d3df | |||
| 3bb9ebf875 | |||
| ee3b7c2c53 | |||
| 746e31dca2 | |||
| 9a59e60044 | |||
| 646221721e | |||
| 554b2863f3 | |||
| 5829dc294e | |||
| 0645912626 | |||
| 430a041724 | |||
| 80512c29ea | |||
| 392d6fe537 | |||
| 6d1e715d9c | |||
| 94b8065dba | |||
| ea902faf43 | |||
| 3d3fa1ed68 | |||
| cd4367e252 | |||
| cf4d54ebfd | |||
| 3b46856b66 | |||
| 1d1702bd9b | |||
| 8a566715db | |||
| 19d8c5c097 | |||
| b3c6e951ee | |||
| 44ac6ce262 | |||
| 1c2cd59f1f | |||
| ca4d4d714c | |||
| 8791432964 | |||
| 638f34c2d3 | |||
| 743ce58b14 | |||
| 0a1d7a24e7 | |||
| 81cb09176c | |||
| 7f04c3aa4c | |||
| bded723261 | |||
| 0776b9d7e5 | |||
| 0ac07e4256 | |||
| cedf51580e | |||
| 1dc7d7b355 | |||
| b1510c3670 | |||
| f4dd4583db | |||
| c74e40e69e | |||
| 514746686f | |||
| 286701ba83 | |||
| 1bfec397b5 | |||
| 84d05be93b | |||
| 03b3fe16b1 | |||
| cda32ea550 | |||
| 32e10284d0 | |||
| b9c439f5a9 | |||
| 449662db8c | |||
| 6601377ece | |||
| d432ef8014 | |||
| 9acaae9277 | |||
| f46c5948e5 | |||
| 1d94f2574c | |||
| 0a64c5cd4b | |||
| 2f44b67e9e |
60
flake.lock
generated
60
flake.lock
generated
@@ -7,68 +7,32 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748226808,
|
||||
"narHash": "sha256-GaBRgxjWO1bAQa8P2+FDxG4ANBVhjnSjBms096qQdxo=",
|
||||
"lastModified": 1767910483,
|
||||
"narHash": "sha256-MOU5YdVu4DVwuT5ztXgQpPuRRBjSjUGIdUzOQr9iQOY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "83665c39fa688bd6a1f7c43cf7997a70f6a109f9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.05",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"home-manager-unstable": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-unstable"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1748227609,
|
||||
"narHash": "sha256-SaSdslyo6UGDpPUlmrPA4dWOEuxCy2ihRN9K6BnqYsA=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "d23d20f55d49d8818ac1f1b2783671e8a6725022",
|
||||
"rev": "82fb7dedaad83e5e279127a38ef410bcfac6d77c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"ref": "release-25.11",
|
||||
"repo": "home-manager",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1748162331,
|
||||
"narHash": "sha256-rqc2RKYTxP3tbjA+PB3VMRQNnjesrT0pEofXQTrMsS8=",
|
||||
"lastModified": 1767799921,
|
||||
"narHash": "sha256-r4GVX+FToWVE2My8VVZH4V0pTIpnu2ZE8/Z4uxGEMBE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "7c43f080a7f28b2774f3b3f43234ca11661bf334",
|
||||
"rev": "d351d0653aeb7877273920cd3e823994e7579b0b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-25.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1748190013,
|
||||
"narHash": "sha256-R5HJFflOfsP5FBtk+zE8FpL8uqE7n62jqOsADvVshhE=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "62b852f6c6742134ade1abdd2a21685fd617a291",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"ref": "nixos-25.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
@@ -76,9 +40,7 @@
|
||||
"root": {
|
||||
"inputs": {
|
||||
"home-manager": "home-manager",
|
||||
"home-manager-unstable": "home-manager-unstable",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-unstable": "nixpkgs-unstable",
|
||||
"sops-nix": "sops-nix"
|
||||
}
|
||||
},
|
||||
@@ -89,11 +51,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1747603214,
|
||||
"narHash": "sha256-lAblXm0VwifYCJ/ILPXJwlz0qNY07DDYdLD+9H+Wc8o=",
|
||||
"lastModified": 1767826491,
|
||||
"narHash": "sha256-WSBENPotD2MIhZwolL6GC9npqgaS5fkM7j07V2i/Ur8=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "8d215e1c981be3aa37e47aeabd4e61bb069548fd",
|
||||
"rev": "ea3adcb6d2a000d9a69d0e23cad1f2cacb3a9fbe",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
29
flake.nix
29
flake.nix
@@ -2,20 +2,11 @@
|
||||
description = "System Configuration";
|
||||
|
||||
inputs = {
|
||||
nixpkgs = {
|
||||
url = "github:nixos/nixpkgs?ref=nixos-25.05";
|
||||
};
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-25.11";
|
||||
home-manager = {
|
||||
url = "github:nix-community/home-manager?ref=release-25.05";
|
||||
url = "github:nix-community/home-manager?ref=release-25.11";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
nixpkgs-unstable = {
|
||||
url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
home-manager-unstable = {
|
||||
url = "github:nix-community/home-manager";
|
||||
inputs.nixpkgs.follows = "nixpkgs-unstable";
|
||||
};
|
||||
sops-nix = {
|
||||
url = "github:Mic92/sops-nix";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
@@ -23,7 +14,11 @@
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs, ... }@inputs:
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
local = import ./lib;
|
||||
mkNixosConfig =
|
||||
@@ -38,11 +33,13 @@
|
||||
modules = [
|
||||
home-manager.nixosModules.home-manager
|
||||
{
|
||||
home-manager.useGlobalPkgs = true;
|
||||
home-manager.useUserPackages = true;
|
||||
home-manager.extraSpecialArgs = {
|
||||
home-manager = {
|
||||
useGlobalPkgs = true;
|
||||
useUserPackages = true;
|
||||
extraSpecialArgs = {
|
||||
inherit inputs local;
|
||||
};
|
||||
};
|
||||
}
|
||||
path
|
||||
];
|
||||
@@ -64,7 +61,7 @@
|
||||
};
|
||||
};
|
||||
features = {
|
||||
development = (import ./home-manager/features/development/development.nix);
|
||||
development = import ./home-manager/features/development/development.nix;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,11 @@
|
||||
discord = {
|
||||
name = "Discord";
|
||||
# Custom options to reduce flickering under wayland.
|
||||
exec = "discord --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu";
|
||||
exec = "env ELECTRON_OZONE_PLATFORM_HINT= discord --enable-features=UseOzonePlatform --ozone-platform=wayland --disable-gpu";
|
||||
};
|
||||
};
|
||||
wayland.windowManager.hyprland.settings.bind = [
|
||||
# Pass Mouse4 through to discord
|
||||
# ", mouse:275, pass, class:^discord$"
|
||||
];
|
||||
}
|
||||
|
||||
64
home-manager/features/3d-printing.nix
Normal file
64
home-manager/features/3d-printing.nix
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
let
|
||||
freecad-wrapped = pkgs.symlinkJoin {
|
||||
name = "freecad-wrapped";
|
||||
paths = [ pkgs.freecad ];
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/freecad \
|
||||
--prefix MESA_LOADER_DRIVER_OVERRIDE : zink \
|
||||
--prefix __EGL_VENDOR_LIBRARY_FILENAMES : ${pkgs.mesa}/share/glvnd/egl_vendor.d/50_mesa.json
|
||||
'';
|
||||
};
|
||||
|
||||
bambu-studio-wrapped = pkgs.symlinkJoin {
|
||||
name = "bambu-studio-wrapped";
|
||||
paths = [ pkgs.bambu-studio ];
|
||||
buildInputs = [ pkgs.makeWrapper ];
|
||||
postBuild = ''
|
||||
wrapProgram $out/bin/bambu-studio \
|
||||
--prefix MESA_LOADER_DRIVER_OVERRIDE : zink \
|
||||
--prefix __EGL_VENDOR_LIBRARY_FILENAMES : ${pkgs.mesa}/share/glvnd/egl_vendor.d/50_mesa.json
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
|
||||
home.packages = with pkgs; [
|
||||
bambu-studio-wrapped
|
||||
LycheeSlicer
|
||||
orca-slicer
|
||||
|
||||
blender
|
||||
|
||||
freecad-wrapped
|
||||
openscad
|
||||
];
|
||||
|
||||
xdg.desktopEntries.orynt3d =
|
||||
let
|
||||
orynt3d-appimage = pkgs.fetchurl {
|
||||
name = "orynt3d-appimage";
|
||||
url = "https://files.orynt3d.com/client/Orynt3D-0.15.3.AppImage";
|
||||
sha256 = "0j10myj06ff4frsd4yv7z3lb3qgw3ha70hc5hdc9idbryica801y";
|
||||
};
|
||||
in
|
||||
{
|
||||
name = "Orynt3D";
|
||||
exec = "env __EGL_VENDOR_LIBRARY_FILENAMES=/run/opengl-driver/share/glvnd/egl_vendor.d/10_nvidia.json ${pkgs.appimage-run}/bin/appimage-run ${orynt3d-appimage}";
|
||||
terminal = false;
|
||||
type = "Application";
|
||||
# icon = "";
|
||||
comment = "3D model viewer and organizer";
|
||||
categories = [
|
||||
"Science"
|
||||
"Development"
|
||||
];
|
||||
};
|
||||
|
||||
# Options to get Bambu Studio to run:
|
||||
# __GLX_VENDOR_LIBRARY_NAME=mesa __EGL_VENDOR_LIBRARY_FILENAMES=/nix/store/js9cfbjvlsls14nddk39fw74vyvlhz4l-mesa-25.0.7/share/glvnd/egl_vendor.d/50_mesa.json MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink WEBKIT_DISABLE_DMABUF_RENDERER=1 bambu-studio
|
||||
}
|
||||
8
home-manager/features/astronomy.nix
Normal file
8
home-manager/features/astronomy.nix
Normal file
@@ -0,0 +1,8 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
stellarium
|
||||
kstars
|
||||
celestia
|
||||
];
|
||||
}
|
||||
@@ -1,7 +1,41 @@
|
||||
{ pkgs, ... }:
|
||||
with pkgs;
|
||||
let
|
||||
# A script that runs as long as media is playing.
|
||||
isMediaPlaying = writeShellApplication {
|
||||
name = "isMediaPlaying";
|
||||
runtimeInputs = [
|
||||
playerctl
|
||||
];
|
||||
text = ''
|
||||
set -e
|
||||
|
||||
while [ "$(playerctl status)" = "Playing" ]; do
|
||||
echo -n "."
|
||||
sleep 1
|
||||
done
|
||||
'';
|
||||
};
|
||||
# A script that prevents the system from going to sleep while media is playing
|
||||
mediaCaffeine = writeShellApplication {
|
||||
name = "media-caffeine";
|
||||
runtimeInputs = [
|
||||
isMediaPlaying
|
||||
systemd
|
||||
];
|
||||
text = ''
|
||||
set -e
|
||||
|
||||
systemd-inhibit --what=sleep --why="Media is playing" --mode=block isMediaPlaying
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
pulseaudio # for pactl and other tools
|
||||
pavucontrol # GUI volume control with lots of options
|
||||
|
||||
mediaCaffeine
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
11
home-manager/features/chat.nix
Normal file
11
home-manager/features/chat.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
../apps/element.nix
|
||||
../apps/discord.nix
|
||||
];
|
||||
|
||||
home.packages = with pkgs; [
|
||||
signal-desktop
|
||||
];
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
nixfmt-rfc-style # Formatter
|
||||
nil # Language Server
|
||||
statix # Lints and suggestions for Nix
|
||||
];
|
||||
|
||||
home.shellAliases = {
|
||||
@@ -14,4 +15,3 @@
|
||||
rebuild-boot = "sudo nixos-rebuild boot --flake ~/system-config --show-trace --print-build-logs --verbose";
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,4 @@
|
||||
(include "./primary-statusbar.yuck")
|
||||
(include "./secondary-statusbar.yuck")
|
||||
(include "./system-monitor.yuck")
|
||||
(include "./launcher.yuck")
|
||||
(include "./vertical-statusbar.yuck")
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
(defwindow launcher
|
||||
:monitor '[ "<primary>", "DP-2", 0 ]'
|
||||
:geometry (geometry
|
||||
:x "100px"
|
||||
:y "100px"
|
||||
:anchor "top left"
|
||||
)
|
||||
:stacking "bottom"
|
||||
:exclusive false
|
||||
:focusable false
|
||||
(box
|
||||
:class "launcher-window stand-alone"
|
||||
:orientation "v"
|
||||
:spacing 4
|
||||
:visible { arraylength(jq(workspaces-json-dp2, "map(select(.active and (.has_windows | not)))")) > 0 }
|
||||
(box
|
||||
:orientation "v"
|
||||
:halign "start"
|
||||
:spacing 4
|
||||
:space-evenly false
|
||||
(label
|
||||
:text "Apps"
|
||||
:halign "start"
|
||||
)
|
||||
(box
|
||||
:orientation "h"
|
||||
:halign "start"
|
||||
:spacing 4
|
||||
:space-evenly false
|
||||
(button
|
||||
:onclick "firefox"
|
||||
(image
|
||||
:class "launcher-icon"
|
||||
:icon "firefox"
|
||||
:icon-size "dialog"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
(box
|
||||
:orientation "v"
|
||||
:halign "start"
|
||||
:spacing 4
|
||||
:space-evenly false
|
||||
(label
|
||||
:text "Games"
|
||||
:halign "start"
|
||||
)
|
||||
(box
|
||||
:orientation "h"
|
||||
:halign "start"
|
||||
:spacing 4
|
||||
:space-evenly false
|
||||
(button
|
||||
;; :onclick "env LUTRIS_SKIP_INIT=1 lutris lutris:rungameid/1"
|
||||
:onclick "/home/drew/.local/bin/wow.sh >/tmp/wow.log 2>&1"
|
||||
(image
|
||||
:class "launcher-icon"
|
||||
:image-width 48
|
||||
:path "/home/drew/.local/share/icons/hicolor/128x128/apps/lutris_battlenet.png"
|
||||
)
|
||||
)
|
||||
;; (button
|
||||
;; :onclick "steam steam://rungameid/1145350"
|
||||
;; (image
|
||||
;; :class "launcher-icon"
|
||||
;; :icon "steam_icon_1145350"
|
||||
;; :icon-size "dialog"
|
||||
;; )
|
||||
;;)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -45,7 +45,7 @@
|
||||
(system-monitor-perf-gpu)
|
||||
)
|
||||
(disks-vega)
|
||||
(system-monitor-net :interface "enp3s0")
|
||||
(system-monitor-net :interface "wlp5s0")
|
||||
(system-monitor-audio)
|
||||
)
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@ let
|
||||
# '';
|
||||
warcraftLogsUploader = pkgs.fetchurl {
|
||||
name = "warcraftlogs-client";
|
||||
url = "https://github.com/RPGLogs/Uploaders-warcraftlogs/releases/download/v8.16.56/warcraftlogs-v8.16.56.AppImage";
|
||||
url = "https://github.com/RPGLogs/Uploaders-warcraftlogs/releases/download/v8.17.47/warcraftlogs-v8.17.47.AppImage";
|
||||
sha256 = "1aypr3ffy6lq0qj64d48c7n54nfs72404xb2kpxsw5slqh66imw6";
|
||||
};
|
||||
warcraftLogsIcon = pkgs.fetchurl {
|
||||
@@ -27,7 +27,7 @@ let
|
||||
raiderioClient = pkgs.fetchurl {
|
||||
name = "raiderio-client";
|
||||
url = "https://raider.io/client/download/linux";
|
||||
sha256 = "1iny8zhp12x40mnxxr7p6kbyyvxf16373d2qa8idxs3hw5fz7gnx";
|
||||
sha256 = "0wcw53bgr9dr02x1ci2jlnc5irpiqxqxgs2hpbrsnj67q50nvlm9";
|
||||
};
|
||||
raiderioIcon = pkgs.fetchurl {
|
||||
name = "raiderio-icon";
|
||||
@@ -47,10 +47,14 @@ in
|
||||
})
|
||||
protonup-ng
|
||||
protonplus
|
||||
protontricks
|
||||
vulkan-tools # useful for debugging Vulkan issues
|
||||
|
||||
# WoW addon updater
|
||||
wowup-cf
|
||||
|
||||
# Nexus Mod Manager
|
||||
nexusmods-app-unfree
|
||||
];
|
||||
|
||||
# xdg.dataFile."applications/wowup-cf.desktop" = {
|
||||
@@ -81,7 +85,7 @@ in
|
||||
categories = [ "Game" ];
|
||||
};
|
||||
|
||||
xdg.desktopEntries.raiderio = local.electronDesktopEntry {
|
||||
xdg.desktopEntries.raiderio = {
|
||||
name = "Raider.io";
|
||||
exec = "${pkgs.appimage-run}/bin/appimage-run ${raiderioClient}";
|
||||
terminal = false;
|
||||
@@ -100,11 +104,16 @@ in
|
||||
|
||||
# Make sure WoW spawns on the right monitor and that Battlenet floats so it renders correctly
|
||||
"monitor 1,title:^World of Warcraft$"
|
||||
"fullscreen,title:^World of Warcraft$"
|
||||
"monitor 1,title:^Battle.net$"
|
||||
"float,title:^Battle.net$"
|
||||
|
||||
# Make Balatro into a regular window.
|
||||
"monitor 1,title:^Balatro$"
|
||||
"tile,title:^Balatro$"
|
||||
|
||||
# Load Cyberpunk 2077 on the right monitor.
|
||||
"monitor 1,class:steam_app_1091500"
|
||||
"fullscreen,class:steam_app_1091500"
|
||||
];
|
||||
}
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
|
||||
listener = [
|
||||
{
|
||||
timeout = 150; # 2.5min.
|
||||
timeout = 300; # 5min
|
||||
on-timeout = "brightnessctl -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor.
|
||||
on-resume = "brightnessctl -r"; # monitor backlight restore.
|
||||
}
|
||||
{
|
||||
timeout = 300; # 5min
|
||||
timeout = 330; # 5.5 min
|
||||
on-timeout = "loginctl lock-session"; # lock screen when timeout has passed
|
||||
}
|
||||
{
|
||||
timeout = 330; # 5.5min
|
||||
timeout = 600; # 10 min
|
||||
on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed
|
||||
on-resume = "hyprctl dispatch dpms on && brightnessctl -r"; # screen on when activity is detected after timeout has fired.
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
|
||||
"$terminal" = "foot";
|
||||
"$menu" = "rofi -show combi -combi-modes drun,ssh,run -theme ~/.config/rofi/launcher/style.rasi";
|
||||
"$browser" = "firefox";
|
||||
"$browser" = "firefox --new-window";
|
||||
|
||||
exec-once = [
|
||||
"nm-applet"
|
||||
@@ -287,6 +287,7 @@
|
||||
"$mainMod, B, exec, $browser"
|
||||
"$mainMod, D, exec, $menu"
|
||||
"$mainMod + SHIFT, S, exec, hyprshot -m region --clipboard-only"
|
||||
"$mainMod + CTRL + SHIFT, S, exec, hyprshot -m region -o ~/Pictures"
|
||||
"$mainMod, C, exec, swaync-client -t"
|
||||
|
||||
"$mainMod + L_CONTROL, Q, exec, /home/drew/.config/rofi/powermenu/powermenu.sh"
|
||||
|
||||
7
home-manager/features/image-editing.nix
Normal file
7
home-manager/features/image-editing.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
gimp3
|
||||
inkscape
|
||||
];
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
home = {
|
||||
packages = with pkgs; [
|
||||
# Desktop Applications
|
||||
signal-desktop
|
||||
gimp3
|
||||
|
||||
# Common utilities
|
||||
feh
|
||||
@@ -50,8 +50,8 @@
|
||||
programs = {
|
||||
# browsers
|
||||
firefox.enable = true;
|
||||
qutebrowser.enable = true;
|
||||
librewolf.enable = true;
|
||||
chromium.enable = true;
|
||||
};
|
||||
|
||||
# GTK settings
|
||||
@@ -83,4 +83,18 @@
|
||||
platformTheme.name = "adwaita";
|
||||
style.name = "adwaita-dark";
|
||||
};
|
||||
|
||||
# Default apps
|
||||
xdg.mimeApps = {
|
||||
enable = true;
|
||||
defaultApplications = {
|
||||
"text/html" = [ "firefox.desktop" ];
|
||||
"default-web-browser" = [ "firefox.desktop" ];
|
||||
"x-scheme-handler/http" = [ "firefox.desktop" ];
|
||||
"x-scheme-handler/https" = [ "firefox.desktop" ];
|
||||
"x-scheme-handler/about" = [ "firefox.desktop" ];
|
||||
"x-scheme-handler/unknown" = [ "firefox.desktop" ];
|
||||
};
|
||||
};
|
||||
home.sessionVariables.DEFAULT_BROWSER = "${pkgs.firefox}/bin/firefox";
|
||||
}
|
||||
|
||||
18
home-manager/features/neovim/config/lazyvim.json
Normal file
18
home-manager/features/neovim/config/lazyvim.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extras": [
|
||||
"lazyvim.plugins.extras.coding.mini-comment",
|
||||
"lazyvim.plugins.extras.coding.mini-surround",
|
||||
"lazyvim.plugins.extras.editor.snacks_picker",
|
||||
"lazyvim.plugins.extras.lang.astro",
|
||||
"lazyvim.plugins.extras.lang.haskell",
|
||||
"lazyvim.plugins.extras.lang.json",
|
||||
"lazyvim.plugins.extras.lang.markdown",
|
||||
"lazyvim.plugins.extras.lang.nix",
|
||||
"lazyvim.plugins.extras.lang.rust",
|
||||
"lazyvim.plugins.extras.lang.tailwind",
|
||||
"lazyvim.plugins.extras.lang.toml",
|
||||
"lazyvim.plugins.extras.lang.typescript"
|
||||
],
|
||||
"install_version": 8,
|
||||
"version": 8
|
||||
}
|
||||
@@ -4,3 +4,6 @@
|
||||
|
||||
-- Creates a shortcut for adding the directory of the current buffer when specifying a file
|
||||
vim.cmd("cnoreabbrev %. %:h<Tab>")
|
||||
|
||||
-- Set snacks as the preferred picker.
|
||||
vim.g.lazyvim_picker = "snacks"
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
return {
|
||||
"augmentcode/augment.vim",
|
||||
enable = true,
|
||||
}
|
||||
@@ -31,7 +31,7 @@ return {
|
||||
cmp.show()
|
||||
end,
|
||||
},
|
||||
["<C-enter>"] = { "select_and_accept" },
|
||||
["<Tab>"] = { "select_and_accept", "snippet_forward", "fallback" },
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
return {
|
||||
{
|
||||
"zbirenbaum/copilot.lua",
|
||||
opts = {
|
||||
filetypes = {
|
||||
markdown = false,
|
||||
help = false,
|
||||
},
|
||||
suggestion = {
|
||||
enabled = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
return {
|
||||
-- Maeson installs it's own binaries that are incompatible with NixOS.
|
||||
{ "williamboman/mason.nvim", enabled = false },
|
||||
{ "williamboman/mason-lspconfig.nvim", enabled = false },
|
||||
{ "mason-org/mason.nvim", enabled = false },
|
||||
{ "mason-org/mason-lspconfig.nvim", enabled = false },
|
||||
}
|
||||
|
||||
@@ -3,9 +3,14 @@ return {
|
||||
"neovim/nvim-lspconfig",
|
||||
opts = {
|
||||
servers = {
|
||||
-- Lua
|
||||
lua_ls = {},
|
||||
-- Nix
|
||||
nil_ls = {},
|
||||
-- Typescript
|
||||
vtsls = {},
|
||||
-- Haskell
|
||||
hls = {},
|
||||
},
|
||||
codelens = {
|
||||
enable = true,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
-- https://github.com/MeanderingProgrammer/render-markdown.nvim?tab=readme-ov-file#setup
|
||||
return {
|
||||
"MeanderingProgrammer/render-markdown.nvim",
|
||||
opts = {
|
||||
|
||||
@@ -1,10 +1,38 @@
|
||||
return {
|
||||
{
|
||||
"echasnovski/mini.surround",
|
||||
"nvim-mini/mini.surround",
|
||||
enable = true,
|
||||
keys = function(_, keys)
|
||||
-- Populate the keys based on the user's options
|
||||
local opts = LazyVim.opts("mini.surround")
|
||||
local mappings = {
|
||||
{ opts.mappings.add, desc = "Add Surrounding", mode = { "n", "v" } },
|
||||
{ opts.mappings.delete, desc = "Delete Surrounding" },
|
||||
{ opts.mappings.find, desc = "Find Right Surrounding" },
|
||||
{ opts.mappings.find_left, desc = "Find Left Surrounding" },
|
||||
{ opts.mappings.highlight, desc = "Highlight Surrounding" },
|
||||
{ opts.mappings.replace, desc = "Replace Surrounding" },
|
||||
{ opts.mappings.update_n_lines, desc = "Update `MiniSurround.config.n_lines`" },
|
||||
}
|
||||
mappings = vim.tbl_filter(function(m)
|
||||
return m[1] and #m[1] > 0
|
||||
end, mappings)
|
||||
return vim.list_extend(mappings, keys)
|
||||
end,
|
||||
opts = {
|
||||
mappings = {
|
||||
add = "gsa", -- Add surrounding in Normal and Visual modes
|
||||
delete = "gsd", -- Delete surrounding
|
||||
find = "gsf", -- Find surrounding (to the right)
|
||||
find_left = "gsF", -- Find surrounding (to the left)
|
||||
highlight = "gsh", -- Highlight surrounding
|
||||
replace = "gsr", -- Replace surrounding
|
||||
update_n_lines = "gsn", -- Update `n_lines`
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"echasnovski/mini.comment",
|
||||
"nvim-mini/mini.comment",
|
||||
enable = true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,22 +1,7 @@
|
||||
return {
|
||||
"epwalsh/obsidian.nvim",
|
||||
"obsidian-nvim/obsidian.nvim",
|
||||
version = "*", -- recommended, use latest release instead of latest commit
|
||||
lazy = true,
|
||||
ft = "markdown",
|
||||
-- Replace the above line with this if you only want to load obsidian.nvim for markdown files in your vault:
|
||||
-- event = {
|
||||
-- -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'.
|
||||
-- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/*.md"
|
||||
-- -- refer to `:h file-pattern` for more examples
|
||||
-- "BufReadPre path/to/my-vault/*.md",
|
||||
-- "BufNewFile path/to/my-vault/*.md",
|
||||
-- },
|
||||
dependencies = {
|
||||
-- Required.
|
||||
"nvim-lua/plenary.nvim",
|
||||
-- For the picker
|
||||
"nvim-telescope/telescope.nvim",
|
||||
},
|
||||
opts = {
|
||||
workspaces = {
|
||||
{
|
||||
@@ -54,8 +39,10 @@ return {
|
||||
checkboxes = {
|
||||
[" "] = { char = "☐", hl_group = "ObsidianTodo" },
|
||||
["x"] = { char = "✔", hl_group = "ObsidianDone" },
|
||||
["/"] = { char = "⛋", hl_group = "ObsidianDone" },
|
||||
[">"] = { char = "⛝", hl_group = "ObsidianDone" },
|
||||
["/"] = { char = "⧗", hl_group = "ObsidianTodo" },
|
||||
[">"] = { char = "»", hl_group = "ObsidianRightArrow" },
|
||||
["~"] = { char = "»", hl_group = "ObsidianTilde" },
|
||||
["!"] = { char = "⛝", hl_group = "ObsidianDone" },
|
||||
},
|
||||
},
|
||||
|
||||
@@ -78,5 +65,9 @@ return {
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
follow_url_func = function(url)
|
||||
vim.ui.open(url) -- Use the built-in open, need Neovim 0.10.0+
|
||||
end,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
return {
|
||||
"folke/snacks.nvim",
|
||||
---@type snacks.Config
|
||||
opts = {
|
||||
opts = function(_, opts)
|
||||
vim.tbl_deep_extend("force", opts, {
|
||||
picker = {
|
||||
smart = {
|
||||
-- Remove the "recent" picker so we don't get things from other directories.
|
||||
@@ -15,286 +15,51 @@ return {
|
||||
cwd_bonus = true,
|
||||
-- Give more weight to files that are more recent
|
||||
history_bonus = true,
|
||||
-- Give more weight to places where the filename is part of the match
|
||||
filename_bonus = true,
|
||||
},
|
||||
},
|
||||
sources = {
|
||||
explorer = {
|
||||
layout = { layout = { position = "right" } },
|
||||
},
|
||||
},
|
||||
-- This only supports the Kitty graphics protocol.
|
||||
-- See
|
||||
-- https://github.com/folke/snacks.nvim/blob/main/docs/image.md
|
||||
-- https://github.com/obsidian-nvim/obsidian.nvim/wiki/Images
|
||||
-- image = {
|
||||
-- resolve = function(path, src)
|
||||
-- if require("obsidian.api").path_is_note(path) then
|
||||
-- return require("obsidian.api").resolve_image_path(src)
|
||||
-- end
|
||||
-- end,
|
||||
-- },
|
||||
},
|
||||
})
|
||||
Snacks.toggle({
|
||||
name = "Color Column",
|
||||
get = function()
|
||||
return vim.o.colorcolumn == "80"
|
||||
end,
|
||||
set = function(state)
|
||||
if state then
|
||||
vim.o.colorcolumn = "80"
|
||||
vim.cmd([[highlight ColorColumn guibg=#202020]])
|
||||
else
|
||||
vim.o.colorcolumn = ""
|
||||
vim.cmd([[highlight ColorColumn guibg=None]])
|
||||
end
|
||||
end,
|
||||
}):map("<leader>ut", { desc = "Toggle Color Column" })
|
||||
end,
|
||||
keys = {
|
||||
{
|
||||
"<leader><space>",
|
||||
function()
|
||||
Snacks.picker.smart({
|
||||
-- Remove the "recent" picker so we don't get things from other directories.
|
||||
multi = { "buffers", "files" },
|
||||
matcher = {
|
||||
-- sort even when the search string is empty
|
||||
sort_empty = false,
|
||||
-- Enable frecensy for matchers. This puts more common files near
|
||||
-- the top This includes files that aren't open and can put files I
|
||||
-- am done with above open files, so it's off.
|
||||
frecency = false,
|
||||
-- Make sure files in the current directory are prioritized
|
||||
cwd_bonus = true,
|
||||
-- Give more weight to files that are more recent
|
||||
history_bonus = true,
|
||||
-- Give more weight to places where the filename is part of the match
|
||||
filename_bonus = true,
|
||||
},
|
||||
})
|
||||
Snacks.picker.smart()
|
||||
end,
|
||||
desc = "Smart Find Files",
|
||||
},
|
||||
|
||||
-- The rest of these are just default bindings. Setting the one binding above seems to override the others.
|
||||
{
|
||||
"<leader>,",
|
||||
function()
|
||||
Snacks.picker.buffers()
|
||||
end,
|
||||
desc = "Buffers",
|
||||
},
|
||||
{ "<leader>/", LazyVim.pick("grep"), desc = "Grep (Root Dir)" },
|
||||
{
|
||||
"<leader>:",
|
||||
function()
|
||||
Snacks.picker.command_history()
|
||||
end,
|
||||
desc = "Command History",
|
||||
},
|
||||
{
|
||||
"<leader>n",
|
||||
function()
|
||||
Snacks.picker.notifications()
|
||||
end,
|
||||
desc = "Notification History",
|
||||
},
|
||||
-- find
|
||||
{
|
||||
"<leader>fb",
|
||||
function()
|
||||
Snacks.picker.buffers()
|
||||
end,
|
||||
desc = "Buffers",
|
||||
},
|
||||
{
|
||||
"<leader>fB",
|
||||
function()
|
||||
Snacks.picker.buffers({ hidden = true, nofile = true })
|
||||
end,
|
||||
desc = "Buffers (all)",
|
||||
},
|
||||
{ "<leader>fc", LazyVim.pick.config_files(), desc = "Find Config File" },
|
||||
{ "<leader>ff", LazyVim.pick("files"), desc = "Find Files (Root Dir)" },
|
||||
{ "<leader>fF", LazyVim.pick("files", { root = false }), desc = "Find Files (cwd)" },
|
||||
{
|
||||
"<leader>fg",
|
||||
function()
|
||||
Snacks.picker.git_files()
|
||||
end,
|
||||
desc = "Find Files (git-files)",
|
||||
},
|
||||
{ "<leader>fr", LazyVim.pick("oldfiles"), desc = "Recent" },
|
||||
{
|
||||
"<leader>fR",
|
||||
function()
|
||||
Snacks.picker.recent({ filter = { cwd = true } })
|
||||
end,
|
||||
desc = "Recent (cwd)",
|
||||
},
|
||||
{
|
||||
"<leader>fp",
|
||||
function()
|
||||
Snacks.picker.projects()
|
||||
end,
|
||||
desc = "Projects",
|
||||
},
|
||||
-- git
|
||||
{
|
||||
"<leader>gd",
|
||||
function()
|
||||
Snacks.picker.git_diff()
|
||||
end,
|
||||
desc = "Git Diff (hunks)",
|
||||
},
|
||||
{
|
||||
"<leader>gs",
|
||||
function()
|
||||
Snacks.picker.git_status()
|
||||
end,
|
||||
desc = "Git Status",
|
||||
},
|
||||
{
|
||||
"<leader>gS",
|
||||
function()
|
||||
Snacks.picker.git_stash()
|
||||
end,
|
||||
desc = "Git Stash",
|
||||
},
|
||||
-- Grep
|
||||
{
|
||||
"<leader>sb",
|
||||
function()
|
||||
Snacks.picker.lines()
|
||||
end,
|
||||
desc = "Buffer Lines",
|
||||
},
|
||||
{
|
||||
"<leader>sB",
|
||||
function()
|
||||
Snacks.picker.grep_buffers()
|
||||
end,
|
||||
desc = "Grep Open Buffers",
|
||||
},
|
||||
{ "<leader>sg", LazyVim.pick("live_grep"), desc = "Grep (Root Dir)" },
|
||||
{ "<leader>sG", LazyVim.pick("live_grep", { root = false }), desc = "Grep (cwd)" },
|
||||
{
|
||||
"<leader>sp",
|
||||
function()
|
||||
Snacks.picker.lazy()
|
||||
end,
|
||||
desc = "Search for Plugin Spec",
|
||||
},
|
||||
{ "<leader>sw", LazyVim.pick("grep_word"), desc = "Visual selection or word (Root Dir)", mode = { "n", "x" } },
|
||||
{
|
||||
"<leader>sW",
|
||||
LazyVim.pick("grep_word", { root = false }),
|
||||
desc = "Visual selection or word (cwd)",
|
||||
mode = { "n", "x" },
|
||||
},
|
||||
-- search
|
||||
{
|
||||
'<leader>s"',
|
||||
function()
|
||||
Snacks.picker.registers()
|
||||
end,
|
||||
desc = "Registers",
|
||||
},
|
||||
{
|
||||
"<leader>s/",
|
||||
function()
|
||||
Snacks.picker.search_history()
|
||||
end,
|
||||
desc = "Search History",
|
||||
},
|
||||
{
|
||||
"<leader>sa",
|
||||
function()
|
||||
Snacks.picker.autocmds()
|
||||
end,
|
||||
desc = "Autocmds",
|
||||
},
|
||||
{
|
||||
"<leader>sc",
|
||||
function()
|
||||
Snacks.picker.command_history()
|
||||
end,
|
||||
desc = "Command History",
|
||||
},
|
||||
{
|
||||
"<leader>sC",
|
||||
function()
|
||||
Snacks.picker.commands()
|
||||
end,
|
||||
desc = "Commands",
|
||||
},
|
||||
{
|
||||
"<leader>sd",
|
||||
function()
|
||||
Snacks.picker.diagnostics()
|
||||
end,
|
||||
desc = "Diagnostics",
|
||||
},
|
||||
{
|
||||
"<leader>sD",
|
||||
function()
|
||||
Snacks.picker.diagnostics_buffer()
|
||||
end,
|
||||
desc = "Buffer Diagnostics",
|
||||
},
|
||||
{
|
||||
"<leader>sh",
|
||||
function()
|
||||
Snacks.picker.help()
|
||||
end,
|
||||
desc = "Help Pages",
|
||||
},
|
||||
{
|
||||
"<leader>sH",
|
||||
function()
|
||||
Snacks.picker.highlights()
|
||||
end,
|
||||
desc = "Highlights",
|
||||
},
|
||||
{
|
||||
"<leader>si",
|
||||
function()
|
||||
Snacks.picker.icons()
|
||||
end,
|
||||
desc = "Icons",
|
||||
},
|
||||
{
|
||||
"<leader>sj",
|
||||
function()
|
||||
Snacks.picker.jumps()
|
||||
end,
|
||||
desc = "Jumps",
|
||||
},
|
||||
{
|
||||
"<leader>sk",
|
||||
function()
|
||||
Snacks.picker.keymaps()
|
||||
end,
|
||||
desc = "Keymaps",
|
||||
},
|
||||
{
|
||||
"<leader>sl",
|
||||
function()
|
||||
Snacks.picker.loclist()
|
||||
end,
|
||||
desc = "Location List",
|
||||
},
|
||||
{
|
||||
"<leader>sM",
|
||||
function()
|
||||
Snacks.picker.man()
|
||||
end,
|
||||
desc = "Man Pages",
|
||||
},
|
||||
{
|
||||
"<leader>sm",
|
||||
function()
|
||||
Snacks.picker.marks()
|
||||
end,
|
||||
desc = "Marks",
|
||||
},
|
||||
{
|
||||
"<leader>sR",
|
||||
function()
|
||||
Snacks.picker.resume()
|
||||
end,
|
||||
desc = "Resume",
|
||||
},
|
||||
{
|
||||
"<leader>sq",
|
||||
function()
|
||||
Snacks.picker.qflist()
|
||||
end,
|
||||
desc = "Quickfix List",
|
||||
},
|
||||
{
|
||||
"<leader>su",
|
||||
function()
|
||||
Snacks.picker.undo()
|
||||
end,
|
||||
desc = "Undotree",
|
||||
},
|
||||
-- ui
|
||||
{
|
||||
"<leader>uC",
|
||||
function()
|
||||
Snacks.picker.colorschemes()
|
||||
end,
|
||||
desc = "Colorschemes",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
-- https://www.lazyvim.org/extras/coding/mini-surround#minisurround
|
||||
return {
|
||||
"echasnovski/mini.surround",
|
||||
keys = function(_, keys)
|
||||
-- Populate the keys based on the user's options
|
||||
local opts = LazyVim.opts("mini.surround")
|
||||
local mappings = {
|
||||
{ opts.mappings.add, desc = "Add Surrounding", mode = { "n", "v" } },
|
||||
{ opts.mappings.delete, desc = "Delete Surrounding" },
|
||||
{ opts.mappings.find, desc = "Find Right Surrounding" },
|
||||
{ opts.mappings.find_left, desc = "Find Left Surrounding" },
|
||||
{ opts.mappings.highlight, desc = "Highlight Surrounding" },
|
||||
{ opts.mappings.replace, desc = "Replace Surrounding" },
|
||||
{ opts.mappings.update_n_lines, desc = "Update `MiniSurround.config.n_lines`" },
|
||||
}
|
||||
mappings = vim.tbl_filter(function(m)
|
||||
return m[1] and #m[1] > 0
|
||||
end, mappings)
|
||||
return vim.list_extend(mappings, keys)
|
||||
end,
|
||||
opts = {
|
||||
mappings = {
|
||||
add = "gsa", -- Add surrounding in Normal and Visual modes
|
||||
delete = "gsd", -- Delete surrounding
|
||||
find = "gsf", -- Find surrounding (to the right)
|
||||
find_left = "gsF", -- Find surrounding (to the left)
|
||||
highlight = "gsh", -- Highlight surrounding
|
||||
replace = "gsr", -- Replace surrounding
|
||||
update_n_lines = "gsn", -- Update `n_lines`
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
return {
|
||||
"nvim-treesitter/nvim-treesitter",
|
||||
opts = {
|
||||
ensure_installed = {
|
||||
"astro",
|
||||
"bash",
|
||||
"html",
|
||||
"css",
|
||||
"javascript",
|
||||
"json",
|
||||
"lua",
|
||||
"markdown",
|
||||
"markdown_inline",
|
||||
"python",
|
||||
"query",
|
||||
"regex",
|
||||
"tsx",
|
||||
"typescript",
|
||||
"vim",
|
||||
"yaml",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
extraPackages = with pkgs; [
|
||||
gcc # For treesitter complation
|
||||
tree-sitter # For treesitter binaries
|
||||
ripgrep # Search support
|
||||
wayclip # Clipboard support
|
||||
fd # finder for telescope
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
obsidian
|
||||
];
|
||||
|
||||
home.shellAliases = {
|
||||
"notes" = "(cd ~/Documents/Notes && nvim)";
|
||||
};
|
||||
|
||||
services.syncthing = {
|
||||
enable = true;
|
||||
tray = {
|
||||
@@ -21,6 +25,7 @@
|
||||
"altair"
|
||||
"mcp"
|
||||
"vega"
|
||||
"proxima"
|
||||
];
|
||||
};
|
||||
};
|
||||
@@ -52,6 +57,14 @@
|
||||
];
|
||||
compression = "always";
|
||||
};
|
||||
proxima = {
|
||||
id = "NWZL6LY-ULJQMZE-EWY3MQU-XPDAFQB-LTIBZV7-GPKIABJ-WBJE36F-SK6LVAY";
|
||||
name = "Proxima";
|
||||
addresses = [
|
||||
"relay://syncthing.blazestar.net:22067"
|
||||
];
|
||||
compression = "always";
|
||||
};
|
||||
};
|
||||
options = {
|
||||
localAnnounceEnabled = false;
|
||||
|
||||
@@ -15,17 +15,19 @@
|
||||
htop
|
||||
btop
|
||||
neofetch
|
||||
killall
|
||||
psmisc # fuser, killal, pstree
|
||||
|
||||
# Files
|
||||
# Archives
|
||||
zip
|
||||
xz
|
||||
unzip
|
||||
p7zip
|
||||
unrar-wrapper
|
||||
|
||||
# File manipulation
|
||||
file
|
||||
tree
|
||||
yazi # File manager
|
||||
ueberzugpp # for image previews
|
||||
w3m # terminal browser for image previews
|
||||
dysk # better disk info
|
||||
ripgrep # better grep
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
nerd-fonts.jetbrains-mono
|
||||
|
||||
libsixel # For working with images in terminals
|
||||
ueberzugpp # for image previews
|
||||
];
|
||||
|
||||
# Allow Home Manager to set fonts.
|
||||
|
||||
@@ -12,10 +12,21 @@ offen:
|
||||
secret: ENC[AES256_GCM,data:sH2siPc/QH1O2M7ZlJwqhqlHRIeLIG9r,iv:eD29ALx2ji0rm1t9j6RulTZT3f6VLK7dxpPOze3qDKA=,tag:zqJTgT2UeA/ecBS4VremUw==,type:str]
|
||||
smtp-token: ENC[AES256_GCM,data:ZTfe65g3JykPvG2l0AN8UQ==,iv:GTruGo/vcP+imfJyqB3NX9ic8dz5jvTEh6SF+OeqMDM=,tag:kgwd59pG/WUt8OAaVzi39Q==,type:str]
|
||||
traefik:
|
||||
oauth2-client-secret: ENC[AES256_GCM,data:gV9/yBCqWPcNG/m7S0PRE3TduKzqRD1ii3RGGjNprQM=,iv:jmwBYWhPQJMZWHZine6Eb+7fdW44QOvkK52LQ6ISK4s=,tag:yNWRJ1IdPcxn6e0DXQe7Cw==,type:str]
|
||||
oauth2-client-secret: ENC[AES256_GCM,data:p7/6OsN2ytBj8mQiK0YL7J6NYLtMHOXIIs/6+bIDpsU=,iv:k6jLZifJEFLYKSFMkyn/kA7iBE+EFB8O/3/3fyTh1SY=,tag:6s49O2+tdlZoXyAGEamuMQ==,type:str]
|
||||
oauth2-plugin-secret: ENC[AES256_GCM,data:sArqwKHAdW35o5kD7DGfXSYCXFUXqvKQdoVnXutsNLw=,iv:qWf597QS3BqkVQkeAb99HbpDB0kUhdD+qKdpUPZEB0o=,tag:vXnb93npaklItWkMZ+/M9Q==,type:str]
|
||||
protonvpn:
|
||||
private_key: ENC[AES256_GCM,data:41pfbR1klj1F24v3HlCCA4ofW2sCEnyE5TH8iX4Ug8D+kmwstTaj5RG2Zz8=,iv:P6XyQnDVoOmdkP8ilBR9DyfqPZA6GsQ6VUwY/tSGhx4=,tag:Bzgdv29lbk/gYlADPZMGVA==,type:str]
|
||||
deploy-key:
|
||||
terakoda.com: ENC[AES256_GCM,data:STOAUPihw2KfndKm/XV5evihrTy/TQrbtVh7EpEyVE6Z1FsJd3UljcjhTmp/Z3nSpq4LCiezmaxISTnQDIP/NzPfou309SLl2QvD7deFhurMsYbeWJw62RP0ClBfteBaVxeqlH/pksoE1cJaZFxv/KxXYYoxzCUzeXC31GQv6Mft+/FnA1rsVp2n0Ay73hMVjMY0ml2csybLOuuKyxEq3nImhLFvtr4jJhVmxnN2L+bs0a+GohjC98HwITJD2OsrJwSpW4cv2v1GqeJCr2om5SgplwvjkiHJrg/WLO8N6BuVDOy0yx9Vbf1cAwkzPd3gBeKd5po+baJwRFAXpB03KvG/w6Yz/4ewo4X78IhwtLvTl876e/i/7K17ILvc5JJrKe9lmEuNUaItRPWYypEHrkge/PXSAvPIqRnAEi3jfOfVXWygZPerS3hs7bBE/Lem1U7/MUcK+pfXnZDgbWVsRuFhZhxasFGa7cG+gBUZsHWbyXi2e/koFUqUTR0HU0q0zF1xw/8jthPPGoIJ/0tP,iv:99AI3rnNjt9XqXJHnQ3DAEFm90h465ymjNWEpsWvRnM=,tag:96dnIojTXXONozgYDFwcBA==,type:str]
|
||||
mcp: ENC[AES256_GCM,data:eQcX8xdz5qZ6nU8ISOvZo+ZtP4Z/ePd+/ZZReX1BKvTUqGQPPFxConbLMwFzvzpD6xAUbA1MLkcR/bT98QbNx6LJYlhbofuDUg2DI79RB0fcrAcj/wUV0YPhmgofUdYYDaimH5A2PSvtmKfB3CtKKuA5HNeLymoXeLEpFzbckkGhzPee/CHiUmxayogp6za6btsDJsiT8hdHbrzyD2S6fhMJrzX+PlRzT32M/6eaFuFWE8EUO1gbkRlNfKPXw/EM2GXWJfR4qXfN2YKIKigqrtlAAoxnrUbp5EBrn/hGHS2ZYZXeRUFr3avFjcI0bLX423PWRHAylfQCPxgYVEtbcRv11CAFmq4rfFl0ZdvnAKbTLNmWcrQNijBATZPaAdQzgKPDHs8pwPUFR9Tcg8pZNbzw0mK9kPolniAOL2PBKUHv6LP/uEkB1E6Pxc7yms0kGpeJyo7hrFVOiVAckCey+SI9dpbJMSB3md070I1xk6Ik7PywrWh2QDeUtOU1U28UkYgnJ/9MJelWsNlUX9SR,iv:oCNeanaV/7UZ3dhmq4ZmJUZ5hb61AnHpHCfskM2Jsm8=,tag:F2uJKN5beM/rfiBMSyUP7w==,type:str]
|
||||
matrix:
|
||||
syncv3:
|
||||
db-password: ENC[AES256_GCM,data:N/IO0k/2BZpmaDTbKZmSgZNzmdk=,iv:p0jGjJ9mTCh5FPM/Oe1vxusYvlyg14UeggE5ynpDVL8=,tag:tZbddwxJf6wSH6L1QRUQVg==,type:str]
|
||||
secret: ENC[AES256_GCM,data:KZjYxjUxGgkY1I5jGF7XMEhkHK+khDaQzxugoKxpLsROmVs722tFfbUAxhp71llam55gy9+eUWGxIPlmvOySlw==,iv:OoThGcT08Z11kpnAMQ7w59wj5JheNFGEk1jfFENsmy0=,tag:8EeKT7dh2/a52Amf6LsL1w==,type:str]
|
||||
blazestar-registration-token: ENC[AES256_GCM,data:TB3bR+E4H4c2l9pRcEOAZr35+vBVaJUcuCs9K0Pjd0aW+M35x5LgZ8+F99Y=,iv:e28sie6LSI5UX41BPb+yN+3n+Yw9Ssfsqe4zppwbPkU=,tag:cQPgZcRFbYSiZnmPVtZxHg==,type:str]
|
||||
tandoor:
|
||||
secret_key: ENC[AES256_GCM,data:nl7S2fS1wENrT5k2iZfLEAGc99lCUktgwR5L5KklF69BNVKQkW1rUgb3aIv50VpXZa+3OxV/vdPmG9NhKMy96I5+Dno=,iv:FFyGQBARz0B5zrONZELzUMsOIn8TWrDNTKGsAHPlS7w=,tag:/c4MnDfLXQpBZDqVxZ0DTg==,type:str]
|
||||
immich:
|
||||
database: ENC[AES256_GCM,data:1fjOQsLZcq/T+r+AkzomWwCQWw==,iv:c4pn2rC+3xkxLJ7uAdhnTE6zVTRQkfuKK3tjUyDhfAw=,tag:kvk7DOv6X/+RDxfPxVak7w==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age1yvdzvuvu5wqztcx6ll2xk6x547uuyqy735tjjdd7zftkz53jsf9qf5ahue
|
||||
@@ -36,7 +47,7 @@ sops:
|
||||
by9aNFY4dXNxaWxnTXFTQS9reHhuQWMKh5rZ93nFtBV9EpFVRp+E+GXZ6xzVy2Jw
|
||||
vFh4deGcAb60q4odSaeWfk1Dr7L9Ua69oK9omjbCNUt+P7Kwlfca7Q==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2025-06-04T22:56:20Z"
|
||||
mac: ENC[AES256_GCM,data:EOPjNLAQRvi2FgmYwHST1eZDj1lMT4+Nwi5YS8yJI7w2Y8pkBiKx1JqMzNW7DSmwIf8J7TCmK+7bmJPF+WyLPous8B920zbn9Rt8ttLpSRBOHCReH9k3FwYAtAkYYCMB2oeDkpWjTnU2xeUh/FqOkRInw98sy3EO0HPEtXdPrng=,iv:17nuB8ders0PI92BrWX3mwuxqDafckM9Reu+wiRo5/0=,tag:mirzSqpscIrDp7vZwX0+NQ==,type:str]
|
||||
lastmodified: "2026-02-25T00:28:13Z"
|
||||
mac: ENC[AES256_GCM,data:hDmqObrtfoVkQqz8JPkqlyXMbiuyBophjdZNLvTFrZw3pAVNCuzsH4zxFBOaxJttkzLc65DWDHDeEIBY5YZam1GLFFXUQ5E3Dxno7hnyzOoM2ipgDTOacI0gbKJAWgGUF3LNDdqVoREA9LC91LoNUJoNmzpTSFtuLb7ORuwCrH4=,iv:8+W3n1Cr6woEiPU9ECaMYM64HNmFHr2AIw6UohCJi00=,tag:7drkZiPAUHaEx5PagXA9JQ==,type:str]
|
||||
unencrypted_suffix: _unencrypted
|
||||
version: 3.10.2
|
||||
version: 3.11.0
|
||||
|
||||
5
system/features/android-dev.nix
Normal file
5
system/features/android-dev.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
{ ... }:
|
||||
{
|
||||
programs.adb.enable = true;
|
||||
users.users.drew.extraGroups = [ "adbusers" ];
|
||||
}
|
||||
@@ -3,13 +3,18 @@
|
||||
virtualisation = {
|
||||
docker = {
|
||||
enable = true;
|
||||
rootless = {
|
||||
enable = true;
|
||||
setSocketVariable = true;
|
||||
};
|
||||
# rootless = {
|
||||
# enable = true;
|
||||
# setSocketVariable = true;
|
||||
# };
|
||||
};
|
||||
|
||||
# Do not use Podman in Wayland/Hyperland. It will crash the session. Very annoying.
|
||||
# podman.enable = true;
|
||||
};
|
||||
|
||||
hardware.nvidia-container-toolkit.enable = true;
|
||||
|
||||
home-manager.users.drew =
|
||||
{ ... }:
|
||||
{
|
||||
|
||||
12
system/features/flatpak.nix
Normal file
12
system/features/flatpak.nix
Normal file
@@ -0,0 +1,12 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.flatpak.enable = true;
|
||||
|
||||
systemd.services.flatpak-repo = {
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.flatpak ];
|
||||
script = ''
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
'';
|
||||
};
|
||||
}
|
||||
50
system/features/graphics.nix
Normal file
50
system/features/graphics.nix
Normal file
@@ -0,0 +1,50 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
options =
|
||||
with lib;
|
||||
with types;
|
||||
{
|
||||
graphics = {
|
||||
enable = mkEnableOption "graphics support";
|
||||
driverChannel = mkOption {
|
||||
type = str;
|
||||
# Default to production because I often want new features, but I don't want bleeding edge.
|
||||
default = "production";
|
||||
description = "Driver channel to use (in order of oldest to newest): stable, beta, latest";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.graphics.enable {
|
||||
# Graphics settings
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
|
||||
hardware.nvidia = {
|
||||
package = config.boot.kernelPackages.nvidiaPackages."${config.graphics.driverChannel}";
|
||||
|
||||
modesetting.enable = true;
|
||||
|
||||
# Nvidia power management. Experimental, and can cause sleep/suspend to fail.
|
||||
# Enable this if you have graphical corruption issues or application crashes after waking
|
||||
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
|
||||
# of just the bare essentials.
|
||||
powerManagement.enable = true;
|
||||
|
||||
# Fine-grained power management for PRIME. Turns off GPU when not in use.
|
||||
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
|
||||
# Requires offload to be enabled.
|
||||
# powerManagement.finegrained = false;
|
||||
|
||||
# Use the open-source driver?
|
||||
open = false;
|
||||
|
||||
# Enable the nvidia-settings menu?
|
||||
nvidiaSettings = true;
|
||||
};
|
||||
};
|
||||
}
|
||||
21
system/features/printing.nix
Normal file
21
system/features/printing.nix
Normal file
@@ -0,0 +1,21 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
services.printing = {
|
||||
enable = true;
|
||||
drivers = [ pkgs.brlaser ];
|
||||
};
|
||||
hardware.printers = {
|
||||
ensurePrinters = [
|
||||
{
|
||||
name = "Brother_HL-L2370DW_series";
|
||||
location = "Home";
|
||||
deviceUri = "dnssd://Brother%20HL-L2370DW%20series._ipp._tcp.local/?uuid=e3248000-80ce-11db-8000-3c2af4f28c38";
|
||||
model = "drv:///brlaser.drv/brl2370d.ppd";
|
||||
ppdOptions = {
|
||||
PageSize = "Letter";
|
||||
};
|
||||
}
|
||||
];
|
||||
ensureDefaultPrinter = "Brother_HL-L2370DW_series";
|
||||
};
|
||||
}
|
||||
127
system/features/web-containers.nix
Normal file
127
system/features/web-containers.nix
Normal file
@@ -0,0 +1,127 @@
|
||||
{ config, lib, ... }:
|
||||
{
|
||||
options =
|
||||
with lib;
|
||||
with types;
|
||||
{
|
||||
virtualisation.web-containers = {
|
||||
enable = mkEnableOption "web containers";
|
||||
containers = mkOption {
|
||||
type = lazyAttrsOf (submodule {
|
||||
options =
|
||||
let
|
||||
strOpt = mkOption { type = str; };
|
||||
intOpt = mkOption { type = int; };
|
||||
boolOpt = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
};
|
||||
strList = mkOption {
|
||||
type = listOf str;
|
||||
default = [ ];
|
||||
};
|
||||
attrOpt = mkOption {
|
||||
type = attrsOf str;
|
||||
default = { };
|
||||
};
|
||||
in
|
||||
{
|
||||
image = strOpt;
|
||||
hostname = strOpt;
|
||||
port = intOpt;
|
||||
homepageOpts = attrOpt;
|
||||
dependsOn = strList;
|
||||
domain = strOpt;
|
||||
volumes = strList;
|
||||
environment = attrOpt;
|
||||
environmentFiles = strList;
|
||||
public = boolOpt;
|
||||
user = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
};
|
||||
extraOptions = strList;
|
||||
oauthProxy = boolOpt;
|
||||
extraLabels = attrOpt;
|
||||
};
|
||||
});
|
||||
default = { };
|
||||
description = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
virtualisation.oci-containers.containers = lib.mkIf config.virtualisation.web-containers.enable (
|
||||
let
|
||||
hostRule = host: domain: "Host(`${host}.${domain}`)";
|
||||
localNet = "192.168.0.0/16";
|
||||
dockerNet = "10.88.0.0/16";
|
||||
localNetRule = "(ClientIP(`${localNet}`) || ClientIP(`${dockerNet}`))";
|
||||
localHostRule = host: domain: "${localNetRule} && ${hostRule host domain}";
|
||||
mkContainer =
|
||||
key:
|
||||
{
|
||||
image,
|
||||
hostname,
|
||||
port,
|
||||
homepageOpts,
|
||||
dependsOn,
|
||||
domain,
|
||||
volumes,
|
||||
environment,
|
||||
environmentFiles,
|
||||
public,
|
||||
user,
|
||||
extraOptions,
|
||||
oauthProxy,
|
||||
extraLabels,
|
||||
}:
|
||||
let
|
||||
fqn = "${hostname}.${domain}";
|
||||
serviceName = builtins.replaceStrings [ "." ] [ "-" ] fqn;
|
||||
routerRule = if public then hostRule hostname domain else localHostRule hostname domain;
|
||||
homepageLabels =
|
||||
if homepageOpts == { } then
|
||||
{ }
|
||||
else
|
||||
{
|
||||
"homepage.group" = "${homepageOpts.group}";
|
||||
"homepage.name" = "${homepageOpts.name}";
|
||||
"homepage.icon" = "${homepageOpts.icon}";
|
||||
"homepage.href" = "https://${fqn}";
|
||||
"homepage.description" = "${homepageOpts.description}";
|
||||
};
|
||||
oauthLabels =
|
||||
if oauthProxy then
|
||||
{ "traefik.http.routers.${serviceName}.middlewares" = "oidc-auth@file"; }
|
||||
else
|
||||
{ };
|
||||
in
|
||||
{
|
||||
inherit
|
||||
image
|
||||
dependsOn
|
||||
volumes
|
||||
environment
|
||||
environmentFiles
|
||||
user
|
||||
extraOptions
|
||||
;
|
||||
autoStart = true;
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${serviceName}.rule" = "${routerRule}";
|
||||
"traefik.http.routers.${serviceName}.service" = "${serviceName}";
|
||||
"traefik.http.routers.${serviceName}.entrypoints" = "web,websecure";
|
||||
"traefik.http.services.${serviceName}.loadbalancer.server.port" = "${toString port}";
|
||||
}
|
||||
// oauthLabels
|
||||
// homepageLabels
|
||||
// extraLabels;
|
||||
};
|
||||
in
|
||||
builtins.mapAttrs mkContainer config.virtualisation.web-containers.containers
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
../../features/gc.nix
|
||||
../../features/gui.nix
|
||||
../../features/container-dev.nix
|
||||
../../features/android-dev.nix
|
||||
../../features/flatpak.nix
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
@@ -8,6 +8,8 @@ in
|
||||
{
|
||||
imports =
|
||||
map (x: ../../../home-manager + x) [
|
||||
"/features/astronomy.nix"
|
||||
"/features/chat.nix"
|
||||
"/features/development/development.nix"
|
||||
"/features/development/docker.nix"
|
||||
"/features/development/haskell.nix"
|
||||
@@ -16,8 +18,10 @@ in
|
||||
"/features/development/vscode.nix"
|
||||
"/features/eww"
|
||||
"/features/gaming.nix"
|
||||
"/features/image-editing.nix"
|
||||
"/features/linux-desktop.nix"
|
||||
"/features/notes.nix"
|
||||
"/features/3d-printing.nix"
|
||||
]
|
||||
++ [
|
||||
(import ../../../home-manager/features/wallpaper.nix monitors)
|
||||
@@ -39,13 +43,15 @@ in
|
||||
userEmail = "drew.haven@gmail.com";
|
||||
};
|
||||
|
||||
# Set up eww here because it's based on the monitor configuration
|
||||
wayland.windowManager.hyprland.settings = {
|
||||
exec-once = [
|
||||
"sleep 2 && eww open-many primary-statusbar secondary-statusbar launcher"
|
||||
# Set up eww here because it's based on the monitor configuration
|
||||
"sleep 2 && eww open-many primary-statusbar secondary-statusbar"
|
||||
# Set DP-2 as the primary monitor, otherwise it defaults to DP-1 because it's first in the list.
|
||||
"xrandr --output DP-2 --primary"
|
||||
];
|
||||
windowrulev2 = [
|
||||
# Rofi doesn't center properly when I have the two asymetric monitors
|
||||
# Rofi doesn't center properly when I have the two asymetric monitors, so we need hyprland to manage it.
|
||||
"center, class:Rofi"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -13,10 +13,14 @@
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
];
|
||||
# Bootloader.
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot = {
|
||||
loader = {
|
||||
systemd-boot.enable = true;
|
||||
efi.canTouchEfiVariables = true;
|
||||
};
|
||||
|
||||
boot.initrd.availableKernelModules = [
|
||||
initrd = {
|
||||
availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ahci"
|
||||
"nvme"
|
||||
@@ -24,16 +28,19 @@
|
||||
"usb_storage"
|
||||
"sd_mod"
|
||||
];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
kernelModules = [ ];
|
||||
};
|
||||
kernelModules = [ "kvm-intel" ];
|
||||
extraModulePackages = [ ];
|
||||
};
|
||||
|
||||
fileSystems."/" = {
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-uuid/343c0ac5-3973-49b3-964a-6ad90c36b89c";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
fileSystems."/boot" = {
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-uuid/5F99-043D";
|
||||
fsType = "vfat";
|
||||
options = [
|
||||
@@ -42,10 +49,11 @@
|
||||
];
|
||||
};
|
||||
|
||||
fileSystems."/home" = {
|
||||
"/home" = {
|
||||
device = "/dev/disk/by-uuid/28f4fb41-9414-4504-a767-c2e8bf5eb2c8";
|
||||
fsType = "ext4";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [ ];
|
||||
|
||||
@@ -58,17 +66,26 @@
|
||||
# networking.interfaces.wlo1.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
|
||||
# Graphics settings
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
|
||||
hardware.nvidia = {
|
||||
hardware = {
|
||||
cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
nvidia = {
|
||||
# Other options include:
|
||||
# stable - Current stable
|
||||
# production - Same as stable
|
||||
# latest - Bleeding edge
|
||||
# beta - latest beta
|
||||
#
|
||||
# See https://nixos.wiki/wiki/Nvidia
|
||||
#
|
||||
# Current versions can be found in https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/os-specific/linux/nvidia-x11/default.nix
|
||||
#
|
||||
package = config.boot.kernelPackages.nvidiaPackages.beta;
|
||||
|
||||
modesetting.enable = true;
|
||||
@@ -90,6 +107,7 @@
|
||||
# Enable the nvidia-settings menu?
|
||||
nvidiaSettings = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Add a udev rule to prevent the mouse from waking the system. Note that it
|
||||
# has two entries depending on whether it's plugged in or not.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{ config, pkgs, ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./vars.nix
|
||||
@@ -16,9 +16,6 @@
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
|
||||
# Set the kernel to be compatible with ZFS
|
||||
boot.kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages;
|
||||
|
||||
networking.hostName = "mcp"; # Define your hostname.
|
||||
networking.hostId = "5e292f2d"; # Define a host ID for ZFS with `head -c 8 /etc/machine-id`
|
||||
# networking.wireless.enable = true; # Enables wireless support via wpa_supplicant.
|
||||
@@ -62,6 +59,7 @@
|
||||
"networkmanager"
|
||||
"wheel"
|
||||
"docker-registry"
|
||||
"docker"
|
||||
];
|
||||
shell = pkgs.zsh;
|
||||
# Enable linger so that systemd services run for this user are started and
|
||||
@@ -96,7 +94,8 @@
|
||||
port = 5000;
|
||||
openFirewall = true;
|
||||
# Bind to the podman network so Traefik can route to it.
|
||||
# Note that it may fail to start if this network has not been created yet.
|
||||
# Note that it may fail to start if this network has not been created yet,
|
||||
# so this has to be manually restarted when the system boots.
|
||||
listenAddress = "10.88.0.1";
|
||||
};
|
||||
|
||||
@@ -107,8 +106,10 @@
|
||||
enabledCollectors = [ "systemd" ];
|
||||
port = 9002;
|
||||
# Open the firewall, but only listen on the internal address
|
||||
# TODO: Add some form authentication
|
||||
openFirewall = true;
|
||||
# Bind to the podman network so Traefik can route to it.
|
||||
# Note that it may fail to start if this network has not been created yet,
|
||||
# so this has to be manually restarted when the system boots.
|
||||
listenAddress = "10.88.0.1";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
# Started from https://nixos.wiki/wiki/Podman
|
||||
{ config, pkgs, ... }:
|
||||
{
|
||||
config,
|
||||
pkgs,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Additional configuration
|
||||
imports = [
|
||||
./containers/havenisms.com
|
||||
./containers/blazestar.net
|
||||
|
||||
# Docker containers
|
||||
./containers/dm-companion.nix
|
||||
./containers/freshrss.nix
|
||||
./containers/gitea.nix
|
||||
./containers/goatcounter.nix
|
||||
./containers/grafana.nix
|
||||
./containers/jobhunt.nix
|
||||
# ./containers/jobhunt.nix
|
||||
./containers/mariadb.nix
|
||||
./containers/media-system.nix
|
||||
./containers/nextcloud.nix
|
||||
./containers/offen.nix
|
||||
# ./containers/offen.nix
|
||||
./containers/pocket-id.nix
|
||||
./containers/prometheus.nix
|
||||
./containers/public-homepage.nix
|
||||
./containers/searxng.nix
|
||||
./containers/shared-postgres.nix
|
||||
./containers/synapse.nix
|
||||
./containers/timetagger.nix
|
||||
# ./containers/timetagger.nix
|
||||
./containers/traefik.nix
|
||||
./containers/users.nix
|
||||
|
||||
@@ -27,10 +34,67 @@
|
||||
./static-site-hooks.nix
|
||||
];
|
||||
|
||||
options.local = with lib; {
|
||||
container-backend = mkOption {
|
||||
type = with types; uniq str;
|
||||
default = "docker";
|
||||
example = "docker";
|
||||
description = "Which backend to use for containers: docker or podman";
|
||||
};
|
||||
container-socket = mkOption {
|
||||
type = with types; uniq str;
|
||||
default = "/var/run/docker.sock";
|
||||
example = "/var/run/docker.sock";
|
||||
description = "Path to the container management deamon's socket.";
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
# local = {
|
||||
# container-backend = "docker";
|
||||
# container-socket = "/var/run/docker.sock";
|
||||
# };
|
||||
local = {
|
||||
container-backend = "podman";
|
||||
container-socket = "/var/run/podman/podman.sock";
|
||||
};
|
||||
|
||||
# Enable common container config files in /etc/containers
|
||||
virtualisation.containers.enable = true;
|
||||
|
||||
virtualisation = {
|
||||
podman = {
|
||||
containers.enable = true;
|
||||
oci-containers.backend = config.local.container-backend;
|
||||
|
||||
docker = lib.mkIf (config.local.container-backend == "docker") {
|
||||
enable = true;
|
||||
# Enable rootless so that I can run containers as other users for security.
|
||||
rootless = {
|
||||
enable = true;
|
||||
# Set this to make the default DOCKER_HOST be the rootless version for normal users.
|
||||
setSocketVariable = true;
|
||||
daemon = {
|
||||
settings = {
|
||||
default-address-pools = [
|
||||
{
|
||||
base = "10.88.0.0/16";
|
||||
size = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
daemon = {
|
||||
settings = {
|
||||
default-address-pools = [
|
||||
{
|
||||
base = "10.88.0.0/16";
|
||||
size = 24;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
podman = lib.mkIf (config.local.container-backend == "podman") {
|
||||
enable = true;
|
||||
|
||||
# Create a `docker` alias for podman, to use it as a drop-in replacement
|
||||
@@ -46,16 +110,12 @@
|
||||
# Useful other development tools
|
||||
environment.systemPackages = with pkgs; [
|
||||
dive # look into docker image layers
|
||||
podman-tui # status of containers in the terminal
|
||||
docker-compose # start group of containers for dev
|
||||
#podman-compose # start group of containers for dev
|
||||
];
|
||||
|
||||
virtualisation.oci-containers.backend = "podman";
|
||||
virtualisation.oci-containers.containers =
|
||||
let
|
||||
inherit (import ./containers/lib.nix config)
|
||||
hostRuleHavenisms
|
||||
localHostRuleHavenisms
|
||||
havenisms
|
||||
;
|
||||
@@ -75,7 +135,7 @@
|
||||
"/tank/secrets/jellyfin.key:/app/config/secrets/jellyfin.key"
|
||||
"/tank/secrets/radarr.key:/app/config/secrets/radarr.key"
|
||||
"/tank/secrets/sonarr.key:/app/config/secrets/sonarr.key"
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock:ro"
|
||||
"${config.local.container-socket}:/var/run/docker.sock:ro"
|
||||
];
|
||||
environment = {
|
||||
HOMEPAGE_FILE_JELLYFIN_KEY = "/app/config/secrets/jellyfin.key";
|
||||
@@ -100,10 +160,10 @@
|
||||
"-l=homepage.widget.type=scrutiny"
|
||||
"-l=homepage.widget.url=http://scrutiny:8080"
|
||||
"--cap-add=SYS_RAWIO"
|
||||
"--device=/dev/sda:/dev/sda"
|
||||
"--device=/dev/sdb:/dev/sdb"
|
||||
"--device=/dev/sdc:/dev/sdc"
|
||||
"--device=/dev/sdd:/dev/sdd"
|
||||
"--device=/dev/disk/by-id/wwn-0x5000cca26fca1aed:/dev/disk/by-id/wwn-0x5000cca26fca1aed"
|
||||
"--device=/dev/disk/by-id/wwn-0x5000cca26fef696c:/dev/disk/by-id/wwm-0x5000cca26fef696c"
|
||||
"--device=/dev/disk/by-id/wwn-0x5000cca270db1d0e:/dev/disk/by-id/wwn-0x5000cca270db1d0e"
|
||||
# "--device=/dev/sdd:/dev/sdd" Removing this one while the disk is down
|
||||
];
|
||||
volumes = [
|
||||
"/run/udev:/run/udev:ro"
|
||||
@@ -119,4 +179,5 @@
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
104
system/hosts/mcp/containers/blazestar.net/chat.nix
Normal file
104
system/hosts/mcp/containers/blazestar.net/chat.nix
Normal file
@@ -0,0 +1,104 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) mkContainer blazestar;
|
||||
matrixHost = "matrix";
|
||||
serviceName = "matrix-blazestar-net";
|
||||
dbPath = "/var/lib/matrix";
|
||||
port = 8448;
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"matrix/blazestar-registration-token" = {
|
||||
restartUnits = [ "${config.local.container-backend}-matrix-blazestar-net.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."matrix-blazestar-net.env".content = ''
|
||||
TUWUNEL_REGISTRATION_TOKEN=${config.sops.placeholder."matrix/blazestar-registration-token"}
|
||||
'';
|
||||
|
||||
# This isn't using any of my usual helpers because I wanted to set a custom
|
||||
# serviceName in Traefik that is different from the hostname to avoid
|
||||
# conflicts with the havenisms.com server.
|
||||
virtualisation.oci-containers.containers."${serviceName}" = {
|
||||
# The 1.1.0 version has an issue with the compression being incorrectly tagged.
|
||||
# See: https://github.com/matrix-construct/tuwunel/issues/79
|
||||
image = "ghcr.io/matrix-construct/tuwunel:v1.0.0-release-all-x86_64-linux-gnu";
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"matrix-blazestar-net-db:${dbPath}"
|
||||
];
|
||||
environment = {
|
||||
TUWUNEL_PORT = toString port;
|
||||
TUWUNEL_ADDRESS = "0.0.0.0"; # It'll bind to localhost by default with Podman
|
||||
TUWUNEL_SERVER_NAME = "blazestar.net";
|
||||
TUWUNEL_ALLOW_REGISTRATION = "true";
|
||||
TUWUNEL_ALLOW_CHECK_FOR_UPDATES = "true";
|
||||
TUWUNEL_ALLOW_FEDERATION = "true";
|
||||
TUWUNEL_DATABASE_BACKEND = "rocksdb";
|
||||
TUWUNEL_DATABASE_PATH = dbPath;
|
||||
TUWUNEL_WELL_KNOWN = ''
|
||||
{
|
||||
client=https://${matrixHost}.blazestar.net,
|
||||
server=${matrixHost}.blazestar.net:443
|
||||
}
|
||||
'';
|
||||
TUWUNEL_TRUSTED_SERVERS = ''["matrix.org", "chat.havenisms.com"]'';
|
||||
};
|
||||
environmentFiles = [
|
||||
config.sops.templates."matrix-blazestar-net.env".path
|
||||
];
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${serviceName}.rule" = "Host(`${matrixHost}.${blazestar}`)";
|
||||
"traefik.http.services.${serviceName}.loadbalancer.server.port" = "${toString port}";
|
||||
|
||||
# Redirect well-known requests to this host.
|
||||
"traefik.http.routers.${matrixHost}-blazestar-net-well-known.rule" =
|
||||
"Host(`blazestar.net`) && PathPrefix(`/.well-known/matrix`)";
|
||||
"traefik.http.routers.${matrixHost}-blazestar-net-well-known.service" = serviceName;
|
||||
};
|
||||
};
|
||||
# virtualisation.oci-containers.containers.matrix-blazestar-net =
|
||||
# mkContainer {
|
||||
# image = "registry.gitlab.com/famedly/conduit/matrix-conduit:latest";
|
||||
# hostName = hostname;
|
||||
# domain = blazestar;
|
||||
# port = port;
|
||||
# ports = [
|
||||
# "8449:6167"
|
||||
# ];
|
||||
# volumes = [
|
||||
# "chat-blazestar-net-db:${dbPath}"
|
||||
# ];
|
||||
# environment = {
|
||||
# CONDUIT_PORT = "6167";
|
||||
# CONDUIT_SERVER_NAME = "blazestar.net";
|
||||
# CONDUIT_ALLOW_REGISTRATION = "true";
|
||||
# CONDUIT_DATABASE_BACKEND = "rocksdb";
|
||||
# CONDUIT_DATABASE_PATH = dbPath;
|
||||
# CONDUIT_ALLOW_CHECK_FOR_UPDATES = "true";
|
||||
# CONDUIT_ALLOW_FEDERATION = "true";
|
||||
# CONDUIT_MAX_REQUEST_SIZE = "20000000";
|
||||
# CONDUIT_TRUSTED_SERVERS = "[\"matrix.org\"]";
|
||||
# CONDUIT_MAX_CONCURRENT_REQUESTS = "100";
|
||||
# CONDUIT_WELL_KNOWN_CLIENT = "https://${hostname}.blazestar.net";
|
||||
# CONDUIT_WELL_KNOWN_SERVER = "${hostname}.blazestar.net:443";
|
||||
# CONDUIT_CONFIG = ""; # Ignore the config file
|
||||
# };
|
||||
# extraLabels = {
|
||||
# "traefik.http.routers.${hostname}-blazestar-net-well-known.rule" =
|
||||
# "Host(`blazestar.net`) && PathPrefix(`/.well-known`)";
|
||||
# "traefik.http.routers.${hostname}-blazestar-net-well-known.service" = "${hostname}-blazestar-net";
|
||||
# };
|
||||
# };
|
||||
virtualisation.oci-containers.containers.chat = mkContainer {
|
||||
image = "vectorim/element-web:latest";
|
||||
hostName = "chat";
|
||||
port = 8080;
|
||||
domain = blazestar;
|
||||
environment = {
|
||||
ELEMENT_WEB_PORT = "8080";
|
||||
};
|
||||
};
|
||||
}
|
||||
7
system/hosts/mcp/containers/blazestar.net/default.nix
Normal file
7
system/hosts/mcp/containers/blazestar.net/default.nix
Normal file
@@ -0,0 +1,7 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./chat.nix
|
||||
./uptime.nix
|
||||
];
|
||||
}
|
||||
15
system/hosts/mcp/containers/blazestar.net/uptime.nix
Normal file
15
system/hosts/mcp/containers/blazestar.net/uptime.nix
Normal file
@@ -0,0 +1,15 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) blazestar;
|
||||
in
|
||||
{
|
||||
virtualisation.web-containers.containers.uptime = {
|
||||
image = "louislam/uptime-kuma:1";
|
||||
hostname = "uptime";
|
||||
domain = blazestar;
|
||||
port = 3001;
|
||||
volumes = [
|
||||
"uptime-kuma:/app/data"
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ./lib.nix config) mkContainer mkMariaDbContainer havenisms;
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(mkMariaDbContainer {
|
||||
name = "bookstack";
|
||||
@@ -14,12 +15,12 @@ in {
|
||||
|
||||
sops.secrets = {
|
||||
bookstack_app_key = {
|
||||
restartUnits = [ "podman-bookstack.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-bookstack.service" ];
|
||||
mode = "0400";
|
||||
owner = config.users.users.bookstack.name;
|
||||
};
|
||||
bookstack_db = {
|
||||
restartUnits = [ "podman-bookstack-mariadb.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-bookstack-mariadb.service" ];
|
||||
mode = "0400";
|
||||
owner = config.users.users.bookstack.name;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,72 @@
|
||||
{ config, ... }:
|
||||
{ config, pkgs, ... }:
|
||||
let
|
||||
inherit (import ./lib.nix config) mkContainer localHostRule havenisms;
|
||||
inherit (import ./lib.nix config) mkContainer localHostRule terakoda;
|
||||
|
||||
nginxConf = pkgs.writeText "dm-companion-nginx.conf" ''
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
# error.log is symlinked to /dev/stderr
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
# access.log is symlinked to /dev/stdout
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
sendfile on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
gzip on;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name dm.blazestar.net;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
# X-Frame-Options is to prevent from clickJacking attack
|
||||
add_header X-Frame-Options SAMEORIGIN;
|
||||
|
||||
# disable content-type sniffing on some browsers.
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
|
||||
# This header enables the Cross-site scripting (XSS) filter
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
|
||||
add_header Referrer-Policy "no-referrer-when-downgrade";
|
||||
|
||||
# Enables response header of "Vary: Accept-Encoding"
|
||||
# This lets the cache have different entries depending on the encoding, e.g. compression
|
||||
gzip_vary on;
|
||||
|
||||
# Serve static files separately.
|
||||
location ~ ^/(robots.txt|manifest.json) {
|
||||
expires modified 1y;
|
||||
add_header Cache-Control "public";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
index index.html;
|
||||
expires -1;
|
||||
add_header Cache-Control "no-store, no-cache, must-revalidate";
|
||||
}
|
||||
}
|
||||
}
|
||||
'';
|
||||
in
|
||||
{
|
||||
virtualisation.oci-containers.containers = {
|
||||
@@ -11,25 +77,32 @@ in
|
||||
mkContainer {
|
||||
inherit hostName;
|
||||
image = "docker.havenisms.com/lazy-dm/pocketbase";
|
||||
domain = terakoda;
|
||||
port = 8080;
|
||||
volumes = [
|
||||
"dm-companion:/pb/pb_data"
|
||||
"/tank/web/dm.terakoda.com/pb_data:/pb/pb_data"
|
||||
"/tank/web/dm.terakoda.com/pb_migrations:/pb/pb_migrations:ro"
|
||||
];
|
||||
environment = { };
|
||||
extraLabels = {
|
||||
"traefik.http.routers.${hostName}-api.rule" =
|
||||
"PathPrefix(`/api`) && ${localHostRule "dm" havenisms}";
|
||||
"PathPrefix(`/api`) && ${localHostRule "dm" terakoda}";
|
||||
"traefik.http.routers.${hostName}-api.service" = "${hostName}";
|
||||
};
|
||||
};
|
||||
|
||||
dm-companion = mkContainer {
|
||||
image = "nginx:alpine";
|
||||
hostName = "dm";
|
||||
image = "docker.havenisms.com/lazy-dm/app";
|
||||
domain = terakoda;
|
||||
port = 80;
|
||||
dependsOn = [
|
||||
"dm-companion-pocketbase"
|
||||
];
|
||||
volumes = [ ];
|
||||
volumes = [
|
||||
"/tank/web/dm.terakoda.com/deployed:/usr/share/nginx/html:ro"
|
||||
"${nginxConf}:/etc/nginx/nginx.conf:ro"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ./lib.nix config) mkContainer mkPostgresContainer terakoda;
|
||||
in {
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(mkPostgresContainer {
|
||||
name = "focalboard";
|
||||
@@ -14,21 +15,26 @@ in {
|
||||
|
||||
sops.secrets = {
|
||||
"focalboard/database" = {
|
||||
restartUnits = [ "podman-focalboard.service" "podman-focalboard-postgres.service" ];
|
||||
restartUnits = [
|
||||
"${config.local.container-backend}-focalboard.service"
|
||||
"${config.local.container-backend}-focalboard-postgres.service"
|
||||
];
|
||||
mode = "0400";
|
||||
owner = config.users.users.focalboard.name;
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."focalboard-config.json" = {
|
||||
restartUnits = [ "podman-focalboard.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-focalboard.service" ];
|
||||
owner = config.users.users.focalboard.name;
|
||||
content = builtins.toJSON {
|
||||
# Defaults from https://github.com/mattermost-community/focalboard/blob/main/config.json
|
||||
"serverRoot" = "https://focalboard.terakoda.com";
|
||||
"port" = 8000;
|
||||
"dbtype" = "postgres";
|
||||
"dbconfig" = "postgres://focalboard:${config.sops.placeholder."focalboard/database"}@focalboard-postgres/focalboard?sslmode=disable&connect_timeout=10";
|
||||
"dbconfig" = "postgres://focalboard:${
|
||||
config.sops.placeholder."focalboard/database"
|
||||
}@focalboard-postgres/focalboard?sslmode=disable&connect_timeout=10";
|
||||
"useSSL" = true;
|
||||
"prometheus_address" = ":9092";
|
||||
"session_expire_time" = 2592000;
|
||||
|
||||
@@ -5,10 +5,10 @@ in
|
||||
{
|
||||
sops.secrets = {
|
||||
"gitea/db_password" = {
|
||||
restartUnits = [ "podman-gitea.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-gitea.service" ];
|
||||
};
|
||||
"gitea/registration_token" = {
|
||||
restartUnits = [ "podman-gitea-runner.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-gitea-runner.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -66,7 +66,7 @@ in
|
||||
];
|
||||
volumes = [
|
||||
# The runner will spawn new containers to run the actions
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock:ro"
|
||||
"${config.local.container-socket}:/var/run/docker.sock:ro"
|
||||
];
|
||||
};
|
||||
}
|
||||
|
||||
58
system/hosts/mcp/containers/goatcounter.nix
Normal file
58
system/hosts/mcp/containers/goatcounter.nix
Normal file
@@ -0,0 +1,58 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ./lib.nix config)
|
||||
terakoda
|
||||
blazestar
|
||||
hostRule
|
||||
;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
../../../features/web-containers.nix
|
||||
];
|
||||
|
||||
virtualisation.web-containers = {
|
||||
enable = true;
|
||||
containers = {
|
||||
goatcounter-terakoda = {
|
||||
image = "arp242/goatcounter";
|
||||
hostname = "goatcounter";
|
||||
domain = terakoda;
|
||||
public = true;
|
||||
port = 8080;
|
||||
volumes = [
|
||||
"goatcounter-data:/home/goatcounter/goatcounter-data"
|
||||
];
|
||||
extraLabels = {
|
||||
# "traefik.http.middlewares.strip-analytics.stripprefix.prefixes" = "/analytics";
|
||||
# "traefik.http.routers.www-terakoda-com-goatcounter.middlewares" = "strip-analytics";
|
||||
# Host the script on www.terakoda.com so that it is easy to fetch
|
||||
"traefik.http.routers.www-terakoda-com-goatcounter.rule" =
|
||||
"PathPrefix(`/count`) && ${hostRule "www" terakoda}";
|
||||
"traefik.http.routers.www-terakoda-com-goatcounter.entrypoints" = "websecure";
|
||||
"traefik.http.routers.www-terakoda-com-goatcounter.service" = "goatcounter-terakoda-com";
|
||||
};
|
||||
};
|
||||
|
||||
goatcounter-blazestar = {
|
||||
image = "arp242/goatcounter";
|
||||
hostname = "goatcounter";
|
||||
domain = blazestar;
|
||||
public = true;
|
||||
port = 8080;
|
||||
volumes = [
|
||||
"goatcounter-data-blazestar:/home/goatcounter/goatcounter-data"
|
||||
];
|
||||
extraLabels = {
|
||||
# "traefik.http.middlewares.strip-analytics.stripprefix.prefixes" = "/analytics";
|
||||
# "traefik.http.routers.www-blazestar-net-goatcounter.middlewares" = "strip-analytics";
|
||||
# Host the script on www.blazestar.net so that it is easy to fetch
|
||||
"traefik.http.routers.www-blazestar-net-goatcounter.rule" =
|
||||
"PathPrefix(`/count`) && ${hostRule "www" blazestar}";
|
||||
"traefik.http.routers.www-blazestar-net-goatcounter.entrypoints" = "websecure";
|
||||
"traefik.http.routers.www-blazestar-net-goatcounter.service" = "goatcounter-blazestar-net@docker";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
84
system/hosts/mcp/containers/havenisms.com/chat.nix
Normal file
84
system/hosts/mcp/containers/havenisms.com/chat.nix
Normal file
@@ -0,0 +1,84 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) hostRule havenisms;
|
||||
syncRule = "(PathPrefix(`/client/`) || PathPrefix(`/_matrix/client/unstable/org.matrix.msc3575/sync`))";
|
||||
wellKnownRule = "(Host(`havenisms.com`) || Host(`chat.havenisms.com`)) && PathPrefix(`/.well-known`)";
|
||||
in
|
||||
{
|
||||
|
||||
sops.secrets = {
|
||||
"matrix/syncv3/db-password" = {
|
||||
restartUnits = [ "${config.local.container-backend}-matrix-sliding-sync.service" ];
|
||||
};
|
||||
"matrix/syncv3/secret" = {
|
||||
restartUnits = [ "${config.local.container-backend}-matrix-sliding-sync.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."matrix-sliding-sync.env".content = ''
|
||||
SYNCV3_SERVER=http://synapse:8008
|
||||
SYNCV3_DB=postgres://syncv3:${
|
||||
config.sops.placeholder."matrix/syncv3/db-password"
|
||||
}@db:5432/syncv3?sslmode=disable
|
||||
SYNCV3_SECRET=${config.sops.placeholder."matrix/syncv3/secret"}
|
||||
SYNCV3_BINDADDR=:8009
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
synapse = {
|
||||
image = "docker.io/matrixdotorg/synapse:latest";
|
||||
autoStart = true;
|
||||
dependsOn = [
|
||||
"db"
|
||||
];
|
||||
|
||||
volumes = [
|
||||
"/tank/config/synapse/data:/data"
|
||||
];
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.synapse.rule=${hostRule "chat" havenisms} && !(${syncRule} || ${wellKnownRule})"
|
||||
"-l=traefik.http.routers.synapse.service=synapse"
|
||||
"-l=traefik.http.services.synapse.loadbalancer.server.port=8008"
|
||||
|
||||
# Federation forwarding
|
||||
"-l=traefik.http.routers.synapse-federation.rule=${hostRule "chat" havenisms}"
|
||||
"-l=traefik.http.routers.synapse-federation.service=synapse-federation"
|
||||
"-l=traefik.http.routers.synapse-federation.entrypoints=matrix-federation"
|
||||
"-l=traefik.http.services.synapse-federation.loadbalancer.server.port=8448"
|
||||
];
|
||||
};
|
||||
|
||||
matrix-sliding-sync = {
|
||||
image = "ghcr.io/matrix-org/sliding-sync:latest";
|
||||
dependsOn = [
|
||||
"db"
|
||||
"synapse"
|
||||
];
|
||||
environmentFiles = [
|
||||
config.sops.templates."matrix-sliding-sync.env".path
|
||||
];
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.syncv3.rule=${hostRule "chat" havenisms} && ${syncRule}"
|
||||
"-l=traefik.http.services.syncv3.loadbalancer.server.port=8009"
|
||||
];
|
||||
};
|
||||
|
||||
# This server helps to serve the .well-known files that are required by clients to find the sync server.
|
||||
matrix-well-known = {
|
||||
image = "nginx";
|
||||
dependsOn = [ "synapse" ];
|
||||
volumes = [
|
||||
"/tank/config/synapse/static-files:/usr/share/nginx/html:ro"
|
||||
];
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.middlewares.strip-well-known.stripprefix.prefixes=/.well-known"
|
||||
"-l=traefik.http.routers.matrix-well-known.rule=${wellKnownRule}"
|
||||
"-l=traefik.http.routers.matrix-well-known.middlewares=strip-well-known"
|
||||
"-l=traefik.http.services.matrix-well-known.loadbalancer.server.port=80"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
11
system/hosts/mcp/containers/havenisms.com/default.nix
Normal file
11
system/hosts/mcp/containers/havenisms.com/default.nix
Normal file
@@ -0,0 +1,11 @@
|
||||
{ ... }:
|
||||
{
|
||||
imports = [
|
||||
./chat.nix
|
||||
# Currently disabled because it doesn't start up properly
|
||||
# ./immich.nix
|
||||
./storyden.nix
|
||||
./tandoor.nix
|
||||
./wallabag.nix
|
||||
];
|
||||
}
|
||||
73
system/hosts/mcp/containers/havenisms.com/immich.nix
Normal file
73
system/hosts/mcp/containers/havenisms.com/immich.nix
Normal file
@@ -0,0 +1,73 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) havenisms mkPostgresContainer;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
(mkPostgresContainer {
|
||||
# Immich wants a custom build of postgres with the vectors extensions.
|
||||
image = "ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:c44be5f2871c59362966d71eab4268170eb6f5653c0e6170184e72b38ffdf107";
|
||||
name = "immich";
|
||||
directory = "/tank/immich/db";
|
||||
uid = config.users.users.immich.uid;
|
||||
gid = config.users.groups.immich.gid;
|
||||
passwordSecret = "immich/database";
|
||||
})
|
||||
];
|
||||
|
||||
sops.secrets = {
|
||||
"immich/database" = {
|
||||
restartUnits = [
|
||||
"${config.local.container-backend}-immich-db.service"
|
||||
];
|
||||
mode = "0400";
|
||||
owner = config.users.users.immich.name;
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."immich.env" = {
|
||||
restartUnits = [ "${config.local.container-backend}-immich.service" ];
|
||||
owner = config.users.users.immich.name;
|
||||
content = ''
|
||||
DB_HOSTNAME=immich-postgres
|
||||
DB_PASSWORD=${config.sops.placeholder."immich/database"}
|
||||
DB_USERNAME=immich
|
||||
DB_DATABASE_NAME=immich
|
||||
REDIS_HOSTNAME=immich-redis
|
||||
IMMICH_LOG_LEVEL=verbose
|
||||
'';
|
||||
};
|
||||
|
||||
virtualisation.web-containers.containers.immich = {
|
||||
image = "ghcr.io/immich-app/immich-server:release";
|
||||
hostname = "immich";
|
||||
domain = havenisms;
|
||||
port = 2283;
|
||||
volumes = [
|
||||
"/tank/photos/immich:/data"
|
||||
"/etc/localtime:/etc/localtime:ro"
|
||||
];
|
||||
dependsOn = [
|
||||
"immich-redis"
|
||||
"immich-postgres"
|
||||
];
|
||||
environmentFiles = [
|
||||
"${config.sops.templates."immich.env".path}"
|
||||
];
|
||||
};
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
"immich-redis" = {
|
||||
image = "docker.io/valkey/valkey";
|
||||
};
|
||||
"immich-machine-learning" = {
|
||||
image = "ghcr.io/immich-app/immich-machine-learning:release";
|
||||
volumes = [
|
||||
"model-cache:/cache"
|
||||
];
|
||||
environmentFiles = [
|
||||
"${config.sops.templates."immich.env".path}"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
17
system/hosts/mcp/containers/havenisms.com/storyden.nix
Normal file
17
system/hosts/mcp/containers/havenisms.com/storyden.nix
Normal file
@@ -0,0 +1,17 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) havenisms;
|
||||
in
|
||||
{
|
||||
|
||||
virtualisation.web-containers.containers.storyden = {
|
||||
image = "ghcr.io/southclaws/storyden";
|
||||
port = 8000;
|
||||
hostname = "storyden";
|
||||
domain = havenisms;
|
||||
environment = {
|
||||
PUBLIC_WEB_ADDRESS = "https://storyden.${havenisms}";
|
||||
PUBLIC_API_ADDRESS = "https://storyden.${havenisms}";
|
||||
};
|
||||
};
|
||||
}
|
||||
30
system/hosts/mcp/containers/havenisms.com/tandoor.nix
Normal file
30
system/hosts/mcp/containers/havenisms.com/tandoor.nix
Normal file
@@ -0,0 +1,30 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) havenisms;
|
||||
in
|
||||
{
|
||||
sops.secrets = {
|
||||
"tandoor/secret_key" = {
|
||||
restartUnits = [ "${config.local.container-backend}-tandoor.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."tandoor.env".content = ''
|
||||
SECRET_KEY="${config.sops.placeholder."tandoor/secret_key"}"
|
||||
DB_ENGINE=django.db.backends.sqlite3
|
||||
'';
|
||||
|
||||
virtualisation.web-containers.containers.tandoor = {
|
||||
image = "vabene1111/recipes";
|
||||
hostname = "recipes";
|
||||
domain = havenisms;
|
||||
port = 80;
|
||||
volumes = [
|
||||
"/tank/tandoor-recipes/mediafiles:/opt/recipes/mediafiles"
|
||||
"/tank/tandoor-recipes/staticfiles:/opt/recipes/staticfiles"
|
||||
];
|
||||
environmentFiles = [
|
||||
config.sops.templates."tandoor.env".path
|
||||
];
|
||||
};
|
||||
}
|
||||
19
system/hosts/mcp/containers/havenisms.com/wallabag.nix
Normal file
19
system/hosts/mcp/containers/havenisms.com/wallabag.nix
Normal file
@@ -0,0 +1,19 @@
|
||||
{ config, ... }:
|
||||
let
|
||||
inherit (import ../lib.nix config) havenisms;
|
||||
in
|
||||
{
|
||||
virtualisation.web-containers.containers.wallabag = {
|
||||
image = "wallabag/wallabag";
|
||||
hostname = "wallabag";
|
||||
domain = havenisms;
|
||||
port = 80;
|
||||
volumes = [
|
||||
"wallabag-data:/var/www/wallabag/data"
|
||||
"wallabag-images:/var/www/wallabag/web/assets/images"
|
||||
];
|
||||
environment = {
|
||||
SYMFONY__ENV__DOMAIN_NAME = "https://wallabag.${havenisms}";
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -70,8 +70,7 @@ in
|
||||
extraOptions
|
||||
;
|
||||
autoStart = true;
|
||||
labels =
|
||||
{
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${hostName}.rule" = "${routerRule}";
|
||||
"traefik.http.services.${hostName}.loadbalancer.server.port" = "${toString port}";
|
||||
@@ -127,11 +126,12 @@ in
|
||||
containerName ? "${name}-postgres",
|
||||
databaseName ? name,
|
||||
username ? name,
|
||||
image ? "postgres",
|
||||
}:
|
||||
{ config, ... }:
|
||||
{
|
||||
virtualisation.oci-containers.containers."${containerName}" = {
|
||||
image = "postgres";
|
||||
inherit image;
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
# Note that data must be mounted at this location to persist.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Common config for all mariadb containers
|
||||
{ ... }:
|
||||
{ config, ... }:
|
||||
{
|
||||
sops.secrets."mariadb_root_password" = {
|
||||
restartUnits = [ "podman-mariadb.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-mariadb.service" ];
|
||||
mode = "0440";
|
||||
group = "mariadb";
|
||||
};
|
||||
|
||||
@@ -6,12 +6,45 @@ let
|
||||
havenisms
|
||||
mkContainer
|
||||
;
|
||||
gluetun_env = "gluetun-proton-vpn-wireguard.env";
|
||||
in
|
||||
{
|
||||
|
||||
sops.secrets = {
|
||||
"protonvpn/private_key" = {
|
||||
restartUnits = [ "${config.local.container-backend}-gluetun.service" ];
|
||||
};
|
||||
};
|
||||
|
||||
# Example Wireguard config file:
|
||||
# # Key for MCP Wireguard
|
||||
# # Bouncing = 13
|
||||
# # NetShield = 1
|
||||
# # Moderate NAT = off
|
||||
# # NAT-PMP (Port Forwarding) = on
|
||||
# # VPN Accelerator = on
|
||||
# PrivateKey = ${config.sops.placeholder."protonvpn/private_key"}
|
||||
# Address = 10.2.0.2/32
|
||||
# DNS = 10.2.0.1
|
||||
#
|
||||
# [Peer]
|
||||
# # US-CA#906
|
||||
# PublicKey = 2xvxhMK0AalXOMq6Dh0QMVJ0Cl3WQTmWT5tdeb8SpR0=
|
||||
# AllowedIPs = 0.0.0.0/0, ::/0
|
||||
# Endpoint = 79.127.185.166:51820
|
||||
#
|
||||
# PersistentKeepalive = 25
|
||||
sops.templates.${gluetun_env}.content = ''
|
||||
VPN_SERVICE_PROVIDER=protonvpn
|
||||
VPN_TYPE=wireguard
|
||||
WIREGUARD_PRIVATE_KEY="${config.sops.placeholder."protonvpn/private_key"}"
|
||||
SERVER_COUNTRIES="United States,United Kingdom,Netherlands,Switzerland,Sweden"
|
||||
VPN_PORT_FORWARDING=on
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
jellyfin = {
|
||||
image = "lscr.io/linuxserver/jellyfin";
|
||||
image = "lscr.io/linuxserver/jellyfin:10.11.6";
|
||||
autoStart = true;
|
||||
extraOptions = [
|
||||
"--device=/dev/dri:/dev/dri"
|
||||
@@ -40,7 +73,7 @@ in
|
||||
# };
|
||||
};
|
||||
deluge = {
|
||||
image = "linuxserver/deluge:latest";
|
||||
image = "lscr.io/linuxserver/deluge:latest";
|
||||
autoStart = true;
|
||||
dependsOn = [
|
||||
"gluetun"
|
||||
@@ -62,7 +95,7 @@ in
|
||||
];
|
||||
};
|
||||
qbittorrent = {
|
||||
image = "linuxserver/qbittorrent:latest";
|
||||
image = "lscr.io/linuxserver/qbittorrent:latest";
|
||||
autoStart = true;
|
||||
dependsOn = [
|
||||
"gluetun"
|
||||
@@ -110,12 +143,8 @@ in
|
||||
"127.0.0.1:8083:8000"
|
||||
];
|
||||
environmentFiles = [
|
||||
"/tank/config/gluetun/vpn.env"
|
||||
config.sops.templates.${gluetun_env}.path
|
||||
];
|
||||
environment = {
|
||||
VPN_SERVICE_PROVIDER = "protonvpn";
|
||||
UMASK = "002";
|
||||
};
|
||||
};
|
||||
prowlarr = {
|
||||
image = "lscr.io/linuxserver/prowlarr";
|
||||
|
||||
@@ -4,7 +4,7 @@ let
|
||||
in
|
||||
{
|
||||
virtualisation.oci-containers.containers.nextcloud = {
|
||||
image = "docker.io/library/nextcloud:latest";
|
||||
image = "docker.io/library/nextcloud:31";
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.nextcloud.rule=${hostRule "cloud" havenisms}"
|
||||
@@ -20,13 +20,5 @@ in
|
||||
volumes = [
|
||||
"/tank/nextcloud:/var/www/html"
|
||||
];
|
||||
environment = {
|
||||
POSTGRES_HOST = "db";
|
||||
POSTGRES_DB = "nextcloud";
|
||||
POSTGRES_USER = "nextcloud";
|
||||
# TODO: Secrets
|
||||
POSTGRES_PASSWORD = "nextcloud123";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ in
|
||||
{
|
||||
sops.secrets = {
|
||||
"oauth2-proxy/cookie-secret" = {
|
||||
restartUnits = [ "podman-oauth2-proxy.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-oauth2-proxy.service" ];
|
||||
mode = "0400";
|
||||
};
|
||||
"oauth2-proxy/client-secret" = {
|
||||
restartUnits = [ "podman-oauth2-proxy.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-oauth2-proxy.service" ];
|
||||
mode = "0400";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
let
|
||||
inherit (import ./lib.nix config) mkContainer havenisms;
|
||||
hostName = "projects";
|
||||
in {
|
||||
in
|
||||
{
|
||||
|
||||
sops.secrets = {
|
||||
"openproject/secret-key-base" = {
|
||||
restartUnits = [ "podman-openproject.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-openproject.service" ];
|
||||
mode = "0400";
|
||||
owner = config.users.users.bookstack.name;
|
||||
};
|
||||
};
|
||||
|
||||
sops.templates."openproject.env" = {
|
||||
restartUnits = [ "podman-openproject.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-openproject.service" ];
|
||||
content = ''
|
||||
OPENPROJECT_SECRET_KEY_BASE=${config.sops.placeholder."openproject/secret-key-base"}
|
||||
OPENPROJECT_HOST__NAME=${hostName}.${havenisms}
|
||||
|
||||
@@ -7,53 +7,58 @@ let
|
||||
blazestar
|
||||
;
|
||||
mkStaticSite =
|
||||
host:
|
||||
{
|
||||
host,
|
||||
dir ? "public",
|
||||
redirectWww ? true,
|
||||
}:
|
||||
let
|
||||
cleanHost = lib.strings.stringAsChars (c: if c == "." then "-" else c) host;
|
||||
wwwLabels =
|
||||
if redirectWww then
|
||||
{
|
||||
"traefik.http.routers.${cleanHost}.middlewares" = "${cleanHost}-add-www@docker";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.regex" = "^https://${host}/(.*)";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.replacement" =
|
||||
"https://www.${host}/\${1}";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.permanent" = "true";
|
||||
|
||||
}
|
||||
else
|
||||
{ };
|
||||
in
|
||||
{
|
||||
"${cleanHost}-static" = {
|
||||
image = "nginx:alpine";
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"/tank/web/${host}/public:/usr/share/nginx/html:ro"
|
||||
"/tank/web/${host}/${dir}:/usr/share/nginx/html:ro"
|
||||
];
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${cleanHost}.rule" = "Host(`${host}`) || Host(`www.${host}`)";
|
||||
"traefik.http.routers.${cleanHost}.middlewares" = "${cleanHost}-add-www@docker";
|
||||
"traefik.http.services.${cleanHost}.loadbalancer.server.port" = "80";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.regex" = "^https://${host}/(.*)";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.replacement" =
|
||||
"https://www.${host}/\${1}";
|
||||
"traefik.http.middlewares.${cleanHost}-add-www.redirectregex.permanent" = "true";
|
||||
};
|
||||
} // wwwLabels;
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
virtualisation.oci-containers.containers =
|
||||
mkStaticSite terakoda
|
||||
// mkStaticSite havenisms
|
||||
// mkStaticSite blazestar
|
||||
// (
|
||||
let
|
||||
host = "www2.terakoda.com";
|
||||
cleanHost = lib.strings.stringAsChars (c: if c == "." then "-" else c) host;
|
||||
in
|
||||
{
|
||||
"${cleanHost}-static" = {
|
||||
image = "nginx:alpine";
|
||||
autoStart = true;
|
||||
volumes = [
|
||||
"/tank/web/www2.terakoda.com/dist:/usr/share/nginx/html:ro"
|
||||
];
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.${cleanHost}.rule" = "Host(`${host}`)";
|
||||
"traefik.http.services.${cleanHost}.loadbalancer.server.port" = "80";
|
||||
};
|
||||
};
|
||||
mkStaticSite {
|
||||
host = terakoda;
|
||||
dir = "deployed";
|
||||
}
|
||||
);
|
||||
// mkStaticSite {
|
||||
host = blazestar;
|
||||
dir = "deployed";
|
||||
}
|
||||
// mkStaticSite {
|
||||
host = "wow.${blazestar}";
|
||||
dir = "deployed";
|
||||
redirectWww = false;
|
||||
}
|
||||
// mkStaticSite {
|
||||
host = havenisms;
|
||||
dir = "public";
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
{ config, ... }:
|
||||
let inherit (import ./lib.nix config) hostRule havenisms;
|
||||
syncRule = "(PathPrefix(`/client/`) || PathPrefix(`/_matrix/client/unstable/org.matrix.msc3575/sync`))";
|
||||
wellKnownRule = "PathPrefix(`/.well-known`)";
|
||||
in
|
||||
{
|
||||
virtualisation.oci-containers.containers = {
|
||||
synapse = {
|
||||
image = "docker.io/matrixdotorg/synapse:latest";
|
||||
autoStart = true;
|
||||
dependsOn = [
|
||||
"db"
|
||||
];
|
||||
volumes = [
|
||||
"/tank/config/synapse/data:/data"
|
||||
];
|
||||
ports = [
|
||||
"8008:8008/tcp"
|
||||
];
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.synapse.rule=${hostRule "chat" havenisms} && !(${syncRule} || ${wellKnownRule})"
|
||||
"-l=traefik.http.services.synapse.loadbalancer.server.port=8008"
|
||||
];
|
||||
};
|
||||
matrix_sliding_sync = {
|
||||
image = "ghcr.io/matrix-org/sliding-sync:latest";
|
||||
dependsOn = ["db"];
|
||||
ports = [
|
||||
"8009:8009"
|
||||
];
|
||||
environment = {
|
||||
SYNCV3_SERVER = "http://synapse:8008";
|
||||
# TODO: Store password securely
|
||||
SYNCV3_DB = "postgres://syncv3:TZKr3RNmVx@db:5432/syncv3?sslmode=disable";
|
||||
# TODO: Store secret securely
|
||||
SYNCV3_SECRET = "4917590296b90910ec31ba355af6c7731409fd5f284d24912b852c3f928fa162";
|
||||
SYNCV3_BINDADDR = ":8009";
|
||||
};
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.syncv3.rule=${hostRule "chat" havenisms} && ${syncRule}"
|
||||
"-l=traefik.http.services.syncv3.loadbalancer.server.port=8009"
|
||||
];
|
||||
};
|
||||
# This server helps to serve the .well-known files that are required by clients to find the sync server.
|
||||
matrix_well_known = {
|
||||
image = "nginx";
|
||||
ports = [ "80" ];
|
||||
volumes = [
|
||||
"/tank/config/synapse/static-files:/usr/share/nginx/html:ro"
|
||||
];
|
||||
extraOptions = [
|
||||
"-l=traefik.enable=true"
|
||||
"-l=traefik.http.routers.matrix-static.rule=${hostRule "chat" havenisms} && ${wellKnownRule}"
|
||||
"-l=traefik.http.services.matrix-static.loadbalancer.server.port=80"
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -10,11 +10,11 @@ in
|
||||
|
||||
sops.secrets = {
|
||||
"traefik/oauth2-client-secret" = {
|
||||
restartUnits = [ "podman-traefik.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-traefik.service" ];
|
||||
mode = "0400";
|
||||
};
|
||||
"traefik/oauth2-plugin-secret" = {
|
||||
restartUnits = [ "podman-traefik.service" ];
|
||||
restartUnits = [ "${config.local.container-backend}-traefik.service" ];
|
||||
mode = "0400";
|
||||
};
|
||||
};
|
||||
@@ -25,14 +25,28 @@ in
|
||||
oidc-auth:
|
||||
plugin:
|
||||
traefik-oidc-auth:
|
||||
LogLevel: DEBUG
|
||||
Secret: "${config.sops.placeholder."traefik/oauth2-plugin-secret"}"
|
||||
CallbackUri: "https://auth.blazestar.net/oidc/callback"
|
||||
# Omitting the Callback URL means it will use the current domain for the callback.
|
||||
# CallbackUri: "https://oidc.blazestar.net/oidc/callback"
|
||||
Provider:
|
||||
Url: "https://auth.blazestar.net/"
|
||||
ClientId: "3e3f7d9a-a684-4412-866c-ea7281954a9f"
|
||||
ClientSecret: "${config.sops.placeholder."traefik/oauth2-client-secret"}"
|
||||
TokenValidation: "IdToken"
|
||||
UsePkce: false
|
||||
Scopes: ["openid", "profile", "email"]
|
||||
Headers:
|
||||
- Name: "X-Oidc-Username"
|
||||
Value: "{{`{{ .claims.preferred_username }}`}}"
|
||||
- Name: "X-Oidc-Email"
|
||||
Value: "{{`{{ .claims.email }}`}}"
|
||||
- Name: "X-Oidc-Subject"
|
||||
Value: "sub"
|
||||
- Name: "Authorization"
|
||||
Value: "{{`Bearer {{ .accessToken }}`}}"
|
||||
- Name: "IdToken"
|
||||
Value: "{{`Bearer {{ .idToken }}`}}"
|
||||
'';
|
||||
|
||||
virtualisation.oci-containers.containers.traefik = mkContainer {
|
||||
@@ -44,9 +58,10 @@ in
|
||||
ports = [
|
||||
"80:80"
|
||||
"443:443"
|
||||
"8448:8448"
|
||||
];
|
||||
volumes = [
|
||||
"/var/run/podman/podman.sock:/var/run/docker.sock:ro"
|
||||
"${config.local.container-socket}:/var/run/docker.sock:ro"
|
||||
# All the configs from the config directory
|
||||
"${traefikConfigDir}:/etc/traefik"
|
||||
# Oauth2 config containing secrets
|
||||
|
||||
@@ -13,6 +13,13 @@ entryPoints:
|
||||
certResolver: letsencrypt
|
||||
metrics:
|
||||
address: ":8082"
|
||||
asDefault: false
|
||||
matrix-federation:
|
||||
address: ":8448"
|
||||
asDefault: false
|
||||
http:
|
||||
tls:
|
||||
certResolver: letsencrypt
|
||||
|
||||
api:
|
||||
insecure: true
|
||||
@@ -39,9 +46,11 @@ metrics:
|
||||
entryPoint: "metrics"
|
||||
|
||||
# Plugins must be defined in static config
|
||||
# Configuration of the plugin is in traefik.nix because it contains secrets.
|
||||
# TODO: Convert this whole file to a template in Nix
|
||||
experimental:
|
||||
plugins:
|
||||
traefik-oidc-auth:
|
||||
moduleName: "github.com/sevensolutions/traefik-oidc-auth"
|
||||
version: "v0.11.0"
|
||||
version: "v0.13.0"
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{ pkgs, ... }: let
|
||||
{ pkgs, ... }:
|
||||
let
|
||||
systemUsers = {
|
||||
gitea = {
|
||||
uid = 2001;
|
||||
@@ -19,6 +20,7 @@
|
||||
home = "/tank/web";
|
||||
packages = [ pkgs.git ];
|
||||
};
|
||||
immich = 2009;
|
||||
};
|
||||
|
||||
mkUser = name: value: {
|
||||
@@ -27,25 +29,30 @@
|
||||
description = "System User for ${name}";
|
||||
group = "${name}";
|
||||
shell = value.shell or null;
|
||||
extraGroups = value.extraGroups or [];
|
||||
openssh.authorizedKeys.keys = value.authorizedKeys or [];
|
||||
extraGroups = value.extraGroups or [ ];
|
||||
openssh.authorizedKeys.keys = value.authorizedKeys or [ ];
|
||||
home = value.home or "/var/empty";
|
||||
packages = value.packages or [];
|
||||
packages = value.packages or [ ];
|
||||
};
|
||||
mkGroup = name: value: let
|
||||
mkGroup =
|
||||
name: value:
|
||||
let
|
||||
# 1. Value if int
|
||||
# 2. "gid" if present
|
||||
# 3. "uid"
|
||||
gid =
|
||||
if builtins.isInt value
|
||||
then value
|
||||
else if builtins.hasAttr "gid" value
|
||||
then value.gid
|
||||
else value.uid;
|
||||
in {
|
||||
if builtins.isInt value then
|
||||
value
|
||||
else if builtins.hasAttr "gid" value then
|
||||
value.gid
|
||||
else
|
||||
value.uid;
|
||||
in
|
||||
{
|
||||
inherit gid;
|
||||
};
|
||||
in {
|
||||
in
|
||||
{
|
||||
users.users = builtins.mapAttrs mkUser systemUsers;
|
||||
users.groups = (builtins.mapAttrs mkGroup systemUsers) // {
|
||||
# Legacy groups.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
../../authorized-keys.nix
|
||||
inputs.sops-nix.nixosModules.sops
|
||||
../../features/gc.nix
|
||||
../../features/printing.nix
|
||||
];
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
@@ -3,23 +3,39 @@ let
|
||||
gitKnownHosts = pkgs.writeText "known_hosts" ''
|
||||
[git.blazestar.net]:2222 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDSikNAZDAbdQ5TA6Eg95FBM3sdPfAfghG+n56akCal8XXV/vOnXgqfeDASfXVOu+PZqCHnpGTxsym7hf2naFC0enznhS2sqahdQKKcsHvSfyQxpYFYyB2Zp8YDbnbRNGl2SbnqOajzk1SxJrJ0fFXmfrRIMnGNz+uFtIqc+T52CM051nd5Gj3f9a8xCwg7hedvSCynobsW9IOCmCc9rZ99TRd+m0kO74pUbgVqLv/+aSuW40K1uCkKgyh6PQsmkZd5GY0URwoJvLZauZLSPxl6DEU6lYz8S/hPrTP/e6fOPZsavQBYC+3Q/akoFnY+qlKgWLQy/Om6hz0EfYuuzNPRhf1jaGKjHgEri1f3OMgXcRMvjovRgbbu0JRGANmN8FMe20S4AAvbxmsQdQci+QcXZPDPbcmT3XJv8e8p4HNQyLxHyh0u9dLBE2ccTv5gdf/6iZy6WXlYEf1UAKC2lExRuKBV3lrnuyHhOj+iL09gUMYFuIyHuX2Hsw9yKZbO8J2+STNIVQfAJ0Upa2cJ33a6RlOxGiHXi4UbZTPguNgQaQdM0CuklVTynBfWr1Hfd8c8hVtT+HLz+XOU2Nrmgq90/w7g7mo5JxXHkcfBlqlXKONTkDUG3KHbwKtQNVC6l3bhpvPc32Mys6e7JeWnrb1zXojopnPvoct54qDVlwc5xQ==
|
||||
'';
|
||||
testHook =
|
||||
migratePocketbase =
|
||||
with pkgs;
|
||||
writeShellScript "migrate-pocketbase" ''
|
||||
set -e
|
||||
|
||||
echo "Migrating in $(pwd) as $(id)"
|
||||
|
||||
${pkgs.pocketbase}/bin/pocketbase migrate up
|
||||
|
||||
echo "Migration complete"
|
||||
'';
|
||||
deployNpmApp =
|
||||
with pkgs;
|
||||
writeShellApplication {
|
||||
name = "deploy-astro-app";
|
||||
name = "build-npm-app";
|
||||
runtimeInputs = [
|
||||
openssh
|
||||
gitFull
|
||||
nodejs_22
|
||||
bashNonInteractive
|
||||
rsync
|
||||
];
|
||||
text = ''
|
||||
set -e
|
||||
id
|
||||
pwd
|
||||
|
||||
echo "Deploying in $(pwd) as $(id)"
|
||||
|
||||
OUTPUT_DIR="./$(date --utc --iso-8601=seconds)"
|
||||
|
||||
echo "Deploying into $OUTPUT_DIR"
|
||||
|
||||
export GIT_SSH_COMMAND='ssh -v -o "UserKnownHostsFile ${gitKnownHosts}" -i "${
|
||||
config.sops.secrets."deploy-key/terakoda.com".path
|
||||
config.sops.secrets."deploy-key/mcp".path
|
||||
}"'
|
||||
|
||||
# Disable astro telemetry otherwise it will try to write to `~/.config/astro/config.json`
|
||||
@@ -33,44 +49,100 @@ let
|
||||
|
||||
# Use a local cache with --cache .npm
|
||||
npm ci --cache .npm
|
||||
npm run build
|
||||
npm run build -- --outDir "$OUTPUT_DIR"
|
||||
|
||||
echo "Activating $OUTPUT_DIR"
|
||||
# Trailing slash on source to only copy contents, not the directory itself
|
||||
rsync --archive --delete "$OUTPUT_DIR"/ deployed
|
||||
echo "Deployment complete"
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
# [ ] Make sure the hook can operate on that directory
|
||||
# [ ] Run the build command
|
||||
|
||||
sops.secrets = {
|
||||
"deploy-key/terakoda.com" = {
|
||||
"deploy-key/mcp" = {
|
||||
restartUnits = [ "webhook.service" ];
|
||||
owner = config.users.users.webhook.name;
|
||||
};
|
||||
};
|
||||
|
||||
services.webhook = {
|
||||
services.webhook =
|
||||
let
|
||||
trigger-rule = {
|
||||
or = [
|
||||
# There were some issues getting the payload signature validation to work.
|
||||
# Switching to only accepting requests from internal IPs.
|
||||
# {
|
||||
# match = {
|
||||
# type = "payload-hmac-sha1";
|
||||
# secret = "mysecret";
|
||||
# parameter = {
|
||||
# source = "header";
|
||||
# name = "X-Hub-Signature";
|
||||
# };
|
||||
# };
|
||||
# }
|
||||
{
|
||||
match = {
|
||||
type = "ip-whitelist";
|
||||
ip-range = "192.168.0.0/16";
|
||||
};
|
||||
}
|
||||
{
|
||||
match = {
|
||||
type = "ip-whitelist";
|
||||
ip-range = "10.88.0.0/16";
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
enable = true;
|
||||
verbose = true;
|
||||
port = 9000;
|
||||
openFirewall = true;
|
||||
hooks = {
|
||||
"deploy-www2-terakoda-com" = {
|
||||
id = "deploy-www2-terakoda-com";
|
||||
"deploy-terakoda-com" = {
|
||||
id = "deploy-terakoda-com";
|
||||
http-methods = [ "POST" ];
|
||||
command-working-directory = "/tank/web/www2.terakoda.com";
|
||||
include-command-output-in-response = true;
|
||||
command-working-directory = "/tank/web/terakoda.com";
|
||||
include-command-output-in-response-on-error = true;
|
||||
execute-command = "${testHook}/bin/deploy-astro-app";
|
||||
trigger-rule = {
|
||||
match = {
|
||||
type = "payload-mac-sha256";
|
||||
secret = "test123";
|
||||
parameter = {
|
||||
source = "header";
|
||||
name = "X-Hub-Signature-256";
|
||||
execute-command = "${deployNpmApp}/bin/build-npm-app";
|
||||
trigger-rule-mismatch-http-response-code = 400;
|
||||
inherit trigger-rule;
|
||||
};
|
||||
"deploy-dm-terakoda-com" = {
|
||||
id = "deploy-dm-terakoda-com";
|
||||
http-methods = [ "POST" ];
|
||||
command-working-directory = "/tank/web/dm.terakoda.com";
|
||||
include-command-output-in-response-on-error = true;
|
||||
execute-command = toString (
|
||||
pkgs.writeShellScript "deploy-dm-terakoda-com" ''
|
||||
"${deployNpmApp}/bin/build-npm-app";
|
||||
"${migratePocketbase}";
|
||||
''
|
||||
);
|
||||
trigger-rule-mismatch-http-response-code = 400;
|
||||
inherit trigger-rule;
|
||||
};
|
||||
"deploy-blazestar-net" = {
|
||||
id = "deploy-blazestar-net";
|
||||
http-methods = [ "POST" ];
|
||||
command-working-directory = "/tank/web/blazestar.net";
|
||||
include-command-output-in-response-on-error = true;
|
||||
execute-command = "${deployNpmApp}/bin/build-npm-app";
|
||||
trigger-rule-mismatch-http-response-code = 400;
|
||||
inherit trigger-rule;
|
||||
};
|
||||
"deploy-wow-blazestar-net" = {
|
||||
id = "deploy-wow-blazestar-net";
|
||||
http-methods = [ "POST" ];
|
||||
command-working-directory = "/tank/web/wow.blazestar.net";
|
||||
include-command-output-in-response-on-error = true;
|
||||
execute-command = "${deployNpmApp}/bin/build-npm-app";
|
||||
trigger-rule-mismatch-http-response-code = 400;
|
||||
inherit trigger-rule;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -107,10 +107,16 @@
|
||||
};
|
||||
|
||||
# Enable flakes
|
||||
nix.settings.experimental-features = [
|
||||
nix = {
|
||||
# Binary caches for Reflex FRP
|
||||
binaryCaches = [ "https://nixcache.reflex-frp.org" ];
|
||||
binaryCachePublicKeys = [ "ryantrinkle.com-1:JJiAKaRv9mWgpVAz8dwewnZe0AzzEAzPkagE9SP5NWI=" ];
|
||||
|
||||
settings.experimental-features = [
|
||||
"nix-command"
|
||||
"flakes"
|
||||
];
|
||||
};
|
||||
|
||||
services.openssh.enable = true;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
{ pkgs, lib, ... }:
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
imports =
|
||||
map (x: ../../../home-manager + x) [
|
||||
"/features/chat.nix"
|
||||
"/features/development/development.nix"
|
||||
"/features/development/docker.nix"
|
||||
"/features/development/haskell.nix"
|
||||
@@ -9,6 +10,7 @@
|
||||
"/features/development/typescript.nix"
|
||||
"/features/development/vscode.nix"
|
||||
"/features/eww"
|
||||
"/features/image-editing.nix"
|
||||
"/features/linux-desktop.nix"
|
||||
"/features/notes.nix"
|
||||
]
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
modulesPath,
|
||||
...
|
||||
}:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/installer/scan/not-detected.nix")
|
||||
imports = [
|
||||
(modulesPath + "/installer/scan/not-detected.nix")
|
||||
../../features/graphics.nix
|
||||
];
|
||||
|
||||
# Bootloader.
|
||||
@@ -13,18 +19,26 @@
|
||||
boot.loader.grub.device = "/dev/sda";
|
||||
boot.loader.grub.useOSProber = true;
|
||||
|
||||
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ata_piix" "ahci" "usbhid" "usb_storage" "sd_mod" ];
|
||||
boot.initrd.availableKernelModules = [
|
||||
"xhci_pci"
|
||||
"ehci_pci"
|
||||
"ata_piix"
|
||||
"ahci"
|
||||
"usbhid"
|
||||
"usb_storage"
|
||||
"sd_mod"
|
||||
];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
fileSystems."/" =
|
||||
{ device = "/dev/disk/by-uuid/4981ad42-b108-4eb4-accb-b092813bd981";
|
||||
fileSystems."/" = {
|
||||
device = "/dev/disk/by-uuid/4981ad42-b108-4eb4-accb-b092813bd981";
|
||||
fsType = "ext4";
|
||||
};
|
||||
|
||||
swapDevices =
|
||||
[ { device = "/dev/disk/by-uuid/f8868dce-6b32-45b7-bdf3-c9a34df1441d"; }
|
||||
swapDevices = [
|
||||
{ device = "/dev/disk/by-uuid/f8868dce-6b32-45b7-bdf3-c9a34df1441d"; }
|
||||
];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
@@ -39,34 +53,6 @@
|
||||
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
|
||||
|
||||
# Graphics settings
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
|
||||
hardware.nvidia = {
|
||||
package = config.boot.kernelPackages.nvidiaPackages.beta;
|
||||
|
||||
modesetting.enable = true;
|
||||
|
||||
# Nvidia power management. Experimental, and can cause sleep/suspend to fail.
|
||||
# Enable this if you have graphical corruption issues or application crashes after waking
|
||||
# up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead
|
||||
# of just the bare essentials.
|
||||
powerManagement.enable = true;
|
||||
|
||||
# Fine-grained power management for PRIME. Turns off GPU when not in use.
|
||||
# Experimental and only works on modern Nvidia GPUs (Turing or newer).
|
||||
# Requires offload to be enabled.
|
||||
# powerManagement.finegrained = false;
|
||||
|
||||
# Use the open-source driver?
|
||||
open = false;
|
||||
|
||||
# Enable the nvidia-settings menu?
|
||||
nvidiaSettings = true;
|
||||
};
|
||||
|
||||
# Using the default production drivers.
|
||||
graphics.enable = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user