This commit is contained in:
ashisgreat22 2026-02-20 20:59:09 +01:00
parent 7529c0c5c4
commit 735aa76ea3
57 changed files with 3366 additions and 2482 deletions

539
flake.lock generated
View file

@ -1,13 +1,35 @@
{
"nodes": {
"arkenfox": {
"inputs": {
"flake-compat": "flake-compat",
"nixpkgs": [
"nixpkgs"
],
"pre-commit": "pre-commit"
},
"locked": {
"lastModified": 1770200864,
"narHash": "sha256-COdM5Lwfw07Q+YefYmcop1VPEX7e2goM9IiwfIrJt0g=",
"owner": "dwarfmaster",
"repo": "arkenfox-nixos",
"rev": "94638bbfacfa250e5c88aaa7a8f2145926fb8e08",
"type": "github"
},
"original": {
"owner": "dwarfmaster",
"repo": "arkenfox-nixos",
"type": "github"
}
},
"cachyos-kernel": {
"flake": false,
"locked": {
"lastModified": 1769435645,
"narHash": "sha256-xxIqw5x8U+13ya2BUcwmAW6BdpCpMhrMTn6Pd0bzocE=",
"lastModified": 1771517207,
"narHash": "sha256-+zDtnmXNyMd3hMepErdPDZzqYS0PiZA0Anbbx9Pvs4g=",
"owner": "CachyOS",
"repo": "linux-cachyos",
"rev": "e8675eeb9b48a23167b3e43f84e3be76e321935e",
"rev": "39737576a25091a3c4ca00729b769a1f92ec98d5",
"type": "github"
},
"original": {
@ -19,11 +41,11 @@
"cachyos-kernel-patches": {
"flake": false,
"locked": {
"lastModified": 1769587384,
"narHash": "sha256-fPOlnH9arzQLmkbaZ6p+otwLuH9YEf/t8Q2o9/Yq/YA=",
"lastModified": 1771516433,
"narHash": "sha256-SuockPZgd2bfjWGmdT8AUBTnBZWvxdA+b8Ss98lNC6c=",
"owner": "CachyOS",
"repo": "kernel-patches",
"rev": "5f061ab9733ad15eccf6b9995e9d56f572e67266",
"rev": "505aef2086e584ba683a5ac1cb8ed8252fea2cfd",
"type": "github"
},
"original": {
@ -37,11 +59,11 @@
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1769432988,
"narHash": "sha256-q4arZjXnLiuMnLzO972lrXIGdzyGb4DGaIt69CcCYdE=",
"lastModified": 1771508520,
"narHash": "sha256-srt94sUlkaGEJHQg7k6gVrBF1QZcHUY/VBESjCgZmKI=",
"owner": "catppuccin",
"repo": "nix",
"rev": "d7a8632c0d8d144478aac1a8c8d5083b770cbb03",
"rev": "ec35c21e843e4748e60822cd5543983eb61dc87a",
"type": "github"
},
"original": {
@ -53,11 +75,11 @@
"catppuccin-userstyles": {
"flake": false,
"locked": {
"lastModified": 1769478525,
"narHash": "sha256-V/5/yrwKJQldrzMW/lo42oOsceEcXFfsaFD1fHqeaGY=",
"lastModified": 1771459037,
"narHash": "sha256-QjS/R1ADaWMuRTOR+W8Ppx/HgGlUlXWjbt3iAkd5vSs=",
"owner": "catppuccin",
"repo": "userstyles",
"rev": "72d08a0e24318741866741d38148aea50b4083e5",
"rev": "9a0dd8c2d0dd87f2962be310ad882762e4ec7074",
"type": "github"
},
"original": {
@ -90,13 +112,40 @@
"type": "github"
}
},
"cppnix": {
"inputs": {
"flake-compat": "flake-compat_4",
"flake-parts": "flake-parts_4",
"git-hooks-nix": "git-hooks-nix",
"nixpkgs": [
"nixbsd",
"nixpkgs"
],
"nixpkgs-23-11": "nixpkgs-23-11",
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1767672747,
"narHash": "sha256-MqjbAkIYgJge5QSjx2b7hivVHkAVWuquN90HV789E1M=",
"owner": "rhelmot",
"repo": "nix",
"rev": "595d3e984f91237a0ecef84567b461c26a9bf8a9",
"type": "github"
},
"original": {
"owner": "rhelmot",
"ref": "freebsd",
"repo": "nix",
"type": "github"
}
},
"crane": {
"locked": {
"lastModified": 1769287525,
"narHash": "sha256-gABuYA6BzoRMLuPaeO5p7SLrpd4qExgkwEmYaYQY4bM=",
"lastModified": 1771121070,
"narHash": "sha256-aIlv7FRXF9q70DNJPI237dEDAznSKaXmL5lfK/Id/bI=",
"owner": "ipetkov",
"repo": "crane",
"rev": "0314e365877a85c9e5758f9ea77a9972afbb4c21",
"rev": "a2812c19f1ed2e5ed5ce2ef7109798b575c180e1",
"type": "github"
},
"original": {
@ -105,18 +154,38 @@
"type": "github"
}
},
"firefox-addons": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1771494902,
"narHash": "sha256-G2yfLhPTuW4nSQCWdXzqknm9uop7OR+zQuoGll5rxLA=",
"owner": "rycee",
"repo": "nur-expressions",
"rev": "07b71eb895d1f977c763899b985ee4980412dc57",
"type": "gitlab"
},
"original": {
"owner": "rycee",
"repo": "nur-expressions",
"type": "gitlab"
}
},
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
@ -137,6 +206,52 @@
"type": "github"
}
},
"flake-compat_3": {
"flake": false,
"locked": {
"lastModified": 1767039857,
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
"owner": "NixOS",
"repo": "flake-compat",
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_4": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-compat_5": {
"locked": {
"lastModified": 1733328505,
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"revCount": 69,
"type": "tarball",
"url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
@ -181,11 +296,11 @@
"nixpkgs-lib": "nixpkgs-lib_2"
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
@ -197,16 +312,17 @@
"flake-parts_4": {
"inputs": {
"nixpkgs-lib": [
"nixvim",
"nixbsd",
"cppnix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1768135262,
"narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
"lastModified": 1733312601,
"narHash": "sha256-4pDvzqnegAfRkPwO3wmwBhVi/Sye1mzps0zHWYnP88c=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
"rev": "205b12d8b7cd4802fbcb8e8ef6a0f1408781a4f9",
"type": "github"
},
"original": {
@ -216,6 +332,27 @@
}
},
"flake-parts_5": {
"inputs": {
"nixpkgs-lib": [
"nixvim",
"nixpkgs"
]
},
"locked": {
"lastModified": 1769996383,
"narHash": "sha256-AnYjnFWgS49RlqX7LrC4uA+sCCDBj0Ry/WOJ5XWAsa0=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "57928607ea566b5db3ad13af0e57e921e6b12381",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-parts_6": {
"inputs": {
"nixpkgs-lib": [
"steam-config-nix",
@ -254,7 +391,64 @@
"type": "github"
}
},
"git-hooks-nix": {
"inputs": {
"flake-compat": [
"nixbsd",
"cppnix"
],
"gitignore": [
"nixbsd",
"cppnix"
],
"nixpkgs": [
"nixbsd",
"cppnix",
"nixpkgs"
],
"nixpkgs-stable": [
"nixbsd",
"cppnix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1734279981,
"narHash": "sha256-NdaCraHPp8iYMWzdXAt5Nv6sA3MUzlCiGiR586TCwo0=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "aa9f40c906904ebd83da78e7f328cd8aeaeae785",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"gitignore": {
"inputs": {
"nixpkgs": [
"arkenfox",
"pre-commit",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "gitignore.nix",
"type": "github"
}
},
"gitignore_2": {
"inputs": {
"nixpkgs": [
"lanzaboote",
@ -283,11 +477,11 @@
]
},
"locked": {
"lastModified": 1769638001,
"narHash": "sha256-hGwdJ/+oo+IRo2TiWV/V8BWWptQihcdFV/olTONaHqg=",
"lastModified": 1771531206,
"narHash": "sha256-1R3Wx6KUkMb4x4E5UOhW9p6rqiexzSGGWxZqSHqW5n0=",
"owner": "nix-community",
"repo": "home-manager",
"rev": "bd9f031efc634be4b80c5090b9171cc3a9f8e49c",
"rev": "91be7cce763fa4022c7cf025a71b0c366d1b6e77",
"type": "github"
},
"original": {
@ -372,15 +566,15 @@
"nixpkgs": [
"nixpkgs"
],
"pre-commit": "pre-commit",
"pre-commit": "pre-commit_2",
"rust-overlay": "rust-overlay"
},
"locked": {
"lastModified": 1769417433,
"narHash": "sha256-0WZ7I/N9InaBHL96/qdiJxg8mqFW3vRla8Z062JmQFE=",
"lastModified": 1771492583,
"narHash": "sha256-nQzvnU4BGu8dA6BsPPCqmVcab/3ebVmHtX3ZWbW3Hxc=",
"owner": "nix-community",
"repo": "lanzaboote",
"rev": "1902463415745b992dbaf301b2a35a1277be1584",
"rev": "5e9380994665ef66c87ab8e22c913ff837174ce4",
"type": "github"
},
"original": {
@ -413,11 +607,11 @@
]
},
"locked": {
"lastModified": 1769469790,
"narHash": "sha256-VJI4KvK2AWtjPdNqanQ43MUydnU9qwN+HTDXrAtS2bI=",
"lastModified": 1769804089,
"narHash": "sha256-Wkot1j0cTx64xxjmLXzPubTckaZBSUJFhESEdOzPYas=",
"owner": "utensils",
"repo": "mcp-nixos",
"rev": "af7b82497af2229893d0a5e4edaad4165f45eec7",
"rev": "37a691ea4ea9c8bdcccfe174c6127847b8213fd3",
"type": "github"
},
"original": {
@ -426,6 +620,27 @@
"type": "github"
}
},
"mini-tmpfiles": {
"inputs": {
"nixpkgs": [
"nixbsd",
"nixpkgs"
]
},
"locked": {
"lastModified": 1742754557,
"narHash": "sha256-nGxgiNhA94eSl8jcQwCboJ5Ed132z8yrFdOoT+rf8bE=",
"owner": "nixos-bsd",
"repo": "mini-tmpfiles",
"rev": "534ee577692c7092fdcd035f89bc29b663c6f9ca",
"type": "github"
},
"original": {
"owner": "nixos-bsd",
"repo": "mini-tmpfiles",
"type": "github"
}
},
"mkdocs-catppuccin": {
"flake": false,
"locked": {
@ -450,11 +665,11 @@
"rust-overlay": "rust-overlay_2"
},
"locked": {
"lastModified": 1769577126,
"narHash": "sha256-v9vz9Rj4MGwPuhGELdvpRKl2HH+xvkgat6VwL0L86Fg=",
"lastModified": 1771305475,
"narHash": "sha256-lqweVTwHhYc+9T33cysp38gVwxaibGJHriOPZXWyhCY=",
"owner": "YaLTeR",
"repo": "niri",
"rev": "f30db163b5748e8cf95c05aba77d0d3736f40543",
"rev": "a2a52911757cb3b497db9407592f9b4c439571ea",
"type": "github"
},
"original": {
@ -472,11 +687,11 @@
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1766319780,
"narHash": "sha256-Uh5180wjvBtSgtJ9zccZ7hu7bd7nvrnb6ff0nDwT2Rw=",
"lastModified": 1770308099,
"narHash": "sha256-VxuIePns4c+qpsHpLXW0CwovpKUx1xnvVIUuJwPO6fQ=",
"owner": "Naxdy",
"repo": "nix-bwrapper",
"rev": "3b0d58d4d3e8da89147369d803926998798443e4",
"rev": "1248b52f2bd4fe5690c1a36836a1798be21d953b",
"type": "github"
},
"original": {
@ -489,16 +704,16 @@
"inputs": {
"cachyos-kernel": "cachyos-kernel",
"cachyos-kernel-patches": "cachyos-kernel-patches",
"flake-compat": "flake-compat_2",
"flake-compat": "flake-compat_3",
"flake-parts": "flake-parts_3",
"nixpkgs": "nixpkgs_4"
},
"locked": {
"lastModified": 1769623217,
"narHash": "sha256-GHpbWLiez3G54o9czW9zc4uy4h0/nMK3/ahMYmILqkY=",
"lastModified": 1771525883,
"narHash": "sha256-XqDuaRbxLGno5HcWRE5lQrgMBeXXs6ncGq+R6eCvsq8=",
"owner": "xddxdd",
"repo": "nix-cachyos-kernel",
"rev": "03f574805ffe01b47e7fa93c7128d678b2037729",
"rev": "15fb6039dd248d478a8f3f7f6c067b206da2bf54",
"type": "github"
},
"original": {
@ -507,19 +722,58 @@
"type": "github"
}
},
"nixflix": {
"nix-flatpak": {
"locked": {
"lastModified": 1768656715,
"narHash": "sha256-Sbh037scxKFm7xL0ahgSCw+X2/5ZKeOwI2clqrYr9j4=",
"owner": "gmodena",
"repo": "nix-flatpak",
"rev": "123fe29340a5b8671367055b75a6e7c320d6f89a",
"type": "github"
},
"original": {
"owner": "gmodena",
"repo": "nix-flatpak",
"type": "github"
}
},
"nixbsd": {
"inputs": {
"mkdocs-catppuccin": "mkdocs-catppuccin",
"cppnix": "cppnix",
"flake-compat": "flake-compat_5",
"mini-tmpfiles": "mini-tmpfiles",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1769570521,
"narHash": "sha256-o4crX1S+jsfytfy0liMr1NSnnVDdIOGoW3UTZXJG5PI=",
"lastModified": 1768417153,
"narHash": "sha256-2Vu3Yocs45HGVEYokRvN3DdBtaft37H4Z6rw4rAQ1gk=",
"owner": "nixos-bsd",
"repo": "nixbsd",
"rev": "e393e147e3c30f6424c2a32c5362241c004b5156",
"type": "github"
},
"original": {
"owner": "nixos-bsd",
"repo": "nixbsd",
"type": "github"
}
},
"nixflix": {
"inputs": {
"mkdocs-catppuccin": "mkdocs-catppuccin",
"nixpkgs": [
"nixpkgs"
],
"treefmt-nix": "treefmt-nix_2"
},
"locked": {
"lastModified": 1771514873,
"narHash": "sha256-sEAorIUS2IA1VG4mUVYWi+6LEnYmmn1f+3h6sNOqhso=",
"owner": "kiriwalawren",
"repo": "nixflix",
"rev": "8037889b0be0275d1a96a4cc0a1d4aa878e2c82e",
"rev": "078f61c04340c0365fd5a6772e08cd432d1123a3",
"type": "github"
},
"original": {
@ -530,11 +784,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1769018530,
"narHash": "sha256-MJ27Cy2NtBEV5tsK+YraYr2g851f3Fl1LpNHDzDX15c=",
"lastModified": 1770197578,
"narHash": "sha256-AYqlWrX09+HvGs8zM6ebZ1pwUqjkfpnv8mewYwAo+iM=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "88d3861acdd3d2f0e361767018218e51810df8a1",
"rev": "00c21e4c93d963c50d4c0c89bfa84ed6e0694df2",
"type": "github"
},
"original": {
@ -544,6 +798,22 @@
"type": "github"
}
},
"nixpkgs-23-11": {
"locked": {
"lastModified": 1717159533,
"narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1765674936,
@ -561,11 +831,11 @@
},
"nixpkgs-lib_2": {
"locked": {
"lastModified": 1765674936,
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"lastModified": 1769909678,
"narHash": "sha256-cBEymOf4/o3FD5AZnzC3J9hLbiZ+QDT/KDuyHXVJOpM=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"rev": "72716169fe93074c333e8d0173151350670b824c",
"type": "github"
},
"original": {
@ -574,13 +844,29 @@
"type": "github"
}
},
"nixpkgs_2": {
"nixpkgs-regression": {
"locked": {
"lastModified": 1758035966,
"narHash": "sha256-qqIJ3yxPiB0ZQTT9//nFGQYn8X/PBoJbofA7hRKZnmE=",
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8d4ddb19d03c65a36ad8d189d001dc32ffb0306b",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1767892417,
"narHash": "sha256-dhhvQY67aboBk8b0/u0XB6vwHdgbROZT3fJAjyNh5Ww=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "3497aa5c9457a9d88d71fa93a4a8368816fbeeba",
"type": "github"
},
"original": {
@ -592,11 +878,11 @@
},
"nixpkgs_3": {
"locked": {
"lastModified": 1754340878,
"narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=",
"lastModified": 1770107345,
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "cab778239e705082fe97bb4990e0d24c50924c04",
"rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4",
"type": "github"
},
"original": {
@ -608,11 +894,11 @@
},
"nixpkgs_4": {
"locked": {
"lastModified": 1769607364,
"narHash": "sha256-bJIFB86xsMAJb0iEwb9p746T1XoslRAxbqMxBz7tjbo=",
"lastModified": 1771482645,
"narHash": "sha256-MpAKyXfJRDTgRU33Hja+G+3h9ywLAJJNRq4Pjbb4dQs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "69459b3b3ea735e9933e1e367db3e68334cce3fe",
"rev": "724cf38d99ba81fbb4a347081db93e2e3a9bc2ae",
"type": "github"
},
"original": {
@ -624,11 +910,11 @@
},
"nixpkgs_5": {
"locked": {
"lastModified": 1769461804,
"narHash": "sha256-msG8SU5WsBUfVVa/9RPLaymvi5bI8edTavbIq3vRlhI=",
"lastModified": 1771369470,
"narHash": "sha256-0NBlEBKkN3lufyvFegY4TYv5mCNHbi5OmBDrzihbBMQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bfc1b8a4574108ceef22f02bafcf6611380c100d",
"rev": "0182a361324364ae3f436a63005877674cf45efb",
"type": "github"
},
"original": {
@ -639,18 +925,18 @@
},
"nixvim": {
"inputs": {
"flake-parts": "flake-parts_4",
"flake-parts": "flake-parts_5",
"nixpkgs": [
"nixpkgs"
],
"systems": "systems_2"
},
"locked": {
"lastModified": 1769644746,
"narHash": "sha256-1X9o0GjCzku03magX4pM+1OZXA0aUTN7KvEReZ9t3OU=",
"lastModified": 1771135771,
"narHash": "sha256-wyvBIhDuyCRyjB3yPg77qoyxrlgQtBR1rVW3c9knV3E=",
"owner": "nix-community",
"repo": "nixvim",
"rev": "3c27e1b35ca0fee6a89bfc20840654361ffe888d",
"rev": "ed0424f0b08d303a7348f52f7850ad1b2704f9ba",
"type": "github"
},
"original": {
@ -666,11 +952,11 @@
]
},
"locked": {
"lastModified": 1769684048,
"narHash": "sha256-KoMHkgsxan9c6JwTuuKSAQBg947zTs+GdjlH9hquccM=",
"lastModified": 1771554771,
"narHash": "sha256-atFYM8h8fgnXW/i/zM3yZnhsbVxlsIQ6eq/FcC6uZ6k=",
"owner": "noctalia-dev",
"repo": "noctalia-shell",
"rev": "7bf3dad98949c4895f15cdc4a7412b52e7d689ea",
"rev": "8eef8ef71d64a7ad0144eb79221cdfcc568848cf",
"type": "github"
},
"original": {
@ -686,11 +972,11 @@
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1758662783,
"narHash": "sha256-igrxT+/MnmcftPOHEb+XDwAMq3Xg1Xy7kVYQaHhPlAg=",
"lastModified": 1768249818,
"narHash": "sha256-ANfn5OqIxq3HONPIXZ6zuI5sLzX1sS+2qcf/Pa0kQEc=",
"owner": "NuschtOS",
"repo": "search",
"rev": "7d4c0fc4ffe3bd64e5630417162e9e04e64b27a4",
"rev": "b6f77b88e9009bfde28e2130e218e5123dc66796",
"type": "github"
},
"original": {
@ -706,11 +992,11 @@
]
},
"locked": {
"lastModified": 1766754166,
"narHash": "sha256-anLh9N8KLqssOMd+xooagd/kLhoU4BChMfEToWmntCg=",
"lastModified": 1771442093,
"narHash": "sha256-DWRdWWS1luEuWgd0pYydmp97MdvfVGdsI8gnWfygNFg=",
"owner": "AodhanHayter",
"repo": "opencode-flake",
"rev": "57574d4c2d550b24487cb810e2cfcb7c259b0357",
"rev": "049b5b433ac88f05453d23a67a6d7ac8f62ea0b1",
"type": "github"
},
"original": {
@ -721,19 +1007,45 @@
},
"pre-commit": {
"inputs": {
"flake-compat": "flake-compat",
"flake-compat": [
"arkenfox",
"flake-compat"
],
"gitignore": "gitignore",
"nixpkgs": [
"arkenfox",
"nixpkgs"
]
},
"locked": {
"lastModified": 1769939035,
"narHash": "sha256-Fok2AmefgVA0+eprw2NDwqKkPGEI5wvR+twiZagBvrg=",
"owner": "cachix",
"repo": "git-hooks.nix",
"rev": "a8ca480175326551d6c4121498316261cbb5b260",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "git-hooks.nix",
"type": "github"
}
},
"pre-commit_2": {
"inputs": {
"flake-compat": "flake-compat_2",
"gitignore": "gitignore_2",
"nixpkgs": [
"lanzaboote",
"nixpkgs"
]
},
"locked": {
"lastModified": 1769069492,
"narHash": "sha256-Efs3VUPelRduf3PpfPP2ovEB4CXT7vHf8W+xc49RL/U=",
"lastModified": 1770726378,
"narHash": "sha256-kck+vIbGOaM/dHea7aTBxdFYpeUl/jHOy5W3eyRvVx8=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "a1ef738813b15cf8ec759bdff5761b027e3e1d23",
"rev": "5eaaedde414f6eb1aea8b8525c466dc37bba95ae",
"type": "github"
},
"original": {
@ -750,11 +1062,11 @@
]
},
"locked": {
"lastModified": 1769582933,
"narHash": "sha256-MUzapTJuDJjfeOMlC9V1aesAX9WjFNUvjkyMCBHIA7E=",
"lastModified": 1771507368,
"narHash": "sha256-Q7cDybjd7GjYsN9SHd/fBSNdgieM5bX23gErJ9QE5xc=",
"owner": "PrismLauncher",
"repo": "PrismLauncher",
"rev": "70cbbf5b07460524a14e661c1242cc51742e0937",
"rev": "eac55d849c7ab44a3310a9c5c822a850331c3160",
"type": "github"
},
"original": {
@ -765,9 +1077,11 @@
},
"root": {
"inputs": {
"arkenfox": "arkenfox",
"catppuccin": "catppuccin",
"catppuccin-userstyles": "catppuccin-userstyles",
"cosmic-manager": "cosmic-manager",
"firefox-addons": "firefox-addons",
"home-manager": "home-manager",
"impermanence": "impermanence",
"lanzaboote": "lanzaboote",
@ -775,6 +1089,8 @@
"niri": "niri",
"nix-bwrapper": "nix-bwrapper",
"nix-cachyos-kernel": "nix-cachyos-kernel",
"nix-flatpak": "nix-flatpak",
"nixbsd": "nixbsd",
"nixflix": "nixflix",
"nixpkgs": "nixpkgs_5",
"nixvim": "nixvim",
@ -793,11 +1109,11 @@
]
},
"locked": {
"lastModified": 1769309768,
"narHash": "sha256-AbOIlNO+JoqRJkK1VrnDXhxuX6CrdtIu2hSuy4pxi3g=",
"lastModified": 1771125043,
"narHash": "sha256-ldf/s49n6rOAxl7pYLJGGS1N/assoHkCOWdEdLyNZkc=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "140c9dc582cb73ada2d63a2180524fcaa744fad5",
"rev": "4912f951a26dc8142b176be2c2ad834319dc06e8",
"type": "github"
},
"original": {
@ -834,11 +1150,11 @@
]
},
"locked": {
"lastModified": 1769469829,
"narHash": "sha256-wFcr32ZqspCxk4+FvIxIL0AZktRs6DuF8oOsLt59YBU=",
"lastModified": 1771524872,
"narHash": "sha256-eksVUcUsfS9mQx4D9DrYu88u9w70bAf+n6KmTDuIGEE=",
"owner": "Mic92",
"repo": "sops-nix",
"rev": "c5eebd4eb2e3372fe12a8d70a248a6ee9dd02eff",
"rev": "e85540ffe97322dc1fea14dd11cdc2f59d540ac7",
"type": "github"
},
"original": {
@ -849,18 +1165,18 @@
},
"steam-config-nix": {
"inputs": {
"flake-parts": "flake-parts_5",
"flake-parts": "flake-parts_6",
"nixpkgs": [
"nixpkgs"
],
"systems": "systems_3"
},
"locked": {
"lastModified": 1768615900,
"narHash": "sha256-5Xfic5IZvg92mcW0sq+kFOh1PWgH7DO5WkxPYsDFDcY=",
"lastModified": 1770296756,
"narHash": "sha256-3jBIUXJu+Pc2MPu1KaHqhTS1z6KospVbDlBPvggATqs=",
"owner": "different-name",
"repo": "steam-config-nix",
"rev": "083054c75cda3d5de25d6fc61aa3e779563c57f8",
"rev": "e409b3bac9412513ff95fe293eb6ad42f985c60b",
"type": "github"
},
"original": {
@ -919,11 +1235,32 @@
"nixpkgs": "nixpkgs_3"
},
"locked": {
"lastModified": 1758728421,
"narHash": "sha256-ySNJ008muQAds2JemiyrWYbwbG+V7S5wg3ZVKGHSFu8=",
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "5eda4ee8121f97b218f7cc73f5172098d458f1d1",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
},
"treefmt-nix_2": {
"inputs": {
"nixpkgs": [
"nixflix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1770228511,
"narHash": "sha256-wQ6NJSuFqAEmIg2VMnLdCnUc0b7vslUohqqGGD+Fyxk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "337a4fe074be1042a35086f15481d763b8ddc0e7",
"type": "github"
},
"original": {

View file

@ -1,6 +1,11 @@
{
description = "Modular NixOS Configuration with Hyprland";
nixConfig = {
extra-substituters = [ "https://attic.mildlyfunctional.gay/nixbsd" ];
extra-trusted-public-keys = [ "nixbsd:gwcQlsUONBLrrGCOdEboIAeFq9eLaDqfhfXmHZs1mgc=" ];
};
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
@ -85,6 +90,23 @@
inputs.nixpkgs.follows = "nixpkgs";
inputs.home-manager.follows = "home-manager";
};
nix-flatpak.url = "github:gmodena/nix-flatpak";
arkenfox = {
url = "github:dwarfmaster/arkenfox-nixos";
inputs.nixpkgs.follows = "nixpkgs";
};
firefox-addons = {
url = "gitlab:rycee/nur-expressions";
inputs.nixpkgs.follows = "nixpkgs";
};
nixbsd = {
url = "github:nixos-bsd/nixbsd";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs =
@ -97,6 +119,9 @@
niri,
cosmic-manager,
nixflix,
arkenfox,
firefox-addons,
nixbsd,
...
}@inputs:
{
@ -122,6 +147,24 @@
default = import ./modules/home-manager;
};
nixosConfigurations.nixbsd = nixbsd.lib.nixbsdSystem {
specialArgs = { inherit inputs; };
modules = [
./hosts/nixbsd/configuration.nix
];
};
nixosConfigurations.nixbsd-vm = nixbsd.lib.nixbsdSystem {
specialArgs = { inherit inputs; };
modules = [
./hosts/nixbsd/configuration.nix
({ config, ... }: {
# Enable VM variant
# This is already in configuration.nix but we can make it explicit here if we want.
})
];
};
nixosConfigurations.nixos = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = { inherit inputs; };
@ -133,10 +176,14 @@
home-manager.nixosModules.home-manager
inputs.catppuccin.nixosModules.catppuccin
inputs.nixvim.nixosModules.nixvim
inputs.nix-flatpak.nixosModules.nix-flatpak
{
home-manager = {
extraSpecialArgs = { inherit inputs; };
sharedModules = [ inputs.cosmic-manager.homeManagerModules.cosmic-manager ];
sharedModules = [
inputs.cosmic-manager.homeManagerModules.cosmic-manager
inputs.arkenfox.homeManagerModules.arkenfox
];
useGlobalPkgs = true;
useUserPackages = true;
backupFileExtension = "backup";
@ -161,7 +208,10 @@
{
home-manager = {
extraSpecialArgs = { inherit inputs; };
sharedModules = [ inputs.cosmic-manager.homeManagerModules.cosmic-manager ];
sharedModules = [
inputs.cosmic-manager.homeManagerModules.cosmic-manager
inputs.arkenfox.homeManagerModules.arkenfox
];
useGlobalPkgs = true;
useUserPackages = true;
backupFileExtension = "backup";

View file

@ -0,0 +1,47 @@
{
config,
lib,
pkgs,
...
}:
{
nixpkgs.hostPlatform = "x86_64-freebsd";
# NixBSD doesn't have systemd, it uses FreeBSD's init or similar.
# The NixBSD modules handle the specific FreeBSD configuration.
networking.hostName = "nixbsd";
# Default user configuration
users.users.ashie = {
isNormalUser = true;
description = "Ashie";
extraGroups = [ "wheel" ];
initialPassword = "nixbsd";
};
# SSH service for access
services.sshd.enable = true;
# FreeBSD loader configuration
boot.loader.stand-freebsd.enable = true;
# File system layout
fileSystems."/" = {
device = "/dev/gpt/nixos";
fsType = "ufs";
};
fileSystems."/boot" = {
device = "/dev/msdosfs/ESP";
fsType = "msdosfs";
};
# VM variant for running in QEMU
virtualisation.vmVariant = {
virtualisation = {
memorySize = 2048; # 2GB RAM
cores = 2;
};
};
}

View file

@ -6,36 +6,6 @@
...
}:
{
# Noctalia shell
# Noctalia shell
environment.systemPackages = with pkgs; [
inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default
ydotool
];
environment.etc."glfw".source = "${pkgs.glfw}/lib";
boot.kernelModules = [
"uinput"
];
users.groups.uinput = { };
users.users.ashie.extraGroups = [ "uinput" ];
services.udev.extraRules = ''
KERNEL=="uinput", GROUP="uinput", MODE="0660", OPTIONS+="static_node=uinput"
'';
# FORCE Root Filesystem to satisfy assertions
fileSystems."/" = lib.mkForce {
device = "none";
fsType = "tmpfs";
options = [
"defaults"
"size=16G"
"mode=755"
];
};
imports = [
./default.nix # Host-specific configuration
./hardware-configuration.nix
@ -46,99 +16,43 @@
./system/packages.nix # Package list
./system/users.nix # User accounts
./system/greetd.nix # Display manager
../../modules/nixos/cosmic.nix # Cosmic Desktop
./system/kernel.nix # CachyOS kernel
./system/locate.nix # mlocate
./system/secrets.nix # SOPS secrets
./system/compatibility.nix # Compatibility layers (nix-ld)
./system/game-drive.nix
#./system/authelia.nix # SSO/2FA
../../modules/nixos/media.nix # Arr Stack
../../modules/nixos/steam-gamemode.nix # Steam GameMode Session
../../modules/nixos/redlib.nix # Redlib private frontend
./system/authelia.nix # SSO/2FA
# Modularized configs
./system/noctalia.nix
./system/filesystems.nix
./system/nix-settings.nix
./system/locale.nix
];
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (lib.getName pkg) [
"steam"
"steam-original"
"steam-run"
"spotify"
"antigravity"
"vscode-extension-bmewburn-vscode-intelephense-client"
"claude-code"
"steam-unwrapped"
];
hardware.enableRedistributableFirmware = true;
# Enable Fish shell
programs.fish.enable = true;
# Enable Gamemode
programs.gamemode.enable = true;
# Disable command-not-found to prevent info leaks
programs.command-not-found.enable = false;
# Git security exception for flakes
programs.git = {
enable = true;
config.safe.directory = "/home/ashie/nixos";
};
# Automatic security updates
system.autoUpgrade = {
enable = true;
allowReboot = false;
dates = "04:00";
flake = "/home/ashie/nixos#nixos";
};
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "en_US.UTF-8";
i18n.supportedLocales = [
"en_US.UTF-8/UTF-8"
"de_DE.UTF-8/UTF-8"
];
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
nix.settings.allowed-users = [ "ashie" ];
nix.settings.sandbox = true;
# Automatic Garbage Collection
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
# Binary caches for CachyOS kernel
nix.settings.substituters = [
"https://hyprland.cachix.org"
"https://nix-community.cachix.org"
"https://attic.xuyh0120.win/lantian"
"https://cache.garnix.io"
];
nix.settings.trusted-public-keys = [
"cache.cachyos.org-1:j9qLlx+z0OYBtCqflh9v4I+5fsljqG5l2/C9t0yY18q="
"hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"lantian:EeAUQ+W+6r7EtwnmYjeVwx5kOGEBpjlBfPlzGlTNvHc="
"cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="
];
# Registry pinning for instant shell startups
nix.registry.nixpkgs.flake = inputs.nixpkgs;
nix.channel.enable = false; # We are using flakes
# Enable performance optimizations
myModules.performance.enable = true;
# Enable modularized components
myModules.desktop.cosmic.enable = true;
myModules.media.enable = true;
myModules.gaming.gamemode.enable = true;
myModules.redlib.enable = true;
# Enable sandboxed applications
myModules.steamSandboxed.enable = true;
myModules.lutrisSandboxed.enable = true;
myModules.firefoxSandboxed.enable = true;
myModules.braveSandboxed.enable = true;
myModules.azaharSandboxed.enable = true;
myModules.faugusSandboxed.enable = true;
myModules.citronSandboxed.enable = true;
myModules.ryubingSandboxed.enable = true;
myModules.spotifySandboxed.enable = true;
myModules.vesktopSandboxed.enable = true;
myModules.tutanotaSandboxed.enable = true;
myModules.prismlauncherSandboxed.enable = true;
system.stateVersion = "25.05";
}

View file

@ -29,46 +29,36 @@
zramAlgorithm = "zstd";
};
# Hardened Malloc (Scudo)
hardenedMalloc = {
enable = false;
};
# Secure Boot (Lanzaboote)
# 1. sudo sbctl create-keys
# 2. sudo sbctl enroll-keys -m
# 3. Enable this option
# 4. Reboot
secureBoot = {
enable = false; # Disabled for initial install (enable after running sbctl create-keys)
enable = false; # switched to grub, needs update
pkiBundle = "/var/lib/sbctl";
};
# DNS-over-TLS with DNSSEC
dnsOverTls = {
enable = true;
dnssec = true;
};
# Cloudflare-only firewall rules
cloudflareFirewall = {
enable = true;
allowLocalTraffic = true;
enablePodmanWorkaround = true;
publicPorts = [
# Ports that are public
443
80
];
restrictedPorts = [ ];
restrictedPorts = [ ]; # Ports that are Cloudflare only
};
# Base Podman container runtime
# Disabled here because system/podman.nix handles Podman + container definitions
podman.enable = true;
# VPN-isolated browser containers
browserVpn = {
enable = true;
enable = false;
browsers = [
"firefox"
"tor-browser"
@ -78,17 +68,14 @@
];
};
# Ollama System Service (Isolated)
ollamaRocm = {
enable = false; # Disabled temporarily to unblock install (namespace issues)
};
# Open WebUI System Service (Isolated)
openWebUI = {
enable = true;
enable = false;
};
# SearXNG (Meta-Search Engine)
searxng = {
enable = true;
port = 8888;

View file

@ -21,6 +21,11 @@
./home/steam.nix
./home/mangohud.nix
./home/starship.nix
./home/opencode.nix
./home/fish.nix
./home/git.nix
./home/xdg.nix
./home/fonts.nix
];
home.packages = [
@ -29,41 +34,6 @@
pkgs.joplin-desktop
pkgs.bemoji
pkgs.wtype
(pkgs.writeShellScriptBin "opencode" ''
export OPENAI_BASE_URL="https://api.ashisgreat.xyz/v1"
export OPENAI_API_KEY="$(cat ${config.sops.secrets.master_api_key.path})"
export OPENCODE_DISABLE_DEFAULT_PLUGINS=true
# Ensure config directory exists
mkdir -p $HOME/.config/opencode
# Force remove config.json if it is a symlink to ensure we can write to it
if [ -L $HOME/.config/opencode/config.json ]; then
rm -f $HOME/.config/opencode/config.json
fi
# Validate permissions and force write correct config
# We verify if we can write to it, if not (e.g. read-only file), we remove it
if [ -f $HOME/.config/opencode/config.json ] && [ ! -w $HOME/.config/opencode/config.json ]; then
rm -f $HOME/.config/opencode/config.json
fi
# Always overwrite config.json to ensure correct settings
cat > $HOME/.config/opencode/config.json <<EOF
{
"model": "openai/gpt-4o",
"disabled_providers": ["opencode-anthropic-auth", "anthropic", "github"],
"plugin": []
}
EOF
# Clear broken plugin from cache if it exists (one-time cleanup)
if [ -d "$HOME/.cache/opencode/node_modules/opencode-anthropic-auth" ]; then
rm -rf "$HOME/.cache/opencode"
fi
exec ${inputs.opencode-flake.packages.${pkgs.stdenv.hostPlatform.system}.default}/bin/opencode "$@"
'')
];
sops.defaultSopsFile = ../../secrets/secrets.yaml;
@ -93,64 +63,10 @@
};
};
programs.fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting # Disable greeting
hyfetch
'';
plugins = [
{
name = "grc";
src = pkgs.fishPlugins.grc.src;
}
{
name = "done";
src = pkgs.fishPlugins.done.src;
}
{
name = "sponge";
src = pkgs.fishPlugins.sponge.src;
}
{
name = "puffer";
src = pkgs.fishPlugins.puffer.src;
}
{
name = "fzf-fish";
src = pkgs.fishPlugins.fzf-fish.src;
}
{
name = "pisces";
src = pkgs.fishPlugins.pisces.src;
}
];
shellAliases = {
btw = "echo i use hyprland btw";
vi = "nvim";
vim = "nvim";
"67" = "nh os switch";
};
};
programs.bash = {
enable = true;
};
programs.git = {
enable = true;
settings.user.name = "ashisgreat22";
settings.user.email = "dev@ashisgreat.xyz";
};
programs.gh = {
enable = true;
settings = {
git_protocol = "ssh";
editor = "nvim";
};
};
programs.direnv = {
enable = true;
nix-direnv.enable = true;
@ -166,49 +82,65 @@
};
};
fonts.fontconfig = {
programs.firefox = {
enable = true;
defaultFonts = {
serif = [ "ComicShannsMono Nerd Font" ];
sansSerif = [ "ComicShannsMono Nerd Font" ];
monospace = [ "ComicShannsMono Nerd Font Mono" ];
emoji = [ "Noto Color Emoji" ];
package = pkgs.firefox-esr; # Use standard package so HM can manage profiles/policies
arkenfox = {
enable = true;
version = "140.0"; # Match ESR version
};
};
xdg.desktopEntries.youtube = {
name = "YouTube";
genericName = "Video Player";
exec = "brave --profile-directory=YouTube --app=https://youtube.com";
terminal = false;
categories = [
"Network"
"Video"
"AudioVideo"
];
icon = "youtube";
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" = [
"onlyoffice-desktopeditors.desktop"
profiles.ashie = {
id = 0;
extensions = with inputs.firefox-addons.legacyPackages.${pkgs.system}.firefox-addons; [
ublock-origin
bitwarden
sponsorblock
];
"application/msword" = [ "onlyoffice-desktopeditors.desktop" ];
"text/html" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/http" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/https" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/about" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/unknown" = [ "nix.bwrapper.firefox.desktop" ];
"application/xhtml+xml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-htm" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-html" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-shtml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-xhtml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-xht" = [ "nix.bwrapper.firefox.desktop" ];
"application/pdf" = [ "nix.bwrapper.firefox.desktop" ];
search = {
default = "AshisGreat";
force = true;
engines = {
"AshisGreat" = {
urls = [{
template = "https://search.ashisgreat.xyz/search";
params = [
{ name = "q"; value = "{searchTerms}"; }
];
}];
iconUpdateURL = "https://search.ashisgreat.xyz/favicon.ico";
updateInterval = 24 * 60 * 60 * 1000; # every day
definedAliases = [ "@ag" ];
};
};
};
arkenfox = {
enable = true;
"0000".enable = true; # Top-level overrides
"0100".enable = true; # Startup
"0200".enable = true; # Geolocation
"0300".enable = true; # Browser Features
"0400".enable = true; # Safe Browsing
"0600".enable = true; # Block Implicit Outbound
"0700".enable = true; # DNS / DoH
"0800".enable = true; # Search Bar / Forms / History
"0900".enable = true; # Passwords
"1000".enable = true; # Disk Cache / Antifingerprinting
"1200".enable = true; # HTTPS
"1600".enable = true; # Referers
"1700".enable = true; # Containers
"2000".enable = true; # Plugins / Media
"2400".enable = true; # DOM
"2600".enable = true; # Storage
"2700".enable = true; # Enhanced Tracking Protection
"2800".enable = true; # Shutdown & Sanitizing
"4500".enable = true; # RFP (Resist Fingerprinting)
"5000".enable = true; # Optional OPSEC
"5500".enable = true; # Optional Hardening
"6000".enable = true; # DON'T TOUCH
"7000".enable = true; # DON'T TOUCH
"8000".enable = true; # DON'T TOUCH
"9000".enable = true; # DON'T TOUCH
};
};
};
@ -224,4 +156,4 @@
WantedBy = [ "default.target" ];
};
};
}
}

42
hosts/nixos/home/fish.nix Normal file
View file

@ -0,0 +1,42 @@
{ pkgs, ... }:
{
programs.fish = {
enable = true;
interactiveShellInit = ''
set fish_greeting # Disable greeting
hyfetch
'';
plugins = [
{
name = "grc";
src = pkgs.fishPlugins.grc.src;
}
{
name = "done";
src = pkgs.fishPlugins.done.src;
}
{
name = "sponge";
src = pkgs.fishPlugins.sponge.src;
}
{
name = "puffer";
src = pkgs.fishPlugins.puffer.src;
}
{
name = "fzf-fish";
src = pkgs.fishPlugins.fzf-fish.src;
}
{
name = "pisces";
src = pkgs.fishPlugins.pisces.src;
}
];
shellAliases = {
btw = "echo i use hyprland btw";
vi = "nvim";
vim = "nvim";
"67" = "nh os switch";
};
};
}

View file

@ -0,0 +1,13 @@
{ ... }:
{
fonts.fontconfig = {
enable = true;
defaultFonts = {
serif = [ "ComicShannsMono Nerd Font" ];
sansSerif = [ "ComicShannsMono Nerd Font" ];
monospace = [ "ComicShannsMono Nerd Font Mono" ];
emoji = [ "Noto Color Emoji" ];
};
};
}

16
hosts/nixos/home/git.nix Normal file
View file

@ -0,0 +1,16 @@
{ ... }:
{
programs.git = {
enable = true;
settings.user.name = "ashisgreat22";
settings.user.email = "dev@ashisgreat.xyz";
};
programs.gh = {
enable = true;
settings = {
git_protocol = "ssh";
editor = "nvim";
};
};
}

View file

@ -0,0 +1,45 @@
{
config,
pkgs,
inputs,
...
}:
{
home.packages = [
(pkgs.writeShellScriptBin "opencode" ''
export OPENAI_BASE_URL="https://api.ashisgreat.xyz/v1"
export OPENAI_API_KEY="$(cat ${config.sops.secrets.master_api_key.path})"
export OPENCODE_DISABLE_DEFAULT_PLUGINS=true
# Ensure config directory exists
mkdir -p $HOME/.config/opencode
# Force remove config.json if it is a symlink to ensure we can write to it
if [ -L $HOME/.config/opencode/config.json ]; then
rm -f $HOME/.config/opencode/config.json
fi
# Validate permissions and force write correct config
# We verify if we can write to it, if not (e.g. read-only file), we remove it
if [ -f $HOME/.config/opencode/config.json ] && [ ! -w $HOME/.config/opencode/config.json ]; then
rm -f $HOME/.config/opencode/config.json
fi
# Always overwrite config.json to ensure correct settings
cat > $HOME/.config/opencode/config.json <<EOF
{
"model": "openai/gpt-4o",
"disabled_providers": ["opencode-anthropic-auth", "anthropic", "github"],
"plugin": []
}
EOF
# Clear broken plugin from cache if it exists (one-time cleanup)
if [ -d "$HOME/.cache/opencode/node_modules/opencode-anthropic-auth" ]; then
rm -rf "$HOME/.cache/opencode"
fi
exec ${inputs.opencode-flake.packages.${pkgs.stdenv.hostPlatform.system}.default}/bin/opencode "$@"
'')
];
}

50
hosts/nixos/home/xdg.nix Normal file
View file

@ -0,0 +1,50 @@
{ ... }:
{
xdg.desktopEntries.youtube = {
name = "YouTube";
genericName = "Video sharing platform";
exec = "brave --profile-directory=YouTube --app=https://youtube.com";
terminal = false;
categories = [
"Network"
"Video"
"AudioVideo"
];
icon = "youtube";
};
xdg.desktopEntries.steam = {
name = "Steam";
genericName = "Game Store";
exec = "steam %U";
terminal = false;
categories = [ "Game" ];
icon = "steam";
mimeType = [
"x-scheme-handler/steam"
"x-scheme-handler/steamlink"
];
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"application/vnd.openxmlformats-officedocument.wordprocessingml.document" = [
"onlyoffice-desktopeditors.desktop"
];
"application/msword" = [ "onlyoffice-desktopeditors.desktop" ];
"text/html" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/http" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/https" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/about" = [ "nix.bwrapper.firefox.desktop" ];
"x-scheme-handler/unknown" = [ "nix.bwrapper.firefox.desktop" ];
"application/xhtml+xml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-htm" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-html" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-shtml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-xhtml" = [ "nix.bwrapper.firefox.desktop" ];
"application/x-extension-xht" = [ "nix.bwrapper.firefox.desktop" ];
"application/pdf" = [ "nix.bwrapper.firefox.desktop" ];
};
};
}

View file

@ -7,9 +7,8 @@
{
services.authelia.instances.main = {
enable = false;
enable = true;
# Secrets
secrets = {
jwtSecretFile = config.sops.secrets.authelia_jwt_secret.path;
storageEncryptionKeyFile = config.sops.secrets.authelia_storage_encryption_key.path;
@ -49,15 +48,19 @@
domain = "auth.ashisgreat.xyz";
policy = "bypass";
}
# Bypass for Jellyfin (handles its own auth)
{
domain = "jellyfin.ashisgreat.xyz";
policy = "bypass";
}
# Protected services (2FA required)
{
domain = [
"sonarr.ashisgreat.xyz"
"radarr.ashisgreat.xyz"
"prowlarr.ashisgreat.xyz"
"jellyfin.ashisgreat.xyz" # Jellyfin can use its own auth, but wrapping it adds 2FA
"torrent.ashisgreat.xyz"
"jellyseer.ashisgreat.xyz" # Note: Typo in services.nix maintained here, check if corrected in Caddy
"jellyseer.ashisgreat.xyz"
];
policy = "two_factor";
}

View file

@ -0,0 +1,13 @@
{ lib, ... }:
{
# FORCE Root Filesystem to satisfy assertions
fileSystems."/" = lib.mkForce {
device = "none";
fsType = "tmpfs";
options = [
"defaults"
"size=16G"
"mode=755"
];
};
}

View file

@ -8,6 +8,8 @@
# Enable early KMS for the prompt
boot.initrd.kernelModules = [ "amdgpu" ];
hardware.enableRedistributableFirmware = true;
hardware.graphics = {
enable = true;
enable32Bit = true;

View file

@ -34,6 +34,7 @@
"wireguard"
"af_packet"
"bridge"
"xt_tcpudp"
];
# =============================================================================

View file

@ -0,0 +1,9 @@
{ ... }:
{
time.timeZone = "Europe/Berlin";
i18n.defaultLocale = "en_US.UTF-8";
i18n.supportedLocales = [
"en_US.UTF-8/UTF-8"
"de_DE.UTF-8/UTF-8"
];
}

View file

@ -19,10 +19,13 @@
Kind = "bridge";
Name = "br0";
};
netdevs."br0".bridgeConfig = {
STP = "no";
};
links."10-eth" = {
matchConfig.Name = "enp4s0";
linkConfig.MACAddressPolicy = "random";
linkConfig.MACAddressPolicy = "persistent";
};
networks."10-eth" = {
@ -34,24 +37,43 @@
matchConfig.Name = "br0";
networkConfig = {
DHCP = "yes";
# Ensure DNS/Gateway is accepted
# Disable STP to prevent bridge topology re-calculations (fixes 15s delays)
# STP = "no"; # Done in netdev
IPv6PrivacyExtensions = "yes";
};
};
};
networking.enableIPv6 = false;
# Disable IPv6 via sysctl
boot.kernel.sysctl = {
"net.ipv6.conf.all.disable_ipv6" = 1;
"net.ipv6.conf.default.disable_ipv6" = 1;
"net.ipv6.conf.lo.disable_ipv6" = 1;
};
networking.enableIPv6 = true;
# Basic firewall settings
networking.firewall.enable = true;
networking.nftables.enable = true;
networking.firewall.checkReversePath = false; # Required for container routing
# Container NAT (Restoring connectivity after removing VPN module)
networking.nftables.tables."container-nat" = {
family = "inet";
content = ''
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# Masquerade all container traffic going out via the bridge
ip saddr 10.89.0.0/16 masquerade
}
'';
};
# Allow forwarding for containers (fixes DNS/Connectivity drops)
networking.nftables.tables."container-filter" = {
family = "inet";
content = ''
chain forward {
type filter hook forward priority -100; policy accept;
ip saddr 10.89.0.0/16 accept
ip daddr 10.89.0.0/16 accept
}
'';
};
# Dynamic DNS for Cloudflare
services.ddclient = {
@ -80,4 +102,42 @@
usev4 = "cmdv4";
extraConfig = "cmdv4='${pkgs.curl}/bin/curl -s https://api.ipify.org'";
};
# Make ddclient use a static user for UID-based routing
users.users.ddclient = {
isSystemUser = true;
group = "ddclient";
uid = 990;
};
users.groups.ddclient = {
gid = 990;
};
# Static Nginx User override removed - using dynamic detection in vpn-routing.nix
systemd.services.ddclient.serviceConfig = {
DynamicUser = lib.mkForce false;
User = "ddclient";
Group = "ddclient";
};
# Local Loopback for Hosted Services
# Ensures the host can reach these domains even if VPN routing prevents public IP loopback
networking.hosts = {
"127.0.0.1" = [
"api.ashisgreat.xyz"
"search.ashisgreat.xyz"
"chat.ashisgreat.xyz"
"auth.ashisgreat.xyz"
"stream.ashisgreat.xyz"
"stream-api.ashisgreat.xyz"
"sonarr.ashisgreat.xyz"
"radarr.ashisgreat.xyz"
"prowlarr.ashisgreat.xyz"
"torrent.ashisgreat.xyz"
"jellyfin.ashisgreat.xyz"
"jellyseer.ashisgreat.xyz"
"jellyseerr.ashisgreat.xyz"
];
};
}

View file

@ -0,0 +1,77 @@
{
lib,
pkgs,
inputs,
...
}:
{
nixpkgs.overlays = [
(final: prev: {
antigravity = prev.antigravity.overrideAttrs (oldAttrs: rec {
version = "1.18.3";
src = prev.fetchurl {
url = "https://edgedl.me.gvt1.com/edgedl/release2/j0qc3/antigravity/stable/1.18.3-4739469533380608/linux-x64/Antigravity.tar.gz";
sha256 = "0f4n3i45gjr36hidpvibzn3p2jla2r7wg91ybmf2akafjn6f8zsc";
};
});
})
];
nixpkgs.config.allowUnfreePredicate =
pkg:
builtins.elem (lib.getName pkg) [
"steam"
"steam-original"
"steam-run"
"spotify"
"antigravity"
"vscode-extension-bmewburn-vscode-intelephense-client"
"claude-code"
"steam-unwrapped"
];
# Disable command-not-found to prevent info leaks
programs.command-not-found.enable = false;
# Git security exception for flakes
programs.git = {
enable = true;
config.safe.directory = "/home/ashie/nixos";
};
# Automatic Updates (System + Containers)
myModules.autoUpdate.enable = true;
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
nix.settings.allowed-users = [ "ashie" ];
nix.settings.sandbox = true;
# Automatic Garbage Collection
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 7d";
};
# Binary caches for CachyOS kernel
nix.settings.substituters = [
"https://hyprland.cachix.org"
"https://nix-community.cachix.org"
"https://attic.xuyh0120.win/lantian"
"https://cache.garnix.io"
];
nix.settings.trusted-public-keys = [
"cache.cachyos.org-1:j9qLlx+z0OYBtCqflh9v4I+5fsljqG5l2/C9t0yY18q="
"hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="
"nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="
"lantian:EeAUQ+W+6r7EtwnmYjeVwx5kOGEBpjlBfPlzGlTNvHc="
"cache.garnix.io:CTFPyKSLcx5RMJKfLo5EEPUObbA78b0YQ2DTCJXqr9g="
];
# Registry pinning for instant shell startups
nix.registry.nixpkgs.flake = inputs.nixpkgs;
nix.channel.enable = false; # We are using flakes
}

View file

@ -0,0 +1,20 @@
{ pkgs, inputs, ... }:
{
# Noctalia shell
environment.systemPackages = with pkgs; [
inputs.noctalia.packages.${pkgs.stdenv.hostPlatform.system}.default
ydotool
];
environment.etc."glfw".source = "${pkgs.glfw}/lib";
boot.kernelModules = [
"uinput"
];
users.groups.uinput = { };
users.users.ashie.extraGroups = [ "uinput" ];
services.udev.extraRules = ''
KERNEL=="uinput", GROUP="uinput", MODE="0660", OPTIONS+="static_node=uinput"
'';
}

View file

@ -34,7 +34,7 @@
git
sbctl
fuzzel
# prismlauncher-sandboxed # Managed by Home Manager
# prismlauncher-sandboxed # Managed by System Module
polychromatic
vscodium
kdePackages.dolphin
@ -58,22 +58,24 @@
mangohud
gamemode
lact
umu-launcher
steam-run
fastfetch
hyfetch
nautilus
lutris-sandboxed
steam-sandboxed
azahar-sandboxed
faugus-sandboxed
citron-sandboxed
ryubing-sandboxed
# lutris-sandboxed # Added by module
# steam-sandboxed # Added by module
# azahar-sandboxed # Added by module
# faugus-sandboxed # Added by module
# citron-sandboxed # Added by module
# ryubing-sandboxed # Added by module
wireguard-tools
jq
grim
vlc
slurp
wl-clipboard
vesktop-sandboxed
# vesktop-sandboxed # Added by module
starship
zip
unzip
@ -96,18 +98,18 @@
stress-ng
kdePackages.kleopatra
kdePackages.ark
easyeffects
dysk
zstd
podman
spotify-sandboxed
# spotify-sandboxed # Added by module
jmtpfs
glfw
mlocate
openssl
nspr
firefox-sandboxed
tutanota-sandboxed
# firefox-sandboxed # Added by module
# tutanota-sandboxed # Added by module
# brave-sandboxed # Imported via module, wrapper provided there
eddie
appimage-run
@ -123,8 +125,14 @@
protontricks
file
ffmpeg-full
gsettings-desktop-schemas
glib
gtk3
gtk4
];
programs.dconf.enable = true;
environment.variables = {
QT_QPA_PLATFORMTHEME = "qt6ct";
};

View file

@ -34,6 +34,13 @@
sops.secrets.wireguard_dns = {
owner = "ashie";
};
sops.secrets.wireguard6_dns = {
owner = "ashie";
};
sops.secrets.wireguard6_adresses = {
owner = "ashie";
};
sops.secrets.open_webui_env = {
owner = "ashie";
@ -46,7 +53,7 @@
WIREGUARD_ENDPOINT_IP=${config.sops.placeholder.wireguard_endpoint_ip}
WIREGUARD_ENDPOINT_PORT=${config.sops.placeholder.wireguard_endpoint_port}
WIREGUARD_PRIVATE_KEY=${config.sops.placeholder.wireguard_private_key}
WIREGUARD_ADDRESSES=${config.sops.placeholder.wireguard_addresses}
WIREGUARD_ADDRESSES=${config.sops.placeholder.wireguard_addresses},${config.sops.placeholder.wireguard6_adresses}
WIREGUARD_PRESHARED_KEY=${config.sops.placeholder.wireguard_preshared_key}
DNS_ADDRESS=${config.sops.placeholder.wireguard_dns}
WIREGUARD_MTU=1320
@ -96,13 +103,13 @@
sops.secrets.prowlarr_api_key = { };
# Authelia Secrets
# sops.secrets.authelia_jwt_secret = {
# owner = "authelia-main";
# };
# sops.secrets.authelia_session_secret = {
# owner = "authelia-main";
# };
# sops.secrets.authelia_storage_encryption_key = {
# owner = "authelia-main";
# };
sops.secrets.authelia_jwt_secret = {
owner = "authelia-main";
};
sops.secrets.authelia_session_secret = {
owner = "authelia-main";
};
sops.secrets.authelia_storage_encryption_key = {
owner = "authelia-main";
};
}

View file

@ -4,8 +4,38 @@
pkgs,
...
}:
let
# Authelia internal location snippet
autheliaLocation = {
proxyPass = "http://127.0.0.1:9099/api/verify";
extraConfig = ''
internal;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
'';
};
# Config to enable Authelia protection
autheliaProtect = ''
auth_request /authelia;
auth_request_set $target_url $scheme://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
error_page 401 =302 https://auth.ashisgreat.xyz/?rd=$target_url;
'';
in
{
services.flatpak.enable = false;
services.flatpak = {
enable = true;
packages = [
"com.github.wwmm.easyeffects"
];
update.onActivation = true;
};
services.snowflake-proxy = {
enable = false;
@ -169,6 +199,8 @@
"sonarr.ashisgreat.xyz" = {
useACMEHost = "ashisgreat.xyz";
forceSSL = true;
extraConfig = autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:8989";
proxyWebsockets = true;
@ -178,6 +210,8 @@
"radarr.ashisgreat.xyz" = {
useACMEHost = "ashisgreat.xyz";
forceSSL = true;
extraConfig = autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:7878";
proxyWebsockets = true;
@ -187,6 +221,8 @@
"prowlarr.ashisgreat.xyz" = {
useACMEHost = "ashisgreat.xyz";
forceSSL = true;
extraConfig = autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:9696";
proxyWebsockets = true;
@ -196,6 +232,8 @@
"torrent.ashisgreat.xyz" = {
useACMEHost = "ashisgreat.xyz";
forceSSL = true;
extraConfig = autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:8080";
proxyWebsockets = true;
@ -221,6 +259,8 @@
"jellyseer.ashisgreat.xyz" = {
useACMEHost = "ashisgreat.xyz";
forceSSL = true;
extraConfig = autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:5055";
proxyWebsockets = true;
@ -242,7 +282,9 @@
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
'';
''
+ autheliaProtect;
locations."/authelia" = autheliaLocation;
locations."/" = {
proxyPass = "http://127.0.0.1:8082";
proxyWebsockets = true;

View file

@ -5,6 +5,8 @@
...
}:
{
programs.fish.enable = true;
users.mutableUsers = false;
users.users.ashie = {

View file

@ -36,26 +36,38 @@ in
systemd.user.services.antigravity2api = {
Unit = {
Description = "Antigravity API to OpenAI Proxy";
After = [ "network.target" ];
After = [ "network-online.target" ];
Wants = [ "network-online.target" ];
};
Service = {
WorkingDirectory = workDir;
ExecStartPre = pkgs.writeShellScript "antigravity2api-init" ''
export PATH="${pkgs.coreutils}/bin:$PATH"
export PATH="${pkgs.coreutils}/bin:${pkgs.iputils}/bin:$PATH"
mkdir -p "${workDir}"
# Ensure network exists (Not needed for host network)
# ${pkgs.podman}/bin/podman network create antigravity-net --ignore >/dev/null 2>&1 || true
# Wait for connectivity to 8.8.8.8 (Google DNS) used by the container
echo "Waiting for internet connectivity..."
until ping -c1 -W1 8.8.8.8 >/dev/null 2>&1; do
sleep 2
done
echo "Connectivity check passed."
cat > "${workDir}/.env" <<EOF
API_KEY=${cfg.credentials.apiKey}
ADMIN_USERNAME=${cfg.credentials.username}
ADMIN_PASSWORD=${cfg.credentials.password}
SYSTEM_INSTRUCTION=""
SYSTEM_INSTRUCTION=""
OFFICIAL_SYSTEM_PROMPT="You are Antigravity, a powerful agentic AI coding assistant designed by the Google Deepmind team working on Advanced Agentic Coding.You are pair programming with a USER to solve their coding task. The task may require creating a new codebase, modifying or debugging an existing codebase, or simply answering a question.**Proactiveness**"
EOF
'';
ExecStart = ''
${pkgs.podman}/bin/podman run --replace --rm --name antigravity2api \
-p 127.0.0.1:8045:8045 \
--network=host \
-v ${workDir}/data:/app/data \
-v ${workDir}/public/images:/app/public/images \
-v ${workDir}/.env:/app/.env \

View file

@ -70,6 +70,33 @@ in
pkgs.lxqt.lxqt-policykit
pkgs.libnotify
pkgs.swww
(pkgs.writeShellScriptBin "freeze-shot" ''
# Capture the screen to a temp file
file=$(mktemp --suffix=.png)
${pkgs.grim}/bin/grim "$file"
# Open imv in fullscreen to simulate freeze
# We run it in the background
${pkgs.imv}/bin/imv -f "$file" &
pid=$!
# Give imv a moment to open
sleep 0.2
# Run slurp to select region
geometry=$(${pkgs.slurp}/bin/slurp)
# Close the "frozen" overlay
kill "$pid"
# If we got a selection, crop and copy
if [ -n "$geometry" ]; then
${pkgs.imagemagick}/bin/magick "$file" -crop "$geometry" - | ${pkgs.wl-clipboard}/bin/wl-copy
fi
# Cleanup
rm "$file"
'')
];
xdg.portal = {
@ -234,7 +261,7 @@ in
Mod+Shift+E { spawn "bemoji" "-t"; }
Print { spawn "sh" "-c" "grim -g \"$(slurp)\" - | wl-copy"; }
Print { spawn "freeze-shot"; }
// Browsers
Mod+W { spawn "firefox"; }

View file

@ -61,6 +61,29 @@ in
mShadow = mocha.crust;
};
plugins = {
sources = [
{
enabled = true;
name = "Official Noctalia Plugins";
url = "https://github.com/noctalia-dev/noctalia-plugins";
branch = "main"; # Explicitly set branch just in case
}
];
states = {
"assistant-panel" = {
enabled = true;
sourceUrl = "https://github.com/noctalia-dev/noctalia-plugins";
};
};
};
pluginSettings = {
"assistant-panel" = {
service = "openai";
};
};
settings = {
colorSchemes = {
darkMode = true;

View file

@ -38,7 +38,7 @@ let
glfw
];
defaultJvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
defaultJvmArgs = "-Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
in
{
@ -66,225 +66,230 @@ in
config = lib.mkIf cfg.enable {
home.packages = [
(bwrapperPkgs.mkBwrapper {
app = {
id = "org.prismlauncher.PrismLauncher";
package = pkgs.prismlauncher.overrideAttrs (old: {
pname = "prismlauncher";
version = old.version or "9.1"; # Fallback or keep current if valid
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.jemalloc ];
(
let
sandboxed = bwrapperPkgs.mkBwrapper {
app = {
id = "org.prismlauncher.PrismLauncher";
package = pkgs.prismlauncher.overrideAttrs (old: {
pname = "prismlauncher";
version = old.version or "9.1"; # Fallback or keep current if valid
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.jemalloc ];
# Keep runtimeLibs in closure without injecting them into environment
postInstall = (old.postInstall or "") + ''
mkdir -p $out/share/prismlauncher-sandboxed
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
'';
# Keep runtimeLibs in closure without injecting them into environment
postInstall = (old.postInstall or "") + ''
mkdir -p $out/share/prismlauncher-sandboxed
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
'';
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
"--set JEMALLOC_PATH ${pkgs.jemalloc}/lib/libjemalloc.so"
"--prefix LD_PRELOAD : ${pkgs.jemalloc}/lib/libjemalloc.so"
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
"--set JEMALLOC_PATH ${pkgs.jemalloc}/lib/libjemalloc.so"
"--prefix LD_PRELOAD : ${pkgs.jemalloc}/lib/libjemalloc.so"
];
});
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
BROWSER = "firefox";
QT_QPA_PLATFORM = "xcb";
GDK_BACKEND = "x11";
NO_AT_BRIDGE = "1";
QT_QPA_PLATFORMTHEME = "";
QT_STYLE_OVERRIDE = "fusion";
# Sanitize Desktop Environment to prevent loading conflicting platform themes
XDG_CURRENT_DESKTOP = "X-Generic";
XDG_SESSION_TYPE = "x11";
GTK_USE_PORTAL = "0";
GTK_THEME = "Adwaita"; # Force a safe theme or empty?
# Unset potential conflict variables
GTK_MODULES = "";
GTK3_MODULES = "";
};
};
sockets.x11 = true;
sockets.wayland = true;
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString cfg.uid}"
# Bind ro system paths commonly needed
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--ro-bind /run/dbus /run/dbus"
];
});
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
BROWSER = "firefox";
QT_QPA_PLATFORM = "xcb";
GDK_BACKEND = "x11";
NO_AT_BRIDGE = "1";
QT_QPA_PLATFORMTHEME = "";
QT_STYLE_OVERRIDE = "fusion";
# Sanitize Desktop Environment to prevent loading conflicting platform themes
XDG_CURRENT_DESKTOP = "X-Generic";
XDG_SESSION_TYPE = "x11";
GTK_USE_PORTAL = "0";
GTK_THEME = "Adwaita"; # Force a safe theme or empty?
# Unset potential conflict variables
GTK_MODULES = "";
GTK3_MODULES = "";
};
};
sockets.x11 = true;
sockets.wayland = true;
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString cfg.uid}"
# Bind ro system paths commonly needed
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--ro-bind /run/dbus /run/dbus"
];
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/qt6ct"
"$HOME/.config/Kvantum"
"$HOME/.config/MangoHud"
"$HOME/Downloads"
];
readWrite = [
"$HOME/.local/share/PrismLauncher"
"$HOME/.cache/PrismLauncher"
];
};
dbus.enable = false;
script.preCmds.stage2 =
let
glfwPath = "${cfg.glfwPackage}/lib/libglfw.so.3";
# We need to access the sandbox-utils.nix. Since it's in system modules,
# we can't easily import it relative to here if it's not exported.
# But the content was small, let's inline what we need or check if we can source it.
# For now, I'll assume the dbus-proxy logic is needed.
# Reimplementing mkDbusProxyScript from sandbox-utils.nix inline to avoid path dependency
mkDbusProxyScript =
{ appId, proxyArgs }:
let
proxyArgsStr = lib.escapeShellArgs proxyArgs;
appDir = "$XDG_RUNTIME_DIR/app/${appId}";
proxySocket = "${appDir}/bus";
in
''
mkdir -p "${appDir}"
# Start xdg-dbus-proxy
${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy \
"$DBUS_SESSION_BUS_ADDRESS" "${proxySocket}" \
${proxyArgsStr} &
DBUS_PROXY_PID=$!
# Kill proxy on exit
trap "kill $DBUS_PROXY_PID" EXIT
# Wait for socket to be created
for i in {1..50}; do
if [ -S "${proxySocket}" ]; then
break
fi
if ! kill -0 $DBUS_PROXY_PID 2>/dev/null; then
echo "xdg-dbus-proxy died unexpectedly"
exit 1
fi
sleep 0.1
done
'';
dbusScript = mkDbusProxyScript {
appId = "org.prismlauncher.PrismLauncher";
proxyArgs = [
"--filter"
"--talk=org.freedesktop.portal.*"
"--call=org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"
"--talk=org.freedesktop.Notifications"
"--own=org.prismlauncher.PrismLauncher"
"--own=org.prismlauncher.PrismLauncher.*"
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/qt6ct"
"$HOME/.config/Kvantum"
"$HOME/.config/MangoHud"
"$HOME/Downloads"
];
readWrite = [
"$HOME/.local/share/PrismLauncher"
"$HOME/.cache/PrismLauncher"
];
};
in
''
${dbusScript}
# Sanitize Environment
unset QT_QPA_PLATFORMTHEME
unset GTK_THEME
unset XDG_CURRENT_DESKTOP
export QT_QPA_PLATFORM=xcb
export GDK_BACKEND=x11
export NO_AT_BRIDGE=1
dbus.enable = false;
# Force Configs (JVM Args + GLFW)
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
if [ -f "$cfg" ]; then
# JVM Args
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${cfg.jvmArgs}|" "$cfg"
else
if ${pkgs.gnugrep}/bin/grep -q "^\\[General\\]" "$cfg"; then
${pkgs.gnused}/bin/sed -i "/^\\[General\\]/a JvmArgs=${cfg.jvmArgs}" "$cfg"
else
echo "JvmArgs=${cfg.jvmArgs}" >> "$cfg"
fi
fi
script.preCmds.stage2 =
let
glfwPath = "${cfg.glfwPackage}/lib/libglfw.so.3";
# GLFW Settings
# 1. CustomGLFWPath
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
else
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
fi
# We need to access the sandbox-utils.nix. Since it's in system modules,
# we can't easily import it relative to here if it's not exported.
# But the content was small, let's inline what we need or check if we can source it.
# For now, I'll assume the dbus-proxy logic is needed.
# 2. UseNativeGLFW
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
else
echo "UseNativeGLFW=true" >> "$cfg"
fi
fi
'';
# Reimplementing mkDbusProxyScript from sandbox-utils.nix inline to avoid path dependency
mkDbusProxyScript =
{ appId, proxyArgs }:
let
proxyArgsStr = lib.escapeShellArgs proxyArgs;
appDir = "$XDG_RUNTIME_DIR/app/${appId}";
proxySocket = "${appDir}/bus";
in
''
mkdir -p "${appDir}"
# Start xdg-dbus-proxy
${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy \
"$DBUS_SESSION_BUS_ADDRESS" "${proxySocket}" \
${proxyArgsStr} &
DBUS_PROXY_PID=$!
fhsenv.bwrap.additionalArgs = [
# D-Bus proxy
''--bind "$XDG_RUNTIME_DIR/bus" "$XDG_RUNTIME_DIR/bus"''
# Note: The original code bound a specific path TO ./bus.
# "''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''"
# But mkDbusProxyScript (if standard) creates a socket.
# The logic in prismlauncher-sandboxed.nix imported sandbox-utils.nix.
# I'll try to match the original bind logic if possible.
# Kill proxy on exit
trap "kill $DBUS_PROXY_PID" EXIT
# The original code had:
# ''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
# But my inline mkDbusProxyScript sets up "$XDG_RUNTIME_DIR/bus" as the listen socket *inside* the script execution?
# Wait, xdg-dbus-proxy runs inside the outer unshared namespace or outside?
# In mkBwrapper, preCmds run *inside* the bwrap?
# No, typically preCmds run before the final exec?
# Actually, looking at nix-bwrapper, `preCmds.stage2` runs *inside* the sandbox?
# Wait for socket to be created
for i in {1..50}; do
if [ -S "${proxySocket}" ]; then
break
fi
if ! kill -0 $DBUS_PROXY_PID 2>/dev/null; then
echo "xdg-dbus-proxy died unexpectedly"
exit 1
fi
sleep 0.1
done
'';
# Let's start with the binds exactly as they were, assuming `sandbox-utils` logic.
# If I can't import sandbox-utils, I have to rely on what I can see.
# The original `sandbox-utils.nix` likely set up the proxy.
# I will copy the binds from the original file.
dbusScript = mkDbusProxyScript {
appId = "org.prismlauncher.PrismLauncher";
proxyArgs = [
"--filter"
"--talk=org.freedesktop.portal.*"
"--call=org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"
"--talk=org.freedesktop.Notifications"
"--own=org.prismlauncher.PrismLauncher"
"--own=org.prismlauncher.PrismLauncher.*"
];
};
in
''
${dbusScript}
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
# Sanitize Environment
unset QT_QPA_PLATFORMTHEME
unset GTK_THEME
unset XDG_CURRENT_DESKTOP
export QT_QPA_PLATFORM=xcb
export GDK_BACKEND=x11
export NO_AT_BRIDGE=1
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# Force Configs (JVM Args + GLFW)
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
if [ -f "$cfg" ]; then
# JVM Args
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${cfg.jvmArgs}|" "$cfg"
else
if ${pkgs.gnugrep}/bin/grep -q "^\\[General\\]" "$cfg"; then
${pkgs.gnused}/bin/sed -i "/^\\[General\\]/a JvmArgs=${cfg.jvmArgs}" "$cfg"
else
echo "JvmArgs=${cfg.jvmArgs}" >> "$cfg"
fi
fi
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
})
# GLFW Settings
# 1. CustomGLFWPath
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
else
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
fi
# 2. UseNativeGLFW
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
else
echo "UseNativeGLFW=true" >> "$cfg"
fi
fi
'';
fhsenv.bwrap.additionalArgs = [
# D-Bus proxy
''--bind "$XDG_RUNTIME_DIR/bus" "$XDG_RUNTIME_DIR/bus"''
# Note: The original code bound a specific path TO ./bus.
# "''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''"
# But mkDbusProxyScript (if standard) creates a socket.
# The logic in prismlauncher-sandboxed.nix imported sandbox-utils.nix.
# I'll try to match the original bind logic if possible.
# The original code had:
# ''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
# But my inline mkDbusProxyScript sets up "$XDG_RUNTIME_DIR/bus" as the listen socket *inside* the script execution?
# Wait, xdg-dbus-proxy runs inside the outer unshared namespace or outside?
# In mkBwrapper, preCmds run *inside* the bwrap?
# No, typically preCmds run before the final exec?
# Actually, looking at nix-bwrapper, `preCmds.stage2` runs *inside* the sandbox?
# Let's start with the binds exactly as they were, assuming `sandbox-utils` logic.
# If I can't import sandbox-utils, I have to rely on what I can see.
# The original `sandbox-utils.nix` likely set up the proxy.
# I will copy the binds from the original file.
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
};
in
sandboxed
)
];
};
}

View file

@ -0,0 +1,81 @@
# Automatic Updates Module
# Provides:
# 1. Weekly Nix flake updates for the system configuration
# 2. Daily NixOS system upgrades via system.autoUpgrade
# 3. Daily Podman container updates for services with 'io.containers.autoupdate' label
{
config,
lib,
pkgs,
...
}:
let
cfg = config.myModules.autoUpdate;
repoPath = "/home/ashie/nixos";
in
{
options.myModules.autoUpdate = {
enable = lib.mkEnableOption "system-wide automatic updates";
};
config = lib.mkIf cfg.enable {
# 1. NixOS System Upgrades
system.autoUpgrade = {
enable = true;
dates = "04:30";
flake = "${repoPath}#nixos";
allowReboot = false;
flags = [
"--refresh"
];
};
# 2. Flake Update Service (Runs before autoUpgrade)
# This ensures the local flake.lock is updated so autoUpgrade has new versions to pull.
systemd.services.nix-flake-update = {
description = "Update Nix Flake Lockfile";
serviceConfig = {
Type = "oneshot";
User = "root";
};
path = [ pkgs.nix pkgs.git pkgs.openssh ];
script = ''
cd ${repoPath}
# Only update if it's a git repo and we have permissions
if [ -d .git ]; then
nix flake update --commit-lock-file
else
nix flake update
fi
'';
startAt = "04:00"; # Run 30 mins before autoUpgrade
};
# 3. Podman Container Auto-Updates
# Runs 'podman auto-update' to refresh containers with the 'io.containers.autoupdate' label.
systemd.services.podman-auto-update = {
description = "Podman Container Auto-Update";
after = [ "network-online.target" "nixos-upgrade.service" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.podman}/bin/podman auto-update";
ExecStartPost = "${pkgs.podman}/bin/podman image prune -f";
};
};
systemd.timers.podman-auto-update = {
description = "Podman Container Auto-Update Timer";
timerConfig = {
OnCalendar = "05:00";
Persistent = true;
};
wantedBy = [ "timers.target" ];
};
# Ensure the auto-upgrade service waits for the flake update
systemd.services.nixos-upgrade.after = [ "nix-flake-update.service" ];
};
}

View file

@ -1,13 +1,14 @@
{
config,
{ config,
lib,
pkgs,
inputs,
...
...
}:
let
let
cfg = config.myModules.azaharSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
pname = "azahar";
version = "2123.4";
@ -35,58 +36,68 @@ let
};
in
{
nixpkgs.overlays = [
(final: prev: {
azahar-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = azahar;
id = "org.azahar_emu.Azahar";
env = {
QT_QPA_PLATFORM = "wayland;xcb";
XDG_CURRENT_DESKTOP = "KDE";
options.myModules.azaharSandboxed = {
enable = lib.mkEnableOption "sandboxed Azahar with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
azahar-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = azahar;
id = "org.azahar_emu.Azahar";
env = {
QT_QPA_PLATFORM = "wayland;xcb";
XDG_CURRENT_DESKTOP = "KDE";
};
};
flatpak.enable = false;
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/org.azahar_emu.Azahar/bus" "$XDG_RUNTIME_DIR/bus"''
];
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = [
"$HOME/Games/3DS"
"$HOME/.config/azahar"
"$HOME/.local/share/azahar"
] ++ cfg.extraBindMounts;
};
dbus.enable = false;
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "org.azahar_emu.Azahar";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.Flatpak"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.secrets"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
];
};
};
})
];
flatpak.enable = false;
fhsenv.bwrap.additionalArgs = [
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
''--bind "$XDG_RUNTIME_DIR/app/org.azahar_emu.Azahar/bus" "$XDG_RUNTIME_DIR/bus"''
];
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
"$HOME/.config/fontconfig"
"$HOME/.icons"
"$HOME/.config/MangoHud"
];
readWrite = [
"$HOME/Games/3DS"
"$HOME/.config/azahar"
"$HOME/.local/share/azahar"
];
};
dbus.enable = false;
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "org.azahar_emu.Azahar";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.Flatpak"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.secrets"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
];
};
};
})
];
environment.systemPackages = [ pkgs.azahar-sandboxed ];
};
}

View file

@ -7,7 +7,9 @@
}:
let
cfg = config.myModules.braveSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
# create a custom settings.ini to force dark mode
darkSettingsIni = pkgs.writeText "settings.ini" ''
@ -31,138 +33,150 @@ let
);
in
{
nixpkgs.overlays = [
(final: prev: {
brave-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = pkgs.symlinkJoin {
name = "brave-single-desktop";
paths = [ prev.brave ];
inherit (prev.brave) pname version meta;
postBuild = ''
rm $out/share/applications/com.brave.Browser.desktop
'';
options.myModules.braveSandboxed = {
enable = lib.mkEnableOption "sandboxed Brave with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
brave-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = pkgs.symlinkJoin {
name = "brave-single-desktop";
paths = [ prev.brave ];
inherit (prev.brave) pname version meta;
postBuild = ''
rm $out/share/applications/com.brave.Browser.desktop
'';
};
# id = "brave-browser"; # Omit app.id to avoid potential bind errors (like Firefox)
env = {
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
GTK_THEME = "catppuccin-mocha-mauve-standard";
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
HYPRCURSOR_SIZE = "32";
# Force ozone/wayland usage for Brave/Chromium
NIXOS_OZONE_WL = "1";
};
};
# id = "brave-browser"; # Omit app.id to avoid potential bind errors (like Firefox)
env = {
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
GTK_THEME = "catppuccin-mocha-mauve-standard";
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
HYPRCURSOR_SIZE = "32";
# Force ozone/wayland usage for Brave/Chromium
NIXOS_OZONE_WL = "1";
flatpak.enable = false;
sockets.x11 = false;
sockets.wayland = true;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
};
flatpak.enable = false;
sockets.x11 = false;
sockets.wayland = true;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /mnt"
"--tmpfs /run"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/booted-system /run/booted-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
# Brave flags
"--setenv NIXOS_OZONE_WL \"1\""
"--setenv NOTIFY_IGNORE_PORTAL 1"
# Bind policies for Theme
"--dir /etc/brave/policies/managed"
"--ro-bind ${bravePolicies} /etc/brave/policies/managed/policies.json"
# Fallback paths for Chromium/Chrome base
"--dir /etc/chromium/policies/managed"
"--ro-bind ${bravePolicies} /etc/chromium/policies/managed/policies.json"
"--dir /etc/opt/chrome/policies/managed"
"--ro-bind ${bravePolicies} /etc/opt/chrome/policies/managed/policies.json"
];
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /mnt"
"--tmpfs /run"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/booted-system /run/booted-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
# Brave flags
"--setenv NIXOS_OZONE_WL \"1\""
"--setenv NOTIFY_IGNORE_PORTAL 1"
# Bind policies for Theme
"--dir /etc/brave/policies/managed"
"--ro-bind ${bravePolicies} /etc/brave/policies/managed/policies.json"
# Fallback paths for Chromium/Chrome base
"--dir /etc/chromium/policies/managed"
"--ro-bind ${bravePolicies} /etc/chromium/policies/managed/policies.json"
"--dir /etc/opt/chrome/policies/managed"
"--ro-bind ${bravePolicies} /etc/opt/chrome/policies/managed/policies.json"
# Filesystem: Limited to Brave directories and Downloads
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.config/fontconfig"
"$HOME/.config/user-dirs.dirs"
"$HOME/.config/mimeapps.list"
"$HOME/.local/share/color-schemes"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/gtk-3.0"
];
readWrite = [
"$HOME/.config/BraveSoftware"
"$HOME/.cache/BraveSoftware"
"$HOME/Downloads"
] ++ cfg.extraBindMounts;
};
# Bind mount systemd-resolved socket for DNS and required system files
# Disable built-in DBus module because it invokes bwrap without --unshare-user
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "nix.bwrapper.brave";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.secrets"''
''--talk="org.kde.StatusNotifierWatcher"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="org.chromium.LibCrosService"'' # Chromium/Brave specific
''--own="org.mpris.MediaPlayer2.chromium.*"''
''--own="org.mpris.MediaPlayer2.brave.*"''
];
enableSystemBus = true;
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.NetworkManager"''
];
};
fhsenv.bwrap.additionalArgs = [
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus" "$XDG_RUNTIME_DIR/bus"''
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus_system" /run/dbus/system_bus_socket''
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--bind-try /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
];
};
})
];
environment.systemPackages = [
(pkgs.writeShellScriptBin "brave" ''
exec ${config.myModules.system.repoPath}/scripts/launch-vpn-app.sh ${pkgs.brave-sandboxed}/bin/brave "$@"
'')
(pkgs.makeDesktopItem {
name = "brave-vpn";
desktopName = "Brave Web Browser";
exec = "brave %U";
icon = "brave-browser";
categories = [
"Network"
"WebBrowser"
];
# Filesystem: Limited to Brave directories and Downloads
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.config/fontconfig"
"$HOME/.config/user-dirs.dirs"
"$HOME/.config/mimeapps.list"
"$HOME/.local/share/color-schemes"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/gtk-3.0"
];
readWrite = [
"$HOME/.config/BraveSoftware"
"$HOME/.cache/BraveSoftware"
"$HOME/Downloads"
];
};
# Bind mount systemd-resolved socket for DNS and required system files
# Disable built-in DBus module because it invokes bwrap without --unshare-user
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "nix.bwrapper.brave";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.secrets"''
''--talk="org.kde.StatusNotifierWatcher"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="org.chromium.LibCrosService"'' # Chromium/Brave specific
''--own="org.mpris.MediaPlayer2.chromium.*"''
''--own="org.mpris.MediaPlayer2.brave.*"''
];
enableSystemBus = true;
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.NetworkManager"''
];
};
fhsenv.bwrap.additionalArgs = [
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus" "$XDG_RUNTIME_DIR/bus"''
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.brave/bus_system" /run/dbus/system_bus_socket''
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
];
};
})
];
environment.systemPackages = [
(pkgs.writeShellScriptBin "brave" ''
exec /home/ashie/nixos/scripts/launch-vpn-app.sh ${pkgs.brave-sandboxed}/bin/brave "$@"
'')
(pkgs.makeDesktopItem {
name = "brave-vpn";
desktopName = "Brave Web Browser";
exec = "brave %U";
icon = "brave-browser";
categories = [
"Network"
"WebBrowser"
];
})
];
}
})
];
};
}

