Compare commits

...

131 commits

Author SHA1 Message Date
5e01993093
feat(nix): add openrouter key and enable for server
WARNING: This commit includes new files and secrets modifications.
2025-07-09 04:58:29 +08:00
1c1c47d7a1
fix(nix): move podman and distrobox to virtualisation options 2025-07-09 04:51:07 +08:00
e9816ab8e2
feat(nix): enable fwupd, podman and distrobox for server 2025-07-09 04:45:38 +08:00
a6bd611c25
fix(nix): bring up to feature parity 2025-07-09 04:43:48 +08:00
738a7b95d2
build(flake): update flake.lock 2025-07-09 04:22:34 +08:00
08090fa25c
feat(nix): add scripts for zk, edit, commit and rebuild 2025-07-09 04:20:46 +08:00
782bbcbaa3
feat(configurations): use host config for monitor settings 2025-07-09 04:13:24 +08:00
79c7e495c8
feat(configurations): pass in host manifest config to home-manager 2025-07-09 03:57:16 +08:00
2710c71820
feat(nix): add rrv.sh module and enable for server 2025-07-09 03:50:34 +08:00
c026887236
feat(nix): add forgejo module and enable for server 2025-07-09 03:46:10 +08:00
9e77ea8e65
feat(nix): add librechat module and enable for server
WARNING: This commit includes new files and secrets modifications.
2025-07-09 03:42:33 +08:00
16fb62f03b
feat(nix): enable sd-webui-forge and comfy-ui for server 2025-07-09 03:30:41 +08:00
8db9ceb372
feat(nix): add comfy-ui module and enable it for server 2025-07-09 03:27:05 +08:00
fbd8a20036
fix(lib): rm infinite recursion somehow 2025-07-09 03:26:31 +08:00
e9a6649f6a
build(flake): add stable-diffusion 2025-07-09 03:25:54 +08:00
5f42498a39
feat(nix): add nginx reverse proxy to web-servers module
Adds nginx reverse proxy functionality with SSL support.
2025-07-09 02:59:31 +08:00
9657329282
feat(nix): add web-servers module and enable SSL certificates 2025-07-09 02:41:14 +08:00
c85db031dc
feat(nix): add dynamic DNS module using godns
Adds support for updating Cloudflare DNS records using godns.
2025-07-09 02:09:19 +08:00
774527379a
feat(nix): add database module and enable mongodb,mysql,pgsql 2025-07-09 01:57:41 +08:00
ea77bf62ad
feat(homes/rafiq): configure graphical modules for hyprland
Moves graphical configs into a nixos module and enables autologin.
2025-07-09 01:47:41 +08:00
5048f44559
feat(homes/rafiq): enable sunshine and fix modules for steam 2025-07-09 01:46:28 +08:00
3db3dc176c
feat(homes/rafiq): enable spotifyd and pass hostName to home 2025-07-09 01:44:06 +08:00
4507f4b113
feat(homes/rafiq): add hyprlock config and pam service fix 2025-07-09 01:39:00 +08:00
09b10869e6
feat(homes/rafiq): add steam and prism-launcher configs 2025-07-09 01:37:46 +08:00
96b5aa3fef
feat(nix): port over libs 2025-07-09 01:33:28 +08:00
03bac12a2d
feat(homes/rafiq): add stylix options and wallpaper 2025-07-09 01:17:54 +08:00
69d7bca0f6
feat(flake): add stylix and base16 theming flakes 2025-07-09 00:57:01 +08:00
2d90d32144
refactor(nix): port homes to homemanager module 2025-07-09 00:53:00 +08:00
2c6cd776ce
feat(nix): use module options instead of specialArgs for graphical 2025-07-09 00:14:55 +08:00
dd74ed210c
feat(nix): refine meta module options for users and hosts 2025-07-08 23:53:42 +08:00
df06e092d6
feat(nix): add graphical module, pass option to nixosSystem 2025-07-07 22:19:38 +08:00
c2bae8cd85
feat(homes/rafiq): import desktop configs 2025-07-07 22:03:14 +08:00
8166894b78
feat(nix): add desktop module and refactor machine options 2025-07-07 21:48:12 +08:00
4c82720251
feat(homes/rafiq): port over configs 2025-07-07 21:19:08 +08:00
aa06b5f6fd
feat(nixos): add sudo module and refactor user options 2025-07-07 19:30:04 +08:00
03fca8b28b
refactor(modules): clean up folder structure 2025-07-07 19:24:36 +08:00
d8aa7f62b4
feat(nixos): add networking module 2025-07-07 19:17:55 +08:00
7881c76f73
feat(nixos): add tailscale module 2025-07-07 19:13:16 +08:00
343c802e6d
feat(nixos/ssh): enable openssh and persist host keys 2025-07-07 19:09:07 +08:00
3bffa8760e
feat(nixos): add machine module with virtualisation and usb options 2025-07-07 19:04:17 +08:00
e097d3e688
feat(nixos): add bluetooth module 2025-07-07 18:44:24 +08:00
ce83834ef4
feat(nixos): add machine module 2025-07-07 18:42:26 +08:00
4cc2b50e15
feat(nixos): add podman module 2025-07-07 18:40:25 +08:00
b4dc19d65c
feat(nixos): add bootloader configuration module 2025-07-07 18:32:34 +08:00
09ab1ac5a6
feat(nixos): set default timezone and locale 2025-07-07 18:29:02 +08:00
294e8458e4
feat(nix/secrets): persist sops age key for home-manager 2025-07-07 18:27:56 +08:00
8fb620284d
feat(nixos/ssh): add ssh config to home-manager 2025-07-07 18:27:03 +08:00
1fe332c302
feat(nix/persist): add impermanence to home-manager 2025-07-07 18:25:43 +08:00
bf260096d5
refactor(nixos/ssh): add authorizedKeys to ssh module & rm from users 2025-07-07 18:18:57 +08:00
b63959f307
refactor(configurations): centralise home-manager config 2025-07-07 18:11:33 +08:00
b5772e4525
refactor(machine/root): centralise root drive cfg 2025-07-07 18:10:32 +08:00
fe91044c8b
refactor(nixos): move persisted ssh host keys to ssh module 2025-07-07 17:47:51 +08:00
4ff7b8e18f
feat(nixos): add user password secrets to sops
This commit adds the user password secrets to sops.
It leverages the `userListToAttrs` lib function.
2025-07-07 17:42:31 +08:00
782a4324a8
feat(lib): add userListToAttrs function 2025-07-07 17:42:31 +08:00
85f2cee212
feat(nixos): add sops module for secrets
Adds .sops.yaml file and sops module to nixos to manage secrets.
2025-07-07 17:42:31 +08:00
d7b8edd054
feat(nix): add sops-nix to flake inputs 2025-07-07 17:42:31 +08:00
5d24a11990
feat(lib): add admin user using custom lib function 2025-07-07 17:42:31 +08:00
da6fa1b9df
refactor(nix): rename lib.nix to meta.nix and add flake.root option 2025-07-07 17:42:31 +08:00
0c2b6b57d9
refactor(lib): remove references to top level lib 2025-07-07 17:42:31 +08:00
9403daff02
refactor(nix): move unfree packages module to options 2025-07-07 17:42:31 +08:00
8c2b1dfc6e
feat(nixos): move persist options to system and users modules 2025-07-07 17:42:31 +08:00
6d43b0db3b
feat(nixos): make persist options 2025-07-07 17:42:31 +08:00
4e74db3938
refactor(lib): add lib output to flake
This is needed so we can use subattributes of flake.lib
2025-07-07 17:42:31 +08:00
1dc3f4bf44
fix(nix): remove flattenAttrs
unfortunately modules don't like to be merged
2025-07-07 17:42:31 +08:00
9abcb6c85b
feat(nixos): add impermanence module for ephemeral roots 2025-07-07 17:42:31 +08:00
714c3b8940
feat(nixos): add disko module for declarative partitioning 2025-07-07 17:42:31 +08:00
06a3f024c5
feat(nixos): add gpu module for nvidia config 2025-07-07 17:42:30 +08:00
5a94f19922
feat(nix): add unfree-packages module 2025-07-07 17:42:30 +08:00
12b7a4b7e0
feat(debug): enable flake-parts debug 2025-07-07 17:42:30 +08:00
0b2f2100cc
feat(nixos): add platform module for different architectures 2025-07-07 17:42:30 +08:00
27161d6b13
refactor: rename modules/flake to flake-parts, hosts to configurations 2025-07-07 17:42:30 +08:00
f78770d4f1
feat(git): add git module, set user config 2025-07-07 17:42:30 +08:00
a71cbb544a
feat(hm): add git config to rafiq home, use forAllUsers' 2025-07-07 17:42:30 +08:00
46f631aab1
feat(shell): enable shell in home-manager module 2025-07-07 17:42:30 +08:00
0ca6436522
feat(users): add shell module, simplify users module 2025-07-07 17:42:30 +08:00
a3ed4c608d
feat(users): use forAllUsers' in nixos module 2025-07-07 17:42:30 +08:00
07413c4ac0
feat(nix): add forAllUsers' and docstrings to lib
Adds forAllUsers' function and docstrings to nix lib.
2025-07-07 17:42:30 +08:00
46cf93f69b
feat(nix): add system module, pass config to lib
This commit introduces a system module for NixOS and Home Manager,
and passes the configuration to the lib file.
2025-07-07 17:42:30 +08:00
b7358cd825
feat(hm): add sharedModules, move configurations.nix to hosts.nix 2025-07-07 17:42:30 +08:00
bd347b9889
refactor: move readme to docs dir, update nix file 2025-07-07 17:42:30 +08:00
c26c432890
feat(nixos): pass hostName to nixosSystem, move hm modules 2025-07-07 17:42:30 +08:00
f7873d54d3
refactor(nixos): simplify configurations.nix and lib
This commit refactors configurations.nix and lib/default.nix by removing the
extractConfigurations function and related code from lib/default.nix,
and moving the NixOS system building logic directly into configurations.nix.
It also changes the structure of hosts in manifest.nix to use a
hosts.nixos attribute.
2025-07-07 17:42:30 +08:00
99f984a523
refactor(users): move owner config to users config in manifest 2025-07-07 17:42:30 +08:00
51071f4107
build(flake): bump inputs 2025-07-07 17:42:30 +08:00
72f9fad9eb
feat(git): add .gitignore and pre-commit config to gitignore 2025-07-07 17:42:30 +08:00
52322afe1c
chore: remove pre-commit config symlink 2025-07-07 17:42:30 +08:00
fc477267ed
docs(readme): add acknowledgements and git links 2025-07-07 17:42:30 +08:00
95fea9184e
refactor(configurations): add default nixos module 2025-07-07 17:42:30 +08:00
aef828b713
feat(nixos): add owner config to manifest and users module 2025-07-07 17:42:30 +08:00
f670889e29
build(flake): add home-manager and example config 2025-07-07 17:42:30 +08:00
1fc8230bfc
refactor: move flake-parts modules to nix/modules/flake 2025-07-07 17:42:30 +08:00
0ea17b9fd8
refactor: rename nixos.nix to configurations.nix 2025-07-07 17:42:30 +08:00
c49beb7c57
refactor: rename hostSpec to manifest and update references 2025-07-07 17:42:30 +08:00
2dd8d0f73d
feat(readme): add structure section and update README.md 2025-07-07 17:42:30 +08:00
e884735f25
refactor: rename modules directory to nix 2025-07-07 17:42:30 +08:00
5501c39e31
feat(lib/mkSystem): add profile suppoet
This commit adds the mkSystem function to simplify nixosSystem
creation and merge profile configs.
2025-07-07 17:42:30 +08:00
90899b5d37
refactor(nixos): move nixosSystem config to lib
Moves the nixosSystem configuration logic to a library function for reuse.
2025-07-07 17:42:30 +08:00
c9636b0bfa
feat(nixos): pass flakeConfig to nixosSystem specialArgs 2025-07-07 17:42:30 +08:00
88318c2e39
feat(lib): add flattenAttrs helper 2025-07-07 17:42:30 +08:00
210ce03fff
feat(hostSpec): add apollo and nemesis hosts (WIP) 2025-07-07 17:42:30 +08:00
b984f5a084
feat(nixos): pass hostConfig to nixosSystem specialArgs 2025-07-07 17:42:30 +08:00
4baf606551
feat(nixos): add common nixos profile; move hostspec config 2025-07-07 17:42:30 +08:00
6a1aa5f30b
feat(hostSpec): add extraCfg to hostSpec and imports to nixosSystem 2025-07-07 17:42:30 +08:00
5ea055f053
feat: add nix-systems/default flake and remove systems module 2025-07-07 17:42:30 +08:00
691b925148
refactor: move docs/readme and docs/cheatsheet to flake-parts 2025-07-07 17:42:30 +08:00
03a43150a1
refactor(text): extract text helper to rrvsh/text.nix
This commit adds the rrvsh/text.nix flake to manage text generation.
It also removes the old text generation helpers module and updates the
README and flake.nix files to use the new flake.
2025-07-07 17:42:30 +08:00
e385783de2
feat(nixos): pass inputs and hostName as specialArgs to nixosSystem 2025-07-07 17:42:30 +08:00
b43476ccee
refactor(nixos): change hostSpec to define top level option 2025-07-07 17:42:30 +08:00
6aa5096172
feat(owner): add module to define owner metadata in flake 2025-07-07 17:42:29 +08:00
b370a9d7db
feat(hostSpec): add module to define hosts in flake 2025-07-07 17:42:29 +08:00
09f9a33620
feat(git-hooks): add more git-hooks and linters 2025-07-07 17:42:29 +08:00
2599d2e49c
feat(git-hooks): enable nixpkgs-fmt pre-commit hook 2025-07-07 17:42:29 +08:00
1b36bdc36d
chore(helpers/text): add TODO comment to extract into repo 2025-07-07 17:42:22 +08:00
b87595ccda
chore(readme): remove order attributes from readme module 2025-07-07 17:42:22 +08:00
9420f4b84c
feat(helpers/text): add support for unordered parts 2025-07-07 17:42:22 +08:00
2c77ff76ba
fix(files): remove TODO comment from files module 2025-07-07 17:42:22 +08:00
145200480d
feat(readme): add headings and descriptions to text.readme 2025-07-07 17:42:22 +08:00
9b54a02eaa
feat(helpers/text): add headings and descriptions 2025-07-07 17:42:22 +08:00
dd0ff1e6ac
feat(docs): add cheatsheet 2025-07-07 17:42:22 +08:00
6e7fc72d38
feat(files): generate list of generated files dynamically 2025-07-07 17:42:22 +08:00
63609ffa14
build(flake.lock,flake.nix): add git-hooks and dedupe_gitignore 2025-07-07 17:42:22 +08:00
295f5daba9
feat: add files module, text helper, and update readme generation 2025-07-07 17:42:22 +08:00
a19ede01a2
feat: basic flake-parts structure, make-shell, files and readme 2025-07-07 17:42:22 +08:00
6c59366f8f
feat: initial flake setup with flake-parts
Sets up a basic flake with flake-parts for modularity.
2025-07-07 17:42:22 +08:00
c81d8dfc9f
chore(tree-wide): rm everything for rebase 2025-07-07 17:42:20 +08:00
abfbb5aa09
feat: rework hostSpec to use providers and machine definitions 2025-07-07 17:41:47 +08:00
69d942a1be
feat: add rebuild package definition 2025-07-07 17:41:47 +08:00
670af2b207
refactor: use flake-parts, keep snowfall-lib for compatibility 2025-07-07 17:41:47 +08:00
66396761aa
docs: improve README structure, add headings 2025-07-07 17:41:47 +08:00
af256488f0
docs: add structure section to README 2025-07-07 17:41:47 +08:00
e24714a3c7
feat(nvf): add flake snippet to nvf snippets 2025-07-07 14:28:47 +08:00
138 changed files with 2645 additions and 3393 deletions

