Add 'old-conf/' from commit '62a64a79a8'

git-subtree-dir: old-conf
git-subtree-mainline: 4667974392
git-subtree-split: 62a64a79a8
This commit is contained in:
Lucy Hochkamp 2025-11-21 13:33:06 +01:00
commit 83de52d5db
195 changed files with 13408 additions and 0 deletions

View file

@ -0,0 +1,199 @@
{ pkgs, inputs, lib, ... }:
with lib;
with lib.my;
{
system.stateVersion = 5;
ids.gids.nixbld = 30000;
users.users.xyno = {
name = "xyno";
home = "/Users/xyno";
};
homebrew = {
enable = true;
taps = [
"cormacrelf/tap" # dark-notify
"leoafarias/fvm" # flutter version manager
];
brews = [
"cormacrelf/tap/dark-notify"
"lima"
"docker" # docker cli
"docker-compose"
# "leoafarias/fvm/fvm" # flutter version manager
"cocoapods" # flutter/other ios shit
# "butane"
"borgbackup" # time machine can eat my ass
];
casks = [
"plexamp"
"vorta" # (borgbackup GUI) time machine can eat my ass
"grandperspective"
"xquartz"
"hammerspoon"
"kicad"
"android-platform-tools"
# "nheko"
"raycast"
"ukelele"
"imhex"
# "homebrew/cask-drivers/zsa-wally"
"thunderbird"
"balenaetcher"
"audacity"
"openlens"
# "ferdium"
"discord"
"vlc"
"rectangle"
"floorp"
# "space-capsule"
"iterm2"
"signal"
"eqmac"
"syncthing"
"android-studio"
# "temurin"
"whisky"
"dbeaver-community"
"rider" # I'm sorry
# "qutebrowser" # rly want to switch to it
# "dmenu-mac"
];
#masApps = {
# # Install Mac App Store apps (install them manually and then do `mas list` to get the id)
# "AdGuard for Safari" = 1440147259;
# "Xcode" = 497799835;
# "Home as Assistant" = 1099568401;
# "WireGuard" = 1451685025;
# "UTM" = 1538878817;
# "Bitwarden" = 1352778147;
# "Shareful" = 1522267256;
# "app.seashore" = 1448648921;
# "Tailscale" = 1475387142;
#};
};
nix.configureBuildUsers = true;
ids.uids.nixbld = lib.mkForce 400;
environment.pathsToLink = [ "/share/fish" ];
#ragon.services.borgmatic =
# let
# tmMountPath = "/tmp/timeMachineSnapshotForBorg";
# in
# {
# enable = false;
# configurations."daedalus-ds9" = {
# source_directories = [
# # tmMountPath
# "/Users/ragon"
# ];
# exclude_if_present = [ ".nobackup" ];
# repositories = [
# { path = "ssh://ragon@ds9/backups/daedalus/borgmatic"; label = "ds9"; }
# { path = "ssh://root@gatebridge/media/backup/daedalus"; label = "gatebridge"; }
# ];
# encryption_passcommand = pkgs.writeShellScript "getBorgmaticPw" ''security find-generic-password -a daedalus -s borgmaticKey -g 2>&1 | grep -E 'password' | sed 's/^.*"\(.*\)"$/\1/g' '';
# compression = "auto,zstd,10";
# #ssh_command = "ssh -o GlobalKnownHostsFile=${config.age.secrets.gatebridgeHostKeys.path} -i ${config.age.secrets.picardResticSSHKey.path}";
# keep_hourly = 24;
# keep_daily = 7;
# keep_weekly = 4;
# keep_monthly = 12;
# keep_yearly = 10;
# # before_backup = [
# # (pkgs.writeShellScript
# # "apfsSnapshot"
# # ''
# # tmutil localsnapshot
# # SNAPSHOT=$(tmutil listlocalsnapshots / | grep TimeMachine | tail -n 1)
# # mkdir -p "${tmMountPath}"
# # mount_apfs -s $SNAPSHOT /System/Volumes/Data "${tmMountPath}"
# # '')
# # ];
# # after_backup = [
# # (pkgs.writeShellScript
# # "apfsSnapshotUnmount"
# # ''
# # diskutil unmount "${tmMountPath}"
# # SNAPSHOT=$(tmutil listlocalsnapshots / | grep TimeMachine | tail -n 1)
# # tmutil deletelocalsnapshots $(echo $SNAPSHOT | sed 's/com\.apple\.TimeMachine\.\(.*\)\.local/\1/g')
# # '')
# # ];
# # on_error = [
# #
# # (pkgs.writeShellScript
# # "apfsSnapshotUnmountError"
# # ''
# # diskutil unmount "${tmMountPath}"
# # '')
# # ];
# };
# };
home-manager.users.xyno = { pkgs, lib, inputs, config, ... }:
{
imports = [
../../hm-modules/nvim
../../hm-modules/tmux
../../hm-modules/vscode
../../hm-modules/xonsh
../../hm-modules/helix
../../hm-modules/zellij
../../hm-modules/nushell
../../hm-modules/cli.nix
../../hm-modules/files.nix
];
home.file.".hammerspoon/init.lua".source =
let
notmuchMails = pkgs.writeScript "notmuch-get-mail-count" ''
#!/usr/bin/env zsh
printf "I%s F%s W%s" $(notmuch search tag:inbox | wc -l) $(notmuch search tag:follow-up | wc -l) $(notmuch search tag:waiting | wc -l)
'';
in
pkgs.substituteAll {
src = ./hammerspoon.lua; inherit notmuchMails;
};
home.file.".hammerspoon/Spoons/MiroWindowsManager.spoon".source = "${inputs.miro}/MiroWindowsManager.spoon";
ragon.vscode.enable = true;
ragon.helix.enable = true;
ragon.nushell.enable = true;
ragon.zellij.enable = true;
programs.home-manager.enable = true;
home.stateVersion = "23.11";
#home.shellAliases = {
# v = lib.mkForce "emacsclient -t";
# vv = lib.mkForce "emacsclient -c";
#};
home.sessionVariables = {
# EDITOR = "nvim";
# VISUAL = "nvim";
COLORTERM = "truecolor"; # emacs tty fix
};
home.packages = with pkgs; [
mosh
pandoc
tectonic
micromamba
bitwarden-cli
rustup
ffmpeg
];
};
}

View file

@ -0,0 +1,258 @@
----------------------------------------------------------------------------------------------------
-- Settings
----------------------------------------------------------------------------------------------------
hs.autoLaunch(true)
hs.automaticallyCheckForUpdates(true)
hs.consoleOnTop(true)
hs.dockIcon(false)
hs.menuIcon(false)
hs.uploadCrashData(false)
hs.window.animationDuration = 0
configWatcher = hs.pathwatcher.new(hs.configdir, hs.reload)
configWatcher:start()
local moonlanderMode = false
local maximizeMode = false
----------------------------------------------------------------------------------------------------
-- Utilities
----------------------------------------------------------------------------------------------------
local modifier = {
cmd = "cmd",
shift = "shift",
ctrl = "ctrl",
option = "alt",
}
local modifiers = {
hyper = { modifier.cmd, modifier.shift, modifier.ctrl, modifier.option },
window = { modifier.ctrl, modifier.option },
clipboard = { modifier.ctrl, modifier.cmd }
}
local bundleID = {
activityMonitor = "com.apple.ActivityMonitor",
finder = "com.apple.finder",
firefox = "org.mozilla.firefox",
emacs = "org.gnu.emacs",
iterm = "com.googlecode.iterm2",
orion = "com.kagi.kagimacOS",
safariTechnologyPreview = "com.apple.SafariTechnologyPreview",
spotify = "com.spotify.client",
bitwarden = "com.bitwarden.desktop",
teams = "com.microsoft.teams",
faclieThings = "com.electron.nativefier.facilethings-nativefier-cf88de",
timeular = "com.timeular.zei",
logseq = "com.electron.logseq"
}
local usbDevice = {
moonlander = "Moonlander Mark I"
}
local function languageIsGerman() return hs.host.locale.preferredLanguages()[1]:sub(0, 2) == "de" end
----------------------------------------------------------------------------------------------------
-- Menu
----------------------------------------------------------------------------------------------------
local function menuItems()
return {
{
title = "Hammerspoon " .. hs.processInfo.version,
disabled = true
},
{ title = "-" },
{
title = "Moonlander Mode",
checked = moonlanderMode,
fn = function() moonlanderDetected(not moonlanderMode) end
},
-- {
-- title = "Maximize Mode",
-- checked = maximizeMode,
-- fn = function() maximizeMode = not maximizeMode end
-- },
{ title = "-" },
{
title = "Reload",
fn = hs.reload
},
{
title = "Console...",
fn = hs.openConsole
},
{ title = "-" },
{
title = "Quit",
fn = function() hs.application.get(hs.processInfo.processID):kill() end
}
}
end
menu = hs.menubar.new()
menu:setMenu(menuItems)
----------------------------------------------------------------------------------------------------
-- Moonlander Detection
----------------------------------------------------------------------------------------------------
local moonlanderModeConfig = {
[false] = {
keyboardLayout = "Colemak DH ISO copy",
icon = hs.configdir .. "/assets/statusicon_off.tiff"
},
[true] = {
keyboardLayout = "EurKEY v1.2",
icon = hs.configdir .. "/assets/statusicon_on.tiff"
}
}
local function isDeviceMoonlander(device) return device.productName == usbDevice.moonlander end
function moonlanderDetected(connected)
moonlanderMode = connected
hs.keycodes.setLayout(moonlanderModeConfig[connected].keyboardLayout)
menu:setIcon(moonlanderModeConfig[connected].icon)
end
local function searchMoonlander()
local usbDevices = hs.usb.attachedDevices()
local moonlanderConnected = hs.fnutils.find(usbDevices, isDeviceMoonlander) ~= nil
moonlanderDetected(moonlanderConnected)
end
searchMoonlander()
usbWatcher = hs.usb.watcher.new(function(event)
if event.productName == usbDevice.moonlander then
moonlanderDetected(event.eventType == "added")
end
end)
usbWatcher:start()
caffeinateWatcher = hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.systemDidWake then
searchMoonlander()
end
end)
caffeinateWatcher:start()
----------------------------------------------------------------------------------------------------
-- Window Management
----------------------------------------------------------------------------------------------------
--hs.window.filter.ignoreAlways = {
-- ["Mail Web Content"] = true,
-- ["Mail-Webinhalt"] = true,
-- ["QLPreviewGenerationExtension (Finder)"] = true,
-- ["Reeder Web Content"] = true,
-- ["Reeder-Webinhalt"] = true,
-- ["Safari Web Content (Cached)"] = true,
-- ["Safari Web Content (Prewarmed)"] = true,
-- ["Safari Web Content"] = true,
-- ["Safari Technology Preview Web Content (Cached)"] = true,
-- ["Safari Technology Preview Web Content (Prewarmed)"] = true,
-- ["Safari Technology Preview Web Content"] = true,
-- ["Safari-Webinhalt (im Cache)"] = true,
-- ["Safari-Webinhalt (vorgeladen)"] = true,
-- ["Safari-Webinhalt"] = true,
-- ["Strongbox (Safari)"] = true,
--}
--windowFilter = hs.window.filter.new({
-- "App Store",
-- "Code",
-- "DataGrip",
-- "Firefox",
-- "Fork",
-- "Fotos",
-- "Google Chrome",
-- "Vivaldi",
-- "IntelliJ IDEA",
-- "Mail",
-- "Emacs",
-- "Microsoft Outlook",
-- "Microsoft Teams",
-- "Music",
-- "Musik",
-- "Photos",
-- "Postman",
-- "Reeder",
-- "Safari",
-- "Safari Technology Preview",
-- "Spotify",
-- "Strongbox",
-- "BitWarden",
-- "Logseq",
-- "Timeular",
-- "Tower",
--})
--windowFilter:subscribe({ hs.window.filter.windowCreated, hs.window.filter.windowFocused }, function(window)
-- if maximizeMode and window ~= nil and window:isStandard() and window:frame().h > 500 then
-- window:maximize()
-- end
--end)
----------------------------------------------------------------------------------------------------
-- Keyboard Shortcuts
----------------------------------------------------------------------------------------------------
-- function showHideBundleId(bundleId)
-- local focusedWindow = hs.window.focusedWindow()
-- if focusedWindow ~= nil and focusedWindow:application():bundleID() == bundleId then -- window is focused
-- focusedWindow:close() -- hide
-- else
-- hs.application.launchOrFocusByBundleID(bundleId)
-- hs.window.focusedWindow():centerOnScreen(hs.mouse.getCurrentScreen())
-- end
-- end
-- hs.loadSpoon("MiroWindowsManager")
-- hs.window.animationDuration = 0
-- spoon.MiroWindowsManager:bindHotkeys({
-- up = {modifiers.window, "up"},
-- right = {modifiers.window, "right"},
-- down = {modifiers.window, "down"},
-- left = {modifiers.window, "left"},
-- fullscreen = {modifiers.window, "return"},
-- nextscreen = {modifiers.hyper, "right"}
-- })
-- hs.hotkey.bind(modifiers.hyper, hs.keycodes.map.delete, function() hs.caffeinate.lockScreen() end)
-- hs.hotkey.bind(modifiers.hyper, "a", function() showHideBundleId(bundleID.activityMonitor) end)
-- hs.hotkey.bind(modifiers.hyper, "o", function() showHideBundleId(bundleID.orion) end)
-- hs.hotkey.bind(modifiers.hyper, "f", function() showHideBundleId(bundleID.faclieThings) end)
-- hs.hotkey.bind(modifiers.hyper, "p", function() showHideBundleId(bundleID.timeular) end)
-- hs.hotkey.bind(modifiers.hyper, "b", function() showHideBundleId(bundleID.bitwarden) end)
-- hs.hotkey.bind(modifiers.hyper, "t", function() showHideBundleId(bundleID.iterm) end)
----------------------------------------------------------------------------------------------------
-- Mouse Shortcuts
----------------------------------------------------------------------------------------------------
local function handleMouse4()
hs.eventtap.keyStroke({ modifier.cmd }, "left")
end
local function handleMouse5()
hs.eventtap.keyStroke({ modifier.cmd }, "right")
end
-- bind mouse3/4 to back and forward
mouseTap = hs.eventtap.new({ hs.eventtap.event.types.otherMouseDown }, function(event)
if event:getButtonState(3) then
handleMouse4()
return true
elseif event:getButtonState(4) then
handleMouse5()
return true
end
return false
end)
mouseTap:start()

View file

@ -0,0 +1,59 @@
{
config,
pkgs,
lib,
inputs,
...
}:
let
stateDir = "/var/lib/atticd2";
in
{
# imports = [ inputs.attic.nixosModules.atticd ];
ragon.agenix.secrets.ds9AtticEnv = { };
ragon.persist.extraDirectories = [
stateDir
];
systemd.services.atticd.serviceConfig.ReadWritePaths = [ stateDir ];
services.atticd = {
enable = true;
# Replace with absolute path to your environment file
environmentFile = config.age.secrets.ds9AtticEnv.path;
settings = {
listen = "[::]:8089";
database.url = "sqlite://${stateDir}/server.db?mode=rwc";
storage = {
type = "local";
path = "${stateDir}/storage";
};
jwt = { };
# Data chunking
#
# Warning: If you change any of the values here, it will be
# difficult to reuse existing chunks for newly-uploaded NARs
# since the cutpoints will be different. As a result, the
# deduplication ratio will suffer for a while after the change.
chunking = {
# The minimum NAR size to trigger chunking
#
# If 0, chunking is disabled entirely for newly-uploaded NARs.
# If 1, all NARs are chunked.
nar-size-threshold = 64 * 1024; # 64 KiB
# The preferred minimum size of a chunk, in bytes
min-size = 16 * 1024; # 16 KiB
# The preferred average size of a chunk, in bytes
avg-size = 64 * 1024; # 64 KiB
# The preferred maximum size of a chunk, in bytes
max-size = 256 * 1024; # 256 KiB
};
};
};
}

View file

@ -0,0 +1,91 @@
{
pkgs,
config,
lib,
inputs,
...
}:
let version = "2025.10.1"; in
{
imports = [
inputs.quadlet-nix.nixosModules.quadlet
];
ragon.agenix.secrets.ds9AuthentikEnv = { };
ragon.agenix.secrets.ds9AuthentikLdapEnv = { };
virtualisation.quadlet = {
containers = {
authentik-server.containerConfig.image = "ghcr.io/goauthentik/server:${version}";
authentik-server.containerConfig.exec = "server";
authentik-server.containerConfig.networks = [
"podman"
"db-net"
"authentik-net"
];
authentik-server.containerConfig.volumes = [
"authentik-media:/media"
"authentik-certs:/certs"
];
authentik-server.containerConfig.environments = {
AUTHENTIK_REDIS__HOST = "authentik-redis";
AUTHENTIK_POSTGRESQL__HOST = "postgres";
AUTHENTIK_POSTGRESQL__USER = "authentik";
AUTHENTIK_POSTGRESQL__NAME = "authentik";
};
authentik-server.serviceConfig.TimeoutStartSec = "60";
authentik-server.containerConfig.environmentFiles = [
config.age.secrets.ds9AuthentikEnv.path
];
authentik-worker.containerConfig.image = "ghcr.io/goauthentik/server:${version}";
authentik-worker.containerConfig.exec = "worker";
authentik-worker.containerConfig.networks = [
"podman"
"db-net"
"authentik-net"
];
authentik-worker.containerConfig.volumes = [
"authentik-media:/media"
"authentik-certs:/certs"
];
authentik-worker.containerConfig.environments = {
AUTHENTIK_REDIS__HOST = "authentik-redis";
AUTHENTIK_POSTGRESQL__HOST = "postgres";
AUTHENTIK_POSTGRESQL__USER = "authentik";
AUTHENTIK_POSTGRESQL__NAME = "authentik";
};
authentik-worker.containerConfig.environmentFiles = [
config.age.secrets.ds9AuthentikEnv.path
];
authentik-worker.serviceConfig.TimeoutStartSec = "60";
authentik-ldap.containerConfig.image = "ghcr.io/goauthentik/ldap:${version}";
authentik-ldap.containerConfig.networks = [
"podman"
"authentik-net"
];
authentik-ldap.containerConfig.environments = {
AUTHENTIK_HOST = "http://authentik-server:9000";
AUTHENTIK_INSECURE = "true";
};
authentik-ldap.containerConfig.environmentFiles = [
config.age.secrets.ds9AuthentikLdapEnv.path
];
authentik-ldap.serviceConfig.TimeoutStartSec = "60";
authentik-redis.containerConfig.image = "docker.io/library/redis:alpine";
authentik-redis.containerConfig.networks = [
"authentik-net"
];
authentik-redis.containerConfig.volumes = [ "authentik-redis:/data" ];
authentik-redis.serviceConfig.TimeoutStartSec = "60";
};
networks = {
authentik.networkConfig.ipv6 = true;
authentik.networkConfig.name = "authentik-net";
authentik.networkConfig.internal = true;
};
};
}

View file

@ -0,0 +1,49 @@
{ config, pkgs, lib, ... }: {
ragon.agenix.secrets."ds9OffsiteBackupSSH" = { };
ragon.agenix.secrets."ds9SyncoidHealthCheckUrl" = { };
ragon.agenix.secrets."gatebridgeHostKeys" = { };
ragon.agenix.secrets."borgmaticEncryptionKey" = { };
# Backup Target
users.users.picardbackup = {
createHome = false;
group = "users";
uid = 993;
home = "/backups/picard";
shell = "/run/current-system/sw/bin/bash";
isSystemUser = true;
openssh.authorizedKeys.keys = [
''command="${pkgs.borgbackup}/bin/borg serve --restrict-to-path /backups/picard/",restrict ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHvCF8KGgpF9O8Q7k+JXqZ5eMeEeTaMhCIk/2ZFOzXL0''
];
};
services.borgmatic = {
enable = true;
configurations."ds9-offsite" = {
source_directories = [ "/backups" "/data" "/persistent" ];
repositories = [{ label = "gatebridge"; path = "ssh://root@gatebridge/media/backup/ds9"; }];
exclude_if_present = [ ".nobackup" ];
#upload_rate_limit = "4000";
encryption_passcommand = "${pkgs.coreutils}/bin/cat ${config.age.secrets.borgmaticEncryptionKey.path}";
compression = "auto,zstd,10";
extra_borg_options = {
init = "--lock-wait 600";
create = "--lock-wait 600";
prune = "--lock-wait 600";
compact = "--lock-wait 600";
check = "--lock-wait 600";
};
ssh_command = "ssh -o ServerAliveInterval=10 -o ServerAliveCountMax=30 -o GlobalKnownHostsFile=${config.age.secrets.gatebridgeHostKeys.path} -i ${config.age.secrets.ds9OffsiteBackupSSH.path}";
before_actions = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.ds9SyncoidHealthCheckUrl.path})/start" ];
after_actions = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.ds9SyncoidHealthCheckUrl.path})" ];
on_error = [ "${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.ds9SyncoidHealthCheckUrl.path})/fail" ];
retention = {
keep_daily = 7;
keep_weekly = 3;
keep_monthly = 6;
keep_yearly = 2;
};
};
};
}

