Compare commits

..
Author SHA1 Message Date
Nexoniarz
f1f5f71245 SSH between my machines and ZeroVRAM's port, home network only; host names nexo-pc / nexo-laptop
- modules/remote.nix: OpenSSH with keys only (no passwords, no root), ports 22 and
  8080 (zvm_node) opened for 192.168.1.0/24 only; /etc/hosts names for both machines
  (DNS goes over TLS, so the router's *.lan names don't resolve)
- the laptop accepts the PC's key; the PC's list is ready for the laptop's
- hostName: nixos -> nexo-laptop

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 18:39:59 +01:00
Nexoniarz
999b49800d Revert "Firefox: DNS-over-HTTPS through Quad9"
Back to trr.mode 5: systemd-resolved already encrypts DNS (DNS-over-TLS
to Cloudflare and Quad9), so Firefox doesn't need its own DoH.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 12:20:41 +01:00
Nexoniarz
466df890c4 Firefox: DNS-over-HTTPS through Quad9
network.trr.mode 2 with dns.quad9.net: DoH first, falling back to the
system resolver (systemd-resolved over DNS-over-TLS), so lookups stay
encrypted either way. Mode 5 had turned Firefox's DoH off entirely.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 12:19:13 +01:00
Nexoniarz
bc190454b6 Bring over the PC config's changes: NexoPass, AppImages, Firefox privacy
- nexopass and nexopass-gui (scripts.nix, with the wordlist and icon)
- AppImages run directly through appimage-run's binfmt (apps.nix)
- Firefox: full fingerprinting protection except forced light mode,
  Accept-Language en-US, and its own font list without corefonts
- README updated to match

Left out as PC-only: OpenRGB, acpi_enforce_resources=lax, the
Vega 8/RTX 3060 Ti graphics setup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 12:09:39 +01:00
Nexoniarz
863abb4fd3 Switch to the PC config layout: Plasma, Limine, shared configs/
Same modules and settings as nexoniarz-config-nixos; only hardware.nix
differs. Pantheon/LightDM -> Plasma 6/SDDM, systemd-boot -> Limine,
system.nix/drivers.nix split into focused modules, Firefox prefs and
fastfetch config in configs/.

Laptop hardware kept: AMD 680M + RTX 4050 PRIME offload (bus IDs
unchanged), NVIDIA suspend fix, asusd + supergfxd, tablet driver,
DualSense ERTM fix, laptop scripts (brightness, hotspot, telemetry,
weather). Dropped: GoPro v4l2loopback webcam, blueman.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:07:55 +02:00
20 changed files with 9609 additions and 197 deletions

View file