4
.gitignore vendored
View file

@ -1,2 +1,2 @@
result
*.qcow2
# gitignore
.pre-commit-config.*

View file

@ -1,7 +1,7 @@
keys:
- &admin age12l33pas8eptwjc7ewux3d8snyzfzwz0tn9qg5kw8le79fswmjgjqdjgyy6
- &rafiq age12l33pas8eptwjc7ewux3d8snyzfzwz0tn9qg5kw8le79fswmjgjqdjgyy6
creation_rules:
- path_regex: \.(yaml|json|env|ini)$
- path_regex: \.(yaml)$
key_groups:
- age:
- *admin
- *rafiq

View file

@ -1,83 +0,0 @@
# Planning
## To-do
- [ ] Copy over ~/.ssh/id_ed25519 and zellij status bar plugin confirmation
- [ ] Migrate immich to apollo, point to helios
- [x] Migrate LibreChat to apollo, maintain db
- [ ] Figure out wakapi
- [x] Add forgejo
- [ ] Add simple blog
## Versions
- 1.0.0
- Setup desktop as hypervisor with nixos and win11
- Spare drive as steam library
- GPU passthrough to either system
- Always running, VMs spun down except when in use
- Apollo as hypervisor
- VMs for docker host, home-assistant, bare metal or containerised services
- Automated backups for home and state directories
- Ability to build VMs of all systems and implement integration tests
- Staging VMs for ad-hoc testing
- All servers set up with following services:
- Git server
- Chat app
- Network shares
- Federation with ActivityPub
- Wakapi
- Add a way to define services per host and refer to them by hostname
- helios as file and db server, apollo as services and reverse proxy
- 0.3.0
- Integration tests for all services
- Migrate services from helios
# Modules
The nixosModules and homeModules exposed by this flake are slightly out of the norm.
Option declarations for user specific configuration are kept to:
- homeModules for CLI
- nixosModules for desktop
System configurations, to this end, should include the window manager, lockscreen, terminal etc. for that system.
These desktop programs will be **configured** in home-manager for each user, but those configurations consult the osConfig variable passed in by home-manager.
# System Setup
The following files are **required** for system activation:
- /persist/home/${mainUser}/.ssh/id_ed25519
This private key will be used by sops-nix to decrypt the secrets in [this encrypted file](secrets/secrets.yaml). The secrets inside the yaml file should also be set, or otherwise removed alongside their declarations , found [here](modules/nixos/system/secrets.nix) and references.
```bash
# On the target machine
# Boot into the NixOS installer
sudo passwd
# On the host machine
deploy --user "rafiq" --ip "10.10.0.102" --hostname "apollo"
```
### From a Local NixOS Installer
The installation may run out of space when installing from an install ISO. In that case, use Disko to format the drives first, then create a `/mnt/tmp` directory and set it as TMPDIR for nixos-install.
```bash
sudo su
nix --extra-experimental-features "nix-command flakes" run github:nix-community/disko/master -- --mode destroy,format,mount --flake github:rrvsh/pantheon#<HOSTNAME>
# Copy SSH key to /persist/home/rafiq/.ssh
mkdir /mnt/tmp
TMPDIR=/mnt/tmp nixos-install --flake github:rrvsh/pantheon#<HOSTNAME> --no-root-password
reboot
```
# Impermanence
System and user state is stored under /persist. Anything not declared under
`{environment,home}.persistence` is deleted on system boot.

29
docs/README.md Normal file
View file