64
modules/nixos/braveapi.py Normal file
View file

@ -0,0 +1,64 @@
"""
Search Engine: Brave Search API
"""
import json
import os
from urllib.parse import quote
# About the engine
about = {
"website": "https://brave.com/search/api/",
"use_official_api": True,
"require_api_key": True,
"results": "JSON",
}
categories = ['general', 'web']
paging = True
max_page = 10
page_size = 20
# API Endpoint
base_url = "https://api.search.brave.com/res/v1/web/search"
def request(query, params):
# Get key from environment
api_key = os.getenv('BRAVE_API_KEY')
# Brave expects offset 0-9 for pages
pageno = min(params.get('pageno', 1), 10)
offset = pageno - 1
# Simple query string construction with proper quoting
# Using 'x-subscription-token' (lowercase) which was verified to work
params['url'] = f"{base_url}?q={quote(query)}&count=20&offset={offset}"
params['headers'] = {
'x-subscription-token': api_key,
'Accept': 'application/json'
}
params['method'] = 'GET'
# Clean up SearXNG defaults to prevent interference
if 'data' in params: del params['data']
if 'params' in params: del params['params']
return params
def response(resp):
results = []
data = json.loads(resp.text)
# The Brave API returns 'web' results
web_results = data.get('web', {}).get('results', [])
for item in web_results:
results.append({
'url': item.get('url'),
'title': item.get('title'),
'content': item.get('description'),
})
return results