View file

@ -0,0 +1,467 @@
{
config,
pkgs,
lib,
...
}:
let
postgres-multi-db = pkgs.writeText "postgres-multiple-db.sh" ''
#!/usr/bin/env bash
set -eu
if [ -n "$POSTGRES_MULTIPLE_DATABASES" ]; then
echo "Multiple database creation requested: $POSTGRES_MULTIPLE_DATABASES"
(
for db in $(echo $POSTGRES_MULTIPLE_DATABASES | tr ',' ' '); do
echo "CREATE DATABASE $db;"
done
for user in $(echo $POSTGRES_MULTIPLE_DATABASES_USERS | tr ',' ' '); do
while IFS=":" read -r usr pw
do
echo "CREATE USER $usr PASSWORD '$pw';"
echo "GRANT ALL PRIVILEGES ON DATABASE \"$usr\" TO $usr;"
done <(echo $user)
done
) | psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER"
fi
'';
in
{
imports = [
./authentik.nix
];
networking.firewall.interfaces."podman+".allowedUDPPorts = [ 53 ];
networking.firewall.interfaces."podman+".allowedTCPPorts = [
12300
3001
];
fileSystems."/var/lib/containers" = {
device = "spool/safe/containers";
fsType = "zfs";
};
# plex
# networking.firewall = {
# allowedTCPPorts = [ 32400 3005 8324 32469 ];
# allowedUDPPorts = [ 1900 5353 32410 32412 32413 32414 ];
# };
# virtualisation.oci-containers.containers.plex = {
# image = "docker.io/plexinc/pms-docker";
# extraOptions = [ "--network=host" ];
# environment = {
# TZ = "Europe/Berlin";
# PLEX_UID = "1000";
# PLEX_GID = "100";
# };
# volumes = [
# "/data/media:/data/media"
# "plex-transcode:/transcode"
# "plex-db:/config"
# ];
# };
# postgres
boot.binfmt.emulatedSystems = [ "aarch64-linux" ];
ragon.agenix.secrets.ds9PostgresEnv = { };
systemd.services."podman-db-network" = {
script = ''
${pkgs.podman}/bin/podman network exists db-net || ${pkgs.podman}/bin/podman network create db-net --internal --ipv6
'';
};
virtualisation.oci-containers.containers.postgres = {
image = "docker.io/tensorchord/pgvecto-rs:pg16-v0.2.1";
extraOptions = [
"--network=db-net"
"--network=podman"
"--health-cmd"
"pg_isready -U postgres"
];
# dependsOn = [ "db-network" ];
environment = {
POSTGRES_INITDB_ARGS = "--data-checksums";
};
environmentFiles = [
config.age.secrets.ds9PostgresEnv.path
];
ports = [ "5432:5432" ];
volumes = [
"${postgres-multi-db}:/docker-entrypoint-initdb.d/create-multiple-postgresql-databases.sh"
"postgres:/var/lib/postgresql/data"
];
};
# immich
ragon.agenix.secrets.ds9ImmichEnv = { };
# systemd.services."podman-immich-network" = {
# script = ''
# echo "Creating immich network"
# ${pkgs.podman}/bin/podman network exists immich-net || ${pkgs.podman}/bin/podman network create immich-net --internal --ipv6
# echo "Created immich network"
# '';
# };
virtualisation.oci-containers.containers.immich-redis = {
image = "docker.io/valkey/valkey:7.2.6-alpine";
environment.TZ = "Europe/Berlin";
extraOptions = [
"--health-cmd"
"valkey-cli ping || exit 1"
"--network=immich-net"
];
environmentFiles = [
config.age.secrets.ds9ImmichEnv.path
];
# dependsOn = [ "immich-network" ];
};
virtualisation.oci-containers.containers.immich-server = {
user = "1000:100";
image = "ghcr.io/immich-app/immich-server:release";
extraOptions = [
"--network=podman"
"--network=immich-net"
"--network=db-net"
];
dependsOn = [
# "immich-network"
"immich-redis"
"postgres"
];
ports = [ "8765:3001" ];
volumes = [
"/data/immich:/usr/src/app/upload"
];
environment = {
IMICH_HOST = "0.0.0.0";
DB_HOSTNAME = "postgres";
REDIS_HOSTNAME = "immich-redis";
TZ = "Europe/Berlin";
};
environmentFiles = [
config.age.secrets.ds9ImmichEnv.path
];
};
virtualisation.oci-containers.containers.immich-machine-learning = {
user = "1000:100";
image = "ghcr.io/immich-app/immich-machine-learning:release";
extraOptions = [
"--network=immich-net"
"--network=db-net"
"--network=podman"
];
dependsOn = [
# "immich-network"
"immich-redis"
"postgres"
];
volumes = [
"immich-model-cache:/cache"
];
environment = {
DB_HOSTNAME = "postgres";
REDIS_HOSTNAME = "immich-redis";
TZ = "Europe/Berlin";
};
environmentFiles = [
config.age.secrets.ds9ImmichEnv.path
];
};
# navidrome
# virtualisation.oci-containers.containers.lms = {
# # don't tell mom
# # user = "1000:100";
# image = "epoupon/lms:latest";
# cmd = [ "/lms.conf" ];
# extraOptions = [ "--network=podman" ];
# volumes =
# let
# lmsConfig = pkgs.writeText "lms-config" ''
# original-ip-header = "X-Forwarded-For";
# behind-reverse-proxy = true;
# trusted-proxies =
# (
# "10.88.0.1"
# );
# authentication-backend = "http-headers";
# http-headers-login-field = "X-Webauth-User";
# '';
# in
# [
# "lightweight-music-server-data:/var/lms:rw"
# "${lmsConfig}:/lms.conf"
# "/data/media/beets/music:/music:ro"
# ];
# environment = { };
# };
# changedetection
systemd.services."podman-cd-network" = {
script = ''
${pkgs.podman}/bin/podman network exists cd-net || ${pkgs.podman}/bin/podman network create cd-net --internal --ipv6
'';
};
virtualisation.oci-containers.containers.changedetection = {
image = "ghcr.io/dgtlmoon/changedetection.io";
extraOptions = [
"--network=podman"
"--network=cd-net"
];
volumes = [
"changedetection-data:/datastore"
];
environment = {
PLAYWRIGHT_DRIVER_URL = "ws://changedetection-chrome:3000";
HIDE_REFERER = "true";
USE_X_SETTINGS = "1";
};
};
virtualisation.oci-containers.containers.changedetection-chrome = {
image = "dgtlmoon/sockpuppetbrowser:latest";
extraOptions = [
"--network=podman"
"--network=cd-net"
];
environment = {
SCREEN_WIDTH = "1920";
SCREEN_HEIGHT = "1024";
SCREEN_DEPTH = "16";
MAX_CONCURRENT_CHROME_PROCESSES = "10";
};
};
networking.firewall.interfaces."podman0".allowedTCPPorts = [ 9090 ];
virtualisation.oci-containers.containers.grafana = {
image = "grafana/grafana-oss:latest";
extraOptions = [
"--network=podman"
"--network=db-net"
];
volumes =
let
ini = pkgs.writeText "grafana.ini" ''
[users]
allow_sign_up = false
auto_assign_org = true
auto_assign_org_role = Viewer
[auth.proxy]
enabled = true
headers = Name:X-Authentik-Username Email:X-Authentik-Email Role:X-Grafana-Role
header_name = X-Authentik-Username
header_property = username
auto_sign_up = true
'';
in
[
"grafana-data:/var/lib/grafana"
"${ini}:/etc/grafana/grafana.ini"
];
environment = {
GF_SERVER_ROOT_URL = "https://grafana.hailsatan.eu/";
GF_INSTALL_PLUGINS = "";
GF_FEATURE_TOGGLES_ENABLE = "featureToggleAdminPage, regressionTransformation";
GF_FEATURE_MANAGEMENT_ALLOW_EDITING = "true";
};
};
virtualisation.oci-containers.containers.node-red = {
image = "nodered/node-red:latest";
extraOptions = [
"--network=podman"
"--network=db-net"
];
volumes = [
"nodered-data:/data"
];
};
virtualisation.oci-containers.containers.jellyfin = {
image = "jellyfin/jellyfin:latest";
user = "1000:100";
extraOptions = [
"--network=podman"
"--mount"
"type=bind,source=/data/media,destination=/media,ro=true,relabel=private"
"-p"
"127.0.0.1:8096:8096"
];
volumes = [
"jellyfin-config:/config"
"jellyfin-cache:/cache"
];
};
# archivebox
systemd.services."podman-archivebox-network" = {
script = ''
${pkgs.podman}/bin/podman network create archivebox-net --internal --ipv6 --ignore
'';
};
virtualisation.oci-containers.containers.archivebox = {
image = "archivebox/archivebox:dev";
environment = {
ALLOWED_HOSTS = "*"; # set this to the hostname(s) you're going to serve the site from!
CSRF_TRUSTED_ORIGINS = "https://archive.hailsatan.eu"; # you MUST set this to the server's URL for admin login and the REST API to work
REVERSE_PROXY_USER_HEADER = "X-Authentik-Username";
REVERSE_PROXY_WHITELIST = "10.88.0.1/32";
PUBLIC_INDEX = "False"; # set to False to prevent anonymous users from viewing snapshot list
PUBLIC_SNAPSHOTS = "False"; # set to False to prevent anonymous users from viewing snapshot content
PUBLIC_ADD_VIEW = "False"; # set to True to allow anonymous users to submit new URLs to archive
SEARCH_BACKEND_ENGINE = "sonic"; # tells ArchiveBox to use sonic container below for fast full-text search
SEARCH_BACKEND_HOST_NAME = "archivebox_sonic";
SEARCH_BACKEND_PASSWORD = "SomeSecretPassword";
};
extraOptions = [
"--network=archivebox-net"
"--network=podman"
];
volumes = [
"/data/media/archivebox:/data"
];
};
virtualisation.oci-containers.containers.archivebox_scheduler = {
image = "archivebox/archivebox:latest";
cmd = [
"schedule"
"--foreground"
"--update"
"--every=day"
];
environment = {
TIMEOUT = "120";
ALLOWED_HOSTS = "*"; # set this to the hostname(s) you're going to serve the site from!
CSRF_TRUSTED_ORIGINS = "https://archive.hailsatan.eu"; # you MUST set this to the server's URL for admin login and the REST API to work
PUBLIC_INDEX = "True"; # set to False to prevent anonymous users from viewing snapshot list
PUBLIC_SNAPSHOTS = "True"; # set to False to prevent anonymous users from viewing snapshot content
PUBLIC_ADD_VIEW = "False"; # set to True to allow anonymous users to submit new URLs to archive
SEARCH_BACKEND_ENGINE = "sonic"; # tells ArchiveBox to use sonic container below for fast full-text search
SEARCH_BACKEND_HOST_NAME = "archivebox_sonic";
SEARCH_BACKEND_PASSWORD = "SomeSecretPassword";
};
extraOptions = [
"--network=archivebox-net"
"--network=podman"
];
volumes = [
"/data/media/archivebox:/data"
];
};
virtualisation.oci-containers.containers.archivebox_sonic = {
image = "archivebox/sonic:latest";
environment = {
SEARCH_BACKEND_PASSWORD = "SomeSecretPassword";
};
extraOptions = [ "--network=archivebox-net" ];
volumes = [
"archivebox-sonic:/data"
];
};
# printer
virtualisation.oci-containers.containers.labello = {
image = "telegnom/labello:latest";
environment = {
LAB_PRINTER_DEVICE = "tcp://BRN008077572A96.lan:9100";
# LABELLO_DOWNLOAD_FONT = "yes";
};
extraOptions = [ "--network=podman" ];
volumes =
let
fonts = pkgs.runCommandNoCC "labello-fonts" { } ''
mkdir $out
cp ${pkgs.roboto}/share/fonts/truetype/* $out
cp ${pkgs.roboto-mono}/share/fonts/truetype/* $out
'';
in
[
"${fonts}:/opt/labello/fonts"
# "/nix/store:/nix/store"
];
};
virtualisation.oci-containers.containers.copyparty = {
image = "docker.io/copyparty/ac:latest";
extraOptions = [ "--network=podman" ];
ports = [ ];
volumes =
let
copypartyCfg = ''
[global]
xff-src: 10.88.0.1/24
idp-h-usr: X-Authentik-Username
idp-h-grp: X-Copyparty-Group
e2dsa # enable file indexing and filesystem scanning
e2ts # enable multimedia indexing
ansi # enable colors in log messages
re-maxage: 3600 # rescan every something
hist: /data/media/copyparty/cache
name: the gayest storage in the west
no-robots
shr: /shr
shr-adm: @admin
[/]
/data/media/copyparty/srv
accs:
A: @admin
r: *
[/dump]
/data/media/copyparty/srv/dump
flags:
dedup
accs:
A: @admin
w: *
[/pub]
/data/media/copyparty/srv/pub
flags:
dedup
accs:
A: @admin
rw: *
[/tv]
/data/media/tv
flags:
hist: /data/media/copyparty/hist/tv
accs:
r: *
[/movies]
/data/media/movies
flags:
hist: /data/media/copyparty/hist/movies
accs:
r: *
[/books]
/data/media/books
flags:
hist: /data/media/copyparty/hist/books
accs:
r: *
[/audiobooks]
/data/media/audiobooks
flags:
hist: /data/media/copyparty/hist/audiobooks
accs:
r: *
[/music]
/data/media/music
flags:
hist: /data/media/copyparty/hist/music
accs:
r: *
[/games]
/data/media/games
flags:
hist: /data/media/copyparty/hist/games
accs:
r: *
'';
cpp = pkgs.writeText "copyparty.conf" copypartyCfg;
in
[
"/data/media/tv:/data/media/tv:ro"
"/data/media/movies:/data/media/movies:ro"
"/data/media/audiobooks:/data/media/audiobooks:ro"
"/data/media/books:/data/media/books:ro"
"/data/media/games:/data/media/games:ro"
"/data/media/beets:/data/media/music:ro"
"/data/media/copyparty:/data/media/copyparty"
"/data/media/copyparty/cfg:/cfg"
"${cpp}:/cfg/copyparty.conf"
];
};
}

View file

@ -0,0 +1,495 @@
{
config,
inputs,
pkgs,
lib,
...
}:
let
pubkeys = import ../../data/pubkeys.nix;
caddy-with-plugins = import ./custom-caddy.nix { inherit pkgs; };
in
{
imports = [
./hardware-configuration.nix
./containers.nix
./backup.nix
./grist.nix
# ./plex.nix
./samba.nix
./paperless.nix
./maubot.nix
./woodpecker.nix
./attic.nix
./ytdl-sub.nix
./snipe-it.nix
./radicale.nix
./lms.nix
../../nixos-modules/networking/tailscale.nix
../../nixos-modules/services/docker.nix
../../nixos-modules/services/libvirt.nix
../../nixos-modules/services/msmtp.nix
# ../../nixos-modules/services/paperless.nix
# ../../nixos-modules/services/photoprism.nix
../../nixos-modules/services/samba.nix
../../nixos-modules/services/ssh.nix
../../nixos-modules/services/caddy
../../nixos-modules/system/agenix.nix
../../nixos-modules/system/fs.nix
../../nixos-modules/system/persist.nix
../../nixos-modules/system/security.nix
../../nixos-modules/user
];
# Don't Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
# power save stuffzies
services.udev.path = [ pkgs.hdparm ];
services.udev.extraRules = ''
ACTION=="add|change", KERNEL=="sd[a-z]", ATTRS{queue/rotational}=="1", RUN+="${pkgs.hdparm}/bin/hdparm -S 60 -B 100 /dev/%k"
'';
services.syncthing.enable = true;
services.syncthing.user = "ragon";
programs.mosh.enable = true;
security.sudo.wheelNeedsPassword = false;
networking.useDHCP = true;
networking.useNetworkd = true;
systemd.network.networks."enp1s0f1".ipv6AcceptRAConfig = {
Token = "prefixstable";
};
networking.bridges."br0".interfaces = [ ];
networking.hostId = "7b4c2932";
networking.firewall.allowedTCPPorts = [
9000
25565
80
443
];
networking.firewall.allowedUDPPorts = [ 443 ]; # http3 :3
boot.initrd.network = {
enable = true;
postCommands = ''
zpool import rpool
zpool import spool
echo "zfs load-key -a; killall zfs" >> /root/.profile
'';
ssh = {
enable = true;
port = 2222;
hostKeys = [
"/persistent/etc/nixos/secrets/initrd/ssh_host_rsa_key"
"/persistent/etc/nixos/secrets/initrd/ssh_host_ed25519_key"
];
authorizedKeys = pubkeys.ragon.computers;
};
};
boot.kernel.sysctl."fs.inotify.max_user_instances" = 512;
# Immutable users due to tmpfs
users.mutableUsers = false;
# users.users.nia = {
# createHome = true;
# isNormalUser = true;
# extraGroups = [
# "docker"
# "podman"
# "wheel"
# ];
# openssh.authorizedKeys.keys = [
# "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDq+jk1Bi8/x0lYDiVi/iVnp9nEleocoQ+xHmlpDt9Qs"
# ];
# };
users.users.bzzt = {
description = "bzzt server service user";
home = "/var/lib/bzzt";
createHome = true;
isSystemUser = true;
group = "bzzt";
};
users.groups.bzzt = { };
users.users.minecraft = {
description = "Minecraft server service user";
home = "/var/lib/minecraft";
createHome = true;
isSystemUser = true;
group = "minecraft";
};
users.groups.minecraft = { };
environment.systemPackages = [
pkgs.jdk17
pkgs.borgbackup
pkgs.beets
];
services.smartd = {
enable = true;
extraOptions = [ "--interval=7200" ];
notifications.test = true;
};
services.zfs.zed.enableMail = true;
services.zfs.zed.settings = {
ZED_EMAIL_ADDR = [ "root" ];
ZED_EMAIL_PROG = "${pkgs.msmtp}/bin/msmtp";
ZED_EMAIL_OPTS = "@ADDRESS@";
ZED_NOTIFY_INTERVAL_SECS = 7200;
ZED_NOTIFY_VERBOSE = true;
ZED_USE_ENCLOSURE_LEDS = false;
ZED_SCRUB_AFTER_RESILVER = true;
};
# dyndns
systemd.services."dyndns-refresh" = {
script = ''
set -eu
export PATH=$PATH:${pkgs.curl}/bin:${pkgs.jq}/bin:${pkgs.iproute2}/bin
${pkgs.bash}/bin/bash ${config.age.secrets.ds9DynDns.path}
'';
serviceConfig = {
Type = "oneshot";
User = "root";
};
startAt = "*:0/10";
};
# services.tailscaleAuth.enable = true;
# services.tailscaleAuth.group = config.services.caddy.group;
systemd.services.caddy.serviceConfig.EnvironmentFile = config.age.secrets.desec.path;
services.caddy = {
# ragon.services.caddy is enabled
extraConfig = ''
(blockBots) {
@botForbidden header_regexp User-Agent "(?i)AdsBot-Google|Amazonbot|anthropic-ai|Applebot|Applebot-Extended|AwarioRssBot|AwarioSmartBot|Bytespider|CCBot|ChatGPT|ChatGPT-User|Claude-Web|ClaudeBot|cohere-ai|DataForSeoBot|Diffbot|FacebookBot|Google-Extended|GPTBot|ImagesiftBot|magpie-crawler|omgili|Omgilibot|peer39_crawler|PerplexityBot|YouBot"
handle @botForbidden {
redir https://hil-speed.hetzner.com/10GB.bin
}
handle /robots.txt {
respond <<TXT
User-Agent: *
Disallow: /
TXT 200
}
}
(podmanRedir) {
reverse_proxy {args[:]} {
transport http {
resolvers 10.88.0.1 # podman dns
}
}
}
(podmanRedirWithAuth) {
route {
# always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* http://authentik-server:9000 {
transport http {
resolvers 10.88.0.1 # podman dns
}
}
forward_auth http://authentik-server:9000 {
transport http {
resolvers 10.88.0.1 # podman dns
}
uri /outpost.goauthentik.io/auth/caddy
copy_headers {
X-Authentik-Username
X-Copyparty-Group
X-Authentik-Groups
X-Authentik-Entitlements
X-Authentik-Email
X-Authentik-Name
X-Authentik-Uid
X-Authentik-Jwt
X-Authentik-Meta-Jwks
X-Authentik-Meta-Outpost
X-Authentik-Meta-Provider
X-Authentik-Meta-App
X-Authentik-Meta-Version
X-Grafana-Role
X-Authentik-Username>X-Remote-User
}
}
reverse_proxy {args[:]} {
transport http {
resolvers 10.88.0.1 # podman dns
}
}
}
}
'';
globalConfig = ''
acme_ca https://acme-v02.api.letsencrypt.org/directory # hard coded so zerossl doesn't get used
acme_dns desec {
token "{$TOKEN}"
}
metrics {
per_host
}
servers {
trusted_proxies static 100.96.45.2/32 fd7a:115c:a1e0:ab12:4843:cd96:6260:2d02/128
}
'';
virtualHosts."*.hailsatan.eu ".logFormat = ''
output file ${config.services.caddy.logDir}/access-*hailsatan.eu_internet.log
'';
virtualHosts."*.hailsatan.eu ".extraConfig = ''
import blockBots
@blog host blog.hailsatan.eu
handle @blog {
route {
# always forward outpost path to actual outpost
reverse_proxy /outpost.goauthentik.io/* http://authentik-server:9000 {
transport http {
resolvers 10.88.0.1 # podman dns
}
}
forward_auth http://authentik-server:9000 {
transport http {
resolvers 10.88.0.1 # podman dns
}
uri /outpost.goauthentik.io/auth/caddy
copy_headers X-Authentik-Username X-Copyparty-Group X-Authentik-Groups X-Authentik-Entitlements X-Authentik-Email X-Authentik-Name X-Authentik-Uid X-Authentik-Jwt X-Authentik-Meta-Jwks X-Authentik-Meta-Outpost X-Authentik-Meta-Provider X-Authentik-Meta-App X-Authentik-Meta-Version X-Grafana-Role
}
root * /srv/www/xynospace
file_server
}
}
@jellyfin host j.hailsatan.eu
handle @jellyfin {
handle /metrics* {
abort
}
import podmanRedir http://jellyfin:8096
}
@mautrix-signal host mautrix-signal.hailsatan.eu
handle @mautrix-signal {
import podmanRedir http://mautrix-signal:29328
}
@woodpecker host woodpecker.hailsatan.eu
handle @woodpecker {
import podmanRedir http://woodpecker-server:8000
}
@attic host attic.hailsatan.eu
handle @attic {
reverse_proxy http://[::1]:8089
}
@auth host auth.hailsatan.eu
handle @auth {
import podmanRedir http://authentik-server:9000
}
@radicale host radicale.hailsatan.eu
handle @radicale {
import podmanRedirWithAuth http://[::1]:5232
}
@grafana host grafana.hailsatan.eu
handle @grafana {
import podmanRedirWithAuth http://grafana:3000
}
@lms host lms.hailsatan.eu
handle @lms {
handle /rest* {
import podmanRedir http://localhost:5082
}
import podmanRedirWithAuth http://localhost:5082
}
@immich host immich.hailsatan.eu
handle @immich {
import podmanRedir http://immich-server:2283
}
@cd host cd.hailsatan.eu
handle @cd {
import podmanRedirWithAuth http://changedetection:5000
}
@node-red host node-red.hailsatan.eu
handle @node-red {
import podmanRedirWithAuth http://node-red:1880
}
@labello host labello.hailsatan.eu
handle @labello {
import podmanRedirWithAuth http://labello:4242
}
@paperless host paperless.hailsatan.eu
handle @paperless {
import podmanRedirWithAuth http://paperless-server:8000
}
@archivebox host archivebox.hailsatan.eu
handle @archivebox {
handle /api/* {
import podmanRedir http://archivebox:8000
}
handle {
import podmanRedirWithAuth http://archivebox:8000
}
}
@grist host grist.hailsatan.eu
handle @grist {
import podmanRedir http://grist:8484
}
@snipe-it host snipe-it.hailsatan.eu
handle @snipe-it {
root * ${pkgs.snipe-it}/share/php/snipe-it/public
php_fastcgi unix//${config.services.phpfpm.pools."snipe-it".socket}
file_server
}
@copyparty host c.hailsatan.eu
handle @copyparty {
# @proxy {
# header_regexp Cookie authentik_proxy_([a-zA-Z0-9])
# }
# handle @proxy {
# import podmanRedirWithAuth http://copyparty:3923
# }
handle /shr/* {
import podmanRedir http://copyparty:3923
}
handle /.cpr/* {
import podmanRedir http://copyparty:3923
}
# @noauth {
# path_regexp ^\/(noauth(\/.*|)|[a-z.]+\.(css|js)|[1-9].png)$
# }
# @getoptionshead {
# method GET OPTIONS HEAD
# }
# handle @noauth {
# handle @getoptionshead {
# import podmanRedir http://copyparty:3923
# }
# }
handle {
import podmanRedirWithAuth http://copyparty:3923
}
}
handle {
import podmanRedirWithAuth http://127.0.0.1:8001
}
'';
};
services.prometheus = {
enable = true;
exporters.node = {
enable = true;
enabledCollectors = [ "systemd" ];
};
exporters.postgres = {
enable = true;
environmentFile = config.age.secrets.ds9PostgresExporterEnv.path;
};
scrapeConfigs = [
{
job_name = "postgres";
static_configs = [
{
targets = [
"localhost:${toString config.services.prometheus.exporters.postgres.port}"
"picard.kangaroo-galaxy.ts.net:${toString config.services.prometheus.exporters.postgres.port}"
];
}
];
}
{
job_name = "caddy";
static_configs = [
{
targets = [
"localhost:2019"
"picard.kangaroo-galaxy.ts.net:2019"
];
}
];
}
{
job_name = "node";
static_configs = [
{
targets = [
"localhost:${toString config.services.prometheus.exporters.node.port}"
"picard.kangaroo-galaxy.ts.net:${toString config.services.prometheus.exporters.node.port}"
];
}
];
}
];
};
home-manager.users.ragon =
{
pkgs,
lib,
inputs,
config,
...
}:
{
imports = [
# ../../hm-modules/nvim
../../hm-modules/helix
# ../../hm-modules/zsh
../../hm-modules/tmux
# ../../hm-modules/xonsh
../../hm-modules/cli.nix
../../hm-modules/files.nix
];
# ragon.xonsh.enable = true;
programs.home-manager.enable = true;
home.stateVersion = "23.11";
};
# begin kube
# services.k3s = {
# enable = true;
# extraFlags = "--disable=traefik --cluster-cidr 10.42.0.0/16,2001:cafe:42::/56 --service-cidr=10.43.0.0/16,2001:cafe:43::/112 --vpn-auth-file=/persistent/tailscale-auth-file";
#};
# systemd.services.k3s.path = [pkgs.tailscale pkgs.coreutils pkgs.bash];
# end kube
ragon = {
agenix.secrets."desec" = { };
agenix.secrets."ds9DynDns" = { };
agenix.secrets."ds9PostgresExporterEnv" = { };
user.enable = true;
persist.enable = true;
persist.extraDirectories = [
"/home/nia"
"/var/lib/syncthing"
"/var/lib/minecraft"
"/var/lib/bzzt"
"/var/lib/rancher"
"/etc/rancher"
"/root/.cache"
"/srv/www"
"/var/lib/${config.services.prometheus.stateDir}"
];
services = {
caddy.enable = true;
docker.enable = true;
ssh.enable = true;
msmtp.enable = true;
# photoprism.enable = true;
tailscale.enable = true;
tailscale.exitNode = true;
tailscale.extraUpCommands = "--advertise-routes=10.0.0.0/16";
# libvirt.enable = true;
# paperless.enable = true;
};
};
}

View file

@ -0,0 +1,34 @@
{
pkgs,
config,
lib,
...
}:
{
ragon.agenix.secrets.ds9GristEnv = { };
virtualisation.quadlet = {
containers.grist = {
containerConfig = {
image = "docker.io/gristlabs/grist-oss";
networks = [
"podman"
"db-net"
];
volumes = [
"grist:/persist"
];
environments = {
GRIST_SANDBOX_FLAVOR = "gvisor";
APP_HOME_URL = "https://grist.hailsatan.eu";
GRIST_FORCE_LOGIN = "true";
GRIST_TELEMETRY_LEVEL = "off";
GRIST_ALLOW_AUTOMATIC_VERSION_CHECKING = "false";
};
addCapabilities = [ "SYS_PTRACE" ];
environmentFiles = [
config.age.secrets.ds9GristEnv.path
];
};
};
};
}

View file

@ -0,0 +1,57 @@
# 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, ... }:
{
imports = [ "${modulesPath}/installer/scan/not-detected.nix" ];
boot.initrd.availableKernelModules = [ "r8169" "ahci" "vfio-pci" "xhci_pci" "ehci_pci" "nvme" "usbhid" "sd_mod" "sr_mod" ];
boot.kernelModules = [ "kvm-amd" ];
nix.settings.max-jobs = lib.mkDefault 12;
powerManagement.powertop.enable = true;
powerManagement.cpuFreqGovernor = "powersave";
powerManagement.scsiLinkPolicy = "min_power";
services.zfs.autoScrub.enable = true;
ragon.system.fs = {
enable = true;
mediadata = false;
swap = false;
persistentSnapshot = false;
nix = "spool/local/nix";
varlog = "spool/local/journal";
persistent = "spool/safe/persist";
arcSize = 16;
};
services.sanoid.datasets."rpool/content/safe/data/media" = { };
services.sanoid.enable = true;
services.sanoid.interval = "0/8:00:00";
swapDevices = [{ device = "/dev/disk/by-id/nvme-eui.000000000000000100a075202c247839-part1"; randomEncryption = true; }];
fileSystems."/boot".device = "/dev/disk/by-uuid/149F-23AA";
fileSystems."/data" = {
device = "rpool/content/safe/data";
fsType = "zfs";
};
fileSystems."/data/media" = {
device = "rpool/content/safe/data/media";
fsType = "zfs";
};
fileSystems."/backups/DaedalusTimeMachine" = {
device = "rpool/content/local/backups/daedalus";
fsType = "zfs";
};
fileSystems."/backups" = {
device = "rpool/content/local/backups";
fsType = "zfs";
};
# fileSystems."/data/media/nzbr" = {
# device = "10.0.1.2:/storage/media";
# fsType = "nfs";
# options = [ "x-systemd.automount" "noauto" ];
# };
}

101
old-conf/hosts/ds9/lms.nix Normal file
View file

@ -0,0 +1,101 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib) concatStringsSep concatMapStringsSep mapAttrsToList;
lmsConfig = {
api-subsonic-support-user-password-auth = true;
behind-reverse-proxy = true;
authentication-backend = "http-headers";
http-headers-login-field = "X-Remote-User";
working-dir = "/var/lib/lms";
scanner-skip-duplicate-mbid = true;
ffmpeg-file = "${pkgs.ffmpeg-full}/bin/ffmpeg";
wt-resources = "${pkgs.wt}/share/Wt/resources";
docroot = "${pkgs.lms}/share/lms/docroot/;/resources,/css,/images,/js,/favicon.ico";
approot = "${pkgs.lms}/share/lms/approot";
# log-min-severity = "debug";
trusted-proxies = ["127.0.0.1" "::1"];
# db-show-queries = true;
};
writeVal =
x:
if builtins.typeOf x == "string" then
''"${x}"''
else if builtins.typeOf x == "list" then
''(${(concatMapStringsSep ",\n" writeVal x)})''
else if builtins.typeOf x == "bool" then
(if x then "true" else "false")
else
(writeVal (toString x));
lmsConfigFile = pkgs.writeText "lms.conf" (
(concatStringsSep "\n" (mapAttrsToList (n: v: "${n} = ${writeVal v};") lmsConfig)) + "\n"
);
in
{
systemd.services.lms = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
environment.OMP_THREAD_LIMIT = "1";
serviceConfig = {
DynamicUser = true;
ExecStart = ''
${pkgs.lms}/bin/lms ${lmsConfigFile}
'';
Group = "users";
StateDirectory = "lms";
RuntimeDirectory = "lms";
WorkingDirectory = "/var/lib/lms";
RootDirectory = "/run/lms";
ReadWritePaths = "";
BindReadOnlyPaths = [
"${config.security.pki.caBundle}:/etc/ssl/certs/ca-certificates.crt"
builtins.storeDir
"/etc"
"/data/media/beets/music"
]
++ lib.optionals config.services.resolved.enable [
"/run/systemd/resolve/stub-resolv.conf"
"/run/systemd/resolve/resolv.conf"
];
CapabilityBoundingSet = "";
RestrictAddressFamilies = [
"AF_UNIX"
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
RestrictRealtime = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
UMask = "0066";
ProtectHostname = true;
};
};
ragon.persist.extraDirectories = [
{
directory = "/var/lib/private/lms";
mode = "0700";
defaultPerms.mode = "0700";
}
];
}

View file

@ -0,0 +1,25 @@
{
config,
pkgs,
lib,
...
}:
{
virtualisation.quadlet = {
containers = {
mautrix-signal = {
containerConfig.image = "dock.mau.dev/mautrix/signal:latest";
containerConfig.volumes = [
"mautrix-signal:/data"
];
# containerConfig.publishPorts = [
# "100.83.96.25:29328:29328"
# ];
containerConfig.networks = [
"podman"
"db-net"
];
};
};
};
}

View file

@ -0,0 +1,75 @@
{
pkgs,
config,
lib,
inputs,
...
}:
{
virtualisation.quadlet = {
containers = {
paperless-server.containerConfig.image = "ghcr.io/paperless-ngx/paperless-ngx:latest";
paperless-server.containerConfig.networks = [
"podman"
"db-net"
"paperless-net"
];
paperless-server.containerConfig.volumes = [
"paperless-media:/usr/src/paperless/media"
"paperless-data:/usr/src/paperless/data"
"/data/paperless-export:/usr/src/paperless/export"
"/data/paperless-consume:/usr/src/paperless/consume"
];
paperless-server.containerConfig.environments = {
PAPERLESS_REDIS = "redis://paperless-redis:6379";
PAPERLESS_DBHOST = "postgres";
PAPERLESS_TIKA_ENABLED = "1";
PAPERLESS_TIKA_GOTENBERG_ENDPOINT = "http://paperless-gotenberg:3000";
PAPERLESS_TIKA_ENDPOINT = "http://paperless-tika:9998";
USERMAP_UID = "1000";
USERMAP_GID = "100";
PAPERLESS_URL = "https://paperless.hailsatan.eu";
PAPERLESS_TIME_ZONE = "Europe/Berlin";
PAPERLESS_OCR_LANGUAGE = "deu";
PAPERLESS_TRUSTED_PROXIES = "10.89.0.1";
PAPERLESS_ENABLE_HTTP_REMOTE_USER = "true";
PAPERLESS_ENABLE_HTTP_REMOTE_API = "true";
PAPERLESS_HTTP_REMOTE_USER_HEADER_NAME = "HTTP_X_AUTHENTIK_USERNAME";
PAPERLESS_DISABLE_REGULAR_LOGIN = "true";
};
paperless-server.serviceConfig.TimeoutStartSec = "60";
paperless-redis.containerConfig.image = "docker.io/library/redis:alpine";
paperless-redis.containerConfig.networks = [
"paperless-net"
];
paperless-redis.containerConfig.volumes = [ "paperless-redis:/data" ];
paperless-redis.serviceConfig.TimeoutStartSec = "60";
paperless-gotenberg = {
containerConfig = {
image = "docker.io/gotenberg/gotenberg:8.7";
exec = "gotenberg --chromium-disable-javascript=true --chromium-allow-list=file:///tmp/.*";
networks = [
"paperless-net"
];
};
serviceConfig.TimeoutStartSec = "60";
};
paperless-tika = {
containerConfig = {
image = "docker.io/apache/tika:latest";
networks = [
"paperless-net"
];
};
serviceConfig.TimeoutStartSec = "60";
};
};
networks = {
paperless.networkConfig.ipv6 = true;
paperless.networkConfig.name = "paperless-net";
paperless.networkConfig.internal = true;
};
};
}

View file

@ -0,0 +1,9 @@
{ config, pkgs, lib, inputs, ... }: {
ragon.persist.extraDirectories = [ config.services.plex.dataDir ];
services.plex = {
enable = true;
openFirewall = true;
user = "ragon";
group = "users";
};
}

View file

@ -0,0 +1,43 @@
{
pkgs,
config,
lib,
...
}:
{
services.radicale = {
enable = true;
settings = {
server.hosts = [ "[::1]:5232" ];
auth = {
type = "http_x_remote_user";
# remote_ip_source = "X-Remote-Addr";
};
storage = {
filesystem_folder = "/var/lib/radicale/collections";
};
};
rights = {
root = {
user = ".+";
collection = "";
permissions = "R";
};
principal = {
user = ".+";
collection = "{user}";
permissions = "RW";
};
calendars = {
user = ".+";
collection = "{user}/[^/]+";
permissions = "rw";
};
};
};
ragon.persist.extraDirectories = [
"/var/lib/radicale"
];
}

View file

@ -0,0 +1,66 @@
{ config, pkgs, lib, ... }: {
# services.samba.extraConfig = ''
# min protocol = SMB3
# vfs objects = acl_xattr catia fruit streams_xattr
# fruit:nfs_aces = no
# inherit permissions = yes
# fruit:posix_rename = yes
# fruit:resource = xattr
# fruit:model = MacSamba
# fruit:veto_appledouble = no
# fruit:wipe_intentionally_left_blank_rfork = yes
# fruit:delete_empty_adfiles = yes
# fruit:metadata = stream
# '';
services.avahi.enable = true;
services.avahi.nssmdns = true;
services.avahi.publish.enable = true;
services.avahi.extraServiceFiles.smb = ''
<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
<host-name>ds9.kangaroo-galaxy.ts.net</host-name>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=MacPro7,1@ECOLOR=226,226,224</txt-record>
</service>
<service>
<type>_adisk._tcp</type>
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
<txt-record>dk0=adVN=TimeMachine,adVF=0x82</txt-record>
<host-name>ds9.kangaroo-galaxy.ts.net</host-name>
</service>
</service-group>
'';
ragon.services = {
samba.enable = true;
samba.shares = {
TimeMachine = {
path = "/backups/DaedalusTimeMachine";
comment = "DaedalusTimeMachine";
"write list" = "@wheel";
"read only" = "no";
"writable" = "yes";
"browseable" = "yes";
"fruit:time machine" = "yes";
"fruit:time machine max size" = "2050G";
"vfs objects" = "acl_xattr fruit streams_xattr";
"inherit acls" = "yes";
};
data = {
path = "/data";
comment = "some data for the people";
"write list" = "@wheel";
};
};
};
}

View file

@ -0,0 +1,34 @@
{
pkgs,
config,
lib,
...
}:
with lib;
{
users.users.nginx.isSystemUser = true;
users.users.nginx.group = "nginx";
users.groups.nginx = { };
services.nginx.enable = mkForce false;
services.nginx.virtualHosts."snipe-it" = mkForce null;
users.users.caddy.extraGroups = [ config.services.snipe-it.group ];
ragon.agenix.secrets.ds9SnipeIt = {
group = config.services.snipe-it.group;
owner = config.services.snipe-it.user;
mode = "440";
};
services.snipe-it = {
enable = true;
database.createLocally = true;
mail.driver = "sendmail";
appURL = "https://snipe-it.hailsatan.eu";
hostName = "snipe-it";
appKeyFile = config.age.secrets.ds9SnipeIt.path;
mail.from.address = "root@hailsatan.eu";
};
ragon.persist.extraDirectories = [
config.services.snipe-it.dataDir
"/var/lib/mysql"
];
}

View file

@ -0,0 +1,59 @@
{
config,
pkgs,
lib,
...
}:
{
virtualisation.podman.dockerSocket.enable = true;
ragon.agenix.secrets.ds9WoodpeckerEnv = { };
ragon.agenix.secrets.ds9WoodpeckerAgentSecretEnv = { };
virtualisation.quadlet = {
containers = {
woodpecker-server = {
containerConfig.image = "woodpeckerci/woodpecker-server:v3";
containerConfig.volumes = [
"woodpecker-server-data:/var/lib/woodpecker"
];
containerConfig.networks = [
"woodpecker-net"
"podman"
];
containerConfig.environments = {
WOODPECKER_HOST = "https://woodpecker.hailsatan.eu";
WOODPECKER_OPEN = "true";
WOODPECKER_ADMIN = "xyno";
};
containerConfig.environmentFiles = [
config.age.secrets.ds9WoodpeckerEnv.path
config.age.secrets.ds9WoodpeckerAgentSecretEnv.path
];
};
woodpecker-agent = {
containerConfig.environmentFiles = [
config.age.secrets.ds9WoodpeckerAgentSecretEnv.path
];
containerConfig.image = "woodpeckerci/woodpecker-agent:v3";
containerConfig.volumes = [
"woodpecker-agent-config:/etc/woodpecker"
"/var/run/docker.sock:/var/run/docker.sock"
];
containerConfig.environments = {
WOODPECKER_SERVER = "woodpecker-server:9000";
BACKEND_DOCKER_ENABLE_IPV6 = "true";
};
containerConfig.networks = [
"woodpecker-net"
"podman"
];
};
};
networks = {
woodpecker.networkConfig = {
ipv6 = true;
name = "woodpecker-net";
internal = false;
};
};
};
}

View file

@ -0,0 +1,130 @@
{
config,
pkgs,
lib,
inputs,
...
}:
with lib;
let
channels = {
"Entertainment" = [
"2BoredGuysOfficial"
"AlexPrinz"
"BagelBoyOfficial"
"DiedeutschenBackrooms"
"DankPods"
"Defunctland"
"Ididathing"
"GarbageTime420"
"Boy_Boy"
"ContraPoints"
"PhilosophyTube"
"PosyMusic"
"RobBubble"
"agingwheels"
"NileBlue"
"NileRed"
"styropyro"
"williamosman"
"billwurtz"
"f4micom"
"hbomberguy"
"simonegiertz"
"Parabelritter"
"DeviantOllam"
"MaxFosh"
"MichaelReeves"
"TomScottGo"
"WilliamOsman2"
];
"Tism" = [
"Echoray1" # alwin meschede
"TechnologyConnections"
"TechnologyConnextras"
"TheB1M"
"bahnblick_eu"
"jameshoffmann"
"scottmanley"
"theCodyReeder"
"standupmaths"
];
"Making" = [
"DIYPerks"
"MaxMakerChannel"
"Nerdforge"
"iliketomakestuff"
"ZackFreedman"
];
"Games" = [
"TylerMcVicker1"
"gabe.follower"
"altf4games"
];
"Programming" = [
"BenEater"
"NoBoilerplate"
"stacksmashing"
];
"Tech" = [
"LinusTechTips"
];
};
in
{
systemd.services."ytdl-sub-default".serviceConfig.ReadWritePaths = [ "/data/media/yt" ];
services.ytdl-sub = {
instances.default = {
enable = true;
schedule = "0/2:0";
config = {
presets."Sponsorblock" = {
ytdl_options.cookiefile = "/data/media/yt/cookies.Personal.txt";
subtitles = {
embed_subtitles = true;
languages = [
"en"
"de"
];
allow_auto_generated_subtitles = false;
};
chapters = {
embed_chapters = true;
sponsorblock_categories = [
# "outro"
"selfpromo"
"preview"
"interaction"
"sponsor"
"music_offtopic"
# "intro"
];
remove_sponsorblock_categories = "all";
force_key_frames = false;
};
};
};
subscriptions = {
"__preset__".overrides = {
tv_show_directory = "/data/media/yt";
only_recent_max_files = 30;
# only_recent_date_range = "30days";
};
"Jellyfin TV Show by Date | Sponsorblock | Only Recent | Max 1080p" = mapAttrs' (
n: v: nameValuePair "= ${n}" (genAttrs v (x: "https://youtube.com/@${x}"))
) channels;
"Jellyfin TV Show Collection | Sponsorblock" = {
"~Murder Drones" = {
s01_url = "https://www.youtube.com/playlist?list=PLHovnlOusNLiJz3sm0d5i2Evwa2LDLdrg";
tv_show_collection_episode_ordering = "playlist-index";
tv_show_directory = "/data/media/tv";
};
};
};
};
group = "users";
};
}

View file

@ -0,0 +1,400 @@
# Edit this configuration file to define what should be installed on
# your system. Help is available in the configuration.nix(5) man page
# and in the NixOS manual (accessible by running nixos-help).
{
inputs,
config,
pkgs,
lib,
...
}:
{
imports = [
# Include the results of the hardware scan.
./hardware-configuration.nix
./xynospace-matrix.nix
./plausible.nix
./obsidianshare.nix
./mail.nix
./gotosocial.nix
./ntfy.nix
# ./ts-ovpn.nix
../../nixos-modules/system/persist.nix
../../nixos-modules/system/agenix.nix
../../nixos-modules/system/fs.nix
../../nixos-modules/system/security.nix
../../nixos-modules/services/ssh.nix
../../nixos-modules/services/msmtp.nix
../../nixos-modules/services/caddy
../../nixos-modules/services/bitwarden.nix
../../nixos-modules/networking/tailscale.nix
# ../../nixos-modules/services/authelia.nix
../../nixos-modules/services/hedgedoc.nix
../../nixos-modules/services/ts3.nix
../../nixos-modules/user
];
documentation.enable = false;
documentation.nixos.enable = false;
documentation.man.enable = false;
boot.loader.grub.enable = true;
boot.loader.grub.device = "/dev/sda";
boot.loader.systemd-boot.enable = false;
services.syncthing.enable = true;
services.syncthing.group = "users";
services.syncthing.user = "ragon";
networking.interfaces."ens3" = {
ipv6 = {
addresses = [
{
address = "2a03:4000:6:8120::1";
prefixLength = 64;
}
];
};
};
networking.defaultGateway6 = {
address = "fe80::1";
interface = "enp0s3";
};
networking.nameservers = [
"1.1.1.1"
"8.8.8.8"
];
# networking.interfaces.eno1.useDHCP = true;
networking.hostId = "7c21236a";
# Immutable users due to tmpfs
users.mutableUsers = false;
services.postgresql.package = pkgs.postgresql_17_jit;
services.postgresql.settings = {
shared_buffers = "4GB";
work_mem = "64MB";
};
systemd.services.caddy.serviceConfig.EnvironmentFile = config.age.secrets.desec.path;
networking.firewall.allowedTCPPorts = [
80
443
config.services.forgejo.settings.server.SSH_PORT
25
143
465
587
993
];
networking.firewall.allowedUDPPorts = [ 443 ];
services.prometheus.exporters.node = {
enable = true;
enabledCollectors = [ "systemd" ];
};
services.prometheus.exporters.postgres = {
enable = true;
runAsLocalSuperUser = true;
};
services.caddy = {
logFormat = "level INFO";
enable = true;
globalConfig = ''
email ssl@xyno.systems
acme_ca https://acme-v02.api.letsencrypt.org/directory # hard coded so zerossl doesn't get used
acme_dns desec {
token "{$TOKEN}"
}
admin :2019
metrics {
per_host
}
'';
virtualHosts."*.hailsatan.eu".extraConfig = ''
tls ssl@xyno.systems {
propagation_delay 1m
ca https://acme-v02.api.letsencrypt.org/directory # hard coded so zerossl doesn't get used
dns desec {
token "{$TOKEN}"
}
}
reverse_proxy https://ds9.kangaroo-galaxy.ts.net {
transport http {
tls_server_name {host}
}
}
'';
virtualHosts."l621.net".extraConfig = ''
reverse_proxy http://127.0.0.1:8186
'';
virtualHosts."xyno.space".extraConfig =
let
fqdn = "matrix.xyno.space";
wkServer = {
"m.server" = "${fqdn}:443";
};
wkClient = {
"m.homeserver" = {
"base_url" = "https://${fqdn}";
};
"m.identity_server" = {
"base_url" = "https://vector.im";
};
# "org.matrix.msc3575.proxy" = { "url" = "https://slidingsync.ragon.xyz"; };
};
in
''
encode zstd gzip
handle /.well-known/matrix/server {
header Content-Type application/json
respond `${builtins.toJSON wkServer}` 200
}
handle /.well-known/matrix/client {
header Content-Type application/json
header Access-Control-Allow-Origin "*"
respond `${builtins.toJSON wkClient}` 200
}
handle /gyakapyukawfyuokfgwtyutf.js {
rewrite * /js/plausible.outbound-links.js
reverse_proxy http://127.0.0.1:${toString config.services.plausible.server.port}
}
handle /api/event {
reverse_proxy http://127.0.0.1:${toString config.services.plausible.server.port}
}
redir /post/nix-darwin-introduction /posts/nix-darwin-introduction/ 301
redir /post/nixos-utm-rosetta /posts/nixos-utm-rosetta/ 301
redir /post/nix-store-nfs /posts/nix-store-nfs/ 301
redir /post/parcel-quicktemplate /posts/parcel-quicktemplate/ 301
redir /posts.rss /atom.xml 301
redir /posts.atom /atom.xml 301
root * /srv/www/xynospace
file_server
'';
virtualHosts."*.xyno.space".extraConfig = ''
@stats host stats.xyno.space
handle @stats {
reverse_proxy http://127.0.0.1:${toString config.services.plausible.server.port}
}
@matrix host matrix.xyno.space
handle @matrix {
handle /_matrix/* {
reverse_proxy http://192.168.100.11:8008
}
handle /notifications {
reverse_proxy http://192.168.100.11:8008
}
handle /_synapse/client/* {
reverse_proxy http://192.168.100.11:8008
}
handle /health {
reverse_proxy http://192.168.100.11:8008
}
}
handle {
abort
}
'';
virtualHosts."*.xyno.systems".extraConfig = ''
@lost host lost.xyno.systems
handle @lost {
handle /register {
header ?Set-Cookie lost-registered=true
respond registered 200
}
@lost-registered {
header Cookie *lost-registered=true*
}
handle @lost-registered {
redir https://snipe-it.hailsatan.eu/hardware{uri}
}
handle {
redir https://xyno.space/contact?utm-source=lost&utm-content={uri}
}
}
@md host md.xyno.systems
handle @md {
reverse_proxy http://[::1]:${toString config.services.hedgedoc.settings.port}
}
# @sso host sso.xyno.systems
# handle @sso {
# reverse_proxy http://127.0.0.1:9091
# }
@git host git.xyno.systems
handle @git {
reverse_proxy http://127.0.0.1:${toString config.services.forgejo.settings.server.HTTP_PORT}
}
@notes host notes.xyno.systems
handle @notes {
reverse_proxy http://127.0.0.1:8086
}
@ntfy host ntfy.xyno.systems
handle @ntfy {
reverse_proxy http://127.0.0.1:15992
}
@bw host bw.xyno.systems
handle @bw {
reverse_proxy http://${config.services.vaultwarden.config.rocketAddress}:${toString config.services.vaultwarden.config.rocketPort}
}
handle {
abort
}
'';
virtualHosts."xyno.systems".extraConfig = ''
redir https://xyno.space{uri}
'';
virtualHosts."robotgirl.cloud".extraConfig = ''
handle / {
header Content-Type text/html
header Access-Control-Allow-Origin "*"
respond `<!DOCTYPE html><html><head><title>beep</title></head><body>
<h2>
beep :3
</h2>
<p>
all the robots are on <a href="https://catgirl.cloud">catgirl.cloud</a> mew :3
</p>
</body></head>` 200
}
'';
};
services.forgejo = {
enable = true;
lfs.enable = true;
settings = {
global.APP_NAME = "xyno.systems git";
session.COOKIE_SECURE = true;
server.DOMAIN = "git.xyno.systems";
server.ROOT_URL = "https://git.xyno.systems/";
server.HTTP_PORT = 3031;
server.HTTP_HOST = "127.0.0.1";
service.DISABLE_REGISTRATION = false;
service.ALLOW_ONLY_EXTERNAL_REGISTRATION = true;
service.SHOW_REGISTRATION_BUTTON = false;
openid = {
ENABLE_OPENID_SIGNIN = false;
ENABLE_OPENID_SIGNUP = true;
WHITELISTED_URIS = "auth.hailsatan.eu";
};
};
};
ragon.agenix.secrets."desec" = { };
ragon.agenix.secrets."picardResticPassword" = { };
ragon.agenix.secrets."picardResticSSHKey" = { };
ragon.agenix.secrets."picardResticHealthCheckUrl" = { };
ragon.agenix.secrets."picardSlidingSyncSecret" = { };
ragon.agenix.secrets."gatebridgeHostKeys" = { };
services.postgresql.ensureUsers = [
{
name = "root";
ensureClauses.superuser = true;
}
];
services.borgmatic = {
enable = true;
configurations."picard-ds9" = {
source_directories = [ "/persistent" ];
repositories = [
{
label = "ds9";
path = "ssh://picardbackup@ds9/backups/picard/borgmatic";
}
{
label = "gatebridge";
path = "ssh://root@gatebridge/media/backup/picard";
}
];
exclude_if_present = [ ".nobackup" ];
encryption_passcommand = "${pkgs.coreutils}/bin/cat ${config.age.secrets.picardResticPassword.path}";
compression = "auto,zstd,10";
ssh_command = "ssh -o GlobalKnownHostsFile=${config.age.secrets.gatebridgeHostKeys.path} -i ${config.age.secrets.picardResticSSHKey.path}";
retention = {
keep_daily = 7;
keep_weekly = 4;
keep_monthly = 12;
keep_yearly = 10;
};
before_actions = [
"${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.picardResticHealthCheckUrl.path})/start"
];
after_actions = [
"${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.picardResticHealthCheckUrl.path})"
];
on_error = [
"${pkgs.curl}/bin/curl -fss -m 10 --retry 5 -o /dev/null $(${pkgs.coreutils}/bin/cat ${config.age.secrets.picardResticHealthCheckUrl.path})/fail"
];
postgresql_databases = [
{
name = "all";
pg_dump_command = "${pkgs.postgresql}/bin/pg_dumpall";
pg_restore_command = "${pkgs.postgresql}/bin/pg_restore";
}
];
};
};
nixpkgs.overlays = [
(self: super: {
zfs = super.zfs.override { enableMail = true; };
})
];
# services.xynoblog.enable = true;
# services.lolpizza2.enable = true;
programs.mosh.enable = true;
home-manager.users.ragon =
{
pkgs,
lib,
inputs,
config,
...
}:
{
imports = [
# ../../hm-modules/nvim
# ../../hm-modules/zsh
../../hm-modules/tmux
../../hm-modules/cli.nix
../../hm-modules/files.nix
];
programs.home-manager.enable = true;
home.stateVersion = "23.11";
};
ragon = {
user.enable = true;
persist.enable = true;
persist.extraDirectories = [
"/var/lib/nixos-containers"
"/srv/www"
config.services.caddy.dataDir
"/var/lib/syncthing"
# "/var/lib/${config.services.xynoblog.stateDirectory}"
"/var/lib/postgresql"
config.services.forgejo.stateDir
];
services = {
caddy.enable = true;
ssh.enable = true;
msmtp.enable = true;
bitwarden.enable = true;
tailscale.enable = true;
hedgedoc.enable = true;
# authelia.enable = true;
ts3.enable = true;
};
};
}

View file

@ -0,0 +1,22 @@
{ pkgs, config, ... }: {
virtualisation.oci-containers.containers."gts" = {
image = "superseriousbusiness/gotosocial:latest";
environment = {
GTS_HOST = "l621.net";
GTS_DB_TYPE = "sqlite";
GTS_DB_ADDRESS = "/gotosocial/storage/sqlite.db";
GTS_LETSENCRYPT_ENABLED = "false";
GTS_WAZERO_COMPILATION_CACHE = "/gotosocial/.cache";
GTS_TRUSTED_PROXIES = "10.88.0.0/16";
TZ = "Europe/Berlin";
};
ports = [
"127.0.0.1:8186:8080"
];
volumes = [
"/var/lib/gotosocial:/gotosocial/storage"
];
};
ragon.persist.extraDirectories = ["/var/lib/gotosocial"];
}

View file

@ -0,0 +1,44 @@
# Do not modify this file! It was generated by nixos-generate-config
# and may be overwritten by future invocations. Please make changes
# to /etc/nixos/configuration.nix instead.
{ config, lib, pkgs, modulesPath, ... }:
let
pubkeys = import ../../data/pubkeys.nix;
in
{
imports = [ "${modulesPath}/profiles/qemu-guest.nix" ];
boot.zfs.requestEncryptionCredentials = true;
ragon.system.fs.enable = true;
ragon.system.fs.nix = "rpool/nix";
ragon.system.fs.varlog = "rpool/varlog";
ragon.system.fs.persistent = "rpool/persist";
ragon.system.fs.swap = false;
ragon.system.fs.mediadata = false;
swapDevices = [
{ device = "/dev/sda2"; randomEncryption.enable = true; }
];
services.syncoid.enable = false; # disable failing zfs syncing
boot.initrd = {
network = {
enable = true;
postCommands = ''
zpool import rpool
echo "zfs load-key -a; killall zfs" >> /root/.profile
'';
ssh = {
enable = true;
port = 2222;
hostKeys = [
"/persistent/etc/nixos/secrets/initrd/ssh_host_rsa_key"
"/persistent/etc/nixos/secrets/initrd/ssh_host_ed25519_key"
];
authorizedKeys = pubkeys.ragon.user;
};
};
};
powerManagement.cpuFreqGovernor = "performance";
}

View file

@ -0,0 +1,37 @@
{
pkgs,
config,
lib,
...
}:
{
virtualisation.oci-containers.containers."mail" = {
image = "ghcr.io/docker-mailserver/docker-mailserver:latest";
hostname = "mail.hailsatan.eu";
ports = [
"25:25" # SMTP (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead)
"143:143" # IMAP4 (explicit TLS => STARTTLS)
"465:465" # ESMTP (implicit TLS)
"587:587" # ESMTP (explicit TLS => STARTTLS)
"993:993" # IMAP4 (implicit TLS)
];
volumes = [
"mail-data:/var/mail/"
"mail-state:/var/mail-state/"
"mail-logs:/var/log/mail/"
"mail-config:/tmp/docker-mailserver/"
"/var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/wildcard_.hailsatan.eu:/srv/tls/meow:ro" # it hates this
];
environment = {
TZ = "Europe/Berlin";
SPOOF_PROTECTION = "1";
LOG_LEVEL = "info";
ENABLE_CLAMAV = "0";
ENABLE_FAIL2BAN = "0";
TLS_LEVEL = "intermediate"; # printers ahhh
SSL_TYPE = "manual";
SSL_CERT_PATH = "/srv/tls/meow/wildcard_.hailsatan.eu.crt";
SSL_KEY_PATH = "/srv/tls/meow/wildcard_.hailsatan.eu.key";
};
};
}

View file

@ -0,0 +1,11 @@
{pkgs,config,lib,...}:{
services.ntfy-sh = {
enable = true;
settings.base-url = "https://ntfy.xyno.systems";
settings.behind-proxy = true;
settings.listen-http = ":15992";
};
ragon.persist.extraDirectories = [
"/var/cache/ntfy"
];
}

View file

@ -0,0 +1,17 @@
{ pkgs, config, ... }: {
ragon.agenix.secrets.picardSharenoteEnv = { };
virtualisation.oci-containers.containers."sharenote" = {
image = "ghcr.io/thexyno/sharenote-py:latest";
environmentFiles = [
config.age.secrets.picardSharenoteEnv.path
];
ports = [
"127.0.0.1:8086:8086"
];
volumes = [
"/var/lib/sharenote:/sharenote-py/static"
];
};
ragon.persist.extraDirectories = ["/var/lib/sharenote"];
}

View file

@ -0,0 +1,76 @@
{ config, lib, pkgs, ... }:
let domain = "stats.xyno.space";
in {
ragon.agenix.secrets."plausibleAdminPw" = { };
ragon.agenix.secrets."plausibleReleaseCookie" = { };
ragon.agenix.secrets."plausibleSecretKeybase" = { };
ragon.agenix.secrets."plausibleGoogleClientId" = { };
ragon.agenix.secrets."plausibleGoogleClientSecret" = { };
ragon.agenix.secrets."smtpPassword" = { };
systemd.services.plausible.serviceConfig.LoadCredential = [
"GOOGLE_CLIENT_ID:${config.age.secrets.plausibleGoogleClientId.path}"
"GOOGLE_CLIENT_SECRET:${config.age.secrets.plausibleGoogleClientSecret.path}"
];
systemd.services.plausible.environment = {
IP_GEOLOCATION_DB = "${pkgs.unstable.dbip-country-lite}/share/dbip/dbip-country-lite.mmdb";
DATABASE_URL = "postgresql:///plausible?host=/run/postgresql";
};
# systemd.services.plausible.script =
# let cfg = config.services.plausible; in lib.mkForce ''
# # Elixir does not start up if `RELEASE_COOKIE` is not set,
# # even though we set `RELEASE_DISTRIBUTION=none` so the cookie should be unused.
# # Thus, make a random one, which should then be ignored.
# export RELEASE_COOKIE=$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 20)
# export ADMIN_USER_PWD="$(< $CREDENTIALS_DIRECTORY/ADMIN_USER_PWD )"
# export SECRET_KEY_BASE="$(< $CREDENTIALS_DIRECTORY/SECRET_KEY_BASE )"
# ${lib.optionalString (
# cfg.mail.smtp.passwordFile != null
# ) ''export SMTP_USER_PWD="$(< $CREDENTIALS_DIRECTORY/SMTP_USER_PWD )"''}
# echo setup
# ${lib.optionalString cfg.database.postgres.setup ''
# # setup
# ${cfg.package}/createdb.sh
# ''}
# echo migrate
# ${cfg.package}/migrate.sh
# export IP_GEOLOCATION_DB=${pkgs.dbip-country-lite}/share/dbip/dbip-country-lite.mmdb
# # ${cfg.package}/bin/plausible eval "(Plausible.Release.prepare() ; Plausible.Auth.create_user(\"$ADMIN_USER_NAME\", \"$ADMIN_USER_EMAIL\", \"$ADMIN_USER_PWD\"))"
# echo start
# exec plausible start
# '';
services.plausible = {
enable = true;
package = pkgs.unstable.plausible;
# releaseCookiePath = config.age.secrets.plausibleSecretKeybase.path;
# adminUser = {
# # activate is used to skip the email verification of the admin-user that's
# # automatically created by plausible. This is only supported if
# # postgresql is configured by the module. This is done by default, but
# # can be turned off with services.plausible.database.postgres.setup.
# activate = true;
# email = "plausible@xyno.space";
# passwordFile = config.age.secrets.plausibleAdminPw.path;
# };
server = {
baseUrl = "https://${domain}";
secretKeybaseFile = config.age.secrets.plausibleSecretKeybase.path;
};
mail.email = "plausible@hailsatan.eu";
mail.smtp = {
user = "plausible@hailsatan.eu";
passwordFile = config.age.secrets.smtpPassword.path;
hostAddr = "mail.hailsatan.eu";
hostPort = 465;
enableSSL = true;
};
};
ragon.persist.extraDirectories = [ "/var/lib/private/plausible" "/var/lib/clickhouse" ];
}

View file

@ -0,0 +1,189 @@
{ config, pkgs, lib,inputs, ... }:
let
fqdn = "matrix.xyno.space";
serverName = "xyno.space";
localAddress = "192.168.100.11";
hostAddress = "192.168.100.10";
stateVer = config.system.stateVersion;
in
{
users.users.matrix-synapse = {
group = "matrix-synapse";
shell = "${pkgs.bash}/bin/bash";
uid = config.ids.uids.matrix-synapse;
};
users.groups.matrix-synapse = {
gid = config.ids.gids.matrix-synapse;
};
ragon.agenix.secrets."matrixSecrets" = { owner = "matrix-synapse"; };
services.postgresql.enable = true;
services.postgresql.initialScript = lib.mkForce (pkgs.writeText "synapse-init.sql" ''
CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse-xynospace"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
CREATE ROLE "matrix-synapse-xynospace" WITH LOGIN PASSWORD 'synapse';
CREATE DATABASE "matrix-synapse-xynospace" WITH OWNER "matrix-synapse-xynospace"
TEMPLATE template0
LC_COLLATE = "C"
LC_CTYPE = "C";
'');
networking.nat.enable = true;
networking.nat.internalInterfaces = [ "ve-+" ];
networking.nat.externalInterface = "ens3";
networking.firewall.trustedInterfaces = [ "ve-+" ];
users.users.slidingsync = { isSystemUser = true; group = "slidingsync"; uid = 990; };
users.groups.slidingsync = { gid = 988; };
# virtualisation.oci-containers.containers."matrix-sliding-sync" = {
# image = "ghcr.io/matrix-org/sliding-sync:latest";
# ports = [ "127.0.0.1:8009:8008" ];
# user = "${toString config.users.users.slidingsync.uid}:${toString config.users.groups.slidingsync.gid}";
# volumes = [
# "/run/postgresql:/run/postgresql"
# ];
# environmentFiles = [ config.age.secrets.picardSlidingSyncSecret.path ];
# environment = {
# SYNCV3_SERVER = "https://${fqdn}";
# SYNCV3_BINDADDR = ":8008";
# SYNCV3_DB = "host=/run/postgresql user=slidingsync dbname=slidingsync password=slidingsync";
# };
# };
services.postgresql = {
ensureDatabases = [ "slidingsync" ];
ensureUsers = [
{
name = "slidingsync";
ensureDBOwnership = true;
}
];
};
containers.xynospace-matrix = let ms = config.age.secrets.matrixSecrets.path; unst = pkgs.unstable; in {
config = { config, pkgs, ... }: {
# nixpkgs.overlays = [(self: super: {
# matrix-synapse-unwrapped = super.matrix-synapse-unwrapped.overrideAttrs (super: self: {
# src = inputs.synapse;
# # cargoHash = "sha256-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX=";
# });
# })];
system.stateVersion = stateVer;
networking.firewall.allowedTCPPorts = [ 8008 ];
services.matrix-synapse = {
enable = true;
# package = unst.matrix-synapse;
settings.server_name = serverName;
extraConfigFiles = [ "/host${ms}" ];
settings.experimental.msc3575_enabled = true;
settings.database.args.user = "matrix-synapse-xynospace";
settings.database.name = "psycopg2";
settings.database.args.database = "matrix-synapse-xynospace";
settings.database.args.host = hostAddress;
settings.trusted_key_servers = [
{ server_name = "catgirl.cloud"; }
{ server_name = "kif.rocks"; }
{ server_name = "fachschaften.org"; }
{ server_name = "matrix.org"; }
];
settings.ip_range_whitelist = [
"2a03:4000:6:8120::1/128"
"37.120.178.81/32"
];
settings.database.args.password = "synapse";
settings.app_service_config_files = [
"/var/lib/signalbot.yaml"
"/var/lib/doublepuppet.yaml"
];
settings.listeners = [
{
port = 8008;
bind_addresses = [ localAddress ];
type = "http";
tls = false;
x_forwarded = true;
resources = [
{
names = [ "client" "federation" ];
compress = false;
}
];
}
];
};
};
inherit localAddress hostAddress;
privateNetwork = true;
autoStart = true;
bindMounts = {
"/host/run" = { hostPath = "/run"; isReadOnly = true; };
"/run/agenix.d" = { hostPath = "/run/agenix.d"; isReadOnly = true; };
};
};
services.nginx.virtualHosts = {
"${serverName}" = {
forceSSL = true;
locations."= /.well-known/matrix/server".extraConfig =
let
# use 443 instead of the default 8448 port to unite
# the client-server and server-server port for simplicity
server = { "m.server" = "${fqdn}:443"; };
in
''
add_header Content-Type application/json;
return 200 '${builtins.toJSON server}';
'';
locations."= /.well-known/matrix/client".extraConfig =
let
client = {
"m.homeserver" = { "base_url" = "https://${fqdn}"; };
"m.identity_server" = { "base_url" = "https://vector.im"; };
"org.matrix.msc3575.proxy" = { "url" = "https://slidingsync.ragon.xyz"; };
};
# ACAO required to allow element-web on any URL to request this json file
in
''
add_header Content-Type application/json;
add_header Access-Control-Allow-Origin *;
return 200 '${builtins.toJSON client}';
'';
};
# Reverse proxy for Matrix client-server and server-server communication
"${fqdn}" = {
forceSSL = true;
enableACME = true;
# Or do a redirect instead of the 404, or whatever is appropriate for you.
# But do not put a Matrix Web client here! See the Element web section below.
locations."/".extraConfig = ''
return 404;
'';
# forward all Matrix API calls to the synapse Matrix homeserver
locations."/_matrix" = {
proxyPass = "http://${localAddress}:8008"; # without a trailing /
};
locations."/notifications" = {
proxyPass = "http://${localAddress}:8008"; # without a trailing /
};
locations."/_synapse/client" = {
proxyPass = "http://${localAddress}:8008"; # without a trailing /
};
locations."/health" = {
proxyPass = "http://${localAddress}:8008"; # without a trailing /
};
};
};
ragon.persist.extraDirectories = [
"/var/lib/nixos-containers"
];
services.postgresql.authentication = ''
host all all ${localAddress}/32 md5
'';
services.postgresql.settings.listen_addresses = lib.mkForce "localhost,${hostAddress}";
}

View file

@ -0,0 +1,99 @@
(defcfg
;; ** For Linux **
input (device-file "/dev/input/by-id/usb-04d9_USB-HID_Keyboard-event-kbd")
;; input (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd")
output (uinput-sink "KMonad output")
;; ** For Windows **
;; input (low-level-hook)
;; output (send-event-sink)
;; ** For MacOS **
;; input (iokit-name "my-keyboard-product-string")
;; output (kext)
fallthrough true
)
(defsrc
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ]
caps a s d f g h j k l ; ' \ ret
lsft 102d z x c v b n m , . / rsft
lctl lmet lalt spc ralt rmet cmp rctl
)
(defalias
ext (layer-toggle extend) ;; Bind 'ext' to the Extend Layer
)
(defalias
cpy C-c
pst C-v
cut C-x
udo C-z
all C-a
fnd C-f
bk Back
fw Forward
)
(defalias
num (layer-toggle num)
t (tap-hold-next-release 200 t (layer-toggle hjkl))
)
(deflayer colemak-dh
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc (tap-hold-next-release 200 a lctrl) (tap-hold-next-release 200 r ralt) (tap-hold-next-release 200 s lmet) @t g m n (tap-hold-next-release 200 e rmet) (tap-hold-next-release 200 i lalt) (tap-hold-next-release 200 o rctrl) ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer hjkl
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc (tap-hold-next-release 200 a lctrl) (tap-hold-next-release 200 r ralt) (tap-hold-next-release 200 s lmet) t g m h j k l ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer num
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc 1 2 3 4 5 6 7 8 9 0 ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer colemak-dhk
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
@ext a r s t g k n e i o ' \\ ret
lsft z x c d v 102d m h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer extend
_ play rewind previoussong nextsong ejectcd refresh brdn brup www mail prog1 prog2
_ f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 _
_ esc @bk @fnd @fw ins pgup home up end menu prnt slck
_ lalt lmet lsft lctl ralt pgdn lft down rght del caps _ _
_ @udo @cut @cpy tab @pst _ pgdn bks lsft lctl comp _
_ _ _ ret _ _ _ _
)
(deflayer empty
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
)

View file

@ -0,0 +1,387 @@
{
config,
inputs,
pkgs,
lib,
...
}:
{
imports = [
./hardware-configuration.nix
./kmonad.nix
../../nixos-modules/networking/tailscale.nix
../../nixos-modules/services/ssh.nix
../../nixos-modules/system/agenix.nix
../../nixos-modules/system/persist.nix
../../nixos-modules/user
# ./gnome.nix
];
# For mount.cifs, required unless domain name resolution is not needed.
environment.systemPackages = [ pkgs.cifs-utils ];
nix.extraOptions = # devenv
''
trusted-users = root ragon
'';
users.extraGroups.plugdev = { };
services.udev.packages = [
pkgs.openocd
pkgs.probe-rs-tools
];
hardware.keyboard.zsa.enable = true;
services.tailscale.useRoutingFeatures = lib.mkForce "client";
xdg.portal = {
enable = true;
wlr.enable = true;
extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
config = {
river = {
"org.freedesktop.impl.portal.Secret" = [
"gnome-keyring"
];
default = [
"gtk"
];
"org.freedesktop.impl.portal.Screenshot" = "wlr";
"org.freedesktop.impl.portal.ScreenCast" = "wlr";
};
};
};
ragon.agenix.secrets.smbSecrets = { };
# fileSystems."/data" = {
# device = "//ds9.kangaroo-galaxy.ts.net/data";
# fsType = "cifs";
# options = let
# automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s,user,users";
# in ["${automount_opts},credentials=${config.age.secrets.smbSecrets.path},uid=1000,gid=100"];
# };
# Don't Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
boot.initrd.luks.devices.cryptroot.device =
"/dev/disk/by-uuid/4cd8dbb3-8eea-48ff-87b1-92945be291ac";
programs.fuse.userAllowOther = true;
programs.sway.enable = true;
programs.nix-ld.enable = true;
programs.gamescope.enable = true;
programs.wireshark.enable = true;
services.gnome.sushi.enable = true;
services.gnome.gnome-settings-daemon.enable = true;
services.gvfs.enable = true;
services.logind.extraConfig = ''
# supspend on pw button press
HandlePowerKey=suspend
'';
programs.kdeconnect.enable = true;
services.power-profiles-daemon.enable = true;
programs.sway.extraSessionCommands = ''
export NIXOS_OZONE_WL=1
'';
# start bt
hardware.bluetooth.enable = true;
services.blueman.enable = true;
# end bt
# start printing
services.avahi = {
enable = true;
nssmdns4 = true;
nssmdns6 = true;
openFirewall = true;
};
services.printing.enable = true;
services.printing.logLevel = "debug";
# end printing
programs.light.enable = true;
# networking.networkmanager.enable = true;
# networking.networkmanager.wifi.backend = "iwd";
networking.wireless.iwd.enable = true;
networking.useDHCP = lib.mkDefault true;
services.xserver.displayManager.gdm.enable = true;
services.xserver.enable = true;
services.xserver.displayManager.gdm.wayland = true;
programs.seahorse.enable = true;
services.gnome.gnome-keyring.enable = true;
services.gnome.gnome-online-accounts.enable = true;
services.gnome.core-utilities.enable = true;
services.displayManager.defaultSession = "river";
programs.river.enable = true;
services.upower.enable = true;
users.users.ragon.extraGroups = [
"networkmanager"
"video"
"netdev"
"plugdev"
"dialout"
"tape"
"uucp"
"wireshark"
];
fonts.packages = with pkgs; [
nerdfonts
cantarell-fonts
dejavu_fonts
source-code-pro # Default monospace font in 3.32
source-sans
b612
];
services.pipewire = {
enable = true;
raopOpenFirewall = true; # airplay
pulse.enable = true;
extraConfig.pipewire = {
"9-clock-allow-higher" = {
"context.properties" = {
"default.clock.allowed-rates" = [
"44100"
"48000"
"96000"
"192000"
];
};
};
"10-raop-discover" = {
"context.modules" = [
{
name = "libpipewire-module-raop-discover";
args = { };
}
];
};
};
};
services.fwupd.enable = true;
programs.ssh.startAgent = true;
programs.evolution.enable = true;
services.gnome.evolution-data-server.enable = true;
services.flatpak.enable = true;
programs.steam = {
enable = true;
remotePlay.openFirewall = true; # Open ports in the firewall for Steam Remote Play
# dedicatedServer.openFirewall = true; # Open ports in the firewall for Source Dedicated Server
localNetworkGameTransfers.openFirewall = true; # Open ports in the firewall for Steam Local Network Game Transfers
};
home-manager.users.ragon =
{
pkgs,
lib,
inputs,
config,
...
}:
{
imports = [
../../hm-modules/helix
../../hm-modules/nushell
../../hm-modules/zellij
../../hm-modules/cli.nix
./swaycfg.nix
./work.nix
./river.nix
../../hm-modules/files.nix
inputs.wired.homeManagerModules.default
];
ragon.helix.enable = true;
ragon.nushell.enable = true;
ragon.nushell.isNixOS = true;
ragon.zellij.enable = true;
services.gnome-keyring.enable = true;
home.file.".config/wezterm/wezterm.lua".text = ''
local wezterm = require 'wezterm'
-- This will hold the configuration.
local config = wezterm.config_builder()
config.default_prog = { 'nu' }
config.hide_tab_bar_if_only_one_tab = true
config.max_fps = 144
config.font = wezterm.font 'Source Code Pro'
-- This is where you actually apply your config choices
-- For example, changing the color scheme:
config.color_scheme = 'Gruvbox Dark (Gogh)'
-- and finally, return the configuration to wezterm
return config
'';
services.syncthing.enable = true;
services.syncthing.tray.enable = true;
services.syncthing.tray.command = "syncthingtray --wait";
programs.firefox.nativeMessagingHosts = [
pkgs.unstable.firefoxpwa
pkgs.unstable.keepassxc
];
programs.firefox.enable = true;
home.packages = with pkgs; [
# inputs.wezterm.packages.${pkgs.system}.default
element-desktop # this is not a place of honor
discord # shitcord
unstable.signal-desktop
unstable.firefoxpwa
mosh
unstable.plexamp
# firefox
obsidian
thunderbird
# unstable.orca-slicer
diebahn
vlc
dolphin
# unstable.kicad
unstable.devenv
lutris
libsecret
mixxx
unstable.harsh
libreoffice-qt6-fresh
inkscape
easyeffects
dune3d
ptyxis
appimage-run
unstable.keepassxc
# unstable.zenbrowser
inputs.zen-browser.packages."${pkgs.system}".default
aerc
w3m
# filezilla
broot
];
home.file.".zshrc".text = lib.mkForce ''
# we're using nushell as our interactive shell
# so if zsh gets spawned by our terminal emulator, exec nu
cat /proc/$PPID/cmdline | grep -q alacritty && exec nu
'';
services.kdeconnect = {
enable = true;
indicator = true;
package = pkgs.kdePackages.kdeconnect-kde;
};
# home.persistence."/persistent/home/ragon" =
# {
# directories = [
# ".mozilla"
# ".cache"
# ".ssh"
# "docs"
# "Images"
# "Downloads"
# "Music"
# "Pictures"
# "Documents"
# "Videos"
# "VirtualBox VMs"
# ".gnupg"
# ".ssh"
# ".local/share/keyrings"
# ".local/share/direnv"
# ".local/share/Steam"
# ];
# allowOther = true;
# };
programs.home-manager.enable = true;
home.stateVersion = "24.05";
programs.alacritty = {
enable = true;
settings = {
font.normal.family = "JetBrainsMono NerdFont";
colors = {
primary = {
# hard contrast
background = "#1d2021";
# normal background = "#282828";
# soft contrast background = = "#32302f"
foreground = "#ebdbb2";
};
normal = {
black = "#282828";
red = "#cc241d";
green = "#98971a";
yellow = "#d79921";
blue = "#458588";
magenta = "#b16286";
cyan = "#689d6a";
white = "#a89984";
};
bright = {
black = "#928374";
red = "#fb4934";
green = "#b8bb26";
yellow = "#fabd2f";
blue = "#83a598";
magenta = "#d3869b";
cyan = "#8ec07c";
white = "#ebdbb2";
};
};
};
};
programs.borgmatic = {
enable = true;
backups.system =
let
notify = "${pkgs.libnotify}/bin/notify-send";
in
{
location.sourceDirectories = [ "/persistent" ];
location.repositories = [ { path = "ssh://ragon@ds9//backups/theseus"; } ];
location.extraConfig.exclude_if_present = [ ".nobackup" ];
storage.encryptionPasscommand = "${pkgs.libsecret}/bin/secret-tool lookup borg-repository system";
location.extraConfig.before_backup = [
"${notify} -u low -a borgmatic borgmatic \"starting backup\" -t 10000"
];
location.extraConfig.after_backup = [
"${notify} -u low -a borgmatic borgmatic \"finished backup\" -t 10000"
];
location.extraConfig.on_error = [
"${notify} -u critical -a borgmatic borgmatic \"backup failed<br>maybe unlock keepass\""
];
location.extraConfig.ssh_command = "ssh -o IdentityAgent=/run/user/1000/ssh-agent";
location.extraConfig.one_file_system = true;
retention = {
keepHourly = 24;
keepDaily = 7;
keepWeekly = 4;
keepMonthly = 12;
keepYearly = 2;
};
};
};
services.borgmatic.enable = true;
};
ragon = {
user.enable = true;
persist.enable = true;
persist.extraDirectories = [
"/var/lib/bluetooth"
"/var/lib/flatpak"
"/var/lib/iwd"
"/var/log" # lol
];
services = {
ssh.enable = true;
tailscale.enable = true;
};
};
}

View file

@ -0,0 +1,16 @@
{ pkgs, config, inputs, lib, ... }:
let
gnomeExtensions = with pkgs.gnomeExtensions; [
paperwm
gsconnect
];
gnomeExtensionUuids = map (x: x.extensionUuid) gnomeExtensions;
in
{
services.xserver.desktopManager.gnome.enable = true;
environment.systemPackages = gnomeExtensions;
home-manager.users.ragon.dconf.settings."org/gnome/shell" = {
"disable-user-extensions" = false;
enabled-extensions = gnomeExtensionUuids;
};
}

View file

@ -0,0 +1,54 @@
# 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, inputs, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
"${inputs.nixos-hardware}/framework/13-inch/7040-amd"
];
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "thunderbolt" "usb_storage" "usbhid" "sd_mod" ];
boot.initrd.kernelModules = [ "dm-snapshot" ];
boot.kernelModules = [ "kvm-amd" ];
boot.extraModulePackages = [ ];
boot.supportedFilesystems = { xfs = true; };
fileSystems."/persistent" =
{ device = "/dev/disk/by-uuid/ca79f433-163a-4c5c-b176-8e694a674dda";
fsType = "xfs";
neededForBoot = true;
};
fileSystems."/nix" = {
device = "/persistent/nix";
fsType = "none";
depends = ["/persistent"];
options = ["bind"];
};
fileSystems."/" =
{ device = "none";
fsType = "tmpfs";
options = [ "size=32G" "defaults" "mode=755"];
};
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/DA11-68A6";
fsType = "vfat";
options = [ "fmask=0022" "dmask=0022" "noauto" "x-systemd.automount" ];
};
swapDevices =
[ { device = "/dev/disk/by-uuid/96c380b3-4498-4eb8-8a18-5eebe2a41428"; }
];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
# networking.interfaces.enp195s0f3u1u3.useDHCP = lib.mkDefault true;
# networking.interfaces.eth0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.amd.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}

View file

@ -0,0 +1,17 @@
{ pkgs, lib, ... }: {
services.kmonad = {
enable = true;
keyboards = {
builtin = {
device = "/dev/input/by-path/platform-i8042-serio-0-event-kbd";
config = builtins.readFile ./builtin.kbd;
};
k70-office = {
device = "/dev/input/by-id/usb-Corsair_CORSAIR_K70_CORE_RGB_TKL_Mechanical_Gaming_Keyboard_599A4D472DCAC05584072AFB922E3BFB-event-kbd";
config = builtins.readFile ./razer.kbd;
};
};
};
}

View file

@ -0,0 +1,30 @@
{ pkgs, config, lib, ... }:
let
cfg = config.xyno.desktop.mako;
makoConf = pkgs.writeText "mako.conf" ''
font=Source Sans Pro Nerd Font 11
background-color=#1d2021ff
border-color=#3c3836FF
text-color=#ebdbb2ff
progress-color=over #928374FF
'';
in
{
options.xyno.desktop.mako.enable = lib.mkEnableOption "enable mako notification daemon";
options.xyno.desktop.mako.wantedBy = lib.mkOption {
type = lib.types.str;
default = "niri.service";
};
options.xyno.desktop.mako.package = lib.mkOption {
type = lib.types.package;
default = pkgs.mako;
};
config = lib.mkIf cfg.enable {
systemd.user.services.mako = {
wantedBy = [ cfg.wantedBy ];
script = "${cfg.package}/bin/mako -c ${makoConf}";
restartTrigers = makoConf;
};
};
}

View file

@ -0,0 +1,39 @@
{ pkgs, config, lib, ... }:
let
floatingAppids = [
"floating-alacritty"
"org.pulseaudio.pavucontrol"
"KeePassXC"
"org.gnome.NautilusPreviewer"
];
matchFloat = lib.concatStringSep "\n" (map (x: ''
window-rule {
match app-id="${x}"
open-floating true
open-focused true
}
'') floatingAppids);
in
{
imports = [
./waybar.nix
./mako.nix
];
xyno.desktop = {
waybar.enable = true;
mako.enable = true;
};
programs.niri.enable = true;
environment.etc."niri/config.kdl".text = ''
screenshot-path "~/Pictures/screenshots/screenshot-%Y-%m-%d %H-%M-%S.png"
input {
workspace-auto-back-and-forth
focus-follows-mouse max-scroll-amount="10%"
touchpad {
tap
}
}
// autogenerated from here on
${matchFloat}
'';
}

View file

@ -0,0 +1,86 @@
(defcfg
;; ** For Linux **
input (device-file "/dev/input/by-id/usb-Corsair_CORSAIR_K70_CORE_RGB_TKL_Mechanical_Gaming_Keyboard_599A4D472DCAC05584072AFB922E3BFB-event-kbd")
;; input (device-file "/dev/input/by-path/platform-i8042-serio-0-event-kbd")
output (uinput-sink "KMonad output razer")
;; ** For Windows **
;; input (low-level-hook)
;; output (send-event-sink)
;; ** For MacOS **
;; input (iokit-name "my-keyboard-product-string")
;; output (kext)
fallthrough true
)
(defsrc
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w e r t y u i o p [ ]
caps a s d f g h j k l ; ' \ ret
lsft 102d z x c v b n m , . / rsft
lctl lmet lalt spc ralt rmet cmp rctl
)
(defalias
cpy C-c
pst C-v
cut C-x
udo C-z
all C-a
fnd C-f
bk Back
fw Forward
)
(defalias
num (layer-toggle num)
t (tap-hold-next-release 200 t (layer-toggle hjkl))
)
(deflayer colemak-dh
102d f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc (tap-hold-next-release 200 a lctrl) (tap-hold-next-release 200 r ralt) (tap-hold-next-release 200 s lmet) @t g m n (tap-hold-next-release 200 e rmet) (tap-hold-next-release 200 i lalt) (tap-hold-next-release 200 o rctrl) ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer hjkl
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc (tap-hold-next-release 200 a lctrl) (tap-hold-next-release 200 r ralt) (tap-hold-next-release 200 s lmet) t g m h j k l ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer num
esc f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12
grv 1 2 3 4 5 6 7 8 9 0 - = bspc
tab q w f p b j l u y ; [ ]
esc 1 2 3 4 5 6 7 8 9 0 ' \\ ret
lsft z x c d v 102d k h , . / rsft
lctl lmet lalt spc ralt rmet _ _
)
(deflayer extend
_ play rewind previoussong nextsong ejectcd refresh brdn brup www mail prog1 prog2
_ f1 f2 f3 f4 f5 f6 f7 f8 f9 f10 f11 f12 _
_ esc @bk @fnd @fw ins pgup home up end menu prnt slck
_ lalt lmet lsft lctl ralt pgdn lft down rght del caps _ _
_ @udo @cut @cpy tab @pst _ pgdn bks lsft lctl comp _
_ _ _ ret _ _ _ _
)
(deflayer empty
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _
)

View file

@ -0,0 +1,620 @@
{ lib, pkgs, config, inputs, ... }:
let
# backgroundImage = builtins.fetchurl {
# url = "https://gruvbox-wallpapers.pages.dev/wallpapers/anime/wallhaven-2e2xyx.jpg";
# sha256 = "1zw1a8x20bp9mn9lx18mxzgzvzi02ss57r4q1lc9f14fsmzphnlq";
# };
setRandomBackground = pkgs.writeScript "setBackground.sh" ''
#!/${pkgs.bash}/bin/bash
while true; do
FILENAME=''$(${pkgs.findutils}/bin/find /home/ragon/Pictures/backgrounds -type f | ${pkgs.coreutils}/bin/shuf -n 1)
${pkgs.swaybg}/bin/swaybg -i $FILENAME -m fill &
PID=$!
sleep 1200
kill $PID
done
'';
backgroundImage = "/home/ragon/Pictures/background.jpg";
pow = n: i:
if i == 1 then n
else if i == 0 then 1
else n * pow n (i - 1);
tag = n: toString (pow 2 (n - 1));
scratchTag = tag 20;
in
{
home.packages = with pkgs; [
unstable.shikane
helvum
swaylock
swayidle
swaybg
wlopm
brightnessctl
dconf
playerctl
pwvucontrol
# networkmanagerapplet
mako
impala
# iwgtk
libnotify
];
dconf = {
settings = {
"org/gnome/desktop/interface" = {
color-scheme = "prefer-dark";
};
};
};
home.file.".config/mako/config".text = ''
font=Source Sans Pro Nerd Font
background-color=#1d2021ff
border-color=#3c3836FF
text-color=#ebdbb2ff
progress-color=over #928374FF
'';
gtk = {
enable = true;
gtk4.extraConfig.gtk-application-prefer-dark-theme = 1;
gtk3.extraConfig.gtk-application-prefer-dark-theme = 1;
};
qt = {
enable = true;
# platformTheme.name = "Adwaita-dark";
platformTheme.name = "Fusion";
style = {
name = "Fusion";
# package = pkgs.adwaita-qt;
};
};
programs.waybar = {
enable = true;
systemd.enable = true;
style = ''
* {
/* `otf-font-awesome` is required to be installed for icons */
font-family: "Source Sans Pro Nerd Font";
font-size: 12px;
}
window#waybar {
/* background-color: rgba(43, 48, 59, 0.5);
border-bottom: 3px solid rgba(100, 114, 125, 0.5);*/
color: #a89984;
background-color: #1d2021;
/* transition-property: background-color;
transition-duration: .5s;*/
}
window#waybar.hidden {
opacity: 0.2;
}
/*
window#waybar.empty {
background-color: transparent;
}
window#waybar.solo {
background-color: #FFFFFF;
}
*/
/*window#waybar.termite {
background-color: #3F3F3F;
}
window#waybar.chromium {
background-color: #000000;
border: none;
}*/
#tags button {
padding: 0 2px;
background-color: #1d2021;
color: #ebdbb2;
/* Use box-shadow instead of border so the text isn't offset */
box-shadow: inset 0 -3px transparent;
/* Avoid rounded borders under each workspace name */
border: none;
border-radius: 0;
}
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#tags button:hover {
background: rgba(0, 0, 0, 0.2);
/* box-shadow: inset 0 -3px #fbf1c7;
*/
background-color: #3c3836;
}
#tags button.focused {
/* box-shadow: inset 0 -3px #fbf1c7;
*/
background-color: #3c3836;
color: #ebdbb2;
}
#tags button.occupied {
color: #d3869b;
}
#tags button.urgent {
background-color: #cc241d;
color: #ebdbb2;
}
#mode {
background-color: #64727D;
border-bottom: 3px solid #fbf1c7;
}
#clock,
#battery,
#cpu,
#memory,
#disk,
#temperature,
#backlight,
#network,
#pulseaudio,
#custom-media,
#tray,
#mode,
#idle_inhibitor,
#custom-poweroff,
#custom-suspend,
#mpd {
padding: 0 2px;
background-color: #1d2021;
color: #ebdbb2;
}
#window,
#workspaces,
#tags {
margin: 0 2px;
}
/* If workspaces is the leftmost module, omit left margin */
.modules-left > widget:first-child > #workspaces {
margin-left: 0;
}
/* If workspaces is the rightmost module, omit right margin */
.modules-right > widget:last-child > #workspaces {
margin-right: 0;
}
#battery {
color: #d3869b;
}
#battery.charging, #battery.plugged {
color: #98971a;
}
@keyframes blink {
to {
background-color: #fbf1c7;
color: #df3f71;
}
}
#battery.critical:not(.charging) {
background-color: #1d2021;
color: #d3869b;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
label:focus {
background-color: #000000;
}
#backlight {
color: #458588;
}
#temperature {
color: #fabd2f;
}
#temperature.critical {
background-color: #fbf1c7;
color: #b57614;
}
#memory {
color: #FCF434; /* enby yellow */
}
#disk {
color: #FFFFFF; /* enby white */
}
#network {
color: #b8bb26; /* enby green */
}
#clock {
color: #9C59D1; /* enby purple */
/*color: #2C2C2C; enby black */
}
#network.disconnected {
background-color: #fbf1c7;
color: #9d0006;
}
#wireplumber {
color: #fe8019;
}
#tray {
}
#tray > .needs-attention {
background-color: #fbf1c7;
color: #3c3836;
}
#idle_inhibitor {
background-color: #1d2021;
color: #ebdbb2;
}
#idle_inhibitor.activated {
background-color: #fbf1c7;
color: #3c3836;
}
#custom-media {
background-color: #66cc99;
color: #2a5c45;
min-width: 100px;
}
#custom-media.custom-spotify {
background-color: #66cc99;
}
#custom-media.custom-vlc {
background-color: #ffa000;
}
#mpd {
background-color: #66cc99;
color: #2a5c45;
}
#mpd.disconnected {
background-color: #f53c3c;
}
#mpd.stopped {
background-color: #90b1b1;
}
#mpd.paused {
background-color: #51a37a;
}
#language {
background: #00b093;
color: #740864;
padding: 0 5px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state {
background: #97e1ad;
color: #000000;
padding: 0 0px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state > label {
padding: 0 5px;
}
#keyboard-state > label.locked {
background: rgba(0, 0, 0, 0.2);
}
'';
settings = {
mainBar = {
layer = "top";
position = "top";
height = 15;
modules-left = [ "river/tags" "river/layout" "river/window" ];
modules-right = [ "tray" "power_profiles_daemon" "idle_inhibitor" "wireplumber" "battery" "backlight" "cpu" "temperature" "memory" "disk" "custom/tailscale" "network" "clock" ];
"river/window" = {
max-length = 40;
};
wireplumber = {
"format" = "{icon} {volume}%";
"format-muted" = " MUTE";
# "on-click" = "${pkgs.pwvucontrol}/bin/pwvucontrol";
"on-click" = "${pkgs.pavucontrol}/bin/pavucontrol";
"on-click-right" = "${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
"format-icons" = [ "" "" "" ];
};
"backlight" = {
"device" = "amdgpu_bl1";
"format" = "{icon} {percent}%";
"format-icons" = [ "󰃚" "󰃛" "󰃜" "󰃝" "󰃞" "󰃟" "󰃠" ];
"on-scroll-up" = "${pkgs.brightnessctl}/bin/brightnessctl s +10";
"on-scroll-down" = "${pkgs.brightnessctl}/bin/brightnessctl s 10-";
};
"idle_inhibitor" = {
format = "{icon} ";
format-icons = {
"activated" = "󰅶";
"deactivated" = "󰾪";
};
};
battery = {
"states" = {
"warning" = 30;
"critical" = 15;
};
"format" = "{icon} {capacity}%";
"format-icons" = [ "" "" "" "" "" ];
"tooltip-format" = "Capacity: {capacity}%\nPower Draw: {power:0.2f}W\n{timeTo}\nCycles: {cycles}";
"max-length" = 25;
};
"cpu" = {
"interval" = 10;
"format" = " {:0.0f}%";
"max-length" = 10;
};
"temperature" = {
"format" = " {temperatureC}°C";
};
memory = {
interval = 30;
format = " {used:0.0f}/{total:0.0f}GB";
};
clock = {
interval = 1;
format = "{:%Y-%m-%dT%H:%M:%S%z}";
"tooltip-format" = "<tt><small>{calendar}</small></tt>";
"calendar" = {
"mode" = "year";
"mode-mon-col" = 3;
"weeks-pos" = "right";
"on-scroll" = 1;
"format" = {
"months" = "<span color='#ffead3'><b>{}</b></span>";
"days" = "<span color='#ecc6d9'><b>{}</b></span>";
"weeks" = "<span color='#99ffdd'><b>W{}</b></span>";
"weekdays" = "<span color='#ffcc66'><b>{}</b></span>";
"today" = "<span color='#ff6699'><b><u>{}</u></b></span>";
};
};
"actions" = {
"on-click-right" = "mode";
"on-scroll-up" = "shift_up";
"on-scroll-down" = "shift_down";
};
};
disk = {
format = "󰋊 {specific_used:0.0f}/{specific_total:0.0f}GB";
unit = "GB";
path = "/persistent";
};
# "custom/tailscale" = {
# exec = pkgs.writeScript "tailscaleWaybar.sh" ''
# #!${pkgs.bash}/bin/bash
# TAILNET=$(${pkgs.tailscale}/bin/tailscale status --json | ${pkgs.jq}/bin/jq -j '.MagicDNSSuffix')
# echo "''${''${TAILNET%.ts.net}:(-15)}"
# '';
# interval = 30;
# };
"network" = {
"on-click" = "${pkgs.alacritty}/bin/alacritty --class floating-alacritty -e ${pkgs.impala}/bin/impala";
"format" = "{ifname}";
"format-wifi" = "󰖩 {essid}";
"format-ethernet" = "󰈀 {ifname}";
"format-disconnected" = "󰖪";
"tooltip-format" = "{ifname} via {gwaddr}\n{ipaddr}/{cidr}";
"tooltip-format-wifi" = "{essid} ({signaldBm} dBm) {frequency} GHz\n{ipaddr}/{cidr}";
"tooltip-format-ethernet" = "{ifname}\n{ipaddr}/{cidr}";
"tooltip-format-disconnected" = "Disconnected";
"max-length" = 50;
};
};
};
};
wayland.windowManager.river = {
enable = true;
systemd.enable = true;
xwayland.enable = true;
settings = {
map = {
normal =
let
scrn = pkgs.writeScript "scrn.sh" ''
#!${pkgs.bash}/bin/bash
IMG_FILE=~/Images/screenshots/scrn-$(date +\"%Y-%m-%d-%H-%M-%S\").png
${pkgs.grim}/bin/grim $IMG_FILE
${pkgs.wl-clipboard}/bin/wl-copy < $IMG_FILE
${pkgs.libnotify}/bin/notify-send -i $IMG_FILE -e -t 10000 "Screenshot Saved" $IMG_FILE
'';
slurpscrn = pkgs.writeScript "scurpscrn.sh" ''
#!${pkgs.bash}/bin/bash
IMG_FILE=~/Images/screenshots/scrn-$(date +\"%Y-%m-%d-%H-%M-%S\").png
${pkgs.slurp}/bin/slurp | ${pkgs.grim}/bin/grim -g - $IMG_FILE
${pkgs.wl-clipboard}/bin/wl-copy < $IMG_FILE
${pkgs.libnotify}/bin/notify-send -i $IMG_FILE -e -t 10000 "Screenshot Saved" $IMG_FILE
'';
in
{
"Super+Alt 4" = "spawn '${slurpscrn}'";
"Super+Alt 1" = "spawn '${scrn}'";
"Super+Shift Space" = "spawn 'rofi -show drun'";
"Super+Shift A" = "spawn alacritty";
"Super+Shift F" = "spawn nautilus";
"Super Q" = "close";
"Super J" = "focus-view next";
"Super K" = "focus-view previous";
"Super Up" = "focus-view next";
"Super Down" = "focus-view previous";
"Super+Shift J" = "swap next";
"Super+Shift K" = "swap previous";
"Super+Shift Up" = "swap next";
"Super+Shift Down" = "swap previous";
"Super Period" = "focus-output right";
"Super Comma" = "focus-output left";
"Super+Control Period" = "send-to-output -current-tags right";
"Super+Control Comma" = "send-to-output -current-tags left";
"Super Return" = "zoom";
"Super H" = ''send-layout-cmd rivertile "main-ratio -0.05"'';
"Super L" = ''send-layout-cmd rivertile "main-ratio +0.05"'';
"Super Left" = ''send-layout-cmd rivertile "main-ratio -0.05"'';
"Super Right" = ''send-layout-cmd rivertile "main-ratio +0.05"'';
"Super+Shift H" = ''send-layout-cmd rivertile "main-count -1"'';
"Super+Shift L" = ''send-layout-cmd rivertile "main-count +1"'';
"Super+Shift Left" = ''send-layout-cmd rivertile "main-count -1"'';
"Super+Shift Right" = ''send-layout-cmd rivertile "main-count +1"'';
# Super+Alt+{H,J,K,L} to move views
"Super+Alt H" = "move left 100";
"Super+Alt J" = "move down 100";
"Super+Alt K" = "move up 100";
"Super+Alt L" = "move right 100";
# Super+Alt+Control+{H,J,K,L} to snap views to screen edges
"Super+Alt+Control H" = "snap left";
"Super+Alt+Control J" = "snap down";
"Super+Alt+Control K" = "snap up";
"Super+Alt+Control L" = "snap right";
# Super+Alt+Shift+{H,J,K,L} to resize views
"Super+Alt+Shift H" = "resize horizontal -100";
"Super+Alt+Shift J" = "resize vertical 100";
"Super+Alt+Shift K" = "resize vertical -100";
"Super+Alt+Shift L" = "resize horizontal 100";
} // (lib.zipAttrs (map
(x_int:
let
tags = toString (pow 2 (x_int - 1));
x = toString x_int;
in
{
"Super ${x}" = "set-focused-tags ${tags}";
"Super+Shift ${x}" = "set-view-tags ${tags}";
"Super+Control ${x}" = "toggle-focused-tags ${tags}";
"Super+Shift+Control ${x}" = "toggle-view-tags ${tags}";
}
)
(lib.range 1 9)))
// {
"Super 0" = "set-focused-tags 4294967295"; # $(((1 << 32) - 1))
"Super+Shift 0" = "set-view-tags 4294967295"; # $(((1 << 32) - 1))
"Super P" = "toggle-focused-tags ${scratchTag}";
"Super+Shift P" = "set-view-tags ${scratchTag}";
# Super+Space to toggle float
"Super Space" = "toggle-float";
# Super+F to toggle fullscreen
"Super F" = "toggle-fullscreen";
# Super+{Up,Right,Down,Left} to change layout orientation
"Super Up" = ''send-layout-cmd rivertile "main-location top"'';
"Super Right" = ''send-layout-cmd rivertile "main-location right"'';
"Super Down" = ''send-layout-cmd rivertile "main-location bottom"'';
"Super Left" = ''send-layout-cmd rivertile "main-location left"'';
# Control pulse audio volume with pamixer (https://github.com/cdemoulins/pamixer)
"None XF86AudioRaiseVolume" = "spawn 'pamixer -i 5'";
"None XF86AudioLowerVolume" = "spawn 'pamixer -d 5'";
"None XF86AudioMute" = "spawn 'pamixer --toggle-mute'";
# Control MPRIS aware media players with playerctl (https://github.com/altdesktop/playerctl)
"None XF86AudioMedia" = "spawn 'playerctl play-pause'";
"None XF86AudioPlay" = "spawn 'playerctl play-pause'";
"None XF86AudioPrev" = "spawn 'playerctl previous'";
"None XF86AudioNext" = "spawn 'playerctl next'";
# Control screen backlight brightness with brightnessctl (https://github.com/Hummer12007/brightnessctl)
"None XF86MonBrightnessUp" = "spawn 'brightnessctl set +5%'";
"None XF86MonBrightnessDown" = "spawn 'brightnessctl set 5%-'";
}
;
};
map-pointer.normal = {
# Super + Left Mouse Button to move views
"Super BTN_LEFT" = "move-view";
# Super + Right Mouse Button to resize views
"Super BTN_RIGHT" = "resize-view";
# Super + Middle Mouse Button to toggle float
"Super BTN_MIDDLE" = "toggle-float";
};
border-color-focused = "0x7c6f64"; # bg4
border-color-unfocused = "0x3c3836"; # bg1
focus-follows-cursor = "normal";
input = {
"pointer-2362-628-PIXA3854:00_093A:0274_Touchpad" = "tap enabled";
};
keyboard-layout = "eu";
xcursor-theme = "Adwaita";
default-layout = "rivertile";
spawn-tagmask = "4293918719"; # (( ((1 << 32) - 1) ^ (1 << 20) )) all but scratch tag
rule-add = {
"-title 'Picture-in-Picture'" = "float";
"-app-id 'floating-alacritty'" = "float";
"-app-id 'org.pulseaudio.pavucontrol'" = "float";
"-app-id 'KeePassXC'" = "float";
"-app-id 'org.gnome.NautilusPreviewer'" = "float";
"-app-id 'Signal'" = "tags ${tag 9}"; # signal
"-app-id 'Element'" = "tags ${tag 9}"; # cinny
"-app-id 'FFPWA-01JHNYASHBQB122KMCDPEZ65JA'" = "tags ${tag 9}"; # yt music
"-app-id 'org.gnome.evolution'" = "tags ${tag 8}"; # evolution
"-app-id 'obsidian'" = "tags ${tag 1}"; # obsidian
"-app-id 'KeePassXC' " = "tags ${scratchTag}";
};
};
extraConfig = ''
export XDG_CURRENT_DESKTOP=river
export SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent
rivertile -view-padding 0 -outer-padding 0 &
swayidle \
timeout 300 'swaylock -i ${backgroundImage}' \
timeout 600 'wlopm --off \*' resume 'wlopm --on \*' \
before-sleep 'swaylock -i ${backgroundImage}' &
# swaybg -i ${backgroundImage} &
${setRandomBackground} &
shikane &
${pkgs.mako}/bin/mako &
# iwgtk likes to crash when restarting iwd
# (while true; do iwgtk -i; sleep 10; done) &
# now autostarting stuff thats always open anyways
obsidian &
signal-desktop &
element-desktop &
evolution &
# ${pkgs.appimage-run}/bin/appimage-run /home/ragon/AppImages/KeePassXC-2.8.0-snapshot-x86_64.AppImage &
keepassxc &
'';
};
# services.wired = {
# enable = true;
# config = ./wired.ron;
# };
}