@ -0,0 +1,29 @@
# Pantheon
This flake serves as a monorepo for my systems (using IaC), dotfiles, and scripts.
It's hosted at https://git.rrv.sh/rrvsh/pantheon, and mirrored to https://github.com/rrvsh/pantheon.
## Structure
The system configurations are defined in [`flake.manifest`](nix/manifest.nix).
`flake.manifest.owner` provides the attributes for the administrator user, including username and pubkey.
`flake.manifest.hosts` provides the specifications for the system configurations that should be exposed by the flake as nixosConfigurations.
`flake.modules.nixos.*` provide NixOS options and configurations.
The attribute `flake.modules.nixos.default` provides options that will be applied to every system of that class.
You can use it as seen [here](nix/modules/flake/home-manager.nix):
```nix
flake.modules.nixos.default.imports = [ inputs.home-manager.nixosModules.default ];
```
The other attributes under `flake.modules.nixos` should be opt-in, i.e. provide options that will be set in the profiles.
`flake.profiles.nixos` provides profiles which use the options defined in `flake.modules.nixos` to define different roles for each system, such as graphical, laptop, headless, etc.
Options should not be defined here.
`flake.contracts.nixos.*` will provide contracts, such as reverse proxies or databases, which will configure options on the provider and receiver host.
## Acknowledgements
Thanks to the following for inspiring this configuration. I highly recommend you look through their writings and configurations.
- [ornicar](https://github.com/ornicar/dotfiles) which is where I first heard of NixOS
- [No Boilerplate](https://www.youtube.com/watch?v=CwfKlX3rA6E&pp=0gcJCfwAo7VqN5tD) for making me finally try the OS
- [ryan4yin](https://nixos-and-flakes.thiscute.world/) for being an amazing introduction to NixOS, home-manager, and flakes
- [NotAShelf](https://github.com/NotAShelf/) for their blog and for the wonderful [NVF](https://github.com/notashelf/nvf)
- [mightyiam](https://github.com/mightyiam/infra) for their infrastructure repo using flake-parts
- [drupol](https://not-a-number.io/2025/refactoring-my-infrastructure-as-code-configurations/) for this blog post which convinced me to rebase my infra to use flake-parts

2
docs/cheatsheet.md Normal file
View file

@ -0,0 +1,2 @@
# cheatsheet
`__curPos.file` will give the full evaluated path of the nix file it is called in. See [this issue](https://github.com/NixOS/nix/issues/5897#issuecomment-1012165198) for more information.

924
flake.lock generated

File diff suppressed because it is too large Load diff

135
flake.nix
View file

@ -1,43 +1,124 @@
{
# TODO: use flake-parts and remove snowfall-lib
outputs =
inputs:
inputs.snowfall-lib.mkFlake {
inherit inputs;
src = ./.;
snowfall.namespace = "pantheon";
};
inputs.flake-parts.lib.mkFlake { inherit inputs; } (
(inputs.import-tree ./nix)
// {
systems = import inputs.systems;
flake.paths.root = ./.;
}
);
inputs = {
# We use nixos-unstable as everything is cached.
### SYSTEM ###
# systems provides a list of supported nix systems.
systems.url = "github:nix-systems/default";
# nixos-unstable provides a binary cache for all packages.
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
# My fork for random shit
rrvsh-nixpkgs.url = "github:rrvsh/nixpkgs/librechat-module";
# home-manager manages our user packages and dotfiles
home-manager = {
url = "github:nix-community/home-manager";
inputs.nixpkgs.follows = "nixpkgs";
};
# the nix user repository for mainly firefox extensions
nur = {
url = "github:nix-community/NUR";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-parts.follows = "flake-parts";
};
# impermanence provides a nice abstraction over linking files from /persist
impermanence.url = "github:nix-community/impermanence";
# flake-parts lets us define flake modules.
flake-parts = {
url = "github:hercules-ci/flake-parts";
inputs.nixpkgs-lib.follows = "nixpkgs";
};
# disko provides declarative drive partitioning
disko = {
url = "github:nix-community/disko";
inputs.nixpkgs.follows = "nixpkgs";
};
# sops-nix lets us version control secrets like passwords and api keys
sops-nix = {
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
stylix = {
url = "github:nix-community/stylix";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-parts.follows = "flake-parts";
systems.follows = "systems";
nur.follows = "nur";
};
};
# import-tree lets us use less imports = []
### FLAKE PARTS MODULES ###
# import-tree imports all nix files in a given directory.
import-tree.url = "github:vic/import-tree";
# files lets us write text files and automatically add checks for them
files.url = "github:mightyiam/files";
# text.nix lets us easily define markdown text to pass to files
text.url = "github:rrvsh/text.nix";
# make-shells.<name> creates devShells and checks
make-shell = {
url = "github:nicknovitski/make-shell";
inputs.flake-compat.follows = "dedupe_flake-compat";
};
# git-hooks ensures nix flake check is ran before commits
git-hooks = {
url = "github:cachix/git-hooks.nix";
inputs = {
flake-compat.follows = "dedupe_flake-compat";
nixpkgs.follows = "nixpkgs";
gitignore.follows = "dedupe_gitignore";
};
};
# The following are used for less boilerplate.
flake-parts.url = "github:hercules-ci/flake-parts";
#TODO: remove snowfall
snowfall-lib = {
url = "github:snowfallorg/lib";
### FLAKES ###
# nix-index-database indexes the nixpkgs binaries for use with comma
nix-index-database = {
url = "github:nix-community/nix-index-database";
inputs.nixpkgs.follows = "nixpkgs";
};
# nvf provides modules to wrap neovim
nvf = {
url = "github:notashelf/nvf";
inputs = {
nixpkgs.follows = "nixpkgs";
flake-parts.follows = "flake-parts";
systems.follows = "systems";
flake-utils.follows = "dedupe_flake-utils";
mnw.follows = "dedupe_mnw";
};
};
# provides comfy ui and sdwebui services
stable-diffusion-webui-nix = {
url = "github:janrupf/stable-diffusion-webui-nix";
inputs.nixpkgs.follows = "nixpkgs";
inputs.flake-utils.follows = "dedupe_flake-utils";
};
# my website :)
rrv-sh = {
url = "github:rrvsh/rrv.sh";
inputs.nixpkgs.follows = "nixpkgs";
};
# Various nix things
nur.url = "github:nix-community/NUR";
sops-nix.url = "github:Mic92/sops-nix";
disko.url = "github:nix-community/disko";
home-manager.url = "github:nix-community/home-manager";
impermanence.url = "github:nix-community/impermanence";
nix-index-database.url = "github:nix-community/nix-index-database";
stylix.url = "github:nix-community/stylix";
systems.url = "github:nix-systems/default";
### DEDUPE ###
# Packages and services that we don't use nixpkgs for.
rrv-sh.url = "github:rrvsh/rrv.sh";
nvf.url = "github:rrvsh/nvf/uv-nvim";
stable-diffusion-webui-nix.url = "github:rrvsh/stable-diffusion-webui-nix/fix/comfy-ui-data-directory";
zjstatus.url = "github:dj95/zjstatus";
dedupe_flake-compat.url = "github:edolstra/flake-compat";
dedupe_flake-utils = {
url = "github:numtide/flake-utils";
inputs.systems.follows = "systems";
};
dedupe_mnw.url = "github:gerg-l/mnw";
dedupe_gitignore = {
url = "github:hercules-ci/gitignore.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
}

View file

@ -1,38 +0,0 @@
{ pkgs, inputs, ... }:
{
imports = [ inputs.nix-index-database.hmModules.nix-index ];
programs = {
tealdeer.enable = true;
tealdeer.enableAutoUpdates = true;
direnv = {
enable = true;
nix-direnv.enable = true;
};
zoxide.enable = true;
nix-index.enable = true;
nix-index-database.comma.enable = true;
};
persistDirs = [ ".local/share/zoxide" ];
home = {
shellAliases = {
windows = "sudo systemctl reboot --boot-loader-entry=auto-windows";
v = "$EDITOR";
e = "edit";
cd = "z"; # zoxide
ai = "aichat -r %shell% -e";
};
packages = with pkgs; [
ripgrep
aichat
pantheon.rebuild
pantheon.deploy
pantheon.edit
pantheon.commit
];
};
xdg.configFile."aichat/config.yaml".text = ''
model: gemini:gemini-2.0-flash
clients:
- type: gemini
'';
}

View file

@ -1,47 +0,0 @@
{
pkgs,
lib,
inputs,
...
}:
{
imports = [ inputs.nvf.homeManagerModules.default ];
home.sessionVariables.EDITOR = "nvim";
programs.nvf.enable = true;
programs.nvf.settings.vim = {
syntaxHighlighting = true;
hideSearchHighlight = true;
searchCase = "ignore";
undoFile.enable = true;
telescope.enable = true;
fzf-lua.enable = true;
git.enable = true;
autopairs.nvim-autopairs.enable = true;
autocomplete = import ./_nvf/autocomplete.nix { inherit lib; };
binds = import ./_nvf/binds.nix;
languages = import ./_nvf/languages.nix;
lsp = import ./_nvf/lsp.nix;
navigation = import ./_nvf/navigation.nix;
notes.todo-comments.enable = true;
options = {
autoindent = true;
backspace = "indent,eol,start";
cursorline = true;
expandtab = true;
shiftwidth = 2;
smartindent = true;
tabstop = 2;
};
snippets = import ./_nvf/snippets.nix { inherit pkgs; };
statusline = import ./_nvf/statusline.nix;
treesitter = {
autotagHtml = true;
fold = true;
indent.disable = [ "markdown" ];
textobjects.enable = true;
};
ui = import ./_nvf/ui.nix;
utility = import ./_nvf/utility.nix;
visuals = import ./_nvf/visuals.nix;
};
}

View file

@ -1,23 +0,0 @@
{ pkgs, ... }:
{
home = {
packages = [ pkgs.fastfetch ];
sessionVariables.FETCH = "hyfetch";
shellAliases.fetch = "hyfetch";
};
programs.hyfetch = {
enable = true;
settings = {
preset = "bisexual";
mode = "rgb";
light_dark = "dark";
lightness = 0.5;
color_align = {
# Flag color alignment
mode = "horizontal";
fore_back = null;
};
backend = "fastfetch";
};
};
}

View file

@ -1,8 +0,0 @@
{
home.sessionVariables.FILE_BROWSER = "yazi";
programs.yazi = {
enable = true;
shellWrapperName = "t";
settings.mgr.sort_by = "natural";
};
}

View file

@ -1,5 +0,0 @@
{
programs.fzf.enable = true;
#TODO: fish
programs.fzf.enableZshIntegration = true;
}

View file

@ -1,61 +0,0 @@
{
osConfig,
inputs,
pkgs,
...
}:
let
zjstatus = inputs.zjstatus.packages.${pkgs.stdenv.hostPlatform.system}.default;
in
{
home.sessionVariables.MULTIPLEXER = "zellij";
# Persists sessions
persistDirs = [ "/.cache/zellij" ];
programs.zellij = {
enable = true;
#TODO: fish
enableZshIntegration = true;
settings = {
pane_frames = false;
show_startup_tips = false;
show_release_notes = false;
};
};
xdg.configFile."zellij/layouts/default.kdl".text = # kdl
''
layout {
default_tab_template {
pane size=1 borderless=true {
plugin location="file:${zjstatus}/bin/zjstatus.wasm" {
format_left "{mode} ${osConfig.hostname}"
format_center "{tabs}"
format_right "{datetime}"
format_space ""
format_hide_on_overlength "true"
format_precedence "lrc"
border_enabled "false"
hide_frame_for_single_pane "false"
mode_default_to_mode "normal"
mode_normal "#[bg=#89B4FA] {name} "
mode_locked "#[bg=#f55e18] {name} "
mode_session "#[bg=#00ff00] {name} "
tab_normal "#[fg=#6C7086] {index} "
tab_active "#[fg=#9399B2,bold,italic] {index} "
tab_display_count "3" // limit to showing 3 tabs
tab_truncate_start_format "..."
tab_truncate_end_format "..."
//TODO: disable if we are not on ssh
datetime "#[fg=#6C7086,bold] {format}"
datetime_format "%H:%M:%S"
datetime_timezone "Asia/Singapore"
}
}
children
}
}
'';
}

View file

@ -1,51 +0,0 @@
{ lib, pkgs, ... }:
let
inherit (builtins) toString;
inherit (lib) getExe mkOrder;
inherit (lib.strings) concatStrings;
screensaverTimeout = toString 100;
screensaverCommand = "${getExe pkgs.cbonsai} -S -w 0.1 -L 40 -M 2 -b 2";
in
{
home.shell.enableShellIntegration = true;
home.sessionVariables.SHELL = "fish";
programs.fish.enable = true;
programs.starship = {
enable = true;
settings = {
add_newline = false;
format = concatStrings [
# First Line
## Left Prompt
"$hostname$directory"
"$fill"
## Right Prompt
"$all"
# Second Line
## Left Prompt
"$character"
];
git_branch.format = "[$symbol$branch(:$remote_branch)]($style) ";
shlvl.disabled = false;
username.disabled = true;
fill.symbol = " ";
};
};
# figure out for fish
programs.zsh.initContent =
mkOrder 1200
# zsh
''
precmd() {
TMOUT=${screensaverTimeout}
}
TRAPALRM() {
TMOUT=1
${screensaverCommand}
# If we exit, assume the previous command was exited out of
TMOUT=${screensaverTimeout}
zle reset-prompt
}
'';
}

View file

@ -1,25 +0,0 @@
{
home.sessionVariables.GIT_CONFIG_GLOBAL = "$HOME/.config/git/config";
home.shellAliases = {
gs = "git status";
gc = "git commit";
gcam = "git commit -am";
gu = "git push";
gy = "git pull";
gdh = "git diff HEAD";
};
programs.git = {
enable = true;
userName = "Mohammad Rafiq";
userEmail = "rafiq@rrv.sh";
signing.key = "~/.ssh/id_ed25519.pub";
signing.signByDefault = true;
extraConfig = {
init.defaultBranch = "prime";
push.autoSetupRemote = true;
pull.rebase = false;
core.editor = "$EDITOR";
gpg.format = "ssh";
};
};
}

View file

@ -1,19 +0,0 @@
{ pkgs, ... }:
{
persistDirs = [ "notebook" ];
programs.zk = {
enable = true;
settings.notebook.dir = "~/notebook";
};
home.packages = [
(pkgs.writeShellScriptBin "note" # bash
''
zk edit -i
pushd ~/notebook > /dev/null
git add .
commit -u
popd > /dev/null
''
)
];
}

View file

@ -1,15 +0,0 @@
{
inputs,
osConfig,
lib,
...
}:
let
inherit (lib) singleton optional;
inherit (inputs) import-tree;
in
{
imports =
(optional osConfig.desktop.enable (import-tree ./desktop))
++ singleton (import-tree ./cli);
}

View file

@ -1,46 +0,0 @@
{
lib,
inputs,
pkgs,
...
}:
let
inherit (builtins) map listToAttrs;
inherit (lib.lists) findFirstIndex;
inherit (inputs.nur.legacyPackages.${pkgs.stdenv.hostPlatform.system}.repos.rycee) firefox-addons;
profiles = listToAttrs (
map (name: {
inherit name;
# If there are duplicate profile names, findFirstIndex will cause issues.
value = profileCfg (findFirstIndex (x: x == name) null syncedProfiles);
}) syncedProfiles
);
syncedProfiles = [
"rafiq"
"test"
];
profileCfg = id: {
inherit id;
settings."extensions.autoDisableScopes" = 0; # Auto enable extensions
#TODO: add default seach unduck and add rest of extensions
extensions = {
force = true;
packages = with firefox-addons; [
darkreader
gesturefy
sponsorblock
ublock-origin
];
};
};
in
{
home.sessionVariables.BROWSER = "firefox";
persistDirs = [ ".mozilla/firefox" ];
programs.firefox = {
enable = true;
inherit profiles;
};
stylix.targets.firefox.colorTheme.enable = true;
stylix.targets.firefox.profileNames = syncedProfiles;
}

View file

@ -1,19 +0,0 @@
{ pkgs, ... }:
{
persistDirs = [
"docs"
"repos"
"vids"
"tmp"
".cache/Smart Code ltd/Stremio"
".local/share/Smart Code ltd/Stremio"
];
programs = {
obs-studio.enable = true;
vesktop.enable = true;
thunderbird.enable = true;
thunderbird.profiles.rafiq.isDefault = true;
};
home.packages = with pkgs; [ stremio ];
stylix.image = ./wallpaper.png;
}

View file

@ -1,3 +0,0 @@
{
home.sessionVariables.LAUNCHER = "fuzzel";
}

View file

@ -1,29 +0,0 @@
let
styling = {
halign = "center";
valign = "center";
zindex = 1;
shadow_passes = 5;
shadow_size = 5;
};
in
{
home.sessionVariables.LOCKSCREEN = "hyprlock";
programs.hyprlock.settings = {
general.hide_cursor = true;
general.ignore_empty_input = true;
background.blur_passes = 5;
background.blur_size = 5;
label = {
text = ''hi, $USER.'';
font_size = 32;
position = "0, 0";
}// styling;
input-field = {
placeholder_text = "";
fade_on_empty = true;
size = "200, 45";
position = "0, -5%";
} // styling;
};
}

View file

@ -1,200 +0,0 @@
{
xdg.configFile."vlc/vlcrc".text = ''
[visual] # Visualizer filter
[glspectrum] # 3D OpenGL spectrum visualization
[wall] # Wall video filter
[panoramix] # Panoramix: wall with overlap video filter
[clone] # Clone video filter
[yuv] # YUV video output
[xdg_shell] # XDG shell surface
[xcb_xv] # XVideo output (XCB)
[xcb_x11] # X11 video output (XCB)
[xcb_window] # X11 video window (XCB)
[wl_shell] # Wayland shell surface
[vmem] # Video memory output
[vdummy] # Dummy video output
[gl] # OpenGL video output
[flaschen] # Flaschen-Taschen video output
[fb] # GNU/Linux framebuffer video output
[transform] # Video transformation filter
[sharpen] # Sharpen video filter
[sepia] # Sepia video filter
[scene] # Scene video filter
[rotate] # Rotate video filter
[puzzle] # Puzzle interactive game video filter
[postproc] # Video post processing filter
[posterize] # Posterize video filter
[motionblur] # Motion blur filter
[mirror] # Mirror video filter
[hqdn3d] # High Quality 3D Denoiser filter
[grain] # Grain video filter
[gradient] # Gradient video filter
[gradfun] # Gradfun video filter
[gaussianblur] # Gaussian blur video filter
[fps] # FPS conversion video filter
[extract] # Extract RGB component video filter
[erase] # Erase video filter
[deinterlace] # Deinterlacing video filter
[croppadd] # Video cropping filter
[colorthres] # Color threshold filter
[canvas] # Canvas video filter
[bluescreen] # Bluescreen video filter
[blendbench] # Blending benchmark filter
[ball] # Ball video filter
[antiflicker] # antiflicker video filter
[anaglyph] # Convert 3D picture to anaglyph image video filter
[alphamask] # Alpha mask video filter
[adjust] # Image properties filter
[swscale] # Video scaling filter
[vaapi_filters] # Video Accelerated API filters
[svg] # svg
[freetype] # Freetype2 font renderer
[stream_out_transcode] # Transcode stream output
[stats] # Writes statistic info about stream
[stream_out_standard] # Standard stream output
[smem] # Stream output to memory buffer
[setid] # Change the id of an elementary stream
[stream_out_rtp] # RTP stream output
[record] # Record stream output
[mosaic_bridge] # Mosaic bridge stream output
[es] # Elementary stream output
[display] # Display stream output
[delay] # Delay a stream
[stream_out_chromecast] # Chromecast stream output
[bridge] # Bridge stream output
[prefetch] # Stream prefetch filter
[subsdelay] # Subtitle delay
[rss] # RSS and Atom feed display
[remoteosd] # Remote-OSD over VNC
[mosaic] # Mosaic video sub source
[marq] # Marquee display
[logo] # Logo sub source
[dynamicoverlay] # Dynamic video overlay
[audiobargraph_v] # Audio Bar Graph Video sub source
[upnp] # Universal Plug'n'Play
[sap] # Network streams (SAP)
[podcast] # Podcasts
[mpegvideo] # MPEG-I/II video packetizer
[mux_ts] # TS muxer (libdvbpsi)
[ps] # PS muxer
[mux_ogg] # Ogg/OGM muxer
[mp4] # MP4/MOV muxer
[avi] # AVI muxer
[asf] # ASF muxer
[rtsp] # Legacy RTSP VoD server
[logger] # File logging
[gnutls] # GNU TLS transport layer security
[audioscrobbler] # Submission of played songs to last.fm
[folder] # Folder meta data
[lua] # Lua interpreter
[syslog] # System logger (syslog)
[file] # File logger
[console] # Console logger
[file] # Secrets are stored on a file without any encryption
[skins2] # Skinnable Interface
[qt] # Qt interface
qt-privacy-ask=0
[ncurses] # Ncurses interface
[vc1] # VC1 video demuxer
[ts] # MPEG Transport Stream demuxer
[subtitle] # Text subtitle parser
[rawvid] # Raw video demuxer
[rawdv] # DV (Digital Video) demuxer
[rawaud] # Raw audio demuxer
[ps] # MPEG-PS demuxer
[playlist] # Playlist
[mp4] # MP4 stream demuxer
[mod] # MOD demuxer (libmodplug)
[mkv] # Matroska stream demuxer
[mjpeg] # M-JPEG camera demuxer
[image] # Image demuxer
[h26x] # H264 video demuxer
[es] # MPEG-I/II/4 / A52 / DTS / MLP audio
[diracsys] # Dirac video demuxer
[demuxdump] # File dumper
[avi] # AVI demuxer
[avformat] # Avformat demuxer
[adaptive] # Unified adaptive streaming for DASH/HLS
[oldrc] # Remote control interface
[netsync] # Network synchronization
[motion] # motion control interface
[gestures] # Mouse gestures control interface
[vorbis] # Vorbis audio decoder
[ttml] # TTML subtitles decoder
[theora] # Theora video decoder
[telx] # Teletext subtitles decoder
[svgdec] # SVG video decoder
[svcdsub] # Philips OGT (SVCD subtitle) decoder
[subsusf] # USF subtitles decoder
[subsdec] # Text subtitle decoder
[spudec] # DVD subtitles decoder
[speex] # Speex audio decoder
[schroedinger] # Dirac video decoder using libschroedinger
[libass] # Subtitle renderers using libass
[kate] # Kate overlay decoder
[jpeg] # JPEG image decoder
[fluidsynth] # FluidSynth MIDI synthesizer
[dvbsub] # DVB subtitles decoder
[ddummy] # Dummy decoder
[cc] # Closed Captions decoder
[avcodec] # FFmpeg audio/video decoder
[a52] # ATSC A/52 (AC-3) audio decoder
[amem] # Audio memory output
[alsa] # ALSA audio output
[afile] # File audio output
[stereo_widen] # Simple stereo widening effect
[speex_resampler] # Speex resampler
[spatializer] # Audio Spatializer
[spatialaudio] # Ambisonics renderer and binauralizer
[scaletempo] # Audio tempo scaler synched with rate
[scaletempo_pitch] # Pitch Shifter
[samplerate] # Secret Rabbit Code (libsamplerate) resampler
[remap] # Audio channel remapper
[param_eq] # Parametric Equalizer
[normvol] # Volume normalizer
[mono] # Stereo to mono downmixer
[headphone] # Headphone virtual spatialization effect
[gain] # Gain control filter
[equalizer] # Equalizer with 10 bands
[compressor] # Dynamic range compressor
[chorus_flanger] # Sound Delay
[audiobargraph_a] # Audio part of the BarGraph function
[udp] # UDP stream output
[access_output_srt] # SRT stream output
[access_output_rist] # RIST stream output
[access_output_livehttp] # HTTP Live streaming output
[http] # HTTP stream output
[file] # File stream output
[xcb_screen] # Screen capture (with X11/XCB)
[vdr] # VDR recordings
[v4l2] # Video4Linux input
[udp] # UDP input
[timecode] # Time code subpicture elementary stream generator
[smb] # SMB input
[shm] # Shared memory framebuffer
[sftp] # SFTP input
[satip] # SAT>IP Receiver Plugin
[rtp] # Real-Time Protocol (RTP) input
[rist] # RIST input
[live555] # RTP/RTSP/SDP demuxer (using Live555)
[linsys_hdsdi] # HD-SDI Input
[libbluray] # Blu-ray Disc support (libbluray)
[access] # HTTPS input
[http] # HTTP input
[ftp] # FTP input
[filesystem] # File input
[dvdread] # DVDRead Input (no menu support)
[dvdnav] # DVDnav Input
[dvb] # DVB input with v4l2 support
[dtv] # Digital Television and Radio
[cdda] # Audio CD input
[avio] # libavformat AVIO access
[access_srt] # SRT input
[access_mms] # Microsoft Media Server (MMS) input
[imem] # Memory input
[concat] # Concatenated inputs
[access_alsa] # ALSA audio capture
[core] # core program
metadata-network-access=1
'';
}

View file

@ -1,5 +0,0 @@
{
home.sessionVariables.NOTIFICATION_DAEMON = "mako";
services.mako.enable = true;
services.mako.settings.default-timeout = 10000;
}

View file

@ -1,53 +0,0 @@
{ pkgs, ... }:
{
home.sessionVariables.STATUS_BAR = "waybar";
stylix.targets.waybar.addCss = false;
programs.waybar = {
enable = true;
settings = [
{
#TODO: review the rest of the modules to see what else can be added
layer = "top";
modules-left = [
"pulseaudio"
];
modules-right = [
"battery"
"clock"
];
"pulseaudio" = {
format = "{icon} {volume}%";
format-muted = "";
format-icons.default = [
""
""
];
on-click = "${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
};
"clock" = {
interval = 1;
format = "{:%F %T}";
};
"battery" = {
interval = 1;
bat-compatibility = true;
};
}
];
style = # css
''
window#waybar {
background-color: rgba(0, 0, 0, 0);
}
#pulseaudio,
#battery,
#clock {
padding-top: 5px;
padding-bottom: 5px;
padding-right: 5px;
color: #ffffff;
}
'';
};
}

View file

@ -1,9 +0,0 @@
{
home.sessionVariables.TERMINAL = "ghostty";
programs.ghostty = {
enable = true;
settings = {
confirm-close-surface = false;
};
};
}

View file

@ -1,21 +0,0 @@
{ lib, pkgs, ... }:
let
inherit (lib) mkMerge;
in
{
wayland.windowManager.hyprland.settings = mkMerge [
(import ./_hyprland/decoration.nix)
(import ./_hyprland/keybinds.nix { inherit pkgs; })
{
ecosystem.no_update_news = true;
xwayland.force_zero_scaling = true;
monitor = [ ", preferred, auto, 1" ];
exec-once = [
"uwsm app -- $LOCKSCREEN"
"uwsm app -- $NOTIFICATION_DAEMON"
"uwsm app -- $STATUS_BAR"
];
}
];
# TODO: add gamescope here or in nixos desktop module
}

View file

@ -1,78 +0,0 @@
{
users.rafiq = {
primary = true;
email = "rafiq@rrv.sh";
alternate-emails = [
"mohammadrafiq@rrv.sh"
"mohammadrafiq567@gmail.com"
];
pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILdsZyY3gu8IGB8MzMnLdh+ClDxQQ2RYG9rkeetIKq8n";
};
entrypoints = {
# For services that should only have one instance across the whole
# flake, define them here and they will get provisioned on those
# hosts, with whatever depends on them configured via that hostname.
nginx.host = "apollo";
ssh.host = "apollo";
};
# This will define all the hosts exposed by the flake and designate the
# modules and services, along with defining the hardware configuration
# for each host.
# <name> of each attr set will resolve to the host's hostname.
hosts.nemesis = {
platform = "amd";
gpu = "nvidia";
ephemeralRoot = true;
boot-drive = "/dev/disk/by-id/nvme-CT2000P3SSD8_2325E6E77434";
bootloader = "systemd-boot";
# Enables dotfiles and desktop environment/services.
desktop.enable = true;
extraCfg = { };
};
hosts.apollo = {
platform = "intel";
ephemeralRoot = true;
bootloader = "systemd-boot";
boot-drive = "/dev/disk/by-id/nvme-eui.002538d221b47b01";
# Public services will be exposed to the web server.
public-services = [
{
name = "librechat";
domain = "chat.bwfiq.com";
}
{
name = "forgejo";
domain = "git.rrv.sh";
}
{
name = "rrv-sh";
domain = "rrv.sh";
}
{
name = "immich";
domain = "photos.bwfiq.com";
}
{
name = "aenyrathia-wiki";
domain = "aenyrathia.wiki";
}
];
# Internal services will be exposed with tailscale only.
internal-services = [
"mongodb"
"mariadb"
"postgresql"
"redis"
];
extraCfg = { };
};
host.helios = {
platform = "intel";
boot-drive = "nvme-eui.6479a784aad00284";
ephemeralRoot = true;
bootloader = "systemd-boot";
extraCfg = { };
};
}

View file

@ -1,57 +0,0 @@
{ lib, ... }:
let
inherit (lib) mkOption singleton;
inherit (lib.types)
int
str
port
path
attrs
;
inherit (lib.strings) splitString;
inherit (builtins) length concatStringsSep tail;
in
rec {
# Helpers
splitDomain = domain: splitString "." domain;
shortenList =
count: list:
let
len = length list;
in
if len <= count then list else (shortenList count (tail list));
# Modules
mkAttrOption = mkOption {
type = attrs;
default = { };
};
mkIntOption =
default:
mkOption {
type = int;
inherit default;
};
mkStrOption = mkOption {
type = str;
default = "";
};
mkPortOption =
default:
mkOption {
type = port;
inherit default;
};
mkPathOption =
default:
mkOption {
type = path;
inherit default;
};
# Domains
isRootDomain = domain: length (splitDomain domain) <= 2;
mkRootDomain = domain: concatStringsSep "." (shortenList 2 (splitDomain domain));
mkWildcardDomain = rootDomain: concatStringsSep "." ((singleton "*") ++ (splitDomain rootDomain));
mkHost = domain: if isRootDomain domain then domain else mkWildcardDomain (mkRootDomain domain);
}

View file

@ -1,66 +0,0 @@
{ lib, ... }:
let
inherit (builtins) toString;
inherit (lib)
mkMerge
mkEnableOption
singleton
mkIf
;
inherit (lib.pantheon)
mkAttrOption
mkRootDomain
mkPortOption
mkStrOption
;
networkingConfig =
{
config,
cfg,
name,
}:
mkIf (cfg.domain != "") {
assertions = singleton {
assertion = config.server.web-servers.nginx.enable;
message = "You must enable a web server if you want to set server.web-apps.${name}.domain.";
};
server.networking.ddns.domains = singleton (mkRootDomain cfg.domain);
server.web-servers.nginx.proxies = singleton {
source = cfg.domain;
target = "http://${config.hostname}:${toString cfg.port}";
};
};
in
{
modules.mkWebApp =
{
config,
name,
defaultPort,
persistDirs ? [ ],
#TODO: specify required secrets
extraOptions ? { },
extraConfig ? { },
}:
let
cfg = config.server.web-apps.${name};
in
{
options.server.web-apps.${name} = {
enable = mkEnableOption "";
port = mkPortOption defaultPort;
domain = mkStrOption;
openFirewall = mkEnableOption "";
extraCfg = mkAttrOption;
} // extraOptions;
config = mkIf cfg.enable (mkMerge [
{
inherit persistDirs;
networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = singleton cfg.port; };
}
(networkingConfig { inherit config cfg name; })
extraConfig
]);
};
}

View file

@ -1,38 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) mkOption;
inherit (lib.types) listOf str;
in
{
imports = [ inputs.impermanence.homeManagerModules.impermanence ];
options.persistDirs = mkOption {
type = listOf str;
default = [ ];
};
config = {
# Helper options
home.persistence."/persist/home/${config.home.username}" = {
directories = config.persistDirs;
allowOther = true;
};
# Global options
persistDirs = [
# For system activation
".ssh"
".config/sops/age"
];
programs.ssh.enable = true;
# To set colors properly when on ssh
programs.ssh.extraConfig = ''
Host *
SetEnv TERM=xterm-256color
'';
home.stateVersion = "24.11";
};
}

View file

@ -1,112 +0,0 @@
{
inputs,
lib,
config,
...
}:
let
inherit (lib) mkOption singleton;
inherit (lib.types)
listOf
str
coercedTo
submodule
shellPackage
;
inherit (lib.pantheon) mkStrOption;
inherit (lib.snowfall.fs) get-file;
rootDir = submodule {
options = {
directory = mkOption { type = str; };
user = mkOption {
type = str;
default = "root";
};
group = mkOption {
type = str;
default = "root";
};
mode = mkOption {
type = str;
default = "0755";
};
};
};
in
{
imports = [
inputs.sops-nix.nixosModules.sops
inputs.stylix.nixosModules.stylix
];
options = {
hostname = mkStrOption;
mainUser = {
name = mkStrOption;
publicKey = mkStrOption;
email = mkStrOption;
shell = mkOption {
type = shellPackage;
};
};
persistDirs = mkOption {
type = listOf (coercedTo str (d: { directory = d; }) rootDir);
default = [ ];
};
};
config = {
# Helper options
environment.persistence."/persist".directories = config.persistDirs;
# Global options
persistDirs = [
"/var/lib/systemd"
"/var/lib/nixos"
];
stylix.enable = true;
nixpkgs.config.allowUnfree = true;
nix.settings.experimental-features = [
"nix-command"
"flakes"
"pipe-operators"
];
nix.settings.trusted-users = [ "@wheel" ];
system.stateVersion = "25.05";
time.timeZone = "Asia/Singapore";
i18n.defaultLocale = "en_US.UTF-8";
users = {
# Don't allow imperative configuration
mutableUsers = false;
users.root.openssh.authorizedKeys.keys = [ config.mainUser.publicKey ];
groups.users = {
gid = 100;
members = [ "${config.mainUser.name}" ];
};
users."${config.mainUser.name}" = {
inherit (config.mainUser) shell;
uid = 1000;
isNormalUser = true;
hashedPasswordFile = config.sops.secrets."${config.mainUser.name}/hashedPassword".path;
extraGroups = [ "wheel" ];
openssh.authorizedKeys.keys = [ config.mainUser.publicKey ];
};
};
security.sudo.wheelNeedsPassword = false;
sops = {
defaultSopsFile = get-file "secrets/secrets.yaml";
age.sshKeyPaths = [ "/persist/home/${config.mainUser.name}/.ssh/id_ed25519" ];
secrets = {
"keys/openrouter" = { };
"keys/gemini" = { };
"keys/cloudflare" = { };
"keys/telegram_bot" = { };
"rafiq/hashedPassword".neededForUsers = true;
"rafiq/personalEmailPassword" = { };
"rafiq/workEmailPassword" = { };
};
};
environment.shellInit = # sh
''
export GEMINI_API_KEY=$(sudo cat ${config.sops.secrets."keys/gemini".path})
'';
};
}

View file

@ -1,6 +0,0 @@
{
services.pipewire = {
enable = true;
pulse.enable = true;
};
}

View file

@ -1,20 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkEnableOption mkIf singleton;
cfg = config.desktop.browser.tor-browser;
in
{
options.desktop.browser.tor-browser.enable = mkEnableOption "";
config = mkIf cfg.enable {
home-manager.sharedModules = singleton {
persistDirs = singleton ".tor project";
home.packages = singleton pkgs.tor-browser;
};
};
}

View file

@ -1,37 +0,0 @@
{
lib,
config,
pkgs,
...
}:
let
inherit (lib)
mkEnableOption
mkIf
singleton
optional
;
inherit (lib.pantheon) mkStrOption;
inherit (pkgs) font-awesome wl-clipboard-rs;
cfg = config.desktop;
in
{
options.desktop = {
enable = mkEnableOption "";
enableWaylandUtilities = mkEnableOption "";
mainMonitor = {
id = mkStrOption;
scale = mkStrOption;
resolution = mkStrOption;
refresh-rate = mkStrOption;
};
};
config = mkIf cfg.enable {
fonts.packages = singleton font-awesome;
services.getty.autologinUser = config.mainUser.name;
home-manager.sharedModules = optional cfg.enableWaylandUtilities {
home.packages = [ wl-clipboard-rs ];
};
};
}

View file

@ -1,37 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkEnableOption
mkIf
mkMerge
singleton
;
cfg = config.desktop.gaming;
in
{
options.desktop.gaming = {
steam.enable = mkEnableOption "";
prism-launcher.enable = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.steam.enable {
programs.steam = {
enable = true;
gamescopeSession.enable = true;
};
home-manager.sharedModules = singleton { persistDirs = singleton ".local/share/Steam"; };
})
(mkIf cfg.prism-launcher.enable {
home-manager.sharedModules = singleton {
home.packages = singleton pkgs.prismlauncher;
persistDirs = singleton ".local/share/PrismLauncher";
};
})
];
}

View file

@ -1,16 +0,0 @@
{ lib, config, ... }:
let
inherit (lib) singleton mkEnableOption;
cfg = config.desktop.launcher;
in
{
options.desktop.launcher = {
fuzzel.enable = mkEnableOption "";
wofi.enable = mkEnableOption "";
};
config.home-manager.sharedModules = singleton {
programs.fuzzel.enable = cfg.fuzzel.enable;
programs.wofi.enable = cfg.wofi.enable;
};
}

View file

@ -1,22 +0,0 @@
{ config, lib, ... }:
let
inherit (lib)
mkEnableOption
mkIf
mkMerge
singleton
;
cfg = config.desktop.lockscreen;
in
{
options.desktop.lockscreen = {
hyprlock.enable = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.hyprlock.enable {
security.pam.services.hyprlock = { };
home-manager.sharedModules = singleton { programs.hyprlock.enable = true; };
})
];
}

View file

@ -1,18 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkEnableOption optional singleton;
inherit (pkgs) vlc;
cfg = config.desktop.media-player;
in
{
options.desktop.media-player = {
vlc.enable = mkEnableOption "";
};
config.home-manager.sharedModules = optional cfg.vlc.enable { home.packages = singleton vlc; };
}

View file

@ -1,30 +0,0 @@
{ config, lib, ... }:
let
inherit (lib)
mkMerge
singleton
mkEnableOption
mkIf
;
cfg = config.desktop.services;
in
{
options.desktop.services = {
spotifyd.enable = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.spotifyd.enable {
networking.firewall.allowedTCPPorts = [ 5353 ];
networking.firewall.allowedUDPPorts = [ 5353 ];
home-manager.sharedModules = singleton {
services.spotifyd.enable = true;
services.spotifyd.settings.global = {
device_name = "${config.hostname}";
device_type = "computer";
zeroconf_port = 5353;
};
};
})
];
}

View file

@ -1,24 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) singleton mkIf mkEnableOption;
cfg = config.desktop.services.sunshine;
in
{
options.desktop.services.sunshine = {
enable = mkEnableOption "";
};
config = mkIf cfg.enable {
services.sunshine = {
enable = true;
capSysAdmin = true;
openFirewall = true;
settings = {
sunshine_name = config.hostname;
origin_pin_allowed = "wan";
origin_web_ui_allowed = "wan";
};
applications = { };
};
home-manager.sharedModules = singleton { persistDirs = singleton ".config/sunshine"; };
};
}

View file

@ -1,55 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkEnableOption mkIf singleton;
inherit (config.desktop) mainMonitor;
cfg = config.desktop.window-manager.hyprland;
in
{
options.desktop.window-manager.hyprland.enable = mkEnableOption "";
config = mkIf cfg.enable {
# Enable custom module for wayland utilities (clipboard etc.)
desktop.enableWaylandUtilities = true;
# Start Hyprland at boot only if not connecting through SSH
environment.loginShellInit = # sh
''
if [[ -z "$SSH_CLIENT" && -z "$SSH_CONNECTION" ]]; then
if uwsm check may-start; then
exec uwsm start hyprland-uwsm.desktop
fi
fi
'';
environment.variables = {
# Get Electron apps to use Wayland
ELECTRON_OZONE_PLATFORM_HINT = "auto";
NIXOS_OZONE_WL = "1";
};
programs.hyprland = {
enable = true;
# Use UWSM to have each process controlled by systemd init
withUWSM = true;
};
home-manager.sharedModules = singleton {
wayland.windowManager.hyprland = {
enable = true;
# This is needed for UWSM
systemd.enable = false;
# Null the packages since we use them system wide
package = null;
portalPackage = null;
settings.monitor = [ "${mainMonitor.id}, ${mainMonitor.resolution}@${mainMonitor.refresh-rate}, auto, ${mainMonitor.scale}" ];
};
xdg.configFile."uwsm/env".text = # sh
''
# Force apps to scale right with Wayland
export GDK_SCALE=${mainMonitor.scale}
export STEAM_FORCE_DESKTOPUI_SCALING=${mainMonitor.scale}
'';
xdg.configFile."uwsm/env-hyprland".text = # sh
''
export GDK_SCALE=${mainMonitor.scale}
export STEAM_FORCE_DESKTOPUI_SCALING=${mainMonitor.scale}
'';
};
};
}

View file

@ -1,30 +0,0 @@
{
config,
lib,
...
}:
let
inherit (lib.pantheon) mkIntOption mkStrOption;
cfg = config.machine.bootloader;
in
{
options.machine.bootloader = {
type = mkStrOption;
configurationLimit = mkIntOption 5;
};
config.boot = {
initrd.availableKernelModules = [
"nvme"
"xhci_pci"
"ahci"
"usbhid"
"usb_storage"
"sd_mod"
];
loader.efi.canTouchEfiVariables = true;
loader.systemd-boot = {
enable = cfg.type == "systemd-boot";
inherit (cfg) configurationLimit;
};
};
}

View file

@ -1,19 +0,0 @@
{ lib, modulesPath, ... }:
let
inherit (lib) singleton;
in
{
imports = [
(modulesPath + "/installer/scan/not-detected.nix")
];
config = {
services.fwupd.enable = true;
persistDirs = singleton "/var/lib/bluetooth";
hardware.bluetooth = {
enable = true;
settings.General.Experimental = true;
};
hardware.xone.enable = true;
};
}

View file

@ -1,116 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) mkIf mkEnableOption;
inherit (lib.pantheon) mkStrOption;
cfg = config.machine.drives.btrfs;
ephemeralRootCfg = {
boot.initrd.postDeviceCommands = lib.mkAfter ''
mkdir /btrfs_tmp
mount /dev/root_vg/root /btrfs_tmp
if [[ -e /btrfs_tmp/root ]]; then
mkdir -p /btrfs_tmp/old_roots
timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%-d_%H:%M:%S")
mv /btrfs_tmp/root "/btrfs_tmp/old_roots/$timestamp"
fi
delete_subvolume_recursively() {
IFS=$'\n'
for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do
delete_subvolume_recursively "/btrfs_tmp/$i"
done
btrfs subvolume delete "$1"
}
for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +30); do
delete_subvolume_recursively "$i"
done
btrfs subvolume create /btrfs_tmp/root
umount /btrfs_tmp
'';
programs.fuse.userAllowOther = true;
fileSystems."/persist".neededForBoot = true;
#FIXME: below should be in module or something
environment.persistence."/persist" = {
hideMounts = true;
files = [
"/etc/ssh/ssh_host_ed25519_key"
"/etc/ssh/ssh_host_ed25519_key.pub"
"/etc/ssh/ssh_host_rsa_key"
"/etc/ssh/ssh_host_rsa_key.pub"
"/etc/machine-id"
];
};
};
in
{
imports = [
inputs.disko.nixosModules.disko
inputs.impermanence.nixosModules.impermanence
];
options.machine.drives.btrfs = {
enable = mkEnableOption "";
drive = mkStrOption;
ephemeralRoot = mkEnableOption "";
};
config = mkIf cfg.enable (
{
boot.initrd.kernelModules = [ "dm-snapshot" ];
disko.devices.disk.main = {
device = cfg.drive;
type = "disk";
content.type = "gpt";
content.partitions = {
boot.name = "boot";
boot.size = "1M";
boot.type = "EF02";
esp.name = "ESP";
esp.size = "500M";
esp.type = "EF00";
esp.content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
};
swap.size = "4G";
swap.content = {
type = "swap";
resumeDevice = true;
};
root.name = "root";
root.size = "100%";
root.content = {
type = "lvm_pv";
vg = "root_vg";
};
};
};
disko.devices.lvm_vg.root_vg = {
type = "lvm_vg";
lvs.root.size = "100%FREE";
lvs.root.content.type = "btrfs";
lvs.root.content.extraArgs = [ "-f" ];
lvs.root.content.subvolumes = {
"/root".mountpoint = "/";
"/persist".mountpoint = "/persist";
"/persist".mountOptions = [
"subvol=persist"
"noatime"
];
"/nix".mountpoint = "/nix";
"/nix".mountOptions = [
"subvol=nix"
"noatime"
];
};
};
}
// ephemeralRootCfg
);
}