@ -1,9 +1,9 @@
# nexoniarz-config-nixos-laptop # nexoniarz-config-nixos-laptop
My personal NixOS system configuration tailored for daily use on an My personal NixOS configuration for an ASUS TUF Gaming A15 (FA507NU).
**ASUS TUF Gaming A15 (FA507NU)**. Same layout and same choices as Shares its layout and settings with my PC config
[nexoniarz-config-nixos](https://github.com/Nexoniarz/nexoniarz-config-nixos) ([nexoniarz-config-nixos](https://github.com/Nexoniarz/nexoniarz-config-nixos));
(the desktop), with the hardware and power modules swapped for this machine. only the hardware differs.
## Overview ## Overview
@ -14,52 +14,39 @@ My personal NixOS system configuration tailored for daily use on an
- **Shell:** Zsh - **Shell:** Zsh
- **Audio:** PipeWire - **Audio:** PipeWire
- **CPU:** AMD Ryzen 5 7535HS - **CPU:** AMD Ryzen 5 7535HS
- **GPU:** AMD Radeon 680M (iGPU, drives the internal panel) + NVIDIA RTX - **GPU:** AMD Radeon 680M (iGPU, drives the panel) + NVIDIA RTX 4050 Max-Q
4050 Max-Q (dGPU, PRIME render offload only — run anything through it with (PRIME render offload only; run things on it with `nvidia-offload <command>`)
`nvidia-offload <command>`) - **Laptop control:** asusctl (fans, keyboard backlight, charge limit) + supergfxctl (dGPU power state)
- **Laptop control:** `asusctl` (fan curves, keyboard backlight, battery
charge limit) + `supergfxctl` (dGPU power-state switching)
## Layout ## Layout
| File | Contents | | File | Contents |
|---|---| |---|---|
| `configuration.nix` | Imports only | | `configuration.nix` | Imports only |
| `hardware-configuration.nix` | Generated by `nixos-generate-config`, don't hand-edit |
| `modules/boot.nix` | Limine, kernel, zram/swap | | `modules/boot.nix` | Limine, kernel, zram/swap |
| `modules/networking.nix` | NetworkManager, firewall, DNS-over-TLS, MAC randomization | | `modules/networking.nix` | NetworkManager, firewall, DNS-over-TLS, MAC randomization |
| `modules/locale.nix` | Timezone, locale, console keymap | | `modules/locale.nix` | Timezone, locale, console keymap |
| `modules/nix-settings.nix` | Nix features, GC, unfree | | `modules/nix-settings.nix` | Nix features, GC, unfree |
| `modules/security.nix` | sysctl hardening, sudo, firejail, GnuPG, polkit | | `modules/security.nix` | sysctl hardening, sudo, firejail, GnuPG, polkit |
| `modules/hardware.nix` | Hybrid graphics (PRIME offload), ASUS daemons, Bluetooth, I2C, RTL-SDR, webcam loopback, tablet, printing | | `modules/remote.nix` | SSH between my machines (keys only) and ZeroVRAM's port 8080, both for the home network only; fixed host names `nexo-pc` / `nexo-laptop` |
| `modules/power.nix` | Power profiles, lid/suspend behaviour, battery notes | | `modules/hardware.nix` | Hybrid graphics (PRIME offload), ASUS daemons, tablet, Bluetooth, I2C, RTL-SDR, printing |
| `modules/audio.nix` | PipeWire | | `modules/audio.nix` | PipeWire |
| `modules/desktop.nix` | Plasma, SDDM, touchpad, fonts, theming | | `modules/desktop.nix` | Plasma, SDDM, fonts, theming |
| `modules/users.nix` | Account, shell, Steam, Flatpak | | `modules/users.nix` | Account, shell, Steam, Flatpak |
| `modules/apps.nix` | Installed packages, nix-ld | | `modules/apps.nix` | Installed packages, nix-ld, AppImage support |
| `modules/default-apps.nix` | MIME associations | | `modules/default-apps.nix` | MIME associations |
| `modules/scripts.nix` | Custom scripts in `modules/scripts/` | | `modules/scripts.nix` | Custom scripts in `modules/scripts/` (vault, metadata stripping, brightness, Wi-Fi hotspot, telemetry, weather, NexoPass) |
| `modules/fastfetch.nix` | Installs `configs/fastfetch/config.jsonc` system-wide |
| `modules/firefox.nix` | Firefox, with prefs from `configs/firefox/prefs.js` (reapplied each start, not locked), and its own font list without the Microsoft core fonts (against font fingerprinting) |
| `configs/` | Plain app config files (Firefox prefs, fastfetch) used by the modules |
Small custom CLI helpers live in `modules/scripts/`: encrypted vault toggle, ## NexoPass
metadata stripping, brightness control (kernel backlight or DDC/CI), Wi-Fi
hotspot, system telemetry, weather fetch.
## Differences from the desktop config `nexopass` (in `modules/scripts/`) derives site passwords from a master with Argon2id, so no password is ever stored. You can have several accounts, each with its own master and an encrypted site list (current versions plus an archive of old ones) in `~/.local/share/nexopass/accounts/`. One app password or PIN unlocks them all; a master is only typed to create or recover an account.
Everything outside hardware is kept identical on purpose. What differs: Passwords of 5-15 words or 12-64 characters, "did you mean" for typos, "stay unlocked" for a few minutes (kernel keyring), encrypted export/import shared with the NexoPass Android app, and `nexopass settings`. Run `nexopass help` for everything else. Apache License 2.0.
- `modules/hardware.nix` — AMD iGPU + NVIDIA dGPU on PRIME offload with `nexopass-gui` is the [NexoPass](https://github.com/Nexoniarz/NexoPass) window (also on Android and Windows), fetched from its GitHub release. It uses the same files as `nexopass`, so both see the same accounts and app password.
`asusd`/`supergfxd`, instead of the desktop's single NVIDIA card and
OpenRGB motherboard lighting. Keyboard lighting is `asusctl aura` here.
- `modules/power.nix` — laptop-only module: power-profiles-daemon (Plasma's
power profile switcher), lid-close behaviour, `powertop`/`acpi`.
- `modules/desktop.nix` — adds touchpad defaults and the Wayland/Ozone flag.
- `modules/boot.nix` — no `acpi_enforce_resources=lax`; ACPI owns the EC that
`asusd` talks to on this machine.
- `modules/networking.nix` — firewall openings for the hotspot script's
`ipv4.method shared` dnsmasq.
- `modules/security.nix` — `pinentry-qt` (Plasma) rather than the desktop's
leftover `pinentry-rofi`.
--- ---

View file

@ -0,0 +1,80 @@
// Gruvbox-themed fastfetch, matching the Limine and icon theme.
// Colors: yellow fabd2f, aqua 8ec07c, blue 83a598, orange fe8019, gray 928374.
{
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
"logo": {
"source": "nixos",
"color": {
"1": "38;2;131;165;152",
"2": "38;2;142;192;124",
"3": "38;2;131;165;152",
"4": "38;2;142;192;124",
"5": "38;2;131;165;152",
"6": "38;2;142;192;124"
},
"padding": { "top": 1, "left": 1, "right": 3 }
},
"display": {
"separator": " ",
"color": {
"keys": "38;2;250;189;47",
"title": "38;2;254;128;25",
"output": "38;2;235;219;178"
},
"key": { "width": 13 },
"bar": {
"char": { "elapsed": "■", "total": "■" },
"border": { "left": "", "right": "" },
"color": { "total": "38;2;80;73;69" },
"width": 12
},
"percent": {
"type": ["num", "bar"],
"color": {
"green": "38;2;184;187;38",
"yellow": "38;2;250;189;47",
"red": "38;2;251;73;52"
}
},
"size": { "binaryPrefix": "iec", "ndigits": 1 }
},
"modules": [
{
"type": "title",
"format": "{#1}󱄅 {#38;2;254;128;25}{user-name}{#38;2;146;131;116}@{#38;2;142;192;124}{host-name}"
},
{
"type": "custom",
"format": "{#38;2;146;131;116}╭─────────────── {#38;2;131;165;152}system{#38;2;146;131;116} ───────────────"
},
{ "type": "os", "key": "│ 󱄅 os", "keyColor": "38;2;131;165;152", "format": "{pretty-name}" },
{ "type": "kernel", "key": "│ 󰌽 kernel", "keyColor": "38;2;131;165;152" },
{ "type": "packages", "key": "│ 󰏖 pkgs", "keyColor": "38;2;131;165;152", "format": "{nix-system} sys · {nix-user} user · {flatpak-all} flatpak" },
{ "type": "uptime", "key": "│ 󰔟 uptime", "keyColor": "38;2;131;165;152" },
{ "type": "shell", "key": "│ 󰆍 shell", "keyColor": "38;2;131;165;152" },
{
"type": "custom",
"format": "{#38;2;146;131;116}├─────────────── {#38;2;142;192;124}desktop{#38;2;146;131;116} ──────────────"
},
{ "type": "de", "key": "│ 󰕮 de", "keyColor": "38;2;142;192;124" },
{ "type": "wm", "key": "│ 󰖲 wm", "keyColor": "38;2;142;192;124" },
{ "type": "icons", "key": "│ 󰀻 icons", "keyColor": "38;2;142;192;124", "format": "{1}" },
{ "type": "cursor", "key": "│ 󰇀 cursor", "keyColor": "38;2;142;192;124" },
{
"type": "custom",
"format": "{#38;2;146;131;116}├─────────────── {#38;2;254;128;25}hardware{#38;2;146;131;116} ─────────────"
},
{ "type": "host", "key": "│ 󰍹 board", "keyColor": "38;2;254;128;25" },
{ "type": "cpu", "key": "│ 󰻠 cpu", "keyColor": "38;2;254;128;25", "temp": true, "format": "{name} ({cores-logical}) @ {freq-max}" },
{ "type": "gpu", "key": "│ 󰢮 gpu", "keyColor": "38;2;254;128;25", "format": "{name}" },
{ "type": "display", "key": "│ 󰍺 display","keyColor": "38;2;254;128;25", "format": "{width}x{height} @ {refresh-rate} Hz" },
{ "type": "memory", "key": "│ 󰑭 ram", "keyColor": "38;2;254;128;25", "format": "{percentage-bar} {used} / {total} ({percentage})" },
{ "type": "disk", "key": "│ 󰋊 disk", "keyColor": "38;2;254;128;25", "folders": "/", "format": "{size-percentage-bar} {size-used} / {size-total} ({size-percentage})" },
{
"type": "custom",
"format": "{#38;2;146;131;116}╰──────────────────────────────────────────"
},
"break",
{ "type": "colors", "symbol": "circle", "paddingLeft": 2 }
]
}

147
configs/firefox/prefs.js Normal file
View file

@ -0,0 +1,147 @@
// Nexoniarz's Firefox prefs (Firefox 157, "Nova" design)
//
// Loaded by NixOS (modules/firefox.nix) into Firefox's autoconfig. pref()
// sets the value on every Firefox start but doesn't lock it: you can still
// change things in Settings/about:config, they just reset on next start.
// To change a setting permanently, edit it here and nixos-rebuild.
// To stop managing a setting, delete its line (Firefox then keeps
// whatever value it last had).
//
// GPU video decoding also needs env vars set in modules/hardware.nix:
// LIBVA_DRIVER_NAME=nvidia NVD_BACKEND=direct MOZ_DISABLE_RDD_SANDBOX=1
/*** PRIVACY: tracking & fingerprinting ***/
// Strict Enhanced Tracking Protection: blocks trackers, cryptominers and
// known fingerprinters, isolates cookies per site (Total Cookie Protection),
// strips tracking parameters from URLs, and turns on fingerprintingProtection
// (randomized canvas, fewer exposed hardware details).
// If a site breaks: click the shield in the address bar and turn it off
// for that site only.
pref("browser.contentblocking.category", "strict");
// Fingerprinting protection at full strength: everything resistFingerprinting
// does (a Windows user agent and platform that agree, UTC time, a fixed core
// count, the bundled font list, no precise GPU name, canvas noise...), but
// switched on through fingerprintingProtection, because only that one takes
// exceptions. The one exception: prefers-color-scheme isn't forced to light,
// so sites still get dark mode.
// To check it worked: coveryourtracks.eff.org should show Windows in both
// User Agent and Platform, and timezone UTC.
pref("privacy.resistFingerprinting", false);
pref("privacy.fingerprintingProtection", true);
pref("privacy.fingerprintingProtection.pbmode", true);
pref("privacy.fingerprintingProtection.overrides", "+AllTargets,-CSSPrefersColorScheme");
// Ask sites for English pages the way most English-speaking browsers do
// (en-US, en), so the language header doesn't stand out. en-GB would be
// rarer, and rarer is what gets you tracked.
pref("intl.accept_languages", "en-US, en");
pref("privacy.spoof_english", 2);
// Sites only see base system fonts, not the ones installed on top
// (the Microsoft core fonts made the font list 1 in 9,481).
pref("layout.css.font-visibility.standard", 1);
pref("layout.css.font-visibility.trackingprotection", 1);
pref("layout.css.font-visibility.private", 1);
pref("layout.css.font-visibility.resistFingerprinting", 1);
// WebGPU tells sites about the graphics card in detail. Off breaks some
// sites (3D, AI demos, some games); uncomment to turn it off.
// pref("dom.webgpu.enabled", false);
// First-party isolation stays ON. Every existing cookie in this profile was
// saved with a first-party tag; turning this off makes Firefox ignore them
// all (logged out everywhere). Works alongside Strict mode.
pref("privacy.firstparty.isolate", true);
// Cross-site requests only send the origin (https://site.com/), not the
// full page URL you came from.
pref("network.http.referer.XOriginTrimmingPolicy", 2);
// Tell sites not to sell/share your data (legally binding in some places).
pref("privacy.globalprivacycontrol.enabled", true);
// No WebRTC: stops IP leaks. Web video calls (Meet, Discord in-browser)
// need this set to true.
pref("media.peerconnection.enabled", false);
/*** PRIVACY: Mozilla data collection ***/
pref("datareporting.healthreport.uploadEnabled", false);
pref("datareporting.policy.dataSubmissionEnabled", false);
pref("datareporting.usage.uploadEnabled", false);
pref("toolkit.telemetry.enabled", false);
pref("toolkit.telemetry.unified", false);
pref("app.shield.optoutstudies.enabled", false);
pref("app.normandy.enabled", false);
pref("nimbus.rollouts.enabled", false);
pref("browser.discovery.enabled", false);
// Firefox Suggest launched in Poland with Firefox 157; it adds sponsored
// results to the address bar.
pref("browser.urlbar.quicksuggest.enabled", false);
pref("browser.urlbar.suggest.quicksuggest.sponsored", false);
pref("browser.urlbar.suggest.quicksuggest.nonsponsored", false);
pref("browser.newtabpage.activity-stream.showSponsored", false);
pref("browser.newtabpage.activity-stream.showSponsoredTopSites", false);
/*** SECURITY ***/
// HTTPS-Only: upgrade every site to HTTPS and warn before loading plain
// HTTP. Was enabled once, but it's off now.
pref("dom.security.https_only_mode", true);
// Safe Browsing back on for malware/phishing. It checks a local list and
// only sends a partial hash when a URL matches, never your history.
// The remote download check (which uploads file metadata to Google) stays off.
pref("browser.safebrowsing.malware.enabled", true);
pref("browser.safebrowsing.phishing.enabled", true);
pref("browser.safebrowsing.downloads.enabled", true);
pref("browser.safebrowsing.downloads.remote.enabled", false);
/*** NETWORK ***/
// DNS: use the system resolver (systemd-resolved with DNS-over-TLS) and
// never let Firefox switch itself to its own DNS-over-HTTPS provider.
pref("network.trr.mode", 5);
// No preloading pages or DNS you didn't ask for.
pref("network.dns.disablePrefetch", true);
pref("network.prefetch-next", false);
pref("network.http.speculative-parallel-limit", 0);
pref("browser.urlbar.speculativeConnect.enabled", false);
pref("network.captive-portal-service.enabled", false);
pref("network.connectivity-service.enabled", false);
/*** GPU VIDEO DECODING (RTX 3060 Ti, nvidia-vaapi-driver) ***/
// Firefox blocklists VA-API on NVIDIA; force it on. The 3060 Ti decodes
// H.264, VP9 and AV1 in hardware. (media.ffmpeg.vaapi.enabled is gone
// since Firefox 137; this pref replaced it.)
pref("media.hardware-video-decoding.force-enabled", true);
pref("media.rdd-ffmpeg.enabled", true);
pref("gfx.webrender.all", true);
/*** LOOK & FEEL ***/
// Compact mode (back in Firefox 157): thinner tabs and toolbars.
// Switch back via ☰ > More tools > Customize toolbar > Density.
pref("browser.compactmode.show", true);
pref("browser.uidensity", 1);
// Smoother, momentum-based scrolling, nicer at 240 Hz.
pref("general.smoothScroll.msdPhysics.enabled", true);
// Middle-click on a page to autoscroll (like on Windows).
pref("general.autoScroll", true);
// Closing the last tab doesn't close the window.
pref("browser.tabs.closeWindowWithLastTab", false);
// Show the full URL including https:// so you always see what site you're on.
pref("browser.urlbar.trimHttps", false);
pref("browser.urlbar.trimURLs", false);
// No "proceed with caution" page every time you open about:config.
pref("browser.aboutConfig.showWarning", false);

View file

@ -10,10 +10,10 @@
./modules/locale.nix ./modules/locale.nix
./modules/nix-settings.nix ./modules/nix-settings.nix
./modules/security.nix ./modules/security.nix
./modules/remote.nix
# Hardware # Hardware
./modules/hardware.nix ./modules/hardware.nix
./modules/power.nix
./modules/audio.nix ./modules/audio.nix
# Desktop & user # Desktop & user
@ -22,6 +22,8 @@
./modules/apps.nix ./modules/apps.nix
./modules/default-apps.nix ./modules/default-apps.nix
./modules/scripts.nix ./modules/scripts.nix
./modules/fastfetch.nix
./modules/firefox.nix
]; ];
# Do not change this value. Read documentation before updating. # Do not change this value. Read documentation before updating.