View file

@ -0,0 +1,308 @@
{ pkgs, config, inputs, ... }: {
# imports = [ inputs.ironbar.homeManagerModules.default ];
home.packages = with pkgs; [
slurp
grim
# mako
# firefox
# light installed via programs.light
playerctl
jq
rofi
# inputs.swaymonad.defaultPackage.x86_64-linux
swaylock
];
# programs.ironbar = {
# enable = false;
# style = ''
# @define-color color_bg #282828;
# @define-color color_bg_dark #3c3836;
# @define-color color_border #665c54;
# @define-color color_border_active #7c6f64;
# @define-color color_text #ebdbb2;
# @define-color color_urgent #cc241d;
# * {
# font-family: Source Sans Pro Nerd Font, sans-serif;
# font-size: 15px;
# border: none;
# border-radius: 0;
# }
# box, menubar, button {
# background-color: @color_bg;
# background-image: none;
# box-shadow: none;
# }
# button, label {
# color: @color_text;
# }
# button:hover {
# background-color: @color_bg_dark;
# }
# scale trough {
# min-width: 1px;
# min-height: 2px;
# }
# /* #bar {
# border-top: 1px solid @color_border;
# } */
# .popup {
# border: 1px solid @color_border;
# padding: 1em;
# }
# '';
# config = {
# position = "top";
# height = 20;
# start = [
# { type = "workspaces"; }
# { type = "sway_mode"; }
# ];
# center = [
# {
# type = "focused";
# show_icon = true;
# show_title = true;
# icon_size = 10;
# truncate = "end";
# }
# ];
# end = [
# { type = "music"; player_name = "mpris"; }
# {
# type = "volume";
# icons = {
# volume_high = "󰕾";
# volume_medium = "󰖀";
# volume_low = "󰕿";
# muted = "󰝟";
# };
# format = "{icon} {percentage}%";
# max_volume = 100;
# }
# {
# type = "upower";
# format = "{icon} {percentage}%";
# }
# {
# type = "sys_info";
# format = [
# " {cpu_percent}%"
# " {temp_c:k10temp-Tctl}°C"
# " {memory_used}/{memory_total}GB"
# "󰋊 {disk_used:/persistent}/{disk_total:/persistent}GB"
# "󰓢 {net_down:wlan0}/{net_up:wlan0} Mbps"
# # "󰖡 {load_average:1} | {load_average:5} | {load_average:15}"
# ];
# interval = {
# "cpu" = 1;
# "disks" = 300;
# "memory" = 30;
# "networks" = 3;
# "temps" = 5;
# };
# }
# {
# type = "clock";
# format = "%Y-%m-%dT%H:%M:%S%z";
# }
# ];
# };
# };
# TODO: change to home-manager module somehow
home.file.".config/sway/config".text = ''
set $mod Mod4
set $term wezterm
set $screenclip slurp | grim -g - ~/Images/screenshots/scrn-$(date +"%Y-%m-%d-%H-%M-%S").png
set $screenshot grim ~/Images/screenshots/scrn-$(date +"%Y-%m-%d-%H-%M-%S").png
set $menu rofi -show drun -run-command 'swaymsg exec -- {cmd}'
set $lock swaylock -c 000000
exec --no-statup-id ${pkgs.kanshi}/bin/kanshi
set $cl_high #009ddc
set $cl_indi #d9d8d8
set $cl_back #231f20
set $cl_fore #d9d8d8
set $cl_urge #ee2e24
# Colors border bg text indi childborder
client.focused $cl_high $cl_high $cl_fore $cl_indi $cl_high
client.focused_inactive $cl_back $cl_back $cl_fore $cl_back $cl_back
client.unfocused $cl_back $cl_back $cl_fore $cl_back $cl_back
client.urgent $cl_urge $cl_urge $cl_fore $cl_urge $cl_urge
# workspaces
set $ws1 1:1
set $ws2 2:2
set $ws3 3:3
set $ws4 4:4
set $ws5 5:5
set $ws6 6:6
set $ws7 7:7
set $ws8 8:8
set $ws9 9:9
set $ws0 10:10
exec --no-startup-id mako
exec --no-startup-id ironbar
input * {
xkb_layout eu
}
input 12972:6:FRMW0004:00_32AC:0006_Consumer_Control {
xkb_layout us
xkb_variant colemak_dh_iso
xkb_options caps:escape
}
input type:touchpad {
tap enabled
}
bindsym $mod+Shift+Return exec $term
bindsym $mod+Space exec $menu
bindsym $mod+Print exec $screenshot
bindsym $mod+Shift+Print exec $screenclip
bindsym $mod+Shift+q kill
bindsym $mod+Shift+c reload
# Brightness controls
bindsym --locked XF86MonBrightnessUp exec --no-startup-id light -A 10
bindsym --locked XF86MonBrightnessDown exec --no-startup-id light -U 10
# Multimedia
bindsym --locked XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume $(pacmd list-sinks |awk '/* index:/{print $3}') +5%
bindsym --locked XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume $(pacmd list-sinks |awk '/* index:/{print $3}') -5%
bindsym --locked XF86AudioMute exec --no-startup-id pactl set-sink-mute $(pacmd list-sinks |awk '/* index:/{print $3}') toggle
bindsym --locked XF86AudioPlay exec playerctl play-pause
bindsym --locked XF86AudioNext exec playerctl next
bindsym --locked XF86AudioPrev exec playerctl previous
# Idle configuration
exec swayidle \
timeout 300 'exec $lock' \
timeout 600 'swaymsg "output * dpms off"' \
after-resume 'swaymsg "output * dpms on"' \
before-sleep 'exec $lock'
# switch to workspace
bindsym $mod+1 workspace $ws1
bindsym $mod+2 workspace $ws2
bindsym $mod+3 workspace $ws3
bindsym $mod+4 workspace $ws4
bindsym $mod+5 workspace $ws5
bindsym $mod+6 workspace $ws6
bindsym $mod+7 workspace $ws7
bindsym $mod+8 workspace $ws8
bindsym $mod+9 workspace $ws9
bindsym $mod+0 workspace $ws0
# move focused container to workspace
bindsym $mod+Shift+1 move container to workspace $ws1
bindsym $mod+Shift+2 move container to workspace $ws2
bindsym $mod+Shift+3 move container to workspace $ws3
bindsym $mod+Shift+4 move container to workspace $ws4
bindsym $mod+Shift+5 move container to workspace $ws5
bindsym $mod+Shift+6 move container to workspace $ws6
bindsym $mod+Shift+7 move container to workspace $ws7
bindsym $mod+Shift+8 move container to workspace $ws8
bindsym $mod+Shift+9 move container to workspace $ws9
bindsym $mod+Shift+0 move container to workspace $ws0
# Layout stuff:
# Make the current focus fullscreen
bindsym $mod+Shift+f fullscreen
# Toggle the current focus between tiling and floating mode
bindsym $mod+Shift+space floating toggle
# Swap focus between the tiling area and the floating area
# bindsym $mod+f focus mode_toggle
# Move the currently focused window to the scratchpad
bindsym $mod+Shift+minus move scratchpad
# Show the next scratchpad window or hide the focused scratchpad window.
# If there are multiple scratchpad windows, this command cycles through them.
bindsym $mod+minus scratchpad show
set $mode_system System: (l) lock, (e) logout, (s) suspend, (r) reboot, (S) shutdown, (R) UEFI
mode "$mode_system" {
bindsym l exec $lock, mode "default"
bindsym e exit
bindsym s exec --no-startup-id systemctl suspend, mode "default"
bindsym r exec --no-startup-id systemctl reboot, mode "default"
bindsym Shift+s exec --no-startup-id systemctl poweroff -i, mode "default"
bindsym Shift+r exec --no-startup-id systemctl reboot --firmware-setup, mode "default"
# return to default mode
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+Shift+e mode "$mode_system"
# exec_always "pkill -f 'python3? .+/swaymonad.py'; swaymonad"
bindsym $mod+Return nop promote_window
bindsym $mod+j nop focus_next_window
bindsym $mod+k nop focus_prev_window
bindsym $mod+Down nop focus_next_window
bindsym $mod+Up nop focus_prev_window
bindsym $mod+Shift+Left nop move left
bindsym $mod+Shift+Down nop move down
bindsym $mod+Shift+Up nop move up
bindsym $mod+Shift+Right nop move right
bindsym $mod+Shift+j nop swap_with_next_window
bindsym $mod+Shift+k nop swap_with_prev_window
bindsym $mod+x nop reflectx
bindsym $mod+y nop reflecty
bindsym $mod+t nop transpose
bindsym $mod+f nop fullscreen
bindsym $mod+Comma nop increment_masters
bindsym $mod+Period nop decrement_masters
mode "resize" {
bindsym Left resize shrink width 10px
bindsym Down resize grow height 10px
bindsym Up resize shrink height 10px
bindsym Right resize grow width 10px
bindsym Shift+Left nop resize_master shrink width 10px
bindsym Shift+Down nop resize_master grow height 10px
bindsym Shift+Up nop resize_master shrink height 10px
bindsym Shift+Right nop resize_master grow width 10px
# bindsym n resize set width (n-1/n)
bindsym 2 resize set width 50ppt # 1/2, 1/2
bindsym 3 resize set width 66ppt # 2/3, 1/3
bindsym 4 resize set width 75ppt # 3/4, 1/4
bindsym Shift+2 nop resize_master set width 50ppt
bindsym Shift+3 nop resize_master set width 66ppt
bindsym Shift+4 nop resize_master set width 75ppt
bindsym Return mode "default"
bindsym Escape mode "default"
}
bindsym $mod+r mode "resize"
mode "layout" {
bindsym t nop set_layout tall
bindsym 2 nop set_layout 2_col
bindsym 3 nop set_layout 3_col
bindsym n nop set_layout nop
bindsym Return mode "default"
bindsym Escape mode "default"
}
# nop set_layout 2_col
bindsym $mod+l mode "layout"
mouse_warping container
focus_wrapping no
'';
}

View file

@ -0,0 +1,381 @@
{ pkgs, config, lib, ... }:
let
cfg = config.xyno.desktop.waybar;
waybarConf = pkgs.writeText "waybar.conf" ''
font=Source Sans Pro Nerd Font
background-color=#1d2021ff
border-color=#3c3836FF
text-color=#ebdbb2ff
progress-color=over #928374FF
'';
in
{
options.xyno.desktop.waybar.enable = lib.mkEnableOption "enable mako notification daemon";
options.xyno.desktop.waybar.wantedBy = lib.mkOption {
type = lib.types.str;
default = "niri.service";
};
options.xyno.desktop.waybar.package = lib.mkOption {
type = lib.types.package;
default = pkgs.waybar;
};
options.xyno.desktop.waybar.mode = lib.mkOption {
type = lib.types.str;
default = "niri";
};
config = lib.mkIf cfg.enable {
programs.waybar.enable = true;
environment.etc."xdg/waybar/config".text = builtins.toJSON {
mainBar = {
layer = "top";
position = "top";
height = 15;
modules-left = (lib.mkIf (cfg.mode == "river") [ "river/tags" "river/layout" "river/window" ])
++ (lib.mkIf (cfg.mode == "niri") [ "niri/workspaces" "niri/window" ]);
modules-right = [ "tray" "power_profiles_daemon" "idle_inhibitor" "wireplumber" "battery" "backlight" "cpu" "temperature" "memory" "disk" "custom/tailscale" "network" "clock" ];
"river/window" = {
max-length = 40;
};
wireplumber = {
"format" = "{icon} {volume}%";
"format-muted" = " MUTE";
# "on-click" = "${pkgs.pwvucontrol}/bin/pwvucontrol";
"on-click" = "${pkgs.pavucontrol}/bin/pavucontrol";
"on-click-right" = "${pkgs.wireplumber}/bin/wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle";
"format-icons" = [ "" "" "" ];
};
"backlight" = {
"device" = "amdgpu_bl1";
"format" = "{icon} {percent}%";
"format-icons" = [ "󰃚" "󰃛" "󰃜" "󰃝" "󰃞" "󰃟" "󰃠" ];
"on-scroll-up" = "${pkgs.brightnessctl}/bin/brightnessctl s +10";
"on-scroll-down" = "${pkgs.brightnessctl}/bin/brightnessctl s 10-";
};
"idle_inhibitor" = {
format = "{icon} ";
format-icons = {
"activated" = "󰅶";
"deactivated" = "󰾪";
};
};
battery = {
"states" = {
"warning" = 30;
"critical" = 15;
};
"format" = "{icon} {capacity}%";
"format-icons" = [ "" "" "" "" "" ];
"tooltip-format" = "Capacity: {capacity}%\nPower Draw: {power:0.2f}W\n{timeTo}\nCycles: {cycles}";
"max-length" = 25;
};
"cpu" = {
"interval" = 10;
"format" = " {:0.0f}%";
"max-length" = 10;
};
"temperature" = {
"format" = " {temperatureC}°C";
};
memory = {
interval = 30;
format = " {used:0.0f}/{total:0.0f}GB";
};
clock = {
interval = 1;
format = "{:%Y-%m-%dT%H:%M:%S%z}";
"tooltip-format" = "<tt><small>{calendar}</small></tt>";
"calendar" = {
"mode" = "year";
"mode-mon-col" = 3;
"weeks-pos" = "right";
"on-scroll" = 1;
"format" = {
"months" = "<span color='#ffead3'><b>{}</b></span>";
"days" = "<span color='#ecc6d9'><b>{}</b></span>";
"weeks" = "<span color='#99ffdd'><b>W{}</b></span>";
"weekdays" = "<span color='#ffcc66'><b>{}</b></span>";
"today" = "<span color='#ff6699'><b><u>{}</u></b></span>";
};
};
"actions" = {
"on-click-right" = "mode";
"on-scroll-up" = "shift_up";
"on-scroll-down" = "shift_down";
};
};
disk = {
format = "󰋊 {specific_used:0.0f}/{specific_total:0.0f}GB";
unit = "GB";
path = "/persistent";
};
"network" = {
"on-click" = "${pkgs.alacritty}/bin/alacritty --class floating-alacritty -e ${pkgs.impala}/bin/impala";
"format" = "{ifname}";
"format-wifi" = "󰖩 {essid}";
"format-ethernet" = "󰈀 {ifname}";
"format-disconnected" = "󰖪";
"tooltip-format" = "{ifname} via {gwaddr}\n{ipaddr}/{cidr}";
"tooltip-format-wifi" = "{essid} ({signaldBm} dBm) {frequency} GHz\n{ipaddr}/{cidr}";
"tooltip-format-ethernet" = "{ifname}\n{ipaddr}/{cidr}";
"tooltip-format-disconnected" = "Disconnected";
"max-length" = 50;
};
};
};
environment.etc."xdg/waybar/style.css".text = ''
* {
/* `otf-font-awesome` is required to be installed for icons */
font-family: "Source Sans Pro Nerd Font";
font-size: 12px;
}
window#waybar {
/* background-color: rgba(43, 48, 59, 0.5);
border-bottom: 3px solid rgba(100, 114, 125, 0.5);*/
color: #a89984;
background-color: #1d2021;
/* transition-property: background-color;
transition-duration: .5s;*/
}
window#waybar.hidden {
opacity: 0.2;
}
/*
window#waybar.empty {
background-color: transparent;
}
window#waybar.solo {
background-color: #FFFFFF;
}
*/
/*window#waybar.termite {
background-color: #3F3F3F;
}
window#waybar.chromium {
background-color: #000000;
border: none;
}*/
#tags button {
padding: 0 2px;
background-color: #1d2021;
color: #ebdbb2;
/* Use box-shadow instead of border so the text isn't offset */
box-shadow: inset 0 -3px transparent;
/* Avoid rounded borders under each workspace name */
border: none;
border-radius: 0;
}
/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */
#tags button:hover {
background: rgba(0, 0, 0, 0.2);
/* box-shadow: inset 0 -3px #fbf1c7;
*/
background-color: #3c3836;
}
#tags button.focused {
/* box-shadow: inset 0 -3px #fbf1c7;
*/
background-color: #3c3836;
color: #ebdbb2;
}
#tags button.occupied {
color: #d3869b;
}
#tags button.urgent {
background-color: #cc241d;
color: #ebdbb2;
}
#mode {
background-color: #64727D;
border-bottom: 3px solid #fbf1c7;
}
#clock,
#battery,
#cpu,
#memory,
#disk,
#temperature,
#backlight,
#network,
#pulseaudio,
#custom-media,
#tray,
#mode,
#idle_inhibitor,
#custom-poweroff,
#custom-suspend,
#mpd {
padding: 0 2px;
background-color: #1d2021;
color: #ebdbb2;
}
#window,
#workspaces,
#tags {
margin: 0 2px;
}
/* If workspaces is the leftmost module, omit left margin */
.modules-left > widget:first-child > #workspaces {
margin-left: 0;
}
/* If workspaces is the rightmost module, omit right margin */
.modules-right > widget:last-child > #workspaces {
margin-right: 0;
}
#battery {
color: #d3869b;
}
#battery.charging, #battery.plugged {
color: #98971a;
}
@keyframes blink {
to {
background-color: #fbf1c7;
color: #df3f71;
}
}
#battery.critical:not(.charging) {
background-color: #1d2021;
color: #d3869b;
animation-name: blink;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-direction: alternate;
}
label:focus {
background-color: #000000;
}
#backlight {
color: #458588;
}
#temperature {
color: #fabd2f;
}
#temperature.critical {
background-color: #fbf1c7;
color: #b57614;
}
#memory {
color: #FCF434; /* enby yellow */
}
#disk {
color: #FFFFFF; /* enby white */
}
#network {
color: #b8bb26; /* enby green */
}
#clock {
color: #9C59D1; /* enby purple */
/*color: #2C2C2C; enby black */
}
#network.disconnected {
background-color: #fbf1c7;
color: #9d0006;
}
#wireplumber {
color: #fe8019;
}
#tray {
}
#tray > .needs-attention {
background-color: #fbf1c7;
color: #3c3836;
}
#idle_inhibitor {
background-color: #1d2021;
color: #ebdbb2;
}
#idle_inhibitor.activated {
background-color: #fbf1c7;
color: #3c3836;
}
#custom-media {
background-color: #66cc99;
color: #2a5c45;
min-width: 100px;
}
#custom-media.custom-spotify {
background-color: #66cc99;
}
#custom-media.custom-vlc {
background-color: #ffa000;
}
#mpd {
background-color: #66cc99;
color: #2a5c45;
}
#mpd.disconnected {
background-color: #f53c3c;
}
#mpd.stopped {
background-color: #90b1b1;
}
#mpd.paused {
background-color: #51a37a;
}
#language {
background: #00b093;
color: #740864;
padding: 0 5px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state {
background: #97e1ad;
color: #000000;
padding: 0 0px;
margin: 0 5px;
min-width: 16px;
}
#keyboard-state > label {
padding: 0 5px;
}
#keyboard-state > label.locked {
background: rgba(0, 0, 0, 0.2);
}
'';
};
}