View file

@ -1,41 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkMerge
mkIf
mkEnableOption
singleton
;
cfg = config.machine.gpu;
in
{
options.machine.gpu = {
nvidia.enable = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.nvidia.enable {
hardware = {
graphics.enable = true;
graphics.extraPackages = singleton pkgs.nvidia-vaapi-driver;
nvidia.open = true;
nvidia.package = config.boot.kernelPackages.nvidiaPackages.latest;
};
services.xserver.videoDrivers = [ "nvidia" ];
nixpkgs.config.allowUnfree = true;
environment.variables = {
LIBVA_DRIVER_NAME = "nvidia";
__GLX_VENDOR_LIBRARY_NAME = "nvidia";
NVD_BACKEND = "direct";
};
nix.settings.substituters = [ "https://cuda-maintainers.cachix.org" ];
nix.settings.trusted-public-keys = [
"cuda-maintainers.cachix.org-1:0dq3bujKpuEPMCX6U4WylrUDZ9JyUG0VpVZa7CNfq5E="
];
})
];
}

View file

@ -1,21 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) singleton mkOption;
inherit (lib.types) enum;
cfg = config.machine.platform;
in
{
options.machine.platform = {
type = mkOption {
type = enum [
"amd"
"intel"
];
};
};
config = {
hardware.cpu.${cfg.type}.updateMicrocode = true;
boot.kernelModules = singleton "kvm-${cfg.type}";
};
}