View file

@ -18,6 +18,7 @@
let
cfg = config.myModules.browserVpn;
mainUser = config.myModules.system.mainUser;
# Helper function for auto-recovery from podman namespace corruption
# Detects "cannot re-exec process" errors and runs migrate to fix
@ -78,7 +79,8 @@ let
echo "Build complete."
;;
run)
if ! podman_with_recovery image exists ${imageName}:latest 2>/dev/null; then
if ! podman_with_recovery image exists ${imageName}:latest 2>/dev/null;
then
echo "Building ${name} container image..."
podman_with_recovery build -t ${imageName}:latest "$REPO_DIR/containers/${name}-wayland/"
fi
@ -168,8 +170,8 @@ let
Fingerprinting = true;
};
Preferences = {
"network.dns.disableIPv6" = true;
"network.ipv6" = false;
"network.dns.disableIPv6" = false;
"network.ipv6" = true;
"network.http.fast-fallback-to-IPv4" = true;
"network.trr.mode" = 5; # Disable DNS over HTTPS (use system/VPN DNS)
"ui.systemUsesDarkTheme" = 1;
@ -231,7 +233,8 @@ let
echo "Build complete."
;;
run)
if ! podman_with_recovery image exists localhost/thorium-wayland:latest 2>/dev/null; then
if ! podman_with_recovery image exists localhost/thorium-wayland:latest 2>/dev/null;
then
echo "Building thorium-dev container image..."
podman_with_recovery build -t localhost/thorium-wayland:latest "$REPO_DIR/containers/thorium-wayland/"
fi
@ -315,7 +318,8 @@ let
echo "Build complete."
;;
run)
if ! podman_with_recovery image exists localhost/arch-kitty:latest 2>/dev/null; then
if ! podman_with_recovery image exists localhost/arch-kitty:latest 2>/dev/null;
then
echo "Building Arch Kitty container image..."
podman_with_recovery build -t localhost/arch-kitty:latest "$REPO_DIR/containers/arch-kitty/"
fi
@ -450,13 +454,13 @@ in
kittyConfigDir = lib.mkOption {
type = lib.types.str;
default = "/home/ashie/.config/kitty";
default = "/home/${mainUser}/.config/kitty";
description = "Path to kitty configuration directory";
};
bashrcPath = lib.mkOption {
type = lib.types.str;
default = "/home/ashie/.bashrc";
default = "/home/${mainUser}/.bashrc";
description = "Path to bashrc file for Kitty container";
};
};
@ -464,4 +468,4 @@ in
config = lib.mkIf cfg.enable {
environment.systemPackages = enabledPackages ++ [ desktopEntriesPackage ];
};
}
}