View file

@ -0,0 +1,302 @@
(
// Maximum number of notifications to show at any one time.
// A value of 0 means that there is no limit.
max_notifications: 0,
// The default timeout, in miliseconds, for notifications that don't have an initial timeout set.
// 1000ms = 1s.
timeout: 10000,
// How should we handle `expire_timeout` values of zero?
// `UseDefault`: use `timeout`.
// `NeverExpire`: show this notification forever.
// The latter is technically correct according to the notification spec: https://specifications.freedesktop.org/notification-spec/notification-spec-latest.html
zero_timeout_behavior: NeverExpire,
// `poll_interval` decides decides how often (in milliseconds) Wired checks events,
// draws notifications (if necessary) -- the update loop while any notification is present.
// Note that when no notifications are present, Wired polls at `idle_poll_interval` instead.
// 16ms ~= 60hz / 7ms ~= 144hz.
poll_interval: 16,
// The interval at which wired updates when no notifications/windows are present.
//idle_poll_interval: 500,
// Wired will pause notifications if you are idle (no mouse or keyboard input) for longer than
// `idle_threshold` seconds.
// Note that notifications will not be automatically unpaused on wake, and will need to be manually
// cleared, unless `unpause_on_input` is set to true.
// Also note that no distinction is made between manually paused and idle paused notifications.
// If `idle_threshold` is not specified, the behavior will be disabled entirely.
//idle_threshold: 3600,
// Notifications will spawn paused, and have to be manually unpaused or cleared by the user,
// unless `unpause_on_input` is also set.
//notifications_spawn_paused: false,
// Unpause notifications when we receive any input after being idle for longer than 1 second.
// Note that no distinction is made between manually paused notifications and idle paused/spawned notifications.
//unpause_on_input: false,
// Enable/disable replacement functionality.
// If this is disabled, replacement requests will just send a new notification.
// E.g., with replacing_enabled: true, Pidgin will only show the latest message from each contact,
// instead of sending a new one for each message.
// Default: true
//replacing_enabled: true,
// Whether a notification should reset its timeout when it is replaced.
// No effect if replacing_enabled is set to false.
// Default: false
//replacing_resets_timeout: false,
// Some apps/programs close notifications on their own by sending a request to dbus.
// Sometimes this is not desired.
// Default: true
//closing_enabled: true,
// How many notifications are kept in history.
// Each notification is roughly 256 bytes (excluding buffers!), so there's some math to do here.
// Default: 100
//history_length: 100,
// When a `NotificationBlock` has monitorr: -1 (i.e. should follow active monitor), then what input
// should we use to determine the active monitor?
// Options: Mouse, Window
// Default: Mouse
//focus_follows: Mouse,
// Enable printing notification data to a file.
// Useful for scripting purposes.
// The data is written as JSON.
// Default: None
//print_to_file: "/tmp/wired.log",
// Minimum window width and height. This is used to create the base rect that the notification
// grows within.
// The notification window will never be smaller than this.
// A value of 1 means that the window will generally always resize with notification, unless
// you have a 1x1 pixel notification...
// Generally, you shouldn't need to set this.
min_window_width: 325,
//min_window_height: 1,
// Trim whitespace in received notification text, since some clients like to send whitespace, which we usually don't actually want.
//trim_whitespace: true,
// Enable/disable debug rendering.
debug: false,
debug_color: Color(r: 0.0, g: 1.0, b: 0.0, a: 1.0), // Primary color for debug rectangles.
debug_color_alt: Color(r: 1.0, g: 0.0, b: 0.0, a: 1.0), // Secondary color for debug rectangles.
layout_blocks: [
// Layout 1, when an image is present.
(
name: "root",
parent: "",
hook: Hook(parent_anchor: TR, self_anchor: TR),
offset: Vec2(x: -15, y: 15),
//render_criteria: [HintImage],
// https://github.com/Toqozz/wired-notify/wiki/NotificationBlock
params: NotificationBlock((
monitor: 0,
border_width: 2.0,
border_rounding: 0.0,
background_color: Color(hex: "#11111b"),
border_color: Color(hex: "#cba6f7"),
border_color_low: Color(hex: "#89b4fa"),
border_color_critical: Color(hex: "#f38ba8"),
border_color_paused: Color(hex: "#f9e2af"),
gap: Vec2(x: 0.0, y: 10),
notification_hook: Hook(parent_anchor: BR, self_anchor: TR),
)),
),
(
name: "image",
parent: "root",
hook: Hook(parent_anchor: ML, self_anchor: ML),
offset: Vec2(x: 0.0, y: 0.0),
// https://github.com/Toqozz/wired-notify/wiki/ImageBlock
params: ImageBlock((
image_type: HintThenApp,
padding: Padding(left: 13.0, right: 6.0, top: 0.0, bottom: 10.0),
rounding: 3.0,
scale_width: 48,
scale_height: 48,
filter_mode: Lanczos3,
)),
),
(
name: "summary",
parent: "image",
hook: Hook(parent_anchor: MR, self_anchor: BL),
offset: Vec2(x: 0.0, y: 0.0),
// https://github.com/Toqozz/wired-notify/wiki/TextBlock
params: TextBlock((
text: "%s",
font: "JetBrains Mono 11",
color: Color(hex: "#ffffff"),
padding: Padding(left: 12.0, right: 11.0, top: 12.0, bottom: 12.0),
dimensions: (width: (min: 50, max: 250), height: (min: 0, max: 0)),
)),
),
(
name: "body",
parent: "summary",
hook: Hook(parent_anchor: BL, self_anchor: TL),
offset: Vec2(x: 0.0, y: 0.0),
render_criteria: [Body],
// https://github.com/Toqozz/wired-notify/wiki/ScrollingTextBlock
params: ScrollingTextBlock((
text: "%b",
font: "JetBrains Mono 10",
color: Color(hex: "#a6adc8"),
padding: Padding(left: 11.0, right: 11.0, top: 0.0, bottom: 11.0),
width: (min: 150, max: 300),
scroll_speed: 0.1,
lhs_dist: 35.0,
rhs_dist: 35.0,
scroll_t: 1.0,
)),
),
(
name: "progress",
parent: "summary",
hook: Hook(parent_anchor: BL, self_anchor: TL),
offset: Vec2(x: 0.0, y: -3.0),
render_criteria: [Progress],
// https://github.com/Toqozz/wired-notify/wiki/ProgressBlock
params: ProgressBlock((
padding: Padding(left: 12.0, right: 11.0, top: 6.0, bottom: 11.0),
border_width: 2.0,
border_rounding: 5.0,
fill_rounding: 5.0,
border_color: Color(hex: "#313244"),
background_color: Color(hex: "#1e1e2e"),
fill_color: Color(hex: "#cba6f7"),
width: 230,
height: 15,
)),
),
(
name: "button_0",
parent: "summary",
hook: Hook(parent_anchor: BL, self_anchor: TL),
offset: Vec2(x: 12.0, y: 0.0),
render_criteria: [ActionOther(0)],
// https://github.com/Toqozz/wired-notify/wiki/ButtonBlock
params: ButtonBlock((
padding: Padding(left: 8.0, right: 11.0, top: 6.0, bottom: 5.0),
action: OtherAction(0),
text: "%a",
font: "JetBrains Mono 9",
border_width: 2.0,
border_rounding: 0.0,
text_color: Color(hex: "#a6adc8"),
border_color: Color(hex: "#313244"),
background_color: Color(hex: "#1e1e2e"),
dimensions: (width: (min: 0, max: 150), height: (min: 0, max: 0)),
)),
),
(
name: "button_1",
parent: "button_0",
hook: Hook(parent_anchor: TR, self_anchor: TL),
offset: Vec2(x: 12.0, y: 0.0),
render_criteria: [ActionOther(1)],
// https://github.com/Toqozz/wired-notify/wiki/ButtonBlock
params: ButtonBlock((
padding: Padding(left: 8.0, right: 11.0, top: 6.0, bottom: 5.0),
action: OtherAction(1),
text: "%a",
font: "JetBrains Mono 9",
border_width: 2.0,
border_rounding: 0.0,
text_color: Color(hex: "#a6adc8"),
border_color: Color(hex: "#313244"),
background_color: Color(hex: "#1e1e2e"),
dimensions: (width: (min: 0, max: 150), height: (min: 0, max: 0)),
)),
),
(
name: "button_2",
parent: "button_1",
hook: Hook(parent_anchor: TR, self_anchor: TL),
offset: Vec2(x: 12.0, y: 0.0),
render_criteria: [ActionOther(2)],
// https://github.com/Toqozz/wired-notify/wiki/ButtonBlock
params: ButtonBlock((
padding: Padding(left: 8.0, right: 11.0, top: 6.0, bottom: 5.0),
action: OtherAction(2),
text: "%a",
font: "JetBrains Mono 9",
border_width: 2.0,
border_rounding: 0.0,
text_color: Color(hex: "#a6adc8"),
border_color: Color(hex: "#313244"),
background_color: Color(hex: "#1e1e2e"),
dimensions: (width: (min: 0, max: 150), height: (min: 0, max: 0)),
)),
),
(
name: "button_3",
parent: "button_2",
hook: Hook(parent_anchor: TR, self_anchor: TL),
offset: Vec2(x: 12.0, y: 0.0),
render_criteria: [ActionOther(3)],
// https://github.com/Toqozz/wired-notify/wiki/ButtonBlock
params: ButtonBlock((
padding: Padding(left: 8.0, right: 11.0, top: 6.0, bottom: 5.0),
action: OtherAction(3),
text: "%a",
font: "JetBrains Mono 9",
border_width: 2.0,
border_rounding: 0.0,
text_color: Color(hex: "#a6adc8"),
border_color: Color(hex: "#313244"),
background_color: Color(hex: "#1e1e2e"),
dimensions: (width: (min: 0, max: 150), height: (min: 0, max: 0)),
)),
),
(
name: "padding",
parent: "button_0",
hook: Hook(parent_anchor: BR, self_anchor: TL),
offset: Vec2(x: 0.0, y: 0.0),
render_criteria: [ActionOther(0)],
// https://github.com/Toqozz/wired-notify/wiki/ScrollingTextBlock
params: TextBlock((
text: "",
font: "JetBrains Mono 1",
color: Color(hex: "#ffffff"),
padding: Padding(left: 12.0, right: 0.0, top: 12.0, bottom: 0.0),
dimensions: (width: (min: 0, max: 0), height: (min: 0, max: 0)),
)),
),
],
// https://github.com/Toqozz/wired-notify/wiki/Shortcuts
shortcuts: ShortcutsConfig (
notification_interact: 1,
notification_close: 2,
// notification_closeall: 99,
// notification_pause: 99,
notification_action1: 3,
// notification_action2: 99,
// notification_action3: 99,
// notification_action4: 99,
),
)

