├── .github
├── dependabot.yml
├── images
│ ├── flake_logo.png
│ ├── hypr_uw_clean.png
│ └── hypr_uw_dirty.png
└── workflows
│ ├── cachix.yaml
│ ├── flake-check.yaml
│ └── flake-inputs.yaml
├── .gitignore
├── LICENSE
├── README.md
├── flake.lock
├── flake.nix
├── home
├── common
│ ├── desktop
│ │ ├── default.nix
│ │ ├── file-associations.nix
│ │ ├── ghostty.nix
│ │ ├── gtk.nix
│ │ ├── hyprland
│ │ │ ├── config
│ │ │ │ ├── displays.nix
│ │ │ │ ├── keybinds.conf
│ │ │ │ └── window-rules.nix
│ │ │ ├── default.nix
│ │ │ ├── hyprlock.nix
│ │ │ └── hyprshot.nix
│ │ ├── mako.nix
│ │ ├── qt.nix
│ │ ├── rofi.nix
│ │ ├── sway
│ │ │ ├── config
│ │ │ │ ├── displays.nix
│ │ │ │ ├── keybindings.nix
│ │ │ │ └── window-rules.nix
│ │ │ ├── default.nix
│ │ │ ├── packages.nix
│ │ │ ├── swappy.nix
│ │ │ └── swaylock.nix
│ │ ├── waybar
│ │ │ ├── default.nix
│ │ │ ├── lib.nix
│ │ │ └── theme.nix
│ │ ├── wl-common.nix
│ │ └── xdg.nix
│ ├── dev
│ │ ├── base.nix
│ │ ├── charm-tools.nix
│ │ ├── default.nix
│ │ └── desktop.nix
│ ├── shell
│ │ ├── atuin.nix
│ │ ├── bat.nix
│ │ ├── bottom.nix
│ │ ├── default.nix
│ │ ├── fastfetch.jsonc
│ │ ├── fastfetch.nix
│ │ ├── fish.nix
│ │ ├── fzf.nix
│ │ ├── git.nix
│ │ ├── helix.nix
│ │ ├── starship.nix
│ │ ├── xdg.nix
│ │ └── zellij.nix
│ └── users
│ │ ├── jon
│ │ ├── default.nix
│ │ ├── freyja.nix
│ │ ├── kara.nix
│ │ └── thor.nix
│ │ └── ubuntu
│ │ └── default.nix
└── default.nix
├── host
├── common
│ ├── base
│ │ ├── boot.nix
│ │ ├── console.nix
│ │ ├── default.nix
│ │ ├── hardware.nix
│ │ ├── locale.nix
│ │ ├── nh.nix
│ │ ├── packages.nix
│ │ └── zramswap.nix
│ ├── desktop
│ │ ├── default.nix
│ │ ├── hyprland.nix
│ │ ├── sway.nix
│ │ └── tiling-common.nix
│ ├── hardware
│ │ ├── bluetooth.nix
│ │ ├── ledger.nix
│ │ ├── yubihsm.nix
│ │ └── yubikey.nix
│ ├── services
│ │ ├── avahi.nix
│ │ ├── backup
│ │ │ ├── default.nix
│ │ │ ├── kara.nix
│ │ │ └── thor.nix
│ │ ├── files.nix
│ │ ├── firewall.nix
│ │ ├── home-assistant.nix
│ │ ├── immich.nix
│ │ ├── libations.nix
│ │ ├── networkmanager.nix
│ │ ├── nfs
│ │ │ ├── default.nix
│ │ │ └── thor.nix
│ │ ├── openssh.nix
│ │ ├── photo-backup
│ │ │ ├── default.nix
│ │ │ └── photo-backup.sh
│ │ ├── pipewire.nix
│ │ ├── reverse-proxy
│ │ │ ├── default.nix
│ │ │ └── thor.nix
│ │ └── tailscale.nix
│ ├── users
│ │ └── jon
│ │ │ └── default.nix
│ └── virt
│ │ ├── default.nix
│ │ ├── docker.nix
│ │ ├── lxd.nix
│ │ └── multipass.nix
├── default.nix
├── kara
│ ├── boot.nix
│ ├── disks.nix
│ ├── extra.nix
│ └── hardware.nix
├── thor
│ ├── boot.nix
│ ├── disks.nix
│ ├── extra.nix
│ └── hardware.nix
└── volnir
│ ├── boot.nix
│ ├── disks.nix
│ ├── extra.nix
│ └── hardware.nix
├── lib
├── default.nix
├── helpers.nix
└── theme
│ ├── colours.nix
│ ├── default.nix
│ ├── lib.nix
│ └── wallpapers
│ ├── elk-colors.jpg
│ ├── jokulsarlon.png
│ ├── mountains.png
│ └── space-clouds.png
├── nixpkgs.nix
├── overlays
├── custom-caddy.nix
└── default.nix
├── pkgs
├── default.nix
├── ght
│ ├── default.nix
│ └── ght-graders-loc.patch
├── juju4.nix
└── nixfmt-plus.nix
├── scripts
├── install-with-disko
├── partition-btrfs-luks
└── setup-hyprland-ubuntu
├── secrets
├── kara-borgbase-passphrase.age
├── kara-borgbase-ssh.age
├── secrets.nix
├── thor-backup-env.age
├── thor-borgbase-passphrase.age
├── thor-borgbase-ssh.age
├── thor-digitalocean.age
├── thor-libations-recipes.age
├── thor-libations-tskey.age
└── volnir-planefinder-config.age
└── shell.nix
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "github-actions"
4 | directory: "/"
5 | schedule:
6 | # Check for updates to GitHub Actions every week
7 | interval: "weekly"
8 |
--------------------------------------------------------------------------------
/.github/images/flake_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/.github/images/flake_logo.png
--------------------------------------------------------------------------------
/.github/images/hypr_uw_clean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/.github/images/hypr_uw_clean.png
--------------------------------------------------------------------------------
/.github/images/hypr_uw_dirty.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/.github/images/hypr_uw_dirty.png
--------------------------------------------------------------------------------
/.github/workflows/cachix.yaml:
--------------------------------------------------------------------------------
1 | name: "Cachix"
2 | on:
3 | push:
4 | jobs:
5 | cachix:
6 | runs-on: ubuntu-latest
7 | strategy:
8 | matrix:
9 | package: ["ght"]
10 | steps:
11 | - name: Checkout flake
12 | uses: actions/checkout@v4
13 |
14 | - name: Install nix
15 | uses: DeterminateSystems/nix-installer-action@v17
16 |
17 | - name: Build ${{ matrix.package }}
18 | run: nix build .#${{ matrix.package }}
19 |
--------------------------------------------------------------------------------
/.github/workflows/flake-check.yaml:
--------------------------------------------------------------------------------
1 | name: "Flake Checks"
2 | on:
3 | push:
4 | jobs:
5 | checks:
6 | runs-on: ubuntu-latest
7 | steps:
8 | - name: Checkout flake
9 | uses: actions/checkout@v4
10 |
11 | - name: Install nix
12 | uses: DeterminateSystems/nix-installer-action@v17
13 |
14 | - name: nix flake check
15 | run: nix flake check
16 |
--------------------------------------------------------------------------------
/.github/workflows/flake-inputs.yaml:
--------------------------------------------------------------------------------
1 | name: Flake ❄️ Checker ✅
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | schedule:
8 | - cron: "37 13 * * *"
9 | workflow_dispatch:
10 |
11 | jobs:
12 | flake-checker:
13 | runs-on: ubuntu-22.04
14 | steps:
15 | - name: Checkout flake
16 | uses: actions/checkout@v4
17 |
18 | - name: Install nix
19 | uses: DeterminateSystems/nix-installer-action@v17
20 |
21 | - name: Check flake inputs
22 | uses: DeterminateSystems/flake-checker-action@v10
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | result*
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright jnsgruk
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | This repository contains a [Nix Flake](https://nixos.wiki/wiki/Flakes) for configuring my machines. As a general rule, my "server" machines track the latest stable release of NixOS, and my workstations/laptops track `unstable`.
8 |
9 | I use [Hyprland](https://hyprland.org/) as my tiling window manager, [Ghostty](https://ghostty.org/) as my terminal emulator, and I move between [Helix](https://helix-editor.com/) and [Visual Studio Code](https://code.visualstudio.com/) for editing. All of my apps/system components are themed with the excellent [Catppuccin](https://catppuccin.com/) theme where possible. I also rely on [1Password](https://1password.com/), [Obsidian](https://obsidian.md/) and [Todoist](https://todoist.com/) in my daily work. At work, we use Google Workspace, so I use [Google Chrome](https://www.google.com/intl/en_uk/chrome/) for work browsing and [Firefox](https://www.mozilla.org/en-GB/firefox/new/) for home browsing. I use (and **love**) [Tailscale](https://tailscale.com/) to network my computers, phones and tablets.
10 |
11 | ## 🖥️ Machines
12 |
13 | My machines are partitioned with [disko], and most are encrypted using the TPM to unlock the disks automatically on boot (I wrote about this [on my blog](https://jnsgr.uk/2024/04/nixos-secure-boot-tpm-fde/)). I tend toward [btrfs] for my machines - I've been using it for many years without issue. Machines are mostly named after characters or places in [Norse mythology](https://en.wikipedia.org/wiki/Norse_mythology).
14 |
15 | | Hostname | Board | CPU | RAM | GPU | OS | Role | Desktop |
16 | | :------: | :-------------------: | :---------------------: | :--: | :-------------------------: | :----: | :-----: | :----------: |
17 | | `dev` | [Multipass] VM | - | - | - | Ubuntu | Server | - |
18 | | `freyja` | [Thinkpad Z13] | [AMD Ryzen 7 Pro 6860Z] | 32GB | AMD Radeon 680M | Ubuntu | Laptop | Hyprland |
19 | | `kara` | [MSI MPG X670 Carbon] | [AMD Ryzen 9 7950X] | 64GB | [AMD Radeon RX 7900 XT] | NixOS | Desktop | Hyprland |
20 | | `thor` | [Intel NUC6i7KYK] | [Intel Core i7-6770HQ] | 16GB | Intel Iris Pro Graphics 580 | NixOS | Server | - |
21 | | `volnir` | [Raspberry Pi 4] | BCM2711 / Cortex A72 | 4GB | - | NixOS | Kiosk | Cage/Firefox |
22 |
23 | [btrfs]: https://btrfs.readthedocs.io/en/latest/index.html
24 | [disko]: https://github.com/nix-community/disko
25 | [Multipass]: https://multipass.run
26 | [Thinkpad Z13]: https://www.lenovo.com/gb/en/p/laptops/thinkpad/thinkpadz/thinkpad-z13-(13-inch-amd)/21d20012uk
27 | [Thinkcentre M93p]: https://psref.lenovo.com/Product/ThinkCentre/ThinkCentre_M93_M93p_Tiny
28 | [MSI MPG X670 Carbon]: https://www.msi.com/Motherboard/MPG-X670E-CARBON-WIFI
29 | [Intel NUC6i7KYK]: https://ark.intel.com/content/www/us/en/ark/products/89187/intel-nuc-kit-nuc6i7kyk.html
30 | [AMD Ryzen 7 Pro 6860Z]: https://www.cpubenchmark.net/cpu.php?id=4921&cpu=AMD+Ryzen+7+PRO+6860Z
31 | [Intel Core i5-4690]: https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-4690+%40+3.50GHz&id=2236
32 | [AMD Ryzen 9 7950X]: https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+9+7950X&id=5031
33 | [Intel Core i7-6770HQ]: https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-6770HQ+%40+2.60GHz&id=2759
34 | [AMD Radeon RX 7900 XT]: https://www.xfxforce.com/shop/xfx-speedster-merc310-7900xt
35 | [Raspberry Pi 4]: https://www.raspberrypi.com/products/raspberry-pi-4-model-b/
36 |
37 | ## 🚧 Structure
38 |
39 | - [.github]: ci/cd workflows for flake checks and version bumps
40 | - [home]: my home-manager configurations
41 | - [host]: host-specific configurations
42 | - [lib]: custom libraries for host/home construction and theming
43 | - [overlays]: package/configuration overlays
44 | - [pkgs]: my custom package definitions
45 | - [scripts]: helper scripts for machine setup
46 | - [secrets]: secrets encrypted with [age] and [agenix]
47 |
48 | Both [host] and [home] contain `common` directories, which contain reusable piece of configuration
49 | used across multiple machines.
50 |
51 | [.github]: ./github
52 | [age]: https://github.com/FiloSottile/age
53 | [agenix]: https://github.com/ryantm/agenix
54 | [home]: ./home
55 | [host]: ./host
56 | [lib]: ./lib
57 | [overlays]: ./overlays
58 | [pkgs]: ./pkgs
59 | [scripts]: ./scripts
60 | [secrets]: ./secrets
61 |
62 | ## 📦 Applications / Packages
63 |
64 | The following is a list of the key elements of my setup, with links to their config:
65 |
66 | | Type | Details |
67 | | :------: | :--------------------------------------------------------------- |
68 | | Shell | [fish], [starship], [helix], [zellij], [fastfetch], [bat], [fzf] |
69 | | WM | [hyprland], [waybar], [hyprlock], [mako], [gtk], [rofi] |
70 | | Apps | [vscode], [ghostty] |
71 | | Services | [home-assistant] |
72 |
73 | ## 🖼️ Screenshots
74 |
75 | 
76 | 
77 |
78 |
79 |
80 | [bat]: ./home/common/shell/bat.nix
81 | [fastfetch]: ./home/common/shell/fastfetch.nix
82 | [fish]: ./home/common/shell/fish.nix
83 | [fzf]: ./home/common/shell/fzf.nix
84 | [ghostty]: ./home/common/desktop/ghostty.nix
85 | [gtk]: ./home/common/desktop/gtk.nix
86 | [helix]: ./home/common/shell/helix.nix
87 | [home-assistant]: ./host/common/services/home-assistant.nix
88 | [hyprland]: ./home/common/desktop/hyprland/default.nix
89 | [hyprlock]: ./home/common/desktop/hyprland/hyprlock.nix
90 | [mako]: ./home/common/desktop/mako.nix
91 | [rofi]: ./home/common/desktop/rofi.nix
92 | [starship]: ./home/common/shell/starship.nix
93 | [vscode]: ./home/common/dev/desktop.nix
94 | [waybar]: ./home/common/desktop/waybar/default.nix
95 | [zellij]: ./home/common/shell/zellij.nix
96 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "agenix": {
4 | "inputs": {
5 | "darwin": "darwin",
6 | "home-manager": "home-manager",
7 | "nixpkgs": [
8 | "nixpkgs"
9 | ],
10 | "systems": "systems"
11 | },
12 | "locked": {
13 | "lastModified": 1736955230,
14 | "narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=",
15 | "owner": "ryantm",
16 | "repo": "agenix",
17 | "rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
18 | "type": "github"
19 | },
20 | "original": {
21 | "owner": "ryantm",
22 | "repo": "agenix",
23 | "type": "github"
24 | }
25 | },
26 | "catppuccin": {
27 | "inputs": {
28 | "nixpkgs": "nixpkgs"
29 | },
30 | "locked": {
31 | "lastModified": 1739822884,
32 | "narHash": "sha256-g17zPoBFOrQfmgwZlBLnk4vfYDyfzllPQl02RWh8r4w=",
33 | "owner": "catppuccin",
34 | "repo": "nix",
35 | "rev": "24dac16e6babd41961d985eef3dce6a30dab2e91",
36 | "type": "github"
37 | },
38 | "original": {
39 | "owner": "catppuccin",
40 | "repo": "nix",
41 | "type": "github"
42 | }
43 | },
44 | "crane": {
45 | "locked": {
46 | "lastModified": 1731098351,
47 | "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=",
48 | "owner": "ipetkov",
49 | "repo": "crane",
50 | "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28",
51 | "type": "github"
52 | },
53 | "original": {
54 | "owner": "ipetkov",
55 | "repo": "crane",
56 | "type": "github"
57 | }
58 | },
59 | "darwin": {
60 | "inputs": {
61 | "nixpkgs": [
62 | "agenix",
63 | "nixpkgs"
64 | ]
65 | },
66 | "locked": {
67 | "lastModified": 1700795494,
68 | "narHash": "sha256-gzGLZSiOhf155FW7262kdHo2YDeugp3VuIFb4/GGng0=",
69 | "owner": "lnl7",
70 | "repo": "nix-darwin",
71 | "rev": "4b9b83d5a92e8c1fbfd8eb27eda375908c11ec4d",
72 | "type": "github"
73 | },
74 | "original": {
75 | "owner": "lnl7",
76 | "ref": "master",
77 | "repo": "nix-darwin",
78 | "type": "github"
79 | }
80 | },
81 | "disko": {
82 | "inputs": {
83 | "nixpkgs": [
84 | "nixpkgs"
85 | ]
86 | },
87 | "locked": {
88 | "lastModified": 1739841949,
89 | "narHash": "sha256-lSOXdgW/1zi/SSu7xp71v+55D5Egz8ACv0STkj7fhbs=",
90 | "owner": "nix-community",
91 | "repo": "disko",
92 | "rev": "15dbf8cebd8e2655a883b74547108e089f051bf0",
93 | "type": "github"
94 | },
95 | "original": {
96 | "owner": "nix-community",
97 | "repo": "disko",
98 | "type": "github"
99 | }
100 | },
101 | "flake-compat": {
102 | "flake": false,
103 | "locked": {
104 | "lastModified": 1696426674,
105 | "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
106 | "owner": "edolstra",
107 | "repo": "flake-compat",
108 | "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
109 | "type": "github"
110 | },
111 | "original": {
112 | "owner": "edolstra",
113 | "repo": "flake-compat",
114 | "type": "github"
115 | }
116 | },
117 | "flake-parts": {
118 | "inputs": {
119 | "nixpkgs-lib": [
120 | "lanzaboote",
121 | "nixpkgs"
122 | ]
123 | },
124 | "locked": {
125 | "lastModified": 1730504689,
126 | "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
127 | "owner": "hercules-ci",
128 | "repo": "flake-parts",
129 | "rev": "506278e768c2a08bec68eb62932193e341f55c90",
130 | "type": "github"
131 | },
132 | "original": {
133 | "owner": "hercules-ci",
134 | "repo": "flake-parts",
135 | "type": "github"
136 | }
137 | },
138 | "flake-utils": {
139 | "inputs": {
140 | "systems": "systems_2"
141 | },
142 | "locked": {
143 | "lastModified": 1681202837,
144 | "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
145 | "owner": "numtide",
146 | "repo": "flake-utils",
147 | "rev": "cfacdce06f30d2b68473a46042957675eebb3401",
148 | "type": "github"
149 | },
150 | "original": {
151 | "owner": "numtide",
152 | "repo": "flake-utils",
153 | "type": "github"
154 | }
155 | },
156 | "flypi": {
157 | "inputs": {
158 | "nixpkgs": "nixpkgs_2"
159 | },
160 | "locked": {
161 | "lastModified": 1738941324,
162 | "narHash": "sha256-3nJgDAbgjMpiMzPgafFI8SAXOGnPrlV3VOwr1b/J6Jo=",
163 | "owner": "jnsgruk",
164 | "repo": "flypi",
165 | "rev": "0e50967176e4983b43e27a6fa462418f641176c7",
166 | "type": "github"
167 | },
168 | "original": {
169 | "owner": "jnsgruk",
170 | "repo": "flypi",
171 | "type": "github"
172 | }
173 | },
174 | "gitignore": {
175 | "inputs": {
176 | "nixpkgs": [
177 | "lanzaboote",
178 | "pre-commit-hooks-nix",
179 | "nixpkgs"
180 | ]
181 | },
182 | "locked": {
183 | "lastModified": 1709087332,
184 | "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
185 | "owner": "hercules-ci",
186 | "repo": "gitignore.nix",
187 | "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
188 | "type": "github"
189 | },
190 | "original": {
191 | "owner": "hercules-ci",
192 | "repo": "gitignore.nix",
193 | "type": "github"
194 | }
195 | },
196 | "home-manager": {
197 | "inputs": {
198 | "nixpkgs": [
199 | "agenix",
200 | "nixpkgs"
201 | ]
202 | },
203 | "locked": {
204 | "lastModified": 1703113217,
205 | "narHash": "sha256-7ulcXOk63TIT2lVDSExj7XzFx09LpdSAPtvgtM7yQPE=",
206 | "owner": "nix-community",
207 | "repo": "home-manager",
208 | "rev": "3bfaacf46133c037bb356193bd2f1765d9dc82c1",
209 | "type": "github"
210 | },
211 | "original": {
212 | "owner": "nix-community",
213 | "repo": "home-manager",
214 | "type": "github"
215 | }
216 | },
217 | "home-manager_2": {
218 | "inputs": {
219 | "nixpkgs": [
220 | "nixpkgs"
221 | ]
222 | },
223 | "locked": {
224 | "lastModified": 1739757849,
225 | "narHash": "sha256-Gs076ot1YuAAsYVcyidLKUMIc4ooOaRGO0PqTY7sBzA=",
226 | "owner": "nix-community",
227 | "repo": "home-manager",
228 | "rev": "9d3d080aec2a35e05a15cedd281c2384767c2cfe",
229 | "type": "github"
230 | },
231 | "original": {
232 | "owner": "nix-community",
233 | "ref": "release-24.11",
234 | "repo": "home-manager",
235 | "type": "github"
236 | }
237 | },
238 | "lanzaboote": {
239 | "inputs": {
240 | "crane": "crane",
241 | "flake-compat": "flake-compat",
242 | "flake-parts": "flake-parts",
243 | "nixpkgs": [
244 | "nixpkgs"
245 | ],
246 | "pre-commit-hooks-nix": "pre-commit-hooks-nix",
247 | "rust-overlay": "rust-overlay"
248 | },
249 | "locked": {
250 | "lastModified": 1739186342,
251 | "narHash": "sha256-2j+sln9RwQn+g7J4GmdFFgvqXnLkvWBNMaUzONlkzUE=",
252 | "owner": "nix-community",
253 | "repo": "lanzaboote",
254 | "rev": "3bdeebbc484a09391c4f0ec8a37bb77809426660",
255 | "type": "github"
256 | },
257 | "original": {
258 | "owner": "nix-community",
259 | "repo": "lanzaboote",
260 | "type": "github"
261 | }
262 | },
263 | "libations": {
264 | "inputs": {
265 | "nixpkgs": [
266 | "nixpkgs"
267 | ]
268 | },
269 | "locked": {
270 | "lastModified": 1738941367,
271 | "narHash": "sha256-lOxliNwviqF5JDVDt7iitmTkdhjV3ugFD2tADco7bqY=",
272 | "owner": "jnsgruk",
273 | "repo": "libations",
274 | "rev": "34eaf7e0d411308c37f8bcea6cf2c799c98fec70",
275 | "type": "github"
276 | },
277 | "original": {
278 | "owner": "jnsgruk",
279 | "repo": "libations",
280 | "type": "github"
281 | }
282 | },
283 | "master": {
284 | "locked": {
285 | "lastModified": 1739871119,
286 | "narHash": "sha256-ljb/20W3Du8kGcn6c9IqDgGd1sbUlYMU3SKHfkuR69I=",
287 | "owner": "nixos",
288 | "repo": "nixpkgs",
289 | "rev": "0add023131d28c3db0fc86889d343b2295f77bef",
290 | "type": "github"
291 | },
292 | "original": {
293 | "owner": "nixos",
294 | "ref": "master",
295 | "repo": "nixpkgs",
296 | "type": "github"
297 | }
298 | },
299 | "nix-system-graphics": {
300 | "inputs": {
301 | "nixpkgs": [
302 | "nixpkgs"
303 | ]
304 | },
305 | "locked": {
306 | "lastModified": 1737457219,
307 | "narHash": "sha256-nX9dxoATDCSQgWw/iv6BngXDJEyHVYYEvHEVQ7Ig3fI=",
308 | "owner": "soupglasses",
309 | "repo": "nix-system-graphics",
310 | "rev": "9c875e0c56cf2eb272b9102a4f3e24e4e31629fd",
311 | "type": "github"
312 | },
313 | "original": {
314 | "owner": "soupglasses",
315 | "repo": "nix-system-graphics",
316 | "type": "github"
317 | }
318 | },
319 | "nixos-hardware": {
320 | "locked": {
321 | "lastModified": 1739798439,
322 | "narHash": "sha256-GyipmjbbQEaosel/+wq1xihCKbv0/e1LU00x/8b/fP4=",
323 | "owner": "NixOS",
324 | "repo": "nixos-hardware",
325 | "rev": "3e2ea8a49d4d76276b0f4e2041df8ca5c0771371",
326 | "type": "github"
327 | },
328 | "original": {
329 | "owner": "NixOS",
330 | "ref": "master",
331 | "repo": "nixos-hardware",
332 | "type": "github"
333 | }
334 | },
335 | "nixpkgs": {
336 | "locked": {
337 | "lastModified": 1736012469,
338 | "narHash": "sha256-/qlNWm/IEVVH7GfgAIyP6EsVZI6zjAx1cV5zNyrs+rI=",
339 | "owner": "NixOS",
340 | "repo": "nixpkgs",
341 | "rev": "8f3e1f807051e32d8c95cd12b9b421623850a34d",
342 | "type": "github"
343 | },
344 | "original": {
345 | "owner": "NixOS",
346 | "ref": "nixos-unstable",
347 | "repo": "nixpkgs",
348 | "type": "github"
349 | }
350 | },
351 | "nixpkgs-stable": {
352 | "locked": {
353 | "lastModified": 1730741070,
354 | "narHash": "sha256-edm8WG19kWozJ/GqyYx2VjW99EdhjKwbY3ZwdlPAAlo=",
355 | "owner": "NixOS",
356 | "repo": "nixpkgs",
357 | "rev": "d063c1dd113c91ab27959ba540c0d9753409edf3",
358 | "type": "github"
359 | },
360 | "original": {
361 | "owner": "NixOS",
362 | "ref": "nixos-24.05",
363 | "repo": "nixpkgs",
364 | "type": "github"
365 | }
366 | },
367 | "nixpkgs_2": {
368 | "locked": {
369 | "lastModified": 1738142207,
370 | "narHash": "sha256-NGqpVVxNAHwIicXpgaVqJEJWeyqzoQJ9oc8lnK9+WC4=",
371 | "owner": "nixos",
372 | "repo": "nixpkgs",
373 | "rev": "9d3ae807ebd2981d593cddd0080856873139aa40",
374 | "type": "github"
375 | },
376 | "original": {
377 | "owner": "nixos",
378 | "ref": "nixos-unstable",
379 | "repo": "nixpkgs",
380 | "type": "github"
381 | }
382 | },
383 | "nixpkgs_3": {
384 | "locked": {
385 | "lastModified": 1739758141,
386 | "narHash": "sha256-uq6A2L7o1/tR6VfmYhZWoVAwb3gTy7j4Jx30MIrH0rE=",
387 | "owner": "nixos",
388 | "repo": "nixpkgs",
389 | "rev": "c618e28f70257593de75a7044438efc1c1fc0791",
390 | "type": "github"
391 | },
392 | "original": {
393 | "owner": "nixos",
394 | "ref": "nixos-24.11",
395 | "repo": "nixpkgs",
396 | "type": "github"
397 | }
398 | },
399 | "pre-commit-hooks-nix": {
400 | "inputs": {
401 | "flake-compat": [
402 | "lanzaboote",
403 | "flake-compat"
404 | ],
405 | "gitignore": "gitignore",
406 | "nixpkgs": [
407 | "lanzaboote",
408 | "nixpkgs"
409 | ],
410 | "nixpkgs-stable": "nixpkgs-stable"
411 | },
412 | "locked": {
413 | "lastModified": 1731363552,
414 | "narHash": "sha256-vFta1uHnD29VUY4HJOO/D6p6rxyObnf+InnSMT4jlMU=",
415 | "owner": "cachix",
416 | "repo": "pre-commit-hooks.nix",
417 | "rev": "cd1af27aa85026ac759d5d3fccf650abe7e1bbf0",
418 | "type": "github"
419 | },
420 | "original": {
421 | "owner": "cachix",
422 | "repo": "pre-commit-hooks.nix",
423 | "type": "github"
424 | }
425 | },
426 | "root": {
427 | "inputs": {
428 | "agenix": "agenix",
429 | "catppuccin": "catppuccin",
430 | "disko": "disko",
431 | "flypi": "flypi",
432 | "home-manager": "home-manager_2",
433 | "lanzaboote": "lanzaboote",
434 | "libations": "libations",
435 | "master": "master",
436 | "nix-system-graphics": "nix-system-graphics",
437 | "nixos-hardware": "nixos-hardware",
438 | "nixpkgs": "nixpkgs_3",
439 | "system-manager": "system-manager",
440 | "unstable": "unstable",
441 | "vscode-server": "vscode-server"
442 | }
443 | },
444 | "rust-overlay": {
445 | "inputs": {
446 | "nixpkgs": [
447 | "lanzaboote",
448 | "nixpkgs"
449 | ]
450 | },
451 | "locked": {
452 | "lastModified": 1731897198,
453 | "narHash": "sha256-Ou7vLETSKwmE/HRQz4cImXXJBr/k9gp4J4z/PF8LzTE=",
454 | "owner": "oxalica",
455 | "repo": "rust-overlay",
456 | "rev": "0be641045af6d8666c11c2c40e45ffc9667839b5",
457 | "type": "github"
458 | },
459 | "original": {
460 | "owner": "oxalica",
461 | "repo": "rust-overlay",
462 | "type": "github"
463 | }
464 | },
465 | "system-manager": {
466 | "inputs": {
467 | "nixpkgs": [
468 | "nixpkgs"
469 | ]
470 | },
471 | "locked": {
472 | "lastModified": 1739316420,
473 | "narHash": "sha256-FZBKtR8mqbcEazdpI1SoID43FeldQPhjnvluUO9HAaI=",
474 | "owner": "numtide",
475 | "repo": "system-manager",
476 | "rev": "82d5a9ecd15ec48bcbfbacf5462066ee267d6aae",
477 | "type": "github"
478 | },
479 | "original": {
480 | "owner": "numtide",
481 | "repo": "system-manager",
482 | "type": "github"
483 | }
484 | },
485 | "systems": {
486 | "locked": {
487 | "lastModified": 1681028828,
488 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
489 | "owner": "nix-systems",
490 | "repo": "default",
491 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
492 | "type": "github"
493 | },
494 | "original": {
495 | "owner": "nix-systems",
496 | "repo": "default",
497 | "type": "github"
498 | }
499 | },
500 | "systems_2": {
501 | "locked": {
502 | "lastModified": 1681028828,
503 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
504 | "owner": "nix-systems",
505 | "repo": "default",
506 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
507 | "type": "github"
508 | },
509 | "original": {
510 | "owner": "nix-systems",
511 | "repo": "default",
512 | "type": "github"
513 | }
514 | },
515 | "unstable": {
516 | "locked": {
517 | "lastModified": 1739736696,
518 | "narHash": "sha256-zON2GNBkzsIyALlOCFiEBcIjI4w38GYOb+P+R4S8Jsw=",
519 | "owner": "nixos",
520 | "repo": "nixpkgs",
521 | "rev": "d74a2335ac9c133d6bbec9fc98d91a77f1604c1f",
522 | "type": "github"
523 | },
524 | "original": {
525 | "owner": "nixos",
526 | "ref": "nixos-unstable",
527 | "repo": "nixpkgs",
528 | "type": "github"
529 | }
530 | },
531 | "vscode-server": {
532 | "inputs": {
533 | "flake-utils": "flake-utils",
534 | "nixpkgs": [
535 | "nixpkgs"
536 | ]
537 | },
538 | "locked": {
539 | "lastModified": 1729422940,
540 | "narHash": "sha256-DlvJv33ml5UTKgu4b0HauOfFIoDx6QXtbqUF3vWeRCY=",
541 | "owner": "nix-community",
542 | "repo": "nixos-vscode-server",
543 | "rev": "8b6db451de46ecf9b4ab3d01ef76e59957ff549f",
544 | "type": "github"
545 | },
546 | "original": {
547 | "owner": "nix-community",
548 | "repo": "nixos-vscode-server",
549 | "type": "github"
550 | }
551 | }
552 | },
553 | "root": "root",
554 | "version": 7
555 | }
556 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "jnsgruk's nixos configuration";
3 | inputs = {
4 | nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
5 | unstable.url = "github:nixos/nixpkgs/nixos-unstable";
6 | master.url = "github:nixos/nixpkgs/master";
7 | nixos-hardware.url = "github:NixOS/nixos-hardware/master";
8 |
9 | system-manager.url = "github:numtide/system-manager";
10 | system-manager.inputs.nixpkgs.follows = "nixpkgs";
11 |
12 | nix-system-graphics.url = "github:soupglasses/nix-system-graphics";
13 | nix-system-graphics.inputs.nixpkgs.follows = "nixpkgs";
14 |
15 | agenix.url = "github:ryantm/agenix";
16 | agenix.inputs.nixpkgs.follows = "nixpkgs";
17 |
18 | catppuccin.url = "github:catppuccin/nix";
19 |
20 | disko.url = "github:nix-community/disko";
21 | disko.inputs.nixpkgs.follows = "nixpkgs";
22 |
23 | flypi.url = "github:jnsgruk/flypi";
24 |
25 | home-manager.url = "github:nix-community/home-manager/release-24.11";
26 | home-manager.inputs.nixpkgs.follows = "nixpkgs";
27 |
28 | lanzaboote.url = "github:nix-community/lanzaboote";
29 | lanzaboote.inputs.nixpkgs.follows = "nixpkgs";
30 |
31 | libations.url = "github:jnsgruk/libations";
32 | libations.inputs.nixpkgs.follows = "nixpkgs";
33 |
34 | vscode-server.url = "github:nix-community/nixos-vscode-server";
35 | vscode-server.inputs.nixpkgs.follows = "nixpkgs";
36 | };
37 |
38 | outputs =
39 | {
40 | self,
41 | unstable,
42 | ...
43 | }@inputs:
44 | let
45 | inherit (self) outputs;
46 | stateVersion = "24.11";
47 | username = "jon";
48 |
49 | libx = import ./lib {
50 | inherit
51 | self
52 | inputs
53 | outputs
54 | stateVersion
55 | username
56 | ;
57 | };
58 | in
59 | {
60 | # nix build .#homeConfigurations."jon@freyja".activationPackage
61 | homeConfigurations = {
62 | # Desktop machines
63 | "${username}@freyja" = libx.mkHome {
64 | hostname = "freyja";
65 | desktop = "hyprland";
66 | };
67 | "${username}@kara" = libx.mkHome {
68 | hostname = "kara";
69 | desktop = "hyprland";
70 | };
71 | # Headless machines
72 | "${username}@thor" = libx.mkHome { hostname = "thor"; };
73 | "${username}@volnir" = libx.mkHome {
74 | hostname = "volnir";
75 | system = "aarch64-linux";
76 | };
77 | "ubuntu@dev" = libx.mkHome {
78 | hostname = "dev";
79 | user = "ubuntu";
80 | };
81 | };
82 |
83 | # nix build .#nixosConfigurations.freyja.config.system.build.toplevel
84 | nixosConfigurations = {
85 | # Desktop machines
86 | kara = libx.mkHost {
87 | hostname = "kara";
88 | desktop = "hyprland";
89 | };
90 | # Headless machines
91 | thor = libx.mkHost {
92 | hostname = "thor";
93 | };
94 | volnir = libx.mkHost {
95 | hostname = "volnir";
96 | };
97 | };
98 |
99 | # system-manager configurations
100 | systemConfigs = {
101 | freyja = libx.mkSystemManager { };
102 | };
103 |
104 | # Custom packages; acessible via 'nix build', 'nix shell', etc
105 | packages = libx.forAllSystems (
106 | system:
107 | let
108 | pkgs = unstable.legacyPackages.${system};
109 | in
110 | import ./pkgs { inherit pkgs; }
111 | );
112 |
113 | # Custom overlays
114 | overlays = import ./overlays { inherit inputs; };
115 |
116 | # Devshell for bootstrapping
117 | # Accessible via 'nix develop' or 'nix-shell' (legacy)
118 | devShells = libx.forAllSystems (
119 | system:
120 | let
121 | pkgs = unstable.legacyPackages.${system};
122 | in
123 | import ./shell.nix { inherit pkgs; }
124 | );
125 |
126 | formatter = libx.forAllSystems (system: self.packages.${system}.nixfmt-plus);
127 | };
128 | }
129 |
--------------------------------------------------------------------------------
/home/common/desktop/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, desktop, ... }:
2 | {
3 | imports = [
4 | (./. + "/${desktop}")
5 |
6 | ../dev
7 |
8 | ./ghostty.nix
9 | ./gtk.nix
10 | ./qt.nix
11 | ./xdg.nix
12 | ];
13 |
14 | programs = {
15 | firefox.enable = true;
16 | mpv.enable = true;
17 | };
18 |
19 | home.packages = with pkgs; [
20 | bambu-studio
21 | catppuccin-gtk
22 | desktop-file-utils
23 | ght
24 | google-chrome
25 | # (google-chrome.override {
26 | # commandLineArgs = [
27 | # "--enable-features=VaapiVideoDecoder,VaapiIgnoreDriverChecks,Vulkan,DefaultANGLEVulkan,VulkanFromANGLE"
28 | # "--ignore-gpu-blocklist"
29 | # "--enable-zero-copy"
30 | # ];
31 | # })
32 | libnotify
33 | loupe
34 | papers
35 | pwvucontrol
36 | thunderbird-latest
37 | todoist-electron
38 | xdg-utils
39 |
40 | unstable.obsidian
41 | unstable.rambox
42 | unstable.signal-desktop
43 | ];
44 |
45 | fonts.fontconfig.enable = true;
46 | }
47 |
--------------------------------------------------------------------------------
/home/common/desktop/file-associations.nix:
--------------------------------------------------------------------------------
1 | let
2 | browser = [ "google-chrome.desktop" ];
3 | archiveManager = [ "org.gnome.FileRoller.desktop" ];
4 | imageViewer = [ "org.gnome.Loupe.desktop" ];
5 | videoPlayer = [ "mpv.desktop" ];
6 | in
7 | {
8 | # XDG MIME types
9 | associations = {
10 | "application/x-extension-htm" = browser;
11 | "application/x-extension-html" = browser;
12 | "application/x-extension-shtml" = browser;
13 | "application/x-extension-xht" = browser;
14 | "application/x-extension-xhtml" = browser;
15 | "application/xhtml+xml" = browser;
16 | "text/html" = browser;
17 | "x-scheme-handler/about" = browser;
18 | "x-scheme-handler/chrome" = browser;
19 | "x-scheme-handler/ftp" = browser;
20 | "x-scheme-handler/http" = browser;
21 | "x-scheme-handler/https" = browser;
22 | "x-scheme-handler/unknown" = browser;
23 |
24 | "audio/*" = videoPlayer;
25 | "video/*" = videoPlayer;
26 | "image/*" = imageViewer;
27 |
28 | "application/json" = browser;
29 |
30 | "application/pdf" = [ "org.gnome.Papers.desktop" ];
31 |
32 | # Archives / compressed files
33 | "application/x-7z-compressed" = archiveManager;
34 | "application/x-7z-compressed-tar" = archiveManager;
35 | "application/x-bzip" = archiveManager;
36 | "application/x-bzip-compressed-tar" = archiveManager;
37 | "application/x-compress" = archiveManager;
38 | "application/x-compressed-tar" = archiveManager;
39 | "application/x-cpio" = archiveManager;
40 | "application/x-gzip" = archiveManager;
41 | "application/x-lha" = archiveManager;
42 | "application/x-lzip" = archiveManager;
43 | "application/x-lzip-compressed-tar" = archiveManager;
44 | "application/x-lzma" = archiveManager;
45 | "application/x-lzma-compressed-tar" = archiveManager;
46 | "application/x-tar" = archiveManager;
47 | "application/x-tarz" = archiveManager;
48 | "application/x-xar" = archiveManager;
49 | "application/x-xz" = archiveManager;
50 | "application/x-xz-compressed-tar" = archiveManager;
51 | "application/zip" = archiveManager;
52 | "application/gzip" = archiveManager;
53 | "application/bzip2" = archiveManager;
54 | "application/vnd.rar" = archiveManager;
55 |
56 | # Images
57 | "image/jpeg" = imageViewer;
58 | "image/png" = imageViewer;
59 | "image/gif" = imageViewer;
60 | "image/webp" = imageViewer;
61 | "image/tiff" = imageViewer;
62 | "image/x-tga" = imageViewer;
63 | "image/vnd-ms.dds" = imageViewer;
64 | "image/x-dds" = imageViewer;
65 | "image/bmp" = imageViewer;
66 | "image/vnd.microsoft.icon" = imageViewer;
67 | "image/vnd.radiance" = imageViewer;
68 | "image/x-exr" = imageViewer;
69 | "image/x-portable-bitmap" = imageViewer;
70 | "image/x-portable-graymap" = imageViewer;
71 | "image/x-portable-pixmap" = imageViewer;
72 | "image/x-portable-anymap" = imageViewer;
73 | "image/x-qoi" = imageViewer;
74 | "image/svg+xml" = imageViewer;
75 | "image/svg+xml-compressed" = imageViewer;
76 | "image/avif" = imageViewer;
77 | "image/heic" = imageViewer;
78 | "image/jxl" = imageViewer;
79 | };
80 | }
81 |
--------------------------------------------------------------------------------
/home/common/desktop/ghostty.nix:
--------------------------------------------------------------------------------
1 | { pkgs, self, ... }:
2 | let
3 | theme = import "${self}/lib/theme" { inherit pkgs; };
4 | in
5 | {
6 | programs.ghostty = {
7 | enable = true;
8 | settings = {
9 | theme = "catppucin-macchiato";
10 | font-family = "${theme.fonts.monospace.name}";
11 | font-size = 14;
12 | window-padding-x = 10;
13 | window-padding-y = 10;
14 | };
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/home/common/desktop/gtk.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | self,
4 | config,
5 | ...
6 | }:
7 | let
8 | theme = import "${self}/lib/theme" { inherit pkgs; };
9 | in
10 | {
11 | home.pointerCursor = {
12 | inherit (theme.cursorTheme) package size name;
13 | gtk.enable = true;
14 | x11.enable = true;
15 | };
16 |
17 | gtk = {
18 | enable = true;
19 |
20 | theme = theme.gtkTheme;
21 |
22 | font = {
23 | inherit (theme.fonts.default) package;
24 | name = "${theme.fonts.default.name}, ${theme.fonts.default.size}";
25 | };
26 |
27 | gtk2 = {
28 | configLocation = "${config.xdg.configHome}/gtk-2.0/gtkrc";
29 | extraConfig = ''
30 | gtk-application-prefer-dark-theme=1
31 | '';
32 | };
33 |
34 | gtk3.extraConfig = {
35 | gtk-button-images = 1;
36 | gtk-application-prefer-dark-theme = true;
37 | };
38 |
39 | gtk4.extraConfig = {
40 | gtk-application-prefer-dark-theme = true;
41 | };
42 |
43 | iconTheme = {
44 | inherit (theme.iconTheme) name package;
45 | };
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/config/displays.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | kara = {
3 | workspace = [ ];
4 | monitor = [ "DP-1, 7680x2160@120Hz, auto, 1" ];
5 | };
6 |
7 | freyja = {
8 | workspace = [ ];
9 | monitor = [ "eDP-1, preferred, auto, 1.5" ];
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/config/keybinds.conf:
--------------------------------------------------------------------------------
1 | # terminal, screen locking, launcher
2 | bind = $mod, RETURN, exec, ghostty
3 | bind = $mod, L, exec, hyprlock
4 | bind = $mod, SPACE, exec, rofi -show drun
5 | bind = ALT, Q, killactive,
6 |
7 | # media controls
8 | bindl = , XF86AudioPlay, exec, playerctl play-pause
9 | bindl = , XF86AudioPrev, exec, playerctl previous
10 | bindl = , XF86AudioNext, exec, playerctl next
11 |
12 | # volume
13 | bindle = , XF86AudioRaiseVolume, exec, volumectl -u up
14 | bindle = , XF86AudioLowerVolume, exec, volumectl -u down
15 | bindl = , XF86AudioMute, exec, volumectl -u toggle-mute
16 | bindl = , XF86AudioMicMute, exec, volumectl -m toggle-mute
17 | bindl = , Pause, exec, volumectl -m toggle-mute
18 |
19 | # backlight
20 | bindle = , XF86MonBrightnessUp, exec, lightctl up
21 | bindle = , XF86MonBrightnessDown, exec, lightctl down
22 |
23 | # clipboard
24 | bind = $mod, C, exec, bash -c "export XDG_CACHE_HOME=/home/$USER/.local/cache; cliphist list | rofi -dmenu -display-columns 2 -window-title "📋" | cliphist decode | wl-copy"
25 |
26 | # apps
27 | bind = $mod, grave, exec, 1password --quick-access
28 | bind = $mod, E, exec, bemoji -c -n
29 |
30 | # window controls
31 | bind = $mod, F, fullscreen,
32 | bind = $mod SHIFT, Space, togglefloating,
33 | bind = $mod, A, togglesplit,
34 |
35 | # override the split direction for the next window to be opened
36 | bind = $mod, V, layoutmsg, preselect d
37 | bind = $mod, H, layoutmsg, preselect r
38 |
39 | # group management
40 | bind = $mod, G, togglegroup,
41 | bind = $mod SHIFT, G, moveoutofgroup,
42 | bind = ALT, left, changegroupactive, b
43 | bind = ALT, right, changegroupactive, f
44 |
45 | # move focus
46 | bind = $mod, left, movefocus, l
47 | bind = $mod, right, movefocus, r
48 | bind = $mod, up, movefocus, u
49 | bind = $mod, down, movefocus, d
50 |
51 | # move window
52 | bind = $mod SHIFT, left, movewindoworgroup, l
53 | bind = $mod SHIFT, right, movewindoworgroup, r
54 | bind = $mod SHIFT, up, movewindoworgroup, u
55 | bind = $mod SHIFT, down, movewindoworgroup, d
56 |
57 | # window resize
58 | bind = $mod, R, submap, resize
59 | submap = resize
60 | binde = , right, resizeactive, 10 0
61 | binde = , left, resizeactive, -10 0
62 | binde = , up, resizeactive, 0 -10
63 | binde = , down, resizeactive, 0 10
64 | bind = , escape, submap, reset
65 | submap = reset
66 |
67 | # mouse bindings
68 | bindm = SUPER, mouse:272, movewindow
69 | bindm = SUPER, mouse:273, resizewindow
70 |
71 | # navigate workspaces
72 | bind = $mod, 1, workspace, 1
73 | bind = $mod, 2, workspace, 2
74 | bind = $mod, 3, workspace, 3
75 | bind = $mod, 4, workspace, 4
76 | bind = $mod, 5, workspace, 5
77 | bind = $mod, 6, workspace, 6
78 | bind = $mod, 7, workspace, 7
79 | bind = $mod, 8, workspace, 8
80 | bind = $mod, 9, workspace, 9
81 |
82 | # move window to workspace
83 | bind = $mod SHIFT, 1, movetoworkspace, 1
84 | bind = $mod SHIFT, 2, movetoworkspace, 2
85 | bind = $mod SHIFT, 3, movetoworkspace, 3
86 | bind = $mod SHIFT, 4, movetoworkspace, 4
87 | bind = $mod SHIFT, 5, movetoworkspace, 5
88 | bind = $mod SHIFT, 6, movetoworkspace, 6
89 | bind = $mod SHIFT, 7, movetoworkspace, 7
90 | bind = $mod SHIFT, 8, movetoworkspace, 8
91 | bind = $mod SHIFT, 9, movetoworkspace, 9
92 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/config/window-rules.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | windowrulev2 = [
3 | # only allow shadows for floating windows
4 | "noshadow, floating:0"
5 |
6 | # idle inhibit while watching videos
7 | "idleinhibit focus, class:^(mpv|.+exe)$"
8 | "idleinhibit fullscreen, class:.*"
9 |
10 | # make Firefox PiP window floating and sticky
11 | "float, title:^(Picture-in-Picture)$"
12 | "pin, title:^(Picture-in-Picture)$"
13 |
14 | "float, class:^(1Password)$"
15 | "stayfocused,title:^(Quick Access — 1Password)$"
16 | "dimaround,title:^(Quick Access — 1Password)$"
17 | "noanim,title:^(Quick Access — 1Password)$"
18 |
19 | "float, class:^(org.gnome.*)$"
20 | "float, class:^(pavucontrol|com.saivert.pwvucontrol)$"
21 | "float, class:(blueberry\.py)"
22 |
23 | # make pop-up file dialogs floating, centred, and pinned
24 | "float, title:(Open|Progress|Save File)"
25 | "center, title:(Open|Progress|Save File)"
26 | "pin, title:(Open|Progress|Save File)"
27 | "float, class:^(code)$, initialTitle:^((?!Visual Studio Code).)*$"
28 | "center, class:^(code)$, initialTitle:^((?!Visual Studio Code).)*$"
29 | "pin, class:^(code)$, initialTitle:^((?!Visual Studio Code).)*$"
30 |
31 | # assign windows to workspaces
32 | # "workspace 1 silent, class:[Ff]irefox"
33 | # "workspace 2 silent, class:[Oo]bsidian"
34 | # "workspace 2 silent, class:google-chrome"
35 | # "workspace 2 silent, class:[Rr]ambox"
36 | # "workspace 1 silent, class:[Ss]ignal"
37 | # "workspace 5 silent, class:code-url-handler"
38 |
39 | # throw sharing indicators away
40 | "workspace special silent, title:^(Firefox — Sharing Indicator)$"
41 | "workspace special silent, title:^(.*is sharing (your screen|a window)\.)$"
42 | ];
43 | }
44 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | hostname,
4 | lib,
5 | pkgs,
6 | ...
7 | }:
8 | let
9 | theme = import "${self}/lib/theme" { inherit pkgs hostname; };
10 | inherit (theme) colours fonts;
11 | keybinds = builtins.readFile ./config/keybinds.conf;
12 | outputs = (import ./config/displays.nix { }).${hostname};
13 | windowRules = import ./config/window-rules.nix { };
14 | in
15 | {
16 | imports = [
17 | ../wl-common.nix
18 | ./hyprlock.nix
19 | ./hyprshot.nix
20 | ];
21 |
22 | wayland.windowManager.hyprland = {
23 | enable = true;
24 | xwayland.enable = true;
25 |
26 | settings = {
27 | inherit (outputs) monitor workspace;
28 | inherit (windowRules) windowrulev2;
29 |
30 | "$mod" = "SUPER";
31 |
32 | general = {
33 | gaps_in = 4;
34 | gaps_out = 8;
35 | border_size = 0;
36 | };
37 |
38 | dwindle = {
39 | preserve_split = true;
40 | force_split = 2;
41 | };
42 |
43 | gestures = {
44 | workspace_swipe = true;
45 | workspace_swipe_forever = true;
46 | workspace_swipe_invert = false;
47 | };
48 |
49 | input = {
50 | kb_layout = "gb";
51 | follow_mouse = 2;
52 | repeat_rate = 50;
53 | repeat_delay = 300;
54 | };
55 |
56 | decoration = {
57 | rounding = 8;
58 | shadow = {
59 | enabled = true;
60 | ignore_window = true;
61 | offset = "0 5";
62 | range = 50;
63 | render_power = 3;
64 | color = "rgba(00000099)";
65 | };
66 | };
67 |
68 | animation = [
69 | "border, 1, 2, default"
70 | "fade, 1, 4, default"
71 | "windows, 1, 3, default, popin 80%"
72 | "workspaces, 1, 2, default, slide"
73 | ];
74 |
75 | misc = {
76 | background_color = "rgb(${__substring 1 7 colours.surface1})";
77 | disable_hyprland_logo = true;
78 | disable_splash_rendering = true;
79 | animate_manual_resizes = true;
80 | };
81 |
82 | group = {
83 | groupbar = {
84 | font_family = "${fonts.default.name}";
85 | font_size = 12;
86 | gradients = true;
87 | };
88 | };
89 |
90 | xwayland = {
91 | force_zero_scaling = true;
92 | };
93 | };
94 |
95 | extraConfig = ''
96 | ${keybinds}
97 | '';
98 | };
99 |
100 | systemd.user.services.swaybg = {
101 | Unit.Description = "swaybg";
102 | Install.WantedBy = [ "hyprland-session.target" ];
103 | Service = {
104 | Type = "simple";
105 | ExecStart = "${lib.getExe pkgs.swaybg} -m fill -i ${theme.wallpaper}";
106 | Restart = "on-failure";
107 | };
108 | };
109 | }
110 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/hyprlock.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | lib,
4 | pkgs,
5 | hostname,
6 | ...
7 | }:
8 | let
9 | theme = import "${self}/lib/theme" { inherit pkgs hostname; };
10 | inherit (theme) hexToRgb colours;
11 | in
12 | {
13 | programs.hyprlock = {
14 | enable = true;
15 | settings = {
16 | general = {
17 | grace = 5;
18 | hide_cursor = true;
19 | };
20 |
21 | background = [
22 | {
23 | path = "${theme.wallpaper}";
24 | blur_passes = 2;
25 | blur_size = 6;
26 | }
27 | ];
28 |
29 | input-field = [
30 | {
31 | size = "250, 60";
32 | outer_color = "rgb(${hexToRgb colours.black})";
33 | inner_color = "rgb(${hexToRgb colours.bgDark})";
34 | font_color = "rgb(${hexToRgb colours.purple})";
35 | placeholder_text = "";
36 | }
37 | ];
38 |
39 | label = [
40 | {
41 | text = "Hello";
42 | color = "rgba(${hexToRgb colours.text}, 1.0)";
43 | font_family = theme.fonts.default.name;
44 | font_size = 64;
45 | text_align = "center";
46 | halign = "center";
47 | valign = "center";
48 | position = "0, 160";
49 | }
50 | {
51 | text = "$TIME";
52 | color = "rgba(${hexToRgb colours.subtext1}, 1.0)";
53 | font_family = theme.fonts.default.name;
54 | font_size = 32;
55 | text_align = "center";
56 | halign = "center";
57 | valign = "center";
58 | position = "0, 75";
59 | }
60 | ];
61 | };
62 | };
63 |
64 | services.hypridle = {
65 | enable = true;
66 | settings = {
67 | general = {
68 | lock_cmd = "${lib.getExe pkgs.hyprlock}";
69 | before_sleep_cmd = "${lib.getExe pkgs.hyprlock}";
70 | };
71 |
72 | listener = [
73 | {
74 | timeout = 300;
75 | on-timeout = "${lib.getExe pkgs.hyprlock}";
76 | }
77 | {
78 | timeout = 305;
79 | on-timeout = "${pkgs.hyprland}/bin/hyprctl dispatch dpms off";
80 | on-resume = "${pkgs.hyprland}/bin/hyprctl dispatch dpms on";
81 | }
82 | ];
83 | };
84 | };
85 | }
86 |
--------------------------------------------------------------------------------
/home/common/desktop/hyprland/hyprshot.nix:
--------------------------------------------------------------------------------
1 | {
2 | config,
3 | lib,
4 | pkgs,
5 | ...
6 | }:
7 | {
8 | home = {
9 | file = {
10 | "${config.xdg.configHome}/satty/config.toml".text = ''
11 | [general]
12 | # Start Satty in fullscreen mode
13 | fullscreen = false
14 | # Exit directly after copy/save action
15 | early-exit = false
16 | # Select the tool on startup [possible values: pointer, crop, line, arrow, rectangle, text, marker, blur, brush]
17 | initial-tool = "pointer"
18 | # Configure the command to be called on copy, for example `wl-copy`
19 | copy-command = "${pkgs.wl-clipboard}/bin/wl-copy"
20 | # Increase or decrease the size of the annotations
21 | annotation-size-factor = 1
22 | # Filename to use for saving action: https://docs.rs/chrono/latest/chrono/format/strftime/index.html
23 | output-filename = "${config.home.homeDirectory}/pictures/screenshots/screenshot-%Y%m%d-%H%M%S.png"
24 | save-after-copy = false
25 | default-hide-toolbars = false
26 | # The primary highlighter: block, freehand
27 | primary-highlighter = "block"
28 | disable-notifications = false
29 |
30 | # Font to use for text annotations
31 | [font]
32 | family = "Work Sans"
33 | style = "Bold"
34 | '';
35 | };
36 | packages = with pkgs; [
37 | hyprshot # screenshot grabber
38 | satty # screenshot editor
39 | ];
40 | };
41 | wayland.windowManager.hyprland = {
42 | settings = {
43 | bind = [
44 | ", Print, exec, ${lib.getExe pkgs.hyprshot} --mode output --raw | ${lib.getExe pkgs.satty} --filename -"
45 | "SHIFT, Print, exec, ${lib.getExe pkgs.hyprshot} --mode window --raw | ${lib.getExe pkgs.satty} --filename -"
46 | "ALT, Print, exec, ${lib.getExe pkgs.hyprshot} --mode region --raw | ${lib.getExe pkgs.satty} --filename -"
47 | ];
48 | };
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/home/common/desktop/mako.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | self,
4 | hostname,
5 | ...
6 | }:
7 | let
8 | theme = import "${self}/lib/theme" { inherit pkgs; };
9 | in
10 | {
11 | catppuccin.mako.enable = true;
12 |
13 | services = {
14 | mako = {
15 | enable = true;
16 | actions = true;
17 | anchor = if hostname == "kara" then "top-center" else "top-right";
18 | borderRadius = 8;
19 | borderSize = 1;
20 | defaultTimeout = 10000;
21 | font = "${theme.fonts.default.name}";
22 | iconPath = "${theme.iconTheme.iconPath}";
23 | icons = true;
24 | layer = "overlay";
25 | maxVisible = 3;
26 | padding = "10";
27 | width = 300;
28 | };
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/home/common/desktop/qt.nix:
--------------------------------------------------------------------------------
1 | { pkgs, self, ... }:
2 | let
3 | theme = import "${self}/lib/theme" { inherit pkgs; };
4 | in
5 | {
6 | qt = {
7 | enable = true;
8 | platformTheme.name = "gtk";
9 | };
10 |
11 | home = {
12 | packages = with pkgs; [
13 | theme.qtTheme.package
14 | libsForQt5.qtstyleplugin-kvantum
15 | ];
16 | sessionVariables = {
17 | "QT_STYLE_OVERRIDE" = "kvantum";
18 | };
19 | };
20 |
21 | xdg.configFile = {
22 | "Kvantum/kvantum.kvconfig".text = ''
23 | [General]
24 | theme=${theme.qtTheme.name}
25 | '';
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/home/common/desktop/rofi.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | catppuccin.rofi = {
4 | enable = true;
5 | flavor = "mocha";
6 | };
7 |
8 | programs.rofi = {
9 | enable = true;
10 | package = pkgs.rofi-wayland;
11 | terminal = "${pkgs.ghostty}/bin/ghostty";
12 |
13 | extraConfig = {
14 | modi = "drun";
15 | show-icons = true;
16 | drun-display-format = "{icon} {name}";
17 | disable-history = false;
18 | hide-scrollbar = true;
19 | display-drun = " Apps ";
20 | sidebar-mode = true;
21 | };
22 | };
23 |
24 | home.packages = [ pkgs.bemoji ];
25 | }
26 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/config/displays.nix:
--------------------------------------------------------------------------------
1 | { wallpaper, ... }:
2 | {
3 | kara = {
4 | "DP-1" = {
5 | mode = "7680x2160@119.997Hz";
6 | bg = "${wallpaper} fill";
7 | };
8 | };
9 |
10 | freyja = {
11 | "eDP-1" = {
12 | mode = "2880x1800@60Hz";
13 | scale = 1.5;
14 | bg = "${wallpaper} fill";
15 | };
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/config/keybindings.nix:
--------------------------------------------------------------------------------
1 | {
2 | modifier,
3 | terminal,
4 | menu,
5 | pkgs,
6 | ...
7 | }:
8 | {
9 | main = {
10 | # Open a terminal
11 | "${modifier}+Return" = "exec ${terminal}";
12 | # Toggle the launcher
13 | "${modifier}+Space" = "exec ${menu} | xargs swaymsg exec --";
14 | # Reload the config
15 | "${modifier}+Shift+c" = "reload";
16 | # Lock the screen
17 | "${modifier}+l" = "exec ${pkgs.swaylock-effects}/bin/swaylock -f";
18 | # Kill application
19 | "Mod1+q" = "kill";
20 |
21 | # Screenshots
22 | "Print" = "exec sway-screenshot screen";
23 | "Shift+Print" = "exec sway-screenshot window";
24 | "Alt+Print" = "exec sway-screenshot region";
25 |
26 | # Move focus
27 | "${modifier}+Left" = "focus left";
28 | "${modifier}+Right" = "focus right";
29 | "${modifier}+Up" = "focus up";
30 | "${modifier}+Down" = "focus down";
31 |
32 | # Move windows
33 | "${modifier}+Shift+Left" = "move left";
34 | "${modifier}+Shift+Down" = "move down";
35 | "${modifier}+Shift+Up" = "move up";
36 | "${modifier}+Shift+Right" = "move right";
37 |
38 | # Workspaces
39 | "${modifier}+1" = "workspace number 1";
40 | "${modifier}+2" = "workspace number 2";
41 | "${modifier}+3" = "workspace number 3";
42 | "${modifier}+4" = "workspace number 4";
43 | "${modifier}+5" = "workspace number 5";
44 | "${modifier}+6" = "workspace number 6";
45 | "${modifier}+7" = "workspace number 7";
46 | "${modifier}+8" = "workspace number 8";
47 | "${modifier}+9" = "workspace number 9";
48 |
49 | # Move focused container to workspace
50 | "${modifier}+Shift+1" = "move container to workspace number 1";
51 | "${modifier}+Shift+2" = "move container to workspace number 2";
52 | "${modifier}+Shift+3" = "move container to workspace number 3";
53 | "${modifier}+Shift+4" = "move container to workspace number 4";
54 | "${modifier}+Shift+5" = "move container to workspace number 5";
55 | "${modifier}+Shift+6" = "move container to workspace number 6";
56 | "${modifier}+Shift+7" = "move container to workspace number 7";
57 | "${modifier}+Shift+8" = "move container to workspace number 8";
58 | "${modifier}+Shift+9" = "move container to workspace number 9";
59 |
60 | # Split current object of focus
61 | "${modifier}+h" = "splith";
62 | "${modifier}+v" = "splitv";
63 |
64 | # Switch layout style for current container
65 | "${modifier}+s" = "layout stacking";
66 | "${modifier}+w" = "layout tabbed";
67 | "${modifier}+a" = "layout toggle split";
68 |
69 | # Make current container fullscreen
70 | "${modifier}+f" = "fullscreen";
71 | # Toggle current container between tiling/floating
72 | "${modifier}+Shift+space" = "floating toggle";
73 | # Swap focus between tiled windows and floating window
74 | "Mod1+space" = "focus mode_toggle";
75 | # Focus parent container
76 | # "${modifier}+a" = "focus parent";
77 | # Move focused window to scratch pad
78 | "${modifier}+Shift+minus" = "move scratchpad";
79 | "${modifier}+minus" = "scratchpad show";
80 |
81 | "${modifier}+r" = "mode 'resize'";
82 |
83 | # Audio/Media Keys
84 | "--locked XF86AudioPlay" = "exec ${pkgs.playerctl}/bin/playerctl play-pause";
85 | "--locked XF86AudioNext" = "exec ${pkgs.playerctl}/bin/playerctl next";
86 | "--locked XF86AudioPrev" = "exec ${pkgs.playerctl}/bin/playerctl prev";
87 |
88 | # Volume Keys
89 | "--locked XF86AudioRaiseVolume" = "exec ${pkgs.avizo}/bin/volumectl -u up";
90 | "--locked XF86AudioLowerVolume" = "exec ${pkgs.avizo}/bin/volumectl -u down";
91 | "--locked XF86AudioMute" = "exec ${pkgs.avizo}/bin/volumectl toggle-mute";
92 | "--locked Pause" = "exec ${pkgs.avizo}/bin/volumectl -m toggle-mute";
93 |
94 | # Brightness Controls
95 | "--locked XF86MonBrightnessUp" = "exec ${pkgs.avizo}/bin/lightctl up";
96 | "--locked XF86MonBrightnessDown" = "exec ${pkgs.avizo}/bin/lightctl down";
97 |
98 | # Applications
99 | "Mod1+grave" = "exec ${pkgs._1password-gui}/bin/1password --quick-access";
100 | "${modifier}+c" = "exec sway-clip";
101 | "${modifier}+e" = "exec bemoji -c -n";
102 | };
103 |
104 | resize = {
105 | "Left" = "resize shrink width 10px";
106 | "Right" = "resize shrink width 10px";
107 | "Up" = "resize shrink height 10px";
108 | "Down" = "resize grow height 10px";
109 | "Return" = "mode 'default'";
110 | "Escape" = "mode 'default'";
111 | };
112 | }
113 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/config/window-rules.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | commands = [
3 | # Floating window config
4 | {
5 | command = "floating enable";
6 | criteria = {
7 | window_role = "pop up|bubble|task_dialog|Preferences|page-info|Saves As|dialog|menu";
8 | };
9 | }
10 | {
11 | command = "floating enable";
12 | criteria = {
13 | app_id = "org.gnome.*|nm-connection-editor|pavucontrol|com.saivert.pwvucontrol|pinentry-qt|^code$";
14 | };
15 | }
16 | {
17 | command = "floating enable";
18 | criteria = {
19 | title = "Picture-in-picture|1Password";
20 | };
21 | }
22 | {
23 | command = "floating enable";
24 | criteria = {
25 | class = "1Password";
26 | };
27 | }
28 | # Floating & Sticky windows
29 | {
30 | command = "floating enable sticky";
31 | criteria = {
32 | window_role = "Open Files|Open Folder|File Operation Progress";
33 | };
34 | }
35 | # Sticky windows
36 | {
37 | command = "sticky enable";
38 | criteria = {
39 | app_id = "^code$";
40 | };
41 | }
42 | {
43 | command = "sticky enable";
44 | criteria = {
45 | instance = "file_progress";
46 | };
47 | }
48 | {
49 | command = "sticky enable";
50 | criteria = {
51 | class = "info|Mate-color-select|gcolor2|timesup|QtPass|GtkFileChooserDialog";
52 | };
53 | }
54 | # Inhibit idle when there is a fullscreen app
55 | {
56 | command = "inhibit_idle fullscreen";
57 | criteria = {
58 | class = ".*";
59 | };
60 | }
61 | ];
62 | }
63 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | self,
4 | hostname,
5 | ...
6 | }:
7 | {
8 | imports = [
9 | ../wl-common.nix
10 |
11 | ./packages.nix
12 | ./swappy.nix
13 | ./swaylock.nix
14 | ];
15 |
16 | wayland.windowManager.sway =
17 | let
18 | theme = import "${self}/lib/theme" { inherit pkgs hostname; };
19 | modifier = "Mod4";
20 | terminal = "ghostty";
21 | menu = "rofi -show drun";
22 | in
23 | {
24 | enable = true;
25 |
26 | systemd.enable = true;
27 | wrapperFeatures = {
28 | gtk = true;
29 | base = true;
30 | };
31 |
32 | config = {
33 | inherit menu terminal modifier;
34 | bars = [ ];
35 | gaps = {
36 | inner = 8;
37 | };
38 |
39 | input = {
40 | "*" = {
41 | xkb_layout = "gb";
42 | };
43 | "type:keyboard" = {
44 | repeat_rate = "100";
45 | repeat_delay = "250";
46 | };
47 | "type:touchpad" = {
48 | tap = "enabled";
49 | };
50 | };
51 |
52 | output = (import ./config/displays.nix { inherit (theme) wallpaper; })."${hostname}";
53 |
54 | fonts = {
55 | names = [ "${theme.fonts.iconFont.name}" ];
56 | size = 8.0;
57 | };
58 |
59 | window = {
60 | border = 0;
61 | hideEdgeBorders = "none";
62 | titlebar = false;
63 | inherit ((import ./config/window-rules.nix { inherit theme; })) commands;
64 | };
65 |
66 | floating = {
67 | border = 1;
68 | titlebar = false;
69 | };
70 |
71 | focus = {
72 | newWindow = "focus";
73 | followMouse = "no";
74 | };
75 |
76 | startup = [ ];
77 |
78 | keybindings =
79 | (import ./config/keybindings.nix {
80 | inherit
81 | terminal
82 | menu
83 | modifier
84 | pkgs
85 | ;
86 | }).main;
87 | modes.resize =
88 | (import ./config/keybindings.nix {
89 | inherit
90 | terminal
91 | menu
92 | modifier
93 | pkgs
94 | ;
95 | }).resize;
96 | };
97 | };
98 | }
99 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/packages.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | let
3 | sway-screenshot = pkgs.writeShellScriptBin "sway-screenshot" ''
4 | if [[ "$1" == "screen" ]]; then
5 | grim -o $(swaymsg -t get_outputs | jq -r '.[] | select(.focused) | .name') - | swappy -f -
6 | elif [[ "$1" == "window" ]]; then
7 | grim -g "$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)" - | swappy -f -
8 | elif [[ "$1" == "region" ]]; then
9 | grim -g "$(slurp)" - | swappy -f -
10 | fi
11 | '';
12 | sway-clip = pkgs.writeShellScriptBin "sway-clip" ''
13 | export XDG_CACHE_HOME=/home/$USER/.local/cache
14 | cliphist list | rofi -dmenu -display-columns 2 -window-title '📋' | cliphist decode | wl-copy
15 | '';
16 | in
17 | {
18 | home.packages = with pkgs; [
19 | grim
20 | slurp
21 | sway-clip
22 | sway-screenshot
23 | ];
24 | }
25 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/swappy.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | home.packages = with pkgs; [ swappy ];
4 |
5 | home.file = {
6 | ".config/swappy/config".text = ''
7 | [Default]
8 | save_dir=$HOME/pictures/screenshots
9 | save_filename_format=screenshot-%Y%m%d-%H%M%S.png
10 | early_exit=true
11 | '';
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/home/common/desktop/sway/swaylock.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | pkgs,
4 | self,
5 | hostname,
6 | ...
7 | }:
8 | let
9 | theme = import "${self}/lib/theme" { inherit pkgs hostname; };
10 | in
11 | {
12 | programs.swaylock = {
13 | enable = true;
14 | package = pkgs.swaylock-effects;
15 |
16 | settings = {
17 |
18 | font = "${theme.fonts.default.name}";
19 | clock = true;
20 |
21 | indicator = true;
22 | ignore-empty-password = true;
23 | indicator-idle-visible = true;
24 | disable-caps-lock-text = true;
25 |
26 | timestr = "%R";
27 | datestr = "%a, %e of %B";
28 | image = "${theme.wallpaper}";
29 | # effect-blur = "30x3";
30 |
31 | key-hl-color = "${theme.colours.green}";
32 | separator-color = "${theme.colours.black}00";
33 |
34 | inside-color = "${theme.colours.bg}99";
35 | inside-clear-color = "${theme.colours.yellow}00";
36 | inside-caps-lock-color = "${theme.colours.lightBlue}00";
37 | inside-ver-color = "${theme.colours.overlay0}00";
38 | inside-wrong-color = "${theme.colours.red}00";
39 |
40 | ring-color = "${theme.colours.bgDark}D9";
41 | ring-clear-color = "${theme.colours.bgDark}D9";
42 | ring-caps-lock-color = "${theme.colours.bgDark}D9";
43 | ring-ver-color = "${theme.colours.bgDark}D9";
44 | ring-wrong-color = "${theme.colours.bgDark}D9";
45 |
46 | line-color = "${theme.colours.black}00";
47 | line-clear-color = "${theme.colours.yellow}FF";
48 | line-caps-lock-color = "${theme.colours.lightBlue}FF";
49 | line-ver-color = "${theme.colours.overlay0}FF";
50 | line-wrong-color = "${theme.colours.red}FF";
51 |
52 | text-clear-color = "${theme.colours.yellow}00";
53 | text-ver-color = "${theme.colours.overlay0}00";
54 | text-wrong-color = "${theme.colours.red}00";
55 |
56 | bs-hl-color = "${theme.colours.red}FF";
57 | caps-lock-key-hl-color = "${theme.colours.yellow}FF";
58 | caps-lock-bs-hl-color = "${theme.colours.red}FF";
59 | text-caps-lock-color = "${theme.colours.lightBlue}";
60 | };
61 | };
62 |
63 | services.swayidle = {
64 | enable = true;
65 | extraArgs = [ "-w" ];
66 | events = [
67 | {
68 | event = "before-sleep";
69 | command = "${lib.getExe pkgs.swaylock-effects} -f";
70 | }
71 | {
72 | event = "lock";
73 | command = "${lib.getExe pkgs.swaylock-effects} -f";
74 | }
75 | ];
76 | timeouts = [
77 | {
78 | timeout = 300;
79 | command = "${lib.getExe pkgs.swaylock-effects} -f";
80 | }
81 | {
82 | timeout = 305;
83 | command = ''${pkgs.sway}/bin/swaymsg "output * dpms off"'';
84 | resumeCommand = ''${pkgs.sway}/bin/swaymsg "output * dpms on"'';
85 | }
86 | ];
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/home/common/desktop/waybar/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | config,
4 | pkgs,
5 | lib,
6 | hostname,
7 | desktop,
8 | ...
9 | }:
10 | let
11 | # If this is a laptop, then include network/battery controls
12 | modules =
13 | if hostname == "freyja" then
14 | [
15 | "network"
16 | "battery"
17 | "custom/vpn"
18 | "wireplumber"
19 | "pulseaudio#source"
20 | "bluetooth"
21 | "group/group-power"
22 | ]
23 | else
24 | [
25 | "wireplumber"
26 | "pulseaudio#source"
27 | "bluetooth"
28 | "group/group-power"
29 | ];
30 |
31 | workspaceConfig = {
32 | format = "{icon}";
33 | format-icons = {
34 | "1" = "";
35 | "2" = "";
36 | "3" = "";
37 | "4" = "";
38 | "5" = "";
39 | "6" = "";
40 | "7" = "";
41 | };
42 | on-click = "activate";
43 | };
44 |
45 | bluetoothToggle = pkgs.writeShellApplication {
46 | name = "bluetooth-toggle";
47 | runtimeInputs = with pkgs; [
48 | gnugrep
49 | bluez
50 | ];
51 | text = ''
52 | if [[ "$(bluetoothctl show | grep -Po "Powered: \K(.+)$")" =~ no ]]; then
53 | bluetoothctl power on
54 | bluetoothctl discoverable on
55 | else
56 | bluetoothctl power off
57 | fi
58 | '';
59 | };
60 |
61 | tsCheck = pkgs.writeShellApplication {
62 | name = "tscheck";
63 | runtimeInputs = with pkgs; [
64 | tailscale
65 | jq
66 | ];
67 | text = ''
68 | if [[ "$1" == "toggle" ]]; then
69 | if [[ "$(tailscale status --json | jq -r '.BackendState')" == "Stopped" ]]; then
70 | tailscale up --operator=jon --ssh --reset
71 | else
72 | tailscale down
73 | fi
74 | elif [[ "$1" == "exit" ]]; then
75 | if [[ "$(tailscale status --json | jq -r '.ExitNodeStatus.Online')" == "true" ]]; then
76 | tailscale set --exit-node=
77 | else
78 | tailscale set --exit-node=gb-lon-wg-001.mullvad.ts.net &>/dev/null
79 | fi
80 | fi
81 |
82 | if tailscale status &>/dev/null; then
83 | if [[ "$(tailscale status --json | jq -r '.ExitNodeStatus.Online')" == "true" ]]; then
84 | ip="$(tailscale status --json | jq -r '.ExitNodeStatus.TailscaleIPs[0]')"
85 | echo "{\"text\": \"\", \"tooltip\": \"Connected to exit node ($ip)\", \"class\": \"exitNode\"}" | jq --unbuffered --compact-output
86 | else
87 | echo "{\"text\": \"\", \"tooltip\": \"Connected to tailnet\", \"class\": \"tailnet\"}" | jq --unbuffered --compact-output
88 | fi
89 | else
90 | echo '{"text": "", "tooltip": "Disconnected", "class": "disconnected"}' | jq --unbuffered --compact-output
91 | fi
92 | '';
93 | };
94 |
95 | theme = import "${self}/lib/theme" { inherit pkgs; };
96 | inherit ((import ./lib.nix { inherit lib; })) toRasi;
97 | in
98 | {
99 | programs.waybar = {
100 | enable = true;
101 |
102 | systemd = {
103 | enable = true;
104 | };
105 |
106 | settings = [
107 | {
108 | exclusive = true;
109 | position = "top";
110 | layer = "top";
111 | height = 18;
112 | width = if hostname == "kara" then 2560 else null;
113 | passthrough = false;
114 | gtk-layer-shell = true;
115 |
116 | modules-left = [ (if desktop == "hyprland" then "hyprland/workspaces" else "sway/workspaces") ];
117 | modules-center = [
118 | "clock"
119 | "idle_inhibitor"
120 | ];
121 | modules-right = modules;
122 |
123 | "hyprland/workspaces" = workspaceConfig;
124 | "sway/workspaces" = workspaceConfig;
125 |
126 | "network" = {
127 | format-wifi = "{essid} ";
128 | format-ethernet = "{ifname} ";
129 | format-disconnected = "";
130 | tooltip-format = "{ifname} / {essid} ({signalStrength}%) / {ipaddr}";
131 | max-length = 15;
132 | on-click = "${pkgs.ghostty}/bin/ghostty -e ${pkgs.networkmanager}/bin/nmtui";
133 | };
134 |
135 | "idle_inhibitor" = {
136 | format = "{icon}";
137 | format-icons = {
138 | activated = "";
139 | deactivated = "";
140 | };
141 | };
142 |
143 | "battery" = {
144 | states = {
145 | good = 95;
146 | warning = 20;
147 | critical = 10;
148 | };
149 | format = "{capacity}% {icon}";
150 | format-charging = "{capacity}% ";
151 | format-plugged = "";
152 | tooltip-format = "{time} ({capacity}%)";
153 | format-alt = "{time} {icon}";
154 | format-full = "";
155 | format-icons = [
156 | ""
157 | ""
158 | ""
159 | ""
160 | ""
161 | ];
162 | };
163 |
164 | "custom/vpn" = {
165 | format = "{}";
166 | exec = "${lib.getExe tsCheck} status";
167 | on-click = "${lib.getExe tsCheck} toggle";
168 | on-click-right = "${lib.getExe tsCheck} exit";
169 | return-type = "json";
170 | interval = 1;
171 | };
172 |
173 | "group/group-power" = {
174 | orientation = "inherit";
175 | drawer = {
176 | transition-duration = 500;
177 | transition-left-to-right = false;
178 | };
179 | modules = [
180 | "custom/power"
181 | "custom/quit"
182 | "custom/lock"
183 | "custom/reboot"
184 | ];
185 | };
186 |
187 | "custom/quit" = {
188 | format = "";
189 | on-click =
190 | if desktop == "hyprland" then
191 | "${pkgs.hyprland}/bin/hyprctl dispatch exit"
192 | else
193 | "${pkgs.sway}/bin/swaymsg exit";
194 | tooltip = false;
195 | };
196 |
197 | "custom/lock" = {
198 | format = "";
199 | on-click =
200 | if desktop == "hyprland" then
201 | "${pkgs.hyprlock}/bin/hyprlock"
202 | else
203 | "${pkgs.swaylock-effects}/bin/swaylock -f";
204 | tooltip = false;
205 | };
206 |
207 | "custom/reboot" = {
208 | format = "";
209 | on-click = "${pkgs.systemd}/bin/systemctl reboot";
210 | tooltip = false;
211 | };
212 |
213 | "custom/power" = {
214 | format = "";
215 | on-click = "${pkgs.systemd}/bin/systemctl poweroff";
216 | tooltip = false;
217 | };
218 |
219 | "clock" = {
220 | format = "{:%d %b %H:%M}";
221 | };
222 |
223 | "wireplumber" = {
224 | format = "{volume}% {icon}";
225 | format-muted = "";
226 | on-click = "${lib.getExe pkgs.pwvucontrol}";
227 | format-icons = [
228 | ""
229 | ""
230 | ""
231 | ];
232 | tooltip-format = "{volume}% / {node_name}";
233 | };
234 |
235 | "pulseaudio#source" = {
236 | format = "{format_source}";
237 | format-source = "";
238 | format-source-muted = "";
239 | on-click = "${lib.getExe pkgs.pwvucontrol}";
240 | tooltip-format = "{source_volume}% / {desc}";
241 | };
242 |
243 | "bluetooth" = {
244 | format-on = "";
245 | format-connected = "{device_alias} ";
246 | format-off = "";
247 | format-disabled = "";
248 | on-click-right = "${lib.getExe' pkgs.blueberry "blueberry"}";
249 | on-click = "${lib.getExe bluetoothToggle}";
250 | };
251 | }
252 | ];
253 |
254 | # This is a bit of a hack. Rasi turns out to be basically CSS, and there is
255 | # a handy helper to convert nix -> rasi in the home-manager module for rofi,
256 | # so I'm using that here to render the stylesheet for waybar
257 | style =
258 | toRasi
259 | (import ./theme.nix {
260 | inherit
261 | config
262 | desktop
263 | lib
264 | pkgs
265 | theme
266 | ;
267 | }).theme;
268 | };
269 |
270 | # This is a hack to ensure that hyprctl ends up in the PATH for the waybar service on hyprland
271 | systemd.user.services.waybar.Service.Environment = lib.optional (desktop == "hyprland") (
272 | lib.mkForce "PATH=${lib.makeBinPath [ pkgs."${desktop}" ]}"
273 | );
274 | }
275 |
--------------------------------------------------------------------------------
/home/common/desktop/waybar/lib.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | let
3 | inherit (lib) isBool isInt;
4 | inherit (builtins)
5 | toString
6 | isList
7 | isString
8 | concatStringsSep
9 | concatMap
10 | removeAttrs
11 | isAttrs
12 | ;
13 | inherit (lib.attrsets) filterAttrs;
14 |
15 | # Copied from https://github.com/nix-community/home-manager/blob/master/modules/programs/rofi.nix
16 | mkValueString =
17 | value:
18 | if isBool value then
19 | if value then "true" else "false"
20 | else if isInt value then
21 | toString value
22 | else if (value._type or "") == "literal" then
23 | value.value
24 | else if isString value then
25 | ''"${value}"''
26 | else if isList value then
27 | "[ ${concatStringsSep "," (map mkValueString value)} ]"
28 | else
29 | abort "Unhandled value type ${builtins.typeOf value}";
30 |
31 | mkKeyValue =
32 | {
33 | sep ? ": ",
34 | end ? ";",
35 | }:
36 | name: value: "${name}${sep}${mkValueString value}${end}";
37 |
38 | mkRasiSection =
39 | name: value:
40 | if isAttrs value then
41 | let
42 | toRasiKeyValue = lib.generators.toKeyValue { mkKeyValue = mkKeyValue { }; };
43 | # Remove null values so the resulting config does not have empty lines
44 | configStr = toRasiKeyValue (filterAttrs (_: v: v != null) value);
45 | in
46 | ''
47 | ${name} {
48 | ${configStr}}
49 | ''
50 | else
51 | (mkKeyValue {
52 | sep = " ";
53 | end = "";
54 | } name value)
55 | + "\n";
56 | in
57 | {
58 | toRasi =
59 | attrs:
60 | concatStringsSep "\n" (
61 | concatMap (lib.attrsets.mapAttrsToList mkRasiSection) [
62 | (filterAttrs (n: _: n == "@theme") attrs)
63 | (filterAttrs (n: _: n == "@import") attrs)
64 | (removeAttrs attrs [
65 | "@theme"
66 | "@import"
67 | ])
68 | ]
69 | );
70 | }
71 |
--------------------------------------------------------------------------------
/home/common/desktop/waybar/theme.nix:
--------------------------------------------------------------------------------
1 | {
2 | config,
3 | lib,
4 | theme,
5 | desktop,
6 | ...
7 | }:
8 | {
9 | theme =
10 | let
11 | inherit (config.lib.formats.rasi) mkLiteral;
12 | in
13 | {
14 | "*" = {
15 | border = mkLiteral "none";
16 | padding = mkLiteral "0px";
17 | font-family = "${theme.fonts.iconFont.name}";
18 | font-size = mkLiteral "15px";
19 | };
20 |
21 | "window#waybar" = {
22 | background-color = mkLiteral "transparent";
23 | };
24 |
25 | "window>box" = {
26 | margin = mkLiteral "8px 8px 0px 8px";
27 | background = mkLiteral "${theme.colours.bg}";
28 | opacity = mkLiteral "0.8";
29 | border-radius = mkLiteral "8px";
30 | };
31 |
32 | ".modules-right" = {
33 | margin-right = mkLiteral "10px";
34 | padding = mkLiteral "5px 10px";
35 | };
36 |
37 | ".modules-center" = {
38 | margin = mkLiteral "0px";
39 | padding = mkLiteral "5px 10px";
40 | };
41 |
42 | ".modules-left" = {
43 | margin-left = mkLiteral "10px";
44 | padding = mkLiteral "5px 0px";
45 | };
46 |
47 | "#workspaces button" = {
48 | padding = if desktop == "hyprland" then mkLiteral "0px 10px" else mkLiteral "0px";
49 | background-color = mkLiteral "transparent";
50 | font-weight = mkLiteral "lighter";
51 | color = mkLiteral "${theme.colours.text}";
52 | };
53 |
54 | "#workspaces button:hover" = {
55 | color = mkLiteral "${theme.colours.accent}";
56 | background-color = mkLiteral "transparent";
57 | };
58 |
59 | "#workspaces button.focused, #workspaces button.active" = {
60 | color = mkLiteral "${theme.colours.accent}";
61 | font-weight = mkLiteral "normal";
62 | background-color = mkLiteral "transparent";
63 | };
64 |
65 | "#battery,
66 | #bluetooth,
67 | #clock,
68 | #cpu,
69 | #custom-lock,
70 | #custom-power,
71 | #custom-quit,
72 | #custom-reboot,
73 | #custom-vpn,
74 | #group-group-power,
75 | #idle_inhibitor,
76 | #memory,
77 | #network,
78 | #pulseaudio,
79 | #wireplumber" =
80 | {
81 | padding = mkLiteral "0px 10px";
82 | color = mkLiteral "${theme.colours.text}";
83 | };
84 |
85 | "#custom-vpn.tailnet" = {
86 | color = mkLiteral "${theme.colours.blue}";
87 | background-color = mkLiteral "transparent";
88 | };
89 | "#custom-vpn.exitNode" = {
90 | color = mkLiteral "${theme.colours.green}";
91 | background-color = mkLiteral "transparent";
92 | };
93 | "#custom-vpn.disconnected" = {
94 | color = mkLiteral "${theme.colours.red}";
95 | background-color = mkLiteral "transparent";
96 | };
97 |
98 | "#custom-power" = {
99 | color = mkLiteral "${theme.colours.accent}";
100 | background-color = mkLiteral "transparent";
101 | };
102 |
103 | "#custom-quit, #custom-lock, #custom-reboot" = {
104 | color = mkLiteral "${theme.colours.red}";
105 | background-color = mkLiteral "transparent";
106 | };
107 |
108 | # -----Indicators----
109 | "#idle_inhibitor.activated" = {
110 | color = mkLiteral "${theme.colours.accent}";
111 | };
112 |
113 | "#battery.charging" = {
114 | color = mkLiteral "${theme.colours.green}";
115 | };
116 |
117 | "#battery.warning:not(.charging)" = {
118 | color = mkLiteral "${theme.colours.orange}";
119 | };
120 |
121 | "#battery.critical:not(.charging)" = {
122 | color = mkLiteral "${theme.colours.red}";
123 | };
124 |
125 | "#temperature.critical" = {
126 | color = mkLiteral "${theme.colours.red}";
127 | };
128 |
129 | "#bluetooth.off" = {
130 | color = mkLiteral "${theme.colours.orange}";
131 | };
132 |
133 | "#wireplumber.muted" = {
134 | color = mkLiteral "${theme.colours.orange}";
135 | };
136 |
137 | "#pulseaudio.source-muted" = {
138 | color = mkLiteral "${theme.colours.orange}";
139 | };
140 | };
141 | }
142 |
--------------------------------------------------------------------------------
/home/common/desktop/wl-common.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | imports = [
4 | ./waybar
5 | ./mako.nix
6 | ./rofi.nix
7 | ];
8 |
9 | services = {
10 | avizo.enable = true;
11 |
12 | cliphist = {
13 | enable = true;
14 | package = pkgs.cliphist;
15 | };
16 |
17 | gnome-keyring.enable = true;
18 |
19 | wlsunset = {
20 | enable = true;
21 | latitude = "51.51";
22 | longitude = "-2.53";
23 | };
24 | };
25 |
26 | systemd.user.services.polkit-gnome-authentication-agent-1 = {
27 | Unit.Description = "polkit-gnome-authentication-agent-1";
28 | Install.WantedBy = [ "graphical-session.target" ];
29 | Service = {
30 | Type = "simple";
31 | ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
32 | Restart = "on-failure";
33 | RestartSec = 1;
34 | TimeoutStopSec = 10;
35 | };
36 | };
37 |
38 | home.packages = with pkgs; [
39 | playerctl
40 | wl-clipboard
41 | wdisplays
42 | ];
43 |
44 | home.sessionVariables = {
45 | _JAVA_AWT_WM_NONREPARENTING = "1";
46 | CLUTTER_BACKEND = "wayland";
47 | GDK_BACKEND = "wayland";
48 | MOZ_ENABLE_WAYLAND = "1";
49 | QT_QPA_PLATFORM = "wayland";
50 | # QT_QPA_PLATFORMTHEME = "qt5ct";
51 | QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
52 | SDL_VIDEODRIVER = "wayland";
53 | XDG_SESSION_TYPE = "wayland";
54 | NIXOS_OZONE_WL = "1";
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/home/common/desktop/xdg.nix:
--------------------------------------------------------------------------------
1 | _:
2 | let
3 | inherit ((import ./file-associations.nix)) associations;
4 | in
5 | {
6 | xdg = {
7 | enable = true;
8 | mimeApps = {
9 | enable = true;
10 | defaultApplications = associations;
11 | };
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/home/common/dev/base.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | home.packages = with pkgs; [
4 | ijq
5 |
6 | # Rust tooling
7 | cargo
8 | rust-analyzer
9 | rustfmt
10 | rustc
11 |
12 | gnumake
13 | gcc
14 |
15 | nodejs
16 | nodePackages_latest.prettier
17 |
18 | spread
19 |
20 | # Container tooling
21 | dive
22 | kubectl
23 | skopeo
24 |
25 | # Go tooling
26 | go
27 | go-tools
28 | gofumpt
29 | gopls
30 |
31 | # Nix tooling
32 | deadnix
33 | nil
34 | nix-init
35 | # My custom wrapper that does nixfmt + deadnix + statix
36 | nixfmt-plus
37 | nixfmt-rfc-style
38 | nurl
39 | statix
40 |
41 | # Python tooling
42 | ruff
43 | uv
44 | (pkgs.python3.withPackages (
45 | p: with p; [
46 | tox
47 | virtualenv
48 | ]
49 | ))
50 |
51 | # Shell tooling
52 | shellcheck
53 | shfmt
54 | ];
55 | }
56 |
--------------------------------------------------------------------------------
/home/common/dev/charm-tools.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | home.packages = with pkgs; [
4 | charmcraft
5 | juju
6 | juju4
7 | rockcraft
8 | snapcraft
9 | ];
10 | }
11 |
--------------------------------------------------------------------------------
/home/common/dev/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | desktop,
3 | lib,
4 | ...
5 | }:
6 | {
7 | imports = [
8 | ./base.nix
9 | ] ++ lib.optional (builtins.isString desktop) ./desktop.nix;
10 | }
11 |
--------------------------------------------------------------------------------
/home/common/dev/desktop.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | programs.vscode = {
4 | enable = true;
5 | };
6 |
7 | home.packages = with pkgs; [ sublime-merge ];
8 | }
9 |
--------------------------------------------------------------------------------
/home/common/shell/atuin.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | programs.atuin = {
4 | enable = true;
5 | enableFishIntegration = true;
6 | package = pkgs.atuin;
7 | flags = [ "--disable-up-arrow" ];
8 | settings = {
9 | enter_accept = false;
10 | dialect = "uk";
11 | dotfiles = {
12 | enabled = false;
13 | };
14 | sync = {
15 | records = true;
16 | };
17 | };
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/home/common/shell/bat.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | catppuccin.bat.enable = true;
3 |
4 | programs = {
5 | bat = {
6 | enable = true;
7 | };
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/home/common/shell/bottom.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | catppuccin.bottom.enable = true;
3 |
4 | programs.bottom = {
5 | enable = true;
6 | };
7 | }
8 |
--------------------------------------------------------------------------------
/home/common/shell/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, self, ... }:
2 | let
3 | theme = import "${self}/lib/theme" { inherit pkgs; };
4 | in
5 | {
6 | imports = [
7 | ./atuin.nix
8 | ./bat.nix
9 | ./bottom.nix
10 | ./fastfetch.nix
11 | ./fzf.nix
12 | ./git.nix
13 | ./helix.nix
14 | ./starship.nix
15 | ./xdg.nix
16 | ./zellij.nix
17 | ./fish.nix
18 | ];
19 |
20 | catppuccin = {
21 | inherit (theme.catppuccin) flavor;
22 | inherit (theme.catppuccin) accent;
23 | };
24 |
25 | programs = {
26 | eza.enable = true;
27 | git.enable = true;
28 | gpg.enable = true;
29 | home-manager.enable = true;
30 | jq.enable = true;
31 | };
32 |
33 | services.gpg-agent = {
34 | enable = true;
35 | pinentryPackage = pkgs.pinentry-curses;
36 | };
37 |
38 | home.packages = with pkgs; [
39 | age
40 | sops
41 | ];
42 | }
43 |
--------------------------------------------------------------------------------
/home/common/shell/fastfetch.jsonc:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
3 | "logo": {
4 | "padding": {
5 | "top": 0,
6 | "left": 5,
7 | "right": 5
8 | }
9 | },
10 | "display": {
11 | "separator": "",
12 | "binaryPrefix": "si",
13 | "size": {
14 | "ndigits": 0
15 | },
16 | "keyWidth": 4
17 | },
18 | "modules": [
19 | "break",
20 | "break",
21 | {
22 | "type": "title",
23 | "key": "",
24 | "color": {
25 | "user": "34",
26 | "host": "34"
27 | },
28 | "keyColor": "32"
29 | },
30 | {
31 | "type": "os",
32 | "key": "",
33 | "format": "{3} ({12})",
34 | "keyColor": "32"
35 | },
36 | {
37 | "type": "kernel",
38 | "key": "",
39 | "format": "{1} {2}",
40 | "keyColor": "32"
41 | },
42 | "break",
43 | {
44 | "type": "cpu",
45 | "key": "",
46 | "keyColor": "34",
47 | "freqNdigits": 1
48 | },
49 | {
50 | "type": "board",
51 | "key": "",
52 | "keyColor": "34"
53 | },
54 | {
55 | "type": "gpu",
56 | "key": "",
57 | "keyColor": "34",
58 | "format": "{2}",
59 | "forceVulkan": true,
60 | "hideType": "integrated"
61 | },
62 | {
63 | "type": "memory",
64 | "key": "",
65 | "keyColor": "34",
66 | "format": "{1} / {2}"
67 | },
68 | "break",
69 | {
70 | "type": "wm",
71 | "key": "",
72 | "keyColor": "33"
73 | },
74 | {
75 | "type": "theme",
76 | "key": "",
77 | "keyColor": "33"
78 | },
79 | {
80 | "type": "terminal",
81 | "key": "",
82 | "format": "{3}",
83 | "keyColor": "33"
84 | },
85 | {
86 | "type": "shell",
87 | "key": "$",
88 | "format": "{1} {4}",
89 | "keyColor": "33"
90 | },
91 | {
92 | "type": "display",
93 | "key": "",
94 | "keyColor": "33",
95 | "compactType": "original"
96 | },
97 | "break",
98 | {
99 | "type": "colors",
100 | "symbol": "circle"
101 | },
102 | "break"
103 | ]
104 | }
105 |
--------------------------------------------------------------------------------
/home/common/shell/fastfetch.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | home = {
4 | packages = with pkgs; [ fastfetch ];
5 |
6 | file = {
7 | ".config/fastfetch/config.jsonc".text = builtins.readFile ./fastfetch.jsonc;
8 | };
9 | };
10 | }
11 |
--------------------------------------------------------------------------------
/home/common/shell/fish.nix:
--------------------------------------------------------------------------------
1 | {
2 | catppuccin.fish.enable = true;
3 |
4 | programs = {
5 | fish = {
6 | enable = true;
7 |
8 | shellInit = ''
9 | set fish_greeting ""
10 | set -gx EDITOR hx
11 | set -gx SUDO_EDITOR hx
12 | '';
13 |
14 | shellAliases = {
15 | ls = "eza -gl --git --color=automatic";
16 | tree = "eza --tree";
17 | cat = "bat";
18 |
19 | lsusb = "cyme --headings";
20 |
21 | ip = "ip --color";
22 | ipb = "ip --color --brief";
23 |
24 | gac = "git add -A && git commit -a";
25 | gp = "git push";
26 | gst = "git status -sb";
27 |
28 | htop = "btm -b";
29 | neofetch = "fastfetch";
30 |
31 | tf = "terraform";
32 | tfi = "terraform init";
33 | tfp = "terraform plan";
34 | tfa = "terraform apply -auto-approve";
35 | tfd = "terraform destroy -auto-approve";
36 | tfo = "terraform output -json";
37 |
38 | wgu = "sudo wg-quick up";
39 | wgd = "sudo wg-quick down";
40 |
41 | ts = "tailscale";
42 | tst = "tailscale status";
43 | tsu = "tailscale up --ssh --operator=$USER";
44 | tsd = "tailscale down";
45 |
46 | js = "juju status";
47 | jsw = "juju status --watch 1s --color";
48 | jsrw = "juju status --watch 1s --color --relations";
49 | jdl = "juju debug-log";
50 |
51 | open = "xdg-open";
52 | k = "kubectl";
53 |
54 | opget = "op item get \"$(op item list --format=json | jq -r '.[].title' | fzf)\"";
55 |
56 | speedtest = "curl -s https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py | python -";
57 |
58 | cleanup-nix = "nh clean all --keep-since 10d --keep 3";
59 | rln = "nh os switch /home/jon/nixos-config";
60 | rlh = "nh home switch /home/jon/nixos-config";
61 | rlb = "rln && rlh";
62 | };
63 | };
64 | };
65 | }
66 |
--------------------------------------------------------------------------------
/home/common/shell/fzf.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | catppuccin.fzf.enable = true;
3 |
4 | programs.fzf = {
5 | enable = true;
6 | enableFishIntegration = true;
7 |
8 | changeDirWidgetOptions = [ "--preview 'tree -C {} | head -200'" ];
9 |
10 | defaultCommand = "rg --files";
11 | defaultOptions = [
12 | "--height 90%"
13 | "--border"
14 | ];
15 |
16 | fileWidgetCommand = "rg --files";
17 | fileWidgetOptions = [
18 | "--preview 'bat -n --color=always {}'"
19 | "--bind 'ctrl-/:change-preview-window(down|hidden|)'"
20 | ];
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/home/common/shell/git.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 |
4 | home.file.".config/git/allowed_signers".text = ''
5 | jon@sgrs.uk sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIB9bIEMgZVBCDxBWQ4m4hQP6ZZp0P3TfzjzcgUOdbYDLAAAABHNzaDo= YK5C
6 | jon@sgrs.uk sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIBC8cs1B64XqEswY5pART6yERbjUMB7RdQdT38dgkZT6AAAABHNzaDo= YK5
7 | jon.seager@canonical.com sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIB9bIEMgZVBCDxBWQ4m4hQP6ZZp0P3TfzjzcgUOdbYDLAAAABHNzaDo= YK5C
8 | jon.seager@canonical.com sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIBC8cs1B64XqEswY5pART6yERbjUMB7RdQdT38dgkZT6AAAABHNzaDo= YK5
9 | jnsgruk@ubuntu.com sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIB9bIEMgZVBCDxBWQ4m4hQP6ZZp0P3TfzjzcgUOdbYDLAAAABHNzaDo= YK5C
10 | jnsgruk@ubuntu.com sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIBC8cs1B64XqEswY5pART6yERbjUMB7RdQdT38dgkZT6AAAABHNzaDo= YK5
11 | '';
12 |
13 | home.packages = with pkgs; [ gh ];
14 |
15 | programs = {
16 | git = {
17 | enable = true;
18 |
19 | userEmail = "jon@sgrs.uk";
20 | userName = "Jon Seager";
21 |
22 | includes = [
23 | # When the working directory is under ~/code/canonical then sign-off commits
24 | # with Canonical email address.
25 | {
26 | condition = "gitdir:~/code/canonical/";
27 | contents.user.email = "jon.seager@canonical.com";
28 | }
29 | # When the working directory is under ~/code/snapcrafters then sign-off commits
30 | # with Ubuntu email address.
31 | {
32 | condition = "gitdir:~/code/snapcrafters/";
33 | contents.user.email = "jnsgruk@ubuntu.com";
34 | }
35 | ];
36 |
37 | aliases = {
38 | lg = "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
39 | };
40 |
41 | extraConfig = {
42 | branch = {
43 | sort = "-committerdate";
44 | };
45 | push = {
46 | default = "matching";
47 | };
48 | pull = {
49 | rebase = true;
50 | };
51 | init = {
52 | defaultBranch = "main";
53 | };
54 | gpg = {
55 | format = "ssh";
56 | ssh = {
57 | defaultKeyCommand = "sh -c 'echo key::$(ssh-add -L | head -n1)'";
58 | allowedSignersFile = "~/.config/git/allowed_signers";
59 | };
60 | };
61 | commit = {
62 | gpgSign = true;
63 | };
64 | tag = {
65 | gpgSign = true;
66 | };
67 | };
68 | };
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/home/common/shell/helix.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | programs.helix = {
3 | enable = true;
4 | settings = {
5 | theme = "catppuccin_macchiato";
6 | editor = {
7 | text-width = 100;
8 | rulers = [ 100 ];
9 | lsp = {
10 | display-inlay-hints = true;
11 | };
12 | };
13 | };
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/home/common/shell/starship.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | {
3 | programs = {
4 | starship = {
5 | enable = true;
6 | enableFishIntegration = true;
7 | settings = lib.mkDefault {
8 | format = lib.concatStrings [
9 | "$username"
10 | "$hostname"
11 | "$directory"
12 | "$git_branch"
13 | "$git_state"
14 | "$git_status"
15 | "$cmd_duration"
16 | "$line_break"
17 | "$nix_shell"
18 | "$python"
19 | "$character"
20 | ];
21 |
22 | directory.style = "blue";
23 |
24 | character = {
25 | success_symbol = "[❯](purple)";
26 | error_symbol = "[❯](red)";
27 | vimcmd_symbol = "[❮](green)";
28 | };
29 |
30 | git_branch = {
31 | format = "[$branch]($style)";
32 | style = "bright-black";
33 | };
34 |
35 | git_status = {
36 | format = "[[(*$conflicted$untracked$modified$staged$renamed$deleted)](218) ($ahead_behind$stashed)]($style)";
37 | style = "cyan";
38 | conflicted = "";
39 | untracked = "";
40 | modified = "";
41 | staged = "";
42 | renamed = "";
43 | deleted = "";
44 | stashed = "≡";
45 | };
46 |
47 | git_state = {
48 | format = "\([$state( $progress_current/$progress_total)]($style)\)";
49 | style = "bright-black";
50 | };
51 |
52 | cmd_duration = {
53 | format = "[$duration]($style)";
54 | style = "yellow";
55 | };
56 |
57 | python = {
58 | format = "[$virtualenv]($style) ";
59 | style = "bright-black";
60 | };
61 |
62 | nix_shell = {
63 | format = "[$name]($style)";
64 | style = "bright-black";
65 | };
66 | };
67 | };
68 | };
69 | }
70 |
--------------------------------------------------------------------------------
/home/common/shell/xdg.nix:
--------------------------------------------------------------------------------
1 | { config, lib, ... }:
2 | {
3 | xdg = {
4 | enable = true;
5 |
6 | configHome = config.home.homeDirectory + "/.config";
7 | cacheHome = config.home.homeDirectory + "/.local/cache";
8 | dataHome = config.home.homeDirectory + "/.local/share";
9 | stateHome = config.home.homeDirectory + "/.local/state";
10 |
11 | userDirs = {
12 | enable = true;
13 | createDirectories = lib.mkDefault true;
14 |
15 | download = config.home.homeDirectory + "/downloads";
16 | pictures = config.home.homeDirectory + "/pictures";
17 |
18 | desktop = config.home.homeDirectory;
19 | documents = config.home.homeDirectory;
20 | music = config.home.homeDirectory;
21 | publicShare = config.home.homeDirectory;
22 | templates = config.home.homeDirectory;
23 | videos = config.home.homeDirectory;
24 |
25 | extraConfig = {
26 | XDG_SCREENSHOTS_DIR = "${config.home.homeDirectory}/pictures/screenshots";
27 | };
28 | };
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/home/common/shell/zellij.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | programs.zellij = {
3 | enable = true;
4 | settings = {
5 | theme = "catppuccin-macchiato";
6 | };
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/home/common/users/jon/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | inputs,
3 | lib,
4 | hostname,
5 | ...
6 | }:
7 | {
8 | imports = [
9 | inputs.vscode-server.nixosModules.home
10 | ] ++ lib.optional (builtins.pathExists (./. + "/${hostname}.nix")) ./${hostname}.nix;
11 |
12 | services = {
13 | # Following install, you may need to run:
14 | # systemctl --user enable auto-fix-vscode-server.service
15 | # systemctl --user start auto-fix-vscode-server.service
16 | vscode-server.enable = true;
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/home/common/users/jon/freyja.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | self,
4 | ...
5 | }:
6 | let
7 | # This isn't a NixOS machine, so the normal host-level packages aren't
8 | # automatically available.
9 | inherit ((import "${self}/host/common/base/packages.nix" { inherit pkgs; })) basePackages;
10 | in
11 | {
12 | targets.genericLinux.enable = true;
13 |
14 | home.packages =
15 | basePackages
16 | # Add additional packages which would usually be added at the NixOS
17 | # host level.
18 | ++ (with pkgs; [
19 | _1password-gui
20 | nh
21 | yubikey-manager
22 |
23 | (nerdfonts.override { fonts = [ "Meslo" ]; })
24 | inter
25 | ]);
26 |
27 | # Work around default Ubuntu config in /etc/X11/Xsession.d/90gpg-agent.
28 | # programs.zsh.envExtra = ''
29 | # SSH_AUTH_SOCK=$XDG_RUNTIME_DIR/ssh-agent
30 | # '';
31 |
32 | services = {
33 | ssh-agent.enable = true;
34 | syncthing = {
35 | enable = true;
36 | extraOptions = [
37 | "-gui-address=freyja.tailnet-d5da.ts.net:8384"
38 | "-home=/home/jon/data/.syncthing"
39 | ];
40 | };
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/home/common/users/jon/kara.nix:
--------------------------------------------------------------------------------
1 | { self, ... }:
2 | {
3 | imports = [
4 | "${self}/home/common/dev/charm-tools.nix"
5 | ];
6 |
7 | services.syncthing = {
8 | enable = true;
9 | extraOptions = [
10 | "-gui-address=kara.tailnet-d5da.ts.net:8384"
11 | "-home=/home/jon/data/.syncthing"
12 | ];
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/home/common/users/jon/thor.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | services.syncthing = {
3 | enable = true;
4 | extraOptions = [
5 | "-gui-address=thor.tailnet-d5da.ts.net:8384"
6 | "-home=/data/apps/syncthing"
7 | ];
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/home/common/users/ubuntu/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, self, ... }:
2 | let
3 | inherit ((import "${self}/host/common/base/packages.nix" { inherit pkgs; })) basePackages;
4 | in
5 | {
6 | imports = [ "${self}/home/common/dev/base.nix" ];
7 | home.packages = basePackages;
8 | }
9 |
--------------------------------------------------------------------------------
/home/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | config,
3 | desktop,
4 | lib,
5 | outputs,
6 | stateVersion,
7 | username,
8 | inputs,
9 | ...
10 | }:
11 | {
12 | # Only import desktop configuration if the host is desktop enabled
13 | # Only import user specific configuration if they have bespoke settings
14 | imports =
15 | [
16 | # If you want to use modules your own flake exports (from modules/home-manager):
17 | # outputs.homeManagerModules.example
18 |
19 | # Or modules exported from other flakes (such as nix-colors):
20 | # inputs.nix-colors.homeManagerModules.default
21 |
22 | ./common/shell
23 | ]
24 | ++ lib.optional (builtins.isString desktop) ./common/desktop
25 | ++ lib.optional (builtins.pathExists (
26 | ./. + "/common/users/${username}"
27 | )) ./common/users/${username};
28 |
29 | home = {
30 | inherit username stateVersion;
31 | homeDirectory = "/home/${username}";
32 | };
33 |
34 | nixpkgs = {
35 | overlays = [
36 | # Add overlays your own flake exports (from overlays and pkgs dir):
37 | outputs.overlays.additions
38 | outputs.overlays.modifications
39 | outputs.overlays.unstable-packages
40 |
41 | # You can also add overlays exported from other flakes:
42 | inputs.agenix.overlays.default
43 | ];
44 |
45 | config = {
46 | # Disable if you don't want unfree packages
47 | allowUnfree = true;
48 | # Workaround for https://github.com/nix-community/home-manager/issues/2942
49 | allowUnfreePredicate = _: true;
50 | permittedInsecurePackages = [ "electron-25.9.0" ];
51 | };
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/host/common/base/boot.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | boot = {
3 | initrd.systemd.enable = true;
4 |
5 | kernel.sysctl = {
6 | "net.ipv4.ip_forward" = 1;
7 | "net.ipv6.conf.all.forwarding" = 1;
8 | };
9 |
10 | loader = {
11 | systemd-boot.enable = true;
12 | efi.canTouchEfiVariables = true;
13 | };
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/host/common/base/console.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | ...
4 | }:
5 | {
6 | boot = {
7 | # Catppuccin theme
8 | kernelParams = [
9 | "vt.default_red=30,243,166,249,137,245,148,186,88,243,166,249,137,245,148,166"
10 | "vt.default_grn=30,139,227,226,180,194,226,194,91,139,227,226,180,194,226,173"
11 | "vt.default_blu=46,168,161,175,250,231,213,222,112,168,161,175,250,231,213,200"
12 | ];
13 | };
14 |
15 | console = {
16 | earlySetup = true;
17 | packages = with pkgs; [
18 | terminus_font
19 | powerline-fonts
20 | ];
21 | font = "ter-powerline-v32n";
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/host/common/base/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | hostname,
3 | pkgs,
4 | lib,
5 | username,
6 | ...
7 | }:
8 | {
9 | imports = [
10 | ./boot.nix
11 | ./console.nix
12 | ./hardware.nix
13 | ./locale.nix
14 | ./nh.nix
15 | ./zramswap.nix
16 |
17 | ../services/avahi.nix
18 | ../services/firewall.nix
19 | ../services/openssh.nix
20 | ../services/tailscale.nix
21 | ];
22 |
23 | networking = {
24 | hostName = hostname;
25 | useDHCP = lib.mkDefault true;
26 | };
27 |
28 | environment.systemPackages = (import ./packages.nix { inherit pkgs; }).basePackages;
29 |
30 | programs = {
31 | fish.enable = true;
32 | _1password.enable = true;
33 | };
34 |
35 | services = {
36 | chrony.enable = true;
37 | journald.extraConfig = "SystemMaxUse=250M";
38 | };
39 |
40 | security = {
41 | polkit.enable = true;
42 | rtkit.enable = true;
43 | };
44 |
45 | # Create dirs for home-manager
46 | systemd.tmpfiles.rules = [ "d /nix/var/nix/profiles/per-user/${username} 0755 ${username} root" ];
47 | }
48 |
--------------------------------------------------------------------------------
/host/common/base/hardware.nix:
--------------------------------------------------------------------------------
1 | _: { hardware.enableRedistributableFirmware = true; }
2 |
--------------------------------------------------------------------------------
/host/common/base/locale.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | time.timeZone = "Europe/London";
3 |
4 | console.keyMap = "uk";
5 | services.xserver.xkb.layout = "gb";
6 |
7 | i18n = {
8 | defaultLocale = "en_GB.utf8";
9 | extraLocaleSettings = {
10 | LC_ADDRESS = "en_GB.utf8";
11 | LC_IDENTIFICATION = "en_GB.utf8";
12 | LC_MEASUREMENT = "en_GB.utf8";
13 | LC_MONETARY = "en_GB.utf8";
14 | LC_NAME = "en_GB.utf8";
15 | LC_NUMERIC = "en_GB.utf8";
16 | LC_PAPER = "en_GB.utf8";
17 | LC_TELEPHONE = "en_GB.utf8";
18 | LC_TIME = "en_GB.utf8";
19 | };
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/host/common/base/nh.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | programs.nh = {
4 | enable = true;
5 | package = pkgs.nh;
6 | flake = "/home/jon/nixos-config";
7 | clean = {
8 | enable = true;
9 | extraArgs = "--keep-since 10d --keep 3";
10 | };
11 | };
12 | }
13 |
--------------------------------------------------------------------------------
/host/common/base/packages.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | basePackages = with pkgs; [
4 | _1password-cli
5 | agenix
6 | bat
7 | binutils
8 | curl
9 | cyme
10 | dig
11 | dua
12 | duf
13 | eza
14 | fd
15 | file
16 | git
17 | jq
18 | killall
19 | nfs-utils
20 | ntfs3g
21 | pciutils
22 | ripgrep
23 | rsync
24 | tpm2-tss
25 | traceroute
26 | tree
27 | unzip
28 | usbutils
29 | vim
30 | wget
31 | yq-go
32 | ];
33 | }
34 |
--------------------------------------------------------------------------------
/host/common/base/zramswap.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | # Balance lz4 latency/throughput
3 | boot.kernel.sysctl."vm.page-cluster" = 1;
4 |
5 | # Hibernate and hybrid-sleep won't work correctly without
6 | # an on-disk swap.
7 | systemd.targets.hibernate.enable = false;
8 | systemd.targets.hybrid-sleep.enable = false;
9 |
10 | # Enable zramSwap
11 | zramSwap = {
12 | algorithm = "lz4";
13 | enable = true;
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/host/common/desktop/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | desktop,
3 | pkgs,
4 | self,
5 | ...
6 | }:
7 | let
8 | theme = import "${self}/lib/theme" { inherit pkgs; };
9 | in
10 | {
11 | imports = [
12 | (./. + "/${desktop}.nix")
13 | ../hardware/yubikey.nix
14 | ../services/pipewire.nix
15 | ../virt
16 | ];
17 |
18 | # Enable Plymouth and surpress some logs by default.
19 | boot.plymouth.enable = true;
20 | boot.kernelParams = [
21 | # The 'splash' arg is included by the plymouth option
22 | "quiet"
23 | "loglevel=3"
24 | "rd.udev.log_priority=3"
25 | "vt.global_cursor_default=0"
26 | ];
27 |
28 | hardware.graphics.enable = true;
29 |
30 | # Enable location services
31 | location.provider = "geoclue2";
32 |
33 | programs = {
34 | _1password-gui = {
35 | enable = true;
36 | polkitPolicyOwners = [ "jon" ];
37 | };
38 | };
39 |
40 | fonts = {
41 | packages = with pkgs; [
42 | liberation_ttf
43 | ubuntu_font_family
44 |
45 | theme.fonts.default.package
46 | theme.fonts.emoji.package
47 | theme.fonts.iconFont.package
48 | theme.fonts.monospace.package
49 | ];
50 |
51 | # Use fonts specified by user rather than default ones
52 | enableDefaultPackages = false;
53 |
54 | fontconfig = {
55 | enable = true;
56 | defaultFonts = {
57 | serif = [
58 | "${theme.fonts.default.name}"
59 | "${theme.fonts.emoji.name}"
60 | ];
61 | sansSerif = [
62 | "${theme.fonts.default.name}"
63 | "${theme.fonts.emoji.name}"
64 | ];
65 | monospace = [ "${theme.fonts.monospace.name}" ];
66 | emoji = [ "${theme.fonts.emoji.name}" ];
67 | };
68 | };
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/host/common/desktop/hyprland.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | lib,
4 | self,
5 | ...
6 | }:
7 | let
8 | theme = import "${self}/lib/theme" { inherit pkgs; };
9 | hypr-run = pkgs.writeShellScriptBin "hypr-run" ''
10 | export XDG_SESSION_TYPE="wayland"
11 | export XDG_SESSION_DESKTOP="Hyprland"
12 | export XDG_CURRENT_DESKTOP="Hyprland"
13 | export GTK_THEME=${theme.gtkTheme.name}
14 |
15 | systemd-run --user --scope --collect --quiet --unit="hyprland" \
16 | systemd-cat --identifier="hyprland" ${pkgs.hyprland}/bin/Hyprland $@
17 |
18 | ${pkgs.hyprland}/bin/hyprctl dispatch exit
19 | '';
20 | in
21 | {
22 | imports = [ ./tiling-common.nix ];
23 |
24 | programs.hyprland.enable = true;
25 |
26 | xdg.portal.extraPortals = with pkgs; [ xdg-desktop-portal-gtk ];
27 |
28 | services.greetd.settings.default_session.command = ''
29 | ${lib.makeBinPath [ pkgs.greetd.tuigreet ]}/tuigreet -r --asterisks --time \
30 | --cmd ${lib.getExe hypr-run}
31 | '';
32 | }
33 |
--------------------------------------------------------------------------------
/host/common/desktop/sway.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | lib,
4 | self,
5 | ...
6 | }:
7 | let
8 | theme = import "${self}/lib/theme" { inherit pkgs; };
9 | sway-run = pkgs.writeShellScriptBin "sway-run" ''
10 | export XDG_SESSION_TYPE="wayland"
11 | export XDG_SESSION_DESKTOP="sway"
12 | export XDG_CURRENT_DESKTOP="sway"
13 | export GTK_THEME=${theme.gtkTheme.name}
14 |
15 | systemd-run --user --scope --collect --quiet --unit="sway" \
16 | systemd-cat --identifier="sway" ${pkgs.sway}/bin/sway $@
17 |
18 | ${pkgs.sway}/bin/swaymsg exit
19 | '';
20 | in
21 | {
22 | imports = [ ./tiling-common.nix ];
23 |
24 | programs.sway = {
25 | enable = true;
26 | wrapperFeatures.gtk = true;
27 | };
28 |
29 | services.greetd.settings.default_session.command = ''
30 | ${lib.makeBinPath [ pkgs.greetd.tuigreet ]}/tuigreet -r --asterisks --time \
31 | --cmd ${lib.getExe sway-run}
32 | '';
33 | }
34 |
--------------------------------------------------------------------------------
/host/common/desktop/tiling-common.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | programs = {
4 | dconf.enable = true;
5 | file-roller.enable = true;
6 | };
7 |
8 | environment = {
9 | variables.NIXOS_OZONE_WL = "1";
10 |
11 | systemPackages = with pkgs; [
12 | nautilus
13 | zenity
14 | # Enable HEIC image previews in Nautilus
15 | libheif
16 | libheif.out
17 | polkit_gnome
18 | ];
19 |
20 | # Enable HEIC image previews in Nautilus
21 | pathsToLink = [ "share/thumbnailers" ];
22 | };
23 |
24 | services = {
25 | dbus = {
26 | enable = true;
27 | implementation = "broker";
28 | };
29 |
30 | gnome = {
31 | gnome-keyring.enable = true;
32 | sushi.enable = true;
33 | };
34 |
35 | greetd = {
36 | enable = true;
37 | restart = false;
38 | };
39 |
40 | gvfs.enable = true;
41 | };
42 | }
43 |
--------------------------------------------------------------------------------
/host/common/hardware/bluetooth.nix:
--------------------------------------------------------------------------------
1 | { pkgs, desktop, ... }:
2 | {
3 | hardware.bluetooth = {
4 | enable = true;
5 | package = pkgs.bluez;
6 | settings = {
7 | General = {
8 | Experimental = true;
9 | KernelExperimental = true;
10 | };
11 | };
12 | };
13 |
14 | environment.systemPackages = if (builtins.isString desktop) then [ pkgs.blueberry ] else [ ];
15 | }
16 |
--------------------------------------------------------------------------------
/host/common/hardware/ledger.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | # Enable the udev rules for Ledger devices
4 | hardware.ledger.enable = true;
5 |
6 | # Install the ledger live desktop app globally
7 | environment.systemPackages = with pkgs; [ ledger-live-desktop ];
8 |
9 | # Needed for Ledger Live app
10 | users.groups.plugdev = { };
11 | }
12 |
--------------------------------------------------------------------------------
/host/common/hardware/yubihsm.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | environment.systemPackages = with pkgs; [
4 | yubihsm-connector
5 | yubihsm-shell
6 | ];
7 | }
8 |
--------------------------------------------------------------------------------
/host/common/hardware/yubikey.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | environment.systemPackages = with pkgs; [ yubikey-manager ];
4 |
5 | services = {
6 | pcscd.enable = true;
7 | udev.packages = [ pkgs.yubikey-personalization ];
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/host/common/services/avahi.nix:
--------------------------------------------------------------------------------
1 | { desktop, ... }:
2 | {
3 | services = {
4 | avahi = {
5 | enable = true;
6 | openFirewall = true;
7 | nssmdns4 = true;
8 | publish = {
9 | enable = true;
10 | addresses = true;
11 | workstation = if (builtins.isString desktop) then true else false;
12 | };
13 | };
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/host/common/services/backup/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | config,
3 | hostname,
4 | lib,
5 | self,
6 | ...
7 | }:
8 | {
9 | imports = lib.optional (builtins.pathExists (./. + "/${hostname}.nix")) ./${hostname}.nix;
10 |
11 | age.secrets = {
12 | borgbase-ssh = {
13 | file = "${self}/secrets/${hostname}-borgbase-ssh.age";
14 | owner = "root";
15 | group = "root";
16 | mode = "400";
17 | };
18 | borgbase-passphrase = {
19 | file = "${self}/secrets/${hostname}-borgbase-passphrase.age";
20 | owner = "root";
21 | group = "root";
22 | mode = "400";
23 | };
24 | };
25 |
26 | # See individual host config files for backup/restore instructions.
27 | services.borgbackup.jobs."borgbase" = {
28 | encryption = {
29 | mode = "repokey-blake2";
30 | passCommand = "cat ${config.age.secrets."borgbase-passphrase".path}";
31 | };
32 | environment.BORG_RSH = "ssh -i ${config.age.secrets."borgbase-ssh".path}";
33 | compression = "auto,lzma";
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/host/common/services/backup/kara.nix:
--------------------------------------------------------------------------------
1 | _: {
2 |
3 | # In order to mount the backup to restore files, perform the following:
4 | #
5 | # mkdir backup
6 | # sudo borg-job-borgbase mount z2sqv4mw@z2sqv4mw.repo.borgbase.com:repo ./backup
7 | #
8 | # Then copy out the files you need using normal Linux commands. Once complete, unmount
9 | # with:
10 | #
11 | # borg-job-borgbase umount backup
12 | services.borgbackup.jobs."borgbase" = {
13 | paths = [ "/home/jon/data" ];
14 | exclude = [
15 | "**/node_modules"
16 | "**/build"
17 | "**/dist"
18 | "**/.tox"
19 | "**/.venv"
20 | "**/venv"
21 | "**/target"
22 | "/home/jon/downloads"
23 | "/home/jon/data/downloads"
24 | "/home/jon/data/temp"
25 | "/home/jon/go"
26 | "/home/jon/sdk"
27 | ];
28 | repo = "z2sqv4mw@z2sqv4mw.repo.borgbase.com:repo";
29 | startAt = "*-*-* 12:00:00";
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/host/common/services/backup/thor.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | # In order to mount the backup to restore files, perform the following:
3 | #
4 | # mkdir backup
5 | # sudo borg-job-borgbase mount ike67cye@ike67cye.repo.borgbase.com:repo ./backup
6 | #
7 | # Then copy out the files you need using normal Linux commands. Once complete, unmount
8 | # with:
9 | #
10 | # borg-job-borgbase umount backup
11 | services.borgbackup.jobs."borgbase" = {
12 | paths = [ "/data" ];
13 | exclude = [
14 | "/data/apps/files/_files/cache"
15 | "/data/lost+found"
16 | "/data/media"
17 | ];
18 | repo = "ike67cye@ike67cye.repo.borgbase.com:repo";
19 | startAt = "daily";
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/host/common/services/files.nix:
--------------------------------------------------------------------------------
1 | { pkgs, config, ... }:
2 | {
3 | # Set up for https://www.files.gallery
4 | services = {
5 | nginx = {
6 | enable = true;
7 | group = "users";
8 | defaultHTTPListenPort = 8081;
9 | virtualHosts."_" = {
10 | root = "/data/apps/files";
11 | locations."/".extraConfig = ''
12 | fastcgi_pass unix:${config.services.phpfpm.pools.nginx-pool.socket};
13 | fastcgi_index index.php;
14 | fastcgi_split_path_info ^(.+\.php)(/.+)$;
15 | include ${pkgs.nginx}/conf/fastcgi_params;
16 | include ${pkgs.nginx}/conf/fastcgi.conf;
17 | '';
18 | };
19 | };
20 | phpfpm.pools.nginx-pool = {
21 | inherit (config.services.nginx) user;
22 | group = "users";
23 | settings = {
24 | pm = "dynamic";
25 | "listen.owner" = config.services.nginx.user;
26 | "pm.max_children" = 5;
27 | "pm.start_servers" = 2;
28 | "pm.min_spare_servers" = 1;
29 | "pm.max_spare_servers" = 3;
30 | "pm.max_requests" = 500;
31 | };
32 | phpOptions = ''
33 | memory_limit=512M
34 | '';
35 | };
36 | };
37 |
38 | environment.systemPackages = with pkgs; [ ffmpeg ];
39 | }
40 |
--------------------------------------------------------------------------------
/host/common/services/firewall.nix:
--------------------------------------------------------------------------------
1 | { lib, hostname, ... }:
2 | let
3 | # Firewall configuration variable for syncthing
4 | syncthing = {
5 | hosts = [
6 | "freyja"
7 | "kara"
8 | "thor"
9 | ];
10 | tcpPorts = [ 22000 ];
11 | udpPorts = [
12 | 22000
13 | 21027
14 | ];
15 | };
16 | in
17 | {
18 | networking = {
19 | firewall = {
20 | enable = true;
21 | allowedTCPPorts = lib.optionals (builtins.elem hostname syncthing.hosts) syncthing.tcpPorts;
22 | allowedUDPPorts = lib.optionals (builtins.elem hostname syncthing.hosts) syncthing.udpPorts;
23 | };
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/host/common/services/home-assistant.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | services.home-assistant = {
4 | enable = true;
5 | openFirewall = true;
6 | package = pkgs.unstable.home-assistant;
7 | extraComponents = [
8 | "apple_tv"
9 | "brother"
10 | "default_config"
11 | "esphome"
12 | "ipp"
13 | "met"
14 | "otbr"
15 | "ring"
16 | "roomba"
17 | "snmp"
18 | "sonos"
19 | "touchline_sl"
20 | "tplink"
21 | "tplink_tapo"
22 | "unifi"
23 | "unifiprotect"
24 | "upnp"
25 | "webostv"
26 | ];
27 | customComponents = [
28 | pkgs.unstable.home-assistant-custom-components.solis-sensor
29 | ];
30 | config = {
31 | default_config = { };
32 | http = {
33 | trusted_proxies = [
34 | "::1"
35 | "127.0.0.1"
36 | ];
37 | use_x_forwarded_for = true;
38 | };
39 | };
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/host/common/services/immich.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | services.immich = {
4 | enable = true;
5 | package = pkgs.immich;
6 | openFirewall = true;
7 | port = 3001;
8 |
9 | redis = {
10 | enable = true;
11 | host = "127.0.0.1";
12 | port = 6379;
13 | };
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/host/common/services/libations.nix:
--------------------------------------------------------------------------------
1 | { config, self, ... }:
2 | {
3 | age.secrets = {
4 | libations-auth-key = {
5 | file = "${self}/secrets/thor-libations-tskey.age";
6 | owner = "root";
7 | group = "root";
8 | mode = "400";
9 | };
10 |
11 | libations-recipes = {
12 | file = "${self}/secrets/thor-libations-recipes.age";
13 | owner = "root";
14 | group = "root";
15 | mode = "444";
16 | };
17 | };
18 |
19 | services.libations = {
20 | enable = true;
21 | recipesFile = config.age.secrets.libations-recipes.path;
22 | tailscaleKeyFile = config.age.secrets.libations-auth-key.path;
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/host/common/services/networkmanager.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | networking = {
3 | networkmanager = {
4 | enable = true;
5 | wifi = {
6 | backend = "iwd";
7 | };
8 | };
9 | };
10 |
11 | # Workaround https://github.com/NixOS/nixpkgs/issues/180175
12 | systemd.services.NetworkManager-wait-online.enable = false;
13 | }
14 |
--------------------------------------------------------------------------------
/host/common/services/nfs/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | hostname,
3 | lib,
4 | ...
5 | }:
6 | {
7 | imports = lib.optional (builtins.pathExists (./. + "/${hostname}.nix")) ./${hostname}.nix;
8 |
9 | services.nfs.server.enable = true;
10 |
11 | networking = {
12 | firewall = {
13 | allowedTCPPorts = [
14 | 111
15 | 2049
16 | 4000
17 | 4001
18 | 4002
19 | 20048
20 | ];
21 | allowedUDPPorts = [
22 | 111
23 | 2049
24 | 4000
25 | 4001
26 | 4002
27 | 20048
28 | ];
29 | };
30 |
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/host/common/services/nfs/thor.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | services.nfs.server.exports = ''
3 | /data 100.64.0.0/10 (rw,fsid=0,no_subtree_check)
4 | '';
5 | }
6 |
--------------------------------------------------------------------------------
/host/common/services/openssh.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | services.openssh = {
3 | enable = true;
4 | openFirewall = true;
5 | settings = {
6 | PasswordAuthentication = false;
7 | PermitRootLogin = "no";
8 | };
9 | };
10 |
11 | programs.ssh.startAgent = true;
12 | }
13 |
--------------------------------------------------------------------------------
/host/common/services/photo-backup/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | lib,
4 | config,
5 | self,
6 | ...
7 | }:
8 | let
9 | photo-backup = pkgs.writeShellApplication {
10 | name = "photo-backup";
11 | runtimeInputs = with pkgs; [
12 | bash
13 | curl
14 | gphotos-sync
15 | unstable.icloudpd
16 | urlencode
17 | ];
18 | text = builtins.readFile ./photo-backup.sh;
19 | };
20 | in
21 | {
22 | age.secrets = {
23 | backup-env = {
24 | file = "${self}/secrets/thor-backup-env.age";
25 | owner = "root";
26 | group = "root";
27 | mode = "400";
28 | };
29 | };
30 |
31 | environment.systemPackages = [ photo-backup ];
32 |
33 | systemd = {
34 | services.photo-backup = {
35 | description = "Photo Backup Service";
36 | after = [ "network.target" ];
37 | serviceConfig = {
38 | Type = "oneshot";
39 | ExecStart = "${lib.getExe photo-backup}";
40 | EnvironmentFile = config.age.secrets."backup-env".path;
41 | };
42 | startAt = "*-*-* 21:00:00";
43 | };
44 |
45 | timers.photo-backup.timerConfig.Persistent = true;
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/host/common/services/photo-backup/photo-backup.sh:
--------------------------------------------------------------------------------
1 | PHOTOS_ROOT="/data/photos"
2 |
3 | handle_failure() {
4 | local name; name="$1"
5 |
6 | echo "Failed to backup photos for $name; See '${PHOTOS_ROOT}/${name}/backup.log'"
7 |
8 | msg="$(mktemp)"
9 | echo "Failed to backup photos for $name:" > "$msg"
10 | echo "" >> "$msg"
11 | cat "${PHOTOS_ROOT}/${name}/backup.log" >> "$msg"
12 |
13 | curl -s -X POST \
14 | -H 'Content-Type: application/json' \
15 | -d "{\"chat_id\": \"${TG_CHAT}\", \"text\": \"$(cat "$msg")\"}" \
16 | "https://api.telegram.org/${TG_TOKEN}/sendMessage" >/dev/null
17 |
18 | rm "$msg"
19 | }
20 |
21 | backup_gphotos() {
22 | local name; name="$1"
23 |
24 | echo "Backing up Google Photos for $name"
25 |
26 | gphotos-sync \
27 | --secret "${PHOTOS_ROOT}/${name}/client_secret.json" \
28 | "${PHOTOS_ROOT}/${name}" \
29 | > "${PHOTOS_ROOT}/${name}/backup.log" \
30 | || handle_failure "$name"
31 | }
32 |
33 | backup_icloud() {
34 | local name; name="$1"
35 | local user; user="$2"
36 | local pass; pass="$3"
37 |
38 | echo "Backing up iCloud Photos for $name"
39 |
40 | icloudpd \
41 | --log-level info \
42 | --directory "${PHOTOS_ROOT}/${name}" \
43 | --cookie-directory "${PHOTOS_ROOT}/.icloudpd"\
44 | --folder-structure "{:%Y/%m-%b}" \
45 | --username "$user" --password "$pass" \
46 | --size original \
47 | > "${PHOTOS_ROOT}/${name}/backup.log" \
48 | || handle_failure "$name"
49 |
50 | icloudpd \
51 | --log-level info \
52 | --directory "${PHOTOS_ROOT}/${name}" \
53 | --cookie-directory "${PHOTOS_ROOT}/.icloudpd"\
54 | --folder-structure "{:%Y/%m-%b}" \
55 | --username "$user" --password "$pass" \
56 | --size original \
57 | --album "Hidden" \
58 | >> "${PHOTOS_ROOT}/${name}/backup.log" \
59 | || handle_failure "$name"
60 |
61 | icloudpd \
62 | --log-level info \
63 | --directory "${PHOTOS_ROOT}/${name}" \
64 | --cookie-directory "${PHOTOS_ROOT}/.icloudpd"\
65 | --folder-structure "{:%Y/%m-%b}" \
66 | --username "$user" --password "$pass" \
67 | --size original \
68 | --album "Recently Deleted" \
69 | >> "${PHOTOS_ROOT}/${name}/backup.log" \
70 | || handle_failure "$name"
71 | }
72 |
73 | auth_icloud() {
74 | local user; user="$1"
75 | local pass; pass="$2"
76 |
77 | icloudpd --auth-only \
78 | --cookie-directory "${PHOTOS_ROOT}/.icloudpd" \
79 | --username "$user" --password "$pass"
80 | }
81 |
82 | if [[ "${1:-}" == "auth" ]]; then
83 | echo "Authenticating Nina"
84 | auth_icloud "$NINA_EMAIL" "$NINA_PASSWORD"
85 | echo "Authenticating Rich"
86 | auth_icloud "$RICH_EMAIL" "$RICH_PASSWORD"
87 | echo "Authenticating Laura"
88 | auth_icloud "$LAURA_EMAIL" "$LAURA_PASSWORD"
89 | echo "Authenticating Jon"
90 | auth_icloud "$JON_EMAIL" "$JON_PASSWORD"
91 | else
92 | backup_gphotos hattie
93 | backup_gphotos tom
94 | backup_icloud nina "$NINA_EMAIL" "$NINA_PASSWORD"
95 | backup_icloud rich "$RICH_EMAIL" "$RICH_PASSWORD"
96 | backup_icloud laura "$LAURA_EMAIL" "$LAURA_PASSWORD"
97 | backup_icloud jon "$JON_EMAIL" "$JON_PASSWORD"
98 | fi
99 |
100 | chown -R jon:users /data/photos
--------------------------------------------------------------------------------
/host/common/services/pipewire.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | pkgs,
4 | desktop,
5 | ...
6 | }:
7 | {
8 | hardware.pulseaudio.enable = lib.mkForce false;
9 |
10 | services.pipewire = {
11 | enable = true;
12 | alsa.enable = true;
13 | pulse.enable = true;
14 | wireplumber.enable = true;
15 | };
16 |
17 | environment.systemPackages = if (builtins.isString desktop) then [ pkgs.pwvucontrol ] else [ ];
18 | }
19 |
--------------------------------------------------------------------------------
/host/common/services/reverse-proxy/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | hostname,
4 | lib,
5 | ...
6 | }:
7 | {
8 | imports = lib.optional (builtins.pathExists (./. + "/${hostname}.nix")) ./${hostname}.nix;
9 |
10 | services.caddy = {
11 | enable = true;
12 | package = pkgs.custom-caddy;
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/host/common/services/reverse-proxy/thor.nix:
--------------------------------------------------------------------------------
1 | { config, self, ... }:
2 | let
3 | tailnet = "tailnet-d5da.ts.net";
4 | domain = "jnsgr.uk";
5 |
6 | mkVHost = backend: ''
7 | tls {
8 | dns digitalocean {$DO_AUTH_TOKEN}
9 | }
10 | reverse_proxy ${backend}
11 | '';
12 | in
13 | {
14 | age.secrets.digitalocean = {
15 | file = "${self}/secrets/thor-digitalocean.age";
16 | owner = "caddy";
17 | group = "caddy";
18 | mode = "600";
19 | };
20 |
21 | # Ensure DigitalOcean token is in Caddy's environment
22 | systemd.services.caddy.serviceConfig.EnvironmentFile = config.age.secrets.digitalocean.path;
23 |
24 | services = {
25 | # Enable caddy to talk to the tailscale daemon for certs
26 | tailscale.permitCertUid = "caddy";
27 |
28 | caddy.virtualHosts = {
29 | "files.${domain}".extraConfig = mkVHost "http://localhost:8081";
30 | "ha.${domain}".extraConfig = mkVHost "http://localhost:8123";
31 | "photos.${domain}".extraConfig = mkVHost "http://localhost:3001";
32 | "freyja.sync.${domain}".extraConfig = mkVHost "http://freyja.${tailnet}:8384";
33 | "kara.sync.${domain}".extraConfig = mkVHost "http://kara.${tailnet}:8384";
34 | "thor.sync.${domain}".extraConfig = mkVHost "http://thor.${tailnet}:8384";
35 | };
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/host/common/services/tailscale.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | services.tailscale = {
3 | enable = true;
4 | useRoutingFeatures = "both";
5 | openFirewall = true;
6 | };
7 |
8 | networking.firewall.trustedInterfaces = [ "tailscale0" ];
9 | }
10 |
--------------------------------------------------------------------------------
/host/common/users/jon/default.nix:
--------------------------------------------------------------------------------
1 | { pkgs, config, ... }:
2 | let
3 | ifExists = groups: builtins.filter (group: builtins.hasAttr group config.users.groups) groups;
4 | in
5 | {
6 | users.users.jon = {
7 | isNormalUser = true;
8 | shell = pkgs.fish;
9 | extraGroups =
10 | [
11 | "audio"
12 | "networkmanager"
13 | "users"
14 | "video"
15 | "wheel"
16 | ]
17 | ++ ifExists [
18 | "docker"
19 | "plugdev"
20 | "render"
21 | "lxd"
22 | ];
23 |
24 | openssh.authorizedKeys.keys = [
25 | "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIB9bIEMgZVBCDxBWQ4m4hQP6ZZp0P3TfzjzcgUOdbYDLAAAABHNzaDo= YK5C"
26 | "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIBC8cs1B64XqEswY5pART6yERbjUMB7RdQdT38dgkZT6AAAABHNzaDo= YK5"
27 | ];
28 |
29 | packages = [ pkgs.home-manager ];
30 | };
31 |
32 | # This is a workaround for not seemingly being able to set $EDITOR in home-manager
33 | environment.sessionVariables = {
34 | EDITOR = "hx";
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/host/common/virt/default.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | imports = [
3 | ./docker.nix
4 | ./lxd.nix
5 | ./multipass.nix
6 | ];
7 | }
8 |
--------------------------------------------------------------------------------
/host/common/virt/docker.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | virtualisation = {
3 | docker = {
4 | enable = true;
5 | storageDriver = "btrfs";
6 | };
7 | };
8 | }
9 |
--------------------------------------------------------------------------------
/host/common/virt/lxd.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | virtualisation = {
4 | lxd = {
5 | enable = true;
6 | zfsSupport = true;
7 | ui = {
8 | enable = true;
9 | package = pkgs.lxd-ui;
10 | };
11 | };
12 | };
13 |
14 | networking = {
15 | firewall = {
16 | trustedInterfaces = [ "lxdbr0" ];
17 | };
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/host/common/virt/multipass.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | virtualisation.multipass = {
3 | enable = true;
4 | };
5 | }
6 |
--------------------------------------------------------------------------------
/host/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | config,
3 | desktop,
4 | hostname,
5 | inputs,
6 | lib,
7 | modulesPath,
8 | outputs,
9 | stateVersion,
10 | username,
11 | ...
12 | }:
13 | {
14 |
15 | imports =
16 | [
17 | (modulesPath + "/installer/scan/not-detected.nix")
18 | (./. + "/${hostname}/boot.nix")
19 | (./. + "/${hostname}/hardware.nix")
20 |
21 | ./common/base
22 | ./common/users/${username}
23 | ]
24 | ++ lib.optional (builtins.pathExists (./. + "/${hostname}/extra.nix")) ./${hostname}/extra.nix
25 | # Include desktop config if a desktop is defined
26 | ++ lib.optional (builtins.isString desktop) ./common/desktop;
27 |
28 | nixpkgs = {
29 | overlays = [
30 | # Add overlays your own flake exports (from overlays and pkgs dir):
31 | outputs.overlays.additions
32 | outputs.overlays.modifications
33 | outputs.overlays.unstable-packages
34 |
35 | # You can also add overlays exported from other flakes:
36 | # neovim-nightly-overlay.overlays.default
37 | inputs.agenix.overlays.default
38 | inputs.flypi.overlay
39 | inputs.libations.overlays.default
40 |
41 | # Or just specify overlays directly here, for example:
42 | # (_: _: { embr = inputs.embr.packages."${pkgs.system}".embr; })
43 | ];
44 |
45 | config = {
46 | allowUnfree = true;
47 | joypixels.acceptLicense = true;
48 | };
49 | };
50 |
51 | nix = {
52 | # This will add each flake input as a registry
53 | # To make nix3 commands consistent with your flake
54 | registry = lib.mkForce (lib.mapAttrs (_: value: { flake = value; }) inputs);
55 |
56 | # This will additionally add your inputs to the system's legacy channels
57 | # Making legacy nix commands consistent as well, awesome!
58 | nixPath = lib.mkForce (
59 | lib.mapAttrsToList (key: value: "${key}=${value.to.path}") config.nix.registry
60 | );
61 |
62 | optimise.automatic = true;
63 | settings = {
64 | auto-optimise-store = true;
65 | experimental-features = [
66 | "nix-command"
67 | "flakes"
68 | ];
69 | trusted-users = [
70 | "root"
71 | "@wheel"
72 | ];
73 | };
74 | };
75 |
76 | system = {
77 | inherit stateVersion;
78 | };
79 | }
80 |
--------------------------------------------------------------------------------
/host/kara/boot.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | {
3 | boot = {
4 | # Secure boot configuration
5 | bootspec.enable = true;
6 | loader.systemd-boot.enable = lib.mkForce false;
7 | lanzaboote = {
8 | enable = true;
9 | pkiBundle = "/etc/secureboot";
10 | };
11 |
12 | initrd = {
13 | availableKernelModules = [
14 | "ahci"
15 | "nvme"
16 | "sd_mod"
17 | "usb_storage"
18 | "usbhid"
19 | "xhci_pci"
20 | ];
21 | };
22 |
23 | kernelModules = [
24 | "kvm_amd"
25 | "vhost_vsock"
26 | ];
27 |
28 | # Use the latest Linux kernel, rather than the default LTS
29 | # kernelPackages = pkgs.linuxPackages_latest;
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/host/kara/disks.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | disks ? [
4 | "/dev/nvme0n1"
5 | "/dev/nvme1n1"
6 | ],
7 | ...
8 | }:
9 | let
10 | cryptroot = "cryptroot";
11 | defaultBtrfsOpts = [
12 | "defaults"
13 | "compress=zstd:1"
14 | "ssd"
15 | "noatime"
16 | "nodiratime"
17 | ];
18 | in
19 | {
20 | boot.initrd.luks.devices.${cryptroot} = {
21 | # TODO: Remove this "device" attr if/when machine is reinstalled.
22 | # This is a workaround for the legacy -> gpt tables disko format.
23 | device = lib.mkForce "/dev/disk/by-uuid/69f73515-2d29-446c-a6e4-ab9deea44712";
24 | allowDiscards = true;
25 | preLVM = true;
26 | };
27 |
28 | environment.etc = {
29 | "crypttab".text = ''
30 | data /dev/disk/by-partlabel/data /etc/data.keyfile
31 | '';
32 | };
33 |
34 | # TODO: Remove this if/when machine is reinstalled.
35 | # This is a workaround for the legacy -> gpt tables disko format.
36 | fileSystems."/boot".device = lib.mkForce "/dev/disk/by-partlabel/ESP";
37 |
38 | disko.devices = {
39 | disk = {
40 | # 1TB root/boot drive. Configured with:
41 | # - A FAT32 ESP partition for systemd-boot
42 | # - A LUKS container which containers multiple btrfs subvolumes for nixos install
43 | nvme0 = {
44 | device = builtins.elemAt disks 0;
45 | type = "disk";
46 | content = {
47 | type = "gpt";
48 | partitions = {
49 | ESP = {
50 | start = "0%";
51 | end = "512MiB";
52 | type = "EF00";
53 | content = {
54 | type = "filesystem";
55 | format = "vfat";
56 | mountpoint = "/boot";
57 | };
58 | };
59 | luks = {
60 | start = "512MiB";
61 | end = "100%";
62 | content = {
63 | type = "luks";
64 | name = "${cryptroot}";
65 |
66 | settings = {
67 | allowDiscards = true;
68 | };
69 |
70 | content = {
71 | type = "btrfs";
72 | # Override existing partition
73 | extraArgs = [ "-f" ];
74 | subvolumes = {
75 | "@" = {
76 | mountpoint = "/";
77 | mountOptions = defaultBtrfsOpts;
78 | };
79 | "@nix" = {
80 | mountpoint = "/nix";
81 | mountOptions = defaultBtrfsOpts;
82 | };
83 | "@home" = {
84 | mountpoint = "/home";
85 | mountOptions = defaultBtrfsOpts;
86 | };
87 | "@var" = {
88 | mountpoint = "/var";
89 | mountOptions = defaultBtrfsOpts;
90 | };
91 | "@snapshots" = {
92 | mountpoint = "/.snapshots";
93 | mountOptions = defaultBtrfsOpts;
94 | };
95 | };
96 | };
97 | };
98 | };
99 | };
100 | };
101 | };
102 |
103 | # 2TB data drive. LUKS encrypted with single btrfs subvolume.
104 | nvme1 = {
105 | device = builtins.elemAt disks 1;
106 | type = "disk";
107 | content = {
108 | type = "gpt";
109 | partitions = {
110 | data = {
111 | start = "0%";
112 | end = "100%";
113 | content = {
114 | type = "luks";
115 | name = "data";
116 |
117 | settings = {
118 | # Make sure there is no trailing newline in keyfile if used for interactive unlock.
119 | # Use `echo -n "password" > /tmp/secret.key`
120 | keyFile = "/tmp/data.keyfile";
121 | allowDiscards = true;
122 | };
123 |
124 | # Don't try to unlock this drive early in the boot.
125 | initrdUnlock = false;
126 |
127 | content = {
128 | type = "btrfs";
129 | # Override existing partition
130 | extraArgs = [ "-f" ];
131 | subvolumes = {
132 | "@data" = {
133 | mountpoint = "/home/jon/data";
134 | mountOptions = defaultBtrfsOpts;
135 | };
136 | };
137 | };
138 | };
139 | };
140 | };
141 | };
142 | };
143 | };
144 | };
145 | }
146 |
--------------------------------------------------------------------------------
/host/kara/extra.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | {
3 | imports = [
4 | ../common/services/backup
5 | ];
6 |
7 | services.pipewire.wireplumber.configPackages = [
8 | (pkgs.writeTextDir "share/wireplumber/wireplumber.conf.d/99-disable-idle-timeout.conf" ''
9 | monitor.alsa.rules = [
10 | {
11 | matches = [
12 | { node.name = "~alsa_input.*" }
13 | { node.name = "~alsa_output.*" }
14 | ]
15 | actions = {
16 | update-props = {
17 | session.suspend-timeout-seconds = 0,
18 | }
19 | }
20 | }
21 | ]
22 | '')
23 | ];
24 | }
25 |
--------------------------------------------------------------------------------
/host/kara/hardware.nix:
--------------------------------------------------------------------------------
1 | { inputs, lib, ... }:
2 |
3 | {
4 | imports = [
5 | inputs.disko.nixosModules.disko
6 | (import ./disks.nix { inherit lib; })
7 |
8 | inputs.nixos-hardware.nixosModules.common-cpu-amd
9 | inputs.nixos-hardware.nixosModules.common-cpu-amd-pstate
10 | inputs.nixos-hardware.nixosModules.common-gpu-amd
11 | inputs.nixos-hardware.nixosModules.common-hidpi
12 | inputs.nixos-hardware.nixosModules.common-pc
13 | inputs.nixos-hardware.nixosModules.common-pc-ssd
14 |
15 | ../common/hardware/bluetooth.nix
16 | ../common/hardware/yubihsm.nix
17 | ];
18 |
19 | hardware.amdgpu.amdvlk.enable = true;
20 | hardware.amdgpu.opencl.enable = true;
21 |
22 | nixpkgs.hostPlatform = "x86_64-linux";
23 | }
24 |
--------------------------------------------------------------------------------
/host/thor/boot.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | boot = {
3 | initrd = {
4 | availableKernelModules = [
5 | "nvme"
6 | "sd_mod"
7 | "sdhci_pci"
8 | "usb_storage"
9 | "usbhid"
10 | "xhci_pci"
11 | ];
12 | kernelModules = [ ];
13 | };
14 |
15 | kernelModules = [
16 | "kvm-intel"
17 | "vhost_vsock"
18 | ];
19 |
20 | kernel = {
21 | sysctl = {
22 | "fs.inotify.max_user_watches" = 524288;
23 | };
24 | };
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/host/thor/disks.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | let
3 | defaultBtrfsOpts = [
4 | "defaults"
5 | "compress=zstd:1"
6 | "ssd"
7 | "noatime"
8 | "nodiratime"
9 | ];
10 | in
11 | {
12 | environment.etc = {
13 | "crypttab".text = ''
14 | data /dev/disk/by-partlabel/data /etc/data.keyfile
15 | '';
16 | };
17 |
18 | # TODO: Remove this if/when machine is reinstalled.
19 | # This is a workaround for the legacy -> gpt tables disko format.
20 | fileSystems = {
21 | "/".device = lib.mkForce "/dev/disk/by-partlabel/root";
22 | "/boot".device = lib.mkForce "/dev/disk/by-partlabel/ESP";
23 | "/.snapshots".device = lib.mkForce "/dev/disk/by-partlabel/root";
24 | "/home".device = lib.mkForce "/dev/disk/by-partlabel/root";
25 | "/nix".device = lib.mkForce "/dev/disk/by-partlabel/root";
26 | "/var".device = lib.mkForce "/dev/disk/by-partlabel/root";
27 | };
28 |
29 | disko.devices = {
30 | disk = {
31 | # 512GB root/boot drive. Configured with:
32 | # - A FAT32 ESP partition for systemd-boot
33 | # - Multiple btrfs subvolumes for the installation of nixos
34 | nvme0 = {
35 | device = "/dev/nvme0n1";
36 | type = "disk";
37 | content = {
38 | type = "gpt";
39 | partitions = {
40 | ESP = {
41 | start = "0%";
42 | end = "512MiB";
43 | type = "EF00";
44 | content = {
45 | type = "filesystem";
46 | format = "vfat";
47 | mountpoint = "/boot";
48 | };
49 | };
50 | root = {
51 | start = "512MiB";
52 | end = "100%";
53 | content = {
54 | type = "btrfs";
55 | # Override existing partition
56 | extraArgs = [ "-f" ];
57 | subvolumes = {
58 | "@" = {
59 | mountpoint = "/";
60 | mountOptions = defaultBtrfsOpts;
61 | };
62 | "@nix" = {
63 | mountpoint = "/nix";
64 | mountOptions = defaultBtrfsOpts;
65 | };
66 | "@home" = {
67 | mountpoint = "/home";
68 | mountOptions = defaultBtrfsOpts;
69 | };
70 | "@var" = {
71 | mountpoint = "/var";
72 | mountOptions = defaultBtrfsOpts;
73 | };
74 | "@snapshots" = {
75 | mountpoint = "/.snapshots";
76 | mountOptions = defaultBtrfsOpts;
77 | };
78 | };
79 | };
80 | };
81 | };
82 | };
83 | };
84 |
85 | # 4TB data drive. LUKS encrypted with single btrfs subvolume.
86 | sda = {
87 | device = "/dev/sda";
88 | type = "disk";
89 | content = {
90 | type = "gpt";
91 | partitions = {
92 | data = {
93 | start = "0%";
94 | end = "100%";
95 | content = {
96 | type = "luks";
97 | name = "data";
98 |
99 | settings = {
100 | # Make sure there is no trailing newline in keyfile if used for interactive unlock.
101 | # Use `echo -n "password" > /tmp/secret.key`
102 | keyFile = "/tmp/data.keyfile";
103 | allowDiscards = true;
104 | };
105 |
106 | # Don't try to unlock this drive early in the boot.
107 | initrdUnlock = false;
108 |
109 | content = {
110 | type = "btrfs";
111 | # Override existing partition
112 | extraArgs = [ "-f" ];
113 | subvolumes = {
114 | "@data" = {
115 | mountpoint = "/data";
116 | mountOptions = defaultBtrfsOpts;
117 | };
118 | };
119 | };
120 | };
121 | };
122 | };
123 | };
124 | };
125 | };
126 | };
127 | }
128 |
--------------------------------------------------------------------------------
/host/thor/extra.nix:
--------------------------------------------------------------------------------
1 | _: {
2 | imports = [
3 | ../common/services/files.nix
4 | ../common/services/home-assistant.nix
5 | ../common/services/libations.nix
6 | ../common/services/immich.nix
7 | ../common/services/backup
8 | ../common/services/nfs
9 | ../common/services/photo-backup
10 | ../common/services/reverse-proxy
11 | ];
12 | }
13 |
--------------------------------------------------------------------------------
/host/thor/hardware.nix:
--------------------------------------------------------------------------------
1 | { inputs, lib, ... }:
2 | {
3 | imports = [
4 | inputs.disko.nixosModules.disko
5 | inputs.nixos-hardware.nixosModules.common-cpu-intel
6 | inputs.nixos-hardware.nixosModules.common-hidpi
7 | inputs.nixos-hardware.nixosModules.common-pc
8 | inputs.nixos-hardware.nixosModules.common-pc-ssd
9 |
10 | (import ./disks.nix { inherit lib; })
11 | ];
12 |
13 | nixpkgs.hostPlatform = "x86_64-linux";
14 | }
15 |
--------------------------------------------------------------------------------
/host/volnir/boot.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | {
3 | boot = {
4 | initrd = {
5 | availableKernelModules = [ ];
6 | kernelModules = [ ];
7 | };
8 |
9 | loader = {
10 | generic-extlinux-compatible.enable = true;
11 | grub.enable = false;
12 | systemd-boot.enable = lib.mkForce false;
13 | };
14 |
15 | extraModulePackages = [ ];
16 | kernelModules = [ ];
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/host/volnir/disks.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | {
3 | fileSystems."/" = {
4 | device = "/dev/disk/by-label/NIXOS_SD";
5 | fsType = "ext4";
6 | };
7 |
8 | swapDevices = [
9 | {
10 | device = "/.swapfile";
11 | size = 2048;
12 | }
13 | ];
14 |
15 | zramSwap.enable = lib.mkForce false;
16 | }
17 |
--------------------------------------------------------------------------------
/host/volnir/extra.nix:
--------------------------------------------------------------------------------
1 | {
2 | inputs,
3 | lib,
4 | pkgs,
5 | self,
6 | config,
7 | ...
8 | }:
9 | {
10 | imports = [
11 | "${self}/host/common/services/networkmanager.nix"
12 | inputs.flypi.nixosModules.dump1090
13 | inputs.flypi.nixosModules.planefinder
14 | ];
15 |
16 | age.secrets = {
17 | pfconfig = {
18 | file = "${self}/secrets/volnir-planefinder-config.age";
19 | owner = "root";
20 | group = "root";
21 | mode = "444";
22 | };
23 | };
24 |
25 | nixpkgs.overlays = [
26 | (_final: super: {
27 | makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; });
28 | })
29 | ];
30 |
31 | programs.firefox.enable = true;
32 |
33 | services = {
34 | cage = {
35 | enable = true;
36 | extraArguments = [ "-s" ];
37 | user = "jon";
38 | program = "${lib.getExe pkgs.firefox} -kiosk http://localhost:30053";
39 | environment = {
40 | WLR_LIBINPUT_NO_DEVICES = "1";
41 | };
42 | };
43 |
44 | chrony.extraConfig = ''
45 | makestep 1 -1
46 | '';
47 |
48 | dump1090.enable = true;
49 |
50 | planefinder = {
51 | enable = true;
52 | openFirewall = true;
53 | configFile = config.age.secrets.pfconfig.path;
54 | };
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/host/volnir/hardware.nix:
--------------------------------------------------------------------------------
1 | { lib, inputs, ... }:
2 | {
3 | imports = [
4 | inputs.nixos-hardware.nixosModules.raspberry-pi-4
5 | (import ./disks.nix { inherit lib; })
6 | ];
7 |
8 | hardware.raspberry-pi."4".fkms-3d.enable = true;
9 |
10 | nixpkgs.hostPlatform = "aarch64-linux";
11 | }
12 |
--------------------------------------------------------------------------------
/lib/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | inputs,
4 | outputs,
5 | stateVersion,
6 | username,
7 | ...
8 | }:
9 | let
10 | helpers = import ./helpers.nix {
11 | inherit
12 | self
13 | inputs
14 | outputs
15 | stateVersion
16 | username
17 | ;
18 | };
19 | in
20 | {
21 | inherit (helpers) mkHome mkHost forAllSystems;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/helpers.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | inputs,
4 | outputs,
5 | stateVersion,
6 | username,
7 | ...
8 | }:
9 | {
10 | # Helper function for generating home-manager configs
11 | mkHome =
12 | {
13 | hostname,
14 | user ? username,
15 | desktop ? null,
16 | system ? "x86_64-linux",
17 | }:
18 | inputs.home-manager.lib.homeManagerConfiguration {
19 | pkgs = inputs.nixpkgs.legacyPackages.${system};
20 | extraSpecialArgs = {
21 | inherit
22 | self
23 | inputs
24 | outputs
25 | stateVersion
26 | hostname
27 | desktop
28 | ;
29 | username = user;
30 | };
31 | modules = [
32 | inputs.catppuccin.homeManagerModules.catppuccin
33 | ../home
34 | ];
35 | };
36 |
37 | # Helper function for generating host configs
38 | mkHost =
39 | {
40 | hostname,
41 | desktop ? null,
42 | pkgsInput ? inputs.nixpkgs,
43 | }:
44 | pkgsInput.lib.nixosSystem {
45 | specialArgs = {
46 | inherit
47 | self
48 | inputs
49 | outputs
50 | stateVersion
51 | username
52 | hostname
53 | desktop
54 | ;
55 | };
56 | modules = [
57 | inputs.agenix.nixosModules.default
58 | inputs.lanzaboote.nixosModules.lanzaboote
59 | inputs.libations.nixosModules.libations
60 | ../host
61 | ];
62 | };
63 |
64 | mkSystemManager =
65 | {
66 | system ? "x86_64-linux",
67 | }:
68 | inputs.system-manager.lib.makeSystemConfig {
69 | modules = [
70 | inputs.nix-system-graphics.systemModules.default
71 | {
72 | config = {
73 | nixpkgs.hostPlatform = system;
74 | system-manager.allowAnyDistro = true;
75 | system-graphics.enable = true;
76 | };
77 | }
78 | ];
79 | };
80 |
81 | forAllSystems = inputs.nixpkgs.lib.genAttrs [
82 | "aarch64-linux"
83 | "i686-linux"
84 | "x86_64-linux"
85 | "aarch64-darwin"
86 | "x86_64-darwin"
87 | ];
88 | }
89 |
--------------------------------------------------------------------------------
/lib/theme/colours.nix:
--------------------------------------------------------------------------------
1 | rec {
2 | colours = rec {
3 | inherit (catppuccin-macchiato)
4 | pink
5 | red
6 | yellow
7 | green
8 | ;
9 | inherit (catppuccin-macchiato) subtext0 subtext1 text;
10 | inherit (catppuccin-macchiato) overlay0 overlay1 overlay2;
11 | inherit (catppuccin-macchiato) surface0 surface1 surface2;
12 |
13 | accent = darkBlue;
14 | black = catppuccin-macchiato.crust;
15 | white = catppuccin-macchiato.rosewater;
16 | lightPink = catppuccin-macchiato.flamingo;
17 | lightRed = catppuccin-macchiato.maroon;
18 | orange = catppuccin-macchiato.peach;
19 | cyan = catppuccin-macchiato.teal;
20 | blue = catppuccin-macchiato.sapphire;
21 | darkBlue = catppuccin-macchiato.blue;
22 | lightBlue = catppuccin-macchiato.sky;
23 | purple = catppuccin-macchiato.mauve;
24 | lightPurple = catppuccin-macchiato.lavender;
25 | bg = catppuccin-macchiato.base;
26 | bgDark = catppuccin-macchiato.mantle;
27 | };
28 |
29 | catppuccin-macchiato = {
30 | rosewater = "#f4dbd6";
31 | flamingo = "#f0c6c6";
32 | pink = "#f5bde6";
33 | mauve = "#c6a0f6";
34 | red = "#ed8796";
35 | maroon = "#ee99a0";
36 | peach = "#f5a97f";
37 | yellow = "#eed49f";
38 | green = "#a6da95";
39 | teal = "#8bd5ca";
40 | sky = "#91d7e3";
41 | sapphire = "#7dc4e4";
42 | blue = "#8aadf4";
43 | lavender = "#b7bdf8";
44 |
45 | subtext0 = "#a5adcb";
46 | subtext1 = "#b8c0e0";
47 | text = "#cad3f5";
48 |
49 | overlay0 = "#6e738d";
50 | overlay1 = "#8087a2";
51 | overlay2 = "#939ab7";
52 |
53 | surface0 = "#363a4f";
54 | surface1 = "#494d64";
55 | surface2 = "#5b6078";
56 |
57 | base = "#24273a";
58 | crust = "#181926";
59 | mantle = "#1e2030";
60 | };
61 | }
62 |
--------------------------------------------------------------------------------
/lib/theme/default.nix:
--------------------------------------------------------------------------------
1 | {
2 | pkgs,
3 | hostname ? "",
4 | ...
5 | }:
6 | let
7 | inherit ((import ./colours.nix)) colours;
8 | libx = import ./lib.nix { inherit (pkgs) lib; };
9 | in
10 | rec {
11 | inherit (libx) hexToRgb;
12 | inherit colours;
13 |
14 | catppuccin = {
15 | flavor = "macchiato";
16 | accent = "blue";
17 | size = "standard";
18 | };
19 |
20 | wallpaper = if hostname == "kara" then ./wallpapers/mountains.png else ./wallpapers/jokulsarlon.png;
21 |
22 | gtkTheme = {
23 | name = "catppuccin-macchiato-blue-standard";
24 | package = pkgs.catppuccin-gtk.override {
25 | inherit (catppuccin) size;
26 | variant = catppuccin.flavor;
27 | accents = [ catppuccin.accent ];
28 | };
29 | };
30 |
31 | qtTheme = {
32 | name = "Catppuccin-Macchiato-Blue";
33 | package = pkgs.catppuccin-kvantum.override {
34 | variant = catppuccin.flavor;
35 | inherit (catppuccin) accent;
36 | };
37 | };
38 |
39 | iconTheme = rec {
40 | name = "Papirus-Dark";
41 | package = pkgs.papirus-icon-theme;
42 | iconPath = "${package}/share/icons/${name}";
43 | };
44 |
45 | cursorTheme = {
46 | name = "Adwaita";
47 | package = pkgs.adwaita-icon-theme;
48 | size = 24;
49 | };
50 |
51 | fonts = {
52 | default = {
53 | name = "Inter";
54 | package = pkgs.inter;
55 | size = "11";
56 | };
57 | iconFont = {
58 | name = "Inter";
59 | package = pkgs.inter;
60 | };
61 | monospace = {
62 | name = "MesloLGSDZ Nerd Font Mono";
63 | package = pkgs.nerdfonts.override { fonts = [ "Meslo" ]; };
64 | };
65 | emoji = {
66 | name = "Joypixels";
67 | package = pkgs.joypixels;
68 | };
69 | };
70 | }
71 |
--------------------------------------------------------------------------------
/lib/theme/lib.nix:
--------------------------------------------------------------------------------
1 | { lib, ... }:
2 | with lib;
3 | rec {
4 | # color-related functions
5 |
6 | # convert rrggbb hex to #rrggbb
7 | x = c: "#${c}";
8 |
9 | # convert #rrggbb -> r, g, b
10 | hexToRgb =
11 | c:
12 | let
13 | r = toString (hexToDec (__substring 1 2 c));
14 | g = toString (hexToDec (__substring 3 2 c));
15 | b = toString (hexToDec (__substring 5 2 c));
16 | res = "${r}, ${g}, ${b}";
17 | in
18 | res;
19 |
20 | # functions copied from https://gist.github.com/corpix/f761c82c9d6fdbc1b3846b37e1020e11
21 | # convert a hex value to an integer
22 | hexToDec =
23 | v:
24 | let
25 | hexToInt = {
26 | "0" = 0;
27 | "1" = 1;
28 | "2" = 2;
29 | "3" = 3;
30 | "4" = 4;
31 | "5" = 5;
32 | "6" = 6;
33 | "7" = 7;
34 | "8" = 8;
35 | "9" = 9;
36 | "a" = 10;
37 | "b" = 11;
38 | "c" = 12;
39 | "d" = 13;
40 | "e" = 14;
41 | "f" = 15;
42 | "A" = 10;
43 | "B" = 11;
44 | "C" = 12;
45 | "D" = 13;
46 | "E" = 14;
47 | "F" = 15;
48 | };
49 | chars = stringToCharacters v;
50 | charsLen = length chars;
51 | in
52 | foldl (a: v: a + v) 0 (imap0 (k: v: hexToInt."${v}" * (pow 16 (charsLen - k - 1))) chars);
53 |
54 | pow =
55 | let
56 | pow' =
57 | base: exponent: value:
58 | # FIXME: It will silently overflow on values > 2**62 :(
59 | # The value will become negative or zero in this case
60 | if exponent == 0 then
61 | 1
62 | else if exponent <= 1 then
63 | value
64 | else
65 | (pow' base (exponent - 1) (value * base));
66 | in
67 | base: exponent: pow' base exponent base;
68 | }
69 |
--------------------------------------------------------------------------------
/lib/theme/wallpapers/elk-colors.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/lib/theme/wallpapers/elk-colors.jpg
--------------------------------------------------------------------------------
/lib/theme/wallpapers/jokulsarlon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/lib/theme/wallpapers/jokulsarlon.png
--------------------------------------------------------------------------------
/lib/theme/wallpapers/mountains.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/lib/theme/wallpapers/mountains.png
--------------------------------------------------------------------------------
/lib/theme/wallpapers/space-clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/lib/theme/wallpapers/space-clouds.png
--------------------------------------------------------------------------------
/nixpkgs.nix:
--------------------------------------------------------------------------------
1 | # A nixpkgs instance that is grabbed from the pinned nixpkgs commit in the lock file
2 | # Useful to avoid using channels when using legacy nix commands
3 | let
4 | lock = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.nixpkgs.locked;
5 | in
6 | import (fetchTarball {
7 | url = "https://github.com/nixos/nixpkgs/archive/${lock.rev}.tar.gz";
8 | sha256 = lock.narHash;
9 | })
10 |
--------------------------------------------------------------------------------
/overlays/custom-caddy.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | let
3 | inherit (pkgs)
4 | buildGoModule
5 | cacert
6 | caddy
7 | go
8 | lib
9 | stdenv
10 | xcaddy
11 | ;
12 | in
13 | caddy.override {
14 | buildGoModule =
15 | args:
16 | buildGoModule (
17 | args
18 | // {
19 | src = stdenv.mkDerivation rec {
20 | pname = "caddy-using-xcaddy-${xcaddy.version}";
21 | inherit (caddy) version;
22 |
23 | dontUnpack = true;
24 | dontFixup = true;
25 |
26 | nativeBuildInputs = [
27 | cacert
28 | go
29 | ];
30 |
31 | plugins = [ "github.com/caddy-dns/digitalocean" ];
32 |
33 | configurePhase = ''
34 | export GOCACHE=$TMPDIR/go-cache
35 | export GOPATH="$TMPDIR/go"
36 | export XCADDY_SKIP_BUILD=1
37 | '';
38 |
39 | buildPhase = ''
40 | ${xcaddy}/bin/xcaddy build "${caddy.src.rev}" ${
41 | lib.concatMapStringsSep " " (plugin: "--with ${plugin}") plugins
42 | }
43 | cd buildenv*
44 | go mod vendor
45 | '';
46 |
47 | installPhase = ''
48 | cp -r --reflink=auto . $out
49 | '';
50 |
51 | outputHash = "sha256-k4Lu9QKShVEhVuvGEPv3KspcsmjQmPUo0jWHhXOlofQ=";
52 | outputHashMode = "recursive";
53 | };
54 |
55 | subPackages = [ "." ];
56 | ldflags = [
57 | "-s"
58 | "-w"
59 | ]; # # don't include version info twice
60 | vendorHash = null;
61 | }
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/overlays/default.nix:
--------------------------------------------------------------------------------
1 | { inputs, ... }:
2 | {
3 | # This one brings our custom packages from the 'pkgs' directory
4 | additions = final: _prev: import ../pkgs { pkgs = final; };
5 |
6 | modifications = _final: prev: {
7 | # example = prev.example.overrideAttrs (oldAttrs: rec {
8 | # ...
9 | # });
10 | custom-caddy = import ./custom-caddy.nix { pkgs = prev; };
11 | };
12 |
13 | # When applied, the unstable nixpkgs set (declared in the flake inputs) will
14 | # be accessible through 'pkgs.unstable'
15 | unstable-packages = final: _prev: {
16 | master = import inputs.master {
17 | inherit (final) system;
18 | config.allowUnfree = true;
19 | overlays = [
20 | (_final: _prev: {
21 | # example = prev.example.overrideAttrs (oldAttrs: rec {
22 | # ...
23 | # });
24 | })
25 | ];
26 | };
27 | unstable = import inputs.unstable {
28 | inherit (final) system;
29 | config.allowUnfree = true;
30 | overlays = [
31 | (_final: _prev: {
32 | # example = prev.example.overrideAttrs (oldAttrs: rec {
33 | # ...
34 | # });
35 | })
36 | ];
37 | };
38 | };
39 | }
40 |
--------------------------------------------------------------------------------
/pkgs/default.nix:
--------------------------------------------------------------------------------
1 | # Custom packages, that can be defined similarly to ones from nixpkgs
2 | # Build them using 'nix build .#example' or (legacy) 'nix-build -A example'
3 |
4 | {
5 | pkgs ? (import ../nixpkgs.nix) { },
6 | }:
7 | {
8 | ght = pkgs.callPackage ./ght { };
9 | juju4 = pkgs.callPackage ./juju4.nix { };
10 | nixfmt-plus = pkgs.callPackage ./nixfmt-plus.nix { };
11 | }
12 |
--------------------------------------------------------------------------------
/pkgs/ght/default.nix:
--------------------------------------------------------------------------------
1 | { lib, pkgs, ... }:
2 | pkgs.buildNpmPackage rec {
3 | pname = "ght";
4 | version = "1.11.3-unstable-2025-01-21";
5 |
6 | src = pkgs.fetchFromGitHub {
7 | owner = "canonical";
8 | repo = "ght";
9 | # rev = "refs/tags/v${version}";
10 | rev = "306565a0fb39e9d24e36de66cf7881cdb4f30d2e";
11 | hash = "sha256-1cBuMJKDM3zPkfCFOH9Q5CoQLP7A8b8Ejvn/Pbrox8U=";
12 | };
13 |
14 | npmDeps = pkgs.fetchNpmDeps {
15 | inherit src;
16 | hash = "sha256-9SrfnaDpdLR1KL8WQjFSM0Pza1yRm7/YgQ/TimTJm8o=";
17 | };
18 |
19 | patches = [ ./ght-graders-loc.patch ];
20 |
21 | postPatch = ''
22 | substituteInPlace ght \
23 | --replace-fail "./index.js" "$out/opt/ght/index.js" \
24 | --replace-fail "./package.json" "$out/opt/ght/package.json"
25 | '';
26 |
27 | env.PUPPETEER_SKIP_DOWNLOAD = true;
28 |
29 | installPhase = ''
30 | mkdir -p $out/bin $out/opt
31 |
32 | # Copy the built tool & node_modules into the output
33 | cp -r dist $out/opt/ght
34 | cp -r node_modules $out/opt/ght/node_modules
35 |
36 | # Copy the 'binary' into place
37 | cp ght $out/bin/ght
38 |
39 | # Make sure that chromium is available and puppeteer knows to use it
40 | wrapProgram $out/bin/ght \
41 | --set PUPPETEER_EXECUTABLE_PATH ${pkgs.chromium.outPath}/bin/chromium
42 | '';
43 |
44 | meta = {
45 | mainProgram = "ght";
46 | description = "Perform actions in Greenhouse from you terminal";
47 | homepage = "https://github.com/canonical/ght";
48 | changelog = "https://github.com/canonical/ght/releases/tag/v${version}";
49 | maintainers = with lib.maintainers; [ jnsgruk ];
50 | };
51 | }
52 |
--------------------------------------------------------------------------------
/pkgs/ght/ght-graders-loc.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/controllers/AssignGradersController.ts b/src/controllers/AssignGradersController.ts
2 | index 422d5b9..ab3fd67 100644
3 | --- a/src/controllers/AssignGradersController.ts
4 | +++ b/src/controllers/AssignGradersController.ts
5 | @@ -92,8 +92,7 @@ export class AssignGradersController extends BaseController {
6 | });
7 |
8 | const gradersConfigPath = join(
9 | - process.env["SNAP_REAL_HOME"] || homedir(),
10 | - "ght-graders.yml",
11 | + homedir(), ".config/ght/ght-graders.yml"
12 | );
13 | const gradersConfig = loadConfigFile(gradersConfigPath);
14 | if (!config) {
15 |
--------------------------------------------------------------------------------
/pkgs/juju4.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 | let
3 | inherit (pkgs) buildGo123Module fetchFromGitHub installShellFiles;
4 | in
5 | buildGo123Module {
6 | pname = "juju4";
7 | version = "4.0-unstable-2024-09-08";
8 |
9 | src = fetchFromGitHub {
10 | owner = "juju";
11 | repo = "juju";
12 | rev = "e51606a12490923092eb8f99882b2c4de7f4af7a";
13 | hash = "sha256-UZUQqlUzsjf52BJ8lGMWqUM+pKDHplMZLlcHFQY4c1c=";
14 | };
15 |
16 | vendorHash = "sha256-KzR7JCjmfGe5nNuXAk4SsxGdpXjzV1+Dc7YOQc1TwcQ=";
17 |
18 | subPackages = [ "cmd/juju" ];
19 |
20 | nativeBuildInputs = [ installShellFiles ];
21 |
22 | doCheck = false;
23 |
24 | postInstall = ''
25 | mv $out/bin/juju $out/bin/juju4
26 | '';
27 | }
28 |
--------------------------------------------------------------------------------
/pkgs/nixfmt-plus.nix:
--------------------------------------------------------------------------------
1 | { pkgs, ... }:
2 |
3 | pkgs.writeShellApplication {
4 | name = "nixfmt-plus";
5 | runtimeInputs = with pkgs; [
6 | deadnix
7 | nixfmt-rfc-style
8 | statix
9 | ];
10 | text = ''
11 | set -x
12 | deadnix --edit
13 | statix fix
14 | nixfmt .
15 | '';
16 | }
17 |
--------------------------------------------------------------------------------
/scripts/install-with-disko:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 | DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
5 |
6 | TARGET_HOST="${1:-}"
7 | TARGET_USER="${2:-jon}"
8 |
9 | if [ "$(id -u)" -eq 0 ]; then
10 | echo "ERROR! $(basename "${0}") should be run as a regular user"
11 | exit 1
12 | fi
13 |
14 | if [[ -z "$TARGET_HOST" ]]; then
15 | echo "ERROR! $(basename "${0}") requires a hostname as the first argument"
16 | exit 1
17 | fi
18 |
19 | if [ ! -e "host/${TARGET_HOST}/disks.nix" ]; then
20 | echo "ERROR! $(basename "${0}") could not find the required host/${TARGET_HOST}/disks.nix"
21 | exit 1
22 | fi
23 |
24 | # Check if the machine we're provisioning expects a keyfile to unlock a disk.
25 | # If it does, generate a new key, and write to a known location.
26 | if grep -q "data.keyfile" "host/${TARGET_HOST}/disks.nix"; then
27 | echo -n "$(head -c32 /dev/random | base64)" > /tmp/data.keyfile
28 | fi
29 |
30 | echo "WARNING! The disks in ${TARGET_HOST} are about to get wiped"
31 | echo " NixOS will be re-installed"
32 | echo " This is a destructive operation"
33 | echo
34 | read -p "Are you sure? [y/N]" -n 1 -r
35 | echo
36 | if [[ $REPLY =~ ^[Yy]$ ]]; then
37 | sudo true
38 |
39 | sudo nix run github:nix-community/disko \
40 | --extra-experimental-features "nix-command flakes" \
41 | --no-write-lock-file \
42 | -- \
43 | --mode zap_create_mount \
44 | "host/${TARGET_HOST}/disks.nix"
45 |
46 | sudo nixos-install --flake ".#${TARGET_HOST}"
47 |
48 | # Rsync my nix-config to the target install
49 | mkdir -p "/mnt/home/${TARGET_USER}/nixos-config"
50 | rsync -a --delete "${DIR}/.." "/mnt/home/${TARGET_USER}/nixos-config"
51 |
52 | # If there is a keyfile for a data disk, put copy it to the root partition and
53 | # ensure the permissions are set appropriately.
54 | if [[ -f "/tmp/data.keyfile" ]]; then
55 | sudo cp /tmp/data.keyfile /mnt/etc/data.keyfile
56 | sudo chmod 0400 /mnt/etc/data.keyfile
57 | fi
58 | fi
59 |
60 |
61 |
--------------------------------------------------------------------------------
/scripts/partition-btrfs-luks:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euo pipefail
3 | # Output green message prefixed with [+]
4 | _info() { echo -e "\e[92m[+] ${1:-}\e[0m"; }
5 | # Output orange message prefixed with [-]
6 | _warn() { echo -e "\e[33m[-] ${1:-}\e[0m"; }
7 | # Output red message prefixed with [!] and exit
8 | _error() { echo -e >&2 "\e[31m[!] ${1:-}\e[0m"; exit 1; }
9 |
10 | DISK="${DISK:-}"
11 | if [[ -z "$DISK" ]]; then
12 | _error "Set the DISK environment variable to continue"
13 | fi
14 |
15 | # Create a new partition table on the disk
16 | parted "${DISK}" -s mklabel gpt
17 | # Create a 500MiB FAT32 Boot Partition
18 | parted "${DISK}" -s mkpart boot fat32 0% 500MiB
19 | # Set the boot/esp flags on the boot partition
20 | parted "${DISK}" set 1 boot on
21 | # Create a single root partition
22 | parted "${DISK}" -s mkpart root 500MiB 100%
23 |
24 | _warn "Setting up disk encryption. Confirmation and password entry required"
25 | root_part="p2"
26 |
27 | # luksFormat the root partition
28 | cryptsetup luksFormat "${DISK}${root_part}"
29 | _warn "Decrypting disk, password entry required"
30 | # Open the encrypted container
31 | cryptsetup open "${DISK}${root_part}" cryptlvm
32 | # Setup LVM physical volumes, volume groups and logical volumes
33 | _info "Setting up LVM"
34 | # Create a physical volume
35 | pvcreate /dev/mapper/cryptlvm
36 | vgcreate vg /dev/mapper/cryptlvm
37 | lvcreate -l 100%FREE vg -n root
38 |
39 | # Setup the filesystems
40 | root_part="/dev/vg/root"
41 |
42 | # Format the root partition
43 | mkfs.btrfs --force "${root_part}"
44 | # Mount the root partition to /mnt
45 | mount "${root_part}" /mnt
46 | # Create btrfs subvolumes
47 | btrfs subvolume create /mnt/@
48 | btrfs subvolume create /mnt/@home
49 | btrfs subvolume create /mnt/@snapshots
50 | btrfs subvolume create /mnt/@var
51 | # Remount with btrfs options
52 | umount -R /mnt
53 | btrfs_opts="defaults,x-mount.mkdir,compress=lzo,ssd,noatime,nodiratime"
54 | mount -t btrfs -o subvol=@,"${btrfs_opts}" "${root_part}" /mnt
55 | mount -t btrfs -o subvol=@home,"${btrfs_opts}" "${root_part}" /mnt/home
56 | mount -t btrfs -o subvol=@var,"${btrfs_opts}" "${root_part}" /mnt/var
57 | mount -t btrfs -o subvol=@snapshots,"${btrfs_opts}" "${root_part}" /mnt/.snapshots
58 |
59 | boot_part="${DISK}p1"
60 | # Format the boot partition
61 | mkfs.fat -F32 "${boot_part}"
62 | # Mount the boot partition
63 | mount -o "defaults,x-mount.mkdir" "${boot_part}" /mnt/boot
64 |
--------------------------------------------------------------------------------
/scripts/setup-hyprland-ubuntu:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # This script is used to make some configuration changes to Ubuntu
4 | # when running Hyprland using home-manager, system-manager and nix-system-graphics.
5 |
6 | # First, create a script that can execute Hyprland in the right context
7 | cat <<-EOF | sudo tee /usr/local/bin/hypr-run
8 | #!/home/jon/.nix-profile/bin/fish
9 | export GTK_THEME="catppuccin-macchiato-blue-standard"
10 | source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh
11 | systemd-run --user --scope --collect --quiet --unit="Hyprland" systemd-cat --identifier="hyprland" /home/jon/.nix-profile/bin/Hyprland $@
12 | EOF
13 |
14 | # Ensure the script is executable
15 | sudo chmod 755 /usr/local/bin/hypr-run
16 |
17 | # Next add a desktop configuration so that Hyprland comes up in the GDM session menu
18 | cat <<-EOF | sudo tee /usr/share/wayland-sessions/hyprland.desktop
19 | [Desktop Entry]
20 | Name=Hyprland
21 | Comment=Hyprland Tiling Window Manager
22 | Exec=/usr/local/bin/hypr-run
23 | Type=application
24 | EOF
25 |
26 | # Prevent errors occurring when launching Chromium/Electron apps.
27 | echo "kernel.apparmor_restrict_unprivileged_userns=0" | sudo tee /etc/sysctl.d/60-apparmor-namespace.conf
28 |
--------------------------------------------------------------------------------
/secrets/kara-borgbase-passphrase.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/kara-borgbase-passphrase.age
--------------------------------------------------------------------------------
/secrets/kara-borgbase-ssh.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/kara-borgbase-ssh.age
--------------------------------------------------------------------------------
/secrets/secrets.nix:
--------------------------------------------------------------------------------
1 | let
2 | jon = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL3bnlKpGO7eqZFafiLxJVG0TYyleVfuO1C9Q2q0QHJg";
3 | kara = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFhVkbNk0hYPZOu4SlBwD1RXd78PmiD21Yen2j8JgT6Z";
4 | thor = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJqnwVNoWVkTJxUJ1yZh64wKBYaij1IwXUA3PRE3/lIx";
5 | volnir = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIASBzlLkAv8pbvg3/ffDko/K7s5YNWutxclPOLPxNmcu";
6 | users = [ jon ];
7 | in
8 | {
9 | "kara-borgbase-ssh.age".publicKeys = users ++ [ kara ];
10 | "kara-borgbase-passphrase.age".publicKeys = users ++ [ kara ];
11 |
12 | "thor-digitalocean.age".publicKeys = users ++ [ thor ];
13 | "thor-borgbase-ssh.age".publicKeys = users ++ [ thor ];
14 | "thor-borgbase-passphrase.age".publicKeys = users ++ [ thor ];
15 | "thor-libations-tskey.age".publicKeys = users ++ [ thor ];
16 | "thor-libations-recipes.age".publicKeys = users ++ [ thor ];
17 | "thor-backup-env.age".publicKeys = users ++ [ thor ];
18 |
19 | "volnir-planefinder-config.age".publicKeys = users ++ [ volnir ];
20 | }
21 |
--------------------------------------------------------------------------------
/secrets/thor-backup-env.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-backup-env.age
--------------------------------------------------------------------------------
/secrets/thor-borgbase-passphrase.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-borgbase-passphrase.age
--------------------------------------------------------------------------------
/secrets/thor-borgbase-ssh.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-borgbase-ssh.age
--------------------------------------------------------------------------------
/secrets/thor-digitalocean.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-digitalocean.age
--------------------------------------------------------------------------------
/secrets/thor-libations-recipes.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-libations-recipes.age
--------------------------------------------------------------------------------
/secrets/thor-libations-tskey.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/thor-libations-tskey.age
--------------------------------------------------------------------------------
/secrets/volnir-planefinder-config.age:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jnsgruk/nixos-config/d88511d5007f71f23acf07d5b7b8d1c4a45dcaae/secrets/volnir-planefinder-config.age
--------------------------------------------------------------------------------
/shell.nix:
--------------------------------------------------------------------------------
1 | # Shell for bootstrapping flake-enabled nix and home-manager
2 | # Access development shell with 'nix develop' or (legacy) 'nix-shell'
3 | {
4 | pkgs ? (import ./nixpkgs.nix) { },
5 | }:
6 | {
7 | default = pkgs.mkShell {
8 | name = "jnsgruk-flake";
9 | # Enable experimental features without having to specify the argument
10 | NIX_CONFIG = "experimental-features = nix-command flakes";
11 | nativeBuildInputs = with pkgs; [
12 | nix
13 | home-manager
14 | git
15 | ];
16 | shellHook = ''
17 | exec fish
18 | '';
19 | };
20 | }
21 |
--------------------------------------------------------------------------------