View file

@ -10,7 +10,9 @@
}:
let
cfg = config.myModules.citronSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
pname = "citron";
version = "0.12.25";
@ -74,123 +76,110 @@ let
};
in
{
nixpkgs.overlays = [
(final: prev: {
citron-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = citron;
id = appId;
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
QT_QPA_PLATFORM = "wayland;xcb";
XDG_CURRENT_DESKTOP = "KDE";
# Allow AppImage to extract and run
APPIMAGE_EXTRACT_AND_RUN = "1";
options.myModules.citronSandboxed = {
enable = lib.mkEnableOption "sandboxed Citron with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
citron-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = citron;
id = appId;
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
QT_QPA_PLATFORM = "wayland;xcb";
XDG_CURRENT_DESKTOP = "KDE";
# Allow AppImage to extract and run
APPIMAGE_EXTRACT_AND_RUN = "1";
};
};
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable Flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for online features
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
"--tmpfs /usr/share"
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
"--ro-bind-try /nix/store /nix/store"
]);
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
# Also create required directories before bwrap runs
script.preCmds.stage2 = ''
# Create directories that bwrap will bind
mkdir -p "$HOME/.cache/citron-tmp"
mkdir -p "$HOME/.config/citron"
mkdir -p "$HOME/.config/Citron"
mkdir -p "$HOME/.local/share/citron"
mkdir -p "$HOME/.local/share/Citron"
mkdir -p "$HOME/Games/Switch"
''
+ sandboxUtils.mkDbusProxyScript {
inherit appId;
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--own="${appId}"''
''--own="${appId}.*"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
# Read-write mounts
"--bind $HOME/Games/Switch $HOME/Games/Switch"
"--bind $HOME/.config/citron $HOME/.config/citron"
"--bind $HOME/.config/Citron $HOME/.config/Citron"
"--bind $HOME/.local/share/citron $HOME/.local/share/citron"
"--bind $HOME/.local/share/Citron $HOME/.local/share/Citron"
"--bind $HOME/.cache/citron-tmp $HOME/.cache/citron-tmp"
];
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = cfg.extraBindMounts;
};
};
})
];
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable Flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for online features
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--dev-bind /dev/shm /dev/shm" # Shared memory
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
"--dev-bind-try /dev/input /dev/input"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
"--tmpfs /usr/share"
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--ro-bind-try /nix/store /nix/store"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# udev for controller hotplug
"--ro-bind-try /run/udev /run/udev"
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
# Also create required directories before bwrap runs
script.preCmds.stage2 = ''
# Create directories that bwrap will bind
mkdir -p "$HOME/.cache/citron-tmp"
mkdir -p "$HOME/.config/citron"
mkdir -p "$HOME/.config/Citron"
mkdir -p "$HOME/.local/share/citron"
mkdir -p "$HOME/.local/share/Citron"
mkdir -p "$HOME/Games/Switch"
''
+ (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
inherit appId;
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--own="${appId}"''
''--own="${appId}.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
# Manual mounts for data persistence
"--ro-bind-try $HOME/.config/kdedefaults $HOME/.config/kdedefaults"
"--ro-bind-try $HOME/.local/share/color-schemes $HOME/.local/share/color-schemes"
"--ro-bind-try $HOME/.config/fontconfig $HOME/.config/fontconfig"
"--ro-bind-try $HOME/.local/share/fonts $HOME/.local/share/fonts"
"--ro-bind-try $HOME/.icons $HOME/.icons"
"--ro-bind-try $HOME/.themes $HOME/.themes"
"--ro-bind-try $HOME/.config/qt6ct $HOME/.config/qt6ct"
"--ro-bind-try $HOME/.config/Kvantum $HOME/.config/Kvantum"
"--ro-bind-try $HOME/.config/MangoHud $HOME/.config/MangoHud"
# Read-write mounts
"--bind $HOME/Games/Switch $HOME/Games/Switch"
"--bind $HOME/.config/citron $HOME/.config/citron"
"--bind $HOME/.config/Citron $HOME/.config/Citron"
"--bind $HOME/.local/share/citron $HOME/.local/share/citron"
"--bind $HOME/.local/share/Citron $HOME/.local/share/Citron"
"--bind $HOME/.cache/citron-tmp $HOME/.cache/citron-tmp"
];
};
})
];
environment.systemPackages = [ pkgs.citron-sandboxed ];
};
}