View file

@ -1,45 +0,0 @@
{
config,
pkgs,
lib,
...
}:
let
inherit (lib)
mkEnableOption
mkIf
mkMerge
singleton
;
cfg = config.machine.usb;
in
{
options.machine.usb = {
automount = mkEnableOption "";
enableQmk = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.automount {
services.udisks2.enable = true;
home-manager.sharedModules = singleton {
services.udiskie = {
enable = true;
automount = true;
notify = true;
};
};
})
(mkIf cfg.enableQmk {
hardware.keyboard.qmk.enable = true;
services.udev = {
packages = with pkgs; [
vial
qmk
qmk-udev-rules
qmk_hid
];
};
})
];
}

View file

@ -1,22 +0,0 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib) mkIf mkEnableOption singleton;
cfg = config.machine.virtualisation.distrobox;
in
{
options.machine.virtualisation.distrobox = {
enable = mkEnableOption "";
};
config = mkIf cfg.enable {
machine.virtualisation.podman.enable = true;
home-manager.sharedModules = singleton {
home.packages = singleton pkgs.distrobox;
# persistDirs = [ ".local/share/containers" ];
};
};
}

View file

@ -1,32 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkEnableOption mkIf;
cfg = config.machine.virtualisation.podman;
in
{
options.machine.virtualisation.podman = {
enable = mkEnableOption "";
};
config = mkIf cfg.enable {
virtualisation = {
containers.enable = true;
podman = {
enable = true;
dockerCompat = true;
defaultNetwork.settings.dns_enabled = true;
};
};
users.users."${config.mainUser.name}" = {
extraGroups = [ "podman" ];
# https://wiki.nixos.org/wiki/Distrobox
# subGidRanges = singleton {
# count = 65536;
# startGid = 1000;
# };
# subUidRanges = singleton {
# count = 65536;
# startUid = 1000;
# };
};
};
}

View file

@ -1,28 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkDefault singleton;
in
{
sops.secrets = {
"tailscale/client-id".sopsFile = ./tailscale.yaml;
"tailscale/client-secret".sopsFile = ./tailscale.yaml;
};
networking = {
enableIPv6 = false;
useDHCP = mkDefault true;
hostName = config.hostname;
networkmanager.enable = true;
};
services.openssh = {
enable = true;
settings.PrintMotd = true;
};
services.tailscale = {
enable = true;
authKeyFile = config.sops.secrets."tailscale/client-secret".path;
authKeyParameters.preauthorized = true;
};
persistDirs = singleton "/var/lib/tailscale";
}

View file

