├── .envrc ├── .github ├── dependabot.yml └── workflows │ ├── check-flake.yml │ ├── check-format.yml │ ├── deploy.yml │ └── update.yml ├── .gitignore ├── LICENSE ├── README.org ├── flake-parts ├── agenix.nix ├── cachix-deploy.nix ├── deploy.nix ├── emacs.nix ├── home-manager.nix ├── installers.nix ├── nixos.nix ├── pkgs.nix └── treefmt.nix ├── flake.lock ├── flake.nix ├── homes ├── basic.nix ├── code.nix ├── core.nix ├── etc │ ├── river │ │ └── init │ └── starship │ │ └── starship.toml ├── extra.nix ├── graphical.nix ├── lib │ └── waybar-config.nix ├── modules.nix ├── modules │ ├── aider │ │ ├── default.nix │ │ └── interface.nix │ ├── browser.nix │ ├── crostini.nix │ ├── direnv.nix │ ├── dunst.nix │ ├── fzy.nix │ ├── git.nix │ ├── gpg.nix │ ├── hyprland.nix │ ├── librewolf.nix │ ├── password-store.nix │ ├── psd.nix │ ├── rebuild-home.nix │ ├── rebuild-nixos.nix │ ├── recoll.nix │ ├── timoni.nix │ ├── words.nix │ ├── wslu.nix │ ├── xdg.nix │ └── zsh.nix └── wsl.nix ├── machines ├── hui │ ├── boot.nix │ ├── default.nix │ └── flake-module.nix ├── li │ ├── boot.nix │ ├── default.nix │ ├── flake-module.nix │ └── rpool5 │ │ ├── default.nix │ │ └── extras.nix ├── metadata.toml ├── shu │ ├── boot.nix │ ├── default.nix │ ├── disko.nix │ └── flake-module.nix ├── voyage │ └── home.nix ├── wang │ ├── boot.nix │ ├── default.nix │ ├── flake-module.nix │ └── fs │ │ ├── annex.nix │ │ ├── btrfs.nix │ │ ├── default.nix │ │ └── storage1.nix ├── yang │ ├── boot.nix │ ├── default.nix │ ├── flake-module.nix │ ├── fs │ │ ├── btrfs.nix │ │ ├── default.nix │ │ └── rpool4.nix │ └── lgtm-stack.nix └── zheng │ ├── default.nix │ ├── flake-module.nix │ ├── router.nix │ ├── secrets │ └── dhcp-hosts.age │ └── usb-wifi.nix ├── nixos ├── models │ └── asus-br1100 │ │ ├── flake-module.nix │ │ └── modules │ │ ├── acpi_call.nix │ │ ├── default.nix │ │ ├── r8168.nix │ │ └── wireless.nix ├── profiles │ ├── acme │ │ ├── default.nix │ │ ├── internal.nix │ │ └── secrets │ │ │ └── nicesunny.day.credentials.txt.age │ ├── adb │ │ └── default.nix │ ├── adguard-home │ │ └── default.nix │ ├── agenix │ │ └── default.nix │ ├── containers │ │ ├── default.nix │ │ └── rootless.nix │ ├── desktop │ │ └── plasma.nix │ ├── docker │ │ ├── default.nix │ │ ├── kind.nix │ │ └── rootless.nix │ ├── dpt-rp1 │ │ └── default.nix │ ├── flatpak │ │ └── default.nix │ ├── home-manager │ │ └── default.nix │ ├── intel-arc │ │ └── default.nix │ ├── k3s │ │ ├── single-node-for-testing.nix │ │ └── single-node.nix │ ├── livebook │ │ ├── default.nix │ │ └── interface.nix │ ├── locale │ │ └── default.nix │ ├── microvm │ │ ├── default.nix │ │ └── ssh.nix │ ├── minio │ │ └── development.nix │ ├── networking │ │ └── usb-tether1.nix │ ├── nginx │ │ └── default.nix │ ├── nix │ │ ├── cachix-deploy.nix │ │ └── default.nix │ ├── nixpkgs │ │ └── channels.nix │ ├── ollama │ │ └── default.nix │ ├── onedev │ │ └── default.nix │ ├── openssh │ │ └── default.nix │ ├── pipewire │ │ └── default.nix │ ├── podman │ │ ├── default.nix │ │ └── rootless-docker.nix │ ├── postgresql │ │ └── development.nix │ ├── rabbitmq │ │ └── development.nix │ ├── reverse-proxy │ │ └── default.nix │ ├── sudo │ │ └── default.nix │ ├── syncthing │ │ └── default.nix │ ├── tailscale │ │ └── default.nix │ ├── users │ │ ├── 1000 │ │ │ └── on-server.nix │ │ └── primary-group.nix │ ├── virtualbox-host │ │ ├── default.nix │ │ └── generate.bash │ ├── wayland │ │ ├── cage │ │ │ ├── emacs.nix │ │ │ ├── firefox.nix │ │ │ ├── foot.nix │ │ │ └── makeWrapper.nix │ │ ├── sessions.nix │ │ ├── sway-utils.nix │ │ ├── wlroots.nix │ │ └── wm │ │ │ ├── hyprland.nix │ │ │ └── labwc.nix │ ├── window-manager │ │ └── generic.nix │ └── yubikey │ │ └── default.nix └── suites │ ├── base │ └── default.nix │ ├── desktop │ └── default.nix │ ├── graphical │ └── default.nix │ ├── hcloud-remote │ └── default.nix │ ├── hcloud │ └── default.nix │ ├── installer │ └── default.nix │ ├── iso │ └── default.nix │ ├── microvm-gui │ └── default.nix │ ├── microvm │ └── default.nix │ ├── remote-installer │ └── default.nix │ └── server │ └── default.nix ├── secrets ├── aider-env.age ├── rekeyed │ ├── yang │ │ └── cde7a1a585cb8ea1ccfb2a2e1535f2ef-nicesunny.day.credentials.txt.age │ └── zheng │ │ └── e10023806a5bd15c8d5351e849343edd-dhcp-hosts.age └── yubikey.pub └── templates ├── flake-module.nix ├── home-manager ├── .gitignore ├── flake.nix └── home.nix └── nixos-wsl ├── .gitignore ├── README.md ├── flake.nix └── justfile /.envrc: -------------------------------------------------------------------------------- 1 | use flake . --accept-flake-config 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | labels: 8 | - "automation" 9 | - "actions" 10 | -------------------------------------------------------------------------------- /.github/workflows/check-flake.yml: -------------------------------------------------------------------------------- 1 | name: Check the flake 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | paths-ignore: 6 | - 'README.*' 7 | - '.github/**' 8 | push: 9 | branches: 10 | - master 11 | paths-ignore: 12 | - 'README.*' 13 | - '.github/**' 14 | - 'treefmt.nix' 15 | concurrency: 16 | group: ${{ github.workflow }}-${{ github.ref }} 17 | cancel-in-progress: true 18 | jobs: 19 | check: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: cachix/install-nix-action@v31.4.0 24 | with: 25 | extra_nix_config: | 26 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 27 | accept-flake-config = true 28 | # It would be possible to add to here a cachix-action step to upload 29 | # everything built within this workflow, but I will choose to save space by 30 | # not uploading anything implicitly. If I have packages that should be 31 | # available from my binary cache, I will upload them from somewhere else or 32 | # use `cachix push` to explicitly specify them. 33 | - run: | 34 | nix flake update emacs-config 35 | nix flake check --print-build-logs --show-trace 36 | -------------------------------------------------------------------------------- /.github/workflows/check-format.yml: -------------------------------------------------------------------------------- 1 | name: Check formatting 2 | on: 3 | workflow_dispatch: 4 | push: 5 | concurrency: 6 | group: ${{ github.workflow }}-${{ github.ref }} 7 | cancel-in-progress: true 8 | jobs: 9 | check: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: cachix/install-nix-action@v31.4.0 14 | with: 15 | extra_nix_config: | 16 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 17 | accept-flake-config = true 18 | # This check is actually done as part of `nix flake check` in 19 | # ./check-flake.yml, but this formatting check requires less time, so run it 20 | # separately for failing fast. 21 | - name: Check formatting 22 | run: | 23 | nix build -L ".#checks.$(nix eval --expr builtins.currentSystem --impure --raw).treefmt" 24 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Cachix Deploy 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'flake.lock' 9 | - 'machines/**' 10 | - 'profiles/**' 11 | - 'suites/**' 12 | - 'homes/**' 13 | schedule: 14 | - cron: '0 18 * * *' # 3:00 am JST 15 | env: 16 | dry: ${{ github.event.event_name == 'push' }} 17 | concurrency: 18 | group: ${{ github.workflow }} 19 | cancel-in-progress: true 20 | jobs: 21 | build-and-deploy: 22 | runs-on: ubuntu-latest 23 | env: 24 | CACHIX_ACTIVATE_TOKEN: ${{ secrets.CACHIX_ACTIVATE_TOKEN }} 25 | CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }} 26 | CACHIX_SIGNING_KEY: ${{ secrets.CACHIX_SIGNING_KEY }} 27 | steps: 28 | - uses: actions/checkout@v4 29 | - uses: cachix/install-nix-action@v31.4.0 30 | with: 31 | extra_nix_config: | 32 | accept-flake-config = true 33 | - uses: cachix/cachix-action@v16 34 | with: 35 | name: akirak 36 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 37 | skipPush: true 38 | pathsToPush: | 39 | # Specify paths to push 40 | # - run: | 41 | # nix flake check \ 42 | # --override-input emacs-config github:akirak/emacs-config/develop 43 | - name: Build the deploys 44 | id: build 45 | # A timeout set arbitrary 46 | timeout-minutes: 90 47 | run: | 48 | nix flake update emacs-config 49 | spec=$(nix build .#cachix-deploys --print-out-paths --print-build-logs \ 50 | ${{ env.dry == 'true' && '--dry-run' || '' }}) 51 | echo "spec_path=$spec" >> "$GITHUB_OUTPUT" 52 | - name: Push to Cachix 53 | if: ${{ env.dry == 'false' }} 54 | run: | 55 | cachix push akirak "$DEPLOY_SPEC" 56 | env: 57 | DEPLOY_SPEC: ${{ steps.build.outputs.spec_path }} 58 | - name: Deploy 59 | if: ${{ env.dry == 'false' }} 60 | # Should be deployed instantly. Some machines may be offline, but then you 61 | # can rerun this workflow 62 | timeout-minutes: 1 63 | # It is very possible that some machines are offline which makes this step 64 | # fail. Don't mark the entire workflow run as a failure. 65 | continue-on-error: true 66 | run: | 67 | cachix deploy activate "$DEPLOY_SPEC" 68 | env: 69 | DEPLOY_SPEC: ${{ steps.build.outputs.spec_path }} 70 | -------------------------------------------------------------------------------- /.github/workflows/update.yml: -------------------------------------------------------------------------------- 1 | name: Update the flake from the registry 2 | on: 3 | workflow_dispatch: 4 | repository_dispatch: 5 | types: 6 | - flake-update 7 | jobs: 8 | update: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: cachix/install-nix-action@v31.4.0 13 | with: 14 | extra_nix_config: | 15 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 16 | accept-flake-config = true 17 | - uses: DeterminateSystems/update-flake-lock@v25 18 | with: 19 | token: ${{ secrets.PAT_FOR_PR }} 20 | pr-title: "Update flake.lock" 21 | pr-labels: | 22 | automation 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gcroots 2 | *.img 3 | result* 4 | .pre-commit-config.yaml 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2025 Akira Komamura 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.org: -------------------------------------------------------------------------------- 1 | # -*- org-id-link-to-org-use-id: nil; -*- 2 | * Home Lab 3 | This repository contains the configuration files of my NixOS machines. 4 | -------------------------------------------------------------------------------- /flake-parts/agenix.nix: -------------------------------------------------------------------------------- 1 | { lib, inputs, ... }: 2 | let 3 | inherit (inputs) self; 4 | 5 | hostPubkeys = lib.pipe (lib.importTOML ../machines/metadata.toml).hosts [ 6 | (lib.filterAttrs (_: attrs: attrs ? publicKey)) 7 | (builtins.mapAttrs (_: attrs: attrs.publicKey)) 8 | ]; 9 | in 10 | { 11 | flake = { 12 | agenix-rekey = inputs.agenix-rekey.configure { 13 | userFlake = self; 14 | nixosConfigurations = builtins.intersectAttrs hostPubkeys self.nixosConfigurations; 15 | }; 16 | 17 | lib = { 18 | inherit hostPubkeys; 19 | }; 20 | }; 21 | 22 | perSystem = 23 | { system, pkgs, ... }: 24 | { 25 | devShells = { 26 | default = pkgs.mkShell { 27 | buildInputs = [ 28 | pkgs.age 29 | pkgs.age-plugin-yubikey 30 | ]; 31 | nativeBuildInputs = [ inputs.agenix-rekey.packages.${system}.default ]; 32 | }; 33 | }; 34 | }; 35 | } 36 | -------------------------------------------------------------------------------- /flake-parts/cachix-deploy.nix: -------------------------------------------------------------------------------- 1 | # Currently unused 2 | { lib, inputs, ... }: 3 | let 4 | inherit (inputs) self; 5 | 6 | nixosHosts = [ 7 | "hui" 8 | ]; 9 | 10 | homeHosts = [ 11 | ]; 12 | in 13 | { 14 | flake = { 15 | packages.x86_64-linux = 16 | let 17 | pkgs = inputs.unstable.legacyPackages.x86_64-linux; 18 | in 19 | { 20 | cachix-deploys = (inputs.cachix-deploy-flake.lib pkgs).spec { 21 | agents = 22 | (lib.genAttrs nixosHosts (name: self.nixosConfigurations.${name}.config.system.build.toplevel)) 23 | // (lib.genAttrs homeHosts (name: self.homeConfigurations.${name}.activationPackage)); 24 | }; 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /flake-parts/deploy.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | inherit (inputs) self stable; 4 | in 5 | { 6 | perSystem = 7 | { 8 | pkgs, 9 | lib, 10 | system, 11 | ... 12 | }: 13 | let 14 | deployToHost = 15 | hostName: 16 | pkgs.writeShellApplication { 17 | name = "deploy"; 18 | runtimeInputs = [ stable.legacyPackages.${system}.nixos-rebuild ]; 19 | meta.description = "A nixos-rebuild wrapper that targets a host on LAN"; 20 | text = '' 21 | target_host="${hostName}" 22 | 23 | usage() { 24 | echo "deploy [--target-host IP] switch|test ARGS" 25 | } 26 | 27 | while [[ $# -gt 0 ]]; do 28 | case "$1" in 29 | --help|-h) 30 | usage 31 | exit 32 | ;; 33 | --target-host) 34 | target_host="$2" 35 | shift; shift 36 | ;; 37 | *) 38 | mode="$1" 39 | shift 40 | break 41 | ;; 42 | esac 43 | done 44 | 45 | if ! [[ -v mode ]]; then 46 | echo >&2 "You need to specify one of the subcommands of nixos-rebuild" 47 | exit 1 48 | fi 49 | 50 | set -x 51 | 52 | # Don't look up known_hosts file because the host key is updated on every deploy 53 | NIX_SSHOPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \ 54 | nixos-rebuild "$mode" \ 55 | --flake ".#${hostName}" \ 56 | --target-host "root@''${target_host}" \ 57 | --option accept-flake-config true \ 58 | "$@" 59 | ''; 60 | }; 61 | in 62 | { 63 | packages = lib.mapAttrs' ( 64 | hostName: _: lib.nameValuePair "deploy-${hostName}" (deployToHost hostName) 65 | ) self.nixosConfigurations; 66 | }; 67 | } 68 | -------------------------------------------------------------------------------- /flake-parts/emacs.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | { 3 | flake = { 4 | nixosModules = { 5 | twistHomeModule = 6 | { homeUser, ... }: 7 | { 8 | home-manager.users.${homeUser} = { 9 | imports = [ inputs.emacs-config.homeModules.twist ]; 10 | }; 11 | }; 12 | }; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /flake-parts/home-manager.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | { 3 | flake = { 4 | nixosModules = { 5 | hmProfile = { 6 | nixpkgs.overlays = [ inputs.self.overlays.default ]; 7 | imports = [ 8 | # Use a home-manager channel corresponding to your OS 9 | # inputs.home-manager.nixosModules.home-manager 10 | inputs.self.nixosModules.twistHomeModule 11 | ../nixos/profiles/home-manager 12 | ]; 13 | }; 14 | }; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /flake-parts/installers.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | inherit (inputs) stable unstable; 4 | 5 | overlayModule = { 6 | nixpkgs.overlays = [ inputs.self.overlays.default ]; 7 | }; 8 | in 9 | { 10 | flake = { 11 | packages.x86_64-linux = { 12 | remote-installer-image = 13 | (stable.lib.nixosSystem { 14 | system = "x86_64-linux"; 15 | modules = [ 16 | overlayModule 17 | ../nixos/suites/remote-installer 18 | ( 19 | { modulesPath, ... }: 20 | { 21 | imports = [ (modulesPath + "/installer/cd-dvd/installation-cd-base.nix") ]; 22 | } 23 | ) 24 | ]; 25 | }).config.system.build.isoImage; 26 | }; 27 | 28 | packages.aarch64-linux = { 29 | bootstrap-sd-image = 30 | (unstable.lib.nixosSystem { 31 | system = "aarch64-linux"; 32 | modules = [ 33 | overlayModule 34 | ( 35 | { modulesPath, ... }: 36 | { 37 | imports = [ (modulesPath + "/installer/sd-card/sd-image-aarch64.nix") ]; 38 | } 39 | ) 40 | ../nixos/suites/installer 41 | { networking.networkmanager.enable = true; } 42 | ]; 43 | }).config.system.build.sdImage; 44 | }; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /flake-parts/nixos.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | inherit (inputs) self flake-pins; 4 | in 5 | { 6 | flake = { 7 | nixosModules = { 8 | default = 9 | { 10 | # Explicitly pass as specialArg to prevent infinite recursion when 11 | # determining the modules to import 12 | hostPubkey, 13 | config, 14 | lib, 15 | ... 16 | }: 17 | let 18 | inherit (config.networking) hostName; 19 | configurationRevision = "${builtins.substring 0 8 self.lastModifiedDate}.${self.rev or "dirty"}"; 20 | # hostPubkey = self.lib.hostPubkeys.${hostName} or null; 21 | in 22 | { 23 | system.configurationRevision = lib.mkIf (inputs.self ? lastModifiedDate) configurationRevision; 24 | nixpkgs.overlays = [ inputs.self.overlays.default ]; 25 | 26 | imports = 27 | [ 28 | inputs.disko.nixosModules.disko 29 | inputs.impermanence.nixosModules.impermanence 30 | flake-pins.nixosModules.nix-registry 31 | ] 32 | ++ lib.optionals (hostPubkey != null) [ 33 | inputs.agenix.nixosModules.default 34 | inputs.agenix-rekey.nixosModules.default 35 | # You have to define these options for every host. 36 | { 37 | age.rekey = { 38 | inherit hostPubkey; 39 | masterIdentities = [ ../secrets/yubikey.pub ]; 40 | storageMode = "local"; 41 | localStorageDir = ../. + "/secrets/rekeyed/${hostName}"; 42 | # TODO: Add backup keys 43 | # extraEncryptionPubkeys = []; 44 | }; 45 | } 46 | ]; 47 | }; 48 | 49 | }; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /flake-parts/pkgs.nix: -------------------------------------------------------------------------------- 1 | { lib, inputs, ... }: 2 | let 3 | inherit (inputs) unstable; 4 | 5 | overlays = [ 6 | inputs.flake-pins.overlays.default 7 | (_final: prev: { 8 | channels = lib.genAttrs [ 9 | "hyprland-contrib" 10 | "fonts" 11 | "zsh-plugins" 12 | ] (name: inputs.${name}.packages.${prev.system}); 13 | unstable = unstable.legacyPackages.${prev.system}; 14 | # Explicit import from the small nixpkgs. 15 | unstable-small-unfree = import inputs.unstable-small { 16 | inherit (prev) system; 17 | config.allowUnfree = true; 18 | }; 19 | # unstable-small = inputs.unstable-small.legacyPackages.${prev.system}; 20 | disko = inputs.disko.packages.${prev.system}.disko; 21 | nix-index = inputs.nix-index-database.packages.${prev.system}.nix-index-with-db; 22 | }) 23 | ]; 24 | in 25 | { 26 | flake = { 27 | overlays.default = lib.composeManyExtensions overlays; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /flake-parts/treefmt.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | { 3 | imports = [ 4 | inputs.treefmt-nix.flakeModule 5 | ]; 6 | 7 | perSystem = _: { 8 | treefmt = { 9 | projectRootFile = "README.org"; 10 | programs = { 11 | # Previously alejandra had been used for formatting Nix, and I don't want to 12 | # reformat existing files until its' necessary. Thus I will disable 13 | # formatting checks on Nix code. 14 | 15 | # nixfmt-rfc-style.enable = true; 16 | 17 | deadnix.enable = true; 18 | shellcheck.enable = true; 19 | yamlfmt.enable = true; 20 | }; 21 | 22 | settings.excludes = [ 23 | "*.age" 24 | "*.pub" 25 | "*.org" 26 | ]; 27 | 28 | settings.formatter = { 29 | shellcheck.excludes = [ ".envrc" ]; 30 | }; 31 | } ; 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | flake-pins.url = "github:akirak/flake-pins"; 4 | 5 | unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | stable.url = "github:NixOS/nixpkgs/nixos-25.05"; 7 | 8 | # More frequently input to use the newer versions of packages. 9 | unstable-small.url = "github:NixOS/nixpkgs/nixos-unstable-small"; 10 | 11 | home-manager-stable.url = "github:nix-community/home-manager/release-25.05"; 12 | home-manager-unstable.url = "github:nix-community/home-manager"; 13 | nix-darwin.url = "github:LnL7/nix-darwin"; 14 | 15 | nixos-hardware.url = "github:NixOS/nixos-hardware"; 16 | 17 | home-manager-stable.inputs.nixpkgs.follows = "stable"; 18 | home-manager-unstable.inputs.nixpkgs.follows = "unstable"; 19 | 20 | flake-parts.url = "github:hercules-ci/flake-parts"; 21 | 22 | disko = { 23 | url = "github:nix-community/disko"; 24 | inputs.nixpkgs.follows = "unstable"; 25 | }; 26 | 27 | impermanence.url = "github:nix-community/impermanence"; 28 | 29 | agenix.url = "github:ryantm/agenix"; 30 | agenix-rekey.url = "github:oddlama/agenix-rekey"; 31 | agenix-rekey.inputs.nixpkgs.follows = "unstable"; 32 | 33 | # cachix-deploy-flake = { 34 | # url = "github:cachix/cachix-deploy-flake"; 35 | # inputs.nixpkgs.follows = "stable"; 36 | # inputs.home-manager.follows = "home-manager-stable"; 37 | # inputs.darwin.follows = "nix-darwin"; 38 | # }; 39 | 40 | treefmt-nix.url = "github:numtide/treefmt-nix"; 41 | 42 | nix-index-database = { 43 | url = "github:Mic92/nix-index-database"; 44 | inputs.nixpkgs.follows = "unstable"; 45 | }; 46 | 47 | hyprland-contrib.url = "github:hyprwm/contrib"; 48 | 49 | emacs-config = { 50 | url = "github:akirak/emacs-config/develop"; 51 | inputs.twist.follows = "twist"; 52 | }; 53 | twist.url = "github:emacs-twist/twist.nix"; 54 | }; 55 | 56 | nixConfig = { 57 | extra-substituters = [ 58 | "https://cachix.cachix.org" 59 | "https://hyprland.cachix.org" 60 | "https://akirak.cachix.org" 61 | "https://nix-community.cachix.org" 62 | ]; 63 | extra-trusted-public-keys = [ 64 | "cachix.cachix.org-1:eWNHQldwUO7G2VkjpnjDbWwy4KQ/HNxht7H4SSoMckM=" 65 | "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" 66 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 67 | "akirak.cachix.org-1:WJrEMdV1dYyALkOdp/kAECVZ6nAODY5URN05ITFHC+M=" 68 | ]; 69 | }; 70 | 71 | outputs = 72 | { 73 | unstable, 74 | flake-parts, 75 | ... 76 | }@inputs: 77 | flake-parts.lib.mkFlake { inherit inputs; } { 78 | imports = [ 79 | ./flake-parts/deploy.nix 80 | ./flake-parts/treefmt.nix 81 | ./flake-parts/agenix.nix 82 | ./flake-parts/installers.nix 83 | ./flake-parts/pkgs.nix 84 | ./flake-parts/emacs.nix 85 | ./flake-parts/nixos.nix 86 | ./flake-parts/home-manager.nix 87 | # ./flake-parts/cachix-deploy.nix 88 | 89 | ./templates/flake-module.nix 90 | 91 | ./nixos/models/asus-br1100/flake-module.nix 92 | 93 | ./machines/li/flake-module.nix 94 | ./machines/yang/flake-module.nix 95 | ./machines/wang/flake-module.nix 96 | ./machines/shu/flake-module.nix 97 | ./machines/hui/flake-module.nix 98 | ./machines/zheng/flake-module.nix 99 | ]; 100 | 101 | systems = [ 102 | "x86_64-linux" 103 | "aarch64-linux" 104 | ]; 105 | 106 | perSystem = 107 | { 108 | system, 109 | ... 110 | }: 111 | { 112 | _module.args.pkgs = unstable.legacyPackages.${system}; 113 | }; 114 | }; 115 | } 116 | -------------------------------------------------------------------------------- /homes/basic.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | { 3 | programs = { 4 | nix-index.enable = true; 5 | nix-index.enableZshIntegration = config.programs.nix-index.enable; 6 | password-store.enable = true; 7 | }; 8 | 9 | home.packages = with pkgs; [ 10 | # Nix 11 | nix-prefetch-git 12 | nix-output-monitor 13 | 14 | # Development 15 | gh 16 | difftastic 17 | duckdb 18 | tbls 19 | hyperfine 20 | just 21 | tailspin 22 | 23 | # Media 24 | git-annex 25 | 26 | # System 27 | btop 28 | dua 29 | duf 30 | 31 | # Net 32 | xh 33 | ]; 34 | 35 | services = { 36 | recoll.enable = true; 37 | syncthing.enable = true; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /homes/code.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: 7 | let 8 | # Build an interpreter-only derivation for running a package directly. 9 | onlySingleBin = 10 | drv: name: 11 | (pkgs.callPackage ( 12 | { runCommand, makeWrapper }: 13 | runCommand name 14 | { 15 | buildInputs = [ 16 | makeWrapper 17 | ]; 18 | propagatedBuildInputs = [ drv ]; 19 | } 20 | '' 21 | mkdir -p $out/bin 22 | makeWrapper ${lib.getExe' drv name} $out/bin/${name} \ 23 | --prefix PATH : ${lib.getBin drv}/bin 24 | '' 25 | ) { }); 26 | in 27 | { 28 | # Custom module 29 | programs.aider = { 30 | enable = true; 31 | age = { 32 | identityFile = lib.mkDefault ../secrets/yubikey.pub; 33 | envFile = lib.mkDefault ../secrets/aider-env.age; 34 | }; 35 | }; 36 | 37 | programs.uv.enable = true; 38 | 39 | home.packages = 40 | (with pkgs; [ 41 | yamlfmt 42 | vscode-langservers-extracted # Primarily for the JSON server 43 | nil # Nix 44 | just-lsp 45 | 46 | customPackages.codex-cli 47 | unstable-small-unfree.claude-code 48 | 49 | # Used to run MCP servers. 50 | (onlySingleBin pkgs.nodejs "npx") 51 | ]) 52 | ++ (lib.optional (!config.programs.uv.enable) (onlySingleBin pkgs.uv "uvx")) 53 | ++ (lib.optionals pkgs.stdenv.isLinux [ 54 | # Sandbox MCP scripts 55 | pkgs.bubblewrap 56 | ]); 57 | } 58 | -------------------------------------------------------------------------------- /homes/core.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | pkgs, 4 | config, 5 | ... 6 | }: let 7 | enableDirenv = config.programs.direnv.enable; 8 | in { 9 | imports = import ./modules.nix {inherit lib;}; 10 | 11 | programs = { 12 | bat.enable = true; 13 | eza.enable = true; 14 | git.enable = true; # ./modules/git.nix 15 | gpg.enable = true; # ./modules/gpg.nix 16 | direnv.enable = true; # ./modules/direnv.nix 17 | direnv.nix-direnv.enable = lib.mkIf enableDirenv true; 18 | }; 19 | 20 | home.packages = with pkgs; [ 21 | # Utilities 22 | ripgrep 23 | fd 24 | jq 25 | ]; 26 | } 27 | -------------------------------------------------------------------------------- /homes/etc/river/init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # This is the example configuration file for river. 4 | # 5 | # If you wish to edit this, you will probably want to copy it to 6 | # $XDG_CONFIG_HOME/river/init or $HOME/.config/river/init first. 7 | # 8 | # See the river(1), riverctl(1), and rivertile(1) man pages for complete 9 | # documentation. 10 | 11 | # Note: the "Super" modifier is also known as Logo, GUI, Windows, Mod4, etc. 12 | 13 | # Also inspired by 14 | # https://github.com/4Dk3/Sway-waybar-and-river/blob/main/river/init 15 | 16 | waybar & 17 | foot --server & 18 | dunst & 19 | 20 | riverctl map normal Super+Shift Return spawn foot 21 | 22 | # Super+Q to close the focused view 23 | riverctl map normal Super Q close 24 | 25 | riverctl map normal Super P spawn 'fuzzel' 26 | 27 | riverctl map normal Super+Shift S spawn 'flameshot gui' 28 | 29 | riverctl map normal Super F9 spawn 'foot nixos-rebuild-and-notify' 30 | 31 | riverctl map normal Super E spawn 'emacsclient -c -a emacs' 32 | 33 | # Super+Shift+Q to exit river 34 | riverctl map normal Super+Shift Q exit 35 | 36 | # Super+J and Super+K to focus the next/previous view in the layout stack 37 | riverctl map normal Super J focus-view next 38 | riverctl map normal Super K focus-view previous 39 | 40 | # Super+Shift+J and Super+Shift+K to swap the focused view with the next/previous 41 | # view in the layout stack 42 | riverctl map normal Super+Shift J swap next 43 | riverctl map normal Super+Shift K swap previous 44 | 45 | # Super+] and Super+[ to focus the next/previous output 46 | riverctl map normal Super BracketRight focus-output next 47 | riverctl map normal Super BracketLeft focus-output previous 48 | 49 | # Super+Shift+{[,]} to send the focused view to the next/previous output 50 | riverctl map normal Super+Shift BracketRight send-to-output next 51 | riverctl map normal Super+Shift BracketLeftComma send-to-output previous 52 | 53 | # Super+Return to bump the focused view to the top of the layout stack 54 | riverctl map normal Super Return zoom 55 | 56 | # Super+H and Super+L to decrease/increase the main ratio of rivertile(1) 57 | riverctl map normal Super H send-layout-cmd rivertile "main-ratio -0.05" 58 | riverctl map normal Super L send-layout-cmd rivertile "main-ratio +0.05" 59 | 60 | # Super+Shift+H and Super+Shift+L to increment/decrement the main count of rivertile(1) 61 | riverctl map normal Super+Shift H send-layout-cmd rivertile "main-count +1" 62 | riverctl map normal Super+Shift L send-layout-cmd rivertile "main-count -1" 63 | 64 | # Super+Alt+{H,J,K,L} to move views 65 | riverctl map normal Super+Alt H move left 100 66 | riverctl map normal Super+Alt J move down 100 67 | riverctl map normal Super+Alt K move up 100 68 | riverctl map normal Super+Alt L move right 100 69 | 70 | # Super+Alt+Control+{H,J,K,L} to snap views to screen edges 71 | riverctl map normal Super+Alt+Control H snap left 72 | riverctl map normal Super+Alt+Control J snap down 73 | riverctl map normal Super+Alt+Control K snap up 74 | riverctl map normal Super+Alt+Control L snap right 75 | 76 | # Super+Alt+Shift+{H,J,K,L} to resize views 77 | riverctl map normal Super+Alt+Shift H resize horizontal -100 78 | riverctl map normal Super+Alt+Shift J resize vertical 100 79 | riverctl map normal Super+Alt+Shift K resize vertical -100 80 | riverctl map normal Super+Alt+Shift L resize horizontal 100 81 | 82 | # Super + Left Mouse Button to move views 83 | riverctl map-pointer normal Super BTN_LEFT move-view 84 | 85 | # Super + Right Mouse Button to resize views 86 | riverctl map-pointer normal Super BTN_RIGHT resize-view 87 | 88 | for i in $(seq 1 9) 89 | do 90 | tags=$((1 << ($i - 1))) 91 | 92 | # Super+[1-9] to focus tag [0-8] 93 | riverctl map normal Super $i set-focused-tags $tags 94 | 95 | # Super+Shift+[1-9] to tag focused view with tag [0-8] 96 | riverctl map normal Super+Shift $i set-view-tags $tags 97 | 98 | # Super+Ctrl+[1-9] to toggle focus of tag [0-8] 99 | riverctl map normal Super+Control $i toggle-focused-tags $tags 100 | 101 | # Super+Shift+Ctrl+[1-9] to toggle tag [0-8] of focused view 102 | riverctl map normal Super+Shift+Control $i toggle-view-tags $tags 103 | done 104 | 105 | # Super+0 to focus all tags 106 | # Super+Shift+0 to tag focused view with all tags 107 | all_tags=$(((1 << 32) - 1)) 108 | riverctl map normal Super 0 set-focused-tags $all_tags 109 | riverctl map normal Super+Shift 0 set-view-tags $all_tags 110 | 111 | # Super+Space to toggle float 112 | riverctl map normal Super Space toggle-float 113 | 114 | # Super+F to toggle fullscreen 115 | riverctl map normal Super F toggle-fullscreen 116 | 117 | # Super+{Up,Right,Down,Left} to change layout orientation 118 | riverctl map normal Super Up send-layout-cmd rivertile "main-location top" 119 | riverctl map normal Super Right send-layout-cmd rivertile "main-location right" 120 | riverctl map normal Super Down send-layout-cmd rivertile "main-location bottom" 121 | riverctl map normal Super Left send-layout-cmd rivertile "main-location left" 122 | 123 | # Declare a passthrough mode. This mode has only a single mapping to return to 124 | # normal mode. This makes it useful for testing a nested wayland compositor 125 | riverctl declare-mode passthrough 126 | 127 | # Super+F11 to enter passthrough mode 128 | riverctl map normal Super F11 enter-mode passthrough 129 | 130 | # Super+F11 to return to normal mode 131 | riverctl map passthrough Super F11 enter-mode normal 132 | 133 | # Various media key mapping examples for both normal and locked mode which do 134 | # not have a modifier 135 | for mode in normal locked 136 | do 137 | # Eject the optical drive (well if you still have one that is) 138 | riverctl map $mode None XF86Eject spawn 'eject -T' 139 | 140 | # Control pulse audio volume with pamixer (https://github.com/cdemoulins/pamixer) 141 | riverctl map $mode None XF86AudioRaiseVolume spawn 'pamixer -i 3' 142 | riverctl map $mode Super Equal spawn 'pamixer -i 3' 143 | riverctl map $mode None XF86AudioLowerVolume spawn 'pamixer -d 3' 144 | riverctl map $mode Super Minus spawn 'pamixer -d 3' 145 | riverctl map $mode None XF86AudioMute spawn 'pamixer --toggle-mute' 146 | riverctl map $mode Super Delete spawn 'pamixer --toggle-mute' 147 | 148 | # Control MPRIS aware media players with playerctl (https://github.com/altdesktop/playerctl) 149 | riverctl map $mode None XF86AudioMedia spawn 'playerctl play-pause' 150 | riverctl map $mode None XF86AudioPlay spawn 'playerctl play-pause' 151 | riverctl map $mode None XF86AudioPrev spawn 'playerctl previous' 152 | riverctl map $mode None XF86AudioNext spawn 'playerctl next' 153 | 154 | # Control screen backlight brightness with light (https://github.com/haikarainen/light) 155 | riverctl map $mode None XF86MonBrightnessUp spawn 'light -A 5' 156 | riverctl map $mode None XF86MonBrightnessDown spawn 'light -U 5' 157 | done 158 | 159 | # Set background and border color 160 | riverctl background-color 0x002b36 161 | riverctl border-color-focused 0x93a1a1 162 | riverctl border-color-unfocused 0x586e75 163 | 164 | # Set keyboard repeat rate 165 | riverctl set-repeat 50 300 166 | 167 | # Make certain views start floating 168 | riverctl float-filter-add app-id float 169 | riverctl float-filter-add title "popup title with spaces" 170 | 171 | # Set app-ids and titles of views which should use client side decorations 172 | riverctl csd-filter-add app-id "gedit" 173 | 174 | # Set the default layout generator to be rivertile and start it. 175 | # River will send the process group of the init executable SIGTERM on exit. 176 | riverctl default-layout rivertile 177 | rivertile -view-padding 6 -outer-padding 6 178 | -------------------------------------------------------------------------------- /homes/etc/starship/starship.toml: -------------------------------------------------------------------------------- 1 | "$schema" = 'https://starship.rs/config-schema.json' 2 | 3 | add_newline = true 4 | 5 | format = """ 6 | $hostname\ 7 | $directory\ 8 | $git_branch\ 9 | $git_state\ 10 | $git_status\ 11 | $line_break\ 12 | $time\ 13 | $status\ 14 | $cmd_duration\ 15 | $username\ 16 | $jobs\ 17 | [\\$](green) \ 18 | """ 19 | 20 | [character] 21 | disabled = true 22 | 23 | [package] 24 | disabled = true 25 | 26 | [cmd_duration] 27 | min_time = 20_000 28 | format = '[in $duration]($style) ' 29 | 30 | [directory] 31 | truncation_length = 0 32 | truncate_to_repo = false 33 | read_only = 'RO' 34 | 35 | [direnv] 36 | disabled = true 37 | 38 | [git_branch] 39 | format = '[$symbol$branch(:$remote_branch)]($style) ' 40 | symbol = '' 41 | truncation_length = 32 42 | 43 | [git_commit] 44 | disabled = true 45 | 46 | [git_state] 47 | disabled = false 48 | 49 | [git_metrics] 50 | disabled = true 51 | 52 | [git_status] 53 | disabled = false 54 | 55 | [hostname] 56 | disabled = false 57 | ssh_only = false 58 | format = '[$hostname]($style):' 59 | 60 | [username] 61 | disabled = false 62 | show_always = false 63 | format = 'as [$user]($style) ' 64 | 65 | [status] 66 | disabled = false 67 | format = '[$status$symbol](bold red) ' 68 | symbol = '✘' 69 | success_symbol = '' 70 | 71 | [time] 72 | disabled = false 73 | format = '[$time]($style) ' 74 | time_format = '%R' 75 | -------------------------------------------------------------------------------- /homes/extra.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | home.packages = [ 4 | # networking 5 | pkgs.dig 6 | pkgs.nmap 7 | pkgs.tcpdump 8 | pkgs.nssTools 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /homes/graphical.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: 7 | let 8 | enableFoot = config.programs.foot.enable; 9 | enableWayland = true; 10 | 11 | defaultBrowser = 12 | if config.programs.librewolf.enable then 13 | "librewolf.desktop" 14 | else if config.programs.firefox.enable then 15 | "firefox.desktop" 16 | else 17 | null; 18 | 19 | defaultApplications = { 20 | "image/svg+xml" = [ 21 | defaultBrowser 22 | ]; 23 | }; 24 | in 25 | { 26 | programs = { 27 | # alacritty.enable = enableGraphical; 28 | mpv.enable = true; 29 | foot.enable = enableWayland; 30 | foot.server.enable = enableFoot; 31 | # TODO: Add font package 32 | foot.settings.main.font = "JetBrainsMono NF:size=10.5"; 33 | 34 | # See modules/librewolf.nix for details 35 | librewolf.enable = true; 36 | # firefox.enable = true; 37 | 38 | # AI coding (Cline) 39 | # vscode.enable = true; 40 | 41 | # enable auto-notify plugin only in graphical environments 42 | zsh = { 43 | plugins = [ 44 | { 45 | name = "auto-notify"; 46 | src = pkgs.customZshPlugins.zsh-auto-notify; 47 | } 48 | ]; 49 | sessionVariables = { 50 | # https://github.com/MichaelAquilina/zsh-auto-notify 51 | "AUTO_NOTIFY_THRESHOLD" = "60"; 52 | }; 53 | initContent = '' 54 | export AUTO_NOTIFY_IGNORE=("nix shell" "nix develop" "ssh" "agenix edit" "man" "less") 55 | ''; 56 | }; 57 | }; 58 | 59 | home.packages = 60 | (with pkgs; [ 61 | blanket 62 | pavucontrol 63 | 64 | # required by zsh-auto-notify plugin 65 | libnotify 66 | 67 | # API development 68 | # hoppscotch 69 | 70 | # database admin 71 | # beekeeper-studio 72 | 73 | # fonts 74 | customFontPackages.jetbrains-mono-nerdfont 75 | # Japanese 76 | ipafont 77 | ]) 78 | ++ lib.optionals enableWayland [ 79 | pkgs.wayshot 80 | pkgs.wf-recorder 81 | pkgs.slurp # Used with wayshot 82 | pkgs.wl-clipboard 83 | 84 | (pkgs.writeShellApplication { 85 | name = "lock-screen"; 86 | runtimeInputs = [ pkgs.swaylock-effects ]; 87 | # TODO: Use a color scheme 88 | text = '' 89 | swaylock -f --clock --fade-in 0.5 90 | ''; 91 | }) 92 | ]; 93 | 94 | xdg.mime.enable = true; 95 | xdg.mimeApps = lib.mkIf (defaultBrowser != null) { 96 | enable = true; 97 | inherit defaultBrowser; 98 | inherit defaultApplications; 99 | associations.added = defaultApplications; 100 | }; 101 | 102 | systemd.user.services.emacs = { 103 | Service = { 104 | Environment = lib.optionals enableWayland [ 105 | "MOZ_ENABLE_WAYLAND=1" 106 | "WAYLAND_DISPLAY=wayland-1" 107 | ]; 108 | }; 109 | }; 110 | 111 | systemd.user.services.foot = lib.mkIf config.programs.foot.server.enable { 112 | Service = { 113 | Environment = lib.mkForce [ 114 | "WAYLAND_DISPLAY=wayland-1" 115 | "PATH=${ 116 | lib.concatMapStrings (dir: dir + ":") config.home.sessionPath 117 | }${config.home.profileDirectory}/bin" 118 | ]; 119 | }; 120 | }; 121 | } 122 | -------------------------------------------------------------------------------- /homes/lib/waybar-config.nix: -------------------------------------------------------------------------------- 1 | let 2 | inherit (builtins) toJSON isFunction; 3 | 4 | defaultModulesRight = [ 5 | "idle_inhibitor" 6 | "pulseaudio" 7 | "network" 8 | "cpu" 9 | "memory" 10 | "temperature" 11 | "backlight" 12 | "keyboard-state" 13 | # "custom/nixos" 14 | "clock" 15 | "tray" 16 | ]; 17 | in 18 | { 19 | writeText, 20 | modulesCenter ? ["hyprland/window"], 21 | modulesLeft ? ["wlr/workspaces"], 22 | modulesRight ? defaultModulesRight, 23 | }: 24 | # Based on https://github.com/Alexays/Waybar/blob/master/resources/config 25 | writeText "config" '' 26 | { 27 | "height": 30, 28 | "spacing": 4, 29 | "modules-left": ${toJSON modulesLeft}, 30 | "modules-center": ${toJSON modulesCenter}, 31 | "modules-right": ${toJSON ( 32 | if isFunction modulesRight 33 | then modulesRight defaultModulesRight 34 | else modulesRight 35 | )}, 36 | "keyboard-state": { 37 | "numlock": true, 38 | "capslock": true, 39 | "format": "{name} {icon}", 40 | "format-icons": { 41 | "locked": "", 42 | "unlocked": "" 43 | } 44 | }, 45 | "sway/mode": { 46 | "format": "{}" 47 | }, 48 | "sway/scratchpad": { 49 | "format": "{icon} {count}", 50 | "show-empty": false, 51 | "format-icons": ["", ""], 52 | "tooltip": true, 53 | "tooltip-format": "{app}: {title}" 54 | }, 55 | "wlr/workspaces": { 56 | "format": "{icon}", 57 | }, 58 | "hyprland/window": { 59 | "format": "{}", 60 | "separate-outputs": true 61 | }, 62 | "hyprland/submap": { 63 | "format": "✌️ {}", 64 | "max-length": 8, 65 | "tooltip": false 66 | }, 67 | "idle_inhibitor": { 68 | "format": "{icon}", 69 | "format-icons": { 70 | "activated": "", 71 | "deactivated": "" 72 | } 73 | }, 74 | "tray": { 75 | "spacing": 10 76 | }, 77 | "clock": { 78 | "format-alt": "{:%Y-%m-%d}", 79 | "tooltip-format": "{:%Y %B}\n{calendar}" 80 | }, 81 | "cpu": { 82 | "format": "{usage}% ", 83 | "tooltip": false 84 | }, 85 | "memory": { 86 | "format": "{}% " 87 | }, 88 | "temperature": { 89 | "critical-threshold": 80, 90 | "format": "{temperatureC}°C {icon}", 91 | "format-icons": ["", "", ""] 92 | }, 93 | "backlight": { 94 | "format": "{percent}% {icon}", 95 | "format-icons": ["", "", "", "", "", "", "", "", ""] 96 | }, 97 | "battery": { 98 | "states": { 99 | "warning": 30, 100 | "critical": 15 101 | }, 102 | "format": "{capacity}% {icon}", 103 | "format-charging": "{capacity}% ", 104 | "format-plugged": "{capacity}% ", 105 | "format-alt": "{time} {icon}", 106 | "format-icons": ["", "", "", "", ""] 107 | }, 108 | "battery#bat2": { 109 | "bat": "BAT2" 110 | }, 111 | "network": { 112 | "format-wifi": "{essid} ({signalStrength}%) ", 113 | "format-ethernet": "{ipaddr}/{cidr} ", 114 | "tooltip-format": "{ifname} via {gwaddr} ", 115 | "format-linked": "{ifname} (No IP) ", 116 | "format-disconnected": "Disconnected ⚠", 117 | "format-alt": "{ifname}: {ipaddr}/{cidr}" 118 | }, 119 | "pulseaudio": { 120 | "format": "{volume}% {icon} {format_source}", 121 | "format-bluetooth": "{volume}% {icon} {format_source}", 122 | "format-bluetooth-muted": " {icon} {format_source}", 123 | "format-muted": " {format_source}", 124 | "format-source": "{volume}% ", 125 | "format-source-muted": "", 126 | "format-icons": { 127 | "headphone": "", 128 | "hands-free": "", 129 | "headset": "", 130 | "phone": "", 131 | "portable": "", 132 | "car": "", 133 | "default": ["", "", ""] 134 | }, 135 | "on-click": "pavucontrol" 136 | }, 137 | "custom/nixos": { 138 | "interval": 60, 139 | "exec": "nixos-version --configuration-revision" 140 | } 141 | } 142 | '' 143 | -------------------------------------------------------------------------------- /homes/modules.nix: -------------------------------------------------------------------------------- 1 | { lib }: 2 | let 3 | dir = ./modules; 4 | 5 | isModule = 6 | name: type: ((type == "regular") && (lib.hasSuffix ".nix" name)) || (type == "directory"); 7 | in 8 | lib.pipe (builtins.readDir dir) [ 9 | (lib.filterAttrs isModule) 10 | builtins.attrNames 11 | (builtins.map (filename: dir + "/${filename}")) 12 | ] 13 | -------------------------------------------------------------------------------- /homes/modules/aider/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./interface.nix 4 | ]; 5 | } 6 | -------------------------------------------------------------------------------- /homes/modules/aider/interface.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: 7 | let 8 | cfg = config.programs.aider; 9 | 10 | inherit (lib) mkOption mkEnableOption types; 11 | 12 | wrapped = cfg.package.overrideAttrs (old: { 13 | nativeBuildInputs = (old.nativeBuildInputs or [ ]) ++ [ 14 | pkgs.makeWrapper 15 | ]; 16 | propagatedBuildInputs = (old.propagatedBuildInputs or [ ]) ++ [ 17 | cfg.age.package 18 | ]; 19 | # Store one or more multiple --api-key options in an age-encrypted 20 | # file and decrypt the content when the program starts. 21 | postInstall = '' 22 | wrapProgram $out/bin/aider \ 23 | --inherit-argv0 \ 24 | --run 'export $(${lib.getExe cfg.age.package} \ 25 | -i ${cfg.age.identityFile} \ 26 | --decrypt ${cfg.age.envFile})' 27 | ''; 28 | }); 29 | in 30 | { 31 | options = { 32 | programs.aider = { 33 | enable = mkEnableOption (lib.mdDoc "Whether to install a custom wrapped version of aider-chat"); 34 | 35 | package = mkOption { 36 | type = types.package; 37 | description = lib.mdDoc "aider-chat package"; 38 | default = pkgs.aider-chat; 39 | }; 40 | 41 | age = { 42 | package = mkOption { 43 | type = types.package; 44 | description = lib.mdDoc "age package"; 45 | default = pkgs.age; 46 | }; 47 | 48 | envFile = mkOption { 49 | type = types.path; 50 | description = lib.mdDoc "Path to an age-encrypted secret"; 51 | }; 52 | 53 | identityFile = mkOption { 54 | type = types.path; 55 | description = lib.mdDoc "Path to an identity file"; 56 | }; 57 | }; 58 | }; 59 | }; 60 | 61 | config = { 62 | home.packages = lib.optionals cfg.enable [ 63 | wrapped 64 | ]; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /homes/modules/browser.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: let 6 | cfg = config.xdg.mimeApps.defaultBrowser; 7 | inherit (lib) types; 8 | in { 9 | options = { 10 | xdg.mimeApps.defaultBrowser = lib.mkOption { 11 | type = types.nullOr types.str; 12 | description = lib.mdDoc '' 13 | Desktop file for the browser. It should support both `text/html` and 14 | `x-scheme-handler/https`. 15 | ''; 16 | default = null; 17 | }; 18 | }; 19 | 20 | config = { 21 | xdg.mimeApps.defaultApplications = lib.mkIf (cfg != null) { 22 | "text/html" = cfg; 23 | "x-scheme-handler/http" = cfg; 24 | "x-scheme-handler/https" = cfg; 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /homes/modules/crostini.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: let 6 | inherit (lib) mkIf mkOption types; 7 | 8 | cfg = config.targets.crostini; 9 | in { 10 | options = { 11 | targets.crostini = { 12 | enable = mkOption { 13 | type = types.bool; 14 | default = false; 15 | description = '' 16 | Whether to enable settings that make Home Manager work better on 17 | Crostini (Linux container) on Chrome OS. 18 | ''; 19 | }; 20 | }; 21 | }; 22 | 23 | config = mkIf cfg.enable { 24 | targets.genericLinux.enable = true; 25 | 26 | xdg.configFile."systemd/user/cros-garcon.service.d/override.conf".text = '' 27 | [Service] 28 | Environment="PATH=${builtins.concatStringsSep ":" 29 | [ 30 | "%h/.nix-profile/bin" 31 | "/usr/local/sbin" 32 | "/usr/local/bin" 33 | "/usr/local/games" 34 | "/usr/sbin" 35 | "/usr/bin" 36 | "/usr/games" 37 | "/sbin" 38 | "/bin" 39 | ]}" "XDG_DATA_DIRS=${builtins.concatStringsSep ":" 40 | [ 41 | "%h/.nix-profile/share" 42 | "%h/.local/share" 43 | "/usr/local/share" 44 | "/usr/share" 45 | ]}" 46 | ''; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /homes/modules/direnv.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | config, 4 | ... 5 | }: let 6 | cfg = config.programs.direnv; 7 | in { 8 | programs.direnv = lib.mkIf cfg.enable ( 9 | { 10 | enableZshIntegration = config.programs.zsh.enable; 11 | } 12 | // ( 13 | if (builtins.compareVersions config.home.stateVersion "22.11" > 0) 14 | then { 15 | enableNushellIntegration = 16 | config.programs.nushell.enable; 17 | } 18 | else {} 19 | ) 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /homes/modules/dunst.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: let 6 | cfg = config.services.dunst; 7 | in { 8 | config = lib.mkIf cfg.enable { 9 | services.dunst = { 10 | waylandDisplay = "wayland-1"; 11 | settings = { 12 | global = { 13 | # monitor = 0; 14 | width = 300; 15 | height = 300; 16 | origin = "top-right"; 17 | offset = "50x65"; 18 | 19 | padding = 16; 20 | horizontal_padding = 16; 21 | 22 | transparency = 10; 23 | 24 | font = "JetBrainsMono Nerd Font 10"; 25 | line_height = 4; 26 | format = ''%s\n%b''; 27 | }; 28 | }; 29 | }; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /homes/modules/fzy.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | home.packages = [ 3 | (pkgs.writeShellApplication { 4 | name = "fzy-zfs-mount"; 5 | runtimeInputs = [ 6 | pkgs.fzy 7 | ]; 8 | text = '' 9 | if fs=$(zfs list -Hp | cut -d $'\t' -f1 | fzy) 10 | then 11 | zfs mount "$fs" 12 | findmnt "$fs" 13 | fi 14 | ''; 15 | }) 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /homes/modules/git.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | ... 6 | }: 7 | let 8 | inherit (lib) mkOption types; 9 | 10 | cfg = config.programs.git; 11 | 12 | makeGitConfig = 13 | { 14 | userName, 15 | userEmail, 16 | githubUser, 17 | signingKey, 18 | }: 19 | pkgs.writeText "config" ( 20 | '' 21 | [user] 22 | name = "${userName}" 23 | email = "${userEmail}" 24 | ${lib.optionalString (signingKey != null) '' 25 | signingKey = "${signingKey}" 26 | ''} 27 | '' 28 | + lib.optionalString (githubUser != null) '' 29 | [github] 30 | user = "${githubUser}" 31 | '' 32 | ); 33 | 34 | defaultIdentity = { 35 | email = "akira.komamura@gmail.com"; 36 | fullName = "Akira Komamura"; 37 | githubUser = "akirak"; 38 | signingKey = "5B3390B01C01D3E"; 39 | conditions = [ 40 | "hasconfig:remote.*.url:git@github.com:akirak/**" 41 | "hasconfig:remote.*.url:git@github.com:emacs-twist/**" 42 | "hasconfig:remote.*.url:git@git.sr.ht:~akirak/**" 43 | "hasconfig:remote.*.url:https://github.com/akirak/**" 44 | "hasconfig:remote.*.url:https://github.com/emacs-twist/**" 45 | "hasconfig:remote.*.url:https://git.sr.ht/~akirak/**" 46 | "gitdir:~/work2/foss/" 47 | "gitdir:~/work2/learning/" 48 | "gitdir:~/work2/personal/" 49 | "gitdir:~/work2/prototypes/" 50 | "gitdir:/assets/" 51 | "gitdir:/git-annex/" 52 | ]; 53 | }; 54 | 55 | identityType = types.submodule { 56 | options = { 57 | email = mkOption { 58 | type = types.str; 59 | description = lib.mdDoc "E-mail address of the user"; 60 | }; 61 | fullName = mkOption { 62 | type = types.str; 63 | description = lib.mdDoc "Full name of the user"; 64 | }; 65 | githubUser = mkOption { 66 | type = types.nullOr types.str; 67 | description = lib.mdDoc "GitHub login of the user"; 68 | default = null; 69 | }; 70 | signingKey = mkOption { 71 | type = types.nullOr types.str; 72 | description = lib.mdDoc "GPG signing key"; 73 | default = null; 74 | }; 75 | conditions = mkOption { 76 | type = types.listOf types.str; 77 | description = lib.mdDoc "List of include conditions"; 78 | }; 79 | }; 80 | }; 81 | in 82 | { 83 | options.programs.git = { 84 | defaultIdentity = mkOption { 85 | type = types.nullOr identityType; 86 | description = lib.mdDoc "Default identity"; 87 | default = defaultIdentity; 88 | }; 89 | 90 | extraIdentities = mkOption { 91 | type = types.listOf identityType; 92 | description = lib.mdDoc "Extra list of identities"; 93 | default = [ ]; 94 | }; 95 | }; 96 | 97 | config = { 98 | programs.git = lib.mkIf cfg.enable { 99 | signing.format = lib.mkForce "openpgp"; 100 | 101 | extraConfig = { 102 | pull.rebase = true; 103 | 104 | merge.conflictstyle = "diff3"; 105 | 106 | "url \"git@github.com:\"".pushInsteadOf = "https://github.com/"; 107 | "url \"git@git.sr.ht:\"".pushInsteadOf = "https://git.sr.ht/"; 108 | 109 | core.autocrlf = "input"; 110 | 111 | # Only on WSL 112 | # core.fileMode = false; 113 | 114 | # Increase the size of post buffers to prevent hung ups of git-push. 115 | # https://stackoverflow.com/questions/6842687/the-remote-end-hung-up-unexpectedly-while-git-cloning#6849424 116 | http.postBuffer = "524288000"; 117 | }; 118 | 119 | ignores = [ 120 | ".direnv" 121 | "result" 122 | "result-*" 123 | "#*" 124 | ".git-bak*" 125 | ".aider*" 126 | # Non-standard 127 | "!.aider.conf.yml" 128 | "!.aiderignore" 129 | ]; 130 | 131 | includes = lib.pipe ([ cfg.defaultIdentity ] ++ cfg.extraIdentities) [ 132 | (builtins.filter (v: v != null)) 133 | (builtins.map ( 134 | { 135 | email, 136 | fullName, 137 | githubUser, 138 | signingKey, 139 | conditions, 140 | }: 141 | let 142 | configFile = makeGitConfig { 143 | inherit githubUser signingKey; 144 | userName = fullName; 145 | userEmail = email; 146 | }; 147 | in 148 | builtins.map (condition: { 149 | path = configFile; 150 | inherit condition; 151 | }) conditions 152 | )) 153 | lib.flatten 154 | ]; 155 | }; 156 | }; 157 | } 158 | -------------------------------------------------------------------------------- /homes/modules/gpg.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.programs.gpg; 8 | in { 9 | services.gpg-agent = lib.mkIf cfg.enable { 10 | enable = true; 11 | enableSshSupport = true; 12 | defaultCacheTtl = 60; 13 | defaultCacheTtlSsh = 60; 14 | # Explicitly set the pinentry package when using a non-standard window 15 | # manager setting 16 | # https://discourse.nixos.org/t/help-with-pinentrypackage/41393/8 17 | pinentry.package = lib.mkForce pkgs.pinentry-gtk2; 18 | extraConfig = '' 19 | allow-emacs-pinentry 20 | allow-loopback-pinentry 21 | ''; 22 | # pinentryFlavor = "gtk2"; 23 | sshKeys = [ 24 | "5B3390B01C01D3EE" 25 | ]; 26 | }; 27 | 28 | programs.bash.initExtra = lib.mkIf cfg.enable '' 29 | gpg-connect-agent /bye 30 | export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) 31 | ''; 32 | } 33 | -------------------------------------------------------------------------------- /homes/modules/hyprland.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | ... 6 | }: 7 | let 8 | cfg = config.wayland.windowManager.hyprland or { enable = false; }; 9 | 10 | footEnabled = config.programs.foot.enable; 11 | 12 | systemdTarget = "hyprland-session.target"; 13 | 14 | systemdStartAfterThis = { 15 | Unit = { 16 | After = [ systemdTarget ]; 17 | }; 18 | Install = { 19 | WantedBy = [ systemdTarget ]; 20 | }; 21 | }; 22 | 23 | runInTerminal = pkgs.writeShellScript "run-in-term" '' 24 | windowclass=$(basename "$1") 25 | 26 | options=() 27 | case "$windowclass" in 28 | hyprprop) 29 | options+=(--hold) 30 | ;; 31 | esac 32 | 33 | footclient -a "$windowclass" ''${options[@]} "$@" 34 | ''; 35 | in 36 | { 37 | config = lib.mkIf cfg.enable { 38 | home.packages = with pkgs; [ 39 | fuzzel 40 | dunst 41 | channels.hyprland-contrib.shellevents 42 | channels.hyprland-contrib.hyprprop 43 | ]; 44 | 45 | programs.waybar = { 46 | enable = true; 47 | systemd.enable = true; 48 | systemd.target = systemdTarget; 49 | }; 50 | 51 | xdg.configFile."waybar/config".source = pkgs.callPackage ../lib/waybar-config.nix { 52 | modulesCenter = [ "hyprland/window" ]; 53 | modulesRight = ms: ms ++ [ "hyprland/submap" ]; 54 | }; 55 | 56 | programs.foot.server.enable = lib.mkIf footEnabled true; 57 | systemd.user.services.foot = lib.mkIf footEnabled systemdStartAfterThis; 58 | 59 | services.dunst = { 60 | enable = true; 61 | waylandDisplay = "wayland-1"; 62 | }; 63 | systemd.user.services.dunst = lib.mkIf config.services.dunst.enable systemdStartAfterThis; 64 | 65 | services.kanshi = { 66 | enable = true; 67 | systemdTarget = lib.mkForce systemdTarget; 68 | }; 69 | 70 | wayland.windowManager.hyprland = { 71 | systemd.enable = true; 72 | xwayland.enable = true; 73 | 74 | settings = { 75 | "$mod" = "SUPER"; 76 | 77 | input = { 78 | kb_layout = "us"; 79 | kb_options = "ctrl:nocaps"; 80 | }; 81 | 82 | general = { 83 | border_size = 5; 84 | # TODO: Use a proper color scheme 85 | "col.active_border" = "rgba(ffaaff88)"; 86 | "col.inactive_border" = "rgba(00000088)"; 87 | gaps_in = 2; 88 | gaps_out = 5; 89 | }; 90 | 91 | bindm = [ 92 | "$mod ,mouse:272,movewindow" 93 | "$mod ,mouse:273,resizewindow" 94 | ]; 95 | 96 | bind = [ 97 | # Hyprland admin 98 | "$mod SHIFT , Q, exec, pkill Hyprland" 99 | 100 | # Launcher 101 | "$mod SHIFT , Return, exec, footclient" 102 | "$mod , Space, exec, fuzzel -T ${runInTerminal}" 103 | "$mod , E, exec, emacsclient -c -a emacs" 104 | "$mod SHIFT , S, exec, flameshot gui" 105 | "$mod , F9, exec, foot --title \"Rebuilding NixOS...\" nixos-rebuild-and-notify" 106 | 107 | # Window management 108 | "$mod , C , killactive" 109 | "$mod , T, togglefloating" 110 | "$mod , F, fullscreen" 111 | "$mod , ', pin" 112 | 113 | # Monitor 114 | "$mod , bracketleft, focusmonitor, -1" 115 | "$mod , bracketright, focusmonitor, 1" 116 | "$mod SHIFT , bracketleft, movewindow, mon:-1" 117 | "$mod SHIFT , bracketright, movewindow, mon:1" 118 | "$mod , Backspace, swapactiveworkspaces, current +1" 119 | 120 | # Master layout 121 | "$mod , Return, layoutmsg, swapwithmaster auto" 122 | "$mod , M, layoutmsg, focusmaster auto" 123 | "$mod , minus, splitratio, -0.15" 124 | "$mod , equal, splitratio, 0.15" 125 | 126 | # Move focus 127 | "$mod , h, movefocus, l" 128 | "$mod , j, movefocus, d" 129 | "$mod , k, movefocus, u" 130 | "$mod , l, movefocus, r" 131 | "$mod SHIFT , h, swapwindow, l" 132 | "$mod SHIFT , j, swapwindow, d" 133 | "$mod SHIFT , k, swapwindow, u" 134 | "$mod SHIFT , l, swapwindow, r" 135 | "$mod , period, focusurgentorlast" 136 | "$mod , comma, togglespecialworkspace" 137 | "$mod , s, movetoworkspace, special" 138 | 139 | # Workspace management 140 | "$mod , f5, exec, hyprctl keyword general:layout dwindle" 141 | "$mod , f6, exec, hyprctl keyword general:layout master" 142 | 143 | "$mod , 1, workspace, 1" 144 | "$mod SHIFT , 1, movetoworkspace, 1" 145 | "$mod , 2, workspace, 2" 146 | "$mod SHIFT , 2, movetoworkspace, 2" 147 | "$mod , 3, workspace, 3" 148 | "$mod SHIFT , 3, movetoworkspace, 3" 149 | "$mod , 4, workspace, 4" 150 | "$mod SHIFT , 4, movetoworkspace, 4" 151 | "$mod , 5, workspace, 5" 152 | "$mod SHIFT , 5, movetoworkspace, 5" 153 | ]; 154 | 155 | windowrulev2 = 156 | let 157 | defaultDialogSize = "780 600"; 158 | 159 | exactClass = className: "class:^(${className})$"; 160 | 161 | exactTitle = className: "title:^(${className})$"; 162 | 163 | andRules = builtins.concatStringsSep ","; 164 | 165 | generateRules = 166 | rules: windows: 167 | lib.flatten (builtins.map (window: (builtins.map (rule: "${rule},${window}") rules)) windows); 168 | in 169 | # FIXME: This doesn't work now. 170 | [ "workspace special,class:^(foot)$,title:^(Rebuilding)" ] 171 | ++ (generateRules 172 | [ 173 | "float" 174 | "size 80% 80%" 175 | "center" 176 | ] 177 | [ (exactClass "btop") ] 178 | ) 179 | ++ (generateRules 180 | [ 181 | "float" 182 | "size 25% 25%" 183 | "move 74% 74%" 184 | ] 185 | [ 186 | # This title is for Firefox which I use daily. 187 | (exactTitle "Picture-in-Picture") 188 | ] 189 | ) 190 | ++ (generateRules 191 | [ 192 | "float" 193 | "size ${defaultDialogSize}" 194 | "center" 195 | ] 196 | [ 197 | (andRules [ 198 | (exactClass "chromium") 199 | (exactTitle "Open Files") 200 | ]) 201 | (exactTitle "Volume Control") # pavucontrol 202 | (exactClass "com.rafaelmardojai.Blanket") 203 | (exactTitle "Android Studio Setup Wizard") 204 | ] 205 | ) 206 | ++ (generateRules 207 | [ 208 | "float" 209 | "center" 210 | ] 211 | [ 212 | (exactClass "mpv") 213 | (exactClass "VirtualBox Manager") 214 | ] 215 | ); 216 | }; 217 | }; 218 | }; 219 | } 220 | -------------------------------------------------------------------------------- /homes/modules/librewolf.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: 6 | let 7 | cfg = config.programs.librewolf; 8 | in 9 | { 10 | # Basically just stolen from https://nixos.wiki/wiki/Librewolf 11 | programs.librewolf = lib.mkIf cfg.enable { 12 | # Enable WebGL, cookies and history 13 | settings = { 14 | "webgl.disabled" = false; 15 | "privacy.resistFingerprinting" = false; 16 | "privacy.clearOnShutdown.history" = false; 17 | "privacy.clearOnShutdown.cookies" = false; 18 | "network.cookie.lifetimePolicy" = 0; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /homes/modules/password-store.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | ... 6 | }: 7 | let 8 | cfg = config.programs.password-store; 9 | 10 | agePackage = pkgs.rage; 11 | 12 | passageRoot = "${config.home.homeDirectory}/secrets"; 13 | 14 | # A wrapper for the steps described in https://github.com/FiloSottile/passage 15 | # for multiple YubiKey support 16 | passage-yubikey-update = pkgs.writeShellApplication { 17 | name = "passage-yubikey-update"; 18 | runtimeInputs = [ 19 | pkgs.age-plugin-yubikey 20 | ]; 21 | text = '' 22 | if ! [[ -d "${cfg.settings.PASSAGE_DIR}" ]]; then 23 | echo >&2 "Error: ${cfg.settings.PASSAGE_DIR} must be created manually." 24 | exit 1 25 | fi 26 | 27 | identitiesFile="${cfg.settings.PASSAGE_IDENTITIES_FILE}" 28 | recipientsFile="${cfg.settings.PASSAGE_RECIPIENTS_FILE}" 29 | 30 | mkdir -p "$(dirname "$identitiesFile")" 31 | mkdir -p "$(dirname "$recipientsFile")" 32 | 33 | age-plugin-yubikey --identity >> "$identitiesFile" 34 | echo >&2 "Updated $identitiesFile" 35 | 36 | age-plugin-yubikey --list >> "$recipientsFile" 37 | echo >&2 "Updated $recipientsFile" 38 | ''; 39 | }; 40 | in 41 | { 42 | programs.password-store = { 43 | package = pkgs.passage; 44 | settings = { 45 | PASSAGE_DIR = "${passageRoot}/store"; 46 | PASSAGE_AGE = lib.getExe agePackage; 47 | PASSAGE_IDENTITIES_FILE = "${passageRoot}/identities"; 48 | PASSAGE_RECIPIENTS_FILE = "${passageRoot}/store/.age-recipients"; 49 | }; 50 | }; 51 | 52 | home.packages = [ 53 | passage-yubikey-update 54 | ]; 55 | } 56 | -------------------------------------------------------------------------------- /homes/modules/psd.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | lib, 4 | config, 5 | ... 6 | }: let 7 | inherit (builtins) concatStringsSep; 8 | # Enable only for selected browsers. 9 | browsers = 10 | (lib.optional config.programs.firefox.enable "firefox") 11 | ++ (lib.optional config.programs.chromium.enable "chromium"); 12 | in { 13 | xdg.configFile."psd/psd.conf".text = '' 14 | USE_OVERLAYFS="${ 15 | if pkgs.stdenv.targetPlatform.isLinux 16 | then "yes" 17 | else "no" 18 | }" 19 | 20 | BROWSERS=(${concatStringsSep " " browsers}) 21 | 22 | BACKUP_LIMIT=3 23 | ''; 24 | } 25 | -------------------------------------------------------------------------------- /homes/modules/rebuild-home.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | inherit (lib) types; 8 | 9 | cfg = config.programs.rebuild-home; 10 | 11 | notify = "${pkgs.notify-desktop}/bin/notify-desktop -r home-manager"; 12 | in { 13 | options = { 14 | programs.rebuild-home = { 15 | enable = lib.mkOption { 16 | type = types.bool; 17 | description = "Install rebuild-home script"; 18 | default = config.targets.genericLinux.enable || pkgs.stdenv.isDarwin; 19 | }; 20 | 21 | name = lib.mkOption { 22 | type = types.str; 23 | description = "Name of the home-manager configuration"; 24 | }; 25 | 26 | configDirectory = lib.mkOption { 27 | type = types.str; 28 | description = "Directory containing the home-manager configuration"; 29 | default = "$HOME/build/nix-config"; 30 | }; 31 | 32 | emacsConfigDirectory = lib.mkOption { 33 | type = types.str; 34 | description = "Directory containing the Emacs configuration"; 35 | default = "$HOME/build/emacs-config"; 36 | }; 37 | }; 38 | }; 39 | 40 | config = lib.mkIf cfg.enable { 41 | home.packages = [ 42 | (pkgs.writeShellScriptBin "rebuild-home" '' 43 | emacs_config="${cfg.emacsConfigDirectory}" 44 | if [[ -d "''${emacs_config}" ]] 45 | then 46 | flags=(--override-input emacs-config $(readlink -f "''${emacs_config}") 47 | --override-input emacs-config/flake-pins github:akirak/flake-pins) 48 | else 49 | flags=() 50 | fi 51 | 52 | cd "${cfg.configDirectory}" 53 | if ${pkgs.nix-output-monitor}/bin/nom build "#homeConfigurations.${cfg.name}" \ 54 | --option accept-flake-config true \ 55 | --print-build-logs \ 56 | ''${flags[@]} \ 57 | && result/activate; then 58 | ${notify} -t 5000 'Successfully switched to a new home-manager generation' 59 | else 60 | ${notify} -t 5000 'Failed to switch to a new home-manager generation' 61 | read 62 | fi 63 | '') 64 | ]; 65 | }; 66 | } 67 | -------------------------------------------------------------------------------- /homes/modules/rebuild-nixos.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: 7 | let 8 | inherit (lib) types; 9 | 10 | cfg = config.programs.nixos-rebuild-and-notify; 11 | 12 | notify = "${pkgs.notify-desktop}/bin/notify-desktop -r nixos-rebuild"; 13 | in 14 | { 15 | options = { 16 | programs.nixos-rebuild-and-notify = { 17 | enable = lib.mkEnableOption (lib.mdDoc "Install nixos-rebuild-and-notify script"); 18 | 19 | directory = lib.mkOption { 20 | type = types.str; 21 | description = "Directory containing the NixOS configuration"; 22 | default = "$HOME/build/nix-config"; 23 | }; 24 | 25 | emacsConfigDirectory = lib.mkOption { 26 | type = types.str; 27 | description = "Directory containing the Emacs configuration"; 28 | default = "$HOME/build/emacs-config"; 29 | }; 30 | }; 31 | }; 32 | 33 | config = lib.mkIf cfg.enable { 34 | home.packages = [ 35 | (pkgs.writeShellScriptBin "nixos-rebuild-and-notify" '' 36 | operation="''${1:-switch}" 37 | 38 | if emacs_config="$(readlink -e "${cfg.emacsConfigDirectory}")" 39 | then 40 | build_flags=(--override-input emacs-config "''${emacs_config}") 41 | else 42 | build_flags=() 43 | fi 44 | 45 | hostname="$(uname -n)" 46 | 47 | function build_and_switch() { 48 | local artifact 49 | cd "${cfg.directory}" 50 | 51 | nix flake update emacs-config 52 | 53 | artifact=$(${pkgs.nix-output-monitor}/bin/nom build \ 54 | ".#nixosConfigurations.$hostname.config.system.build.toplevel" \ 55 | --option accept-flake-config true \ 56 | --no-write-lock-file \ 57 | --print-out-paths \ 58 | --no-link \ 59 | --print-build-logs \ 60 | ''${build_flags[@]}) 61 | if [[ $? -eq 0 ]] 62 | then 63 | sudo nix-env -p /nix/var/nix/profiles/system --set "$artifact" \ 64 | && sudo "$artifact/bin/switch-to-configuration" "$operation" 65 | else 66 | return 1 67 | fi 68 | } 69 | 70 | if build_and_switch; then 71 | ${notify} -t 5000 "nixos-rebuild $operation has finished successfully" 72 | else 73 | ${notify} -t 5000 "nixos-rebuild $operation has failed" 74 | read 75 | fi 76 | '') 77 | ]; 78 | }; 79 | } 80 | -------------------------------------------------------------------------------- /homes/modules/recoll.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.recoll.settings = { 3 | followLinks = true; 4 | 5 | # TODO: Add support for extra (private) top directories 6 | topdirs = [ 7 | "~/resources/bundles" 8 | "~/resources/ebooks" 9 | "~/resources/sound" 10 | "~/resources/bundles" 11 | "~/notes-and-pdfs/notes" 12 | "~/notes-and-pdfs/ebooks" 13 | ]; 14 | 15 | excludedmimetypes = [ 16 | "text/html" 17 | "application/x-mobipocket-ebook" 18 | "audio/flac" 19 | ]; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /homes/modules/timoni.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.programs.timoni; 8 | inherit (lib) mkIf mkOption mkEnableOption types; 9 | in { 10 | options = { 11 | programs.timoni = { 12 | enable = mkEnableOption (lib.mdDoc "Install timoni for development."); 13 | 14 | enableZshIntegration = mkOption { 15 | type = types.bool; 16 | default = true; 17 | description = "Whether to enable Zsh integration."; 18 | }; 19 | }; 20 | }; 21 | 22 | config = lib.mkIf cfg.enable { 23 | home.packages = [ 24 | pkgs.timoni 25 | ]; 26 | 27 | programs.zsh.initContent = mkIf cfg.enableZshIntegration '' 28 | source <(${pkgs.timoni}/bin/timoni completion zsh) 29 | compdef _timoni timoni 30 | ''; 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /homes/modules/words.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | xdg.dataFile."dict/words".source = 3 | (pkgs.fetchFromGitHub { 4 | owner = "dwyl"; 5 | repo = "english-words"; 6 | rev = "a77cb15f4f5beb59c15b945f2415328a6b33c3b0"; 7 | sha256 = "12mj9yas7z48cjy0zpi7jz09svipasr62v786lj3wkdssy8wrbfj"; 8 | }) 9 | + "/words_alpha.txt"; 10 | } 11 | -------------------------------------------------------------------------------- /homes/modules/wslu.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | pkgs, 5 | ... 6 | }: let 7 | cfg = config.programs.wslu; 8 | in { 9 | options = { 10 | programs.wslu = { 11 | enable = lib.mkEnableOption "Enable WSL utilities."; 12 | }; 13 | }; 14 | 15 | config = lib.mkIf cfg.enable { 16 | home.packages = [ 17 | pkgs.wslu 18 | (pkgs.makeDesktopItem { 19 | name = "wslview"; 20 | desktopName = "wslview"; 21 | exec = "wslview"; 22 | }) 23 | ]; 24 | 25 | xdg.mimeApps.defaultBrowser = lib.mkDefault "wslview.desktop"; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /homes/modules/xdg.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | pkgs, 4 | config, 5 | ... 6 | }: let 7 | inherit (lib) mkIf; 8 | inherit (pkgs.stdenv) isDarwin; 9 | inherit (config.home) homeDirectory; 10 | in { 11 | xdg.configHome = mkIf (!isDarwin) "${homeDirectory}/.config"; 12 | xdg.cacheHome = mkIf (!isDarwin) "${homeDirectory}/.cache"; 13 | xdg.dataHome = mkIf (!isDarwin) "${homeDirectory}/.local/share"; 14 | } 15 | -------------------------------------------------------------------------------- /homes/modules/zsh.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | home.packages = with pkgs; [ 4 | zsh 5 | nix-zsh-completions 6 | fzy 7 | ]; 8 | 9 | programs.zsh = { 10 | enable = true; 11 | autosuggestion.enable = true; 12 | enableCompletion = true; 13 | dotDir = ".config/zsh"; 14 | defaultKeymap = "emacs"; 15 | history = { 16 | expireDuplicatesFirst = true; 17 | save = 5000; 18 | share = true; 19 | size = 5000; 20 | }; 21 | 22 | plugins = [ 23 | { 24 | name = "zsh-history-substring-search"; 25 | src = pkgs.zsh-history-substring-search; 26 | } 27 | { 28 | name = "fzy"; 29 | src = pkgs.customZshPlugins.zsh-fzy; 30 | } 31 | { 32 | name = "nix-shell"; 33 | src = pkgs.customZshPlugins.zsh-nix-shell; 34 | } 35 | { 36 | name = "fast-syntax-highlighting"; 37 | src = pkgs.customZshPlugins.zsh-fast-syntax-highlighting; 38 | } 39 | { 40 | name = "history-filter"; 41 | src = pkgs.customZshPlugins.zsh-history-filter; 42 | } 43 | ]; 44 | 45 | sessionVariables = { 46 | "DIRSTACKSIZE" = "20"; 47 | "NIX_BUILD_SHELL" = "zsh"; 48 | # "VAGRANT_WSL_WINDOWS_ACCESS" = "1"; 49 | # Set locale archives 50 | # https://github.com/NixOS/nixpkgs/issues/38991 51 | "LOCALE_ARCHIVE_2_11" = "${pkgs.glibcLocales}/lib/locale/locale-archive"; 52 | "LOCALE_ARCHIVE_2_27" = "${pkgs.glibcLocales}/lib/locale/locale-archive"; 53 | }; 54 | 55 | initContent = '' 56 | setopt auto_cd 57 | setopt cdable_vars 58 | setopt auto_name_dirs 59 | setopt auto_pushd 60 | setopt pushd_ignore_dups 61 | setopt pushdminus 62 | 63 | # Configuration for zsh-fzy plugin https://github.com/aperezdc/zsh-fzy 64 | bindkey '\eq' fzy-proc-widget 65 | bindkey '\ew' fzy-cd-widget 66 | bindkey '\ee' fzy-file-widget 67 | bindkey '\er' fzy-history-widget 68 | zstyle :fzy:file command fd -t f 69 | zstyle :fzy:cd command fd -t d 70 | 71 | # Support directory tracking on emacs-libvterm. 72 | # https://github.com/akermu/emacs-libvterm#directory-tracking 73 | function chpwd() { 74 | print -Pn "\e]51;A$(pwd)\e\\"; 75 | } 76 | 77 | function pick() { 78 | local arg 79 | fzy | read -r arg && "$@" "$arg" 80 | } 81 | 82 | function mountpoints() { 83 | findmnt -oTARGET --list --noheadings 84 | } 85 | 86 | function remotes() { 87 | git rev-parse --show-toplevel >/dev/null || return 1 88 | git --no-pager config --local --list \ 89 | | sed -n -E 's/^remote\..+?\.url=(.+)/\1/p' \ 90 | | xargs realpath -q -s -e 91 | } 92 | 93 | function projects() { 94 | { 95 | tmp=$(mktemp -p "''${XDG_RUNTIME_DIR}") 96 | trap "rm -f '$tmp'" ERR EXIT 97 | # If the server isn't running, this script will exit with 1. 98 | emacsclient --eval "(with-temp-buffer 99 | (insert (string-join 100 | (thread-last 101 | (project-known-project-roots) 102 | (append (thread-last 103 | (frame-list) 104 | (mapcan #'window-list) 105 | (mapcar #'window-buffer) 106 | (mapcar (lambda (buffer) 107 | (buffer-local-value 'default-directory buffer))))) 108 | (mapcar #'expand-file-name) 109 | (seq-uniq)) 110 | \"\\n\")) 111 | (write-region (point-min) (point-max) \"$tmp\"))" > /dev/null 112 | cat "$tmp" 113 | } 114 | } 115 | 116 | function project-subdirectories() { 117 | local root="$(git rev-parse --show-toplevel)" 118 | if [[ -z "$root" ]]; then 119 | return 1 120 | else 121 | ( cd "$root" && fd -a -L -t d ) 122 | fi 123 | } 124 | 125 | function emacs-visible-directories() { 126 | tmp=$(mktemp -p "''${XDG_RUNTIME_DIR}") 127 | trap "rm -f '$tmp'" ERR EXIT 128 | # If the server isn't running, this script will exit with 1. 129 | emacsclient --eval "(with-temp-buffer 130 | (insert (string-join 131 | (thread-last 132 | (window-list) 133 | (mapcar #'window-buffer) 134 | (mapcar (lambda (buffer) 135 | (expand-file-name 136 | (buffer-local-value 'default-directory buffer)))) 137 | (seq-uniq)) 138 | \"\\n\")) 139 | (write-region (point-min) (point-max) \"$tmp\"))" > /dev/null 140 | cat "$tmp" 141 | } 142 | 143 | function cdv() { 144 | builtin cd "$1" && pwd 145 | } 146 | 147 | function cd() { 148 | case "$1" in 149 | -h) 150 | echo <<-HELP 151 | Usage: cd [-p|-m|-r|DIR] 152 | 153 | Options: 154 | -p: Select an Emacs project (requires an Emacs server running) 155 | -m: Select a mount point 156 | -r: Select a remote of the current Git repository 157 | -w: Select the directory of a visible buffer 158 | -d: Select a sub-directory inside the current Git repository 159 | -g: Go to the root of the current Git working tree 160 | HELP 161 | ;; 162 | -p|) 163 | projects | pick cdv 164 | ;; 165 | -m) 166 | mountpoints | pick cdv 167 | ;; 168 | -r) 169 | remotes | pick cdv 170 | ;; 171 | -w) 172 | emacs-visible-directories | pick cdv 173 | ;; 174 | -d) 175 | project-subdirectories | pick cdv 176 | ;; 177 | -g) 178 | local root="$(git rev-parse --show-toplevel)" 179 | if [[ -n "$root" ]]; then 180 | builtin cd "$root" 181 | fi 182 | ;; 183 | *) 184 | builtin cd "$@" 185 | ;; 186 | esac 187 | } 188 | 189 | function clone() { 190 | if [[ $# -eq 0 ]] 191 | then 192 | echo "Usage: clone URL" >&2 193 | return 1 194 | else 195 | dir=''${$(emacsclient --eval "(expand-file-name (akirak-git-clone-dir \"$1\"))")//\"/} 196 | cd "$dir" 197 | echo "$dir" 198 | fi 199 | } 200 | 201 | function clock() { 202 | emacsclient -n --eval "(akirak-capture-clock-in 203 | (org-dog-complete-file \"Clock into file: \") 204 | \"$*\" 205 | :body (format \"[[file:%s]]\n%%?\" (abbreviate-file-name \"$PWD/\")))" 206 | } 207 | 208 | export NIX_BUILD_SHELL=bash 209 | 210 | export EDITOR=emacsclient 211 | 212 | # Use gpg-agent as ssh-agent. 213 | gpg-connect-agent /bye 214 | export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) 215 | 216 | export STARSHIP_CONFIG=${pkgs.writeText "starship.toml" (pkgs.lib.fileContents ../etc/starship/starship.toml)} 217 | 218 | eval "$(${pkgs.starship}/bin/starship init zsh)" 219 | 220 | # https://github.com/MichaelAquilina/zsh-history-filter 221 | export HISTORY_FILTER_EXCLUDE=("TOKEN") 222 | ''; 223 | shellAliases = { 224 | ".." = "cd .."; 225 | "..." = "cd ../.."; 226 | "rm" = "rm -i"; 227 | "j" = "journalctl -xe"; 228 | "e" = "emacsclient -n"; 229 | "start" = "systemctl --user start"; 230 | "stop" = "systemctl --user stop"; 231 | "enable" = "systemctl --user enable"; 232 | "disable" = "systemctl --user disable"; 233 | "reload" = "systemctl --user daemon-reload"; 234 | "status" = "systemctl --user --full status"; 235 | "restart" = "systemctl --user restart"; 236 | "ssh-ignore" = "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"; 237 | }; 238 | }; 239 | } 240 | -------------------------------------------------------------------------------- /homes/wsl.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Configuration for Windows Subsystem for Linux (WSL) with WSLg 3 | */ 4 | {pkgs, ...}: { 5 | home.packages = [ 6 | pkgs.blanket 7 | ]; 8 | 9 | programs.wslu.enable = true; 10 | } 11 | -------------------------------------------------------------------------------- /machines/hui/boot.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | boot.loader.systemd-boot.enable = true; 3 | boot.loader.efi.canTouchEfiVariables = true; 4 | 5 | environment.systemPackages = [ 6 | pkgs.lshw 7 | pkgs.git 8 | ]; 9 | 10 | boot.kernel.sysctl = { 11 | "vm.swappiness" = 10; 12 | }; 13 | 14 | boot.initrd.kernelModules = [ 15 | "usbcore" 16 | "nvme" 17 | "sdhci_pci" 18 | "mmc_block" 19 | "xhci_hcd" 20 | "usb-storage" 21 | ]; 22 | 23 | boot.initrd.luks.reusePassphrases = true; 24 | 25 | boot.supportedFilesystems = ["btrfs"]; 26 | boot.initrd.supportedFilesystems = ["btrfs"]; 27 | 28 | boot.initrd.luks.devices.cryptroot = { 29 | device = "/dev/disk/by-uuid/78af0865-093e-4529-bf6a-841ee6b492e9"; 30 | allowDiscards = true; 31 | }; 32 | 33 | fileSystems = { 34 | "/" = { 35 | device = "/dev/mapper/cryptroot"; 36 | fsType = "btrfs"; 37 | neededForBoot = true; 38 | options = [ 39 | "subvol=/root" 40 | "discard=async" 41 | ]; 42 | }; 43 | 44 | "/boot" = { 45 | device = "/dev/disk/by-uuid/8627-ED16"; 46 | fsType = "vfat"; 47 | neededForBoot = true; 48 | options = [ 49 | "fmask=0137" 50 | "dmask=0027" 51 | ]; 52 | }; 53 | 54 | "/nix" = { 55 | device = "/dev/mapper/cryptroot"; 56 | fsType = "btrfs"; 57 | neededForBoot = true; 58 | options = [ 59 | "subvol=/nix" 60 | "compress=lz4" 61 | "noatime" 62 | "discard=async" 63 | ]; 64 | }; 65 | }; 66 | 67 | swapDevices = [ 68 | { 69 | device = "/dev/disk/by-partuuid/109d2b63-22f6-4188-8dc5-8346617d3df3"; 70 | randomEncryption = { 71 | enable = true; 72 | allowDiscards = true; 73 | }; 74 | } 75 | ]; 76 | 77 | boot.tmp.useTmpfs = true; 78 | boot.tmp.tmpfsSize = "4096m"; 79 | 80 | boot.runSize = "64m"; 81 | boot.devSize = "256m"; 82 | boot.devShmSize = "256m"; 83 | } 84 | -------------------------------------------------------------------------------- /machines/hui/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeUser, 3 | pkgs, 4 | ... 5 | }: 6 | let 7 | stateVersion = "25.05"; 8 | in 9 | { 10 | imports = [ 11 | ./boot.nix 12 | ../../nixos/suites/base 13 | ../../nixos/suites/graphical 14 | ../../nixos/suites/desktop 15 | ../../nixos/profiles/locale 16 | ../../nixos/profiles/home-manager 17 | ../../nixos/profiles/nix 18 | ../../nixos/profiles/sudo 19 | ../../nixos/profiles/tailscale 20 | ../../nixos/profiles/wayland/wlroots.nix 21 | # ../../nixos/profiles/wayland/cage/emacs.nix 22 | ../../nixos/profiles/wayland/cage/foot.nix 23 | # ../../nixos/profiles/wayland/cage/firefox.nix 24 | # ../../nixos/profiles/wayland/wm/labwc.nix 25 | ../../nixos/profiles/wayland/wm/hyprland.nix 26 | # ../../nixos/profiles/nix/cachix-deploy.nix 27 | ../../nixos/profiles/dpt-rp1 28 | ]; 29 | 30 | networking = { 31 | firewall.enable = true; 32 | useDHCP = false; 33 | networkmanager.enable = true; 34 | }; 35 | 36 | system.stateVersion = stateVersion; 37 | 38 | hardware.graphics.enable = true; 39 | 40 | systemd.services.NetworkManager-wait-online.enable = false; 41 | 42 | services.journald.extraConfig = '' 43 | SystemMaxFiles=5 44 | ''; 45 | 46 | services.auto-cpufreq.enable = true; 47 | 48 | zramSwap = { 49 | enable = true; 50 | }; 51 | 52 | users.users.${homeUser} = { 53 | description = "Akira Komamura"; 54 | uid = 1000; 55 | isNormalUser = true; 56 | hashedPassword = "$6$3LmgpFGu4WEeoTss$9NQpF4CEO8ivu0uJTlDYXdiB6ZPHBsLXDZr.6S59bBNxmNuhirmcOmHTwhccdgSwq7sJOz2JbOOzmOCivxdak0"; 57 | 58 | extraGroups = [ 59 | "wheel" 60 | "video" 61 | "audio" 62 | "disk" 63 | "networkmanager" 64 | "systemd-journal" 65 | # "docker" 66 | ]; 67 | }; 68 | 69 | services.greetd = { 70 | enable = true; 71 | settings.default_session = { 72 | # You have to install *.desktop files to the directory 73 | command = "${pkgs.greetd.tuigreet}/bin/tuigreet -t -s /etc/wayland-sessions"; 74 | user = homeUser; 75 | }; 76 | }; 77 | 78 | home-manager.users.${homeUser} = { 79 | imports = [ 80 | ../../homes/basic.nix 81 | ../../homes/extra.nix 82 | ../../homes/graphical.nix 83 | ]; 84 | 85 | # wayland.windowManager.labwc.enable = true; 86 | wayland.windowManager.hyprland.enable = true; 87 | 88 | programs.gpg.enable = true; 89 | 90 | programs.emacs-twist = { 91 | enable = true; 92 | serviceIntegration.enable = false; 93 | settings = { 94 | extraFeatures = [ 95 | "beancount" 96 | "OCaml" 97 | "Emacs" 98 | "Emacs__lisp" 99 | "Org" 100 | ]; 101 | }; 102 | }; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /machines/hui/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.unstable; 4 | in 5 | { 6 | flake = { 7 | nixosConfigurations.hui = channel.lib.nixosSystem { 8 | system = "x86_64-linux"; 9 | 10 | specialArgs = { 11 | homeUser = "akirakomamura"; 12 | hostPubkey = null; 13 | inherit (inputs) emacs-config; 14 | }; 15 | 16 | modules = [ 17 | inputs.home-manager-unstable.nixosModules.home-manager 18 | inputs.self.nixosModules.asus-br1100 19 | inputs.self.nixosModules.twistHomeModule 20 | inputs.self.nixosModules.default 21 | ./. 22 | { 23 | networking.hostName = "hui"; 24 | } 25 | ]; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /machines/li/boot.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | ... 6 | }: 7 | let 8 | annex-dm = "local_annex"; 9 | in 10 | { 11 | imports = [ 12 | ../../nixos/profiles/intel-arc 13 | ]; 14 | 15 | boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; 16 | 17 | boot.loader.systemd-boot.enable = true; 18 | boot.loader.efi.canTouchEfiVariables = true; 19 | boot.initrd.availableKernelModules = [ 20 | "xhci_pci" 21 | "ahci" 22 | "nvme" 23 | "usbhid" 24 | "usb_storage" 25 | "sd_mod" 26 | ]; 27 | # This kernel module is needed if and only if unlock LUKS devices on boot 28 | # boot.initrd.kernelModules = [ "dm-snapshot" ]; 29 | boot.kernelModules = [ "kvm-intel" ]; 30 | boot.extraModulePackages = [ ]; 31 | 32 | # ZFS support 33 | boot.supportedFilesystems.zfs = true; 34 | boot.initrd.supportedFilesystems.zfs = true; 35 | boot.zfs.requestEncryptionCredentials = true; 36 | services.zfs.autoSnapshot.enable = true; 37 | services.zfs.autoScrub.enable = true; 38 | # Configure ARC up to 4 GiB 39 | boot.kernelParams = [ "zfs.zfs_arc_max=4294967296" ]; 40 | 41 | environment.systemPackages = [ 42 | pkgs.lshw 43 | pkgs.git 44 | ]; 45 | 46 | fileSystems."/" = { 47 | device = "tmpfs"; 48 | fsType = "tmpfs"; 49 | options = [ 50 | "defaults" 51 | "size=10G" 52 | "mode=755" 53 | ]; 54 | }; 55 | 56 | fileSystems."/boot" = { 57 | device = "/dev/disk/by-uuid/B327-FDEA"; 58 | fsType = "vfat"; 59 | options = [ 60 | "fmask=0137" 61 | "dmask=0027" 62 | ]; 63 | }; 64 | 65 | fileSystems."/nix" = { 66 | device = "/dev/disk/by-uuid/89ca01cd-558b-410a-b282-3af5601b9f97"; 67 | fsType = "ext4"; 68 | }; 69 | 70 | boot.initrd.luks.devices.${annex-dm} = { 71 | device = "/dev/disk/by-uuid/2f67dfa5-200f-4d38-b96d-2aabbd9f5186"; 72 | allowDiscards = true; 73 | }; 74 | 75 | fileSystems."/git-annex/${config.networking.hostName}" = { 76 | device = "/dev/mapper/${annex-dm}"; 77 | fsType = "ext4"; 78 | options = [ 79 | "relatime" 80 | "discard" 81 | ]; 82 | }; 83 | 84 | swapDevices = [ ]; 85 | 86 | hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; 87 | 88 | hardware.enableRedistributableFirmware = true; 89 | 90 | # hardware.bluetooth = { 91 | # enable = true; 92 | # }; 93 | 94 | boot.runSize = "64m"; 95 | boot.devSize = "256m"; 96 | boot.devShmSize = "256m"; 97 | 98 | services.smartd = { 99 | enable = true; 100 | devices = [ 101 | { device = "/dev/disk/by-id/ata-CT1000MX500SSD1_2316E6CCB0BC"; } 102 | { device = "/dev/disk/by-id/ata-CT1000MX500SSD1_2316E6CCB574"; } 103 | ]; 104 | }; 105 | 106 | services.scrutiny = { 107 | enable = true; 108 | # Access only locally for now 109 | openFirewall = false; 110 | settings = { 111 | web.listen = { 112 | port = 9233; 113 | host = "127.0.0.1"; 114 | }; 115 | }; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /machines/li/default.nix: -------------------------------------------------------------------------------- 1 | { homeUser, pkgs, ... }: 2 | let 3 | stateVersion = "25.05"; 4 | 5 | mainMonitor = { 6 | criteria = "Unknown VA32AQ K3LMAS000141 (HDMI-A-2)"; 7 | mode = "2560x1440"; 8 | position = "1920,0"; 9 | }; 10 | 11 | subMonitor = { 12 | criteria = "Dell Inc. DELL S2421HS CBPT223 (DP-1)"; 13 | mode = "1920x1080"; 14 | position = "0,380"; 15 | }; 16 | in 17 | { 18 | imports = [ 19 | ./boot.nix 20 | ./rpool5 21 | ../../nixos/suites/base 22 | ../../nixos/suites/graphical 23 | ../../nixos/suites/desktop 24 | ../../nixos/profiles/locale 25 | ../../nixos/profiles/home-manager 26 | ../../nixos/profiles/nix 27 | ../../nixos/profiles/sudo 28 | ../../nixos/profiles/tailscale 29 | # ../../nixos/profiles/rabbitmq/development.nix 30 | ../../nixos/profiles/networking/usb-tether1.nix 31 | ../../nixos/profiles/wayland/wm/hyprland.nix 32 | ../../nixos/profiles/wayland/cage/foot.nix 33 | # ../../nixos/profiles/wayland/wm/river.nix 34 | # ../../nixos/profiles/nix/cachix-deploy.nix 35 | ../../nixos/profiles/postgresql/development.nix 36 | ../../nixos/profiles/livebook 37 | ../../nixos/profiles/ollama 38 | ../../nixos/profiles/virtualbox-host 39 | ../../nixos/profiles/dpt-rp1 40 | ../../nixos/profiles/podman/rootless-docker.nix 41 | # ../../nixos/profiles/docker/rootless.nix 42 | # ../../nixos/profiles/docker 43 | # ../../nixos/profiles/docker/kind.nix 44 | # ../../nixos/profiles/k3s/single-node-for-testing.nix 45 | ]; 46 | 47 | hardware.graphics = { 48 | enable = true; 49 | extraPackages = [ 50 | pkgs.intel-compute-runtime 51 | pkgs.intel-media-driver 52 | ]; 53 | }; 54 | 55 | system.stateVersion = stateVersion; 56 | 57 | # Needed for the ZFS pool. 58 | networking.hostId = "8425e349"; 59 | 60 | # I didn't use disko when I first set up this machine. 61 | # disko.devices = import ./disko.nix {}; 62 | 63 | networking = { 64 | useDHCP = false; 65 | networkmanager.enable = true; 66 | }; 67 | # systemd.services.NetworkManager-wait-online.enable = true; 68 | 69 | environment.systemPackages = [ 70 | pkgs.clinfo 71 | pkgs.hunspellDicts.en_US 72 | pkgs.hunspellDicts.en_GB-ise 73 | 74 | # Install Cloud Hypervisor for use with MicroVM 75 | pkgs.cloud-hypervisor 76 | ]; 77 | 78 | services.journald.extraConfig = '' 79 | SystemMaxFiles=5 80 | ''; 81 | 82 | services.auto-cpufreq.enable = true; 83 | 84 | zramSwap = { 85 | enable = true; 86 | }; 87 | 88 | users.users.${homeUser} = { 89 | description = "Akira Komamura"; 90 | uid = 1000; 91 | isNormalUser = true; 92 | hashedPassword = "$6$3LmgpFGu4WEeoTss$9NQpF4CEO8ivu0uJTlDYXdiB6ZPHBsLXDZr.6S59bBNxmNuhirmcOmHTwhccdgSwq7sJOz2JbOOzmOCivxdak0"; 93 | 94 | extraGroups = [ 95 | "wheel" 96 | "video" 97 | "audio" 98 | "disk" 99 | "networkmanager" 100 | "systemd-journal" 101 | "docker" 102 | "livebook" 103 | ]; 104 | }; 105 | 106 | services.greetd = { 107 | enable = true; 108 | settings.default_session = { 109 | # You have to install *.desktop files to the directory 110 | command = "${pkgs.greetd.tuigreet}/bin/tuigreet -t -s /etc/wayland-sessions"; 111 | user = homeUser; 112 | }; 113 | }; 114 | 115 | services.my-livebook = { 116 | enable = true; 117 | settings = { 118 | ipAddress = "127.0.0.1"; 119 | port = 8200; 120 | enableNix = true; 121 | }; 122 | }; 123 | 124 | services.ollama.acceleration = false; 125 | 126 | services.postgresql = { 127 | package = pkgs.postgresql_17; 128 | }; 129 | 130 | home-manager.users.${homeUser} = { 131 | imports = [ 132 | ../../homes/basic.nix 133 | ../../homes/extra.nix 134 | ../../homes/code.nix 135 | ../../homes/graphical.nix 136 | ]; 137 | 138 | programs.chromium = { 139 | enable = true; 140 | package = pkgs.ungoogled-chromium; 141 | extensions = [ 142 | { 143 | # Google Input Tools 144 | id = "mclkkofklkfljcocdinagocijmpgbhab"; 145 | } 146 | ]; 147 | }; 148 | 149 | programs.uv.settings = { 150 | # ZFS 151 | link-mode = "copy"; 152 | }; 153 | 154 | home.stateVersion = stateVersion; 155 | 156 | home.packages = [ 157 | pkgs.rclone 158 | # pkgs.steam-run 159 | # pkgs.wine 160 | # pkgs.tenacity 161 | # pkgs.microsoft-edge 162 | # pkgs.zoom-us 163 | ]; 164 | 165 | home.file.".npmrc".text = '' 166 | # Required because of the network instability 167 | fetch-retries = 5 168 | # Required because of ZFS 169 | package-import-method=copy 170 | ''; 171 | 172 | services.kanshi.settings = [ 173 | { 174 | profile.name = "docked"; 175 | profile.outputs = [ 176 | mainMonitor 177 | subMonitor 178 | ]; 179 | } 180 | { 181 | profile.name = "undocked"; 182 | profile.outputs = [ mainMonitor ]; 183 | } 184 | { 185 | profile.name = "as_secondary"; 186 | profile.outputs = [ subMonitor ]; 187 | } 188 | ]; 189 | 190 | wayland.windowManager.hyprland.enable = true; 191 | 192 | # programs.river.enable = true; 193 | 194 | programs.gpg.enable = true; 195 | 196 | programs.emacs-twist = { 197 | enable = true; 198 | settings = { 199 | extraFeatures = [ 200 | "beancount" 201 | "OCaml" 202 | "Emacs" 203 | "Emacs__lisp" 204 | "Org" 205 | "MCP" 206 | # "Coq" 207 | # "Lean4" 208 | # "lsp_mode" 209 | ]; 210 | }; 211 | }; 212 | }; 213 | } 214 | -------------------------------------------------------------------------------- /machines/li/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.unstable; 4 | in 5 | { 6 | flake = { 7 | nixosConfigurations.li = channel.lib.nixosSystem { 8 | system = "x86_64-linux"; 9 | 10 | specialArgs = { 11 | homeUser = "akirakomamura"; 12 | hostPubkey = null; 13 | inherit (inputs) emacs-config; 14 | }; 15 | 16 | modules = [ 17 | inputs.home-manager-unstable.nixosModules.home-manager 18 | inputs.nixos-hardware.nixosModules.common-gpu-intel 19 | inputs.self.nixosModules.twistHomeModule 20 | inputs.self.nixosModules.default 21 | ./. 22 | { 23 | networking.hostName = "li"; 24 | } 25 | ]; 26 | }; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /machines/li/rpool5/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ ./extras.nix ]; 3 | 4 | fileSystems."/persist" = { 5 | device = "rpool5/safe/persist"; 6 | fsType = "zfs"; 7 | neededForBoot = true; 8 | }; 9 | 10 | fileSystems."/home" = { 11 | device = "rpool5/safe/home"; 12 | fsType = "zfs"; 13 | }; 14 | 15 | # You will require github:nix-community/impermanence to use this 16 | environment.persistence."/persist" = { 17 | directories = [ 18 | "/var/log" 19 | "/var/tmp" 20 | "/var/lib/nixos" 21 | "/var/lib/bluetooth" 22 | "/var/lib/livebook" 23 | "/var/lib/rabbitmq" 24 | "/etc/NetworkManager/system-connections" 25 | ]; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /machines/li/rpool5/extras.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | config, 4 | homeUser, 5 | ... 6 | }: 7 | let 8 | rootlessStoragePath = "/home/${homeUser}/.local/share/containers"; 9 | in 10 | { 11 | # fileSystems."/backup" = { 12 | # device = "/dev/mapper/backup_rpool5"; 13 | # fsType = "ext4"; 14 | # neededForBoot = true; 15 | # }; 16 | 17 | fileSystems."/var/lib/postgresql" = { 18 | # This pool name was a mistake 19 | device = "rpool5/safe/postgresql"; 20 | fsType = "zfs"; 21 | neededForBoot = true; 22 | }; 23 | 24 | # You always have to backup databases. Automatic snapshots of ZFS do not work 25 | # for database backups, so set up a dataset (with optional automatic 26 | # snapshots) for backups and run pgbackup periodically. 27 | fileSystems.${config.services.postgresqlBackup.location} = { 28 | device = "rpool5/safe/pgbackup"; 29 | fsType = "zfs"; 30 | neededForBoot = true; 31 | }; 32 | 33 | # Enable the transparent compression of ZFS 34 | services.postgresqlBackup = lib.mkIf config.services.postgresqlBackup.enable { 35 | compression = "none"; 36 | }; 37 | 38 | fileSystems."/var/lib/private" = { 39 | device = "rpool5/local/ollama"; 40 | fsType = "zfs"; 41 | # The root directory of this file system needs to have 0700 permission. 42 | }; 43 | 44 | fileSystems."/var/lib/containers" = { 45 | device = "rpool5/local/containers"; 46 | fsType = "zfs"; 47 | }; 48 | 49 | fileSystems.${rootlessStoragePath} = { 50 | device = "rpool5/local/containers-rootless"; 51 | fsType = "zfs"; 52 | }; 53 | virtualisation.containers.storage.settings.storage.rootless_storage_path = rootlessStoragePath; 54 | 55 | fileSystems."/media/virtualbox" = { 56 | device = "rpool5/safe/virtualbox"; 57 | fsType = "zfs"; 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /machines/metadata.toml: -------------------------------------------------------------------------------- 1 | # Use `ssh-keyscan -t ed25519 ...` to get the public key(s) remotely 2 | [hosts.zheng] 3 | ipAddress = "192.168.10.1" 4 | publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPok1B5NsawQoyxJ2Is3wynnfqZ51o1fyueJ3gpLLCa5" 5 | 6 | [hosts.li] 7 | ipAddress = "192.168.10.60" 8 | syncthingId = "FWMZWNO-CIL5HZL-5IOA5IZ-UGXYQK6-DYK76L4-VDQAOZP-VHDLLC4-JYUSAAU" 9 | 10 | [hosts.yang] 11 | ipAddress = "192.168.10.10" 12 | publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBBqIBetzQSQhJeOgBXCcNwwyWToSGh2ZUMLEROwwxeF" 13 | 14 | [hosts.wang] 15 | ipAddress = "192.168.10.11" 16 | 17 | [networks.home] 18 | subnet = "192.168.10.0/16" 19 | -------------------------------------------------------------------------------- /machines/shu/boot.nix: -------------------------------------------------------------------------------- 1 | {config, ...}: let 2 | cryptName = "cryptroot"; 3 | cryptDevice = "/dev/sda3"; 4 | in { 5 | boot.kernelModules = ["virtio_net"]; 6 | boot.loader.efi.canTouchEfiVariables = false; 7 | 8 | boot.initrd = { 9 | enable = true; 10 | 11 | # Network card drivers. 12 | kernelModules = ["virtio_net"]; 13 | 14 | luks.devices.${cryptName} = { 15 | device = cryptDevice; 16 | allowDiscards = true; 17 | }; 18 | 19 | network = { 20 | enable = true; 21 | 22 | ssh = { 23 | enable = true; 24 | port = 222; 25 | 26 | hostKeys = [ 27 | "/persist/boot_ed25519_key" 28 | ]; 29 | 30 | authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; 31 | }; 32 | }; 33 | }; 34 | 35 | networking = { 36 | useDHCP = false; 37 | interfaces.eth0.useDHCP = true; 38 | }; 39 | 40 | boot.supportedFilesystems = ["zfs"]; 41 | boot.initrd.supportedFilesystems = ["zfs"]; 42 | boot.zfs.requestEncryptionCredentials = true; 43 | boot.kernelParams = ["zfs.zfs_arc_max=805306368"]; 44 | services.zfs.autoSnapshot.enable = true; 45 | services.zfs.autoScrub.enable = true; 46 | } 47 | -------------------------------------------------------------------------------- /machines/shu/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ../../nixos/suites/hcloud-remote 4 | ../../nixos/suites/base 5 | ../../nixos/profiles/tailscale 6 | ../../nixos/profiles/nginx 7 | ../../nixos/profiles/nix/cachix-deploy.nix 8 | ./boot.nix 9 | (import ./disko.nix {}) 10 | ]; 11 | 12 | networking.hostId = "9bc2dd3d"; 13 | time.timeZone = "America/Los_Angeles"; 14 | 15 | nix.settings.allowed-users = ["root"]; 16 | 17 | services.journald.extraConfig = '' 18 | SystemMaxUse=1G 19 | MaxFileSec=10day 20 | ''; 21 | } 22 | -------------------------------------------------------------------------------- /machines/shu/disko.nix: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/numtide/nixos-remote-examples/blob/9768e438b1467ec55d42e096860e7199bd1ef43d/disk-config.nix 2 | { 3 | disks ? [ "/dev/sda" ], 4 | luksKey ? "/persist/luks-cryptroot.key", 5 | ... 6 | }: 7 | { 8 | disko.devices = { 9 | disk.sda = { 10 | device = builtins.elemAt disks 0; 11 | type = "disk"; 12 | content = { 13 | type = "gpt"; 14 | partitions = { 15 | boot = { 16 | start = "0"; 17 | end = "1M"; 18 | type = "EF02"; 19 | }; 20 | 21 | ESP = { 22 | start = "1MiB"; 23 | end = "100MiB"; 24 | content = { 25 | type = "filesystem"; 26 | format = "vfat"; 27 | mountpoint = "/boot"; 28 | mountOptions = [ 29 | "defaults" 30 | ]; 31 | }; 32 | }; 33 | 34 | luks = { 35 | start = "100MiB"; 36 | end = "100%"; 37 | content = { 38 | type = "luks"; 39 | name = "cryptroot"; 40 | keyFile = luksKey; 41 | content = { 42 | type = "zfs"; 43 | pool = "zroot"; 44 | }; 45 | }; 46 | }; 47 | }; 48 | }; 49 | }; 50 | 51 | zpool = { 52 | zroot = { 53 | type = "zpool"; 54 | # mode = "mirror"; 55 | rootFsOptions = { 56 | "com.sun:auto-snapshot" = "false"; 57 | }; 58 | 59 | mountpoint = "/"; 60 | 61 | datasets = { 62 | nix = { 63 | type = "zfs_fs"; 64 | mountpoint = "/nix"; 65 | options = { 66 | compression = "lz4"; 67 | "com.sun:auto-snapshot" = "true"; 68 | }; 69 | }; 70 | persist = { 71 | type = "zfs_fs"; 72 | mountpoint = "/persist"; 73 | options = { 74 | "com.sun:auto-snapshot" = "true"; 75 | }; 76 | }; 77 | var = { 78 | type = "zfs_fs"; 79 | mountpoint = "/var"; 80 | options = { 81 | compression = "lz4"; 82 | "com.sun:auto-snapshot" = "true"; 83 | }; 84 | }; 85 | }; 86 | }; 87 | }; 88 | }; 89 | } 90 | -------------------------------------------------------------------------------- /machines/shu/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.stable; 4 | in 5 | { 6 | flake = { 7 | diskoConfigurations.shu = import ./disko.nix; 8 | nixosConfigurations.shu = channel.lib.nixosSystem { 9 | system = "x86_64-linux"; 10 | 11 | specialArgs = { 12 | hostPubkey = null; 13 | }; 14 | 15 | modules = [ 16 | ./. 17 | inputs.self.nixosModules.default 18 | { 19 | networking.hostName = "shu"; 20 | } 21 | ]; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /machines/voyage/home.nix: -------------------------------------------------------------------------------- 1 | {homeUser, ...}: { 2 | home.username = homeUser; 3 | home.homeDirectory = "/home/${homeUser}"; 4 | 5 | imports = [ 6 | ../../homes/core.nix 7 | ]; 8 | 9 | targets.crostini.enable = true; 10 | 11 | services.cachix-agent = { 12 | enable = true; 13 | name = "voyage"; 14 | }; 15 | 16 | programs.rebuild-home.name = "voyage"; 17 | 18 | programs.emacs-twist = { 19 | enable = true; 20 | settings = { 21 | extraFeatures = [ 22 | ]; 23 | }; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /machines/wang/boot.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | ... 5 | }: 6 | { 7 | boot.extraModulePackages = [ 8 | (config.boot.kernelPackages.r8168.overrideAttrs ( 9 | import ../../modules/overrides/r8168.nix { inherit pkgs; } 10 | )) 11 | ]; 12 | 13 | boot.loader = { 14 | efi.canTouchEfiVariables = false; 15 | systemd-boot.enable = true; 16 | timeout = 3; 17 | }; 18 | 19 | boot.kernelParams = [ "ip=dhcp" ]; 20 | 21 | boot.supportedFilesystems = { 22 | zfs = true; 23 | btrfs = true; 24 | ext4 = true; 25 | }; 26 | 27 | boot.initrd = { 28 | enable = true; 29 | 30 | supportedFilesystems = { 31 | zfs = true; 32 | btrfs = true; 33 | ext4 = true; 34 | }; 35 | 36 | availableKernelModules = [ 37 | "xhci_pci" 38 | "r8169" 39 | # To temporarily access removable USB storage devices 40 | "uas" 41 | "sd_mod" 42 | ]; 43 | 44 | network = { 45 | enable = true; 46 | 47 | ssh = { 48 | enable = true; 49 | port = 222; 50 | 51 | hostKeys = [ 52 | # Generate a key pair using ssh-keygen 53 | "/persist/initrd-ssh-hostkey" 54 | ]; 55 | 56 | authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; 57 | }; 58 | 59 | postCommands = '' 60 | zpool import storage1 61 | echo "zfs load-key -r storage1; /bin/cryptsetup-askpass" >> /root/.profile 62 | ''; 63 | }; 64 | }; 65 | 66 | boot.tmp = { 67 | tmpfsSize = "1G"; 68 | useTmpfs = true; 69 | }; 70 | 71 | boot.zfs = { 72 | # The default is true, but it is highly recommended to turn it off for 73 | # increased reliability. 74 | forceImportRoot = false; 75 | }; 76 | } 77 | -------------------------------------------------------------------------------- /machines/wang/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | modulesPath, 4 | ... 5 | }: 6 | let 7 | stateVersion = "25.05"; 8 | in 9 | { 10 | imports = [ 11 | # basics 12 | (modulesPath + "/profiles/hardened.nix") 13 | (modulesPath + "/profiles/headless.nix") 14 | ../../nixos/suites/server 15 | ./fs 16 | ./boot.nix 17 | 18 | # Create a non-wheel user for hosting some personal data. 19 | ../../nixos/profiles/users/1000/on-server.nix 20 | ]; 21 | 22 | system.stateVersion = stateVersion; 23 | 24 | # Needed for the ZFS pool. 25 | # Use `cat /etc/machine-id | cut -c1-8` 26 | networking.hostId = "4cc22902"; 27 | 28 | boot.runSize = "64m"; 29 | boot.devSize = "256m"; 30 | boot.devShmSize = "256m"; 31 | 32 | services.auto-cpufreq.enable = true; 33 | powerManagement.cpuFreqGovernor = "ondemand"; 34 | 35 | environment.systemPackages = [ 36 | pkgs.lshw 37 | pkgs.usbutils 38 | pkgs.pkgs.git 39 | pkgs.git-annex 40 | # Install gdisk to allow working with new storage devices while the server 41 | # is online. 42 | pkgs.gptfdisk 43 | ]; 44 | 45 | time.timeZone = "Asia/Tokyo"; 46 | } 47 | -------------------------------------------------------------------------------- /machines/wang/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.stable; 4 | in 5 | { 6 | flake = { 7 | nixosConfigurations.wang = channel.lib.nixosSystem { 8 | system = "x86_64-linux"; 9 | 10 | specialArgs = { 11 | hostPubkey = null; 12 | }; 13 | 14 | modules = [ 15 | ./. 16 | inputs.self.nixosModules.default 17 | { 18 | networking.hostName = "wang"; 19 | } 20 | ]; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /machines/wang/fs/annex.nix: -------------------------------------------------------------------------------- 1 | { 2 | boot.initrd.luks.reusePassphrases = true; 3 | 4 | boot.initrd.luks.devices = { 5 | annex1 = { 6 | device = "/dev/disk/by-partuuid/31efb973-e795-4dcf-b72b-19cc7faefb14"; 7 | }; 8 | annex2 = { 9 | device = "/dev/disk/by-partuuid/a3e493bc-346d-4df0-9491-3d6bb986a0ed"; 10 | }; 11 | }; 12 | 13 | fileSystems = { 14 | "/git-annex/wang-annex1" = { 15 | device = "/dev/mapper/annex1"; 16 | fsType = "ext4"; 17 | options = [ 18 | "noatime" 19 | ]; 20 | }; 21 | "/git-annex/wang-annex2" = { 22 | device = "/dev/mapper/annex2"; 23 | fsType = "ext4"; 24 | options = [ 25 | "noatime" 26 | ]; 27 | }; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /machines/wang/fs/btrfs.nix: -------------------------------------------------------------------------------- 1 | # Use a non-ZFS encrypted partition for a Nix store, downloads, git-annex 2 | # repositories, and other temporary files. 3 | { 4 | device, 5 | }: 6 | { 7 | fileSystems = 8 | builtins.mapAttrs 9 | ( 10 | _mountpoint: 11 | { 12 | subvol, 13 | mountOptions ? [ ], 14 | neededForBoot ? false, 15 | }: 16 | { 17 | inherit device neededForBoot; 18 | fsType = "btrfs"; 19 | options = [ 20 | "subvol=${subvol}" 21 | "compress=zstd" 22 | ] ++ mountOptions; 23 | } 24 | ) 25 | { 26 | "/" = { 27 | subvol = "root"; 28 | neededForBoot = true; 29 | }; 30 | "/nix" = { 31 | subvol = "nix"; 32 | mountOptions = [ "noatime" ]; 33 | neededForBoot = true; 34 | }; 35 | "/var/log" = { 36 | subvol = "var/log"; 37 | neededForBoot = true; 38 | }; 39 | # Other persistent files (e.g. /var/tmp) and static data that should not 40 | # be put in the world-wide Nix store 41 | "/persist" = { 42 | subvol = "persist"; 43 | neededForBoot = true; 44 | }; 45 | }; 46 | 47 | environment.persistence."/persist" = { 48 | directories = [ 49 | "/etc/nixos" 50 | "/var/lib/nixos" 51 | "/var/lib/systemd/coredump" 52 | # # Required for some services 53 | "/var/lib/private" 54 | ]; 55 | files = [ 56 | "/etc/machine-id" 57 | "/etc/ssh/ssh_host_rsa_key" 58 | "/etc/ssh/ssh_host_rsa_key.pub" 59 | "/etc/ssh/ssh_host_ed25519_key" 60 | "/etc/ssh/ssh_host_ed25519_key.pub" 61 | ]; 62 | # Add minimal settings for user files. 63 | # users.akirakomamura = {}; 64 | }; 65 | } 66 | -------------------------------------------------------------------------------- /machines/wang/fs/default.nix: -------------------------------------------------------------------------------- 1 | { lib, ... }: 2 | let 3 | systemSsd = "/dev/disk/by-id/ata-CT500BX500SSD1_2432E8BE667B"; 4 | cryptBtrfs = "root"; 5 | decryptedDevice = "/dev/mapper/${cryptBtrfs}"; 6 | in 7 | { 8 | imports = [ 9 | (import ./btrfs.nix { 10 | device = decryptedDevice; 11 | }) 12 | ./storage1.nix 13 | ./annex.nix 14 | ]; 15 | 16 | boot.initrd.luks.devices.${cryptBtrfs} = { 17 | device = "${systemSsd}-part2"; 18 | allowDiscards = true; 19 | }; 20 | 21 | # Required for impermanence. See 22 | # https://github.com/nix-community/impermanence?tab=readme-ov-file#btrfs-subvolumes 23 | boot.initrd.postDeviceCommands = lib.mkAfter '' 24 | mkdir /btrfs_tmp 25 | mount ${decryptedDevice} /btrfs_tmp 26 | if [[ -e /btrfs_tmp/root ]]; then 27 | mkdir -p /btrfs_tmp/old_roots 28 | timestamp=$(date --date="@$(stat -c %Y /btrfs_tmp/root)" "+%Y-%m-%-d_%H:%M:%S") 29 | mv /btrfs_tmp/root "/btrfs_tmp/old_roots/$timestamp" 30 | fi 31 | 32 | delete_subvolume_recursively() { 33 | IFS=$'\n' 34 | for i in $(btrfs subvolume list -o "$1" | cut -f 9- -d ' '); do 35 | delete_subvolume_recursively "/btrfs_tmp/$i" 36 | done 37 | btrfs subvolume delete "$1" 38 | } 39 | 40 | for i in $(find /btrfs_tmp/old_roots/ -maxdepth 1 -mtime +30); do 41 | delete_subvolume_recursively "$i" 42 | done 43 | 44 | btrfs subvolume create /btrfs_tmp/root 45 | umount /btrfs_tmp 46 | ''; 47 | 48 | fileSystems = { 49 | "/boot" = { 50 | device = "${systemSsd}-part1"; 51 | fsType = "vfat"; 52 | options = [ 53 | "fmask=0137" 54 | "dmask=0027" 55 | ]; 56 | }; 57 | }; 58 | 59 | services.smartd = { 60 | enable = true; 61 | devices = [ 62 | { device = systemSsd; } 63 | { 64 | device = "/dev/disk/by-id/ata-TOSHIBA_MG08ADA800E_74G0A1ZQFCXH"; 65 | } 66 | { 67 | device = "/dev/disk/by-id/ata-TOSHIBA_MG08ADA800E_74G0A203FCXH"; 68 | } 69 | ]; 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /machines/wang/fs/storage1.nix: -------------------------------------------------------------------------------- 1 | { 2 | boot.zfs = { 3 | requestEncryptionCredentials = [ 4 | "storage1" 5 | ]; 6 | }; 7 | 8 | services.zfs = { 9 | autoSnapshot.enable = true; 10 | autoScrub.enable = true; 11 | }; 12 | 13 | boot.kernelParams = [ 14 | # 20 GiB 15 | "zfs.zfs_arc_max=21474836480" 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /machines/yang/boot.nix: -------------------------------------------------------------------------------- 1 | { config, ... }: 2 | { 3 | boot.loader = { 4 | efi.canTouchEfiVariables = false; 5 | systemd-boot.enable = true; 6 | timeout = 3; 7 | }; 8 | 9 | boot.kernelParams = [ "ip=dhcp" ]; 10 | 11 | boot.supportedFilesystems = { 12 | "zfs" = true; 13 | "btrfs" = true; 14 | }; 15 | 16 | boot.initrd = { 17 | enable = true; 18 | 19 | supportedFilesystems = { 20 | "zfs" = true; 21 | "btrfs" = true; 22 | }; 23 | 24 | availableKernelModules = [ 25 | "xhci_hcd" 26 | "r8169" 27 | ]; 28 | 29 | # systemd.users.root.shell = "/bin/cryptsetup-askpass"; 30 | 31 | network = { 32 | enable = true; 33 | 34 | ssh = { 35 | enable = true; 36 | port = 222; 37 | 38 | hostKeys = [ 39 | # Generate a key pair using ssh-keygen 40 | "/persist/initrd-ssh-hostkey" 41 | ]; 42 | 43 | authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; 44 | }; 45 | 46 | postCommands = '' 47 | zpool import rpool4 48 | echo "zfs load-key -r rpool4; /bin/cryptsetup-askpass" >> /root/.profile 49 | ''; 50 | }; 51 | }; 52 | 53 | boot.zfs = { 54 | # The default is true, but it is suggested to turn it off. 55 | forceImportRoot = false; 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /machines/yang/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | pkgs, 4 | lib, 5 | modulesPath, 6 | ... 7 | }: 8 | let 9 | stateVersion = "25.05"; 10 | 11 | metadata = lib.importTOML ../metadata.toml; 12 | 13 | ip = metadata.hosts.yang.ipAddress; 14 | 15 | inherit (config.services) reverse-proxy; 16 | 17 | hostsTextForReverseProxy = lib.pipe reverse-proxy.subdomains [ 18 | builtins.attrNames 19 | (builtins.map (name: "${ip} ${name} ${name}.${reverse-proxy.domain}")) 20 | (builtins.concatStringsSep "\n") 21 | ]; 22 | in 23 | { 24 | imports = [ 25 | (modulesPath + "/profiles/hardened.nix") 26 | # Create a non-wheel user for hosting some personal data. 27 | ../../nixos/profiles/users/1000/on-server.nix 28 | ../../nixos/profiles/agenix 29 | ../../nixos/profiles/openssh 30 | ../../nixos/profiles/onedev 31 | ../../nixos/profiles/docker 32 | ../../nixos/profiles/reverse-proxy 33 | ../../nixos/profiles/acme/internal.nix 34 | ./fs 35 | ./boot.nix 36 | ./lgtm-stack.nix 37 | ../../nixos/profiles/syncthing 38 | ]; 39 | 40 | system.stateVersion = stateVersion; 41 | 42 | # Needed for the ZFS pool. 43 | # Use `cat /etc/machine-id | cut -c1-8` 44 | networking.hostId = "8425e349"; 45 | 46 | # This option is enabled by default in nixos/modules/profiles/hardened.nix, 47 | # but needed to be turned off to load br_netfilter module for Docker. 48 | security.lockKernelModules = false; 49 | 50 | boot.runSize = "64m"; 51 | boot.devSize = "256m"; 52 | boot.devShmSize = "256m"; 53 | 54 | services.auto-cpufreq.enable = true; 55 | powerManagement.cpuFreqGovernor = "ondemand"; 56 | 57 | environment.systemPackages = [ 58 | # Tools for diagnostics 59 | pkgs.tcpdump 60 | pkgs.dig 61 | ]; 62 | 63 | services.reverse-proxy = { 64 | enable = true; 65 | domain = "nicesunny.day"; 66 | }; 67 | 68 | services.coredns = { 69 | enable = true; 70 | config = '' 71 | nicesunny.day { 72 | # Bypass requests for ACME challenges 73 | forward _acme-challenge.nicesunny.day 1.1.1.1 74 | hosts { 75 | ${ip} test test.nicesunny.day 76 | ${hostsTextForReverseProxy} 77 | ${lib.pipe metadata.hosts [ 78 | (lib.filterAttrs (_: attrs: attrs ? ipAddress)) 79 | (lib.mapAttrsToList (name: attrs: "${attrs.ipAddress} ${name} ${name}.nicesunny.day")) 80 | (builtins.concatStringsSep "\n") 81 | ]} 82 | fallthrough 83 | } 84 | log 85 | } 86 | 87 | . { 88 | # acme-v02.api.letsencrypt.org should be discoverable from the host 89 | forward . 1.1.1.1 8.8.8.8 9.9.9.9 90 | } 91 | ''; 92 | }; 93 | 94 | services.resolved.enable = false; 95 | 96 | networking.firewall.allowedTCPPorts = [ 97 | 2019 # Allow installation of local certificates for caddy 98 | 53 # DNS 99 | ]; 100 | networking.firewall.allowedUDPPorts = [ 101 | 53 # DNS 102 | ]; 103 | 104 | networking = { 105 | useNetworkd = true; 106 | }; 107 | 108 | systemd.network = { 109 | networks = { 110 | "20-lan" = { 111 | matchConfig.Name = "enp1s0"; 112 | networkConfig = { 113 | DHCP = "ipv4"; 114 | Address = metadata.hosts.${config.networking.hostName}.ipAddress; 115 | Gateway = metadata.hosts.zheng.ipAddress; 116 | DNS = metadata.hosts.zheng.ipAddress; 117 | }; 118 | }; 119 | }; 120 | }; 121 | 122 | virtualisation.docker = { 123 | storageDriver = "zfs"; 124 | }; 125 | 126 | users.users.akirakomamura = { 127 | # Provide minimal packages needed for specific needs. 128 | packages = [ 129 | pkgs.git 130 | pkgs.git-annex 131 | ]; 132 | }; 133 | 134 | time.timeZone = "Asia/Tokyo"; 135 | } 136 | -------------------------------------------------------------------------------- /machines/yang/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.unstable; 4 | in 5 | { 6 | flake = { 7 | nixosConfigurations.yang = channel.lib.nixosSystem { 8 | system = "x86_64-linux"; 9 | 10 | specialArgs = { 11 | hostPubkey = inputs.self.lib.hostPubkeys.yang; 12 | }; 13 | 14 | modules = [ 15 | ./. 16 | inputs.self.nixosModules.default 17 | { 18 | networking.hostName = "yang"; 19 | } 20 | ]; 21 | }; 22 | }; 23 | 24 | perSystem = 25 | { pkgs, ... }: 26 | { 27 | devShells = { 28 | # Provide caddy and certutils to install certificates from caddy 29 | # into the root store 30 | caddy = pkgs.mkShell { 31 | buildInputs = [ 32 | pkgs.caddy 33 | pkgs.nssTools # certutils 34 | ]; 35 | }; 36 | }; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /machines/yang/fs/btrfs.nix: -------------------------------------------------------------------------------- 1 | # Use a non-ZFS encrypted partition for a Nix store, downloads, git-annex 2 | # repositories, and other temporary files. 3 | { 4 | device, 5 | hostName, 6 | }: { 7 | fileSystems = 8 | builtins.mapAttrs (_mountpoint: { 9 | subvol, 10 | mountOptions, 11 | neededForBoot ? false, 12 | }: { 13 | inherit device neededForBoot; 14 | fsType = "btrfs"; 15 | options = 16 | [ 17 | "subvol=${subvol}" 18 | "compress=zstd" 19 | ] 20 | ++ mountOptions; 21 | }) { 22 | "/nix" = { 23 | subvol = "nix"; 24 | mountOptions = ["noatime"]; 25 | neededForBoot = true; 26 | }; 27 | # Working space for applications 28 | "/home" = { 29 | subvol = "home"; 30 | mountOptions = ["relatime"]; 31 | }; 32 | # Storage for disposable files, e.g. downloads 33 | "/cache" = { 34 | subvol = "cache"; 35 | mountOptions = ["noatime"]; 36 | neededForBoot = true; 37 | }; 38 | # Other persistent files (e.g. /var/tmp) and static data that should not 39 | # be put in the world-wide Nix store 40 | "/persist" = { 41 | subvol = "persist"; 42 | mountOptions = ["noatime"]; 43 | neededForBoot = true; 44 | }; 45 | "/git-annex/${hostName}" = { 46 | subvol = "git-annex"; 47 | mountOptions = ["noatime"]; 48 | }; 49 | }; 50 | 51 | environment.persistence."/cache" = { 52 | directories = [ 53 | "/var/cache" 54 | "/var/db/dhcpcd" 55 | ]; 56 | }; 57 | 58 | environment.persistence."/persist" = { 59 | directories = [ 60 | "/var/tmp" 61 | "/var/lib/nixos" 62 | ]; 63 | files = [ 64 | "/etc/ssh/ssh_host_ed25519_key" 65 | "/etc/ssh/ssh_host_ed25519_key.pub" 66 | ]; 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /machines/yang/fs/default.nix: -------------------------------------------------------------------------------- 1 | {config, ...}: let 2 | sataSsd = "/dev/disk/by-id/ata-Samsung_SSD_860_QVO_1TB_S59HNG0N413450P"; 3 | cryptBtrfs = "crypted"; 4 | in { 5 | imports = [ 6 | (import ./btrfs.nix { 7 | device = "/dev/mapper/${cryptBtrfs}"; 8 | hostName = config.networking.hostName; 9 | }) 10 | ./rpool4.nix 11 | ]; 12 | 13 | boot.initrd.luks.devices.${cryptBtrfs} = { 14 | device = "${sataSsd}-part3"; 15 | allowDiscards = true; 16 | }; 17 | 18 | fileSystems = { 19 | "/" = { 20 | device = "tmpfs"; 21 | fsType = "tmpfs"; 22 | options = ["defaults" "size=1G" "mode=755"]; 23 | }; 24 | 25 | "/boot" = { 26 | device = "${sataSsd}-part1"; 27 | fsType = "vfat"; 28 | options = ["fmask=0137" "dmask=0027"]; 29 | }; 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /machines/yang/fs/rpool4.nix: -------------------------------------------------------------------------------- 1 | { 2 | boot.zfs = { 3 | requestEncryptionCredentials = [ 4 | "rpool4" 5 | ]; 6 | }; 7 | services.zfs = { 8 | autoSnapshot.enable = true; 9 | autoScrub.enable = true; 10 | }; 11 | 12 | boot.kernelParams = [ 13 | # 3 GiB 14 | "zfs.zfs_arc_max=3221225472" 15 | ]; 16 | 17 | fileSystems = 18 | builtins.mapAttrs (_mountPoint: device: { 19 | inherit device; 20 | fsType = "zfs"; 21 | }) { 22 | "/var/log" = "rpool4/log"; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /machines/yang/lgtm-stack.nix: -------------------------------------------------------------------------------- 1 | # Configuration of the LGTM (Logs, Grafana, Traces, and Metrics) stack 2 | # 3 | # This configuration is mostly based on the following resources: 4 | # 5 | # https://xeiaso.net/blog/prometheus-grafana-loki-nixos-2020-11-20/ 6 | # https://gist.github.com/rickhull/895b0cb38fdd537c1078a858cf15d63e 7 | { config, ... }: 8 | let 9 | grafanaSettings = config.services.grafana.settings; 10 | 11 | prometheusExporters = config.services.prometheus.exporters; 12 | 13 | domain = "nicesunny.day"; 14 | in 15 | { 16 | imports = [ ../../nixos/profiles/reverse-proxy ]; 17 | 18 | services.reverse-proxy.subdomains.grafana = { 19 | # TODO: Proxy web sockets? 20 | reverse-proxy = "localhost:${toString grafanaSettings.server.http_port}"; 21 | }; 22 | 23 | # Set the domain to avoid "Origin not allowed" error. 24 | services.grafana = { 25 | enable = true; 26 | settings.server = { 27 | domain = "grafana.${domain}"; 28 | http_addr = "127.0.0.1"; 29 | http_port = 2342; 30 | }; 31 | }; 32 | 33 | services.prometheus = { 34 | enable = true; 35 | port = 9001; 36 | 37 | exporters = { 38 | node = { 39 | enable = true; 40 | enabledCollectors = [ "systemd" ]; 41 | port = 9002; 42 | }; 43 | }; 44 | 45 | scrapeConfigs = [ 46 | { 47 | job_name = "node-localhost"; 48 | static_configs = [ { targets = [ "127.0.0.1:${toString prometheusExporters.node.port}" ]; } ]; 49 | } 50 | ]; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /machines/zheng/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | lib, 4 | ... 5 | }: let 6 | stateVersion = "25.05"; 7 | in { 8 | imports = [ 9 | # (modulesPath + "/profiles/headless.nix") 10 | # ../../nixos/profiles/nix/cachix-deploy.nix 11 | ../../nixos/profiles/openssh 12 | ./router.nix 13 | ]; 14 | 15 | nixpkgs.overlays = [ 16 | (_final: super: { 17 | makeModulesClosure = x: 18 | super.makeModulesClosure (x // {allowMissing = true;}); 19 | }) 20 | ]; 21 | 22 | boot.loader.timeout = 6; 23 | 24 | # Replace the raspberry-pi-4 nixos-hardware module with an explicit list of 25 | # kernel modules. See 26 | # https://www.eisfunke.com/posts/2023/nixos-on-raspberry-pi-4.html 27 | boot.initrd.availableKernelModules = [ 28 | "usbhid" 29 | "usb_storage" 30 | "vc4" 31 | "pcie_brcmstb" 32 | "reset-raspberrypi" 33 | ]; 34 | 35 | boot.supportedFilesystems = { 36 | btrfs = true; 37 | vfat = true; 38 | # Force no ZFS 39 | zfs = lib.mkForce false; 40 | # Just unnecessary for the system 41 | ntfs = lib.mkForce false; 42 | reiserfs = lib.mkForce false; 43 | cifs = lib.mkForce false; 44 | }; 45 | 46 | hardware.deviceTree = { 47 | kernelPackage = pkgs.linux_rpi4; 48 | }; 49 | 50 | hardware.enableRedistributableFirmware = true; 51 | 52 | system.stateVersion = stateVersion; 53 | 54 | time.timeZone = "Asia/Tokyo"; 55 | 56 | nix.settings.allowed-users = ["root"]; 57 | 58 | services.journald.extraConfig = '' 59 | SystemMaxUse=1G 60 | MaxFileSec=10day 61 | ''; 62 | 63 | boot.tmp.cleanOnBoot = true; 64 | 65 | powerManagement.cpuFreqGovernor = "ondemand"; 66 | 67 | zramSwap.enable = true; 68 | 69 | sdImage.compressImage = false; 70 | } 71 | -------------------------------------------------------------------------------- /machines/zheng/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | channel = inputs.stable; 4 | in 5 | { 6 | flake = { 7 | nixosConfigurations.zheng = channel.lib.nixosSystem { 8 | system = "aarch64-linux"; 9 | 10 | specialArgs = { 11 | hostPubkey = inputs.self.lib.hostPubkeys.zheng; 12 | }; 13 | 14 | modules = [ 15 | ./. 16 | inputs.self.nixosModules.default 17 | (channel + "/nixos/modules/installer/sd-card/sd-image-aarch64.nix") 18 | { 19 | networking.hostName = "zheng"; 20 | } 21 | ]; 22 | }; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /machines/zheng/router.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | # This configuration is mostly based on the following awesome blog post: 3 | # https://github.com/ghostbuster91/blogposts/blob/a2374f0039f8cdf4faddeaaa0347661ffc2ec7cf/router2023-part2/main.md 4 | let 5 | metadata = lib.importTOML ../metadata.toml; 6 | 7 | routerAddress = metadata.hosts.zheng.ipAddress; 8 | 9 | subnet = metadata.networks.home.subnet; 10 | 11 | modules = [ 12 | "uas" 13 | "genet" 14 | ]; 15 | 16 | adguardhome = config.services.adguardhome; 17 | 18 | # To disable name resolution of *.nicesunny.day with CoreDNS, make this to 19 | # false 20 | useInternalDns = true; 21 | in 22 | { 23 | imports = [ 24 | ./usb-wifi.nix 25 | ../../nixos/profiles/adguard-home 26 | ]; 27 | 28 | boot.kernelModules = modules; 29 | 30 | # https://github.com/ghostbuster91/blogposts/blob/a2374f0039f8cdf4faddeaaa0347661ffc2ec7cf/router2023-part2/main.md#kernel 31 | boot.kernel = { 32 | sysctl = { 33 | "net.ipv4.conf.all.forwarding" = true; 34 | "net.ipv6.conf.all.forwarding" = false; 35 | 36 | # Filter out Martian packets. See 37 | # https://github.com/ghostbuster91/blogposts/blob/a2374f0039f8cdf4faddeaaa0347661ffc2ec7cf/router2023-part2/main.md#security 38 | "net.ipv4.conf.default.rp_filter" = 1; 39 | "net.ipv4.conf.wan.rp_filter" = 1; 40 | "net.ipv4.conf.br-lan.rp_filter" = 0; 41 | }; 42 | }; 43 | 44 | # https://github.com/ghostbuster91/blogposts/blob/a2374f0039f8cdf4faddeaaa0347661ffc2ec7cf/router2023-part2/main.md#interfaces 45 | systemd.network = { 46 | wait-online.anyInterface = true; 47 | 48 | netdevs = { 49 | # Create the bridge interface 50 | "20-br-lan" = { 51 | netdevConfig = { 52 | Kind = "bridge"; 53 | Name = "br-lan"; 54 | }; 55 | }; 56 | }; 57 | 58 | links = { 59 | # Enable USB tethering. 60 | "40-usb0" = { 61 | matchConfig = { 62 | Driver = "rndis_host"; 63 | }; 64 | linkConfig = { 65 | Name = "usb0"; 66 | }; 67 | }; 68 | }; 69 | 70 | networks = { 71 | "30-lan0" = { 72 | matchConfig.Name = "end0"; 73 | linkConfig.RequiredForOnline = "enslaved"; 74 | networkConfig = { 75 | Bridge = "br-lan"; 76 | ConfigureWithoutCarrier = true; 77 | }; 78 | }; 79 | # There is also a built-in wifi, wlan0, but it doesn't allow enslaving to 80 | # a bridge. 81 | "40-br-lan" = { 82 | matchConfig.Name = "br-lan"; 83 | bridgeConfig = { }; 84 | address = [ "${routerAddress}/24" ]; 85 | networkConfig = { 86 | ConfigureWithoutCarrier = true; 87 | }; 88 | }; 89 | "50-wan" = { 90 | matchConfig.Name = "usb0"; 91 | networkConfig = { 92 | # start a DHCP Client for IPv4 Addressing/Routing 93 | DHCP = "ipv4"; 94 | DNSOverTLS = true; 95 | DNSSEC = true; 96 | IPv6PrivacyExtensions = false; 97 | IPv4Forwarding = true; 98 | }; 99 | # make routing on this interface a dependency for network-online.target 100 | linkConfig.RequiredForOnline = "routable"; 101 | }; 102 | }; 103 | }; 104 | 105 | networking = { 106 | useNetworkd = true; 107 | useDHCP = false; 108 | 109 | nat.enable = false; 110 | firewall.enable = false; 111 | 112 | nftables = { 113 | enable = true; 114 | # https://wiki.nftables.org/wiki-nftables/index.php/Simple_ruleset_for_a_home_router 115 | ruleset = '' 116 | define DEV_PRIVATE = br-lan 117 | define DEV_WORLD = usb0 118 | define NET_PRIVATE = ${subnet} 119 | 120 | table ip global { 121 | 122 | chain inbound_world { 123 | # accepting ping (icmp-echo-request) for diagnostic purposes. 124 | # However, it also lets probes discover this host is alive. 125 | # This sample accepts them within a certain rate limit: 126 | # 127 | # icmp type echo-request limit rate 5/second accept 128 | 129 | # allow SSH connections from some well-known internet host 130 | # ip saddr 81.209.165.42 tcp dport ssh accept 131 | } 132 | 133 | chain inbound_private { 134 | # accepting ping (icmp-echo-request) for diagnostic purposes. 135 | icmp type echo-request limit rate 5/second accept 136 | 137 | # allow DHCP, DNS and SSH from the private network 138 | # also allow access to the admin of AdguardHome 139 | ip protocol . th dport vmap { tcp . 22 : accept, udp . 53 : accept, tcp . 53 : accept, udp . 67 : accept, tcp . 3000 : accept } 140 | } 141 | 142 | chain inbound { 143 | type filter hook input priority 0; policy drop; 144 | 145 | # Allow traffic from established and related packets, drop invalid 146 | ct state vmap { established : accept, related : accept, invalid : drop } 147 | 148 | # allow loopback traffic, anything else jump to chain for further evaluation 149 | iifname vmap { lo : accept, $DEV_WORLD : jump inbound_world, $DEV_PRIVATE : jump inbound_private } 150 | 151 | # the rest is dropped by the above policy 152 | } 153 | 154 | chain forward { 155 | type filter hook forward priority 0; policy drop; 156 | 157 | # Allow traffic from established and related packets, drop invalid 158 | ct state vmap { established : accept, related : accept, invalid : drop } 159 | 160 | # connections from the internal net to the internet or to other 161 | # internal nets are allowed 162 | iifname $DEV_PRIVATE accept 163 | 164 | # the rest is dropped by the above policy 165 | } 166 | 167 | chain postrouting { 168 | type nat hook postrouting priority 100; policy accept; 169 | 170 | # masquerade private IP addresses 171 | ip saddr $NET_PRIVATE oifname $DEV_WORLD masquerade 172 | } 173 | } 174 | ''; 175 | }; 176 | }; 177 | 178 | # systemd-resolved listens on port 53, which conflicts with dnsmasq, so 179 | # disable it. 180 | services.resolved.enable = false; 181 | 182 | # dhcp-hosts contains the MAC address of each host. It's probably safe to put 183 | # them in a public repository, but just in case. 184 | age.secrets = { 185 | "dhcp-hosts" = { 186 | rekeyFile = ./secrets/dhcp-hosts.age; 187 | owner = "dnsmasq"; 188 | group = "dnsmasq"; 189 | }; 190 | }; 191 | 192 | services.dnsmasq = { 193 | enable = true; 194 | 195 | resolveLocalQueries = !useInternalDns; 196 | 197 | settings = { 198 | # upstream DNS servers 199 | server = 200 | ( 201 | if adguardhome.enable then 202 | [ "127.0.0.1#${builtins.toString adguardhome.settings.dns.port}" ] 203 | else 204 | [ 205 | "1.1.1.1" 206 | "8.8.8.8" 207 | "9.9.9.9" 208 | ] 209 | ) 210 | ++ (lib.optional useInternalDns "/nicesunny.day/${metadata.hosts.yang.ipAddress}"); 211 | # sensible behaviours 212 | domain-needed = true; 213 | bogus-priv = true; 214 | no-resolv = true; 215 | 216 | # Use as the primary DNS for the network 217 | port = 53; 218 | 219 | # Cache dns queries. 220 | cache-size = 1000; 221 | 222 | dhcp-range = [ "br-lan,192.168.10.50,192.168.10.254,24h" ]; 223 | interface = "br-lan"; 224 | dhcp-host = routerAddress; 225 | dhcp-authoritative = true; 226 | # dhcp-sequential-ip = true; 227 | dhcp-option = [ 228 | "3,${routerAddress}" 229 | "6,${routerAddress}" 230 | ]; 231 | 232 | dhcp-hostsfile = config.age.secrets."dhcp-hosts".path; 233 | 234 | # local domains 235 | # https://datatracker.ietf.org/doc/html/rfc6762#appendix-G 236 | local = lib.mkIf (!useInternalDns) "/nicesunny.day/"; 237 | domain = "nicesunny.day"; 238 | expand-hosts = true; 239 | 240 | # don't use /etc/hosts as this would advertise surfer as localhost 241 | no-hosts = true; 242 | address = [ 243 | "/zheng/${routerAddress}" 244 | "/zheng.nicesunny.day/${routerAddress}" 245 | ]; 246 | }; 247 | }; 248 | 249 | services.hostapd = { 250 | enable = true; 251 | radios = { 252 | wlp1s0u1u4 = { 253 | band = "2g"; 254 | countryCode = "JP"; 255 | channel = 8; 256 | 257 | settings.bridge = "br-lan"; 258 | 259 | wifi4 = { 260 | enable = true; 261 | capabilities = [ 262 | "RX-STBC1" 263 | "SHORT-GI-40" 264 | "SHORT-GI-20" 265 | "DSSS_CCK-40" 266 | "MAX-AMSDU-7935" 267 | ]; 268 | }; 269 | 270 | networks = { 271 | wlp1s0u1u4 = { 272 | ssid = "nicky"; 273 | authentication = { 274 | # Use the transition mode to support older devices. wpa3-sae is 275 | # more secure and hence would be more desirable. 276 | mode = "wpa3-sae-transition"; 277 | saePasswordsFile = "/etc/hostapd/password"; 278 | # Provide both sae and wpa passwords for the transition mode. 279 | wpaPasswordFile = "/etc/hostapd/password"; 280 | }; 281 | }; 282 | }; 283 | }; 284 | }; 285 | }; 286 | 287 | services.adguardhome.settings = lib.mkIf adguardhome.enable { 288 | dns.bind_hosts = [ 289 | "127.0.0.1" 290 | "192.168.10.1" 291 | ]; 292 | }; 293 | } 294 | -------------------------------------------------------------------------------- /machines/zheng/secrets/dhcp-hosts.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirak/homelab/982762f4dc21623c268a852ceffeafff210fe3c5/machines/zheng/secrets/dhcp-hosts.age -------------------------------------------------------------------------------- /machines/zheng/usb-wifi.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | ... 5 | }: { 6 | environment.systemPackages = [ 7 | # Add lshw for ease of debugging. Use `lshw -c network` to find 8 | # `driver=8192eu` 9 | pkgs.lshw 10 | ]; 11 | 12 | boot.extraModulePackages = [ 13 | (config.boot.kernelPackages.rtl8192eu.overrideAttrs (old: { 14 | # Set flags specific to Raspberry Pi. 15 | makeFlags = 16 | (old.makeFlags or []) 17 | ++ [ 18 | "CONFIG_PLATFORM_I386_PC=n" 19 | "CONFIG_PLATFORM_ARM_RPI=y" 20 | ]; 21 | 22 | src = old.src.override { 23 | rev = "7ef82518547dcb5aacd8797e370332337b37d601"; 24 | sha256 = "sha256-HK4VYEfe7tcXxQBqQ9reaOypubkKVRqa6zyNaQUhlxQ="; 25 | }; 26 | 27 | meta.broken = false; 28 | })) 29 | ]; 30 | 31 | boot.blacklistedKernelModules = [ 32 | "rtl8xxxu" 33 | ]; 34 | } 35 | -------------------------------------------------------------------------------- /nixos/models/asus-br1100/flake-module.nix: -------------------------------------------------------------------------------- 1 | { inputs, ... }: 2 | let 3 | inherit (inputs) stable; 4 | 5 | overlayModule = { 6 | nixpkgs.overlays = [ inputs.self.overlays.default ]; 7 | }; 8 | in 9 | { 10 | flake = { 11 | nixosModules = { 12 | asus-br1100 = import ./modules { inherit (inputs) nixos-hardware; }; 13 | }; 14 | 15 | packages.x86_64-linux = { 16 | asus-br1100-iso = 17 | (stable.lib.nixosSystem { 18 | system = "x86_64-linux"; 19 | modules = [ 20 | overlayModule 21 | inputs.self.nixosModules.asus-br1100 22 | ../../suites/iso 23 | ]; 24 | }).config.system.build.isoImage; 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /nixos/models/asus-br1100/modules/acpi_call.nix: -------------------------------------------------------------------------------- 1 | {config, ...}: { 2 | boot.kernelModules = ["acpi_call"]; 3 | boot.extraModulePackages = with config.boot.kernelPackages; [ 4 | acpi_call 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /nixos/models/asus-br1100/modules/default.nix: -------------------------------------------------------------------------------- 1 | {nixos-hardware}: {...}: { 2 | imports = [ 3 | (nixos-hardware.outPath + "/common/pc/laptop") 4 | (nixos-hardware.outPath + "/common/gpu/intel") 5 | ./r8168.nix 6 | ./wireless.nix 7 | ./acpi_call.nix 8 | ]; 9 | 10 | # I don't know if this parameter is necessary. 11 | boot.kernelParams = ["nouveau.modeset=0"]; 12 | 13 | # boot.kernelPackages = pkgs.linuxKernel.packages.linux_6_0; 14 | } 15 | -------------------------------------------------------------------------------- /nixos/models/asus-br1100/modules/r8168.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | ... 5 | }: 6 | { 7 | # At present, wired interface does not work even with this kernel module due 8 | # to a common "ucsi_acpi usbc000:00: ppm init failed" error. This issue may be 9 | # fixed at some point, but I am not sure. 10 | boot.extraModulePackages = [ 11 | (config.boot.kernelPackages.r8168.overrideAttrs ( 12 | _: super: rec { 13 | version = "8.054.00"; 14 | src = pkgs.fetchFromGitHub { 15 | owner = "mtorromeo"; 16 | repo = "r8168"; 17 | rev = version; 18 | sha256 = "sha256-KyycAe+NBmyDDH/XkAM4PpGvXI5J1CuMW4VuHcOm0UQ="; 19 | }; 20 | meta = super.meta // { 21 | broken = false; 22 | }; 23 | } 24 | )) 25 | ]; 26 | boot.blacklistedKernelModules = [ "r8169" ]; 27 | } 28 | -------------------------------------------------------------------------------- /nixos/models/asus-br1100/modules/wireless.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | boot.kernelModules = ["iwlwifi"]; 3 | hardware.firmware = [pkgs.wireless-regdb]; 4 | hardware.enableRedistributableFirmware = true; 5 | } 6 | -------------------------------------------------------------------------------- /nixos/profiles/acme/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | let 3 | defaultEmail = "akira.komamura@gmail.com"; 4 | in 5 | { 6 | security.acme = { 7 | acceptTerms = true; 8 | defaults.email = defaultEmail; 9 | }; 10 | 11 | users.users.nginx = lib.mkIf config.services.nginx.enable { extraGroups = [ "acme" ]; }; 12 | } 13 | -------------------------------------------------------------------------------- /nixos/profiles/acme/internal.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | let 3 | domain = "nicesunny.day"; 4 | 5 | credentialsPath = "nicesunny.day.credentials.txt"; 6 | in 7 | { 8 | imports = [ ./. ]; 9 | 10 | age.secrets = { 11 | ${credentialsPath} = { 12 | rekeyFile = ./secrets/nicesunny.day.credentials.txt.age; 13 | # path = "/etc/acme/secrets/nicesunnyday.txt"; 14 | # mode = ""; 15 | # owner = ""; 16 | # group = ""; 17 | }; 18 | }; 19 | 20 | security.acme.certs.${domain} = { 21 | inherit domain; 22 | extraDomainNames = [ "*.${domain}" ]; 23 | dnsProvider = "cloudflare"; 24 | dnsResolver = "1.1.1.1:53"; 25 | # We don't need to wait for propagation since this is a local DNS server 26 | dnsPropagationCheck = false; 27 | environmentFile = config.age.secrets.${credentialsPath}.path; 28 | }; 29 | 30 | services.caddy = { 31 | package = pkgs.caddy.withPlugins { 32 | plugins = [ 33 | "github.com/caddy-dns/cloudflare@v0.0.0-20250228175314-1fb64108d4de" 34 | ]; 35 | hash = "sha256-YYpsf8HMONR1teMiSymo2y+HrKoxuJMKIea5/NEykGc="; 36 | }; 37 | globalConfig = '' 38 | acme_dns cloudflare {env.CLOUDFLARE_DNS_API_TOKEN} 39 | ''; 40 | }; 41 | 42 | systemd.services.caddy.serviceConfig = { 43 | EnvironmentFile = [ 44 | config.age.secrets.${credentialsPath}.path 45 | ]; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /nixos/profiles/acme/secrets/nicesunny.day.credentials.txt.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirak/homelab/982762f4dc21623c268a852ceffeafff210fe3c5/nixos/profiles/acme/secrets/nicesunny.day.credentials.txt.age -------------------------------------------------------------------------------- /nixos/profiles/adb/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | homeUser, 4 | ... 5 | }: { 6 | programs.adb.enable = true; 7 | users.users.${homeUser}.extraGroups = [ 8 | "adbusers" 9 | ]; 10 | home-manager.users.${homeUser} = { 11 | home.packages = [ 12 | pkgs.android-studio 13 | ]; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /nixos/profiles/adguard-home/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.adguardhome = { 3 | enable = true; 4 | mutableSettings = false; 5 | settings = { 6 | dhcp = { 7 | enabled = false; 8 | }; 9 | dns = { 10 | # Use the AdguardHome DNS only for external traffic 11 | port = 5353; 12 | bootstrap_dns = [ 13 | # Cloudflare 14 | "1.1.1.1" 15 | "1.0.0.1" 16 | ]; 17 | upstream_dns = [ 18 | "1.1.1.1" 19 | "8.8.8.8" 20 | "9.9.9.9" 21 | ]; 22 | upstream_mode = "fastest_addr"; 23 | }; 24 | }; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /nixos/profiles/agenix/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | age.identityPaths = [ 3 | "/etc/ssh/ssh_host_ed25519_key" 4 | ]; 5 | } 6 | -------------------------------------------------------------------------------- /nixos/profiles/containers/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation.containers.enable = true; 3 | } 4 | -------------------------------------------------------------------------------- /nixos/profiles/containers/rootless.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./. 4 | ]; 5 | 6 | virtualisation.containers = { 7 | # Based on https://carlosvaz.com/posts/rootless-podman-and-docker-compose-on-nixos/ 8 | storage.settings = { 9 | storage = { 10 | driver = "overlay"; 11 | runroot = "/run/containers/storage"; 12 | graphroot = "/var/lib/containers/storage"; 13 | # The size can be large, so don't store the directory on tmpfs. 14 | # Instead, you can create a separate file system. 15 | # rootless_storage_path = "/tmp/containers-$USER"; 16 | options.overlay.mountopt = "nodev,metacopy=on"; 17 | }; 18 | }; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /nixos/profiles/desktop/plasma.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: { 6 | services.xserver.displayManager.sddm.enable = true; 7 | services.xserver.desktopManager.plasma5.enable = true; 8 | 9 | services.xrdp.defaultWindowManager = 10 | lib.mkIf config.services.xrdp.enable "startplasma-x11"; 11 | } 12 | -------------------------------------------------------------------------------- /nixos/profiles/docker/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation.docker.enable = true; 3 | } 4 | -------------------------------------------------------------------------------- /nixos/profiles/docker/kind.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ./. 4 | ]; 5 | 6 | environment.systemPackages = [ 7 | pkgs.kind 8 | pkgs.kubectl 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/docker/rootless.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./default.nix 4 | ]; 5 | 6 | virtualisation.docker.rootless = { 7 | enable = true; 8 | setSocketVariable = true; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/dpt-rp1/default.nix: -------------------------------------------------------------------------------- 1 | # Connectivity with Fujitsu Quaderno using dpt-rp1-py 2 | # https://github.com/janten/dpt-rp1-py 3 | { pkgs, ... }: 4 | { 5 | environment.systemPackages = [ 6 | pkgs.dpt-rp1-py 7 | 8 | # I use this program to set the mode of the device to CDC/ECM manually. See 9 | # https://github.com/janten/dpt-rp1-py/blob/master/docs/linux-ethernet-over-usb.md#switching-the-usb-mode-the-ethernet-over-usb 10 | # for an instruction. 11 | pkgs.picocom 12 | ]; 13 | 14 | services.avahi = { 15 | enable = true; 16 | # Check the interface name 17 | allowInterfaces = [ 18 | "usb1" 19 | ]; 20 | # Only IPv6 is used by the program 21 | ipv6 = true; 22 | nssmdns6 = true; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /nixos/profiles/flatpak/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | # You may have to restart the window manager to enable environment variables 3 | # (e.g. XDG_DATA_DIRS) required to run 4 | services.flatpak.enable = true; 5 | } 6 | -------------------------------------------------------------------------------- /nixos/profiles/home-manager/default.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Default integration with home-manager 3 | 4 | You also have to import home-manager.nixosModules.home-manager 5 | */ 6 | { 7 | homeUser, 8 | config, 9 | pkgs, 10 | lib, 11 | ... 12 | }: { 13 | imports = [ 14 | ../nixpkgs/channels.nix 15 | ]; 16 | 17 | users.defaultUserShell = 18 | if config.programs.zsh.enable 19 | then pkgs.zsh 20 | else pkgs.bash; 21 | 22 | programs.zsh.enable = true; 23 | 24 | users.users.${homeUser}.extraGroups = 25 | (lib.optional config.virtualisation.docker.enable "docker") 26 | ++ (lib.optionals config.virtualisation.virtualbox.host.enable [ 27 | "vboxusers" 28 | "vboxsf" 29 | ]); 30 | 31 | home-manager = { 32 | useGlobalPkgs = true; 33 | useUserPackages = true; 34 | 35 | users.${homeUser} = { 36 | imports = [ 37 | ../../../homes/core.nix 38 | ]; 39 | 40 | programs.nixos-rebuild-and-notify.enable = true; 41 | 42 | home.stateVersion = lib.mkDefault config.system.stateVersion; 43 | }; 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /nixos/profiles/intel-arc/default.nix: -------------------------------------------------------------------------------- 1 | # Based on https://github.com/VTimofeenko/monorepo-machine-config/blob/4c1f85c700c45a5d3a8a38956194d2c97753b8ba/nixosConfigurations/neon/configuration/hw-acceleration.nix#L24 2 | # 3 | # Also add inputs.nixos-hardware.nixosModules.common-gpu-intel to the module 4 | # list in flake.nix 5 | { pkgs, ... }: 6 | { 7 | hardware.graphics = { 8 | enable = true; 9 | extraPackages = with pkgs; [ 10 | intel-media-driver 11 | intel-ocl 12 | # nixos-unstable 13 | vpl-gpu-rt 14 | intel-media-sdk 15 | intel-compute-runtime 16 | intel-vaapi-driver 17 | ]; 18 | }; 19 | 20 | boot.kernelParams = [ 21 | # Check the ID by running `lspci -k | grep -EA3 'VGA|3D|Display'` 22 | "i915.force_probe=6021" 23 | "i915.enable_guc=3" 24 | ]; 25 | 26 | environment.sessionVariables = { 27 | VDPAU_DRIVER = "va_gl"; 28 | LIBVA_DRIVER_NAME = "iHD"; 29 | }; 30 | hardware.intelgpu.driver = "xe"; 31 | 32 | # Use the latest kernel for the intel driver that supports ZFS 33 | boot.kernelPackages = pkgs.linuxPackages_6_12; 34 | 35 | environment.systemPackages = with pkgs; [ 36 | libva-utils 37 | intel-gpu-tools 38 | ]; 39 | } 40 | -------------------------------------------------------------------------------- /nixos/profiles/k3s/single-node-for-testing.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ./single-node.nix 4 | ]; 5 | 6 | services.k3s = { 7 | # https://0to1.nl/post/k3s-kubectl-permission/ 8 | environmentFile = pkgs.writeText "environment" '' 9 | K3S_KUBECONFIG_MODE="644" 10 | ''; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /nixos/profiles/k3s/single-node.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Single-node k3s configuration. 3 | 4 | Based on https://nixos.wiki/wiki/K3s#Single_node_setup 5 | */ 6 | {pkgs, ...}: { 7 | # This is required so that pod can reach the API server (running on port 6443 by default) 8 | networking.firewall.allowedTCPPorts = [6443]; 9 | services.k3s.enable = true; 10 | services.k3s.role = "server"; 11 | services.k3s.extraFlags = toString [ 12 | # "--kubelet-arg=v=4" # Optionally add additional args to k3s 13 | ]; 14 | environment.systemPackages = [pkgs.k3s]; 15 | } 16 | -------------------------------------------------------------------------------- /nixos/profiles/livebook/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | imports = [ 3 | ./interface.nix 4 | ]; 5 | } 6 | -------------------------------------------------------------------------------- /nixos/profiles/livebook/interface.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Options taken from pleroma.nix 3 | at 4 | in https://github.com/NixOS/nixpkgs 5 | */ 6 | { 7 | config, 8 | lib, 9 | pkgs, 10 | ... 11 | }: let 12 | cfg = config.services.my-livebook; 13 | 14 | openScript = pkgs.writers.writeBashBin "open-livebook" '' 15 | set -euo pipefail 16 | 17 | LIVEBOOK_SERVICE="''${LIVEBOOK_SERVICE:-livebook.service}" 18 | 19 | if [[ ! -v DISPLAY ]] && [[ ! -v WAYLAND_DISPLAY ]] 20 | then 21 | echo "This command can be run only in a graphical environment" >&2 22 | exit 1 23 | fi 24 | 25 | err() { 26 | echo "$@" >&2 27 | ${pkgs.notify-desktop}/bin/notify-desktop --app-name=Livebook "$@" 28 | exit 1 29 | } 30 | 31 | if ! systemctl is-active "''${LIVEBOOK_SERVICE}" >/dev/null 32 | then 33 | err "''${LIVEBOOK_SERVICE} is not running" 34 | fi 35 | 36 | if [[ $(systemctl show "''${LIVEBOOK_SERVICE}" --property=MainPID) =~ MainPID=([[:digit:]]+) ]] 37 | then 38 | pid=''${BASH_REMATCH[1]} 39 | else 40 | err "Failed to parse the main PID of the service" 41 | fi 42 | 43 | out="$(journalctl --no-pager -t livebook -g "Application running at" | tail -1)" 44 | 45 | if [[ -z "$out" ]] 46 | then 47 | ${pkgs.notify-desktop}/bin/notify-desktop 'Restarting livebook service to retrieve the PID' 48 | systemctl restart --wait "''${LIVEBOOK_SERVICE}" 49 | LIVEBOOK_SERVICE="''${LIVEBOOK_SERVICE}" exec "$0" 50 | fi 51 | 52 | if [[ $out =~ livebook\[([[:digit:]]+)\] ]] \ 53 | && [[ ''${BASH_REMATCH[1]} = $pid ]] \ 54 | && [[ $out =~ http://[^[:space:]]+ ]] 55 | then 56 | url="''${BASH_REMATCH[0]}" 57 | else 58 | err "Failed to parse the output of journalctl" 59 | fi 60 | 61 | echo "Opening $url" 62 | 63 | if ! ${pkgs.handlr}/bin/handlr open "$url" 64 | then 65 | err "Failed to open the URL $url" 66 | fi 67 | ''; 68 | in { 69 | options = { 70 | services.my-livebook = with lib; { 71 | enable = mkEnableOption (lib.mdDoc "Elixir Livebook"); 72 | 73 | package = mkOption { 74 | type = types.package; 75 | default = pkgs.livebook; 76 | defaultText = literalExpression "pkgs.livebook"; 77 | description = lib.mdDoc "Livebook package to use."; 78 | }; 79 | 80 | user = mkOption { 81 | type = types.str; 82 | default = "livebook"; 83 | }; 84 | 85 | group = mkOption { 86 | type = types.str; 87 | default = "livebook"; 88 | }; 89 | 90 | dataDir = mkOption { 91 | type = types.str; 92 | default = "/var/lib/livebook/data"; 93 | readOnly = true; 94 | description = "Directory to be used as LIVEBOOK_DATA_PATH."; 95 | }; 96 | 97 | settings = { 98 | ipAddress = mkOption { 99 | type = types.str; 100 | default = "127.0.0.1"; 101 | description = "LIVEBOOK_IP"; 102 | }; 103 | 104 | port = mkOption { 105 | type = types.port; 106 | default = 0; 107 | description = "LIVEBOOK_PORT"; 108 | }; 109 | 110 | homeDirectory = mkOption { 111 | type = types.str; 112 | default = "/var/lib/livebook"; 113 | description = "LIVEBOOK_HOME"; 114 | }; 115 | 116 | enableNix = mkOption { 117 | type = types.bool; 118 | default = false; 119 | description = "Enable Nix package manager for the user."; 120 | }; 121 | 122 | extraPackages = mkOption { 123 | type = types.listOf types.package; 124 | default = []; 125 | description = lib.mdDoc "List of packages that are made available to the user."; 126 | }; 127 | }; 128 | }; 129 | }; 130 | 131 | config = lib.mkIf cfg.enable { 132 | ids = { 133 | # Check nixos/modules/misc/ids.nix in nixpkgs to ensure there is no 134 | # collision 135 | # 136 | # If the user/group has been already created with a different numeric ID, 137 | # first disable the livebook service to remove the user and group and 138 | # then re-enable it to recreate them. 139 | uids.livebook = 293; 140 | gids.livebook = 293; 141 | }; 142 | 143 | users = { 144 | users.${cfg.user} = { 145 | description = "Livebook user"; 146 | group = cfg.group; 147 | isSystemUser = true; 148 | createHome = true; 149 | home = "/var/lib/livebook"; 150 | homeMode = "750"; 151 | # Provide a shell with dependencies to allow administration. For 152 | # example, you can enter a shell with `sudo su - livebook` and install 153 | # hex by running `mix local.hex`. 154 | useDefaultShell = true; 155 | packages = cfg.package.nativeBuildInputs ++ cfg.package.buildInputs; 156 | uid = config.ids.uids.livebook; 157 | }; 158 | groups.${cfg.group} = { 159 | gid = config.ids.gids.livebook; 160 | }; 161 | }; 162 | 163 | nix.settings.allowed-users = lib.optionals cfg.settings.enableNix [ 164 | cfg.user 165 | ]; 166 | 167 | environment.systemPackages = [ 168 | openScript 169 | (pkgs.makeDesktopItem { 170 | name = "open-livebook"; 171 | desktopName = "Open Livebook"; 172 | exec = "open-livebook"; 173 | tryExec = "${openScript}/bin/open-livebook"; 174 | }) 175 | ]; 176 | 177 | # Without epmd already running, livebook tries to start it on its own, which 178 | # can conflict with another instance of epmd required by other services, 179 | # e.g. rabbitmq. 180 | services.epmd.enable = true; 181 | 182 | systemd.services.livebook = { 183 | description = "Elixir Livebook"; 184 | wantedBy = ["multi-user.target"]; 185 | requires = [ 186 | "epmd.socket" 187 | ]; 188 | after = [ 189 | "epmd.socket" 190 | ]; 191 | 192 | path = 193 | [ 194 | # osmon fails if /bin is not in the PATH. 195 | # Based on information at 196 | # 197 | "" 198 | ] 199 | # This is not a proper way to add Nix packages to the environment, but I 200 | # was unable to find other way. Adding packages to 201 | # users.users.livebook.packages didn't work :( 202 | ++ cfg.settings.extraPackages 203 | ++ (lib.optionals cfg.settings.enableNix [ 204 | config.nix.package 205 | "${cfg.settings.homeDirectory}/.nix-profile" 206 | ]); 207 | 208 | environment = { 209 | LIVEBOOK_DATA_PATH = cfg.dataDir; 210 | LIVEBOOK_IP = cfg.settings.ipAddress; 211 | LIVEBOOK_PORT = builtins.toString cfg.settings.port; 212 | LIVEBOOK_HOME = cfg.settings.homeDirectory; 213 | RELEASE_COOKIE = "${cfg.settings.homeDirectory}/.cookie"; 214 | }; 215 | 216 | serviceConfig = { 217 | User = cfg.user; 218 | Group = cfg.group; 219 | 220 | Type = "exec"; 221 | 222 | StandardOutput = "journal"; 223 | StandardError = "journal"; 224 | 225 | ExecStart = "${cfg.package}/bin/livebook start"; 226 | 227 | # Create a release cookie. The code is based on 228 | # https://github.com/nixos/nixpkgs/blob/nil/nixos/modules/services/networking/pleroma.nix 229 | ExecStartPre = "${pkgs.writers.writeBashBin "write-cookie" '' 230 | RELEASE_COOKIE="${cfg.settings.homeDirectory}/.cookie" 231 | 232 | if [[ ! -f "''${RELEASE_COOKIE}" ]] 233 | then 234 | dd if=/dev/urandom bs=1 count=16 | ${pkgs.hexdump}/bin/hexdump -e '16/1 "%02x"' > "''${RELEASE_COOKIE}" 235 | fi 236 | ''}/bin/write-cookie"; 237 | 238 | # If you ran a public instance, it might be important to set these 239 | # options properly, but I am only running a local private instance, so I 240 | # don't find it worth the effort. 241 | PrivateTmp = true; 242 | # ProtectHome = true; 243 | # ProtectSystem = "full"; 244 | # PrivateDevices = false; 245 | # NoNewPrivileges = true; 246 | # CapabilityBoundingSet = "~CAP_SYS_ADMIN"; 247 | }; 248 | }; 249 | }; 250 | } 251 | -------------------------------------------------------------------------------- /nixos/profiles/locale/default.nix: -------------------------------------------------------------------------------- 1 | /* 2 | My preferred locale settings 3 | */ 4 | let 5 | defaultLocale = "en_US.UTF-8"; 6 | in { 7 | i18n = { 8 | inherit defaultLocale; 9 | extraLocaleSettings = { 10 | LC_CTYPE = defaultLocale; 11 | # LC_COLLATE = "C.UTF-8"; 12 | # LC_TIME = "en_DK.UTF-8"; 13 | }; 14 | supportedLocales = [ 15 | "en_US.UTF-8/UTF-8" 16 | "en_GB.UTF-8/UTF-8" 17 | "zh_CN.UTF-8/UTF-8" 18 | "zh_TW.UTF-8/UTF-8" 19 | "ja_JP.UTF-8/UTF-8" 20 | ]; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /nixos/profiles/microvm/default.nix: -------------------------------------------------------------------------------- 1 | # Based on flake.nix for github:astro/microvm.nix 2 | { 3 | hypervisor, 4 | config, 5 | lib, 6 | ... 7 | }: let 8 | inherit (builtins) elem; 9 | 10 | hypervisorsWith9p = ["qemu"]; 11 | hypervisorsWithUserNet = ["qemu" "kvmtool"]; 12 | in { 13 | microvm.hypervisor = hypervisor; 14 | 15 | microvm.shares = lib.optional (elem hypervisor hypervisorsWith9p) { 16 | tag = "ro-store"; 17 | source = "/nix/store"; 18 | mountPoint = "/nix/.ro-store"; 19 | }; 20 | microvm.writableStoreOverlay = "/nix/.rw-store"; 21 | microvm.volumes = [ 22 | { 23 | image = "nix-store-overlay.img"; 24 | mountPoint = config.microvm.writableStoreOverlay; 25 | size = 2048; 26 | } 27 | ]; 28 | 29 | microvm.interfaces = lib.optional (elem hypervisor hypervisorsWithUserNet) { 30 | type = "user"; 31 | id = "qemu"; 32 | mac = "02:00:00:01:01:01"; 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /nixos/profiles/microvm/ssh.nix: -------------------------------------------------------------------------------- 1 | {...}: let 2 | sshPort = 22; 3 | in { 4 | microvm.forwardPorts = [ 5 | { 6 | host.port = 2222; 7 | guest.port = sshPort; 8 | } 9 | ]; 10 | 11 | networking.firewall.enable = true; 12 | 13 | services.openssh = { 14 | enable = true; 15 | ports = [sshPort]; 16 | openFirewall = true; 17 | settings = { 18 | PermitRootLogin = "yes"; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /nixos/profiles/minio/development.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.minio = { 3 | enable = true; 4 | listenAddress = "127.0.0.1:9000"; 5 | consoleAddress = "127.0.0.1:9001"; 6 | rootCredentialsFile = "/persist/minio-root-credentials"; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /nixos/profiles/networking/usb-tether1.nix: -------------------------------------------------------------------------------- 1 | { 2 | systemd.network.links."20-usb1" = { 3 | matchConfig = { 4 | Driver = "rndis_host"; 5 | }; 6 | linkConfig = { 7 | Name = "usb1"; 8 | }; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/nginx/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.nginx = { 3 | enable = true; 4 | }; 5 | 6 | networking.firewall.allowedTCPPorts = [ 7 | 80 8 | 443 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/nix/cachix-deploy.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | environment.systemPackages = [ 3 | pkgs.cachix 4 | ]; 5 | 6 | # To start an agent, you have to create /etc/cachix-agent.token file which 7 | # contains an CACHIX_AGENT_TOKEN environment entry. The file is not created in 8 | # nixos-rebuild. 9 | services.cachix-agent.enable = true; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/nix/default.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Nix options for desktop machines 3 | 4 | If you don't build Nix on the host, don't import this profile. 5 | */ 6 | { 7 | nix = { 8 | gc = { 9 | dates = "monthly"; 10 | automatic = true; 11 | }; 12 | optimise.automatic = false; 13 | 14 | settings = { 15 | # sandbox = true; 16 | allowed-users = [ "@wheel" ]; 17 | trusted-users = [ 18 | "root" 19 | "@wheel" 20 | ]; 21 | 22 | substituters = [ 23 | "https://cache.nixos.org/" 24 | "https://nix-community.cachix.org" 25 | "https://akirak.cachix.org" 26 | ]; 27 | 28 | trusted-substituters = [ 29 | "https://emacs-ci.cachix.org" 30 | ]; 31 | 32 | trusted-public-keys = [ 33 | "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" 34 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 35 | "akirak.cachix.org-1:WJrEMdV1dYyALkOdp/kAECVZ6nAODY5URN05ITFHC+M=" 36 | "emacs-ci.cachix.org-1:B5FVOrxhXXrOL0S+tQ7USrhjMT5iOPH+QN9q0NItom4=" 37 | ]; 38 | }; 39 | 40 | extraOptions = '' 41 | # min-free = 536870912 42 | # keep-outputs = true 43 | # keep-derivations = true 44 | # fallback = true 45 | experimental-features = nix-command flakes 46 | ''; 47 | }; 48 | } 49 | -------------------------------------------------------------------------------- /nixos/profiles/nixpkgs/channels.nix: -------------------------------------------------------------------------------- 1 | {lib, ...}: { 2 | nixpkgs.config = { 3 | allowUnfreePredicate = pkg: 4 | builtins.elem (lib.getName pkg) [ 5 | # Explicitly select unfree packages. 6 | "wpsoffice" 7 | "steam-run" 8 | "steam-original" 9 | "symbola" 10 | "vscode" 11 | "microsoft-edge-stable" 12 | "android-studio-stable" 13 | "zoom" 14 | "Oracle_VM_VirtualBox_Extension_Pack" # older 15 | "Oracle_VirtualBox_Extension_Pack" # newer 16 | "google-chrome" 17 | "intel-ocl" 18 | "cursor" 19 | "steam-unwrapped" 20 | "windsurf" 21 | "claude-code" 22 | "copilot-language-server" 23 | "tokenizer.json" 24 | ]; 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /nixos/profiles/ollama/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.ollama = { 3 | enable = true; 4 | loadModels = [ 5 | "mistral" 6 | "gemma3:4b" 7 | "phi4-mini" 8 | ]; 9 | # /var/lib/private should be on a persistent file system 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /nixos/profiles/onedev/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation.oci-containers = { 3 | # Not sure if it works with podman. There is no specific recommendation for 4 | # OneDev itself, but I will follow the documentation for now. 5 | backend = "docker"; 6 | 7 | # docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v $(pwd)/onedev:/opt/onedev -p 6610:6610 -p 6611:6611 1dev/server 8 | containers.onedev = { 9 | image = "1dev/server"; 10 | ports = [ 11 | "6610:6610" 12 | "6611:6611" 13 | ]; 14 | volumes = [ 15 | "/var/lib/onedev:/opt/onedev" 16 | "/var/run/docker.sock:/var/run/docker.sock" 17 | ]; 18 | }; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /nixos/profiles/openssh/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | config, 4 | ... 5 | }: { 6 | services.openssh = { 7 | enable = true; 8 | 9 | ports = lib.mkIf config.services.tailscale.enable [ 10 | 2022 11 | ]; 12 | 13 | openFirewall = true; 14 | 15 | # Most of these options have been stolen from 16 | # https://xeiaso.net/blog/paranoid-nixos-2021-07-18 17 | settings = { 18 | PasswordAuthentication = false; 19 | KbdInteractiveAuthentication = false; 20 | }; 21 | allowSFTP = false; 22 | extraConfig = '' 23 | AllowTcpForwarding yes 24 | X11Forwarding no 25 | AllowAgentForwarding no 26 | AllowStreamLocalForwarding no 27 | AuthenticationMethods publickey 28 | ''; 29 | 30 | # Disable generation of an RSA key. See https://xeiaso.net/blog/move-away-rsa-ssh 31 | hostKeys = [ 32 | { 33 | path = "/etc/ssh/ssh_host_ed25519_key"; 34 | type = "ed25519"; 35 | } 36 | ]; 37 | }; 38 | 39 | users.users.root = { 40 | openssh.authorizedKeys.keys = [ 41 | "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEHKzdRvr0KjzLNGVV7eNcjh0m8liuXR2JLj2UA0Qa0yep3yZuVEc/I3l57z4FF27YvFVgxhLAAzXupeI98l3QTYXfaL4SF64/IZHElSC4pH5hHNNDMF37DCVLBAeAxesSkqhVoUMsG8lDiLSHy24GQBt9mKxFk461eViyVxLnPwzs7NsDo2sKVLFkPIG+SFI9wFrvRZK30l/twgljNefSoJc5xlIr6XXme3rKp00T4DMPb2sC2a9yYG5SgihQuB1RJkPXrp1gvp0wD1vc+lmniGiJEWbSefq3Ntaue48+o+yMgnazCQXSc/ozxmoK2ZISztEW+CBk5V9uD9TU8w5V cardno:11 482 161" 42 | ]; 43 | }; 44 | } 45 | -------------------------------------------------------------------------------- /nixos/profiles/pipewire/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, ... }: 2 | { 3 | environment.systemPackages = [ 4 | pkgs.pavucontrol 5 | ]; 6 | 7 | # Based on https://nixos.wiki/wiki/PipeWire 8 | security.rtkit.enable = true; 9 | services.pipewire = { 10 | enable = true; 11 | alsa.enable = true; 12 | alsa.support32Bit = true; 13 | pulse.enable = true; 14 | # If you want to use JACK applications, uncomment this 15 | #jack.enable = true; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /nixos/profiles/podman/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | virtualisation = { 3 | oci-containers.backend = "podman"; 4 | podman = { 5 | enable = true; 6 | }; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /nixos/profiles/podman/rootless-docker.nix: -------------------------------------------------------------------------------- 1 | # Provide a podman-based environment for using podman-compose with docker 2 | # compatibility to run a bunch of examples in Docker-based tutorials. 3 | # 4 | # Based on https://carlosvaz.com/posts/rootless-podman-and-docker-compose-on-nixos/ 5 | { pkgs, ... }: 6 | { 7 | imports = [ 8 | ./. 9 | ../containers/rootless.nix 10 | ]; 11 | 12 | virtualisation.podman = { 13 | # Make docker command available. 14 | dockerCompat = true; 15 | }; 16 | 17 | environment.systemPackages = [ 18 | pkgs.podman-compose 19 | ]; 20 | } 21 | -------------------------------------------------------------------------------- /nixos/profiles/postgresql/development.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, ... }: 2 | { 3 | services = { 4 | postgresql = { 5 | enable = true; 6 | 7 | settings = { 8 | # Default: 5432 9 | port = 5432; 10 | 11 | # Enable logical replication for certain use cases. 12 | # See https://kinsta.com/blog/postgresql-replication/ and 13 | # https://electric-sql.com/docs/usage/installation/postgres 14 | wal_level = "logical"; 15 | }; 16 | 17 | # Specify an explicit major version 18 | # package = pkgs.postgresql_14; 19 | 20 | # Trust local access 21 | authentication = pkgs.lib.mkOverride 12 '' 22 | local all all trust 23 | host all all localhost trust 24 | ''; 25 | 26 | ensureUsers = [ { name = "postgres"; } ]; 27 | 28 | enableTCPIP = false; 29 | 30 | # Set the data directory explicitly 31 | # dataDir = "/var/lib/postgresql/14"; 32 | }; 33 | 34 | pgadmin = { 35 | # Currently fails to build 36 | # enable = true; 37 | # Default 38 | port = 5050; 39 | initialEmail = "akira.komamura@gmail.com"; 40 | initialPasswordFile = "/persist/etc/pgpasswd"; 41 | }; 42 | 43 | postgresqlBackup = { 44 | enable = true; 45 | # PostgreSQL dump and ZFS snapshot must not occur simultaneously. 46 | startAt = "*-*-* *:05,20,35,50:00"; 47 | location = "/var/backup/postgresql"; 48 | backupAll = lib.mkDefault true; 49 | }; 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /nixos/profiles/rabbitmq/development.nix: -------------------------------------------------------------------------------- 1 | { 2 | services.rabbitmq = { 3 | enable = true; 4 | managementPlugin.enable = true; 5 | 6 | # These values are the default, but set explicitly to ensure the service is 7 | # private. 8 | listenAddress = "127.0.0.1"; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /nixos/profiles/reverse-proxy/default.nix: -------------------------------------------------------------------------------- 1 | { config, lib, ... }: 2 | let 3 | inherit (lib) types mkOption mkEnableOption; 4 | 5 | cfg = config.services.reverse-proxy; 6 | 7 | httpPort = 80; 8 | 9 | httpsPort = 443; 10 | 11 | subdomainType = types.submodule { 12 | options.reverse-proxy = mkOption { 13 | type = types.str; 14 | example = "localhost:8080"; 15 | }; 16 | }; 17 | in 18 | { 19 | options.services.reverse-proxy = { 20 | enable = mkEnableOption (lib.mdDoc "Enable a reverse-proxy service for loopback services."); 21 | 22 | domain = mkOption { 23 | type = types.str; 24 | description = lib.mdDoc '' 25 | Public DNS domain on which the services should be served as subdomains. 26 | ''; 27 | }; 28 | 29 | useACMEHost = mkOption { 30 | type = types.str; 31 | default = cfg.domain; 32 | description = lib.mdDoc '' 33 | ACME host 34 | ''; 35 | }; 36 | 37 | subdomains = mkOption { 38 | type = types.attrsOf subdomainType; 39 | description = lib.mdDoc '' 40 | Subdomains served via the reverse proxy. 41 | ''; 42 | }; 43 | }; 44 | 45 | config = { 46 | services.caddy = { 47 | enable = lib.mkIf cfg.enable true; 48 | virtualHosts = lib.optionalAttrs cfg.enable ( 49 | lib.concatMapAttrs (name: attrs: { 50 | "${name}.${cfg.domain}" = { 51 | inherit (cfg) useACMEHost; 52 | extraConfig = '' 53 | reverse_proxy ${attrs.reverse-proxy} 54 | ''; 55 | }; 56 | "${name}:${builtins.toString httpPort}" = { 57 | extraConfig = '' 58 | redir https://${name}.${cfg.domain} 59 | ''; 60 | }; 61 | }) cfg.subdomains 62 | ); 63 | }; 64 | 65 | networking.firewall.allowedTCPPorts = lib.optionals cfg.enable [ 66 | httpPort 67 | httpsPort 68 | ]; 69 | }; 70 | } 71 | -------------------------------------------------------------------------------- /nixos/profiles/sudo/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | security.sudo = { 3 | enable = true; 4 | wheelNeedsPassword = false; 5 | execWheelOnly = true; 6 | }; 7 | } 8 | -------------------------------------------------------------------------------- /nixos/profiles/syncthing/default.nix: -------------------------------------------------------------------------------- 1 | { lib, config, ... }: 2 | let 3 | inherit (builtins) toString; 4 | 5 | cfg = config.services.syncthing; 6 | 7 | devices = lib.pipe (lib.importTOML ../../../machines/metadata.toml).hosts [ 8 | (lib.filterAttrs (_: attrs: attrs ? syncthingId)) 9 | (builtins.mapAttrs (_: attrs: { id = attrs.syncthingId; })) 10 | ]; 11 | 12 | inherit (config.networking) hostName; 13 | 14 | otherDevicesByHostName = lib.remove hostName; 15 | 16 | allDevices = otherDevicesByHostName (builtins.attrNames devices); 17 | 18 | enableReverseProxy = config.services.reverse-proxy.enable; 19 | 20 | guiPort = 8384; 21 | in 22 | { 23 | services.syncthing = { 24 | enable = true; 25 | # Just the default dataDir. This needs to be on a dedicated ZFS dataset. 26 | dataDir = "/var/lib/syncthing"; 27 | overrideDevices = true; 28 | overrideFolders = true; 29 | openDefaultPorts = true; 30 | guiAddress = 31 | if enableReverseProxy then "127.0.0.1:${toString guiPort}" else "0.0.0.0:${toString guiPort}"; 32 | settings = { 33 | devices = lib.filterAttrs (name: _: name != hostName) devices; 34 | folders = { 35 | "org" = { 36 | path = cfg.dataDir + "/org"; 37 | devices = allDevices; 38 | id = "v3msx-gwdqt"; 39 | }; 40 | "notes-and-pdfs" = { 41 | path = cfg.dataDir + "/notes-and-pdfs"; 42 | devices = otherDevicesByHostName [ 43 | "li" 44 | ]; 45 | id = "4warh-yejmn"; 46 | }; 47 | "private" = { 48 | path = cfg.dataDir + "/private"; 49 | devices = otherDevicesByHostName [ 50 | "li" 51 | "yang" 52 | ]; 53 | id = "gstwc-lxb3v"; 54 | }; 55 | }; 56 | # Prevent "Host check error" 57 | # https://docs.syncthing.net/users/faq.html#why-do-i-get-host-check-error-in-the-gui-api 58 | gui.insecureSkipHostCheck = lib.mkIf enableReverseProxy true; 59 | 60 | # Wait for the PR 61 | # gui.user = "akirak"; 62 | # inherit guiPasswordFile; 63 | }; 64 | }; 65 | 66 | services.reverse-proxy = lib.mkIf enableReverseProxy { 67 | subdomains.syncthing = { 68 | reverse-proxy = "localhost:${toString guiPort}"; 69 | }; 70 | }; 71 | 72 | # The other ports are opened via openDefaultPorts, so only the web port needs 73 | # to be explicitly opened. 74 | networking.firewall = lib.mkIf (config.networking.firewall.enable && !enableReverseProxy) { 75 | allowedTCPPorts = [ 8384 ]; 76 | }; 77 | 78 | # The password is unencrypted, so it's basically useless. Wait for the PR on 79 | # guiPasswordFile option to get merged. 80 | 81 | # services.syncthing.settings.gui = { 82 | # user = "akirak"; 83 | # password = "$2y$10$epya6R5qrkZzGGCUZFQ5duA9NBvPesWkNp1QBnyJE8JWp1zenEEdq"; 84 | # }; 85 | } 86 | -------------------------------------------------------------------------------- /nixos/profiles/tailscale/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | pkgs, 3 | config, 4 | ... 5 | }: let 6 | cfg = config.services.tailscale; 7 | in { 8 | services.tailscale = { 9 | enable = true; 10 | package = pkgs.unstable.tailscale; 11 | }; 12 | 13 | networking.firewall = { 14 | trustedInterfaces = ["tailscale0"]; 15 | checkReversePath = "loose"; 16 | 17 | allowedTCPPorts = [ 18 | cfg.port 19 | ]; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /nixos/profiles/users/1000/on-server.nix: -------------------------------------------------------------------------------- 1 | let 2 | login = "akirakomamura"; 3 | group = login; 4 | in 5 | { 6 | users = { 7 | users.${login} = { 8 | description = "Akira Komamura"; 9 | createHome = true; 10 | uid = 1000; 11 | inherit group; 12 | isNormalUser = true; 13 | openssh.authorizedKeys.keys = [ 14 | "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEHKzdRvr0KjzLNGVV7eNcjh0m8liuXR2JLj2UA0Qa0yep3yZuVEc/I3l57z4FF27YvFVgxhLAAzXupeI98l3QTYXfaL4SF64/IZHElSC4pH5hHNNDMF37DCVLBAeAxesSkqhVoUMsG8lDiLSHy24GQBt9mKxFk461eViyVxLnPwzs7NsDo2sKVLFkPIG+SFI9wFrvRZK30l/twgljNefSoJc5xlIr6XXme3rKp00T4DMPb2sC2a9yYG5SgihQuB1RJkPXrp1gvp0wD1vc+lmniGiJEWbSefq3Ntaue48+o+yMgnazCQXSc/ozxmoK2ZISztEW+CBk5V9uD9TU8w5V cardno:11 482 161" 15 | ]; 16 | }; 17 | 18 | groups.${group} = { 19 | gid = 1000; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /nixos/profiles/users/primary-group.nix: -------------------------------------------------------------------------------- 1 | { 2 | homeUser, 3 | lib, 4 | config, 5 | ... 6 | }: let 7 | groupName = homeUser; 8 | in { 9 | users = { 10 | users.${homeUser}.group = groupName; 11 | 12 | groups.${groupName}.gid = lib.mkDefault config.users.users.${homeUser}.uid; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /nixos/profiles/virtualbox-host/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: let 2 | virtualboxDesktopItemsGenerator = pkgs.writeShellApplication { 3 | name = "virtualbox-generate-desktop-items"; 4 | 5 | text = builtins.readFile ./generate.bash; 6 | }; 7 | in { 8 | virtualisation.virtualbox.host = { 9 | enable = true; 10 | enableExtensionPack = true; 11 | }; 12 | 13 | environment.systemPackages = [ 14 | virtualboxDesktopItemsGenerator 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /nixos/profiles/virtualbox-host/generate.bash: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | vm_dir="${VIRTUALBOX_VM_DIR:-$HOME/VirtualBox VMs}" 4 | data_home="${XDG_DATA_HOME:-$HOME/.local/share}" 5 | data_dir="${data_home}/virtualbox-items" 6 | applications_dir="${data_home}/applications" 7 | 8 | boxes=() 9 | 10 | function prepareDirectory() { 11 | mkdir -p "${data_dir}" "${applications_dir}" 12 | find "${data_dir}" -name '*.desktop' -delete 13 | } 14 | 15 | function generateDesktopItem() { 16 | local name="$1" 17 | cat <<-CONTENT 18 | [Desktop Entry] 19 | Type=Application 20 | Name=$name on VirtualBox 21 | TryExec=VirtualBoxVM 22 | Exec=VirtualBoxVM --startvm "$name" 23 | Icon=virtualbox-vbox 24 | CONTENT 25 | } 26 | 27 | function createItems() { 28 | for box in "${boxes[@]}"; do 29 | outfile="${data_dir}/$box.desktop" 30 | generateDesktopItem "$box" > "$outfile" 31 | ln -sf -t "${applications_dir}" "$outfile" 32 | echo "$box" 33 | done 34 | } 35 | 36 | function cleanupObsoleteItems() { 37 | while read -r f; do 38 | dest=$(readlink "$f") 39 | if [[ $dest = ${data_dir}/* ]] && ! [[ -e "$dest" ]]; then 40 | rm -v "$f" 41 | fi 42 | done < <(find "${applications_dir}" -maxdepth 1 -name '*.desktop') 43 | } 44 | 45 | if ! [[ -d "${vm_dir}" ]]; then 46 | echo >&2 "Directory ${vm_dir} does not exist" 47 | echo >&2 "Consider setting VIRTUALBOX_VM_DIR to the directory containing VMs" 48 | exit 0 49 | fi 50 | 51 | while read -r filename; do 52 | boxes+=("$filename") 53 | done < <(find "${vm_dir}" -maxdepth 3 -name '*.vbox' -exec basename -s .vbox {} \;) 54 | 55 | if [[ ${#boxes[@]} -eq 0 ]]; then 56 | echo >&2 "No vbox file exists in ${vm_dir}" 57 | exit 0 58 | fi 59 | 60 | prepareDirectory 61 | createItems 62 | cleanupObsoleteItems 63 | 64 | xdg-desktop-menu forceupdate 65 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/cage/emacs.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../sessions.nix 4 | ]; 5 | 6 | environment.systemPackages = [ 7 | (pkgs.callPackage ./makeWrapper.nix { 8 | sessionName = "emacs-session"; 9 | command = "emacs"; 10 | }) 11 | ]; 12 | 13 | wayland.sessions = [ 14 | { 15 | name = "emacs-session"; 16 | } 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/cage/firefox.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../sessions.nix 4 | ]; 5 | 6 | environment.systemPackages = [ 7 | (pkgs.callPackage ./makeWrapper.nix { 8 | sessionName = "firefox-session"; 9 | command = "firefox"; 10 | }) 11 | ]; 12 | 13 | wayland.sessions = [ 14 | { 15 | name = "firefox-session"; 16 | } 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/cage/foot.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../sessions.nix 4 | ]; 5 | 6 | environment.systemPackages = [ 7 | (pkgs.callPackage ./makeWrapper.nix { 8 | sessionName = "foot-session"; 9 | command = "foot"; 10 | }) 11 | ]; 12 | 13 | wayland.sessions = [ 14 | { 15 | name = "foot-session"; 16 | } 17 | ]; 18 | } 19 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/cage/makeWrapper.nix: -------------------------------------------------------------------------------- 1 | { 2 | writeShellScriptBin, 3 | cage, 4 | sessionName, 5 | command, 6 | }: 7 | writeShellScriptBin sessionName '' 8 | export XKB_DEFAULT_LAYOUT=us 9 | export XKB_DEFAULT_OPTIONS=ctrl:nocaps 10 | export XDG_SESSION_TYPE=wayland 11 | export XDG_SESSION_DESKTOP=sway 12 | export XDG_CURRENT_DESKTOP=sway 13 | export MOZ_ENABLE_WAYLAND=1 14 | # Set SWAYSOCK to use swaymsg and other sway-compatible utilities 15 | export SWAYSOCK=''${XDG_RUNTIME_DIR}/wayland-1 16 | exec ${cage}/bin/cage ${command} 17 | '' 18 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/sessions.nix: -------------------------------------------------------------------------------- 1 | { 2 | config, 3 | lib, 4 | ... 5 | }: let 6 | inherit (lib) mkOption types; 7 | 8 | session = types.submodule { 9 | options.name = mkOption { 10 | type = types.str; 11 | example = "firefox-session"; 12 | }; 13 | options.desktopName = mkOption { 14 | type = types.nullOr types.str; 15 | example = "Firefox Session"; 16 | default = null; 17 | }; 18 | options.exec = mkOption { 19 | type = types.nullOr types.str; 20 | example = "firefox-session"; 21 | default = null; 22 | }; 23 | }; 24 | in { 25 | options = { 26 | wayland.sessions = mkOption { 27 | type = types.listOf session; 28 | default = []; 29 | }; 30 | }; 31 | 32 | config = { 33 | environment.etc = builtins.listToAttrs (builtins.map 34 | ({ 35 | name, 36 | desktopName, 37 | exec, 38 | }: { 39 | name = "wayland-sessions/${name}.desktop"; 40 | value = { 41 | text = '' 42 | [Desktop Entry] 43 | Name=${ 44 | if desktopName != null 45 | then desktopName 46 | else name 47 | } 48 | Exec=${ 49 | if exec != null 50 | then exec 51 | else name 52 | } 53 | Type=Application 54 | ''; 55 | }; 56 | }) 57 | config.wayland.sessions); 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/sway-utils.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | environment.systemPackages = with pkgs; [ 3 | (pkgs.writeShellApplication { 4 | name = "lock-screen"; 5 | runtimeInputs = [pkgs.swaylock-effects]; 6 | # TODO: Use a color scheme 7 | text = '' 8 | swaylock -f --clock --fade-in 0.5 9 | ''; 10 | }) 11 | 12 | # screenshot and screen recording 13 | wayshot 14 | wf-recorder 15 | slurp # Used with wayshot 16 | 17 | fuzzel 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/wlroots.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../window-manager/generic.nix 4 | ./sway-utils.nix 5 | ]; 6 | 7 | environment.systemPackages = [ 8 | pkgs.xdg-utils 9 | pkgs.wlr-randr 10 | ]; 11 | 12 | xdg.portal = { 13 | enable = true; 14 | wlr = { 15 | enable = true; 16 | }; 17 | xdgOpenUsePortal = true; 18 | config = { 19 | common.default = "*"; 20 | }; 21 | }; 22 | 23 | security.pam.services.swaylock = {}; 24 | } 25 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/wm/hyprland.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../sessions.nix 4 | ]; 5 | 6 | environment.systemPackages = [ 7 | pkgs.wev 8 | ]; 9 | 10 | wayland.sessions = [ 11 | { 12 | name = "Hyprland"; 13 | } 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /nixos/profiles/wayland/wm/labwc.nix: -------------------------------------------------------------------------------- 1 | {...}: { 2 | imports = [ 3 | ../sessions.nix 4 | ]; 5 | 6 | wayland.sessions = [ 7 | { 8 | name = "labwc"; 9 | } 10 | ]; 11 | } 12 | -------------------------------------------------------------------------------- /nixos/profiles/window-manager/generic.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | environment.systemPackages = [ 3 | pkgs.networkmanagerapplet 4 | pkgs.elementary-xfce-icon-theme 5 | ]; 6 | 7 | services.xserver = { 8 | xkb.options = "ctrl:nocaps"; 9 | enableCtrlAltBackspace = true; 10 | # startDbusSession = true; 11 | }; 12 | services.libinput = { 13 | enable = true; 14 | mouse = { 15 | disableWhileTyping = true; 16 | }; 17 | }; 18 | 19 | services.dbus = { 20 | enable = true; 21 | # socketActivated = true; 22 | packages = [pkgs.dconf]; 23 | }; 24 | 25 | # services.gnome.gnome-keyring.enable = true; 26 | 27 | services.blueman.enable = true; 28 | 29 | xdg.portal.extraPortals = [ 30 | pkgs.xdg-desktop-portal-gtk 31 | ]; 32 | } 33 | -------------------------------------------------------------------------------- /nixos/profiles/yubikey/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | services.yubikey-agent.enable = true; 3 | 4 | services.udev.packages = [ 5 | pkgs.yubikey-personalization 6 | ]; 7 | 8 | services.pcscd = { 9 | enable = true; 10 | }; 11 | 12 | environment.systemPackages = [ 13 | pkgs.yubikey-manager 14 | pkgs.yubioath-flutter 15 | pkgs.age-plugin-yubikey 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /nixos/suites/base/default.nix: -------------------------------------------------------------------------------- 1 | {...}: { 2 | imports = [ 3 | ../../profiles/openssh 4 | ]; 5 | 6 | networking.firewall.enable = true; 7 | 8 | nix = { 9 | settings = { 10 | auto-optimise-store = true; 11 | }; 12 | gc.automatic = true; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /nixos/suites/desktop/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | modulesPath, 3 | pkgs, 4 | lib, 5 | config, 6 | ... 7 | }: 8 | { 9 | imports = [ 10 | (modulesPath + "/profiles/base.nix") 11 | ../../profiles/yubikey 12 | ../../profiles/users/primary-group.nix 13 | ]; 14 | 15 | environment.systemPackages = [ 16 | pkgs.lsof 17 | pkgs.psmisc 18 | pkgs.handlr 19 | pkgs.libnotify 20 | ] ++ lib.optional config.services.postgresql.enable pkgs.pgcli; 21 | 22 | environment.sessionVariables = { 23 | "TMPDIR" = "/tmp"; 24 | }; 25 | 26 | networking.usePredictableInterfaceNames = true; 27 | 28 | time.timeZone = "Asia/Tokyo"; 29 | 30 | services.earlyoom.enable = true; 31 | services.psd.enable = true; 32 | 33 | # Allow mounting FUSE filesystems as a user. 34 | # https://discourse.nixos.org/t/fusermount-systemd-service-in-home-manager/5157 35 | environment.etc."fuse.conf".text = '' 36 | user_allow_other 37 | ''; 38 | 39 | programs.nix-ld.enable = true; 40 | } 41 | -------------------------------------------------------------------------------- /nixos/suites/graphical/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | pkgs, 4 | ... 5 | }: 6 | { 7 | imports = [ 8 | ../../profiles/pipewire 9 | ]; 10 | 11 | environment.systemPackages = with pkgs; [ 12 | # flameshot 13 | handlr 14 | ]; 15 | 16 | fonts = { 17 | packages = with pkgs; [ 18 | customFontPackages.jetbrains-mono-nerdfont 19 | merriweather 20 | lato 21 | ]; 22 | 23 | fontconfig.defaultFonts = { 24 | monospace = [ "JetBrains Mono NF" ]; 25 | 26 | sansSerif = [ "Lato" ]; 27 | 28 | serif = [ "Merriweather" ]; 29 | }; 30 | }; 31 | 32 | systemd.services.setxkbmap = { 33 | enable = true; 34 | after = [ "post-resume.target" ]; 35 | description = "Run setxkbmap"; 36 | 37 | script = "/run/current-system/sw/bin/setxkbmap -option ctrl:nocaps"; 38 | environment = { 39 | DISPLAY = ":0"; 40 | }; 41 | }; 42 | 43 | services.xserver.xkb.layout = lib.mkDefault "us"; 44 | } 45 | -------------------------------------------------------------------------------- /nixos/suites/hcloud-remote/default.nix: -------------------------------------------------------------------------------- 1 | # This profile can be used for fresh NixOS installation from kexec. 2 | # See https://github.com/numtide/nixos-remote 3 | {modulesPath, ...}: { 4 | imports = [ 5 | (modulesPath + "/installer/scan/not-detected.nix") 6 | (modulesPath + "/profiles/qemu-guest.nix") 7 | (modulesPath + "/profiles/hardened.nix") 8 | (modulesPath + "/profiles/headless.nix") 9 | ]; 10 | 11 | boot.initrd.availableKernelModules = [ 12 | "ata_piix" 13 | "uhci_hcd" 14 | "xen_blkfront" 15 | "vmw_pvscsi" 16 | ]; 17 | boot.initrd.kernelModules = ["nvme"]; 18 | 19 | zramSwap.enable = true; 20 | boot.tmp.cleanOnBoot = true; 21 | 22 | boot.loader.grub = { 23 | device = "/dev/sda"; 24 | efiSupport = true; 25 | efiInstallAsRemovable = true; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /nixos/suites/hcloud/default.nix: -------------------------------------------------------------------------------- 1 | # This profile can be used for NixOS installation with nixos-infect. 2 | {modulesPath, ...}: { 3 | imports = [ 4 | (modulesPath + "/profiles/qemu-guest.nix") 5 | (modulesPath + "/profiles/hardened.nix") 6 | (modulesPath + "/profiles/headless.nix") 7 | ]; 8 | 9 | boot.initrd.availableKernelModules = ["ata_piix" "uhci_hcd" "xen_blkfront" "vmw_pvscsi"]; 10 | boot.initrd.kernelModules = ["nvme"]; 11 | 12 | zramSwap.enable = true; 13 | boot.tmp.cleanOnBoot = true; 14 | 15 | fileSystems."/" = { 16 | device = "/dev/sda1"; 17 | fsType = "ext4"; 18 | }; 19 | 20 | boot.loader.grub.enable = true; 21 | boot.loader.grub.device = "/dev/sda"; 22 | } 23 | -------------------------------------------------------------------------------- /nixos/suites/installer/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../base 4 | ../../profiles/nix 5 | ]; 6 | 7 | environment.systemPackages = [ 8 | pkgs.emacs 9 | pkgs.gnupg 10 | 11 | pkgs.git 12 | # Provided from disko flake via overlayModule 13 | pkgs.disko 14 | pkgs.git-annex 15 | 16 | # Import useful packages from the package list in 17 | # nixos/modules/profiles/base.nix of nixpkgs. 18 | pkgs.gptfdisk 19 | pkgs.efibootmgr 20 | pkgs.efivar 21 | pkgs.parted 22 | pkgs.gptfdisk 23 | pkgs.ddrescue 24 | pkgs.ccrypt 25 | pkgs.cryptsetup 26 | pkgs.mkpasswd 27 | 28 | pkgs.fuse 29 | pkgs.fuse3 30 | pkgs.rsync 31 | pkgs.socat 32 | 33 | pkgs.ntfsprogs 34 | pkgs.dosfstools 35 | pkgs.mtools 36 | pkgs.xfsprogs.bin 37 | pkgs.jfsutils 38 | pkgs.f2fs-tools 39 | pkgs.btrfs-progs 40 | pkgs.zfs 41 | 42 | pkgs.lshw 43 | 44 | pkgs.unzip 45 | pkgs.zip 46 | ]; 47 | } 48 | -------------------------------------------------------------------------------- /nixos/suites/iso/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | modulesPath, 4 | ... 5 | }: { 6 | imports = [ 7 | ../installer 8 | (modulesPath + "/installer/cd-dvd/channel.nix") 9 | (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") 10 | ]; 11 | 12 | nix.extraOptions = '' 13 | experimental-features = nix-command flakes 14 | ''; 15 | 16 | nix.settings = { 17 | substituters = [ 18 | "https://cache.nixos.org/" 19 | "https://nix-community.cachix.org" 20 | "https://akirak.cachix.org" 21 | ]; 22 | trusted-public-keys = [ 23 | "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" 24 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 25 | "akirak.cachix.org-1:WJrEMdV1dYyALkOdp/kAECVZ6nAODY5URN05ITFHC+M=" 26 | ]; 27 | }; 28 | 29 | # Faster compression algorithm. See https://nixos.wiki/wiki/Creating_a_NixOS_live_CD 30 | isoImage.squashfsCompression = "gzip -Xcompression-level 1"; 31 | 32 | system.stateVersion = lib.mkDefault lib.trivial.release; 33 | } 34 | -------------------------------------------------------------------------------- /nixos/suites/microvm-gui/default.nix: -------------------------------------------------------------------------------- 1 | /* 2 | MicroVM with GUI for rapid prototyping of a desktop environment 3 | 4 | Based on https://github.com/astro/microvm.nix/blob/main/flake.nix 5 | */ 6 | {config, ...}: let 7 | xrdpPort = 3389; 8 | in { 9 | imports = [ 10 | ../../profiles/microvm 11 | ../../profiles/microvm/ssh.nix 12 | ]; 13 | 14 | # Set a message printed to the console before login. 15 | services.getty.helpLine = '' 16 | Connect to the RDP server using xfreerdp/wlfreerdp: 17 | 18 | xfreerdp /u:root /v:localhost:${builtins.toString xrdpPort} 19 | 20 | From this console, you can log in as "root" with an empty password. 21 | ''; 22 | 23 | # login: "root", password: empty 24 | users.users.root.password = ""; 25 | 26 | microvm = { 27 | mem = 4096; 28 | vcpu = 2; 29 | }; 30 | 31 | nixpkgs.config.permittedInsecurePackages = [ 32 | "xrdp-0.9.9" 33 | ]; 34 | 35 | services.xserver = { 36 | enable = true; 37 | }; 38 | 39 | services.xrdp = { 40 | enable = true; 41 | openFirewall = true; 42 | port = xrdpPort; 43 | }; 44 | 45 | microvm.forwardPorts = [ 46 | { 47 | host.port = xrdpPort; 48 | guest.port = xrdpPort; 49 | } 50 | ]; 51 | } 52 | -------------------------------------------------------------------------------- /nixos/suites/microvm/default.nix: -------------------------------------------------------------------------------- 1 | /* 2 | Based on https://github.com/astro/microvm.nix/blob/main/flake.nix 3 | */ 4 | {...}: { 5 | imports = [ 6 | ../../profiles/microvm 7 | ]; 8 | 9 | services.getty.helpLine = '' 10 | From this console, you can log in as "root" with an empty password. 11 | ''; 12 | 13 | users.users.root.password = ""; 14 | 15 | microvm = { 16 | mem = 2048; 17 | vcpu = 2; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /nixos/suites/remote-installer/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | config, 4 | ... 5 | }: { 6 | imports = [ 7 | ../installer 8 | ../../profiles/openssh 9 | ]; 10 | 11 | nix.extraOptions = '' 12 | experimental-features = nix-command flakes 13 | ''; 14 | 15 | nix.settings = { 16 | substituters = [ 17 | "https://cache.nixos.org/" 18 | "https://nix-community.cachix.org" 19 | "https://akirak.cachix.org" 20 | ]; 21 | trusted-public-keys = [ 22 | "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" 23 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 24 | "akirak.cachix.org-1:WJrEMdV1dYyALkOdp/kAECVZ6nAODY5URN05ITFHC+M=" 25 | ]; 26 | }; 27 | 28 | networking = { 29 | useDHCP = false; 30 | wireless.enable = false; 31 | networkmanager.enable = true; 32 | }; 33 | 34 | system.stateVersion = lib.mkDefault lib.trivial.release; 35 | 36 | users.users.nixos = { 37 | uid = 1000; 38 | isNormalUser = true; 39 | 40 | extraGroups = [ 41 | "wheel" 42 | "networkmanager" 43 | ]; 44 | 45 | openssh.authorizedKeys.keys = config.users.users.root.openssh.authorizedKeys.keys; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /nixos/suites/server/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, ...}: { 2 | imports = [ 3 | ../base 4 | ]; 5 | 6 | environment.systemPackages = with pkgs; [ 7 | duf 8 | du-dust 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /secrets/aider-env.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirak/homelab/982762f4dc21623c268a852ceffeafff210fe3c5/secrets/aider-env.age -------------------------------------------------------------------------------- /secrets/rekeyed/yang/cde7a1a585cb8ea1ccfb2a2e1535f2ef-nicesunny.day.credentials.txt.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirak/homelab/982762f4dc21623c268a852ceffeafff210fe3c5/secrets/rekeyed/yang/cde7a1a585cb8ea1ccfb2a2e1535f2ef-nicesunny.day.credentials.txt.age -------------------------------------------------------------------------------- /secrets/rekeyed/zheng/e10023806a5bd15c8d5351e849343edd-dhcp-hosts.age: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akirak/homelab/982762f4dc21623c268a852ceffeafff210fe3c5/secrets/rekeyed/zheng/e10023806a5bd15c8d5351e849343edd-dhcp-hosts.age -------------------------------------------------------------------------------- /secrets/yubikey.pub: -------------------------------------------------------------------------------- 1 | # Serial: 11482161, Slot: 2 2 | # Name: age identity 33298455 3 | # Created: Thu, 01 Aug 2024 10:35:29 +0000 4 | # PIN policy: Once (A PIN is required once per session, if set) 5 | # Touch policy: Cached (A physical touch is required for decryption, and is cached for 15 seconds) 6 | # Recipient: age1yubikey1qdlq02upxrg2q379tchjr2f9avrkj2dpmyssgd0jh0e3c662d3ejs4yl452 7 | AGE-PLUGIN-YUBIKEY-1XY627QYRXV5CG4GE25EVR 8 | -------------------------------------------------------------------------------- /templates/flake-module.nix: -------------------------------------------------------------------------------- 1 | { 2 | flake = { 3 | # Templates can be defined only once 4 | templates = { 5 | home-manager = { 6 | path = ./home-manager; 7 | description = "An example configuration repository for home-manager"; 8 | }; 9 | nixos-wsl = { 10 | path = ./nixos-wsl; 11 | description = "An example configuration flake for NixOS-WSL"; 12 | }; 13 | }; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /templates/home-manager/.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | *~ 3 | -------------------------------------------------------------------------------- /templates/home-manager/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; 4 | unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; 5 | home-manager = { 6 | url = "github:nix-community/home-manager"; 7 | inputs.nixpkgs.follows = "nixpkgs"; 8 | }; 9 | 10 | flake-parts.url = "github:hercules-ci/flake-parts"; 11 | 12 | my-overlay.url = "github:akirak/nixpkgs-overlay"; 13 | emacs-config.url = "github:akirak/emacs-config/develop"; 14 | homelab.url = "github:akirak/homelab"; 15 | }; 16 | 17 | nixConfig = { 18 | registry = "https://raw.githubusercontent.com/akirak/flake-pins/master/registry.json"; 19 | extra-substituters = [ 20 | "https://akirak.cachix.org" 21 | ]; 22 | extra-trusted-public-keys = [ 23 | "akirak.cachix.org-1:WJrEMdV1dYyALkOdp/kAECVZ6nAODY5URN05ITFHC+M=" 24 | ]; 25 | }; 26 | 27 | outputs = { 28 | self, 29 | nixpkgs, 30 | flake-parts, 31 | home-manager, 32 | ... 33 | } @ inputs: let 34 | inherit (nixpkgs) lib; 35 | 36 | overlays = [ 37 | (_final: prev: { 38 | unstable = inputs.unstable.legacyPackages.${prev.system}; 39 | zsh-plugins = inputs.my-overlay.zsh-plugins; 40 | }) 41 | inputs.my-overlay.overlays.default 42 | ]; 43 | 44 | allowUnfreePredicate = pkg: 45 | builtins.elem (lib.getName pkg) [ 46 | # Explicitly select unfree packages. 47 | "symbola" 48 | ]; 49 | 50 | pkgsForSystem = system: 51 | import nixpkgs { 52 | inherit system; 53 | inherit overlays; 54 | config = { 55 | inherit allowUnfreePredicate; 56 | }; 57 | }; 58 | 59 | systems = [ 60 | "x86_64-linux" 61 | ]; 62 | in 63 | flake-parts.lib.mkFlake {inherit inputs;} { 64 | inherit systems; 65 | 66 | flake = { 67 | homeConfigurations = { 68 | penguin = home-manager.lib.homeManagerConfiguration { 69 | pkgs = pkgsForSystem "x86_64-linux"; 70 | extraSpecialArgs = { 71 | homeUser = "akirakomamura"; 72 | inherit (inputs) emacs-config; 73 | }; 74 | modules = [ 75 | { 76 | home.stateVersion = "23.05"; 77 | } 78 | ./home.nix 79 | (inputs.homelab.outPath + "/homes/core.nix") 80 | inputs.emacs-config.homeModules.twist 81 | ]; 82 | }; 83 | }; 84 | 85 | checks = lib.genAttrs systems (system: 86 | lib.pipe inputs.self.homeConfigurations [ 87 | (lib.filterAttrs (_: hc: hc.pkgs.system == system)) 88 | (builtins.mapAttrs (_: hc: hc.activationPackage)) 89 | ]); 90 | }; 91 | }; 92 | } 93 | -------------------------------------------------------------------------------- /templates/home-manager/home.nix: -------------------------------------------------------------------------------- 1 | {homeUser, ...}: { 2 | home.username = homeUser; 3 | home.homeDirectory = "/home/${homeUser}"; 4 | 5 | programs.emacs-twist = { 6 | enable = true; 7 | settings = { 8 | extraFeatures = [ 9 | ]; 10 | }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /templates/nixos-wsl/.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | *~ 3 | -------------------------------------------------------------------------------- /templates/nixos-wsl/README.md: -------------------------------------------------------------------------------- 1 | # Flake Template for NixOS-WSL 2 | 3 | This is a flake template for quickly setting up my custom NixOS environment for 4 | development on Windows Subsystem for Linux. 5 | 6 | ## How to use 7 | 8 | First follow [the 9 | instruction](https://github.com/nix-community/NixOS-WSL?tab=readme-ov-file#quick-start) 10 | to create a NixOS container. 11 | 12 | ``` shell 13 | nix-shell -p git 14 | alias nix='nix --extra-experimental-features nix-command --extra-experimental-features flakes' 15 | nix flake new -t github:akirak/homelab#nixos-wsl ~/config-local 16 | cd ~/config-local 17 | git init 18 | git add flake.nix 19 | ``` 20 | 21 | Tweak `flake.nix` as needed and run: 22 | 23 | ``` shell 24 | # Make `just` available 25 | nix develop 26 | # Run nixos-rebuild build 27 | just build 28 | # Run nixos-rebuild switch 29 | just switch 30 | ``` 31 | -------------------------------------------------------------------------------- /templates/nixos-wsl/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; 4 | home-manager = { 5 | url = "github:nix-community/home-manager/release-23.11"; 6 | inputs.nixpkgs.follows = "nixpkgs"; 7 | }; 8 | nixos-wsl = { 9 | url = "github:nix-community/NixOS-WSL"; 10 | inputs.nixpkgs.follows = "nixpkgs"; 11 | }; 12 | 13 | flake-parts.url = "github:hercules-ci/flake-parts"; 14 | 15 | emacs-config = { 16 | url = "github:akirak/emacs-config/develop"; 17 | inputs.flake-pins.follows = "flake-pins"; 18 | }; 19 | flake-pins.url = "github:akirak/flake-pins"; 20 | homelab.url = "github:akirak/homelab"; 21 | }; 22 | 23 | outputs = { 24 | nixpkgs, 25 | flake-parts, 26 | ... 27 | } @ inputs: let 28 | inherit (nixpkgs) lib; 29 | in 30 | flake-parts.lib.mkFlake {inherit inputs;} { 31 | systems = [ 32 | "x86_64-linux" 33 | ]; 34 | 35 | perSystem = {pkgs, ...}: { 36 | devShells.default = pkgs.mkShell { 37 | buildInputs = [ 38 | pkgs.just 39 | ]; 40 | }; 41 | }; 42 | 43 | flake = { 44 | nixosConfigurations = { 45 | wsl-private = inputs.homelab.lib.mkSystem (throw "Set the host name") { 46 | system = "x86_64-linux"; 47 | self' = inputs.self; 48 | channel = nixpkgs; 49 | specialArgs = { 50 | homeUser = throw "Set the user name"; 51 | inherit (inputs) emacs-config; 52 | }; 53 | extraModules = [ 54 | # Mandatory settings for NixOS-WSL 55 | (inputs.nixos-wsl.outPath + "/modules") 56 | ({homeUser, ...}: { 57 | wsl.enable = true; 58 | wsl.defaultUser = homeUser; 59 | system.stateVersion = "23.11"; 60 | time.timeZone = throw "Set your time zone"; 61 | }) 62 | 63 | inputs.home-manager.nixosModules.home-manager 64 | inputs.homelab.nixosModules.hmProfile 65 | 66 | # Add profiles as needed 67 | (inputs.homelab.outPath + "/profiles/nix") 68 | (inputs.homelab.outPath + "/profiles/locale") 69 | # (inputs.homelab.outPath + "/profiles/docker/rootless.nix") 70 | 71 | # My custom settings 72 | ({homeUser, ...}: { 73 | home-manager.users.${homeUser} = { 74 | imports = [ 75 | (inputs.homelab.outPath + "/homes/basic.nix") 76 | (inputs.homelab.outPath + "/homes/wsl.nix") 77 | ]; 78 | 79 | home.username = homeUser; 80 | home.homeDirectory = "/home/${homeUser}"; 81 | home.stateVersion = "23.11"; 82 | 83 | programs.git.extraIdentities = [ 84 | { 85 | email = throw "E-mail address"; 86 | fullName = throw "Full Name"; 87 | conditions = [ 88 | (throw "Please set conditions") 89 | "hasconfig:remote.*.url:git@YOURORG.com:XXX/**" 90 | "hasconfig:remote.*.url:https://YOURORG.com/XXX/**" 91 | "gitdir:~/work2/XXX/" 92 | ]; 93 | } 94 | ]; 95 | 96 | programs.emacs-twist = { 97 | enable = true; 98 | serviceIntegration.enable = true; 99 | settings = { 100 | extraFeatures = [ 101 | ]; 102 | }; 103 | }; 104 | }; 105 | }) 106 | ]; 107 | }; 108 | }; 109 | }; 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /templates/nixos-wsl/justfile: -------------------------------------------------------------------------------- 1 | host := "wsl-private" 2 | 3 | overrides := "--override-input emacs-config github:akirak/emacs-config/develop" 4 | 5 | upstream := "github:akirak/homelab" 6 | 7 | build: 8 | nixos-rebuild build --flake .\#{{host}} 9 | 10 | test: 11 | nixos-rebuild test --flake .\#{{host}} --use-remote-sudo 12 | 13 | switch: 14 | nixos-rebuild switch --flake .\#{{host}} --use-remote-sudo 15 | 16 | update: 17 | nix flake update --inputs-from {{upstream}} {{overrides}} 18 | --------------------------------------------------------------------------------