View file

@ -118,13 +118,16 @@ in
# Allow all traffic from internal container interfaces (Podman/CNI)
# This allows containers to reach the host (DNS, Gateway)
iifname "podman*" accept
iifname "cni*" accept
# Allow container subnet (fixes issues with non-podman* interface names)
ip saddr 10.89.0.0/16 accept
# Allow RFC1918 Private Networks (LAN, Containers, Link-Local)
${lib.optionalString cfg.allowLocalTraffic ''
ip saddr 10.0.0.0/8 accept
ip saddr 172.16.0.0/12 accept
ip saddr 192.168.0.0/16 accept
ip saddr 10.0.0.0/8 accept
ip saddr 172.16.0.0/12 accept
ip saddr 192.168.0.0/16 accept
''}
ip saddr 169.254.0.0/16 accept
@ -137,7 +140,7 @@ in
${lib.optionalString (cfg.restrictedPorts != [ ]) ''
ip saddr @cloudflare_ipv4 tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } accept
ip6 saddr @cloudflare_ipv6 tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } accept
# Drop all other traffic to restricted ports
tcp dport { ${lib.concatStringsSep ", " (map toString cfg.restrictedPorts)} } drop
''}
@ -151,6 +154,9 @@ in
oifname "podman*" accept
iifname "cni*" accept
oifname "cni*" accept
# Allow container subnet forwarding
ip saddr 10.89.0.0/16 accept
ip daddr 10.89.0.0/16 accept
# Allow established/related forwarding
ct state established,related accept

View file

@ -10,5 +10,11 @@
default = "/home/ashie/nixos";
description = "Path to the main NixOS configuration repository";
};
mainUser = lib.mkOption {
type = lib.types.str;
default = "ashie";
description = "Username of the main user";
};
};
}

View file

@ -1,14 +1,25 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.myModules.desktop.cosmic;
in
{
services.desktopManager.cosmic.enable = true;
services.displayManager.cosmic-greeter.enable = false;
options.myModules.desktop.cosmic = {
enable = lib.mkEnableOption "Cosmic Desktop Environment";
};
# Optimization
services.system76-scheduler.enable = true;
config = lib.mkIf cfg.enable {
services.desktopManager.cosmic.enable = true;
services.displayManager.cosmic-greeter.enable = false;
# Clipboard support (unstable protocol)
environment.sessionVariables.COSMIC_DATA_CONTROL_ENABLED = "1";
}
# Optimization
services.system76-scheduler.enable = true;
# Clipboard support (unstable protocol)
environment.sessionVariables.COSMIC_DATA_CONTROL_ENABLED = "1";
};
}

View file

@ -36,5 +36,10 @@
./tutanota-sandboxed.nix
./hardened-malloc.nix
./searxng.nix
./media.nix
./cosmic.nix
./steam-gamemode.nix
./redlib.nix
./auto-update.nix
];
}
}

View file

@ -10,138 +10,125 @@
}:
let
cfg = config.myModules.faugusSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
in
{
nixpkgs.overlays = [
(final: prev: {
faugus-sandboxed =
let
singleDesktopPkg =
pkgs.symlinkJoin {
name = "faugus-launcher-single";
paths = [ prev.faugus-launcher ];
postBuild = ''
rm -rf $out/share/applications
mkdir -p $out/share/applications
ln -s ${prev.faugus-launcher}/share/applications/faugus-launcher.desktop $out/share/applications/io.github.faugus.Launcher.desktop
'';
}
// {
inherit (prev.faugus-launcher) pname version meta;
options.myModules.faugusSandboxed = {
enable = lib.mkEnableOption "sandboxed Faugus Launcher with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
faugus-sandboxed =
let
singleDesktopPkg =
pkgs.symlinkJoin {
name = "faugus-launcher-single";
paths = [ prev.faugus-launcher ];
postBuild = ''
rm -rf $out/share/applications
mkdir -p $out/share/applications
ln -s ${prev.faugus-launcher}/share/applications/faugus-launcher.desktop $out/share/applications/io.github.faugus.Launcher.desktop
'';
}
// {
inherit (prev.faugus-launcher) pname version meta;
};
in
bwrapperPkgs.mkBwrapper {
app = {
package = singleDesktopPkg;
id = "io.github.faugus.Launcher";
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Fix for file dialogs/theming
XDG_CURRENT_DESKTOP = "KDE";
# GTK theming
GTK_THEME = "catppuccin-frappe-blue-standard";
# Force GTK to use the portal for file dialogs
GTK_USE_PORTAL = "1";
# Force Wayland backend to ensure xdg-foreign protocol works
GDK_BACKEND = "wayland";
};
};
in
bwrapperPkgs.mkBwrapper {
app = {
package = singleDesktopPkg;
id = "io.github.faugus.Launcher";
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Fix for file dialogs/theming
XDG_CURRENT_DESKTOP = "KDE";
# GTK theming
GTK_THEME = "catppuccin-frappe-blue-standard";
# Force GTK to use the portal for file dialogs
GTK_USE_PORTAL = "1";
# Force Wayland backend to ensure xdg-foreign protocol works
GDK_BACKEND = "wayland";
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable Flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network
unshareIpc = false;
};
};
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
# Disable Flatpak emulation
flatpak.enable = false;
mounts = {
read = sandboxUtils.mkGuiMounts.read ++ [
"$HOME/.gtkrc-2.0"
];
readWrite = [
"$HOME/Games"
"$HOME/.config/faugus-launcher"
"$HOME/.local/share/faugus-launcher"
"$HOME/.cache/faugus-launcher"
"$HOME/.config/qt6ct" # Allow theming
] ++ cfg.extraBindMounts;
};
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network
unshareIpc = false;
};
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--dev-bind /dev/shm /dev/shm" # Shared memory
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
];
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "io.github.faugus.Launcher";
enableSystemBus = false; # No system bus access
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.portal.FileChooser"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="org.freedesktop.portal.Settings"''
''--talk="com.feralinteractive.GameMode"''
''--own="io.github.faugus.Launcher"''
''--own="io.github.faugus.Launcher.*"''
];
};
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
"$HOME/.config/fontconfig"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.local/share/fonts"
"$HOME/.config/Kvantum"
"$HOME/.config/gtk-3.0"
"$HOME/.config/gtk-4.0"
"$HOME/.gtkrc-2.0"
"$HOME/.config/MangoHud"
];
readWrite = [
"$HOME/Games"
"$HOME/.config/faugus-launcher"
"$HOME/.local/share/faugus-launcher"
"$HOME/.cache/faugus-launcher"
"$HOME/.config/qt6ct" # Allow theming
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/io.github.faugus.Launcher/bus" "$XDG_RUNTIME_DIR/bus"''
# dconf for GTK settings
"--bind-try /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
];
};
})
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "io.github.faugus.Launcher";
enableSystemBus = false; # No system bus access
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.portal.FileChooser"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="org.freedesktop.portal.Settings"''
''--talk="com.feralinteractive.GameMode"''
''--own="io.github.faugus.Launcher"''
''--own="io.github.faugus.Launcher.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/io.github.faugus.Launcher/bus" "$XDG_RUNTIME_DIR/bus"''
# dconf for GTK settings
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
];
};
})
];
environment.systemPackages = [ pkgs.faugus-sandboxed ];
};
}

View file

@ -7,38 +7,14 @@
}:
let
cfg = config.myModules.firefoxSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
# create a custom settings.ini to force dark mode
darkSettingsIni = pkgs.writeText "settings.ini" ''
[Settings]
gtk-theme-name=catppuccin-mocha-mauve-standard
gtk-application-prefer-dark-theme=1
gtk-cursor-theme-name=Future-Cyan-Hyprcursor_Theme
gtk-xft-antialias=1
gtk-xft-hinting=1
gtk-xft-hintstyle=hintslight
gtk-xft-rgba=rgb
'';
# Define policies.json with Catppuccin Theme and P-Stream extension
firefoxPolicies = pkgs.writeText "policies.json" (
builtins.toJSON {
policies = {
ExtensionSettings = {
# Catppuccin Mocha Mauve (Official)
"catppuccin-mocha-mauve-official@catppuccin.com" = {
install_url = "https://addons.mozilla.org/firefox/downloads/latest/catppuccin-mocha-mauve-official/latest.xpi";
installation_mode = "force_installed";
};
# P-Stream extension
"{de055456-589b-45fe-8342-c685a7ffb424}" = {
install_url = "https://github.com/p-stream/extension/releases/download/1.3.5/firefox-mv3-prod.xpi";
installation_mode = "force_installed";
};
};
Preferences = {
"extensions.activeThemeID" = "catppuccin-mocha-mauve-official@catppuccin.com";
"xpinstall.signatures.required" = false;
};
};
@ -46,112 +22,112 @@ let
);
in
{
nixpkgs.overlays = [
(final: prev: {
firefox-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.firefox;
# Omit app.id to avoid document portal bind that fails on FUSE
env = {
MOZ_ENABLE_WAYLAND = "1";
LD_PRELOAD = "";
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
GTK_THEME = "catppuccin-mocha-mauve-standard";
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
HYPRCURSOR_SIZE = "32";
options.myModules.firefoxSandboxed = {
enable = lib.mkEnableOption "sandboxed Firefox with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
firefox-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.firefox-esr;
# Omit app.id to avoid document portal bind that fails on FUSE
env = {
MOZ_ENABLE_WAYLAND = "1";
LD_PRELOAD = "";
# Propagate XDG_DATA_DIRS so GTK can find themes in user profile/system
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
GTK_THEME = "catppuccin-mocha-mauve-standard";
HYPRCURSOR_THEME = "Future-Cyan-Hyprcursor_Theme";
HYPRCURSOR_SIZE = "32";
};
};
};
flatpak.enable = false;
sockets.x11 = false;
sockets.wayland = true;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
flatpak.enable = false;
sockets.x11 = false;
sockets.wayland = true;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /mnt"
"--tmpfs /run"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/booted-system /run/booted-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
# Removed: --bind "$XDG_RUNTIME_DIR/doc/by-app/..." which causes FUSE errors
"--unsetenv LD_PRELOAD"
"--setenv MOZ_ENABLE_WAYLAND \"1\""
"--setenv NOTIFY_IGNORE_PORTAL 1"
"--dir /etc"
"--dir /etc/firefox"
"--dir /etc/firefox/policies"
"--ro-bind ${firefoxPolicies} /etc/firefox/policies/policies.json"
];
fhsenv.bwrap.baseArgs = lib.mkForce (
sandboxUtils.mkCommonBindArgs { inherit config lib; }
++ sandboxUtils.mkGamingBindArgs { }
++ [
"--tmpfs /mnt"
"--ro-bind-try /run/booted-system /run/booted-system"
"--setenv MOZ_ENABLE_WAYLAND \"1\""
"--setenv NOTIFY_IGNORE_PORTAL 1"
"--dir /etc"
"--dir /etc/firefox"
"--dir /etc/firefox/policies"
"--ro-bind ${firefoxPolicies} /etc/firefox/policies/policies.json"
]
);
# Filesystem: Limited to Mozilla directories and Downloads
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.config/fontconfig"
"$HOME/.config/user-dirs.dirs"
"$HOME/.config/mimeapps.list"
"$HOME/.local/share/color-schemes"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/gtk-3.0"
];
readWrite = [
"$HOME/.mozilla"
"$HOME/.cache/mozilla"
"$HOME/Downloads"
# Filesystem: Limited to Mozilla directories and Downloads
mounts = {
read = sandboxUtils.mkGuiMounts.read ++ [
"$HOME/.config/user-dirs.dirs"
"$HOME/.config/mimeapps.list"
];
readWrite = [
"$HOME/.mozilla"
"$HOME/.cache/mozilla"
"$HOME/Downloads"
]
++ cfg.extraBindMounts;
};
# Bind mount systemd-resolved socket for DNS and required system files
# Disable built-in DBus module because it invokes bwrap without --unshare-user
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "nix.bwrapper.firefox";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.secrets"''
''--talk="org.kde.StatusNotifierWatcher"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="org.mozilla.firefox"''
''--own="org.mozilla.firefox.*"''
''--own="org.mpris.MediaPlayer2.firefox.*"''
];
enableSystemBus = true;
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.NetworkManager"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus" "$XDG_RUNTIME_DIR/bus"''
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus_system" /run/dbus/system_bus_socket''
"--bind-try /run/user/${
toString config.users.users.${config.myModules.system.mainUser}.uid
}/dconf /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}/dconf"
];
};
})
];
# Bind mount systemd-resolved socket for DNS and required system files
# Disable built-in DBus module because it invokes bwrap without --unshare-user
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "nix.bwrapper.firefox";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.secrets"''
''--talk="org.kde.StatusNotifierWatcher"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="org.mozilla.firefox"''
''--own="org.mozilla.firefox.*"''
''--own="org.mpris.MediaPlayer2.firefox.*"''
];
enableSystemBus = true;
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.NetworkManager"''
];
};
fhsenv.bwrap.additionalArgs = [
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus" "$XDG_RUNTIME_DIR/bus"''
''--bind "$XDG_RUNTIME_DIR/app/nix.bwrapper.firefox/bus_system" /run/dbus/system_bus_socket''
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--bind-try /run/user/${toString config.users.users.ashie.uid}/dconf /run/user/${toString config.users.users.ashie.uid}/dconf"
];
};
})
];
environment.systemPackages = [ pkgs.firefox-sandboxed ];
};
}

View file

@ -57,6 +57,7 @@
"Music"
"Pictures"
"Videos"
"src/aadniz-searxng"
"Torrents"
"nixos" # Config repo
".local/share/PrismLauncher" # Minecraft
@ -71,7 +72,8 @@
".config/Antigravity" # Antigravity Config
".config/modprobed-db" # Local modconfig database
".config/VSCodium" # Codium Config
".config/sops" # Sops Keys
".config/sops" # Sops keys
".config/easyeffects"
".config/gh" # Github CLI Auth
".local/share/keyrings" # Gnome Keyrings (Passwords)
".local/share/nvim" # NeoVim data (LazyVim, Mason, etc.)
@ -91,6 +93,8 @@
".local/share/umu"
".cache/mesa_shader_cache"
# ".local/share/Steam" # Symlinked to /games/Steam (Already Persistent)
".paradoxlauncher"
".local/share/Paradox Interactive"
".steam" # Steam Symlinks and logs
".config/steamtinkerlaunch" # Example of extra tools
".local/share/applications" # Desktop entries
@ -99,6 +103,11 @@
".local/share/qBittorrent"
".local/share/jellyfin-desktop"
".cache/jellyfin-desktop"
".local/share/zoxide"
".local/share/fish"
"fabric-docs-mcp"
];
files = [
];
};
};

View file

@ -69,6 +69,9 @@ in
"vsyscall=none"
"oops=panic"
"module.sig_enforce=1"
"amd_iommu=on"
"mitigations=auto"
"lockdown=confidentiality"
];
# Kernel sysctl hardening

View file

@ -9,136 +9,141 @@
}:
let
cfg = config.myModules.lutrisSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
in
{
nixpkgs.overlays = [
(final: prev: {
lutris-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.lutris.override {
extraPkgs = pkgs: [
pkgs.curl
pkgs.wget
pkgs.gnutar
pkgs.gzip
pkgs.zstd
pkgs.xz
pkgs.p7zip
pkgs.which
pkgs.file
pkgs.zenity
pkgs.vulkan-loader
pkgs.vulkan-tools
pkgs.unzip
pkgs.cabextract
pkgs.pciutils
pkgs.gamemode.lib
pkgs.xdg-utils
options.myModules.lutrisSandboxed = {
enable = lib.mkEnableOption "sandboxed Lutris with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
lutris-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.lutris.override {
extraPkgs = pkgs: [
pkgs.curl
pkgs.wget
pkgs.gnutar
pkgs.gzip
pkgs.zstd
pkgs.xz
pkgs.p7zip
pkgs.which
pkgs.file
pkgs.zenity
pkgs.vulkan-loader
pkgs.vulkan-tools
pkgs.unzip
pkgs.cabextract
pkgs.pciutils
pkgs.gamemode.lib
pkgs.xdg-utils
pkgs.umu-launcher
pkgs.sdl3
];
};
isFhsenv = true;
id = "net.lutris.Lutris";
env = {
WEBKIT_DISABLE_DMABUF_RENDERER = 1;
APPIMAGE_EXTRACT_AND_RUN = 1;
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = "python";
GTK_THEME = "catppuccin-mocha-blue-standard";
BROWSER = "xdg-open";
XDG_CURRENT_DESKTOP = "niri";
XDG_SESSION_TYPE = "wayland";
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json:/run/opengl-driver-32/share/vulkan/icd.d/radeon_icd.i686.json";
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
};
};
fhsenv = {
skipExtraInstallCmds = false;
};
# Disable Flatpak emulation
flatpak.enable = false;
# Filesystem: Limited to Games directory
mounts = {
read = sandboxUtils.mkGuiMounts.read ++ [
"$HOME/.local/share/Steam/compatibilitytools.d"
"/data/Torrents/Games" # Repack installers
];
readWrite = [
"$HOME/Games/windows"
"$HOME/Games/linux"
"$HOME/.local/share/icons"
"$HOME/.config/lutris"
"$HOME/.local/share/lutris"
"$HOME/.cache/lutris"
"$HOME/.steam"
"$HOME/.local/share/steam"
"$HOME/.local/share/umu"
"$HOME/.local/share/applications"
"$HOME/.local/share/desktop-directories"
]
++ cfg.extraBindMounts;
};
# Bind mount systemd-resolved socket directory to fix DNS
# The sandbox mounts a tmpfs on /run, so we need to validly expose this
fhsenv.bwrap.baseArgs = lib.mkForce (
sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { }
);
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus" "$XDG_RUNTIME_DIR/bus"''
# D-Bus system proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus_system" /run/dbus/system_bus_socket''
# Bind system themes to /usr/share
"--ro-bind /run/current-system/sw/share/themes /usr/share/themes"
"--ro-bind /run/current-system/sw/share/icons /usr/share/icons"
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "net.lutris.Lutris";
enableSystemBus = true;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.Flatpak"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="net.lutris.Lutris"''
];
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.UDisks2"'' # Disk detection
];
};
isFhsenv = true;
id = "net.lutris.Lutris";
env = {
WEBKIT_DISABLE_DMABUF_RENDERER = 1;
APPIMAGE_EXTRACT_AND_RUN = 1;
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION = "python";
GTK_THEME = "catppuccin-mocha-blue-standard";
BROWSER = "xdg-open";
XDG_CURRENT_DESKTOP = "niri";
XDG_SESSION_TYPE = "wayland";
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
VK_ICD_FILENAMES = "/run/opengl-driver/share/vulkan/icd.d/radeon_icd.x86_64.json:/run/opengl-driver-32/share/vulkan/icd.d/radeon_icd.i686.json";
};
};
})
];
fhsenv = {
skipExtraInstallCmds = false;
};
# Disable Flatpak emulation
flatpak.enable = false;
# Filesystem: Limited to Games directory
mounts = {
read = [
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
"$HOME/.local/share/Steam/compatibilitytools.d"
"$HOME/.config/gtk-3.0"
"$HOME/.config/gtk-4.0"
"$HOME/.icons"
"/data/Torrents/Games" # Repack installers
];
readWrite = [
"$HOME/Games/windows"
"$HOME/.local/share/icons"
"$HOME/.config/lutris"
"$HOME/.local/share/lutris"
"$HOME/.cache/lutris"
"$HOME/.steam"
"$HOME/.local/share/steam"
"$HOME/.local/share/umu"
"$HOME/.local/share/applications"
"$HOME/.local/share/desktop-directories"
];
};
# Bind mount systemd-resolved socket directory to fix DNS
# The sandbox mounts a tmpfs on /run, so we need to validly expose this
fhsenv.bwrap.additionalArgs = [
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# D-Bus session proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus" "$XDG_RUNTIME_DIR/bus"''
# D-Bus system proxy
''--bind "$XDG_RUNTIME_DIR/app/net.lutris.Lutris/bus_system" /run/dbus/system_bus_socket''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
# Hardware access
"--dev-bind /dev/dri /dev/dri"
"--dev-bind /dev/shm /dev/shm"
"--ro-bind /sys /sys"
# Bind system themes to /usr/share
"--ro-bind /run/current-system/sw/share/themes /usr/share/themes"
"--ro-bind /run/current-system/sw/share/icons /usr/share/icons"
# OpenGL/Vulkan drivers
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "net.lutris.Lutris";
enableSystemBus = true;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.Flatpak"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="net.lutris.Lutris"''
];
systemProxyArgs = [
"--filter"
''--talk="org.freedesktop.UDisks2"'' # Disk detection
];
};
};
})
];
environment.systemPackages = [ pkgs.lutris-sandboxed ];
};
}

View file