@ -1,18 +0,0 @@
tailscale:
client-id: ENC[AES256_GCM,data:kQ4H9b2h8DN+5eTvwIYHZ6s=,iv:/nC3LM0qDNj3wIm9XZd7UUn5SxmAOA1dofsDGElKjVU=,tag:AIj5F7KkORujLDe+ZOxJgw==,type:str]
client-secret: ENC[AES256_GCM,data:O0cKyuK+FfK2E1mzQpkgybPrqEs0fH1y3jCOG6usT++6x3sWuJNvT56OIHpVNu8GH/6BIBsnenC1J/sVNTYIzA==,iv:FugIzSjNpoe9Bwy+x/GHl0BpCtbogQXpY7s3ICevQc0=,tag:1kQIO4ekjKuvexQ923YE3g==,type:str]
sops:
age:
- recipient: age12l33pas8eptwjc7ewux3d8snyzfzwz0tn9qg5kw8le79fswmjgjqdjgyy6
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGbTNsZE5lN2JOT1Jsd2hz
OWpDWTFzTW05Nzl5K1AyMmgxcVV2eHlBRlF3Cnc3VW5IN014ck8zM3BIWnBMNFFt
UnE4aGhGNERUOTlwZEJyNWF1Q1o0RXcKLS0tIFlZSFFoaDlOMnBMSFVyT3FMbFZj
ckl5RVZiMnkzV0RFQXN1aHZKM2doMnMKD6BjRdqsHiKDth4aBiZ1lvlcO1OgY36O
cGkZjuH45L4a0Y0kvptq3iZ/iPnmX8hw8n/gdplzUkpBzdsNPebvSg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2025-07-01T21:11:39Z"
mac: ENC[AES256_GCM,data:YWgrMqqJgrGe+40a9CSDpAAgwPOeGXRFb58c6X6PxDHve3u5vQfHh+wkC0TFxadMsYcJTczRYf8YWuAwf7kFoO7ofYs+PfEi4ydKhl8WY9nXTsq+BFT4rDl/BaCfQw6qWD5/TKTtxm2pdtBNrG7bNeZJ8cVSOO/wsjoqrrbh3fk=,iv:8BXOX5O5apYLhZOWihagQBVldmsVoV+uEcejcO3cC0I=,tag:vansSul5Ebwooay48uYNZQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.10.2

View file

@ -1,84 +0,0 @@
{
lib,
config,
pkgs,
...
}:
let
inherit (lib) singleton;
cfg = config.server.databases;
in
{
options.server.databases = {
mongodb = {
enable = lib.mkEnableOption "the MongoDB server";
port = lib.pantheon.mkPortOption 27017;
};
mysql = {
enable = lib.mkEnableOption "the MySQL server";
port = lib.pantheon.mkPortOption 3306;
};
postgresql = {
enable = lib.mkEnableOption "the postgresql server";
port = lib.pantheon.mkPortOption 5432;
};
};
config = lib.mkMerge [
(lib.mkIf cfg.postgresql.enable {
networking.firewall.allowedTCPPorts = lib.singleton cfg.postgresql.port;
persistDirs = singleton {
directory = builtins.toString config.services.postgresql.dataDir;
user = "postgres";
group = "postgres";
};
services.postgresql = {
enable = true;
enableTCPIP = true;
settings = { inherit (cfg.postgresql) port; };
authentication = lib.mkOverride 10 ''
#type database DBuser auth-method
local all all trust
# ipv4
host all all 0.0.0.0/0 trust
'';
ensureDatabases = singleton "alphastory";
ensureUsers = singleton {
name = "alphastory";
ensureDBOwnership = true;
};
};
})
(lib.mkIf cfg.mongodb.enable {
networking.firewall.allowedTCPPorts = [ cfg.mongodb.port ];
persistDirs = singleton {
directory = builtins.toString config.services.mongodb.dbpath;
user = "mongodb";
group = "mongodb";
};
services.mongodb = {
enable = true;
bind_ip = "0.0.0.0";
extraConfig = ''
net.port: ${builtins.toString cfg.mongodb.port}
'';
};
})
(lib.mkIf cfg.mysql.enable {
networking.firewall.allowedTCPPorts = [ cfg.mysql.port ];
persistDirs = singleton {
directory = builtins.toString config.services.mysql.dataDir;
user = "mysql";
group = "mysql";
};
services.mysql = {
enable = true;
package = pkgs.mariadb;
settings.mysqld = {
inherit (cfg.mysql) port;
};
};
})
];
}

View file

@ -1,43 +0,0 @@
{ lib, config, ... }:
{
options.server.mountHelios = lib.mkEnableOption "";
config = lib.mkIf config.server.mountHelios {
sops.secrets."rafiq/oldSMBCredentials" = { };
sops.templates."smb-credentials".content = ''
username=rafiq
password=${config.sops.placeholder."rafiq/oldSMBCredentials"}
'';
fileSystems = {
"/media/helios/data" = {
device = "//helios/data";
fsType = "cifs";
options = [
"x-systemd.automount"
"x-systemd.requires=tailscaled.service"
"x-systemd.mount-timeout=0"
];
};
"/media/helios/rafiqcloud" = {
device = "//helios/rafiqcloud";
fsType = "cifs";
options = [
"x-systemd.automount"
"x-systemd.requires=tailscaled.service"
"x-systemd.mount-timeout=0"
"credentials=${config.sops.templates."smb-credentials".path}"
];
};
"/media/helios/rafiqmedia" = {
device = "//helios/rafiqmedia";
fsType = "cifs";
options = [
"x-systemd.automount"
"x-systemd.requires=tailscaled.service"
"x-systemd.mount-timeout=0"
"credentials=${config.sops.templates."smb-credentials".path}"
];
};
};
};
}

View file

@ -1,62 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) mkIf mkOption mkEnableOption;
inherit (lib.types) enum str listOf;
inherit (lib.lists) unique;
inherit (builtins) map;
cfg = config.server.networking.ddns;
mkDomain = domain_name: {
inherit domain_name;
sub_domains = [
"@"
"*"
];
};
# Sanitize the list of domains with unique so we can add to it with every service.
mkDomains = map mkDomain (unique cfg.domains);
in
{
options.server.networking.ddns = {
enable = mkEnableOption "";
type = mkOption {
type = enum [ "godns" ];
default = "godns";
};
domains = mkOption {
type = listOf str;
default = [ ];
};
};
config = mkIf cfg.enable {
services.godns = {
enable = if (cfg.type == "godns") then true else false;
loadCredential = [
"cf_token:${config.sops.secrets."keys/cloudflare".path}"
"telegram_bot_token:${config.sops.secrets."keys/telegram_bot".path}"
];
settings = {
provider = "Cloudflare";
login_token_file = "$CREDENTIALS_DIRECTORY/cf_token";
domains = mkDomains;
resolver = "1.1.1.1";
ip_urls = [
"https://wtfismyip.com/text"
"https://api.ipify.org"
"https://myip.biturl.top"
"https://api-ipv4.ip.sb/ip"
];
ip_type = "IPv4";
interval = 300;
notify = {
telegram = {
enabled = true;
bot_api_key_file = "$CREDENTIALS_DIRECTORY/telegram_bot_token";
chat_id = "384288005";
message_template = "Domain *{{ .Domain }} has been updated to %0A{{ .CurrentIP }}";
};
};
};
};
};
}

View file

@ -1,34 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) singleton;
inherit (lib.pantheon.modules) mkWebApp;
upstreamCfg = config.services.comfyUi;
in
mkWebApp {
inherit config;
name = "comfy-ui";
defaultPort = 8188;
persistDirs = singleton {
directory = upstreamCfg.dataDir;
inherit (upstreamCfg) user group;
mode = "777";
};
extraConfig = {
assertions = singleton {
assertion = config.machine.gpu.nvidia.enable;
message = "You must run the comfy-ui service only with an nvidia gpu.";
};
services.comfyUi = {
enable = true;
listenHost = "0.0.0.0";
};
};
}
// {
imports = [ inputs.stable-diffusion-webui-nix.nixosModules.default ];
}

View file

@ -1,41 +0,0 @@
{ config, lib, ... }:
let
inherit (lib) singleton optional;
inherit (lib.pantheon) mkPortOption;
inherit (lib.pantheon.modules) mkWebApp;
cfg = config.server.web-apps.forgejo;
upstreamCfg = config.services.forgejo;
in
mkWebApp {
inherit config;
name = "forgejo";
defaultPort = 3000;
persistDirs = singleton {
directory = upstreamCfg.stateDir;
inherit (upstreamCfg) user group;
};
extraOptions = {
sshPort = mkPortOption 2222;
};
extraConfig = {
networking.firewall.allowedTCPPorts = optional cfg.openFirewall cfg.sshPort;
services.forgejo = {
enable = true;
settings = {
server = {
DOMAIN = cfg.domain;
ROOT_URL = "https://${cfg.domain}/";
HTTP_PORT = cfg.port;
START_SSH_SERVER = true;
SSH_PORT = cfg.sshPort;
};
repository = {
USE_COMPAT_SSH_URI = false;
ENABLE_PUSH_CREATE_USER = true;
ENABLE_PUSH_CREATE_ORG = true;
};
"repository.signing".FORMAT = "ssh";
};
};
};
}

View file

@ -1,17 +0,0 @@
{ lib, config, ... }:
let
inherit (lib.pantheon.modules) mkWebApp;
cfg = config.server.web-apps.glance;
in
mkWebApp {
inherit config;
name = "glance";
defaultPort = 8080;
extraConfig = {
services.glance = {
enable = true;
settings.server.host = "0.0.0.0";
settings.server.port = cfg.port;
};
};
}

View file

@ -1,80 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) singleton;
inherit (lib.pantheon) mkStrOption;
inherit (lib.pantheon.modules) mkWebApp;
cfg = config.server.web-apps.librechat;
upstreamCfg = config.services.librechat;
in
mkWebApp {
inherit config;
name = "librechat";
defaultPort = 3080;
persistDirs = singleton {
directory = upstreamCfg.dataDir;
inherit (upstreamCfg) user group;
};
extraOptions.mongodbURI = mkStrOption // {
default = "mongodb://${config.hostname}:27017/LibreChat";
};
extraConfig = {
sops.secrets = {
"librechat/creds_key" = { };
"librechat/creds_iv" = { };
"librechat/jwt_secret" = { };
"librechat/jwt_refresh_secret" = { };
};
services.librechat = {
enable = true;
openFirewall = true;
inherit (cfg) port;
env = {
HOST = "0.0.0.0";
ALLOW_REGISTRATION = "true";
NO_INDEX = "true";
MONGO_URI = cfg.mongodbURI;
DOMAIN_CLIENT = cfg.domain;
DOMAIN_SERVER = cfg.domain;
ENDPOINTS = "anthropic,agents,google";
};
credentials = {
CREDS_KEY = config.sops.secrets."librechat/creds_key".path;
CREDS_IV = config.sops.secrets."librechat/creds_iv".path;
JWT_SECRET = config.sops.secrets."librechat/jwt_secret".path;
JWT_REFRESH_SECRET = config.sops.secrets."librechat/jwt_refresh_secret".path;
OPENROUTER_KEY = config.sops.secrets."keys/openrouter".path;
GOOGLE_KEY = config.sops.secrets."keys/gemini".path;
};
settings = {
version = "1.1.4";
cache = true;
endpoints.custom = [
{
name = "OpenRouter";
apiKey = "\${OPENROUTER_KEY}";
baseURL = "https://openrouter.ai/api/v1";
models.default = [ "meta-llama/llama-3-70b-instruct" ];
models.fetch = true;
titleConvo = true;
titleModel = "current_model";
modelDisplayLabel = "OpenRouter";
}
];
interface = {
privacyPolicy = {
externalUrl = "https://librechat.ai/privacy-policy";
openNewTab = true;
};
};
};
};
};
}
// {
imports = singleton "${inputs.rrvsh-nixpkgs}/nixos/modules/services/web-apps/librechat.nix";
}

View file

@ -1,24 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib.pantheon.modules) mkWebApp;
cfg = config.server.web-apps.rrv-sh;
in
mkWebApp {
inherit config;
name = "rrv-sh";
defaultPort = 2309;
extraConfig = {
services.rrv-sh = {
enable = true;
inherit (cfg) port;
};
};
}
// {
imports = [ inputs.rrv-sh.nixosModules.default ];
}

View file

@ -1,34 +0,0 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) singleton;
inherit (lib.pantheon.modules) mkWebApp;
upstreamCfg = config.services.sd-webui-forge;
in
mkWebApp {
inherit config;
name = "sd-webui-forge";
defaultPort = 7860;
persistDirs = singleton {
directory = upstreamCfg.dataDir;
inherit (upstreamCfg) user group;
};
extraConfig = {
assertions = singleton {
assertion = config.machine.gpu.nvidia.enable;
message = "You must run the sd-webui-forge service only with an nvidia gpu.";
};
services.sd-webui-forge = {
enable = true;
listen = true;
extraArgs = "--cuda-malloc";
};
};
}
// {
imports = [ inputs.stable-diffusion-webui-nix.nixosModules.default ];
}

View file

@ -1,34 +0,0 @@
{ config, lib, ... }:
let
inherit (lib)
mkMerge
mkIf
mkEnableOption
singleton
;
cfg = config.server.web-servers;
in
{
options.server.web-servers = {
enableSSL = mkEnableOption "";
};
config = mkMerge [
(mkIf cfg.enableSSL {
security.acme = {
acceptTerms = true;
defaults = {
inherit (config.mainUser) email;
dnsProvider = "cloudflare";
credentialFiles."CLOUDFLARE_DNS_API_TOKEN_FILE" = config.sops.secrets."keys/cloudflare".path;
};
certs = {
"rrv.sh".extraDomainNames = singleton "*.rrv.sh";
"bwfiq.com".extraDomainNames = singleton "*.bwfiq.com";
"slayment.com".extraDomainNames = singleton "*.slayment.com";
"aenyrathia.wiki".extraDomainNames = singleton "*.aenyrathia.wiki";
};
};
})
];
}

View file

@ -1,119 +0,0 @@
{ config, lib, ... }:
let
inherit (lib)
mkMerge
mkOption
mkEnableOption
mkIf
singleton
;
inherit (lib.types) listOf submodule attrs;
inherit (lib.pantheon) mkStrOption mkPathOption mkRootDomain;
inherit (builtins) listToAttrs map;
cfg = config.server.web-servers.nginx;
sslCheck = good: bad: if config.server.web-servers.enableSSL then good else bad;
defaultSink = mkIf cfg.enableDefaultSink {
"_" = {
default = true;
rejectSSL = sslCheck true false;
locations."/" = {
return = "444";
};
};
};
pages = listToAttrs (
map (page: {
name = page.domain;
value = {
addSSL = sslCheck true false;
useACMEHost = sslCheck (mkRootDomain page.domain) null;
acmeRoot = null; # needed for DNS validation
locations = {
"/" = {
inherit (page) root;
} // page.extraConfig;
} // page.locations;
};
}) cfg.pages
);
proxyPasses = listToAttrs (
map (proxy: {
name = proxy.source;
value = {
addSSL = sslCheck true false;
useACMEHost = sslCheck (mkRootDomain proxy.source) null;
acmeRoot = null; # needed for DNS validation
locations = {
"/" = {
proxyPass = proxy.target;
} // proxy.extraConfig;
} // proxy.locations;
};
}) cfg.proxies
);
in
{
options.server.web-servers.nginx = {
enable = mkEnableOption "the Nginx server";
openFirewall = mkEnableOption "" // {
default = true;
};
enableDefaultSink = mkEnableOption "" // {
default = true;
};
pages = mkOption {
default = [ ];
type = listOf (submodule {
options = {
domain = mkStrOption;
root = mkPathOption "";
extraConfig = lib.mkOption {
type = attrs;
default = { };
};
locations = lib.mkOption {
type = attrs;
default = { };
};
};
});
};
proxies = mkOption {
default = [ ];
type = listOf (submodule {
options = {
source = mkStrOption;
target = mkStrOption;
extraConfig = lib.mkOption {
type = attrs;
default = { };
};
locations = lib.mkOption {
type = attrs;
default = { };
};
};
});
};
};
config = mkIf cfg.enable {
networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [
443
80
];
users.users.nginx.extraGroups = singleton "acme";
services.nginx = {
enable = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
recommendedOptimisation = true;
recommendedGzipSettings = true;
virtualHosts = mkMerge [
defaultSink
proxyPasses
pages
];
};
};
}

45
nix/configurations.nix Normal file
View file

@ -0,0 +1,45 @@
{
config,
lib,
inputs,
...
}:
let
inherit (lib) nixosSystem;
inherit (lib.lists) optional;
inherit (lib.attrsets) mapAttrs;
inherit (cfg.lib.modules) forAllUsers';
cfg = config.flake;
globalCfg = name: hostConfig: {
useGlobalPkgs = true;
useUserPackages = true;
extraSpecialArgs = {
inherit hostConfig;
hostName = name;
};
sharedModules = [ cfg.modules.homeManager.default ];
users = forAllUsers' (name: _: cfg.modules.homeManager.${name});
};
hosts = cfg.manifest.hosts or { };
mkConfigurations =
class: hosts:
mapAttrs (
name: value:
if class == "nixos" then
nixosSystem {
specialArgs.hostName = name;
modules = [
cfg.modules.nixos.default
inputs.home-manager.nixosModules.home-manager
{ home-manager = globalCfg name value; }
(value.extraCfg or { })
] ++ optional value.graphical cfg.modules.nixos.graphical;
}
else
{ }
) hosts;
in
{
imports = [ inputs.home-manager.flakeModules.home-manager ];
flake.nixosConfigurations = mkConfigurations "nixos" hosts.nixos;
}

18
nix/files/cheatsheet.nix Normal file
View file

