mirror of
https://github.com/Nexoniarz/nexoniarz-config-nixos-laptop.git
synced 2026-11-03 04:24:27 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f5f71245 | ||
|
|
999b49800d | ||
|
|
466df890c4 | ||
|
|
bc190454b6 | ||
|
|
863abb4fd3 |
25 changed files with 10058 additions and 368 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.claude
|
||||
result
|
||||
result-*
|
||||
62
README.md
62
README.md
|
|
@ -1,36 +1,52 @@
|
|||
# nexoniarz-config-nixos-laptop
|
||||
|
||||
My personal NixOS system configuration tailored for daily use on an
|
||||
**ASUS TUF Gaming A15 (FA507NU)**.
|
||||
My personal NixOS configuration for an ASUS TUF Gaming A15 (FA507NU).
|
||||
Shares its layout and settings with my PC config
|
||||
([nexoniarz-config-nixos](https://github.com/Nexoniarz/nexoniarz-config-nixos));
|
||||
only the hardware differs.
|
||||
|
||||
## Overview
|
||||
|
||||
- **OS:** NixOS
|
||||
- **DE / Compositor:** Pantheon (gala, Wayland)
|
||||
- **Display manager:** LightDM (elementary greeter)
|
||||
- **OS:** NixOS 26.05 (unstable channel)
|
||||
- **Desktop:** KDE Plasma 6 on Wayland (KWin), SDDM
|
||||
- **Bootloader:** Limine
|
||||
- **Terminal:** Konsole
|
||||
- **Shell:** Zsh
|
||||
- **Audio:** PipeWire
|
||||
- **CPU:** AMD Ryzen 5 7535HS
|
||||
- **GPU:** AMD Radeon 680M (iGPU, drives the internal panel) + NVIDIA RTX
|
||||
4050 Max-Q (dGPU, PRIME render offload only — run anything through it with
|
||||
`nvidia-offload <command>`)
|
||||
- **Laptop control:** `asusctl` (fan curves, keyboard backlight, battery
|
||||
charge limit) + `supergfxctl` (dGPU power-state switching)
|
||||
- **GPU:** AMD Radeon 680M (iGPU, drives the panel) + NVIDIA RTX 4050 Max-Q
|
||||
(PRIME render offload only; run things on it with `nvidia-offload <command>`)
|
||||
- **Laptop control:** asusctl (fans, keyboard backlight, charge limit) + supergfxctl (dGPU power state)
|
||||
|
||||
## Layout
|
||||
|
||||
- `configuration.nix` — top-level imports
|
||||
- `hardware-configuration.nix` — generated by `nixos-generate-config`, don't
|
||||
hand-edit
|
||||
- `modules/system.nix` — bootloader, networking, time, sound, hardening,
|
||||
nix-ld
|
||||
- `modules/drivers.nix` — hybrid graphics (NVIDIA PRIME offload), ASUS
|
||||
daemons, misc hardware (webcam loopback, tablet driver)
|
||||
- `modules/desktop.nix` — Pantheon desktop environment
|
||||
- `modules/users.nix` — user account, Steam, Firefox, Flatpak
|
||||
- `modules/apps.nix` — all installed packages
|
||||
- `modules/scripts.nix` + `modules/scripts/` — small custom CLI helpers
|
||||
(encrypted vault toggle, metadata stripping, brightness control, Wi-Fi
|
||||
hotspot, system telemetry, weather fetch)
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| `configuration.nix` | Imports only |
|
||||
| `modules/boot.nix` | Limine, kernel, zram/swap |
|
||||
| `modules/networking.nix` | NetworkManager, firewall, DNS-over-TLS, MAC randomization |
|
||||
| `modules/locale.nix` | Timezone, locale, console keymap |
|
||||
| `modules/nix-settings.nix` | Nix features, GC, unfree |
|
||||
| `modules/security.nix` | sysctl hardening, sudo, firejail, GnuPG, polkit |
|
||||
| `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/hardware.nix` | Hybrid graphics (PRIME offload), ASUS daemons, tablet, Bluetooth, I2C, RTL-SDR, printing |
|
||||
| `modules/audio.nix` | PipeWire |
|
||||
| `modules/desktop.nix` | Plasma, SDDM, fonts, theming |
|
||||
| `modules/users.nix` | Account, shell, Steam, Flatpak |
|
||||
| `modules/apps.nix` | Installed packages, nix-ld, AppImage support |
|
||||
| `modules/default-apps.nix` | MIME associations |
|
||||
| `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 |
|
||||
|
||||
## NexoPass
|
||||
|
||||
`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.
|
||||
|
||||
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.
|
||||
|
||||
`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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
80
configs/fastfetch/config.jsonc
Normal file
80
configs/fastfetch/config.jsonc
Normal 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
147
configs/firefox/prefs.js
Normal 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);
|
||||
|
|
@ -1,16 +1,29 @@
|
|||
# Main NixOS configuration file importing modular configurations.
|
||||
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix # Generated hardware scan results
|
||||
./modules/system.nix # Bootloader, networking, time, sound, hardening, nix-ld
|
||||
./modules/drivers.nix # AMD/NVIDIA hybrid graphics (PRIME) and ASUS laptop control
|
||||
./modules/desktop.nix # Pantheon desktop environment (LightDM + gala)
|
||||
./modules/users.nix # User accounts and global configurations
|
||||
./modules/apps.nix # All installed packages: apps, CLI tools, dev toolchains
|
||||
./modules/scripts.nix # Custom system scripts and helpers
|
||||
./hardware-configuration.nix
|
||||
|
||||
# Core system
|
||||
./modules/boot.nix
|
||||
./modules/networking.nix
|
||||
./modules/locale.nix
|
||||
./modules/nix-settings.nix
|
||||
./modules/security.nix
|
||||
./modules/remote.nix
|
||||
|
||||
# Hardware
|
||||
./modules/hardware.nix
|
||||
./modules/audio.nix
|
||||
|
||||
# Desktop & user
|
||||
./modules/desktop.nix
|
||||
./modules/users.nix
|
||||
./modules/apps.nix
|
||||
./modules/default-apps.nix
|
||||
./modules/scripts.nix
|
||||
./modules/fastfetch.nix
|
||||
./modules/firefox.nix
|
||||
];
|
||||
|
||||
# Do not change this value. Read documentation before updating.
|
||||
|
|
|
|||
104
modules/apps.nix
104
modules/apps.nix
|
|
@ -1,16 +1,46 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
|
||||
# Both SDR++ and rtl_433 default to supporting every radio ever made, which
|
||||
# drags in UHD (USRP firmware), BladeRF and LimeSuite — ~1.5 GB for
|
||||
# hardware we don't own. These two overrides cut that down to the RTL-SDR paths.
|
||||
|
||||
soapysdrLean = pkgs.soapysdr.override {
|
||||
extraPackages = with pkgs; [
|
||||
soapyrtlsdr
|
||||
soapyremote
|
||||
];
|
||||
};
|
||||
|
||||
rtl433Lean = pkgs.rtl_433.override {
|
||||
soapysdr-with-plugins = soapysdrLean;
|
||||
};
|
||||
|
||||
# Leaves the RTL-SDR, rtl_tcp, file and network sources on.
|
||||
sdrppLean = pkgs.sdrpp.override {
|
||||
soapy_source = false;
|
||||
bladerf_source = false;
|
||||
limesdr_source = false;
|
||||
plutosdr_source = false;
|
||||
airspy_source = false;
|
||||
airspyhf_source = false;
|
||||
hermes_source = false;
|
||||
rfspace_source = false;
|
||||
dragonlabs_source = false;
|
||||
spectran_http_source = false;
|
||||
};
|
||||
|
||||
in
|
||||
{
|
||||
# Every installed package — GUI apps, CLI tools, and dev toolchains alike.
|
||||
# If it's "install X", it goes here.
|
||||
users.users."nexoniarz".packages = with pkgs; [
|
||||
# Hardware control (Pantheon itself ships Files/Terminal/Screenshot/
|
||||
# notifications/dock/launcher — see services.desktopManager.pantheon
|
||||
# in modules/desktop.nix, nothing to list here for those)
|
||||
brightnessctl # Backlight brightness (internal laptop panel)
|
||||
ddcutil # DDC/CI brightness (external monitors)
|
||||
lm_sensors # sensors-detect helps ddcutil find I2C buses; also feeds asusctl
|
||||
|
||||
tumbler
|
||||
brightnessctl
|
||||
ddcutil
|
||||
lm_sensors
|
||||
networkmanager # nmcli, for the Wi-Fi hotspot script
|
||||
xdg-user-dirs
|
||||
|
||||
# Apps
|
||||
blender
|
||||
|
|
@ -22,35 +52,79 @@
|
|||
vlc
|
||||
filezilla
|
||||
chromium
|
||||
obs-studio
|
||||
sdrppLean
|
||||
rtl433Lean
|
||||
lmms
|
||||
krita
|
||||
|
||||
# Games
|
||||
prismlauncher
|
||||
pkgs.osu-lazer-bin
|
||||
osu-lazer-bin
|
||||
|
||||
# Dev: compilers, runtimes, languages
|
||||
# Dev
|
||||
glibc
|
||||
musl
|
||||
cmake
|
||||
gnumake # Provides the 'make' command
|
||||
gnumake
|
||||
gcc
|
||||
python3
|
||||
openjdk25
|
||||
claude-code # AI Developer Assistant
|
||||
go
|
||||
claude-code
|
||||
codex
|
||||
];
|
||||
|
||||
# Global command-line utilities available everywhere
|
||||
environment.systemPackages = with pkgs; [
|
||||
git
|
||||
gh # GitHub CLI — was only installed ad-hoc before (login didn't survive)
|
||||
gh
|
||||
vim
|
||||
fastfetch
|
||||
gparted
|
||||
efibootmgr
|
||||
firejail
|
||||
gnupg
|
||||
lmstudio
|
||||
kdePackages.ark
|
||||
p7zip
|
||||
unzip
|
||||
unrar
|
||||
libreoffice # GTK3 build — matches Pantheon's native GTK theming, unlike the Qt build
|
||||
kdePackages.gwenview
|
||||
kdePackages.kate
|
||||
kdePackages.qqc2-desktop-style
|
||||
linphonePackages.linphone-desktop
|
||||
kdePackages.kcalc
|
||||
kdePackages.okular
|
||||
kdePackages.elisa
|
||||
kdePackages.konsole
|
||||
kdePackages.dolphin
|
||||
kdePackages.plasma-systemmonitor
|
||||
kdePackages.kdialog
|
||||
qt5.qtwayland
|
||||
qt6.qtwayland
|
||||
qemu
|
||||
file
|
||||
wineWow64Packages.stable
|
||||
ghidra
|
||||
jdk
|
||||
python3
|
||||
radare2
|
||||
binwalk
|
||||
];
|
||||
|
||||
# Lets non-Nix binaries (e.g. the Tor Browser bundle) find an FHS linker.
|
||||
programs.nix-ld.enable = true;
|
||||
programs.nix-ld.libraries = with pkgs; [
|
||||
glib gtk3 gdk-pixbuf pango cairo atk
|
||||
dbus dbus-glib fontconfig freetype
|
||||
libx11 libxext libxrender libxtst
|
||||
libxi libxcomposite libxdamage libxfixes
|
||||
libxrandr libxcursor libxcb libxkbcommon
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
25
modules/audio.nix
Normal file
25
modules/audio.nix
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
security.rtkit.enable = true;
|
||||
services.pulseaudio.enable = false;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = 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" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
39
modules/boot.nix
Normal file
39
modules/boot.nix
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.limine = {
|
||||
enable = true;
|
||||
maxGenerations = 5;
|
||||
|
||||
# Gruvbox, to match the icon theme.
|
||||
style = {
|
||||
wallpapers = [ ]; # Solid background; a path here would be used instead
|
||||
interface = {
|
||||
branding = "NixOS";
|
||||
brandingColor = "fabd2f";
|
||||
helpColor = "928374";
|
||||
helpColorBright = "d79921";
|
||||
};
|
||||
graphicalTerminal = {
|
||||
foreground = "ebdbb2";
|
||||
background = "00282828";
|
||||
brightForeground = "fbf1c7";
|
||||
palette = "282828;cc241d;98971a;d79921;458588;b16286;689d6a;a89984";
|
||||
brightPalette = "928374;fb4934;b8bb26;fabd2f;83a598;d3869b;8ec07c;ebdbb2";
|
||||
margin = 32;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
boot.kernelPackages = pkgs.linuxPackages;
|
||||
boot.supportedFilesystems = [ "fuse" ];
|
||||
programs.fuse.userAllowOther = true;
|
||||
|
||||
# zram instead of disk swap: nothing sensitive is written to disk in
|
||||
# plaintext. systemd's gpt-auto-generator would otherwise re-activate the
|
||||
# old swap partition regardless of swapDevices, hence the kernel param.
|
||||
zramSwap.enable = true;
|
||||
swapDevices = lib.mkForce [ ];
|
||||
boot.kernelParams = [ "systemd.gpt_auto=0" ];
|
||||
}
|
||||
80
modules/default-apps.nix
Normal file
80
modules/default-apps.nix
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
libreoffice-qt6
|
||||
];
|
||||
|
||||
# GIO picks the terminal from here for "Open Terminal" style actions.
|
||||
environment.etc."xdg/xdg-terminals.list".text = ''
|
||||
org.kde.konsole.desktop
|
||||
'';
|
||||
|
||||
# System-level fallbacks. Per the XDG spec these are only consulted for a
|
||||
# mimetype the user's own ~/.config/mimeapps.list doesn't already claim,
|
||||
# so any "Open With" choice you make later still wins over this.
|
||||
#
|
||||
# One mimetype=desktopfile pair per line. The semicolon only separates
|
||||
# multiple candidates for the SAME key — it does not chain separate pairs,
|
||||
# and parsers match by scanning for a line starting with "mimetype=", so
|
||||
# cramming several onto one line silently hides all but the first.
|
||||
environment.etc."xdg/mimeapps.list".text =
|
||||
let
|
||||
gwenviewMimes = [
|
||||
"image/avif" "image/gif" "image/heif" "image/jpeg"
|
||||
"image/jxl" "image/png" "image/bmp" "image/x-eps" "image/x-icns"
|
||||
"image/x-ico" "image/x-portable-bitmap" "image/x-portable-graymap"
|
||||
"image/x-portable-pixmap" "image/x-xbitmap" "image/x-xpixmap"
|
||||
"image/tiff" "image/x-psd" "image/x-webp" "image/webp" "image/x-tga"
|
||||
"image/x-xcf" "image/openraster" "image/svg+xml" "image/svg+xml-compressed"
|
||||
];
|
||||
arkMimes = [
|
||||
"application/x-cd-image" "application/x-bcpio" "application/x-cpio"
|
||||
"application/x-cpio-compressed" "application/x-rpm" "application/x-compress"
|
||||
"application/gzip" "application/x-bzip" "application/x-bzip2"
|
||||
"application/x-lzma" "application/x-xz" "application/zstd" "application/x-lz4"
|
||||
"application/x-source-rpm" "application/vnd.debian.binary-package"
|
||||
"application/vnd.ms-cab-compressed" "application/x-archive" "application/x-tar"
|
||||
"application/x-compressed-tar" "application/x-bzip-compressed-tar"
|
||||
"application/x-bzip2-compressed-tar" "application/x-tarz"
|
||||
"application/x-xz-compressed-tar" "application/x-lzma-compressed-tar"
|
||||
"application/x-7z-compressed" "application/vnd.rar" "application/zip"
|
||||
"application/x-java-archive" "application/x-arj"
|
||||
];
|
||||
okularMimes = [
|
||||
"application/pdf" "application/x-pdf" "image/vnd.djvu" "application/epub+zip"
|
||||
"application/x-fictionbook+xml" "application/x-mobipocket-ebook"
|
||||
"image/x-portable-document" "application/x-cbr" "application/x-cbz"
|
||||
"application/x-cbt" "application/x-cb7" "application/postscript"
|
||||
];
|
||||
vlcMimes = [
|
||||
"video/mp4" "video/x-matroska" "video/webm" "video/x-msvideo"
|
||||
"video/quicktime" "video/mpeg" "video/x-ms-wmv" "video/x-flv"
|
||||
"video/3gpp" "video/ogg" "video/x-theora+ogg" "video/x-ogm+ogg"
|
||||
"application/x-matroska" "application/vnd.rn-realmedia"
|
||||
];
|
||||
elisaMimes = [
|
||||
"audio/mpeg" "audio/flac" "audio/x-flac" "audio/ogg" "audio/x-vorbis+ogg"
|
||||
"audio/opus" "audio/x-opus+ogg" "audio/mp4" "audio/aac" "audio/x-wav"
|
||||
"audio/wav" "audio/x-ms-wma" "audio/x-aiff" "audio/x-musepack"
|
||||
];
|
||||
kateMimes = [
|
||||
"text/plain" "text/markdown" "text/x-csrc" "text/x-c++src" "text/x-chdr"
|
||||
"text/x-c++hdr" "text/x-python" "text/x-java" "text/x-shellscript"
|
||||
"text/x-nix" "text/css" "text/html" "text/xml" "application/json"
|
||||
"application/x-yaml" "application/toml" "application/javascript"
|
||||
"application/x-shellscript" "text/x-log"
|
||||
];
|
||||
line = desktop: mime: "${mime}=${desktop}";
|
||||
in
|
||||
''
|
||||
[Default Applications]
|
||||
inode/directory=org.kde.dolphin.desktop
|
||||
${lib.concatMapStringsSep "\n" (line "org.kde.gwenview.desktop") gwenviewMimes}
|
||||
${lib.concatMapStringsSep "\n" (line "org.kde.ark.desktop") arkMimes}
|
||||
${lib.concatMapStringsSep "\n" (line "org.kde.okular.desktop") okularMimes}
|
||||
${lib.concatMapStringsSep "\n" (line "vlc.desktop") vlcMimes}
|
||||
${lib.concatMapStringsSep "\n" (line "org.kde.elisa.desktop") elisaMimes}
|
||||
${lib.concatMapStringsSep "\n" (line "org.kde.kate.desktop") kateMimes}
|
||||
'';
|
||||
}
|
||||
|
|
@ -1,38 +1,72 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
# --- Pantheon: elementary OS's desktop environment (gala compositor, Wayland) ---
|
||||
# Pulls in its own session (pantheon-wayland), top panel (Wingpanel), dock,
|
||||
# app launcher, Files, Terminal, Screenshot, Photos, notifications, and
|
||||
# GTK/icon theming — no separate compositor config or dotfile symlinking
|
||||
# needed, unlike the previous Hyprland setup.
|
||||
# Plasma ships a proper Wayland session (KWin) with solid Xwayland
|
||||
# support; xserver stays on for that Xwayland layer and for the xkb
|
||||
# layout below, not because the session itself needs it.
|
||||
services.xserver.enable = true;
|
||||
services.xserver.displayManager.lightdm.enable = true;
|
||||
services.desktopManager.pantheon.enable = true;
|
||||
services.desktopManager.plasma6.enable = true;
|
||||
|
||||
# SDDM is KDE's own greeter — Qt-based, and launches Wayland sessions
|
||||
# natively, Plasma included.
|
||||
services.displayManager.sddm = {
|
||||
enable = true;
|
||||
wayland.enable = true;
|
||||
};
|
||||
|
||||
# Keyboard layout for LightDM/XWayland; Pantheon's own session picks this
|
||||
# up too.
|
||||
services.xserver.xkb = {
|
||||
layout = "pl";
|
||||
variant = "";
|
||||
};
|
||||
|
||||
security.polkit.enable = true;
|
||||
services.tumbler.enable = true;
|
||||
services.gvfs.enable = true;
|
||||
|
||||
# Native Wayland backend for Electron/Chromium-based apps
|
||||
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
||||
# xserver.nix installs xterm unconditionally; Konsole is the terminal here.
|
||||
services.xserver.excludePackages = [ pkgs.xterm ];
|
||||
|
||||
# Comfortable trackpad defaults for a laptop — tap-to-click and natural
|
||||
# scrolling aren't on by default, and gala reads touchpad settings from
|
||||
# GSettings at runtime (not services.libinput, which is X11-only), so
|
||||
# they're set here as a dconf default instead.
|
||||
programs.dconf.profiles.user.databases = [
|
||||
{
|
||||
settings."org/gnome/desktop/peripherals/touchpad" = {
|
||||
tap-to-click = true;
|
||||
natural-scroll = true;
|
||||
two-finger-scrolling-enabled = true;
|
||||
};
|
||||
}
|
||||
# Icon/cursor theme packages. Plasma has no gsettings-style declarative
|
||||
# knob for this the way Budgie did — pick them in System Settings, or
|
||||
# bring in plasma-manager later for a fully declarative setup.
|
||||
environment.systemPackages = [
|
||||
pkgs.gruvbox-plus-icons
|
||||
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; [
|
||||
corefonts
|
||||
dejavu_fonts
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-color-emoji
|
||||
nerd-fonts.fira-code
|
||||
nerd-fonts.jetbrains-mono
|
||||
nerd-fonts.hack
|
||||
inter
|
||||
liberation_ttf
|
||||
roboto
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,79 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Enable graphics driver support and 32-bit acceleration (for Steam/gaming)
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
#OpenTabletDriver
|
||||
hardware.opentabletdriver.enable = true;
|
||||
hardware.uinput.enable = true;
|
||||
boot.kernelModules = [ "uinput" "v4l2loopback" ];
|
||||
|
||||
# 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
|
||||
# PS4/PS5 controllers (e.g. DualSense) connect over Bluetooth then
|
||||
# immediately disconnect — a well-known Linux Bluetooth stack issue
|
||||
# where many adapters' Enhanced Retransmission Mode implementation is
|
||||
# broken. Disabling ERTM is the standard, widely-documented fix.
|
||||
options bluetooth disable_ertm=1
|
||||
'';
|
||||
|
||||
# I2C bus, for DDC/CI monitor control (brightness) via ddcutil, when
|
||||
# driving an external monitor over DisplayPort/HDMI. The internal panel
|
||||
# uses the kernel backlight class instead (brightness-ctl picks whichever
|
||||
# applies — see modules/scripts/brightness-ctl.sh).
|
||||
hardware.i2c.enable = true;
|
||||
|
||||
# --- Hybrid graphics: AMD Radeon 680M (iGPU, drives the internal panel)
|
||||
# + NVIDIA RTX 4050 Max-Q (dGPU, offload-only) — ASUS TUF Gaming A15
|
||||
# FA507NU. Bus IDs come straight from `lspci` on this machine, not
|
||||
# guessed: 01:00.0 (NVIDIA) -> PCI:1:0:0, 35:00.0 (AMD) -> PCI:53:0:0.
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
|
||||
hardware.nvidia = {
|
||||
# Required settings
|
||||
modesetting.enable = true;
|
||||
|
||||
# Enable NVIDIA Open GPU Kernel Modules (Turing architecture or newer —
|
||||
# this RTX 4050 is Ada Lovelace, well within support)
|
||||
open = true;
|
||||
|
||||
# Enable the NVIDIA settings menu
|
||||
nvidiaSettings = true;
|
||||
|
||||
# Use the stable driver package matching current kernel
|
||||
package = config.boot.kernelPackages.nvidiaPackages.stable;
|
||||
|
||||
# Fixes suspend/resume hangs that are common with NVIDIA on laptops.
|
||||
powerManagement.enable = 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 is only spun 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 = {
|
||||
offload = {
|
||||
enable = true;
|
||||
enableOffloadCmd = true;
|
||||
};
|
||||
amdgpuBusId = "PCI:53:0:0";
|
||||
nvidiaBusId = "PCI:1:0:0";
|
||||
};
|
||||
};
|
||||
|
||||
# ASUS laptop control: keyboard backlight/fan curves/battery charge limit
|
||||
# (asusctl) and dGPU power-state switching between Integrated/Hybrid modes
|
||||
# (supergfxctl) — the two standard asus-linux.org daemons for ROG/TUF
|
||||
# laptops, both packaged directly in nixpkgs.
|
||||
services.asusd.enable = true;
|
||||
services.supergfxd.enable = true;
|
||||
}
|
||||
7
modules/fastfetch.nix
Normal file
7
modules/fastfetch.nix
Normal 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
36
modules/firefox.nix
Normal 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;
|
||||
};
|
||||
}
|
||||
76
modules/hardware.nix
Normal file
76
modules/hardware.nix
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
hardware.graphics = {
|
||||
enable = true;
|
||||
enable32Bit = true;
|
||||
};
|
||||
|
||||
# Hybrid graphics on the ASUS TUF Gaming A15 (FA507NU): AMD Radeon 680M
|
||||
# iGPU drives the internal panel, NVIDIA RTX 4050 Max-Q is offload-only.
|
||||
# Run something on the dGPU with `nvidia-offload <command>`.
|
||||
# Bus IDs from `lspci` on this machine: 01:00.0 (NVIDIA) -> PCI:1:0:0,
|
||||
# 35:00.0 (AMD) -> PCI:53:0:0.
|
||||
services.xserver.videoDrivers = [ "nvidia" ];
|
||||
|
||||
hardware.nvidia = {
|
||||
modesetting.enable = true;
|
||||
open = true;
|
||||
nvidiaSettings = true;
|
||||
package = config.boot.kernelPackages.nvidiaPackages.stable;
|
||||
|
||||
# Fixes suspend/resume hangs common with NVIDIA on laptops.
|
||||
powerManagement.enable = true;
|
||||
|
||||
prime = {
|
||||
offload = {
|
||||
enable = true;
|
||||
enableOffloadCmd = true;
|
||||
};
|
||||
amdgpuBusId = "PCI:53: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).
|
||||
|
||||
# asusctl (fan curves, keyboard backlight, battery charge limit) and
|
||||
# supergfxctl (dGPU power-state switching), from asus-linux.org.
|
||||
services.asusd.enable = true;
|
||||
services.supergfxd.enable = true;
|
||||
|
||||
hardware.opentabletdriver.enable = true;
|
||||
hardware.uinput.enable = true;
|
||||
boot.kernelModules = [ "uinput" ];
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
settings = {
|
||||
General = {
|
||||
Experimental = true; # Battery level of connected devices
|
||||
FastConnectable = true; # Faster reconnects, more power draw
|
||||
};
|
||||
Policy = {
|
||||
AutoEnable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
# Plasma ships its own Bluetooth UI (Bluedevil); blueman just duplicated it.
|
||||
|
||||
boot.extraModprobeConfig = ''
|
||||
# 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
|
||||
# pkgs.rtl-sdr already is here. Also blacklists the DVB-T drivers.
|
||||
hardware.rtl-sdr.enable = true;
|
||||
|
||||
# For ddcutil on an external monitor; the internal panel uses the kernel
|
||||
# backlight instead (brightness-ctl picks whichever applies).
|
||||
hardware.i2c.enable = true;
|
||||
|
||||
services.printing.enable = true;
|
||||
}
|
||||
19
modules/locale.nix
Normal file
19
modules/locale.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
time.timeZone = "Europe/Warsaw";
|
||||
i18n.defaultLocale = "pl_PL.UTF-8";
|
||||
i18n.extraLocaleSettings = {
|
||||
LC_ADDRESS = "pl_PL.UTF-8";
|
||||
LC_IDENTIFICATION = "pl_PL.UTF-8";
|
||||
LC_MEASUREMENT = "pl_PL.UTF-8";
|
||||
LC_MONETARY = "pl_PL.UTF-8";
|
||||
LC_NAME = "pl_PL.UTF-8";
|
||||
LC_NUMERIC = "pl_PL.UTF-8";
|
||||
LC_PAPER = "pl_PL.UTF-8";
|
||||
LC_TELEPHONE = "pl_PL.UTF-8";
|
||||
LC_TIME = "pl_PL.UTF-8";
|
||||
};
|
||||
|
||||
console.keyMap = "pl2";
|
||||
}
|
||||
38
modules/networking.nix
Normal file
38
modules/networking.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
networking.hostName = "nexo-laptop";
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowPing = true;
|
||||
allowedTCPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||
allowedUDPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||
allowedTCPPorts = [ 80 443 ];
|
||||
};
|
||||
|
||||
# DNS-over-TLS via systemd-resolved; NetworkManager defers to it rather
|
||||
# than writing its own /etc/resolv.conf.
|
||||
networking.nameservers = [ "1.1.1.1#cloudflare-dns.com" "9.9.9.9#dns.quad9.net" ];
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
settings.Resolve = {
|
||||
DNSSEC = "allow-downgrade";
|
||||
DNSOverTLS = "true";
|
||||
};
|
||||
};
|
||||
networking.networkmanager.dns = "systemd-resolved";
|
||||
|
||||
# Ethernet stays "stable" (pseudonymous but consistent) so static DHCP
|
||||
# reservations on the router keep working; Wi-Fi is fully random.
|
||||
networking.networkmanager.wifi.macAddress = "random";
|
||||
networking.networkmanager.wifi.scanRandMacAddress = true;
|
||||
networking.networkmanager.ethernet.macAddress = "stable";
|
||||
|
||||
# Disable NetworkManager's periodic captive-portal probe.
|
||||
networking.networkmanager.settings.connectivity = {
|
||||
uri = "";
|
||||
interval = 0;
|
||||
};
|
||||
}
|
||||
14
modules/nix-settings.nix
Normal file
14
modules/nix-settings.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
nix.settings.auto-optimise-store = true;
|
||||
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 7d";
|
||||
};
|
||||
}
|
||||
38
modules/remote.nix
Normal file
38
modules/remote.nix
Normal 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;
|
||||
}
|
||||
|
|
@ -1,16 +1,45 @@
|
|||
{ config, pkgs, ... }:
|
||||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
# Wrap external shell scripts into system executables
|
||||
vaultToggle = pkgs.writeShellScriptBin "vault-toggle" (builtins.readFile ./scripts/vault-toggle.sh);
|
||||
stripMetadata = pkgs.writeShellScriptBin "strip-metadata" (builtins.readFile ./scripts/strip-metadata.sh);
|
||||
brightnessCtl = pkgs.writeShellScriptBin "brightness-ctl" (builtins.readFile ./scripts/brightness-ctl.sh);
|
||||
hotspotStart = pkgs.writeShellScriptBin "hotspot-start" (builtins.readFile ./scripts/hotspot-start.sh);
|
||||
systemTelemetry = pkgs.writeShellScriptBin "system-telemetry" (builtins.readFile ./scripts/system-telemetry.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
|
||||
{
|
||||
# Install CLI dependencies required by the scripts
|
||||
environment.systemPackages = with pkgs; [
|
||||
gocryptfs
|
||||
exiftool
|
||||
|
|
@ -21,5 +50,7 @@ in
|
|||
hotspotStart
|
||||
systemTelemetry
|
||||
weatherFetch
|
||||
nexopass
|
||||
nexopassGui
|
||||
];
|
||||
}
|
||||
|
|
|
|||
7776
modules/scripts/eff_large_wordlist.txt
Normal file
7776
modules/scripts/eff_large_wordlist.txt
Normal file
File diff suppressed because it is too large
Load diff
BIN
modules/scripts/nexopass.png
Normal file
BIN
modules/scripts/nexopass.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
1390
modules/scripts/nexopass.sh
Executable file
1390
modules/scripts/nexopass.sh
Executable file
File diff suppressed because it is too large
Load diff
38
modules/security.nix
Normal file
38
modules/security.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
security.polkit.enable = true;
|
||||
|
||||
security.sudo.extraConfig = ''
|
||||
Defaults pwfeedback
|
||||
'';
|
||||
|
||||
programs.firejail.enable = true;
|
||||
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
enableSSHSupport = true;
|
||||
pinentryPackage = pkgs.pinentry-rofi;
|
||||
};
|
||||
|
||||
boot.kernel.sysctl = {
|
||||
"kernel.kptr_restrict" = 2;
|
||||
"kernel.dmesg_restrict" = 1;
|
||||
"net.ipv4.conf.all.rp_filter" = 1;
|
||||
"net.ipv4.conf.default.rp_filter" = 1;
|
||||
"net.ipv4.conf.all.accept_redirects" = false;
|
||||
"net.ipv4.conf.default.accept_redirects" = false;
|
||||
"net.ipv6.conf.all.accept_redirects" = false;
|
||||
"net.ipv6.conf.default.accept_redirects" = false;
|
||||
"net.ipv4.conf.all.send_redirects" = false;
|
||||
"net.ipv4.conf.default.send_redirects" = false;
|
||||
# Only bites ad-hoc `gdb -p <pid>` on a non-child process.
|
||||
"kernel.yama.ptrace_scope" = 1;
|
||||
"net.ipv4.tcp_timestamps" = 0;
|
||||
};
|
||||
|
||||
systemd.coredump.enable = false;
|
||||
security.protectKernelImage = true;
|
||||
|
||||
services.geoclue2.enable = false;
|
||||
}
|
||||
|
|
@ -1,204 +0,0 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Bootloader & Kernel
|
||||
boot.loader.systemd-boot.enable = true;
|
||||
boot.loader.efi.canTouchEfiVariables = true;
|
||||
boot.loader.systemd-boot.configurationLimit = 5;
|
||||
boot.kernelPackages = pkgs.linuxPackages;
|
||||
boot.supportedFilesystems = [ "fuse" ];
|
||||
|
||||
# Networking
|
||||
networking.hostName = "nixos";
|
||||
networking.networkmanager.enable = true;
|
||||
|
||||
# Firewall Configuration
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
|
||||
# Allow local ping diagnostic queries
|
||||
allowPing = true;
|
||||
|
||||
allowedTCPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||
allowedUDPPortRanges = [ { from = 1714; to = 1764; } ];
|
||||
allowedTCPPorts = [ 80 443 ];
|
||||
# allowedUDPPorts = [ ];
|
||||
};
|
||||
|
||||
# Time zone and Internationalization
|
||||
time.timeZone = "Europe/Warsaw";
|
||||
i18n.defaultLocale = "pl_PL.UTF-8";
|
||||
i18n.extraLocaleSettings = {
|
||||
LC_ADDRESS = "pl_PL.UTF-8";
|
||||
LC_IDENTIFICATION = "pl_PL.UTF-8";
|
||||
LC_MEASUREMENT = "pl_PL.UTF-8";
|
||||
LC_MONETARY = "pl_PL.UTF-8";
|
||||
LC_NAME = "pl_PL.UTF-8";
|
||||
LC_NUMERIC = "pl_PL.UTF-8";
|
||||
LC_PAPER = "pl_PL.UTF-8";
|
||||
LC_TELEPHONE = "pl_PL.UTF-8";
|
||||
LC_TIME = "pl_PL.UTF-8";
|
||||
};
|
||||
|
||||
nix.settings.auto-optimise-store = true;
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 7d";
|
||||
};
|
||||
|
||||
# Console keymap
|
||||
console.keyMap = "pl2";
|
||||
|
||||
# Sound and Audio (Pipewire)
|
||||
security.rtkit.enable = true;
|
||||
services.pulseaudio.enable = false;
|
||||
services.pipewire = {
|
||||
enable = true;
|
||||
alsa.enable = true;
|
||||
alsa.support32Bit = true;
|
||||
pulse.enable = true;
|
||||
};
|
||||
|
||||
hardware.bluetooth = {
|
||||
enable = true;
|
||||
powerOnBoot = true;
|
||||
settings = {
|
||||
General = {
|
||||
# Shows battery charge of connected devices on supported
|
||||
# Bluetooth adapters. Defaults to 'false'.
|
||||
Experimental = true;
|
||||
# When enabled other devices can connect faster to us, however
|
||||
# the tradeoff is increased power consumption. Defaults to
|
||||
# 'false'.
|
||||
FastConnectable = true;
|
||||
};
|
||||
Policy = {
|
||||
# Enable all controllers when they are found. This includes
|
||||
# adapters present on start as well as adapters that are plugged
|
||||
# in later on. Defaults to 'true'.
|
||||
AutoEnable = true;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
services.blueman.enable = true;
|
||||
|
||||
#Firejail
|
||||
programs.firejail = {
|
||||
enable = true;
|
||||
};
|
||||
|
||||
#FUSE shit
|
||||
programs.fuse.userAllowOther = true;
|
||||
|
||||
# Enable GnuPG Agent with GUI pinentry support
|
||||
programs.gnupg.agent = {
|
||||
enable = true;
|
||||
enableSSHSupport = true;
|
||||
pinentryPackage = pkgs.pinentry-gnome3; # Matches Pantheon's GTK/gnome-keyring stack
|
||||
};
|
||||
|
||||
security.sudo.extraConfig = ''
|
||||
Defaults pwfeedback
|
||||
'';
|
||||
|
||||
# Printing services
|
||||
services.printing.enable = true;
|
||||
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
|
||||
fonts.packages = with pkgs; [
|
||||
corefonts
|
||||
dejavu_fonts
|
||||
noto-fonts
|
||||
noto-fonts-cjk-sans
|
||||
noto-fonts-color-emoji
|
||||
nerd-fonts.fira-code
|
||||
nerd-fonts.jetbrains-mono
|
||||
nerd-fonts.hack
|
||||
inter
|
||||
liberation_ttf
|
||||
roboto
|
||||
];
|
||||
|
||||
# --- Loader shim for running non-Nix-packaged binaries (e.g. the official
|
||||
# Tor Browser bundle) that expect a standard FHS dynamic linker/libraries. ---
|
||||
programs.nix-ld.enable = true;
|
||||
programs.nix-ld.libraries = with pkgs; [
|
||||
glib gtk3 gdk-pixbuf pango cairo atk
|
||||
dbus dbus-glib fontconfig freetype
|
||||
libx11 libxext libxrender libxtst
|
||||
libxi libxcomposite libxdamage libxfixes
|
||||
libxrandr libxcursor libxcb libxkbcommon
|
||||
alsa-lib mesa zlib stdenv.cc.cc
|
||||
];
|
||||
environment.systemPackages = [ pkgs.file ];
|
||||
|
||||
# --- Hardening: swap, kernel sysctls, DNS, MAC randomization ---
|
||||
|
||||
# Swap: replace disk swap with compressed in-RAM swap. Nothing sensitive
|
||||
# (decrypted vault contents, browser memory, GPG session data) ever gets
|
||||
# written to disk in plaintext via swap. Also faster than disk swap under
|
||||
# memory pressure.
|
||||
zramSwap.enable = true;
|
||||
swapDevices = lib.mkForce [ ];
|
||||
# systemd's gpt-auto-generator independently re-discovers and activates any
|
||||
# GPT partition tagged as Linux swap, regardless of the swapDevices list
|
||||
# above — this disables that auto-discovery so the old disk swap partition
|
||||
# actually stays off. Doesn't affect /, /home, /nix, /boot: those are
|
||||
# already explicitly declared in hardware-configuration.nix, not relying on
|
||||
# gpt-auto. Takes effect on next reboot.
|
||||
boot.kernelParams = [ "systemd.gpt_auto=0" ];
|
||||
|
||||
# Kernel/system hardening sysctls
|
||||
boot.kernel.sysctl = {
|
||||
# Hide kernel pointers from unprivileged users (blocks a common
|
||||
# local info-leak used in exploit chains).
|
||||
"kernel.kptr_restrict" = 2;
|
||||
# Restrict dmesg access to root.
|
||||
"kernel.dmesg_restrict" = 1;
|
||||
# Reverse-path filtering: drop packets with spoofed source addresses.
|
||||
"net.ipv4.conf.all.rp_filter" = 1;
|
||||
"net.ipv4.conf.default.rp_filter" = 1;
|
||||
# Don't accept/send ICMP redirects (blocks a classic local MITM trick).
|
||||
"net.ipv4.conf.all.accept_redirects" = false;
|
||||
"net.ipv4.conf.default.accept_redirects" = false;
|
||||
"net.ipv6.conf.all.accept_redirects" = false;
|
||||
"net.ipv6.conf.default.accept_redirects" = false;
|
||||
"net.ipv4.conf.all.send_redirects" = false;
|
||||
"net.ipv4.conf.default.send_redirects" = false;
|
||||
};
|
||||
|
||||
# Crash dumps can contain decrypted memory contents, passwords, keys —
|
||||
# never write them to disk.
|
||||
systemd.coredump.enable = false;
|
||||
|
||||
# Blocks kexec-based kernel image tampering.
|
||||
security.protectKernelImage = true;
|
||||
|
||||
# DNS-over-TLS system-wide (Tor Browser already routes its own DNS
|
||||
# through Tor, so this only affects everything else). Cloudflare + Quad9
|
||||
# both support DoT; "allow-downgrade" avoids hard failures on domains
|
||||
# with broken DNSSEC deployment.
|
||||
networking.nameservers = [ "1.1.1.1#cloudflare-dns.com" "9.9.9.9#dns.quad9.net" ];
|
||||
services.resolved = {
|
||||
enable = true;
|
||||
settings.Resolve = {
|
||||
DNSSEC = "allow-downgrade";
|
||||
DNSOverTLS = "true";
|
||||
};
|
||||
};
|
||||
networking.networkmanager.dns = "systemd-resolved";
|
||||
|
||||
# MAC address randomization.
|
||||
# WiFi: fully random per connection (you're on ethernet now, but this
|
||||
# protects you if you ever use WiFi).
|
||||
# Ethernet: "stable" — a consistent pseudonymous MAC per connection
|
||||
# profile rather than your real hardware MAC, so it won't break any
|
||||
# static DHCP reservation/MAC filtering on your OpenWRT router, while
|
||||
# still not exposing your real hardware identity.
|
||||
networking.networkmanager.wifi.macAddress = "random";
|
||||
networking.networkmanager.wifi.scanRandMacAddress = true;
|
||||
networking.networkmanager.ethernet.macAddress = "stable";
|
||||
}
|
||||
|
|
@ -1,27 +1,26 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Primary user account configuration (Access and settings only)
|
||||
users.users."nexoniarz" = {
|
||||
isNormalUser = true;
|
||||
description = "Nexoniarz";
|
||||
extraGroups = [ "networkmanager" "wheel" "fuse" "i2c" "video" ];
|
||||
extraGroups = [ "networkmanager" "wheel" "fuse" "i2c" "video" "plugdev" ];
|
||||
shell = pkgs.zsh;
|
||||
};
|
||||
|
||||
# Default shell (ZSH)
|
||||
programs.zsh.enable = true;
|
||||
|
||||
# Web browser configuration
|
||||
programs.firefox.enable = true;
|
||||
|
||||
# Enable Steam with optimized system configurations
|
||||
programs.steam = {
|
||||
enable = true;
|
||||
remotePlay.openFirewall = true;
|
||||
dedicatedServer.openFirewall = true;
|
||||
};
|
||||
|
||||
# Enable Flatpak support
|
||||
services.flatpak.enable = true;
|
||||
|
||||
# Flatpak's exported .desktop files aren't on XDG_DATA_DIRS by default,
|
||||
# so Bottles would otherwise not show up in the launcher.
|
||||
systemd.tmpfiles.rules = [
|
||||
"L+ /var/lib/flatpak/exports/share/applications - - - - /var/lib/flatpak/app/com.usebottles.bottles/current/active/export/share/applications"
|
||||
];
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue