diff --git a/README.md b/README.md index ee0d382..f8496c7 100644 --- a/README.md +++ b/README.md @@ -7,5 +7,12 @@ - `thinkpad` - Thinkpad T480, i5 8350U, 16GB RAM, 256GB NVME - `homelab` - i7 8700T, 32GB RAM, 512GB NVME, 1TB 2.5" SATA +## Todo +- Automatic backups to external drives. +- Better documentation and code structure. +- Use NixOS modules system. + ## Credits -- [orangc's flake](https://git.orangc.net/c/dots) \ No newline at end of file +- [orangc's flake](https://git.orangc.net/c/dots) +- [vimjoyer's tutorials](https://www.youtube.com/@vimjoyer) +- [wallpaper source](https://github.com/er2de2/catppuccin_walls/blob/master/wallpapers_png/autumn_2.0.png) \ No newline at end of file diff --git a/modules/hardware/misc/battery-power.nix b/modules/hardware/misc/battery-power.nix index 3a2ca6b..8c529e1 100644 --- a/modules/hardware/misc/battery-power.nix +++ b/modules/hardware/misc/battery-power.nix @@ -17,8 +17,10 @@ BAT_PCT=`${pkgs.acpi}/bin/acpi -b | ${pkgs.gnugrep}/bin/grep -P -o '[0-9]+(?=%)'` BAT_STA=`${pkgs.acpi}/bin/acpi -b | ${pkgs.gnugrep}/bin/grep -P -o '\w+(?=,)'` echo "`date` battery status:$BAT_STA percentage:$BAT_PCT" - test $BAT_PCT -le 30 && test $BAT_PCT -gt 15 && test $BAT_STA = "Discharging" && DISPLAY=:0.0 ${pkgs.libnotify}/bin/notify-send "Low Battery" "Battery remaining: $BAT_PCT%." - test $BAT_PCT -le 15 && test $BAT_STA = "Discharging" && DISPLAY=:0.0 ${pkgs.libnotify}/bin/notify-send -u critical "Low Battery" "Shutdown at 10%." + export DISPLAY=:0 + export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus + test $BAT_PCT -le 30 && test $BAT_PCT -gt 15 && test $BAT_STA = "Discharging" && ${pkgs.libnotify}/bin/notify-send "Low Battery" "Battery remaining: $BAT_PCT%." + test $BAT_PCT -le 15 && test $BAT_STA = "Discharging" && ${pkgs.libnotify}/bin/notify-send -u critical "Low Battery" "Shutdown at 10%." ''} > /tmp/cron.batt.log 2>&1" ]; }; diff --git a/modules/home/core/cli.nix b/modules/home/core/cli.nix index 86b3c08..4f2dbf6 100644 --- a/modules/home/core/cli.nix +++ b/modules/home/core/cli.nix @@ -49,10 +49,20 @@ initLua = '' vim.opt.clipboard = "unnamedplus" vim.opt.termguicolors = true + vim.g.clipboard = { + name = "OSC 52", + copy = { + ["+"] = require("vim.ui.clipboard.osc52").copy("+"), + ["*"] = require("vim.ui.clipboard.osc52").copy("*"), + }, + paste = { + ["+"] = require("vim.ui.clipboard.osc52").paste("+"), + ["*"] = require("vim.ui.clipboard.osc52").paste("*"), + }, + } require("nvim-tree").setup() vim.api.nvim_create_autocmd("VimEnter", { callback = function() - -- vim.cmd("NvimTreeOpen") vim.cmd("set nu") vim.cmd.wincmd 'p' end, diff --git a/modules/home/core/shell.nix b/modules/home/core/shell.nix index 2a23a42..7c69e47 100644 --- a/modules/home/core/shell.nix +++ b/modules/home/core/shell.nix @@ -37,9 +37,9 @@ "cd" = "z"; "sys" = "sudo systemctl --runtime"; - "sys-log" = "journalctl -f -b -u"; + "sys-log" = "journalctl -o cat -f -b -u"; "user" = "systemctl --user --runtime"; - "user-log" = "journalctl -f -b --user-unit"; + "user-log" = "journalctl -o cat -f -b --user-unit"; "ts" = "sudo tailscale"; "tsip" = "tailscale ip -4"; diff --git a/modules/system/homelab/dash.nix b/modules/system/homelab/dash.nix index d973699..e7d62bf 100644 --- a/modules/system/homelab/dash.nix +++ b/modules/system/homelab/dash.nix @@ -89,6 +89,101 @@ in { }; pages = [ + { + name = "Dashboard"; + show-mobile-header = true; + width = "slim"; + columns = [ + { + size = "small"; + widgets = [ + { + type = "monitor"; + title = "Critical Systems"; + cache = "15s"; + style = "compact"; + show-failing-only = true; + sites = map (e: { + same-tab = true; + allow-insecure = true; + title = builtins.elemAt e 0; + url = builtins.elemAt e 1; + }) monitor; + } + { + type = "dns-stats"; + title = "DNS Stats"; + service = "adguard"; + url = "http://localhost:8088/"; + hour-format = "12h"; + } + { + type = "bookmarks"; + groups = [ + { + links = [{ + same-tab = true; + title = "NixFlake"; + icon = "si:nixos"; + url = "https://flake.satr14.my.id"; + }]; + } + { + links = map (e: { + same-tab = true; + title = builtins.elemAt e 0; + icon = "si:${builtins.elemAt e 1}"; + url = builtins.elemAt e 2; + alt-status-codes = [ 401 ]; + }) bookmarks; + } + ]; + } + { + type = "to-do"; + id = "tasks"; + } + ]; + } + { + size = "full"; + widgets = [ + { + type = "server-stats"; + servers = [{ + type = "local"; + mountpoints = { + "/boot".hide = true; + "/nix/store".hide = true; + "/var/lib/vaultwarden".hide = true; + "/var/lib/private/cryptpad".hide = true; + "/var/lib/acme/proxy.satr14.my.id".hide = true; + }; + }]; + } + { + type = "monitor"; + cache = "1m"; + title = "Services"; + sites = map (e: { + same-tab = true; + allow-insecure = true; + title = builtins.elemAt e 0; + icon = "si:${builtins.elemAt e 1}"; + url = builtins.elemAt e 2; + check-url = builtins.elemAt e 3; + }) homelab.dash; + } + { + type = "docker-containers"; + title = "Containers"; + format-container-names = true; + hide-by-default = true; + } + ]; + } + ]; + } { name = "Home"; show-mobile-header = true; @@ -187,101 +282,6 @@ in { } ]; } - { - name = "Dashboard"; - show-mobile-header = true; - width = "slim"; - columns = [ - { - size = "small"; - widgets = [ - { - type = "monitor"; - title = "Critical Systems"; - cache = "15s"; - style = "compact"; - show-failing-only = true; - sites = map (e: { - same-tab = true; - allow-insecure = true; - title = builtins.elemAt e 0; - url = builtins.elemAt e 1; - }) monitor; - } - { - type = "dns-stats"; - title = "DNS Stats"; - service = "adguard"; - url = "http://localhost:8088/"; - hour-format = "12h"; - } - { - type = "bookmarks"; - groups = [ - { - links = [{ - same-tab = true; - title = "NixFlake"; - icon = "si:nixos"; - url = "https://flake.satr14.my.id"; - }]; - } - { - links = map (e: { - same-tab = true; - title = builtins.elemAt e 0; - icon = "si:${builtins.elemAt e 1}"; - url = builtins.elemAt e 2; - alt-status-codes = [ 401 ]; - }) bookmarks; - } - ]; - } - { - type = "to-do"; - id = "tasks"; - } - ]; - } - { - size = "full"; - widgets = [ - { - type = "server-stats"; - servers = [{ - type = "local"; - mountpoints = { - "/boot".hide = true; - "/nix/store".hide = true; - "/var/lib/vaultwarden".hide = true; - "/var/lib/private/cryptpad".hide = true; - "/var/lib/acme/proxy.satr14.my.id".hide = true; - }; - }]; - } - { - type = "monitor"; - cache = "1m"; - title = "Services"; - sites = map (e: { - same-tab = true; - allow-insecure = true; - title = builtins.elemAt e 0; - icon = "si:${builtins.elemAt e 1}"; - url = builtins.elemAt e 2; - check-url = builtins.elemAt e 3; - }) homelab.dash; - } - { - type = "docker-containers"; - title = "Containers"; - format-container-names = true; - hide-by-default = true; - } - ]; - } - ]; - } ]; }; }; diff --git a/modules/system/homelab/git.nix b/modules/system/homelab/git.nix index db30c7a..2544f90 100644 --- a/modules/system/homelab/git.nix +++ b/modules/system/homelab/git.nix @@ -45,7 +45,7 @@ url = "http://localhost:5080"; #"https://git.proxy.${homelab.domain}"; tokenFile = "/mnt/data/apps/forgejo/token-runner"; labels = [ "self-hosted:host" ]; - hostPackages = with pkgs; [ bash coreutils git nix openssh nodejs ]; + hostPackages = with pkgs; [ bash coreutils git nix openssh bun ]; }; }; systemd.services = { diff --git a/modules/system/homelab/mc-backup.nix b/modules/system/homelab/mc-backup.nix deleted file mode 100644 index 1a2cb96..0000000 --- a/modules/system/homelab/mc-backup.nix +++ /dev/null @@ -1,103 +0,0 @@ -{ pkgs, ... }: let - serverName = "mc0-explorers-creativity"; - serviceName = "minecraft-server-${serverName}"; - backupDir = "/mnt/data/backups/mc"; - keepBackups = 7; # number of backups to retain - rconHost = "localhost"; - rconPort = "25575"; - rconPassword = "howdy"; - ntfyUrl = "http://127.0.0.1:8067"; - ntfyTopic = "mc-backup"; - - backupScript = pkgs.writeShellScriptBin "mc-backup" '' - set -euo pipefail - - rcon() { - ${pkgs.rcon-cli}/bin/rcon-cli --address "${rconHost}:${rconPort}" --password "${rconPassword}" "$@" || true - } - - BACKUP_OK=false - - on_exit() { - # Always restart the server first - echo "[mc-backup] Restarting server..." - systemctl start ${serviceName}.service - - # Notify via ntfy only on failure - if [ "$BACKUP_OK" != "true" ]; then - echo "[mc-backup] Sending failure notification..." - ${pkgs.curl}/bin/curl -s -o /dev/null \ - -H "Title: Minecraft Backup Failed" \ - -H "Priority: high" \ - -H "Tags: warning" \ - -d "Nightly backup failed at $(date '+%Y-%m-%d %H:%M:%S'). Check logs with: journalctl -u mc-backup -n 50" \ - "${ntfyUrl}/${ntfyTopic}" - fi - } - - # Always restart the server on exit, even if the script fails mid-backup - trap on_exit EXIT - - # --- Countdown warnings via RCON --- - echo "[mc-backup] Sending 5-minute warning..." - rcon "say §c[Backup] §fServer will restart in §e5 minutes §ffor a scheduled backup." - - sleep 240 - - echo "[mc-backup] Sending 1-minute warning..." - rcon "say §c[Backup] §fServer restarting in §e1 minute§f." - - sleep 50 - - echo "[mc-backup] Sending 10-second warning..." - rcon "say §c[Backup] §fServer restarting in §e10 seconds§f." - - sleep 10 - - rcon "say §c[Backup] §fShutting down now. Back shortly!" - - # --- Save world & stop --- - echo "[mc-backup] Saving world..." - rcon "save-all" - sleep 5 - - echo "[mc-backup] Stopping ${serviceName}..." - systemctl stop ${serviceName}.service - - # --- Backup --- - echo "[mc-backup] Backing up to ${backupDir}..." - mkdir -p "${backupDir}" - TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S) - XZ_OPT="-9e" tar -cJf "${backupDir}/mc-backup-$TIMESTAMP.tar.xz" \ - -C /srv/minecraft ${serverName} - - # Prune old backups, keeping the last ${toString keepBackups} - ls -t "${backupDir}"/mc-backup-*.tar.xz | tail -n +${toString (keepBackups + 1)} | xargs -r rm -- - - echo "[mc-backup] Backup complete: mc-backup-$TIMESTAMP.tar.xz" - BACKUP_OK=true - # Server restart is handled by the EXIT trap above - ''; -in { - environment.systemPackages = [ backupScript ]; - - systemd.services.mc-backup = { - description = "Nightly Minecraft server backup"; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${backupScript}/bin/mc-backup"; - User = "root"; - StandardOutput = "journal"; - StandardError = "journal"; - }; - }; - - systemd.timers.mc-backup = { - description = "Nightly Minecraft backup timer"; - wantedBy = [ "timers.target" ]; - timerConfig = { - OnCalendar = "daily"; # fires at 00:00:00 every day - Persistent = true; # catch up if the machine was off at midnight - }; - }; -} diff --git a/modules/system/homelab/mc.nix b/modules/system/homelab/mc.nix index 276ab69..90e2e76 100644 --- a/modules/system/homelab/mc.nix +++ b/modules/system/homelab/mc.nix @@ -1,75 +1,65 @@ { inputs, lib, pkgs, ... }: let - ram-allocation = "10240M"; - # auth-server = "https://mc.satr14.my.id"; # TODO: self hosted drasl server + production = true; + ram-allocation-mb = 12288; + rcon-pass = "howdy"; modpack = let - commit = "667aadf36aac9b0689289f4988a76b924bbb9cbc"; + commit = "8523f89493ace13087eb68cd9fe3b5eb4f669440"; + path = if production then "commit/${commit}" else "branch/main"; in pkgs.fetchPackwizModpack { - packHash = "sha256-sNWuqTIpqnwxhoof5PkJXrvVE5x/wnhc3LoqomjYBNs="; - url = "https://git.satr14.my.id/satr14/server-modpack/raw/commit/${commit}/pack.toml"; + packHash = "sha256-xB9Oc/aneogSQ9r7L42vyVM6xwq+QkoTaXYNuUzeo6M="; + url = "https://git.satr14.my.id/satr14/server-modpack/raw/${path}/pack.toml"; }; + in { imports = [ inputs.mc.nixosModules.minecraft-servers ]; nixpkgs.overlays = [ inputs.mc.overlay ]; + powerManagement.cpuFreqGovernor = "powersave"; # performance governor causes overheating and thermal throttling, works fine with powesave + boot.kernel.sysctl = { + "vm.nr_hugepages" = (ram-allocation-mb / 2) + 512; # (heap_mb / 2MB per page) + 512 pages (1GB) for ZGC off-heap overhead + "vm.swappiness" = 10; + }; + services.minecraft-servers = { enable = true; eula = true; - managementSystem.systemd-socket.enable = true; # Referenced but unset environment variable evaluates to an empty string: MAINPID + managementSystem.systemd-socket.enable = true; # ^^^ https://github.com/Infinidoge/nix-minecraft/issues/119 + + # TODO: figure out how to set gamerules on start + # gamerules to disable: locator_bar, mob_explosion_drop_decay, (and possibly) reduced_debug_info, global_sound_events + # gamerules to enable (temporarily): noend:disable_end - servers.mc0-explorers-creativity = { + servers.da-s3 = { enable = true; autoStart = true; restart = "always"; - enableReload = false; # NOTE: development phase, disable in production + enableReload = production; + # extraReload = '' + # function rcon() { + # ${pkgs.rcon-cli}/bin/rcon-cli -p ${rcon-pass} $@ + # } + + # rcon "gamerule locator_bar false" + # rcon "gamerule mob_explosion_drop_decay false" + # rcon "gamerule reduced_debug_info false" + # rcon "gamerule global_sound_events false" + # ''; - package = pkgs.fabricServers.fabric-1_21_11.override { - jre_headless = pkgs.javaPackages.compiler.temurin-bin.jre-25; - loaderVersion = "0.19.2"; + operators = lib.mkIf (!production) { + "satr14" = { + uuid = "54441a30-fe73-46e7-adca-c476bd4fc6d2"; + bypassesPlayerLimit = true; + level = 4; + }; }; - - jvmOpts = let - flags = [ - "-Xms${ram-allocation}" - "-Xmx${ram-allocation}" - "--add-modules=jdk.incubator.vector" - - # Custom auth server - # "-Dminecraft.api.env=custom" - # "-Dminecraft.api.auth.host=${auth-server}/auth" - # "-Dminecraft.api.account.host=${auth-server}/account" - # "-Dminecraft.api.profiles.host=${auth-server}/account" - # "-Dminecraft.api.session.host=${auth-server}/session" - # "-Dminecraft.api.services.host=${auth-server}/services" - - # Aikar's GC flags (tuned for 10GB) - "-XX:+UseG1GC" - "-XX:+ParallelRefProcEnabled" - "-XX:MaxGCPauseMillis=200" - "-XX:+UnlockExperimentalVMOptions" - "-XX:+DisableExplicitGC" - "-XX:+AlwaysPreTouch" - "-XX:G1HeapWastePercent=5" - "-XX:G1MixedGCCountTarget=4" - "-XX:InitiatingHeapOccupancyPercent=15" - "-XX:G1MixedGCLiveThresholdPercent=90" - "-XX:G1RSetUpdatingPauseTimePercent=5" - "-XX:SurvivorRatio=32" - "-XX:+PerfDisableSharedMem" - "-XX:MaxTenuringThreshold=1" - "-Dusing.aikars.flags=https://mcflags.emc.gs" - "-Daikars.new.flags=true" - "-XX:G1NewSizePercent=30" - "-XX:G1MaxNewSizePercent=40" - "-XX:G1HeapRegionSize=8M" - "-XX:G1ReservePercent=20" - ]; - in lib.concatStringsSep " " flags; serverProperties = { + # server-ip = "localhost"; server-port = 25565; - server-name = "Digit Association"; - motd = "§lSeason 3 TESTING§r - §dExplorers Creativity 🔥"; + server-name = "Minecraft Server"; + motd = "§lSeason 3§r - §dExplorers Creativity 🔥"; + log-ips = false; # TODO: figure out how to get ips from cloudflared tunnel difficulty = "normal"; gamemode = "survival"; @@ -84,26 +74,41 @@ in { allow-flight = false; player-idle-timeout = 0; - # resource-pack = "https://cdn.satr14.my.id/public/fullslide-1.21.11.zip"; - # resource-pack-sha1 = "e0958dcef5755286f390c22280700c471ec34a65"; - # resource-pack-enforce = false; - - simulation-distance = 16; - view-distance = 4; + view-distance = 12; + simulation-distance = 4; enable-rcon = true; sync-chunk-writes = false; - "rcon.password" = "howdy"; + "rcon.password" = rcon-pass; "rcon.port" = 25575; }; - symlinks = { - # "resources/datapack/required" = "${modpack}/datapacks"; - "mods" = "${modpack}/mods"; - - # "server-icon.png" = "${modpack}/server-icon.png"; - # "config" = ""; + symlinks = lib.mapAttrs' + (name: _: lib.nameValuePair "mods/${name}" "${modpack}/mods/${name}") + (builtins.readDir "${modpack}/mods"); + + package = pkgs.fabricServers.fabric-1_21_11.override { + jre_headless = pkgs.javaPackages.compiler.temurin-bin.jdk-25; + loaderVersion = "0.19.2"; }; + + jvmOpts = let flags = [ + "-Xms${toString ram-allocation-mb}M" + "-Xmx${toString ram-allocation-mb}M" + + "-XX:+UseZGC" # Use ZGC (requires Java v25+, 8+ CPU cores, 10GB+ RAM) + "-XX:+UseCompactObjectHeaders" # Use compact object headers (requires Java v16+, saves a couple of bits per object) + + "--add-modules=jdk.incubator.vector" # Exposes SIMD instructions (requires full JDK, useful with performance mods) + "-XX:+UseLargePages" # Large pages support (requires hugepages configured on the system) + "-XX:+AlwaysPreTouch" # Pre-allocates memory on startup, OS claims it immediately for JVM instead of negotiating it + "-XX:+DisableExplicitGC" # Disables mods from manually invoking the GC + "-XX:+PerfDisableSharedMem" # Disables constant /tmp writes for JVM metrics + "-XX:ZAllocationSpikeTolerance=5" # Helps when server is active with many players + "-XX:SoftMaxHeapSize=${toString (ram-allocation-mb - 2048)}M" # Leave 2GB headroom + "-XX:ZCollectionInterval=1" # Force a GC cycle at minimum every second + "-XX:ConcGCThreads=8" # Threads ZGC uses for concurrent work + ]; in lib.concatStringsSep " " flags; }; }; } \ No newline at end of file diff --git a/modules/system/misc/utilities.nix b/modules/system/misc/utilities.nix index de5d35e..a637e8d 100644 --- a/modules/system/misc/utilities.nix +++ b/modules/system/misc/utilities.nix @@ -8,6 +8,7 @@ ntfs3g exfatprogs smartmontools + rclone ncdu ventoy-full-qt diff --git a/modules/system/server.nix b/modules/system/server.nix index 0916649..a2cef9f 100644 --- a/modules/system/server.nix +++ b/modules/system/server.nix @@ -26,7 +26,6 @@ in { ./homelab/ai.nix ./homelab/db.nix ./homelab/mc.nix - ./homelab/mc-backup.nix ./core/swapfile.nix ./core/oom.nix @@ -36,14 +35,17 @@ in { users.users.root.openssh.authorizedKeys.keys = homelab.ssh-keys; - services.tailscale = { - enable = true; - authKeyFile = "/mnt/data/apps/tailscale/authkey"; - useRoutingFeatures = "server"; - extraUpFlags = ts-flags; - extraSetFlags = ts-flags; + services = { + netbird.enable = true; + tailscale = { + enable = true; + authKeyFile = "/mnt/data/apps/tailscale/authkey"; + useRoutingFeatures = "server"; + extraUpFlags = ts-flags; + extraSetFlags = ts-flags; + }; }; - + virtualisation = { oci-containers.backend = "docker"; docker = { diff --git a/modules/system/user.nix b/modules/system/user.nix index 44910e9..5f50a54 100644 --- a/modules/system/user.nix +++ b/modules/system/user.nix @@ -7,6 +7,7 @@ shell = pkgs.zsh; extraGroups = [ "networkmanager" + "minecraft" "wheel" "dialout" "libvirtd"