View file

@ -36,9 +36,9 @@ in
users.users."nexoniarz".packages = with pkgs; [ users.users."nexoniarz".packages = with pkgs; [
tumbler tumbler
brightnessctl # Backlight on the internal panel brightnessctl
ddcutil # DDC/CI brightness on an external monitor ddcutil
lm_sensors # sensors-detect also helps ddcutil find its I2C buses lm_sensors
networkmanager # nmcli, for the Wi-Fi hotspot script networkmanager # nmcli, for the Wi-Fi hotspot script
xdg-user-dirs xdg-user-dirs
@ -56,6 +56,7 @@ in
sdrppLean sdrppLean
rtl433Lean rtl433Lean
lmms lmms
krita
# Games # Games
prismlauncher prismlauncher
@ -71,6 +72,7 @@ in
openjdk25 openjdk25
go go
claude-code claude-code
codex
]; ];
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
@ -97,10 +99,17 @@ in
kdePackages.konsole kdePackages.konsole
kdePackages.dolphin kdePackages.dolphin
kdePackages.plasma-systemmonitor kdePackages.plasma-systemmonitor
kdePackages.kdialog
qt5.qtwayland qt5.qtwayland
qt6.qtwayland qt6.qtwayland
qemu qemu
file file
wineWow64Packages.stable
ghidra
jdk
python3
radare2
binwalk
]; ];
# Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker. # Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker.
@ -113,4 +122,9 @@ in
libxrandr libxcursor libxcb libxkbcommon libxrandr libxcursor libxcb libxkbcommon
alsa-lib mesa zlib stdenv.cc.cc alsa-lib mesa zlib stdenv.cc.cc
]; ];
# Registers AppImages with binfmt_misc, so ./Foo.AppImage (or a double-click
# in Dolphin) runs straight through appimage-run's FHS environment.
programs.appimage.enable = true;
programs.appimage.binfmt = true;
} }