@ -6,11 +6,11 @@
}:
let
# Define the user and group consistently
user = "ashie";
cfg = config.myModules.media;
user = config.myModules.system.mainUser;
group = "users";
puid = "1000";
pgid = "100";
puid = toString config.users.users.${user}.uid;
pgid = "100"; # GID for 'users' group
# Common env vars to avoid repetition
commonEnv = {
@ -20,183 +20,202 @@ let
};
in
{
# 1. Enable Podman (required backend)
virtualisation = {
podman = {
enable = true;
autoPrune.enable = true;
};
oci-containers.backend = "podman";
options.myModules.media = {
enable = lib.mkEnableOption "media server stack (Arr suite + Jellyfin)";
};
# 2. Container Definitions
virtualisation.oci-containers.containers = {
config = lib.mkIf cfg.enable {
# 1. Enable Podman (required backend)
myModules.podman.enable = true;
virtualisation.podman.autoPrune.enable = true;
# --- VPN Gateway ---
vpn = {
image = "docker.io/qmcgaw/gluetun";
# The VPN manages the ports for the attached containers
ports = [
"8080:8080" # qBittorrent WebUI
"36630:36630" # Torrent Port TCP
"36630:36630/udp"
"9696:9696" # Prowlarr
"8191:8191" # Flaresolverr
];
environmentFiles = [ config.sops.templates."gluetun.env".path ];
environment = {
TZ = "Europe/Berlin";
DOT = "off"; # DNS over TLS off (optional)
FIREWALL_OUTBOUND_SUBNETS = "10.89.0.0/24"; # Allow access to local docker network
FIREWALL_VPN_INPUT_PORTS = "36630"; # Allow incoming torrent traffic
# 2. Container Definitions
virtualisation.oci-containers.containers = {
# --- VPN Gateway ---
vpn = {
image = "docker.io/qmcgaw/gluetun";
labels = { "io.containers.autoupdate" = "registry"; };
# The VPN manages the ports for the attached containers
ports = [
"127.0.0.1:8080:8080" # qBittorrent WebUI (Localhost only)
"36630:36630" # Torrent Port TCP (Public)
"36630:36630/udp" # Torrent Port UDP (Public)
"127.0.0.1:8191:8191" # Flaresolverr (Localhost only)
"127.0.0.1:9696:9696" # Prowlarr (Localhost only)
];
environmentFiles = [ config.sops.templates."gluetun.env".path ];
environment = {
TZ = "Europe/Berlin";
DOT = "off"; # DNS over TLS off (optional)
FIREWALL_OUTBOUND_SUBNETS = "10.89.0.0/24"; # Allow access to local docker network
FIREWALL_VPN_INPUT_PORTS = "36630"; # Allow incoming torrent traffic
};
extraOptions = [
"--cap-add=NET_ADMIN"
"--cap-add=NET_RAW"
"--device=/dev/net/tun:/dev/net/tun"
"--network=media" # It joins the bridge so others can talk to it
"--ip=10.89.0.5" # Static IP for VPN/Flaresolverr
"--network-alias=flaresolverr" # Allow other containers to reach Flaresolverr via VPN
"--add-host=sonarr:10.89.0.50" # Allow Prowlarr to reach Sonarr
"--add-host=radarr:10.89.0.51" # Allow Prowlarr to reach Radarr
"--add-host=prowlarr:127.0.0.1" # Prowlarr matches VPN IP for self-reference if needed
];
};
extraOptions = [
"--cap-add=NET_ADMIN"
"--cap-add=NET_RAW"
"--device=/dev/net/tun:/dev/net/tun"
"--network=media" # It joins the bridge so others can talk to it
"--network-alias=prowlarr" # Allow other containers to reach Prowlarr via VPN
"--network-alias=flaresolverr" # Allow other containers to reach Flaresolverr via VPN
"--add-host=sonarr:10.89.0.50" # Allow Prowlarr to reach Sonarr
"--add-host=radarr:10.89.0.51" # Allow Prowlarr to reach Radarr
];
};
# --- Torrent Client (Routed via VPN) ---
torrent = {
image = "lscr.io/linuxserver/qbittorrent:latest";
# VITAL: Reuse the VPN container's network stack
extraOptions = [ "--network=container:vpn" ];
dependsOn = [ "vpn" ];
environment = commonEnv // {
WEBUI_PORT = "8080";
# --- Torrent Client (Routed via VPN) ---
torrent = {
image = "lscr.io/linuxserver/qbittorrent:latest";
labels = { "io.containers.autoupdate" = "registry"; };
# VITAL: Reuse the VPN container's network stack
extraOptions = [ "--network=container:vpn" ];
dependsOn = [ "vpn" ];
environment = commonEnv // {
WEBUI_PORT = "8080";
};
volumes = [
"/var/lib/qbittorrent:/config"
"/data:/data"
];
};
volumes = [
"/var/lib/qbittorrent:/config"
"/data:/data"
];
};
# --- The Arr Stack ---
prowlarr = {
image = "lscr.io/linuxserver/prowlarr:latest";
extraOptions = [
"--network=container:vpn"
];
dependsOn = [ "vpn" ];
environment = commonEnv;
volumes = [ "/var/lib/nixarr/prowlarr:/config" ];
};
# --- The Arr Stack ---
prowlarr = {
image = "lscr.io/linuxserver/prowlarr:latest";
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [
"--network=container:vpn"
];
dependsOn = [ "vpn" ];
environment = commonEnv;
volumes = [ "/var/lib/nixarr/prowlarr:/config" ];
};
sonarr = {
image = "lscr.io/linuxserver/sonarr:latest";
extraOptions = [
"--network=media"
"--ip=10.89.0.50"
];
ports = [ "8989:8989" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/sonarr:/config"
"/data:/data"
];
};
sonarr = {
image = "lscr.io/linuxserver/sonarr:latest";
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [
"--network=media"
"--ip=10.89.0.50"
"--dns=8.8.8.8"
"--add-host=qbittorrent:10.89.0.5"
"--add-host=prowlarr:10.89.0.5"
];
ports = [ "127.0.0.1:8989:8989" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/sonarr:/config"
"/data:/data"
];
};
radarr = {
image = "lscr.io/linuxserver/radarr:latest";
extraOptions = [
"--network=media"
"--ip=10.89.0.51"
];
ports = [ "7878:7878" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/radarr:/config"
"/data:/data"
];
};
radarr = {
image = "lscr.io/linuxserver/radarr:latest";
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [
"--network=media"
"--ip=10.89.0.51"
"--dns=8.8.8.8"
"--add-host=qbittorrent:10.89.0.5"
"--add-host=prowlarr:10.89.0.5"
];
ports = [ "127.0.0.1:7878:7878" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/radarr:/config"
"/data:/data"
];
};
# --- Media Server ---
jellyfin = {
image = "lscr.io/linuxserver/jellyfin:latest";
extraOptions = [
"--network=media"
"--device=/dev/dri:/dev/dri"
];
ports = [ "8096:8096" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/jellyfin:/config"
"/data:/data"
];
};
# --- Media Server ---
jellyfin = {
image = "lscr.io/linuxserver/jellyfin:latest";
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [
"--network=media"
"--device=/dev/dri:/dev/dri"
"--dns=8.8.8.8"
"--ip=10.89.0.4"
];
ports = [ "127.0.0.1:8096:8096" ];
environment = commonEnv;
volumes = [
"/var/lib/nixarr/jellyfin:/config"
"/data:/data"
];
};
jellyseerr = {
image = "ghcr.io/fallenbagel/jellyseerr:latest";
extraOptions = [ "--network=media" ];
ports = [ "5055:5055" ];
environment = commonEnv;
volumes = [ "/var/lib/nixarr/jellyseerr:/app/config" ];
};
jellyseerr = {
image = "ghcr.io/seerr-team/seerr:latest"; # Migrated from jellyseerr (stale) to seerr (v3+)
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [
"--init" # Required for Seerr
"--network=media"
"--dns=8.8.8.8"
"--ip=10.89.0.3"
"--add-host=sonarr:10.89.0.50"
"--add-host=radarr:10.89.0.51"
"--add-host=jellyfin:10.89.0.4"
];
ports = [ "127.0.0.1:5055:5055" ];
environment = commonEnv;
volumes = [ "/var/lib/nixarr/jellyseerr:/app/config" ];
};
flaresolverr = {
image = "ghcr.io/flaresolverr/flaresolverr:latest";
extraOptions = [ "--network=container:vpn" ];
dependsOn = [ "vpn" ];
environment = {
TZ = "Europe/Berlin";
flaresolverr = {
image = "ghcr.io/flaresolverr/flaresolverr:latest";
labels = { "io.containers.autoupdate" = "registry"; };
extraOptions = [ "--network=container:vpn" ];
dependsOn = [ "vpn" ];
environment = {
TZ = "Europe/Berlin";
};
};
};
# 3. Network Setup (Fixed)
# Ensure the network is created before ANY container starts
systemd.services.create-media-network = {
script = ''
${pkgs.podman}/bin/podman network exists media || ${pkgs.podman}/bin/podman network create --subnet 10.89.0.0/24 media
'';
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Removed 'User = ashie' -> Networks created by root are visible to root services
};
};
# Ensure containers wait for the network
systemd.services."podman-vpn".requires = [ "create-media-network.service" ];
systemd.services."podman-vpn".after = [ "create-media-network.service" ];
# (Repeat for others if they don't depend on VPN, but usually unnecessary if they all join 'media')
# 4. Permissions
systemd.tmpfiles.rules = [
"d /data 0775 ${user} ${group} - -"
"d /var/lib/nixarr/prowlarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/sonarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/radarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/jellyfin 0755 ${user} ${group} - -"
"d /var/lib/nixarr/jellyseerr 0755 ${user} ${group} - -"
"d /var/lib/qbittorrent 0755 ${user} ${group} - -"
];
users.users.${user}.extraGroups = [ "media" ];
# 5. Firewall
networking.firewall.allowedTCPPorts = [
80
443
36630
9696
];
networking.firewall.allowedUDPPorts = [
36630
443
];
};
# 3. Network Setup (Fixed)
# Ensure the network is created before ANY container starts
systemd.services.create-media-network = {
script = ''
${pkgs.podman}/bin/podman network exists media || ${pkgs.podman}/bin/podman network create media
'';
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
# Removed 'User = ashie' -> Networks created by root are visible to root services
};
};
# Ensure containers wait for the network
systemd.services."podman-vpn".requires = [ "create-media-network.service" ];
systemd.services."podman-vpn".after = [ "create-media-network.service" ];
# (Repeat for others if they don't depend on VPN, but usually unnecessary if they all join 'media')
# 4. Permissions
systemd.tmpfiles.rules = [
"d /data 0775 ${user} media - -"
"d /var/lib/nixarr/prowlarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/sonarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/radarr 0755 ${user} ${group} - -"
"d /var/lib/nixarr/jellyfin 0755 ${user} ${group} - -"
"d /var/lib/nixarr/jellyseerr 0755 ${user} ${group} - -"
"d /var/lib/qbittorrent 0755 ${user} ${group} - -"
];
users.users.${user}.extraGroups = [ "media" ];
# 5. Firewall
networking.firewall.allowedTCPPorts = [
80
443
9696
8989
7878
8096
5055
8080
36630
8082
8191
];
networking.firewall.allowedUDPPorts = [
36630
443
];
}

View file

@ -147,6 +147,7 @@ in
];
ExecStart = ''
${pkgs.podman}/bin/podman run --rm --name ollama \
--label "io.containers.autoupdate=registry" \
--network=antigravity-net \
--network-alias=ollama \
--dns=8.8.8.8 \

View file

@ -112,6 +112,7 @@ in
];
ExecStart = ''
${pkgs.podman}/bin/podman run --rm --name open-webui \
--label "io.containers.autoupdate=registry" \
--network=antigravity-net \
--dns=8.8.8.8 \
--userns=auto \

View file

@ -8,7 +8,9 @@
}:
let
cfg = config.myModules.prismlauncherSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
# Libraries required by Minecraft natives (LWJGL), various mods,
# and the Microsoft authentication flow (NSS/NSPR).
@ -48,153 +50,137 @@ let
];
in
{
nixpkgs.overlays = [
(final: prev: {
prismlauncher-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
id = "org.prismlauncher.PrismLauncher";
package = pkgs.prismlauncher.overrideAttrs (old: {
pname = "prismlauncher";
version = old.version or "9.1";
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.mimalloc ];
options.myModules.prismlauncherSandboxed = {
enable = lib.mkEnableOption "sandboxed PrismLauncher with nix-bwrapper";
# Keep runtimeLibs in closure without injecting them into environment
postInstall = (old.postInstall or "") + ''
mkdir -p $out/share/prismlauncher-sandboxed
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
prismlauncher-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
id = "org.prismlauncher.PrismLauncher";
package = pkgs.prismlauncher.overrideAttrs (old: {
pname = "prismlauncher";
version = old.version or "9.1";
buildInputs = (old.buildInputs or [ ]) ++ [ pkgs.mimalloc ];
# Keep runtimeLibs in closure without injecting them into environment
postInstall = (old.postInstall or "") + ''
mkdir -p $out/share/prismlauncher-sandboxed
echo "${lib.makeLibraryPath runtimeLibs}" > $out/share/prismlauncher-sandboxed/libs
'';
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
"--set MIMALLOC_PATH ${pkgs.mimalloc}/lib/libmimalloc.so"
"--prefix LD_PRELOAD : ${pkgs.mimalloc}/lib/libmimalloc.so"
];
});
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
# XDG_DATA_DIRS = "$XDG_DATA_DIRS";
BROWSER = "firefox";
QT_QPA_PLATFORMTHEME = "";
QT_STYLE_OVERRIDE = "fusion";
};
};
sockets.x11 = true; # Old versions of minecraft require X11, and forge still doesnt care its breaking wayland.
sockets.wayland = true;
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
"--ro-bind /run/dbus /run/dbus"
]);
mounts = {
read = sandboxUtils.mkGuiMounts.read ++ [
"$HOME/Downloads"
];
readWrite = [
"$HOME/.local/share/PrismLauncher"
"$HOME/.cache/PrismLauncher"
] ++ cfg.extraBindMounts;
};
dbus.enable = false;
script.preCmds.stage2 =
let
jvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
glfwPath = "${pkgs.glfw}/lib/libglfw.so.3";
dbusScript = sandboxUtils.mkDbusProxyScript {
appId = "org.prismlauncher.PrismLauncher";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--own="org.prismlauncher.PrismLauncher"''
''--own="org.prismlauncher.PrismLauncher.*"''
];
};
in
''
${dbusScript}
# Force Configs (JVM Args + GLFW)
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
if [ -f "$cfg" ]; then
# JVM Args
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${jvmArgs}|" "$cfg"
else
if ${pkgs.gnugrep}/bin/grep -q "^\[General\]" "$cfg"; then
${pkgs.gnused}/bin/sed -i "/^\[General\]/a JvmArgs=${jvmArgs}" "$cfg"
else
echo "JvmArgs=${jvmArgs}" >> "$cfg"
fi
fi
# GLFW Settings
# 1. CustomGLFWPath
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
else
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
fi
# 2. UseNativeGLFW
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
else
echo "UseNativeGLFW=true" >> "$cfg"
fi
fi
'';
qtWrapperArgs = (old.qtWrapperArgs or [ ]) ++ [
"--set MIMALLOC_PATH ${pkgs.mimalloc}/lib/libmimalloc.so"
"--prefix LD_PRELOAD : ${pkgs.mimalloc}/lib/libmimalloc.so"
];
});
env = {
# Propagate XDG_DATA_DIRS so themes/icons can be found
# XDG_DATA_DIRS = "$XDG_DATA_DIRS";
BROWSER = "firefox";
QT_QPA_PLATFORMTHEME = "";
QT_STYLE_OVERRIDE = "fusion";
};
};
sockets.x11 = true; # Old versions of minecraft require X11, and forge still doesnt care its breaking wayland.
sockets.wayland = true;
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# Bind ro system paths commonly needed
# "--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--ro-bind /run/dbus /run/dbus"
];
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/qt6ct"
"$HOME/.config/Kvantum"
"$HOME/.config/MangoHud"
"$HOME/Downloads"
];
readWrite = [
"$HOME/.local/share/PrismLauncher"
"$HOME/.cache/PrismLauncher"
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus proxy
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
];
};
})
];
dbus.enable = false;
script.preCmds.stage2 =
let
jvmArgs = "-XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+AlwaysActAsServerClassMachine -XX:+AlwaysPreTouch -XX:+DisableExplicitGC -XX:+UseNUMA -XX:NmethodSweepActivity=1 -XX:ReservedCodeCacheSize=400M -XX:NonNMethodCodeHeapSize=12M -XX:ProfiledCodeHeapSize=194M -XX:NonProfiledCodeHeapSize=194M -XX:-DontCompileHugeMethods -XX:MaxNodeLimit=240000 -XX:NodeLimitFudgeFactor=8000 -XX:+UseVectorCmov -XX:+PerfDisableSharedMem -XX:+UseFastUnorderedTimeStamps -XX:+UseCriticalJavaThreadPriority -XX:ThreadPriorityPolicy=1 -XX:AllocatePrefetchStyle=3 -XX:+UseShenandoahGC -XX:ShenandoahGCMode=iu -XX:ShenandoahGuaranteedGCInterval=1000000 -XX:AllocatePrefetchStyle=1 -XX:ConcGCThreads=4";
glfwPath = "${pkgs.glfw}/lib/libglfw.so.3";
dbusScript = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "org.prismlauncher.PrismLauncher";
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--own="org.prismlauncher.PrismLauncher"''
''--own="org.prismlauncher.PrismLauncher.*"''
];
};
in
''
${dbusScript}
# Force Configs (JVM Args + GLFW)
cfg="$HOME/.local/share/PrismLauncher/prismlauncher.cfg"
if [ -f "$cfg" ]; then
# JVM Args
if ${pkgs.gnugrep}/bin/grep -q "^JvmArgs=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^JvmArgs=.*|JvmArgs=${jvmArgs}|" "$cfg"
else
if ${pkgs.gnugrep}/bin/grep -q "^\[General\]" "$cfg"; then
${pkgs.gnused}/bin/sed -i "/^\[General\]/a JvmArgs=${jvmArgs}" "$cfg"
else
echo "JvmArgs=${jvmArgs}" >> "$cfg"
fi
fi
# GLFW Settings
# 1. CustomGLFWPath
if ${pkgs.gnugrep}/bin/grep -q "^CustomGLFWPath=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^CustomGLFWPath=.*|CustomGLFWPath=${glfwPath}|" "$cfg"
else
echo "CustomGLFWPath=${glfwPath}" >> "$cfg"
fi
# 2. UseNativeGLFW
if ${pkgs.gnugrep}/bin/grep -q "^UseNativeGLFW=" "$cfg"; then
${pkgs.gnused}/bin/sed -i "s|^UseNativeGLFW=.*|UseNativeGLFW=true|" "$cfg"
else
echo "UseNativeGLFW=true" >> "$cfg"
fi
fi
'';
fhsenv.bwrap.additionalArgs = [
# D-Bus proxy
''--bind "$XDG_RUNTIME_DIR/app/org.prismlauncher.PrismLauncher/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse (PipeWire hosts both)
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
};
})
];
environment.systemPackages = [ pkgs.prismlauncher-sandboxed ];
};
}

View file

@ -16,6 +16,8 @@
let
cfg = config.myModules.redlib;
mainUser = config.myModules.system.mainUser;
mainUserUid = toString config.users.users.${mainUser}.uid;
in
{
options.myModules.redlib = {
@ -34,6 +36,7 @@ in
# Redlib Container
virtualisation.oci-containers.containers."redlib" = {
image = "quay.io/redlib/redlib:latest";
labels = { "io.containers.autoupdate" = "registry"; };
# ports = [ "127.0.0.1:${toString cfg.port}:8080" ]; # Port exposed via VPN
extraOptions = [
"--pull=always"
@ -44,20 +47,20 @@ in
};
# Rootless Overrides
systemd.services."podman-redlib".serviceConfig.User = lib.mkForce "ashie";
systemd.services."podman-redlib".serviceConfig.User = lib.mkForce mainUser;
systemd.services."podman-redlib".environment = {
HOME = "/home/ashie";
XDG_RUNTIME_DIR = "/run/user/1000";
HOME = "/home/${mainUser}";
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
};
systemd.services."podman-redlib".serviceConfig.Type = lib.mkForce "simple";
systemd.services."podman-redlib".serviceConfig.Delegate = true;
systemd.services."podman-redlib".after = [
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"podman-vpn.service"
];
systemd.services."podman-redlib".requires = [
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"podman-vpn.service"
];
};
}
}

View file

@ -7,122 +7,114 @@
}:
let
cfg = config.myModules.ryubingSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
appId = "org.ryubing.Ryubing";
in
{
nixpkgs.overlays = [
(final: prev: {
ryubing-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = pkgs.ryubing;
id = appId;
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Ryubing uses Avalonia which works better with X11
AVALONIA_SCREEN_SCALE_FACTOR = "1";
options.myModules.ryubingSandboxed = {
enable = lib.mkEnableOption "sandboxed Ryubing with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
ryubing-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = pkgs.ryubing;
id = appId;
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Ryubing uses Avalonia which works better with X11
AVALONIA_SCREEN_SCALE_FACTOR = "1";
};
};
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable Flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for online features
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
"--tmpfs /usr/share"
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
"--ro-bind-try /nix/store /nix/store"
]);
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
# Also create required directories before bwrap runs
script.preCmds.stage2 = ''
# Create directories that bwrap will bind
# Note: Ryubing still uses Ryujinx config paths
mkdir -p "$HOME/.config/Ryujinx/system"
mkdir -p "$HOME/.config/Ryujinx/bis/system/Contents/registered"
mkdir -p "$HOME/.local/share/Ryujinx"
mkdir -p "$HOME/Games/Switch"
''
+ sandboxUtils.mkDbusProxyScript {
inherit appId;
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--own="${appId}"''
''--own="${appId}.*"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
# Read-write mounts
"--bind $HOME/Games/Switch $HOME/Games/Switch"
"--bind $HOME/.config/Ryujinx $HOME/.config/Ryujinx"
"--bind $HOME/.local/share/Ryujinx $HOME/.local/share/Ryujinx"
];
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = cfg.extraBindMounts;
};
};
})
];
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable Flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for online features
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--dev-bind /dev/shm /dev/shm" # Shared memory
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
"--dev-bind-try /dev/input /dev/input"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# Fix for amdgpu.ids missing - use tmpfs so mkdir can succeed
"--tmpfs /usr/share"
"--ro-bind ${pkgs.libdrm}/share/libdrm /usr/share/libdrm"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--ro-bind-try /nix/store /nix/store"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# udev for controller hotplug
"--ro-bind-try /run/udev /run/udev"
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
# Also create required directories before bwrap runs
script.preCmds.stage2 = ''
# Create directories that bwrap will bind
# Note: Ryubing still uses Ryujinx config paths
mkdir -p "$HOME/.config/Ryujinx/system"
mkdir -p "$HOME/.config/Ryujinx/bis/system/Contents/registered"
mkdir -p "$HOME/.local/share/Ryujinx"
mkdir -p "$HOME/Games/Switch"
''
+ (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
inherit appId;
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.Desktop"''
''--talk="org.freedesktop.portal.OpenURI"''
''--talk="org.freedesktop.portal.FileChooser"''
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--own="${appId}"''
''--own="${appId}.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
# Manual mounts for data persistence
"--ro-bind-try $HOME/.config/kdedefaults $HOME/.config/kdedefaults"
"--ro-bind-try $HOME/.local/share/color-schemes $HOME/.local/share/color-schemes"
"--ro-bind-try $HOME/.config/fontconfig $HOME/.config/fontconfig"
"--ro-bind-try $HOME/.local/share/fonts $HOME/.local/share/fonts"
"--ro-bind-try $HOME/.icons $HOME/.icons"
"--ro-bind-try $HOME/.themes $HOME/.themes"
"--ro-bind-try $HOME/.config/MangoHud $HOME/.config/MangoHud"
# Read-write mounts
"--bind $HOME/Games/Switch $HOME/Games/Switch"
"--bind $HOME/.config/Ryujinx $HOME/.config/Ryujinx"
"--bind $HOME/.local/share/Ryujinx $HOME/.local/share/Ryujinx"
];
};
})
];
environment.systemPackages = [ pkgs.ryubing-sandboxed ];
};
}

View file