@ -0,0 +1,18 @@
{ lib, config, ... }:
let
inherit (builtins) concatStringsSep;
inherit (lib.lists) singleton;
in
{
text.cheatsheet = concatStringsSep "\n" [
"`__curPos.file` will give the full evaluated path of the nix file it is called in. See [this issue](https://github.com/NixOS/nix/issues/5897#issuecomment-1012165198) for more information."
];
perSystem =
{ pkgs, ... }:
{
files.files = singleton {
path_ = "docs/cheatsheet.md";
drv = pkgs.writeText "cheatsheet.md" config.text.cheatsheet;
};
};
}

13
nix/files/gitignore.nix Normal file
View file

@ -0,0 +1,13 @@
{ config, ... }:
{
perSystem =
{ pkgs, ... }:
{
files.files = [
{
path_ = ".gitignore";
drv = pkgs.writeText ".gitignore" config.text.gitignore;
}
];
};
}

54
nix/files/readme.nix Normal file
View file

@ -0,0 +1,54 @@
{ config, ... }:
{
text.readme = {
heading = "Pantheon";
description = # markdown
''
This flake serves as a monorepo for my systems (using IaC), dotfiles, and scripts.
It's hosted at https://git.rrv.sh/rrvsh/pantheon, and mirrored to https://github.com/rrvsh/pantheon.
'';
order = [
"Structure"
"Acknowledgements"
];
parts."Acknowledgements" = # markdown
''
Thanks to the following for inspiring this configuration. I highly recommend you look through their writings and configurations.
- [ornicar](https://github.com/ornicar/dotfiles) which is where I first heard of NixOS
- [No Boilerplate](https://www.youtube.com/watch?v=CwfKlX3rA6E&pp=0gcJCfwAo7VqN5tD) for making me finally try the OS
- [ryan4yin](https://nixos-and-flakes.thiscute.world/) for being an amazing introduction to NixOS, home-manager, and flakes
- [NotAShelf](https://github.com/NotAShelf/) for their blog and for the wonderful [NVF](https://github.com/notashelf/nvf)
- [mightyiam](https://github.com/mightyiam/infra) for their infrastructure repo using flake-parts
- [drupol](https://not-a-number.io/2025/refactoring-my-infrastructure-as-code-configurations/) for this blog post which convinced me to rebase my infra to use flake-parts
'';
parts."Structure" = # markdown
''
The system configurations are defined in [`flake.manifest`](nix/manifest.nix).
`flake.manifest.owner` provides the attributes for the administrator user, including username and pubkey.
`flake.manifest.hosts` provides the specifications for the system configurations that should be exposed by the flake as nixosConfigurations.
`flake.modules.nixos.*` provide NixOS options and configurations.
The attribute `flake.modules.nixos.default` provides options that will be applied to every system of that class.
You can use it as seen [here](nix/modules/flake/home-manager.nix):
```nix
flake.modules.nixos.default.imports = [ inputs.home-manager.nixosModules.default ];
```
The other attributes under `flake.modules.nixos` should be opt-in, i.e. provide options that will be set in the profiles.
`flake.profiles.nixos` provides profiles which use the options defined in `flake.modules.nixos` to define different roles for each system, such as graphical, laptop, headless, etc.
Options should not be defined here.
`flake.contracts.nixos.*` will provide contracts, such as reverse proxies or databases, which will configure options on the provider and receiver host.
'';
};
perSystem =
{ pkgs, ... }:
{
files.files = [
{
path_ = "docs/README.md";
drv = pkgs.writeText "README.md" config.text.readme;
}
];
};
}

View file

@ -0,0 +1,3 @@
{
debug = true;
}

28
nix/flake-parts/files.nix Normal file
View file

@ -0,0 +1,28 @@
{
inputs,
withSystem,
lib,
config,
...
}:
let
inherit (builtins) map head;
inherit (lib.lists) concatStringsSep;
mkListEntry = x: "- [" + x.path_ + "](" + x.path_ + ")";
listOfGeneratedFiles = withSystem (head config.systems) (psArgs: psArgs.config.files.files);
in
{
imports = [ inputs.files.flakeModules.default ];
perSystem = psArgs: {
make-shells.default.packages = [ psArgs.config.files.writer.drv ];
};
text.readme.parts."Generated Files" = concatStringsSep "\n" (
[
"This flake uses the [files flake-parts module](https://flake.parts/options/files.html) to generate documentation."
"The list of generated files are:"
]
++ (map mkListEntry listOfGeneratedFiles)
);
}

View file

@ -0,0 +1,24 @@
{ inputs, ... }:
{
imports = [ inputs.git-hooks.flakeModule ];
text.gitignore = ".pre-commit-config.*";
perSystem = psArgs: {
pre-commit.settings.hooks = {
# Nix Linters
deadnix.enable = true;
statix.enable = true;
nil.enable = true;
nixfmt-rfc-style.enable = true;
# Flake Health Checks
flake-checker.enable = true;
# Misc
mixed-line-endings.enable = true;
trim-trailing-whitespace.enable = true;
#TODO: figure out vale
#TODO: make nix develop work
#TODO: add nix flake check
#TODO: add write-files
};
make-shells.default.shellHook = psArgs.config.pre-commit.installationScript;
};
}

View file

@ -0,0 +1,5 @@
{ inputs, ... }:
{
#TODO: add to readme
imports = [ inputs.make-shell.flakeModules.default ];
}

View file

@ -0,0 +1,4 @@
{ inputs, ... }:
{
imports = [ inputs.flake-parts.flakeModules.modules ];
}

4
nix/flake-parts/text.nix Normal file
View file

@ -0,0 +1,4 @@
{ inputs, ... }:
{
imports = [ inputs.text.flakeModules.default ];
}

View file

@ -23,8 +23,6 @@
enable = true;
format.type = "ruff";
lsp.server = "pyright";
uv.enable = true;
uv.setupOpts.picker_integration = true;
};
rust.enable = true;
rust.crates.enable = true;

View file

@ -0,0 +1,9 @@
{ pkgs, ... }:
pkgs.writeShellScriptBin "note" # bash
''
zk edit -i
pushd ~/notebook > /dev/null
git add .
commit -u
popd > /dev/null
''

View file

@ -1,6 +1,6 @@
{ pkgs, lib, ... }:
{ pkgs }:
let
inherit (lib) getExe;
inherit (pkgs.lib) getExe;
in
pkgs.writeShellScriptBin "rebuild" # sh
''
@ -71,7 +71,7 @@ pkgs.writeShellScriptBin "rebuild" # sh
local NEW_GENERATION=$(ssh "$1" readlink /nix/var/nix/profiles/system | cut -d- -f2)
info "$1 - New generation is $NEW_GENERATION. Current is $CURRENT_GENERATION."
if [ ! $NEW_GENERATION -gt $CURRENT_GENERATION ]; then
warn "New config was not added to bootloader."
warn "New config was not added to bootloader."
fi
fi
}
@ -102,10 +102,10 @@ pkgs.writeShellScriptBin "rebuild" # sh
hostnames=$(nix flake show --all-systems --json | , jq -r '.nixosConfigurations | keys | .[]')
for host in ''${hostnames[@]}; do
info "Checking if $host is reachable..."
if ping -c 1 -W 1 "$host" > /dev/null 2>&1 ; then
if ping -c 1 -W 1 "$host" > /dev/null 2>&1 ; then
info "$host is reachable."
reachable_hosts+=("$host")
else
else
warn "$host is unreachable."
fi
done

145
nix/homes/rafiq/default.nix Normal file
View file

@ -0,0 +1,145 @@
{ lib, inputs, ... }:
let
inherit (lib.strings) concatStrings;
in
{
flake.modules.homeManager.rafiq =
{ pkgs, ... }:
{
imports = [
inputs.nvf.homeManagerModules.default
inputs.nix-index-database.hmModules.nix-index
];
persistDirs = [
".local/share/zoxide"
"notebook"
];
xdg.configFile."aichat/config.yaml".text = ''
model: gemini:gemini-2.0-flash
clients:
- type: gemini
'';
home = {
sessionVariables = {
EDITOR = "nvim";
FETCH = "hyfetch";
FILE_BROWSER = "yazi";
SHELL = "fish";
};
shellAliases = {
fetch = "hyfetch";
windows = "sudo systemctl reboot --boot-loader-entry=auto-windows";
v = "$EDITOR";
e = "edit";
cd = "z"; # zoxide
ai = "aichat -r %shell% -e";
};
packages = with pkgs; [
fastfetch
ripgrep
aichat
(import ./_scripts/edit.nix { inherit pkgs; })
(import ./_scripts/commit.nix { inherit pkgs; })
(import ./_scripts/note.nix { inherit pkgs; })
(import ./_scripts/rebuild.nix { inherit pkgs; })
];
};
programs = {
nvf.enable = true;
nvf.settings.vim = {
syntaxHighlighting = true;
hideSearchHighlight = true;
searchCase = "ignore";
undoFile.enable = true;
telescope.enable = true;
fzf-lua.enable = true;
git.enable = true;
autopairs.nvim-autopairs.enable = true;
autocomplete = import ./_nvf/autocomplete.nix { inherit lib; };
binds = import ./_nvf/binds.nix;
languages = import ./_nvf/languages.nix;
lsp = import ./_nvf/lsp.nix;
navigation = import ./_nvf/navigation.nix;
notes.todo-comments.enable = true;
options = {
autoindent = true;
backspace = "indent,eol,start";
cursorline = true;
expandtab = true;
shiftwidth = 2;
smartindent = true;
tabstop = 2;
};
snippets = import ./_nvf/snippets.nix { inherit pkgs; };
statusline = import ./_nvf/statusline.nix;
treesitter = {
autotagHtml = true;
fold = true;
indent.disable = [ "markdown" ];
textobjects.enable = true;
};
ui = import ./_nvf/ui.nix;
utility = import ./_nvf/utility.nix;
visuals = import ./_nvf/visuals.nix;
};
zk = {
enable = true;
settings.notebook.dir = "~/notebook";
};
hyfetch = {
enable = true;
settings = {
preset = "bisexual";
mode = "rgb";
light_dark = "dark";
lightness = 0.5;
color_align = {
# Flag color alignment
mode = "horizontal";
fore_back = null;
};
backend = "fastfetch";
};
};
tealdeer.enable = true;
tealdeer.enableAutoUpdates = true;
direnv = {
enable = true;
nix-direnv.enable = true;
};
zoxide.enable = true;
nix-index.enable = true;
nix-index-database.comma.enable = true;
fzf.enable = true;
fzf.enableZshIntegration = true;
yazi = {
enable = true;
shellWrapperName = "t";
settings.mgr.sort_by = "natural";
};
fish.enable = true;
starship = {
enable = true;
settings = {
add_newline = false;
format = concatStrings [
# First Line
## Left Prompt
"$hostname$directory"
"$fill"
## Right Prompt
"$all"
# Second Line
## Left Prompt
"$character"
];
git_branch.format = "[$symbol$branch(:$remote_branch)]($style) ";
shlvl.disabled = false;
username.disabled = true;
fill.symbol = " ";
};
};
};
};
}

View file

@ -0,0 +1,288 @@
{
lib,
inputs,
config,
...
}:
let
cfg = config.flake;
in
{
allowedUnfreePackages = [
"stremio-shell"
"stremio-server"
"steam"
"steam-unwrapped"
];
flake.modules.nixos.graphical =
{ config, pkgs, ... }:
{
fonts.packages = [ pkgs.font-awesome ];
services.getty.autologinUser = cfg.admin.username;
# Start Hyprland at boot only if not connecting through SSH
environment.loginShellInit = # sh
''
if [[ -z "$SSH_CLIENT" && -z "$SSH_CONNECTION" ]]; then
if uwsm check may-start; then
exec uwsm start hyprland-uwsm.desktop
fi
fi
'';
environment.variables = {
# Get Electron apps to use Wayland
ELECTRON_OZONE_PLATFORM_HINT = "auto";
NIXOS_OZONE_WL = "1";
};
programs = {
hyprland = {
enable = true;
# Use UWSM to have each process controlled by systemd init
withUWSM = true;
};
steam = {
enable = true;
gamescopeSession.enable = true;
};
};
security.pam.services.hyprlock = { };
services.sunshine = {
enable = true;
capSysAdmin = true;
openFirewall = true;
settings = {
sunshine_name = config.networking.hostName;
origin_pin_allowed = "wan";
origin_web_ui_allowed = "wan";
};
applications = { };
};
# spotifyd
networking.firewall.allowedTCPPorts = [ 5353 ];
networking.firewall.allowedUDPPorts = [ 5353 ];
};
flake.modules.homeManager.rafiq =
{
pkgs,
config,
hostName,
hostConfig,
...
}:
let
inherit (lib.modules) mkMerge mkIf;
inherit (builtins) map listToAttrs;
inherit (lib.lists) findFirstIndex;
inherit (inputs.nur.legacyPackages.${pkgs.stdenv.hostPlatform.system}.repos.rycee) firefox-addons;
profiles = listToAttrs (
map (name: {
inherit name;
# If there are duplicate profile names, findFirstIndex will cause issues.
value = profileCfg (findFirstIndex (x: x == name) null syncedProfiles);
}) syncedProfiles
);
syncedProfiles = [
"rafiq"
"test"
];
profileCfg = id: {
inherit id;
settings."extensions.autoDisableScopes" = 0; # Auto enable extensions
extensions = {
force = true;
packages = with firefox-addons; [
darkreader
gesturefy
sponsorblock
ublock-origin
];
};
};
in
mkIf config.graphical {
stylix = {
image = ./wallpaper.png;
targets = {
firefox.colorTheme.enable = true;
firefox.profileNames = syncedProfiles;
waybar.addCss = false;
};
};
persistDirs = [
"docs"
"repos"
"vids"
"tmp"
".cache/Smart Code ltd/Stremio"
".local/share/Smart Code ltd/Stremio"
".mozilla/firefox"
".tor project"
".local/share/Steam"
".local/share/PrismLauncher"
".config/sunshine"
];
home = {
packages = with pkgs; [
prismlauncher
stremio
tor-browser
vlc
wl-clipboard-rs
];
sessionVariables = {
BROWSER = "firefox";
LAUNCHER = "fuzzel";
LOCKSCREEN = "hyprlock";
NOTIFICATION_DAEMON = "mako";
TERMINAL = "ghostty";
STATUS_BAR = "waybar";
};
};
programs = {
fuzzel.enable = true;
obs-studio.enable = true;
vesktop.enable = true;
thunderbird.enable = true;
thunderbird.profiles.rafiq.isDefault = true;
firefox = {
enable = true;
inherit profiles;
};
hyprlock = {
enable = true;
settings = {
general.hide_cursor = true;
general.ignore_empty_input = true;
background.blur_passes = 5;
background.blur_size = 5;
label = {
text = ''hi, $USER.'';
font_size = 32;
position = "0, 0";
halign = "center";
valign = "center";
zindex = 1;
shadow_passes = 5;
shadow_size = 5;
};
input-field = {
placeholder_text = "";
fade_on_empty = true;
size = "200, 45";
position = "0, -5%";
halign = "center";
valign = "center";
zindex = 1;
shadow_passes = 5;
shadow_size = 5;
};
};
};
ghostty = {
enable = true;
settings = {
confirm-close-surface = false;
};
};
waybar = {
enable = true;
settings = [
{
layer = "top";
modules-left = [
"pulseaudio"
];
modules-right = [
"battery"
"clock"
];
"pulseaudio" = {
format = "{icon} {volume}%";
format-muted = "";
format-icons.default = [
""
""
];
on-click = "${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
};
"clock" = {
interval = 1;
format = "{:%F %T}";
};
"battery" = {
interval = 1;
bat-compatibility = true;
};
}
];
style = # css
''
window#waybar {
background-color: rgba(0, 0, 0, 0);
}
#pulseaudio,
#battery,
#clock {
padding-top: 5px;
padding-bottom: 5px;
padding-right: 5px;
color: #ffffff;
}
'';
};
};
services = {
spotifyd.enable = true;
spotifyd.settings.global = {
device_name = "${hostName}";
device_type = "computer";
zeroconf_port = 5353;
};
mako.enable = true;
mako.settings.default-timeout = 10000;
};
wayland.windowManager.hyprland = {
enable = true;
# This is needed for UWSM
systemd.enable = false;
# Null the packages since we use them system wide
package = null;
portalPackage = null;
settings = mkMerge [
(import ./_hyprland/decoration.nix)
(import ./_hyprland/keybinds.nix { inherit pkgs; })
{
ecosystem.no_update_news = true;
xwayland.force_zero_scaling = true;
monitor =
let
mainMonitor = hostConfig.machine.monitors.main;
in
[
"${mainMonitor.id}, ${mainMonitor.resolution}@${mainMonitor.refresh-rate}, auto, ${mainMonitor.scale}"
", preferred, auto, 1"
];
exec-once = [
"uwsm app -- $LOCKSCREEN"
"uwsm app -- $NOTIFICATION_DAEMON"
"uwsm app -- $STATUS_BAR"
];
}
];
};
# xdg.configFile."uwsm/env".text = # sh
# ''
# # Force apps to scale right with Wayland
# export GDK_SCALE=${mainMonitor.scale}
# export STEAM_FORCE_DESKTOPUI_SCALING=${mainMonitor.scale}
# '';
# xdg.configFile."uwsm/env-hyprland".text = # sh
# ''
# export GDK_SCALE=${mainMonitor.scale}
# export STEAM_FORCE_DESKTOPUI_SCALING=${mainMonitor.scale}
# '';
};
}

View file

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Before After
Before After

23
nix/homes/rafiq/git.nix Normal file
View file

@ -0,0 +1,23 @@
{
flake.modules.homeManager.rafiq = {
home.shellAliases = {
gs = "git status";
gc = "git commit";
gcam = "git commit -am";
gu = "git push";
gy = "git pull";
gdh = "git diff HEAD";
};
programs.git = {
enable = true;
signing.signByDefault = true;
extraConfig = {
init.defaultBranch = "prime";
push.autoSetupRemote = true;
pull.rebase = false;
core.editor = "$EDITOR";
gpg.format = "ssh";
};
};
};
}

54
nix/lib/attrsets.nix Normal file
View file

@ -0,0 +1,54 @@
{ lib, ... }:
let
inherit (builtins) attrNames head;
inherit (lib.trivial) pipe;
inherit (lib.attrsets) filterAttrs;
in
{
flake.lib.attrsets = {
/**
`firstAttrNameMatching pred set` filters an attribute set `set` based on a predicate `pred`
and returns the *first* attribute name that satisfies the predicate.
# Example
```nix
let
mySet = {
a = { value = 1; };
b = { value = 2; };
c = { value = 3; };
};
isGreaterThanOne = name: value: value.value > 1;
result = firstAttrNameMatching isGreaterThanOne mySet;
in
result
# Output: "b"
```
# Type
```
firstAttrNameMatching :: (String -> Any -> Bool) -> AttrSet -> String
```
# Arguments
pred
: A function that takes an attribute name and its value and returns a boolean.
set
: The attribute set to filter.
*/
firstAttrNameMatching =
pred: set:
pipe set [
(filterAttrs pred)
attrNames
head
];
};
}

13
nix/lib/lists.nix Normal file
View file

@ -0,0 +1,13 @@
let
inherit (builtins) length tail;
in
{
flake.lib.lists = rec {
shortenList =
count: list:
let
len = length list;
in
if len <= count then list else (shortenList count (tail list));
};
}

101
nix/lib/modules.nix Normal file
View file

@ -0,0 +1,101 @@
{ lib, config, ... }:
let
cfg = config.flake;
inherit (builtins) foldl' attrNames;
inherit (lib.attrsets) mapAttrs;
in
{
flake.lib.modules = {
/**
Fold over the users list and create an attribute set.
# Inputs
`f`
: A function that takes the name of a user and returns an attribute set.
# Type
```
userListToAttrs :: (String -> AttrSet) -> AttrSet
```
# Examples
:::{.example}
## `userListToAttrs` usage example
```nix
flake.manifest.users.rafiq = { ... };
flake.modules.homeManager.users = userListToAttrs (name: {
${name}.home.username = name;
});
=> flake.modules.homeManager.default.users.rafiq.home.username = "rafiq";
```
:::
*/
userListToAttrs = f: foldl' (acc: elem: acc // (f elem)) { } (attrNames cfg.manifest.users);
/**
Return an attribute set for use with a option that needs to be used for all users.
# Inputs
`attrset`
: An attribute set to apply to all the users.
# Type
```
forAllUsers :: AttrSet -> AttrSet
```
# Examples
:::{.example}
## `forAllUsers` usage example
```nix
flake.manifest.users.rafiq = { ... };
flake.modules.nixos.default.users = forAllUsers {
isNormalUser = true;
};
=> flake.modules.nixos.default.users.rafiq.isNormalUser = true;
```
:::
*/
forAllUsers = attrset: mapAttrs (_: _: attrset) cfg.manifest.users;
/**
Like forAllUsers, but passes in the name and value from the manifest.
# Inputs
`f`
: A function that takes an attribute name and its value, and returns the new value for the attribute.
# Type
```
forAllUsers' :: (String -> Any -> Any) -> AttrSet
```
# Examples
:::{.example}
## `forAllUsers'` usage example
```nix
flake.manifest.users.rafiq = { ... };
flake.modules.homeManager.users = forAllUsers' (name: value: {
home.username = name;
});
=> flake.modules.homeManager.default.users.rafiq.home.username = "rafiq";
```
:::
*/
forAllUsers' = f: mapAttrs f cfg.manifest.users;
};
}

45
nix/lib/options.nix Normal file
View file

@ -0,0 +1,45 @@
{ lib, ... }:
let
inherit (lib.options) mkOption;
inherit (lib.types)
str
path
int
port
attrs
;
in
{
flake.lib.options = {
mkStrOption =
default:
mkOption {
inherit default;
type = str;
};
mkAttrOption =
default:
mkOption {
inherit default;
type = attrs;
};
mkIntOption =
default:
mkOption {
inherit default;
type = int;
};
mkPortOption =
default:
mkOption {
type = port;
inherit default;
};
mkPathOption =
default:
mkOption {
type = path;
inherit default;
};
};
}

69
nix/lib/services.nix Normal file
View file

@ -0,0 +1,69 @@
{ config, lib, ... }:
let
inherit (builtins) length concatStringsSep;
inherit (lib.options) mkEnableOption;
inherit (lib.strings) splitString;
inherit (lib.lists) singleton;
inherit (lib.modules) mkMerge mkIf;
inherit (cfg.lib.options) mkStrOption mkPortOption mkAttrOption;
inherit (cfg.lib.lists) shortenList;
cfg = config.flake;
in
{
flake.lib.services = rec {
splitDomain = domain: splitString "." domain;
isRootDomain = domain: length (splitDomain domain) <= 2;
mkRootDomain = domain: concatStringsSep "." (shortenList 2 (splitDomain domain));
mkWildcardDomain = rootDomain: concatStringsSep "." ((singleton "*") ++ (splitDomain rootDomain));
mkHost = domain: if isRootDomain domain then domain else mkWildcardDomain (mkRootDomain domain);
mkWebApp =
{
config,
name,
defaultPort,
persistDirs ? [ ],
extraOptions ? { },
extraConfig ? { },
}:
let
cfg = config.server.web-apps.${name};
networkingConfig =
{
config,
cfg,
name,
}:
mkIf (cfg.domain != "") {
assertions = singleton {
assertion = config.server.web-servers.nginx.enable;
message = "You must enable a web server if you want to set server.web-apps.${name}.domain.";
};
server.ddns.domains = singleton (mkRootDomain cfg.domain);
server.web-servers.nginx.proxies = singleton {
source = cfg.domain;
target = "http://${config.networking.hostName}:${toString cfg.port}";
};
};
in
{
options.server.web-apps.${name} = {
enable = mkEnableOption "";
port = mkPortOption defaultPort;
domain = mkStrOption "";
openFirewall = mkEnableOption "";
extraCfg = mkAttrOption { };
} // extraOptions;
config = mkIf cfg.enable (mkMerge [
{
inherit persistDirs;
networking.firewall = mkIf cfg.openFirewall { allowedTCPPorts = singleton cfg.port; };
}
(networkingConfig { inherit config cfg name; })
extraConfig
]);
};
};
}

92
nix/manifest.nix Normal file
View file

@ -0,0 +1,92 @@
{
flake.manifest = {
users.rafiq = {
primary = true;
name = "Mohammad Rafiq";
email = "rafiq@rrv.sh";
shell = "fish";
pubkey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILdsZyY3gu8IGB8MzMnLdh+ClDxQQ2RYG9rkeetIKq8n rafiq";
};
hosts.nixos = {
nemesis = {
graphical = true;
machine = {
platform = "amd";
gpu = "nvidia";
root.drive = "/dev/disk/by-id/nvme-CT2000P3SSD8_2325E6E77434";
monitors.main = {
id = "desc:OOO AN-270W04K";
resolution = "3840x2160";
refresh-rate = "60";
scale = "2";
};
};
extraCfg = {
services.fwupd.enable = true; # FIXME: remove
machine = {
bluetooth.enable = true;
usb.automount = true;
virtualisation = {
podman.enable = true;
podman.distrobox.enable = true;
};
};
server.web-apps = {
comfy-ui.enable = true;
sd-webui-forge.enable = true;
};
};
};
apollo = {
graphical = false;
machine = {
platform = "intel";
root.drive = "/dev/disk/by-id/nvme-eui.002538d221b47b01";
};
extraCfg.server = {
ddns = {
enable = true;
domains = [
"aenyrathia.wiki"
"slayment.com"
];
};
web-servers = {
enableSSL = true;
nginx = {
enable = true;
proxies = [
{
source = "aenyrathia.wiki";
target = "http://helios:5896";
}
{
source = "il.bwfiq.com";
target = "http://helios:2283";
}
];
};
};
databases = {
mongodb.enable = true;
mysql.enable = true;
postgresql.enable = true;
};
web-apps = {
librechat = {
enable = true;
domain = "chat.bwfiq.com";
};
forgejo = {
enable = true;
domain = "git.rrv.sh";
openFirewall = true;
};
rrv-sh.enable = true;
rrv-sh.domain = "rrv.sh";
};
};
};
};
};
}

101
nix/meta.nix Normal file
View file

@ -0,0 +1,101 @@
{
lib,
config,
inputs,
...
}:
let
inherit (lib.options) mkOption mkEnableOption;
inherit (cfg.lib.options) mkStrOption;
inherit (lib.types)
path
lazyAttrsOf
raw
deferredModule
submodule
;
inherit (inputs.flake-parts.lib) mkSubmoduleOptions;
inherit (cfg.lib.attrsets) firstAttrNameMatching;
cfg = config.flake;
monitorOpts = submodule {
options = {
id = mkStrOption "";
resolution = mkStrOption "";
refresh-rate = mkStrOption "";
scale = mkStrOption "";
};
};
userOpts = submodule {
options = {
username = mkStrOption "";
primary = mkEnableOption "";
name = mkStrOption "";
email = mkStrOption "";
shell = mkStrOption "";
pubkey = mkStrOption "";
};
};
hostOpts = submodule {
options = {
graphical = mkEnableOption "";
machine = {
platform = mkStrOption "";
gpu = mkStrOption "";
root.drive = mkStrOption "";
monitors = mkOption {
type = lazyAttrsOf monitorOpts;
default = { };
};
};
extraCfg = mkOption {
type = deferredModule;
default = { };
};
};
};
in
{
options.flake = mkSubmoduleOptions {
lib = mkOption {
type = lazyAttrsOf raw;
default = { };
};
paths = {
root = mkOption { type = path; };
secrets = mkOption {
type = path;
readOnly = true;
};
};
manifest = mkOption {
type = submodule {
options = {
users = mkOption {
type = lazyAttrsOf userOpts;
default = { };
};
hosts = mkOption {
# hosts.nixos, hosts.darwin, etc.
type = lazyAttrsOf (lazyAttrsOf hostOpts);
default = { };
};
};
};
};
# Helper Option
admin = mkOption {
type = userOpts;
default = { };
};
};
config.flake =
let
username = firstAttrNameMatching (_: v: v.primary or false) cfg.manifest.users;
in
{
paths.secrets = cfg.paths.root + "/secrets";
admin = cfg.manifest.users.${username} // {
inherit username;
};
};
}

17
nix/modules/cli/git.nix Normal file
View file

@ -0,0 +1,17 @@
{ config, ... }:
let
inherit (config.flake) manifest;
in
{
flake.modules.homeManager.default =
{ config, ... }:
{
home.sessionVariables.GIT_CONFIG_GLOBAL = "$HOME/.config/git/config";
programs.git = {
enable = true;
userName = manifest.users.${config.home.username}.name;
userEmail = manifest.users.${config.home.username}.email;
signing.key = "~/.ssh/id_ed25519.pub";
};
};
}

Some files were not shown because too many files have changed in this diff Show more