View file

@ -8,5 +8,18 @@
alsa.enable = true; alsa.enable = true;
alsa.support32Bit = true; alsa.support32Bit = true;
pulse.enable = true; pulse.enable = true;
# Bluetooth headphones are playback-only here (mic comes from the USB
# codec). Disable HSP/HFP so they never drop to 8/16 kHz mono call mode.
wireplumber.extraConfig."11-bluetooth-policy" = {
"wireplumber.settings" = {
"bluetooth.autoswitch-to-headset-profile" = false;
};
"monitor.bluez.properties" = {
# PC only sends audio. Allowing a2dp_sink lets the Monitor II (which
# also advertises an A2DP source) connect backwards as "audio gateway".
"bluez5.roles" = [ "a2dp_source" ];
};
};
}; };
} }

View file

@ -32,16 +32,8 @@
# zram instead of disk swap: nothing sensitive is written to disk in # zram instead of disk swap: nothing sensitive is written to disk in
# plaintext. systemd's gpt-auto-generator would otherwise re-activate the # plaintext. systemd's gpt-auto-generator would otherwise re-activate the
# swap partition hardware-configuration.nix still lists, hence the kernel # old swap partition regardless of swapDevices, hence the kernel param.
# param. / /home /nix /boot are declared explicitly there, so they don't
# depend on gpt-auto.
zramSwap.enable = true; zramSwap.enable = true;
swapDevices = lib.mkForce [ ]; swapDevices = lib.mkForce [ ];
# Unlike the desktop this doesn't carry acpi_enforce_resources=lax: that
# only exists there to let lm_sensors poke the Super I/O chip behind ACPI's
# back, and on a laptop — where ACPI genuinely owns the EC that asusd talks
# to — relaxing it is how you get fan/thermal weirdness. CPU temps come
# from k10temp, everything else from asusd.
boot.kernelParams = [ "systemd.gpt_auto=0" ]; boot.kernelParams = [ "systemd.gpt_auto=0" ];
} }