View file

@ -0,0 +1,10 @@
{ config, pkgs, lib, ... }: {
home.packages = [
# pkgs.dotnet-sdk_8
pkgs.unstable.dotnet-sdk_9
pkgs.unstable.jetbrains.rider
# pkgs.jetbrains.datagrip
(pkgs.unstable.firefox-devedition.overrideAttrs (super: self: { meta.priority = 1; }))
];
}

View file

@ -0,0 +1,52 @@
{ config, inputs, pkgs, lib, ... }:
{
imports =
[
./hardware-configuration.nix
../../nixos-modules/networking/tailscale.nix
../../nixos-modules/services/ssh.nix
../../nixos-modules/system/agenix.nix
../../nixos-modules/system/persist.nix
../../nixos-modules/user
];
# Don't Use the systemd-boot EFI boot loader.
boot.loader.systemd-boot.enable = true;
programs.mosh.enable = true;
security.sudo.wheelNeedsPassword = false;
networking.useDHCP = true;
services.xserver.enable = true;
services.xserver.displayManager.sddm.enable = true;
services.xserver.desktopManager.plasma5.enable = true;
environment.systemPackages = [
pkgs.whipper
];
home-manager.users.ragon = { pkgs, lib, inputs, config, ... }: {
imports = [
../../hm-modules/nvim
../../hm-modules/zsh
../../hm-modules/tmux
../../hm-modules/xonsh
../../hm-modules/cli.nix
../../hm-modules/files.nix
];
ragon.xonsh.enable = true;
programs.home-manager.enable = true;
home.stateVersion = "23.11";
};
ragon = {
user.enable = true;
services = {
ssh.enable = true;
tailscale.enable = true;
};
};
}