@ -1,91 +1,311 @@
{ pkgs, lib }:
{
let
# Generates the shell script content to set up xdg-dbus-proxy inside a bwrap user namespace.
# This is used for sandboxed apps that run with unshareUser = true.
mkDbusProxyScript = {
appId, # Unique ID for the app (e.g. "org.mozilla.firefox")
proxyArgs, # Arguments for xdg-dbus-proxy (session bus). Can be string or list.
socketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus",
upstreamSocket ? "$XDG_RUNTIME_DIR/bus",
enableSystemBus ? false,
systemProxyArgs ? "", # Arguments for xdg-dbus-proxy (system bus). Can be string or list.
systemSocketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus_system",
systemUpstreamSocket ? "/run/dbus/system_bus_socket"
}:
let
bwrap = "${pkgs.bubblewrap}/bin/bwrap";
dbusProxy = "${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy";
coreutils = "${pkgs.coreutils}/bin";
# Helper to normalize args (support list or string)
normalizeArgs = args: if builtins.isList args then lib.concatStringsSep " " args else args;
pArgs = normalizeArgs proxyArgs;
sArgs = normalizeArgs systemProxyArgs;
mkDbusProxyScript =
{
appId,
# Unique ID for the app (e.g. "org.mozilla.firefox")
proxyArgs, # Arguments for xdg-dbus-proxy (session bus). Can be string or list.
socketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus",
upstreamSocket ? "$XDG_RUNTIME_DIR/bus",
enableSystemBus ? false,
systemProxyArgs ? "", # Arguments for xdg-dbus-proxy (system bus). Can be string or list.
systemSocketPath ? "$XDG_RUNTIME_DIR/app/${appId}/bus_system",
systemUpstreamSocket ? "/run/dbus/system_bus_socket",
}:
let
bwrap = "${pkgs.bubblewrap}/bin/bwrap";
dbusProxy = "${pkgs.xdg-dbus-proxy}/bin/xdg-dbus-proxy";
coreutils = "${pkgs.coreutils}/bin";
# Helper to generate the function definition
# We bind XDG_RUNTIME_DIR to allow creating the socket.
# We optionally bind /run/dbus for the system bus socket.
mkProxyFunc = name: upstream: sock: args: bindSystem: ''
${name}() {
${coreutils}/mkdir -p "$(${coreutils}/dirname "${sock}")"
${bwrap} \
--unshare-user \
--dev /dev \
--proc /proc \
--new-session \
--ro-bind /nix/store /nix/store \
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
${if bindSystem then "--ro-bind /run/dbus /run/dbus" else ""} \
--die-with-parent \
--clearenv \
-- \
${dbusProxy} "unix:path=${upstream}" "${sock}" ${args}
# Helper to normalize args (support list or string)
normalizeArgs = args: if builtins.isList args then lib.concatStringsSep " " args else args;
pArgs = normalizeArgs proxyArgs;
sArgs = normalizeArgs systemProxyArgs;
# Helper to generate the function definition
# We bind XDG_RUNTIME_DIR to allow creating the socket.
# We optionally bind /run/dbus for the system bus socket.
mkProxyFunc = name: upstream: sock: args: bindSystem: ''
${name}() {
${coreutils}/mkdir -p "$(${coreutils}/dirname "${sock}")"
${bwrap} \
--unshare-user \
--dev /dev \
--proc /proc \
--new-session \
--ro-bind /nix/store /nix/store \
--bind "$XDG_RUNTIME_DIR" "$XDG_RUNTIME_DIR" \
${if bindSystem then "--ro-bind /run/dbus /run/dbus" else ""} \
--die-with-parent \
--clearenv \
-- \
${dbusProxy} "unix:path=${upstream}" "${sock}" ${args}
}
'';
sessionFunc = mkProxyFunc "set_up_dbus_proxy" upstreamSocket socketPath pArgs false;
systemFunc =
if enableSystemBus then
mkProxyFunc "set_up_system_dbus_proxy" systemUpstreamSocket systemSocketPath sArgs true
else
"";
waitLoop = ''
# Wait for socket(s) with fail-fast check
for i in $(${coreutils}/seq 1 50);
do
# Check if processes are still running
if ! kill -0 "$PID_SESSION" 2>/dev/null;
then
echo "Error: Session D-Bus proxy (PID $PID_SESSION) died unexpectedly." >&2
exit 1
fi
${
if enableSystemBus then
''
if ! kill -0 "$PID_SYSTEM" 2>/dev/null;
then
echo "Error: System D-Bus proxy (PID $PID_SYSTEM) died unexpectedly." >&2
exit 1
fi
''
else
""
}
# Check for sockets
if [ -S "${socketPath}" ]${if enableSystemBus then " && [ -S \"${systemSocketPath}\" ]" else ""};
then
break
fi
${coreutils}/sleep 0.02
done
'';
in
''
${sessionFunc}
${systemFunc}
set_up_dbus_proxy &
PID_SESSION=$!
${
if enableSystemBus then
''
set_up_system_dbus_proxy &
PID_SYSTEM=$!
''
else
""
}
${waitLoop}
'';
sessionFunc = mkProxyFunc "set_up_dbus_proxy" upstreamSocket socketPath pArgs false;
systemFunc = if enableSystemBus
then mkProxyFunc "set_up_system_dbus_proxy" systemUpstreamSocket systemSocketPath sArgs true
else "";
waitLoop = ''
# Wait for socket(s) with fail-fast check
for i in $(${coreutils}/seq 1 50);
do
# Check if processes are still running
if ! kill -0 "$PID_SESSION" 2>/dev/null;
then
echo "Error: Session D-Bus proxy (PID $PID_SESSION) died unexpectedly." >&2
exit 1
fi
${if enableSystemBus then ''
if ! kill -0 "$PID_SYSTEM" 2>/dev/null;
then
echo "Error: System D-Bus proxy (PID $PID_SYSTEM) died unexpectedly." >&2
exit 1
fi
'' else ""}
# Standard Common Binds (System Essentials)
mkCommonBindArgs =
{ config, lib }:
[
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind-try /dev/ntsync /dev/ntsync"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.${config.myModules.system.mainUser}.uid}"
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--unsetenv LD_PRELOAD"
];
# Check for sockets
if [ -S "${socketPath}" ]${if enableSystemBus then " && [ -S \"${systemSocketPath}\" ]" else ""};
then
break
fi
${coreutils}/sleep 0.02
done
'';
# GUI Application Binds (Fonts, Themes, Wayland/X11 sockets)
mkGuiBindArgs =
{ }:
[
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
in ''
${sessionFunc}
${systemFunc}
# GUI Mounts (Fonts, Configs)
mkGuiMounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/qt6ct"
"$HOME/.config/Kvantum"
"$HOME/.config/MangoHud"
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
"$HOME/.config/gtk-3.0"
"$HOME/.config/gtk-4.0"
];
};
set_up_dbus_proxy &
PID_SESSION=$!
${if enableSystemBus then ''
set_up_system_dbus_proxy &
PID_SYSTEM=$!
'' else ""}
${waitLoop}
'';
}
# Gaming Binds (GPU, Controllers, Input)
mkGamingBindArgs =
{ }:
[
"--dev-bind /dev/dri /dev/dri" # GPU
"--dev-bind /dev/shm /dev/shm" # Shared Mem
"--dev-bind-try /dev/uinput /dev/uinput"
"--dev-bind-try /dev/input /dev/input"
"--dev-bind-try /dev/hidraw0 /dev/hidraw0"
"--dev-bind-try /dev/hidraw1 /dev/hidraw1"
"--dev-bind-try /dev/hidraw2 /dev/hidraw2"
"--dev-bind-try /dev/hidraw3 /dev/hidraw3"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--ro-bind-try /run/udev /run/udev"
];
# Helper to create a sandboxed application module
mkSandboxedApp =
{
config,
lib,
pkgs,
inputs,
optionName, # e.g. "steamSandboxed"
packageName, # e.g. "steam-sandboxed"
description,
package, # e.g. pkgs.steam
appId, # e.g. "com.valvesoftware.Steam"
isFhsenv ? false,
env ? { },
sockets ? {
x11 = true;
wayland = true;
},
flatpak ? false,
# Mounts
mounts ? {
read = [ ];
readWrite = [ ];
},
# Bwrap/Fhsenv options
fhsenvOpts ? {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
},
fhsenvExtra ? { }, # merged into fhsenv
# Args
baseArgs ? (mkCommonBindArgs { inherit config lib; }),
additionalArgs ? [ ], # merged into fhsenv.bwrap.additionalArgs
# DBus
dbusProxy ? null, # { rules ? [], systemRules ? [], enableSystemBus ? false }
}:
let
cfg = config.myModules.${optionName};
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
# Handle DBus Proxy Logic
hasDbusProxy = dbusProxy != null;
proxyScript =
if hasDbusProxy then
mkDbusProxyScript {
inherit appId;
enableSystemBus = dbusProxy.enableSystemBus or false;
proxyArgs = dbusProxy.rules or [ ];
systemProxyArgs = dbusProxy.systemRules or [ ];
}
else
"";
dbusBindArgs =
if hasDbusProxy then
[
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus" "$XDG_RUNTIME_DIR/bus"''
]
++ (
if (dbusProxy.enableSystemBus or false) then
[
''--bind "$XDG_RUNTIME_DIR/app/${appId}/bus_system" /run/dbus/system_bus_socket''
]
else
[ ]
)
else
[ ];
in
{
options.myModules.${optionName} = {
enable = lib.mkEnableOption description;
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
${packageName} = bwrapperPkgs.mkBwrapper {
app = {
package = package;
inherit isFhsenv;
env = env;
id = appId;
};
inherit sockets;
flatpak.enable = flatpak;
fhsenv = fhsenvExtra // {
opts = fhsenvOpts;
bwrap = {
baseArgs = lib.mkForce baseArgs;
additionalArgs = mkGuiBindArgs { } ++ additionalArgs ++ dbusBindArgs;
};
};
mounts = {
read = mkGuiMounts.read ++ mounts.read;
readWrite = mounts.readWrite ++ cfg.extraBindMounts;
};
dbus.enable = false;
script.preCmds.stage2 = proxyScript;
};
})
];
environment.systemPackages = [ pkgs.${packageName} ];
};
};
in
{
inherit
mkDbusProxyScript
mkCommonBindArgs
mkGuiBindArgs
mkGuiMounts
mkGamingBindArgs
mkSandboxedApp
;
}

View file

@ -17,189 +17,8 @@
let
cfg = config.myModules.searxng;
catppuccinCss = pkgs.writeText "searxng-catppuccin.css" ''
:root {
/* Mocha (Dark) */
--cat-rosewater: #f5e0dc;
--cat-flamingo: #f2cdcd;
--cat-pink: #f5c2e7;
--cat-mauve: #cba6f7;
--cat-red: #f38ba8;
--cat-maroon: #eba0ac;
--cat-peach: #fab387;
--cat-yellow: #f9e2af;
--cat-green: #a6e3a1;
--cat-teal: #94e2d5;
--cat-sky: #89dceb;
--cat-sapphire: #74c7ec;
--cat-blue: #89b4fa;
--cat-lavender: #b4befe;
--cat-text: #cdd6f4;
--cat-subtext1: #bac2de;
--cat-subtext0: #a6adc8;
--cat-overlay2: #9399b2;
--cat-overlay1: #7f849c;
--cat-overlay0: #6c7086;
--cat-surface2: #585b70;
--cat-surface1: #45475a;
--cat-surface0: #313244;
--cat-base: #1e1e2e;
--cat-mantle: #181825;
--cat-crust: #11111b;
}
@media (prefers-color-scheme: light) {
:root {
/* Latte (Light) */
--cat-rosewater: #dc8a78;
--cat-flamingo: #dd7878;
--cat-pink: #ea76cb;
--cat-mauve: #8839ef;
--cat-red: #d20f39;
--cat-maroon: #e64553;
--cat-peach: #fe640b;
--cat-yellow: #df8e1d;
--cat-green: #40a02b;
--cat-teal: #179287;
--cat-sky: #04a5e5;
--cat-sapphire: #209fb5;
--cat-blue: #1e66f5;
--cat-lavender: #7287fd;
--cat-text: #4c4f69;
--cat-subtext1: #5c5f77;
--cat-subtext0: #6c6f85;
--cat-overlay2: #7c7f93;
--cat-overlay1: #8c8fa1;
--cat-overlay0: #9ca0b0;
--cat-surface2: #acb0be;
--cat-surface1: #bcc0cc;
--cat-surface0: #ccd0da;
--cat-base: #eff1f5;
--cat-mantle: #e6e9ef;
--cat-crust: #dce0e8;
}
}
/* Apply variables */
:root {
--color-base-font: var(--cat-text);
--color-base-background: var(--cat-base);
--color-base-background-mobile: var(--cat-base);
--color-url-font: var(--cat-mauve);
--color-url-visited-font: var(--cat-mauve);
--color-header-background: var(--cat-mantle);
--color-header-border: var(--cat-mantle);
--color-footer-background: var(--cat-mantle);
--color-footer-border: var(--cat-mantle);
--color-sidebar-border: var(--cat-base);
--color-sidebar-font: var(--cat-text);
--color-sidebar-background: var(--cat-base);
--color-backtotop-font: var(--cat-subtext1);
--color-backtotop-border: var(--cat-surface0);
--color-backtotop-background: var(--cat-surface0);
--color-btn-background: var(--cat-mauve);
--color-btn-font: var(--cat-base);
--color-show-btn-background: var(--cat-mauve);
--color-show-btn-font: var(--cat-base);
--color-search-border: var(--cat-surface0);
--color-search-shadow: 0 2px 8px var(--cat-crust);
--color-search-background: var(--cat-surface0);
--color-search-font: var(--cat-text);
--color-search-background-hover: var(--cat-mauve);
--color-error: var(--cat-red);
--color-error-background: var(--cat-surface0);
--color-warning: var(--cat-yellow);
--color-warning-background: var(--cat-surface0);
--color-success: var(--cat-green);
--color-success-background: var(--cat-surface0);
--color-categories-item-selected-font: var(--cat-text);
--color-categories-item-border-selected: var(--cat-mauve);
--color-autocomplete-font: var(--cat-subtext1);
--color-autocomplete-border: var(--cat-surface0);
--color-autocomplete-shadow: 0 2px 8px var(--cat-crust);
--color-autocomplete-background: var(--cat-surface0);
--color-autocomplete-background-hover: var(--cat-surface1);
--color-answer-font: var(--cat-text);
--color-answer-background: var(--cat-mantle);
--color-result-background: var(--cat-mantle);
--color-result-border: var(--cat-base);
--color-result-url-font: var(--cat-subtext1);
--color-result-vim-selected: var(--cat-surface0);
--color-result-vim-arrow: var(--cat-mauve);
--color-result-description-highlight-font: var(--cat-text);
--color-result-link-font: var(--cat-mauve);
--color-result-link-font-highlight: var(--cat-mauve);
--color-result-link-visited-font: var(--cat-mauve);
--color-result-publishdate-font: var(--cat-surface2);
--color-result-engines-font: var(--cat-surface2);
--color-result-search-url-border: var(--cat-surface2);
--color-result-search-url-font: var(--cat-text);
--color-result-detail-font: var(--cat-text);
--color-result-detail-label-font: var(--cat-subtext0);
--color-result-detail-background: var(--cat-base);
--color-result-detail-hr: var(--cat-base);
--color-result-detail-link: var(--cat-mauve);
--color-result-detail-loader-border: rgba(255, 255, 255, 0.2);
--color-result-detail-loader-borderleft: var(--cat-crust);
--color-result-image-span-font: var(--cat-text);
--color-result-image-span-font-selected: var(--cat-base);
--color-result-image-background: var(--cat-mantle);
--color-settings-tr-hover: var(--cat-surface0);
--color-settings-engine-description-font: var(--cat-text);
--color-settings-engine-group-background: var(--cat-surface0);
--color-toolkit-badge-font: var(--cat-text);
--color-toolkit-badge-background: var(--cat-surface0);
--color-toolkit-kbd-font: var(--cat-text);
--color-toolkit-kbd-background: var(--cat-mantle);
--color-toolkit-dialog-border: var(--cat-mantle);
--color-toolkit-dialog-background: var(--cat-mantle);
--color-toolkit-tabs-label-border: var(--cat-base);
--color-toolkit-tabs-section-border: var(--cat-base);
--color-toolkit-select-background: var(--cat-surface0);
--color-toolkit-select-border: var(--cat-surface0);
--color-toolkit-select-background-hover: var(--cat-surface1);
--color-toolkit-input-text-font: var(--cat-text);
--color-toolkit-checkbox-onoff-off-background: var(--cat-surface0);
--color-toolkit-checkbox-onoff-on-background: var(--cat-surface0);
--color-toolkit-checkbox-onoff-on-mark-background: var(--cat-green);
--color-toolkit-checkbox-onoff-on-mark-color: var(--cat-mantle);
--color-toolkit-checkbox-onoff-off-mark-background: var(--cat-red);
--color-toolkit-checkbox-onoff-off-mark-color: var(--cat-mantle);
--color-toolkit-checkbox-label-background: var(--cat-base);
--color-toolkit-checkbox-label-border: var(--cat-mantle);
--color-toolkit-checkbox-input-border: var(--cat-mauve);
--color-toolkit-engine-tooltip-border: var(--cat-surface0);
--color-toolkit-engine-tooltip-background: var(--cat-surface0);
--color-toolkit-loader-border: rgba(255, 255, 255, 0.2);
--color-toolkit-loader-borderleft: var(--cat-crust);
--color-doc-code: var(--cat-rosewater);
--color-doc-code-background: var(--cat-mantle);
}
#search_logo svg :not([fill="none"]) {
fill: var(--cat-mauve) !important;
}
#search_logo svg :not([stroke="none"]) {
stroke: var(--cat-mauve) !important;
}
/* Additional cute tweaks */
article.result {
background-color: var(--color-result-background);
border-radius: 0.75em;
padding: 0.75em;
margin: 0.5em;
border: 1px solid var(--cat-surface0);
}
article.category-images {
padding-bottom: 4em;
}
input[type="text"] {
border-radius: 2em !important;
}
'';
mainUser = config.myModules.system.mainUser;
mainUserUid = toString config.users.users.${mainUser}.uid;
anubisPolicy = pkgs.writeText "anubis-policy.yml" ''
bots:
- name: "Allow OpenSearch"
@ -217,6 +36,10 @@ let
[favicons.cache]
db_url = "/var/cache/searxng/faviconcache.db"
LIMIT_TOTAL_BYTES = 2147483648
[favicons.proxy.resolver_map]
google = "searx.favicons.resolver.google_resolver"
duckduckgo = "searx.favicons.resolver.duckduckgo_resolver"
'';
in
{
@ -251,25 +74,32 @@ in
# 1. Create Bridge Network
systemd.services."create-searxng-network" = {
serviceConfig.Type = "oneshot";
serviceConfig.User = "ashie";
serviceConfig.User = mainUser;
serviceConfig.RemainAfterExit = true;
after = [ "user-runtime-dir@1000.service" ];
requires = [ "user-runtime-dir@1000.service" ];
after = [ "user-runtime-dir@${mainUserUid}.service" ];
requires = [ "user-runtime-dir@${mainUserUid}.service" ];
path = [
pkgs.podman
pkgs.shadow
];
script = ''
export PATH=/run/wrappers/bin:$PATH
export XDG_RUNTIME_DIR="/run/user/1000"
export HOME="/home/ashie"
podman network create searxng-net --subnet 10.89.2.0/24 --ignore
export XDG_RUNTIME_DIR="/run/user/${mainUserUid}"
export HOME="/home/${mainUser}"
if ! podman network exists searxng-net; then
echo "Creating searxng-net..."
podman network create searxng-net --subnet 10.89.2.0/24
else
echo "searxng-net already exists."
fi
'';
};
# 2. Valkey Container (Cache/Limiter)
virtualisation.oci-containers.containers."searxng-valkey" = {
image = "docker.io/valkey/valkey:alpine";
labels = { "io.containers.autoupdate" = "registry"; };
cmd = [
"valkey-server"
"--save"
@ -286,12 +116,12 @@ in
# 3. SearXNG Container
virtualisation.oci-containers.containers."searxng" = {
image = "ghcr.io/privau/searxng:latest";
# ports = [ "127.0.0.1:${toString cfg.port}:8080" ]; # Port moved to Anubis
image = "localhost/aadniz/searxng:latest";
environment = {
"SEARXNG_BASE_URL" = "https://${cfg.domain}";
"SEARXNG_REDIS_URL" = "valkey://valkey:6379"; # Talk to Valkey via alias
"SEARXNG_URL_BASE" = "https://${cfg.domain}";
"GRANIAN_HOST" = "0.0.0.0";
};
environmentFiles = [
# Contains SEARXNG_SECRET_KEY
@ -308,8 +138,9 @@ in
];
volumes = [
"${config.sops.templates."searxng_settings.yml".path}:/etc/searxng/settings.yml:ro"
"${catppuccinCss}:/etc/searxng/custom.css:ro"
"${faviconsConfig}:/etc/searxng/favicons.toml:ro"
"${./braveapi.py}:/usr/local/searxng/searx/engines/braveapi.py:ro"
"searxng-cache:/var/cache/searxng"
];
dependsOn = [ "searxng-valkey" ];
@ -318,6 +149,7 @@ in
# 4. Anubis Container (AI Firewall)
virtualisation.oci-containers.containers."searxng-anubis" = {
image = "ghcr.io/techarohq/anubis:latest";
labels = { "io.containers.autoupdate" = "registry"; };
ports = [ "127.0.0.1:${toString cfg.port}:8080" ];
environment = {
"TARGET" = "http://searxng:8080";
@ -326,6 +158,7 @@ in
};
extraOptions = [
"--network=searxng-net"
"--network-alias=searxng-anubis"
];
volumes = [
"${anubisPolicy}:/etc/anubis/policy.yml:ro"
@ -333,32 +166,24 @@ in
dependsOn = [ "searxng" ];
};
# 5. Permanent NAT Fix for SearXNG Network
networking.nftables.tables.searxng-nat = {
family = "inet";
content = ''
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 10.89.2.0/24 masquerade
}
'';
};
sops.templates."searxng.env" = {
owner = "ashie";
owner = mainUser;
content = ''
SEARXNG_SECRET_KEY=${config.sops.placeholder.searxng_secret_key}
BRAVE_API_KEY=${config.sops.placeholder.searxng_brave_api_key}
'';
};
sops.templates."searxng_settings.yml" = {
owner = "ashie";
owner = mainUser;
content = ''
use_default_settings: true
general:
debug: false
instance_name: "Ashie Search"
contact_url: false
issue_url: false
donation_url: ${if cfg.donations ? "Monero" then "\"${cfg.donations.Monero}\"" else "false"}
donations:
${lib.concatStringsSep "\n " (
@ -366,15 +191,20 @@ in
)}
engines:
- name: brave
engine: brave
api_key: "${config.sops.placeholder.searxng_brave_api_key}"
- name: braveapi
engine: braveapi
shortcut: brapi
categories: general
# api_key: set via BRAVE_API_KEY env var
tokens: ["${config.sops.placeholder.searxng_private_token}"]
timeout: 2.0
weight: 2
disabled: false
search:
safe_search: 0
favicon_resolver: "duckduckgo"
favicon_resolver: "google"
autocomplete: "google"
default_lang: "en-US"
formats:
@ -387,17 +217,15 @@ in
secret_key: "${config.sops.placeholder.searxng_secret_key}"
limiter: true
image_proxy: true
public_instance: true
default_http_headers:
Content-Security-Policy: "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'sha256-/ldGxQqxNIMRftg3AGsPF+F281wiBPECUDcL2RJkxdU='; form-action 'self' https://github.com/searxng/searxng/issues/new; font-src 'self'; frame-ancestors 'self'; img-src 'self' data:; connect-src 'self' https://overpass-api.de; manifest-src 'self'"
ui:
default_theme: simple
default_theme_style: kagi
default_theme: red-floof
default_theme_style: dark
static_use_hash: true
# custom_css: custom.css
# theme_args:
# simple_style: kagi
hostname_replace:
'(^|.*\.)reddit\.com$': 'reddit.ashisgreat.xyz'
redis:
url: valkey://valkey:6379/0
@ -410,58 +238,59 @@ in
sops.secrets.searxng_private_token = { };
# Rootless Overrides
systemd.services."podman-searxng".serviceConfig.User = lib.mkForce "ashie";
systemd.services."podman-searxng".serviceConfig.User = lib.mkForce mainUser;
systemd.services."podman-searxng".environment = {
HOME = "/home/ashie";
XDG_RUNTIME_DIR = "/run/user/1000";
HOME = "/home/${mainUser}";
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
};
systemd.services."podman-searxng".serviceConfig.Type = lib.mkForce "simple";
systemd.services."podman-searxng".serviceConfig.Delegate = true;
systemd.services."podman-searxng".after = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
systemd.services."podman-searxng".requires = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
systemd.services."podman-searxng-valkey".serviceConfig.User = lib.mkForce "ashie";
systemd.services."podman-searxng-valkey".serviceConfig.User = lib.mkForce mainUser;
systemd.services."podman-searxng-valkey".environment = {
HOME = "/home/ashie";
XDG_RUNTIME_DIR = "/run/user/1000";
HOME = "/home/${mainUser}";
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
};
systemd.services."podman-searxng-valkey".serviceConfig.Type = lib.mkForce "simple";
systemd.services."podman-searxng-valkey".serviceConfig.Delegate = true;
systemd.services."podman-searxng-valkey".after = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
systemd.services."podman-searxng-valkey".requires = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
systemd.services."podman-searxng-anubis".serviceConfig.User = lib.mkForce "ashie";
systemd.services."podman-searxng-anubis".serviceConfig.User = lib.mkForce mainUser;
systemd.services."podman-searxng-anubis".environment = {
HOME = "/home/ashie";
XDG_RUNTIME_DIR = "/run/user/1000";
HOME = "/home/${mainUser}";
XDG_RUNTIME_DIR = "/run/user/${mainUserUid}";
};
systemd.services."podman-searxng-anubis".serviceConfig.Type = lib.mkForce "simple";
systemd.services."podman-searxng-anubis".serviceConfig.Delegate = true;
systemd.services."podman-searxng-anubis".after = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
systemd.services."podman-searxng-anubis".requires = [
"create-searxng-network.service"
"user-runtime-dir@1000.service"
"user-runtime-dir@${mainUserUid}.service"
"network-online.target"
];
};
}

View file

@ -8,111 +8,94 @@
}:
let
cfg = config.myModules.spotifySandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
in
{
nixpkgs.overlays = [
(final: prev: {
spotify-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.spotify;
id = "com.spotify.Client";
env = {
# Propagate XDG_DATA_DIRS for theming
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Force Wayland if preferred, or rely on auto-detection
# DISPLAY variable is handled by sockets.x11/wayland
options.myModules.spotifySandboxed = {
enable = lib.mkEnableOption "sandboxed Spotify with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
spotify-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.spotify;
id = "com.spotify.Client";
env = {
# Propagate XDG_DATA_DIRS for theming
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
};
};
};
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Spotify is not a flatpak ref, so disable flatpak emulation
flatpak.enable = false;
# Spotify is not a flatpak ref, so disable flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for streaming
unshareIpc = false;
};
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for streaming
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# Audio
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
];
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { } ++ [
# Audio
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
]);
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
];
readWrite = [
"$HOME/.config/spotify"
"$HOME/.cache/spotify"
"$HOME/.local/share/spotify"
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = [
"$HOME/.config/spotify"
"$HOME/.cache/spotify"
"$HOME/.local/share/spotify"
] ++ cfg.extraBindMounts;
};
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "com.spotify.Client";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.mpris.MediaPlayer2.Player"''
''--own="org.mpris.MediaPlayer2.spotify"''
''--own="com.spotify.Client"''
''--own="com.spotify.Client.*"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/com.spotify.Client/bus" "$XDG_RUNTIME_DIR/bus"''
];
};
})
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "com.spotify.Client";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.mpris.MediaPlayer2.Player"''
''--own="org.mpris.MediaPlayer2.spotify"''
''--own="com.spotify.Client"''
''--own="com.spotify.Client.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/com.spotify.Client/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
};
})
];
environment.systemPackages = [ pkgs.spotify-sandboxed ];
};
}