View file

@ -25,39 +25,37 @@
# xserver.nix installs xterm unconditionally; Konsole is the terminal here. # xserver.nix installs xterm unconditionally; Konsole is the terminal here.
services.xserver.excludePackages = [ pkgs.xterm ]; services.xserver.excludePackages = [ pkgs.xterm ];
# Native Wayland backend for the Electron/Chromium apps (vesktop, chromium,
# lmstudio) instead of letting them fall back to Xwayland.
environment.sessionVariables.NIXOS_OZONE_WL = "1";
# Laptop trackpad. This writes an Xorg/libinput snippet, so it covers
# Xwayland and any X11 session — KWin's own Wayland session keeps touchpad
# settings per-device in ~/.config/kcminputrc instead (System Settings →
# Mouse & Touchpad), and those keys are keyed by the device's VID/PID, so
# they can't be pinned down from another machine. Set them once there, or
# bring in plasma-manager if you want them declarative too.
services.libinput.enable = true;
services.libinput.touchpad = {
tapping = true;
naturalScrolling = true;
disableWhileTyping = true;
};
# Hybrid graphics: KWin normally picks the right GPU on its own, but if a
# session ever comes up rendering on the RTX 4050 (hot, loud, worse battery)
# pin it to the AMD iGPU — bus 35:00.0 from `lspci`. Verify the path exists
# before enabling, an invalid device makes KWin fail to start:
# ls /dev/dri/by-path/
# environment.sessionVariables.KWIN_DRM_DEVICES =
# "/dev/dri/by-path/pci-0000:35:00.0-card";
# Icon/cursor theme packages. Plasma has no gsettings-style declarative # Icon/cursor theme packages. Plasma has no gsettings-style declarative
# knob for this the way Pantheon did — pick them in System Settings, or # knob for this the way Budgie did — pick them in System Settings, or
# bring in plasma-manager later for a fully declarative setup. # bring in plasma-manager later for a fully declarative setup.
environment.systemPackages = [ environment.systemPackages = [
pkgs.gruvbox-plus-icons pkgs.gruvbox-plus-icons
pkgs.bibata-cursors pkgs.bibata-cursors
]; ];
# The third-party "Bouncing Popups" KWin effect (~/.local/share/kwin/effects)
# stacks on top of Plasma's own slidingpopups/fadingpopups and forces blur
# on every popup and the panel, making applet popups and panel settings
# open sluggishly. [$i] locks the key so ~/.config/kwinrc can't re-enable it.
environment.etc."xdg/kwinrc".text = ''
[Plugins]
bouncingPopupsEnabled[$i]=false
'';
# Breeze Dark as the default Plasma (panel/popup) theme. Avoid sparse
# third-party themes like "Darkly" (18 files): every SVG they lack falls
# back via an uncached search of all ~89 XDG_DATA_DIRS, which made applet
# popups and panel settings take 2-6 s to open. Not locked, so the theme
# can still be changed in System Settings.
environment.etc."xdg/plasmarc".text = ''
[Theme]
name=breeze-dark
'';
environment.extraInit = ''
export XDG_DATA_DIRS="$XDG_DATA_DIRS:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}"
'';
fonts.packages = with pkgs; [ fonts.packages = with pkgs; [
corefonts corefonts
dejavu_fonts dejavu_fonts

7
modules/fastfetch.nix Normal file
View file

@ -0,0 +1,7 @@
{ config, pkgs, ... }:
{
# System-wide config; fastfetch searches /etc/xdg/fastfetch/ after
# ~/.config/fastfetch/, so a user config there would still win.
environment.etc."xdg/fastfetch/config.jsonc".source = ../configs/fastfetch/config.jsonc;
}

36
modules/firefox.nix Normal file
View file

@ -0,0 +1,36 @@
{ config, pkgs, ... }:
let
# Firefox's own font setup: every system font except the Microsoft core
# fonts. Sites measure which fonts are installed to fingerprint you, and
# Comic Sans, Impact, Georgia, Verdana... made that list 1 in 9,000.
# Only Firefox is affected: other apps still have corefonts. In Firefox,
# Arial, Times New Roman and Courier New render as Liberation (same
# letter widths), the rest fall back to Noto.
firefoxFonts = pkgs.writeText "firefox-fonts.conf" ''
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<fontconfig>
<include ignore_missing="no">/etc/fonts/fonts.conf</include>
<selectfont>
<rejectfont>
<glob>${pkgs.corefonts}/*</glob>
</rejectfont>
</selectfont>
</fontconfig>
'';
in
{
programs.firefox = {
enable = true;
# The wrapper sets FONTCONFIG_FILE when Firefox starts. (overrideAttrs
# keeps the package overridable, so the autoConfig below still applies.)
package = pkgs.firefox.overrideAttrs (old: {
makeWrapperArgs = old.makeWrapperArgs ++ [ "--set" "FONTCONFIG_FILE" "${firefoxFonts}" ];
});
# Not locked: values are reapplied on every Firefox start, but can be
# changed in the UI for the current session. (Read as text: the module
# doesn't copy autoConfigFiles paths into the store.)
autoConfig = builtins.readFile ../configs/firefox/prefs.js;
};
}

View file

@ -6,38 +6,22 @@
enable32Bit = true; enable32Bit = true;
}; };
# --- Hybrid graphics: AMD Radeon 680M (iGPU, drives the internal panel) # Hybrid graphics on the ASUS TUF Gaming A15 (FA507NU): AMD Radeon 680M
# + NVIDIA RTX 4050 Max-Q (dGPU, offload-only) — ASUS TUF Gaming A15 # iGPU drives the internal panel, NVIDIA RTX 4050 Max-Q is offload-only.
# FA507NU. Bus IDs come straight from `lspci` on this machine, not # Run something on the dGPU with `nvidia-offload <command>`.
# guessed: 01:00.0 (NVIDIA) -> PCI:1:0:0, 35:00.0 (AMD) -> PCI:53:0:0 # Bus IDs from `lspci` on this machine: 01:00.0 (NVIDIA) -> PCI:1:0:0,
# (the PCI: form is decimal, 0x35 = 53). # 35:00.0 (AMD) -> PCI:53:0:0.
services.xserver.videoDrivers = [ "nvidia" ]; services.xserver.videoDrivers = [ "nvidia" ];
hardware.nvidia = { hardware.nvidia = {
modesetting.enable = true; modesetting.enable = true;
# Open GPU kernel modules — fine on Turing or newer, and this Ada
# Lovelace RTX 4050 is well within support.
open = true; open = true;
nvidiaSettings = true; nvidiaSettings = true;
package = config.boot.kernelPackages.nvidiaPackages.stable; package = config.boot.kernelPackages.nvidiaPackages.stable;
# Preserves video memory across suspend/resume, which is what fixes the # Fixes suspend/resume hangs common with NVIDIA on laptops.
# classic NVIDIA-laptop "black screen after lid close" hang.
powerManagement.enable = true; powerManagement.enable = true;
# Runtime PM, i.e. letting the dGPU drop to D3cold when idle, is left
# off on purpose: supergfxd below already power-cycles the dGPU when you
# switch to Integrated mode, and driving both power paths at once is the
# usual source of resume hangs on TUF laptops. If you want to try it:
# powerManagement.finegrained = true;
# PRIME render offload: the AMD iGPU drives the display at all times
# (much better battery life than keeping the dGPU powered on), and the
# NVIDIA GPU only spins up on demand for a specific process — run
# anything with `nvidia-offload <command>` (generated by
# enableOffloadCmd) to route it through the RTX 4050, e.g. games or
# Blender's Cycles renderer.
prime = { prime = {
offload = { offload = {
enable = true; enable = true;
@ -47,28 +31,17 @@
nvidiaBusId = "PCI:1:0:0"; nvidiaBusId = "PCI:1:0:0";
}; };
}; };
# No LIBVA/NVD env vars here (unlike the PC): video decoding runs on the
# AMD iGPU, which libva picks automatically (radeonsi).
# ASUS laptop control: keyboard backlight/fan curves/battery charge limit # asusctl (fan curves, keyboard backlight, battery charge limit) and
# (asusctl) and dGPU power-state switching between Integrated/Hybrid modes # supergfxctl (dGPU power-state switching), from asus-linux.org.
# (supergfxctl) — the two standard asus-linux.org daemons for ROG/TUF
# laptops, both packaged directly in nixpkgs.
services.asusd.enable = true; services.asusd.enable = true;
services.supergfxd.enable = true; services.supergfxd.enable = true;
hardware.opentabletdriver.enable = true; hardware.opentabletdriver.enable = true;
hardware.uinput.enable = true; hardware.uinput.enable = true;
boot.kernelModules = [ "uinput" "v4l2loopback" ]; boot.kernelModules = [ "uinput" ];
# Virtual webcam device so ffmpeg (fed by the GoPro's stream) can appear
# as a normal camera to apps like Discord. exclusive_caps=1 is required
# for Chromium/WebRTC-based apps to recognize it as a real capture device.
boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ];
boot.extraModprobeConfig = ''
options v4l2loopback devices=1 video_nr=10 card_label="GoPro Webcam" exclusive_caps=1
# DualSense/PS4 pads pair over Bluetooth then drop instantly; broken
# ERTM in many adapters. Disabling it is the standard fix.
options bluetooth disable_ertm=1
'';
hardware.bluetooth = { hardware.bluetooth = {
enable = true; enable = true;
@ -83,28 +56,21 @@
}; };
}; };
}; };
# No blueman here: Plasma brings its own Bluetooth stack (bluedevil), and # Plasma ships its own Bluetooth UI (Bluedevil); blueman just duplicated it.
# running the GTK applet alongside it just gives you two tray icons
# fighting over the same adapter. The desktop repo still has it enabled, boot.extraModprobeConfig = ''
# left over from the Budgie days. # DualSense/PS4 pads pair over Bluetooth then drop instantly; broken
# ERTM in many adapters. Disabling it is the standard fix.
options bluetooth disable_ertm=1
'';
# Blog V4 needs the rtlsdrblog fork of librtlsdr, which is what # Blog V4 needs the rtlsdrblog fork of librtlsdr, which is what
# pkgs.rtl-sdr already is here. Also blacklists the DVB-T drivers. # pkgs.rtl-sdr already is here. Also blacklists the DVB-T drivers.
hardware.rtl-sdr.enable = true; hardware.rtl-sdr.enable = true;
# I2C bus, for DDC/CI brightness on an external monitor over HDMI/USB-C # For ddcutil on an external monitor; the internal panel uses the kernel
# via ddcutil. The internal panel goes through the kernel backlight class # backlight instead (brightness-ctl picks whichever applies).
# instead — brightness-ctl picks whichever applies, see
# modules/scripts/brightness-ctl.sh.
hardware.i2c.enable = true; hardware.i2c.enable = true;
services.udev.extraRules = ''
# ddcutil without root (i2c group, see modules/users.nix)
SUBSYSTEM=="i2c-dev", GROUP="i2c", MODE="0660"
'';
# No OpenRGB: that's the desktop's motherboard/RAM lighting. The keyboard
# backlight on this machine is asusd's job (`asusctl aura`).
services.printing.enable = true; services.printing.enable = true;
} }

View file

@ -1,7 +1,7 @@
{ config, pkgs, ... }: { config, pkgs, ... }:
{ {
networking.hostName = "nixos"; networking.hostName = "nexo-laptop";
networking.networkmanager.enable = true; networking.networkmanager.enable = true;
networking.firewall = { networking.firewall = {
@ -10,18 +10,6 @@
allowedTCPPortRanges = [ { from = 1714; to = 1764; } ]; allowedTCPPortRanges = [ { from = 1714; to = 1764; } ];
allowedUDPPortRanges = [ { from = 1714; to = 1764; } ]; allowedUDPPortRanges = [ { from = 1714; to = 1764; } ];
allowedTCPPorts = [ 80 443 ]; allowedTCPPorts = [ 80 443 ];
# modules/scripts/hotspot-start.sh brings up an AP with
# `ipv4.method shared`, which has NetworkManager spawn dnsmasq on the
# Wi-Fi interface. Without these the hotspot associates but clients never
# get a lease, because the global firewall drops their DHCP and DNS
# queries. Scoped to the Wi-Fi interface only ("wl+" is the iptables
# wildcard, so it covers wlan0/wlp*), and dnsmasq only listens while the
# hotspot profile is up — the same NIC can't be AP and client at once.
interfaces."wl+" = {
allowedUDPPorts = [ 53 67 ];
allowedTCPPorts = [ 53 ];
};
}; };
# DNS-over-TLS via systemd-resolved; NetworkManager defers to it rather # DNS-over-TLS via systemd-resolved; NetworkManager defers to it rather
@ -37,9 +25,7 @@
networking.networkmanager.dns = "systemd-resolved"; networking.networkmanager.dns = "systemd-resolved";
# Ethernet stays "stable" (pseudonymous but consistent) so static DHCP # Ethernet stays "stable" (pseudonymous but consistent) so static DHCP
# reservations on the router keep working; Wi-Fi is fully random, which # reservations on the router keep working; Wi-Fi is fully random.
# matters more here than on the desktop — this machine joins other
# people's networks.
networking.networkmanager.wifi.macAddress = "random"; networking.networkmanager.wifi.macAddress = "random";
networking.networkmanager.wifi.scanRandMacAddress = true; networking.networkmanager.wifi.scanRandMacAddress = true;
networking.networkmanager.ethernet.macAddress = "stable"; networking.networkmanager.ethernet.macAddress = "stable";

View file

@ -1,48 +0,0 @@
{ config, lib, pkgs, ... }:
{
# Suspend-to-RAM support and the powersave plumbing Plasma builds on:
# plasma6.nix turns powerdevil and upower on when this is set, and it
# defaults to true — spelled out here because on a laptop it matters.
powerManagement.enable = true;
# Backs Plasma's Power Profiles switcher (Performance / Balanced /
# Power Saver in the battery applet). Plasma already defaults it on; kept
# explicit since it's the one knob that actually changes CPU behaviour.
# Mutually exclusive with tlp and auto-cpufreq — don't add either.
services.power-profiles-daemon.enable = true;
# Lid behaviour. Closing the lid suspends on battery, but only locks when
# docked or on AC, so an external-monitor setup keeps running with the lid
# shut. Renamed options: this is services.logind.settings.Login now, the
# old services.logind.lidSwitch spelling is deprecated in 26.05.
services.logind.settings.Login = {
HandleLidSwitch = "suspend";
HandleLidSwitchExternalPower = "lock";
HandleLidSwitchDocked = "ignore";
HandlePowerKey = "suspend";
};
# Hibernate isn't available and won't be: swap is zram-only (see
# modules/boot.nix), and security.protectKernelImage in modules/security.nix
# blocks the kexec path hibernation resume needs anyway.
# Battery longevity is asusd's department rather than a NixOS option —
# there's no hardware.asus module in nixpkgs. Set it once and asusd
# persists it across reboots:
# asusctl -c 80 # stop charging at 80%
# asusctl -c 100 # back to full, before a trip
# Fan curves and keyboard lighting likewise: `asusctl profile -l`,
# `asusctl aura -h`.
# amd_pstate is left at the kernel's own default. Forcing
# "amd_pstate=active" is the usual tweak for Zen 3+ laptops, but 6.18
# already picks it when the firmware advertises CPPC, so pinning it here
# would only matter if the BIOS regressed:
# boot.kernelParams = [ "amd_pstate=active" ];
environment.systemPackages = with pkgs; [
powertop # `powertop --auto-tune` and per-process wakeup accounting
acpi # quick battery/thermal readout from a terminal
];
}

38
modules/remote.nix Normal file
View file

@ -0,0 +1,38 @@
{ config, lib, pkgs, ... }:
# My machines working together at home: SSH (keys only) and ZeroVRAM's zvm_node (port 8080),
# both reachable from the home network only — not from other networks the laptop joins.
let
homeLan = "192.168.1.0/24";
homePorts = [ 22 8080 ]; # SSH, zvm_node
rule = op: port: "iptables ${op} nixos-fw -p tcp -s ${homeLan} --dport ${toString port} -j nixos-fw-accept";
in
{
# Fixed names for the machines (their addresses are reserved in the router). The router's own
# *.lan names don't resolve here: DNS goes over TLS to public resolvers (networking.nix).
networking.hosts = {
"192.168.1.225" = [ "nexo-pc" ];
"192.168.1.197" = [ "nexo-laptop" ];
};
services.openssh = {
enable = true;
openFirewall = false; # opened below for the home network only
settings = {
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
PermitRootLogin = "no";
AllowUsers = [ "nexoniarz" ];
};
};
# Keys allowed to log in here: the PC
users.users."nexoniarz".openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAPXDmX7gYH0A2zez4f1F63kjAI8t7iyte+gXmyI4wtz nexoniarz@nexo-pc"
];
# Inserted at the top of the firewall chain (rules appended at the end would come after its
# final reject); removed again when the firewall stops or reloads.
networking.firewall.extraCommands = lib.concatMapStringsSep "\n" (rule "-I") homePorts;
networking.firewall.extraStopCommands = lib.concatMapStringsSep "\n" (p: "${rule "-D" p} || true") homePorts;
}

View file

@ -1,16 +1,45 @@
{ config, pkgs, ... }: { config, pkgs, lib, ... }:
let let
# Wrap external shell scripts into system executables
vaultToggle = pkgs.writeShellScriptBin "vault-toggle" (builtins.readFile ./scripts/vault-toggle.sh); vaultToggle = pkgs.writeShellScriptBin "vault-toggle" (builtins.readFile ./scripts/vault-toggle.sh);
stripMetadata = pkgs.writeShellScriptBin "strip-metadata" (builtins.readFile ./scripts/strip-metadata.sh); stripMetadata = pkgs.writeShellScriptBin "strip-metadata" (builtins.readFile ./scripts/strip-metadata.sh);
brightnessCtl = pkgs.writeShellScriptBin "brightness-ctl" (builtins.readFile ./scripts/brightness-ctl.sh); brightnessCtl = pkgs.writeShellScriptBin "brightness-ctl" (builtins.readFile ./scripts/brightness-ctl.sh);
hotspotStart = pkgs.writeShellScriptBin "hotspot-start" (builtins.readFile ./scripts/hotspot-start.sh); hotspotStart = pkgs.writeShellScriptBin "hotspot-start" (builtins.readFile ./scripts/hotspot-start.sh);
systemTelemetry = pkgs.writeShellScriptBin "system-telemetry" (builtins.readFile ./scripts/system-telemetry.sh); systemTelemetry = pkgs.writeShellScriptBin "system-telemetry" (builtins.readFile ./scripts/system-telemetry.sh);
weatherFetch = pkgs.writeShellScriptBin "weather-fetch" (builtins.readFile ./scripts/weather-fetch.sh); weatherFetch = pkgs.writeShellScriptBin "weather-fetch" (builtins.readFile ./scripts/weather-fetch.sh);
nexopass = pkgs.writeShellApplication {
name = "nexopass";
runtimeInputs = with pkgs; [ libargon2 gnupg wl-clipboard keyutils coreutils gnused ];
runtimeEnv.NEXOPASS_WORDLIST = "${./scripts/eff_large_wordlist.txt}";
text = builtins.readFile ./scripts/nexopass.sh;
};
# NexoPass window (github.com/Nexoniarz/NexoPass). Shares accounts, site
# lists and the app password with the nexopass command above.
nexopassGuiVersion = "1.3.1";
nexopassGuiJar = pkgs.fetchurl {
url = "https://github.com/Nexoniarz/NexoPass/releases/download/v${nexopassGuiVersion}/NexoPass-linux-x64-${nexopassGuiVersion}.jar";
hash = "sha256-WeUixuz+aLPsMDj+a0Gs09gfikMYYCf8uuZIN89CqVo=";
};
nexopassGuiLibs = with pkgs; [ libGL libx11 libxext libxrender libxtst libxi libxrandr libxcursor fontconfig freetype ];
nexopassGuiDesktop = pkgs.makeDesktopItem {
name = "nexopass";
desktopName = "NexoPass";
comment = "Passwords derived from a master";
exec = "nexopass-gui";
icon = "nexopass";
categories = [ "Utility" "Security" ];
};
nexopassGui = pkgs.runCommand "nexopass-gui-${nexopassGuiVersion}" { nativeBuildInputs = [ pkgs.makeWrapper ]; } ''
makeWrapper ${pkgs.jdk17}/bin/java $out/bin/nexopass-gui \
--add-flags "-Xmx1g -jar ${nexopassGuiJar}" \
--prefix LD_LIBRARY_PATH : /run/opengl-driver/lib:${lib.makeLibraryPath nexopassGuiLibs}
install -Dm644 ${./scripts/nexopass.png} $out/share/icons/hicolor/512x512/apps/nexopass.png
install -Dm644 ${nexopassGuiDesktop}/share/applications/nexopass.desktop $out/share/applications/nexopass.desktop
'';
in in
{ {
# Install CLI dependencies required by the scripts
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
gocryptfs gocryptfs
exiftool exiftool
@ -21,5 +50,7 @@ in
hotspotStart hotspotStart
systemTelemetry systemTelemetry
weatherFetch weatherFetch
nexopass
nexopassGui
]; ];
} }

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1390
modules/scripts/nexopass.sh Executable file

File diff suppressed because it is too large Load diff

View file

@ -12,9 +12,7 @@
programs.gnupg.agent = { programs.gnupg.agent = {
enable = true; enable = true;
enableSSHSupport = true; enableSSHSupport = true;
# Qt pinentry to match Plasma (the desktop still says pinentry-rofi, a pinentryPackage = pkgs.pinentry-rofi;
# leftover from its Hyprland days — rofi isn't even installed there).
pinentryPackage = pkgs.pinentry-qt;
}; };
boot.kernel.sysctl = { boot.kernel.sysctl = {

View file

@ -9,7 +9,6 @@
}; };
programs.zsh.enable = true; programs.zsh.enable = true;
programs.firefox.enable = true;
programs.steam = { programs.steam = {
enable = true; enable = true;