View file

@ -0,0 +1,37 @@
{ config, lib, pkgs, modulesPath, ... }:
{
imports =
[ (modulesPath + "/installer/scan/not-detected.nix")
];
boot.initrd.availableKernelModules = [ "xhci_pci" "ehci_pci" "ahci" "usb_storage" "sd_mod" "sr_mod" "rtsx_pci_sdmmc" ];
boot.initrd.kernelModules = [ ];
boot.kernelModules = [ "kvm-intel" ];
boot.extraModulePackages = [ ];
fileSystems."/" =
{ device = "/dev/disk/by-uuid/e852ae04-9863-4820-a452-26b2f6ab8231";
fsType = "xfs";
};
boot.initrd.luks.devices."cryptroot".device = "/dev/disk/by-uuid/76e36f6c-9f91-47fd-a2f7-c135d8d2a6c0";
fileSystems."/boot" =
{ device = "/dev/disk/by-uuid/86AF-D2AB";
fsType = "vfat";
};
swapDevices = [ { device = "/dev/disk/by-partuuid/2bbe9b96-6019-4d41-ab2c-da419d24d398"; randomEncryption = true; } ];
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
# (the default) this is the recommended approach. When using systemd-networkd it's
# still possible to use this option, but it's recommended to use it in conjunction
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
networking.useDHCP = lib.mkDefault true;
# networking.interfaces.enp0s25.useDHCP = lib.mkDefault true;
# networking.interfaces.wlan0.useDHCP = lib.mkDefault true;
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware;
}