View file

@ -1,50 +1,63 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.myModules.gaming.gamemode;
in
{
programs.gamescope = {
enable = true;
capSysNice = true;
options.myModules.gaming.gamemode = {
enable = lib.mkEnableOption "Steam GameMode Session";
};
services.displayManager.sessionPackages = [
(pkgs.writeTextFile {
name = "steam-gamemode-session";
destination = "/share/wayland-sessions/steam-gamemode.desktop";
text = ''
[Desktop Entry]
Name=Steam GameMode
Comment=Launch Steam in GameMode with Gamescope
Exec=${pkgs.writeShellScript "steam-gamemode-start" ''
# Load system environment
. /etc/profile
config = lib.mkIf cfg.enable {
programs.gamemode.enable = true;
# Ensure we are in the user's home directory
cd "$HOME" || exit 1
programs.gamescope = {
enable = true;
capSysNice = true;
};
exec >/tmp/steam-gamemode.log 2>&1
echo "Starting Steam GameMode Session at $(date)"
echo "User: $(whoami)"
echo "PATH: $PATH"
echo "Gamescope path: ${pkgs.gamescope}/bin/gamescope"
services.displayManager.sessionPackages = [
(pkgs.writeTextFile {
name = "steam-gamemode-session";
destination = "/share/wayland-sessions/steam-gamemode.desktop";
text = ''
[Desktop Entry]
Name=Steam GameMode
Comment=Launch Steam in GameMode with Gamescope
Exec=${pkgs.writeShellScript "steam-gamemode-start" ''
# Load system environment
. /etc/profile
# Check for steam binary
if ! command -v steam >/dev/null; then
echo "ERROR: steam command not found in PATH"
exit 1
fi
# Ensure we are in the user's home directory
cd "$HOME" || exit 1
echo "Launching gamescope..."
exec ${pkgs.gamescope}/bin/gamescope -f -e -- steam -gamepadui
''}
Type=Application
'';
derivationArgs = {
passthru = {
providedSessions = [ "steam-gamemode" ];
exec >/tmp/steam-gamemode.log 2>&1
echo "Starting Steam GameMode Session at $(date)"
echo "User: $(whoami)"
echo "PATH: $PATH"
echo "Gamescope path: ${pkgs.gamescope}/bin/gamescope"
# Check for steam binary
if ! command -v steam >/dev/null; then
echo "ERROR: steam command not found in PATH"
exit 1
fi
echo "Launching gamescope..."
exec ${pkgs.gamescope}/bin/gamescope -f -e -- steam -gamepadui
''}
Type=Application
'';
derivationArgs = {
passthru = {
providedSessions = [ "steam-gamemode" ];
};
};
};
})
];
}
})
];
};
}

View file

@ -9,144 +9,81 @@
}:
let
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
in
{
nixpkgs.overlays = [
(final: prev: {
steam-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = prev.steam;
isFhsenv = true; # Steam uses buildFHSEnv
id = "com.valvesoftware.Steam";
env = {
# Unset LD_PRELOAD to avoid mimalloc crashes
LD_PRELOAD = "";
# Propagate XDG_DATA_DIRS for theming
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Proton/Wine optimizations
PROTON_USE_NTSYNC = 1;
XDG_CURRENT_DESKTOP = "niri";
XDG_SESSION_TYPE = "wayland";
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
};
};
sandboxUtils.mkSandboxedApp {
inherit
config
lib
pkgs
inputs
;
optionName = "steamSandboxed";
packageName = "steam-sandboxed";
description = "sandboxed Steam with nix-bwrapper";
package = pkgs.steam;
appId = "com.valvesoftware.Steam";
isFhsenv = true;
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
PROTON_USE_NTSYNC = 1;
XDG_CURRENT_DESKTOP = "niri";
XDG_SESSION_TYPE = "wayland";
DBUS_SESSION_BUS_ADDRESS = "unix:path=$XDG_RUNTIME_DIR/bus";
};
# Disable Flatpak emulation
flatpak.enable = false;
fhsenvExtra = {
skipExtraInstallCmds = true;
};
fhsenv = {
skipExtraInstallCmds = true; # Steam package is special, don't try to modify it
};
fhsenvOpts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false;
unshareIpc = false;
};
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false; # Share PIDs for compatibility
unshareNet = false; # Need network for Steam login/downloads
unshareIpc = false;
};
baseArgs =
sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { };
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--dev-bind /dev/shm /dev/shm" # Shared memory (required for games)
"--dev-bind-try /dev/uinput /dev/uinput" # Controller support
"--dev-bind-try /dev/input /dev/input" # Controller/input devices
"--dev-bind-try /dev/hidraw0 /dev/hidraw0" # HID devices (controllers)
"--dev-bind-try /dev/hidraw1 /dev/hidraw1"
"--dev-bind-try /dev/hidraw2 /dev/hidraw2"
"--dev-bind-try /dev/hidraw3 /dev/hidraw3"
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
"--unsetenv LD_PRELOAD"
# udev for controller hotplug
"--ro-bind-try /run/udev /run/udev"
];
mounts = {
read = [ ];
readWrite = [
"$HOME/.steam"
"$HOME/.local/share/Steam"
"$HOME/.local/share/umu"
"$HOME/.local/share/applications"
"$HOME/.local/share/desktop-directories"
"$HOME/.local/share/icons"
"$HOME/.local/share/Larian Studios"
"$HOME/Desktop"
"/games/steam"
"/games/windows/Modlist"
"/games/windows/Modlist_Downloads"
];
};
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/qt6ct"
"$HOME/.config/Kvantum"
"$HOME/.config/MangoHud"
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
];
readWrite = [
"$HOME/.steam"
"$HOME/.local/share/Steam"
"$HOME/.local/share/umu"
"$HOME/.local/share/applications"
"$HOME/.local/share/desktop-directories"
"$HOME/.local/share/icons"
"$HOME/.local/share/Larian Studios"
"$HOME/Desktop"
"/games/steam"
"/games/windows/Modlist"
"/games/windows/Modlist_Downloads"
"$HOME/Games/windows/Modlist/Nordic"
];
};
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "com.valvesoftware.Steam";
enableSystemBus = false; # No system bus access
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--talk="org.freedesktop.portal.*"''
''--own="com.valvesoftware.Steam"''
''--own="com.valvesoftware.Steam.*"''
''--own="com.steampowered.PressureVessel.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/com.valvesoftware.Steam/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
};
})
];
dbusProxy = {
enable = true;
enableSystemBus = false;
rules = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.kde.KWin"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="org.freedesktop.secrets"''
''--talk="com.feralinteractive.GameMode"''
''--talk="org.freedesktop.portal.*"''
''--own="com.valvesoftware.Steam"''
''--own="com.valvesoftware.Steam.*"''
''--own="com.steampowered.PressureVessel.*"''
];
};
}

View file

@ -3,11 +3,12 @@
lib,
pkgs,
inputs,
...
}:
...}:
let
cfg = config.myModules.tutanotaSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
pname = "tutanota-desktop";
version = "319.260107.1";
@ -34,86 +35,73 @@ let
};
in
{
nixpkgs.overlays = [
(final: prev: {
tutanota-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = tutanota;
id = "com.tutanota.Tutanota";
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
options.myModules.tutanotaSandboxed = {
enable = lib.mkEnableOption "sandboxed Tutanota Desktop with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
tutanota-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = tutanota;
id = "com.tutanota.Tutanota";
env = {
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
};
};
};
flatpak.enable = false;
flatpak.enable = false;
# Basic sandboxing
fhsenv.opts = {
unshareUser = true;
unshareUts = true;
unshareCgroup = true;
unsharePid = true;
unshareNet = false; # Needs network
unshareIpc = true;
};
# Basic sandboxing
fhsenv.opts = {
unshareUser = true;
unshareUts = true;
unshareCgroup = true;
unsharePid = true;
unshareNet = false; # Needs network
unshareIpc = true;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
];
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
];
readWrite = [
"$HOME/.config/tutanota-desktop"
"$HOME/Downloads"
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = [
"$HOME/.config/tutanota-desktop"
"$HOME/Downloads"
] ++ cfg.extraBindMounts;
};
dbus.enable = false;
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "com.tutanota.Tutanota";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.secrets"''
''--talk="org.gnome.keyring.SystemPrompter"'' # Often needed for secrets
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="com.tutanota.Tutanota"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/com.tutanota.Tutanota/bus" "$XDG_RUNTIME_DIR/bus"''
];
};
})
];
dbus.enable = false;
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "com.tutanota.Tutanota";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.secrets"''
''--talk="org.gnome.keyring.SystemPrompter"'' # Often needed for secrets
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--own="com.tutanota.Tutanota"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/com.tutanota.Tutanota/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
];
};
})
];
environment.systemPackages = [ pkgs.tutanota-sandboxed ];
};
}

View file

@ -8,7 +8,9 @@
}:
let
cfg = config.myModules.vesktopSandboxed;
bwrapperPkgs = pkgs.extend inputs.nix-bwrapper.overlays.default;
sandboxUtils = import ./sandbox-utils.nix { inherit pkgs lib; };
# Define specific Vesktop version to avoid build errors from source
vesktop-bin = pkgs.stdenv.mkDerivation rec {
@ -40,106 +42,86 @@ let
};
in
{
nixpkgs.overlays = [
(final: prev: {
vesktop-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = vesktop-bin;
id = "dev.vencord.Vesktop";
env = {
# Propagate XDG_DATA_DIRS for theming
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Force Wayland
NIXOS_OZONE_WL = "1";
options.myModules.vesktopSandboxed = {
enable = lib.mkEnableOption "sandboxed Vesktop with nix-bwrapper";
extraBindMounts = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [];
description = "Extra paths to bind mount (read-write) into the sandbox";
};
};
config = lib.mkIf cfg.enable {
nixpkgs.overlays = [
(final: prev: {
vesktop-sandboxed = bwrapperPkgs.mkBwrapper {
app = {
package = vesktop-bin;
id = "dev.vencord.Vesktop";
env = {
# Propagate XDG_DATA_DIRS for theming
XDG_DATA_DIRS = "$XDG_DATA_DIRS";
# Force Wayland
NIXOS_OZONE_WL = "1";
};
};
};
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Enable X11 and Wayland
sockets.x11 = true;
sockets.wayland = true;
# Disable flatpak emulation
flatpak.enable = false;
# Disable flatpak emulation
flatpak.enable = false;
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for Discord
unshareIpc = false;
};
fhsenv.opts = {
unshareUser = true;
unshareUts = false;
unshareCgroup = false;
unsharePid = false;
unshareNet = false; # Need network for Discord
unshareIpc = false;
};
fhsenv.bwrap.baseArgs = lib.mkForce [
"--new-session"
"--proc /proc"
"--dev /dev"
"--dev-bind /dev/dri /dev/dri" # GPU acceleration
"--tmpfs /home"
"--tmpfs /tmp"
"--tmpfs /run"
"--dir /run/user"
"--dir /run/user/${toString config.users.users.ashie.uid}"
# System paths
"--ro-bind /sys /sys"
"--ro-bind-try /run/current-system /run/current-system"
"--ro-bind-try /run/opengl-driver /run/opengl-driver"
"--ro-bind-try /run/opengl-driver-32 /run/opengl-driver-32"
"--dir /run/systemd/resolve"
"--ro-bind-try /run/systemd/resolve /run/systemd/resolve"
# Audio
"--ro-bind-try /etc/asound.conf /etc/asound.conf"
];
fhsenv.bwrap.baseArgs = lib.mkForce (sandboxUtils.mkCommonBindArgs { inherit config lib; } ++ sandboxUtils.mkGamingBindArgs { });
mounts = {
read = [
"$HOME/.config/fontconfig"
"$HOME/.local/share/fonts"
"$HOME/.icons"
"$HOME/.themes"
"$HOME/.local/share/themes"
"$HOME/.config/kdedefaults"
"$HOME/.local/share/color-schemes"
];
readWrite = [
"$HOME/.config/vesktop"
"$HOME/Downloads"
mounts = {
read = sandboxUtils.mkGuiMounts.read;
readWrite = [
"$HOME/.config/vesktop"
"$HOME/Downloads"
] ++ cfg.extraBindMounts;
};
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = sandboxUtils.mkDbusProxyScript {
appId = "dev.vencord.Vesktop";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="com.canonical.AppMenu.Registrar"''
''--own="dev.vencord.Vesktop"''
''--own="dev.vencord.Vesktop.*"''
];
};
fhsenv.bwrap.additionalArgs = sandboxUtils.mkGuiBindArgs { } ++ [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/dev.vencord.Vesktop/bus" "$XDG_RUNTIME_DIR/bus"''
];
};
})
];
# Disable built-in DBus module (invokes bwrap without --unshare-user)
dbus.enable = false;
# Manually set up DBus proxy with --unshare-user (session bus only)
script.preCmds.stage2 = (import ./sandbox-utils.nix { inherit pkgs lib; }).mkDbusProxyScript {
appId = "dev.vencord.Vesktop";
enableSystemBus = false;
proxyArgs = [
"--filter"
''--talk="org.freedesktop.portal.*"''
''--call="org.freedesktop.portal.*=*@/org/freedesktop/portal/desktop"''
''--talk="org.freedesktop.Notifications"''
''--talk="org.freedesktop.ScreenSaver"''
''--talk="org.kde.StatusNotifierWatcher"''
''--talk="org.gnome.Mutter.DisplayConfig"''
''--talk="com.canonical.AppMenu.Registrar"''
''--own="dev.vencord.Vesktop"''
''--own="dev.vencord.Vesktop.*"''
];
};
fhsenv.bwrap.additionalArgs = [
# D-Bus session proxy only
''--bind "$XDG_RUNTIME_DIR/app/dev.vencord.Vesktop/bus" "$XDG_RUNTIME_DIR/bus"''
# Wayland socket
''--bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY"''
# PipeWire + Pulse
''--bind "$XDG_RUNTIME_DIR/pipewire-0" "$XDG_RUNTIME_DIR/pipewire-0"''
''--bind "$XDG_RUNTIME_DIR/pulse" "$XDG_RUNTIME_DIR/pulse"''
];
};
})
];
environment.systemPackages = [ pkgs.vesktop-sandboxed ];
};
}

10
scripts/run-nixbsd-vm.sh Executable file
View file

@ -0,0 +1,10 @@
#!/usr/bin/env bash
# Script to build and run the NixBSD VM
set -e
echo "Building NixBSD VM..."
VM_PATH=$(nix build .#nixosConfigurations.nixbsd.config.system.build.vm --no-link --print-out-paths --extra-experimental-features 'nix-command flakes')
echo "Starting NixBSD VM..."
$VM_PATH/bin/run-nixbsd-vm

View file

@ -23,6 +23,11 @@ authelia_session_secret: ENC[AES256_GCM,data:jNB1QBocUNZSljjgIrtgTtmDQKthuGY8Gv8
authelia_storage_encryption_key: ENC[AES256_GCM,data:2ELisYBEh7rY+Jcfy5c2mBOvFUi6uYnTHtkMviOffqkIkSUmgc+43Kt2tQA7P97y6Tn8/1w/3jJjx/1voz3ojQ==,iv:85k4x8bMoaJEGz4JgyrpmcTJktGypQjK/2GUxIFymOc=,tag:cJTW6YwZTtoUQDSXnYS32A==,type:str]
searxng_brave_api_key: ENC[AES256_GCM,data:LgBCXW1jISajMWiZ7Miygv9TGjGImGP9TY7QLH4j1Q==,iv:r8E4dSjPofv+XFAsJFx3Z+y592tOOxWr0a/gGkJjPJw=,tag:1FHVfjvyvw7F5IOjQefySA==,type:str]
searxng_private_token: ENC[AES256_GCM,data:Jw2yKNEkCZM7XHSrmz9wynSacT2XszjzDULo61Aodw==,iv:+0SA5IxRA7e/fd5Umw5wlWZj3YaTVEvYX7Jc1WZmPxk=,tag:rsg4N6GEl4yPmRsYzFAjOA==,type:str]
cloudflare_warp_address_ipv4: ENC[AES256_GCM,data:kKmmnwVGkjNvbGAFYw==,iv:3FH6JA2KzwhHEYlMBmEl4ENTer78RMhk+g8KihO3t5Q=,tag:mVX6RmPH1JFCisJmxr7HbA==,type:str]
cloudflare_warp_address_ipv6: ENC[AES256_GCM,data:YYbDxJKkyv8PM0eDMEf+LoTB0+a6MMOtSIox+PlWOuBTdPMhVQA7avg0,iv:/gR19idYvnAwDkIVW7gijKgQzZm0JsScbcYDJV6gBds=,tag:+hdPtRlZkDuJmj+tROA+iw==,type:str]
cloudflare_warp_endpoint: ENC[AES256_GCM,data:gnjWcn9PABTaDPf+o/wsWyTPddkhg86g0aLbWg49hgM=,iv:jIHTtXz/crmQg+bABImMi3DVbUkUM3tfykBcwMeJD6c=,tag:bsU5hbQ+tc5mIDIN6nxnYg==,type:str]
cloudflare_warp_private_key: ENC[AES256_GCM,data:KfpITQZ+VgTTiyoQdguazeLkUbK8RrAv927fLAWCe+VHVK9heGzwJS+S3sE=,iv:6rOGVFGdkPTXISTl9C2wU4GozI66p2BJDw65nKdHA+M=,tag:AabWup0iLEgmABhiNRhvmw==,type:str]
cloudflare_warp_public_key: ENC[AES256_GCM,data:rN08TQCT3pNZokVl/ToKSy+7l5OkwH/BLURfhL+u5kZtOtN4fZmoPcKjcLU=,iv:4DN5rfmX2NnSYP51rgs3teYneWcnSD6G9BJQqa2RIO4=,tag:TPmoIEPcg5ey2BQrEi7pzA==,type:str]
sops:
age:
- recipient: age1g76q4cec3qykmkzrd6f4fxxpafj5fsut4jk7pklweuff97scpuusnwdknu
@ -43,7 +48,7 @@ sops:
cVlpL1pxTFN3d1llbEhiNzlCcDV6NzAK6RlVB106woOkrmlINKB5hjoQs8CBfMAI
nAjTYfHW0h4PznY0JpWfeNaVRD4EbDwbE2m8X6OzQEWJJB1WESw4Zg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-29T18:21:33Z"
mac: ENC[AES256_GCM,data:k7C/t0INfl4bfUdrj81S2jbKjHGCP/W4+NeYXgzXrQ3mKD6myWNJW9j5Yh6WucFleV5uvk0IsH8zdUv/6F12fsCGRJ153Le8+LUZ400Co6toaLLIubLvC+mcUxqiXzSnGBUhjNH2jYNscBXtSSD+o2xUsyvs/vc5kqIv2tZzqHY=,iv:ef4nRzAaux9NEap87iphzOj3p1zPrvansBhq2v0w47o=,tag:HN0J/FlzWKg/ZoNvxYtRrg==,type:str]
lastmodified: "2026-02-12T00:55:55Z"
mac: ENC[AES256_GCM,data:KAXGETbqcDHyCtn0qiKg2PKPHrfzrwLFkx693j37pQTD1yKY/ziyencM0qQHl7oEtp4KI8u8pd7zwO6qJEts4wCCqG8MGJnKrwcD5AD8L+zn9szLKLPK31MSaRW799CcEGDE2PgaAtc7atqvs0OH8+KElN3vQeinJWFicqeICak=,iv:6E9uRXMadFt9mP0tPFOYNn2tt2KeyQb6DyS3NYykpy8=,tag:zdZ2CzCm6HIlX/W5m9es5A==,type:str]
unencrypted_suffix: _unencrypted
version: 3.11.0