diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..748ec06 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "github-actions" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "daily" diff --git a/.github/workflows/build-sd-image.yml b/.github/workflows/build-sd-image.yml new file mode 100644 index 0000000..7a806b6 --- /dev/null +++ b/.github/workflows/build-sd-image.yml @@ -0,0 +1,35 @@ +name: Build SD image for Raspberry Pi 5 + +on: + workflow_dispatch: + +jobs: + build-sd-image: + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install QEMU + run: sudo apt-get install qemu-user-static + + - name: Install Nix + uses: cachix/install-nix-action@v31 + with: + extra_nix_config: | + system = aarch64-linux + + - name: Build SD image + run: nix build -L '.#nixosConfigurations.pochita-sd.config.system.build.sdImage' + + - name: Zip the Resulting SD image + run: | + mkdir -p sd-image + cp -r result/* sd-image + zip -r sd-image.zip sd-image + + - name: Upload SD image + uses: actions/upload-artifact@v5 + with: + name: sd-image + diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000..f7a8481 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,37 @@ +name: Nix +on: + push: + paths-ignore: + - README.md + pull_request: + paths-ignore: + - README.md + +jobs: + build: + strategy: + matrix: + target-system: + - ymir + - tartarus + - pochita + - pochita-sd + - harmonica + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: cachix/install-nix-action@v31 + # TODO: add a binary cache + # - uses: cachix/cachix-action@v10 + # with: + # name: YOURCACHE + # authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + - run: nix flake check --accept-flake-config + # Pre-build the system configuration + - run: nix build --accept-flake-config --dry-run .#nixosConfigurations.${{ matrix.target-system }}.config.system.build.toplevel + check-formatting: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v5 + - uses: cachix/install-nix-action@v31 + - run: nix run nixpkgs#nixfmt-tree -- --ci diff --git a/.github/workflows/test-my-packages.yml b/.github/workflows/test-my-packages.yml new file mode 100644 index 0000000..91ec739 --- /dev/null +++ b/.github/workflows/test-my-packages.yml @@ -0,0 +1,41 @@ +name: Build and test the packages i maintain on Nixpkgs + + +on: + # cron every hour at 3 minutes 00:03 AM, 01:03 AM etc. + schedule: + - cron: '3 0 * * *' + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + matrix: + nixpkgs-branch: [nixos-unstable, nixpkgs-unstable, master] # TODO: add stable branch once they are available + # platform: [x86_64-linux, aarch64-linux] #TODO: add aarch64-linux + myPackages: # TODO automate this list + - python313Packages.runstats + - python313Packages.fastmri + - python312Packages.runstats + - python312Packages.fastmri + - python311Packages.runstats + # - python311Packages.fastmri # broken for now + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Install Nix + uses: cachix/install-nix-action@v31 + # with: + # extra_nix_config: | + # # system = ${{ matrix.platform }} + + # i want to create .drv file and check if they exist in the nixos.cache + # if they dont exist, i want to skip the build + + # - name: Check if the dependencies are in the cache + # run: nix path-info --closure-size --eval-store auto --store https://cache.nixos.org 'github:nixos/nixpkgs/${{ matrix.nixpkgs-branch }}#${{ matrix.myPackages }}^*' + + - name: Build my packages + run: nix build -L "github:nixos/nixpkgs/${{ matrix.nixpkgs-branch }}#${{ matrix.myPackages }}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5177d89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +result +.DS_Store +.direnv +*.old \ No newline at end of file diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000..2952370 --- /dev/null +++ b/.mailmap @@ -0,0 +1,3 @@ +osbm +osbm +osbm <74963545+osbm@users.noreply.github.com> diff --git a/LICENSE b/LICENSE index 6a8223b..0a54b1a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Osman F Bayram +Copyright (c) 2025 Osman F Bayram Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 53d09dc..e654d52 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,136 @@ -# nix-configuration -The nix configuration +# nixos is life +The nix configuration of mine. My intentions are just to maintain my configuration and to contribute to the nix community. + +Here i have 4 machines and 1 sd card image that i maintain. +- Laptop **tartarus** (faulty hardware, nvidia gpu doesnt work) +- Desktop **ymir** (beast, my most prized possession as of now) +- Raspberry Pi 5 **pochita** (a server that i experiment with) +- Raspberry Pi 5 SD image **pochita-sd** (produces an sd image that could be used to flash the sd card of a rpi-5) +- Phone **atreus** (unrooted, nix-on-droid) + +I didnt get these setup yet. +- Raspberry Pi Zero 2W **harmonica** (small machine for small tasks and cronjobs) (not setup yet) +- Android phone (termux) **android** (not setup yet) + +My options: + +I implemented a module system for my configurations. Each machine has its own set of options that can be enabled or disabled. The options are defined in the `modules/options.nix` file. Each option is a module that can be imported into the machine configuration. + +I am containing my options in the `osbmModules` attribute set. I dont like to interfere with the global configuration namespace. Here is all the available options: + +```nix +osbmModules = { + desktopEnvironment = "plasma"; # options: "plasma", "none" + homeManager.enable = true; + machineType = "desktop"; # options: "desktop", "laptop", "server", "embedded", "mobile" + users = [ "osbm" "bayram" ]; + defaultUser = "osbm"; + agenix.enable = true; + nixSettings.enable = true; + programs = { + steam.enable = true; + graphical.enable = true; + commandLine.enable = true; + neovim.enable = true; + arduino.enable = true; + adbFastboot.enable = true; + }; + services = { + # list services to enable + }; + hardware = { + sound.enable = true; + nvidia.enable = false; + hibernation.enable = false; + disko = { + enable = true; + fileSystem = "zfs"; # options: "zfs", "ext4" + initrd-ssh = { + enable = true; + ethernetDrivers = [ "igc" ]; + }; + zfs = { + enable = true; + hostID = "49e95c43"; + root = { + disk1 = "nvme0n1"; + disk2 = "nvme1n1"; + reservation = "200G"; + impermanenceRoot = true; + }; + storage = { + enable = true; + disks = [ + "sda" + "sdb" + ]; + reservation = "1500G"; + mirror = true; + #amReinstalling = true; + }; + }; + }; + } +}; +``` + + + + +
+ How to bootstrap raspberry pi 5 + +## How to use raspberry pi 5 + +I have 2 configurations for the raspberry pi 5. One is for the sd card (basically bootstraps the system) and the other is for my customized system itself. + +build the image first (this took about 4 hours on ymir (binfmt for aarch64 needs to be enabled if you are building on x86_64)) +```sh +$ nix build -L '.#nixosConfigurations.pochita-sd.config.system.build.sdImage' +``` + +then to flash the image to the sd card enable zstd +```sh +$ nix-shell -p zstd +``` + +then flash the image to the sd card +```sh +$ zstdcat nixos-sd-image-24.05.20241116.e8c38b7-aarch64-linux.img.zst | dd of=/dev/sda status=progress +``` + +and voila! when you plug the sd card to the raspberry pi 5 it will boot up with the configuration that you have built. And then you can ssh into it and further configure it. + +
+build iso with: + nix build .#nixosConfigurations.myISO.config.system.build.isoImage + +# To-do list + +- [x] iso image generator for nixos + - Basically the original nixos iso with added packages and tweaks. +- [ ] build custom android rom + - Or how to run nixos on the phone. +- [ ] build android apps using nix + - [ ] lichess + - [ ] termux +- [ ] build my qmk keyboard with nix +- agenix + - [ ] add my gpg keys + - [x] add ssh keys so that machines can connect to each other +- [x] module system with options +- [ ] see which derivations will be built and which will be downloaded from cache or which is already present in the nix store. +- [ ] see which python packages are giving build errors. +- [x] home-manager setup +- [ ] make a development environment nix repository +- [ ] enable swap on pochita +- [ ] learnis it possible to enable swap with sd-image? + + +nano /tmp/secret.key +sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode destroy,format,mount --flake github:osbm/flake#apollo + +sudo mkdir -p /mnt/etc/ssh +sudo ssh-keygen -t ed25519 -N "" -f /mnt/etc/ssh/initrd + +sudo nixos-install --flake github:osbm/flake#apollo --root /mnt --no-root-passwd diff --git a/configuration.nix b/configuration.nix deleted file mode 100644 index f1a4b0e..0000000 --- a/configuration.nix +++ /dev/null @@ -1,149 +0,0 @@ -# Edit this configuration file to define what should be installed on -# your system. Help is available in the configuration.nix(5) man page -# and in the NixOS manual (accessible by running ‘nixos-help’). - -{ config, pkgs, ... }: - -{ - imports = - [ # Include the results of the hardware scan. - ./hardware-configuration.nix - ]; - - # Bootloader. - boot.loader.systemd-boot.enable = true; - boot.loader.efi.canTouchEfiVariables = true; - - networking.hostName = "tartarus"; # Define your hostname. - # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. - - # Configure network proxy if necessary - # networking.proxy.default = "http://user:password@proxy:port/"; - # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; - - # Enable networking - networking.networkmanager.enable = true; - - # Set your time zone. - time.timeZone = "Europe/Istanbul"; - - # Select internationalisation properties. - i18n.defaultLocale = "en_US.UTF-8"; - - i18n.extraLocaleSettings = { - LC_ADDRESS = "tr_TR.UTF-8"; - LC_IDENTIFICATION = "tr_TR.UTF-8"; - LC_MEASUREMENT = "tr_TR.UTF-8"; - LC_MONETARY = "tr_TR.UTF-8"; - LC_NAME = "tr_TR.UTF-8"; - LC_NUMERIC = "tr_TR.UTF-8"; - LC_PAPER = "tr_TR.UTF-8"; - LC_TELEPHONE = "tr_TR.UTF-8"; - LC_TIME = "tr_TR.UTF-8"; - }; - - # Enable the X11 windowing system. - # You can disable this if you're only using the Wayland session. - services.xserver.enable = true; - - # Enable the KDE Plasma Desktop Environment. - services.displayManager.sddm.enable = true; - services.desktopManager.plasma6.enable = true; - - # Configure keymap in X11 - services.xserver.xkb = { - layout = "us"; - variant = ""; - }; - - # Enable CUPS to print documents. - services.printing.enable = true; - - # Enable sound with pipewire. - hardware.pulseaudio.enable = false; - security.rtkit.enable = true; - services.pipewire = { - enable = true; - alsa.enable = true; - alsa.support32Bit = true; - pulse.enable = true; - # If you want to use JACK applications, uncomment this - #jack.enable = true; - - # use the example session manager (no others are packaged yet so this is enabled by default, - # no need to redefine it in your config for now) - #media-session.enable = true; - }; - - # Enable touchpad support (enabled default in most desktopManager). - # services.xserver.libinput.enable = true; - - # Define a user account. Don't forget to set a password with ‘passwd’. - users.users.osbm = { - isNormalUser = true; - description = "osbm"; - extraGroups = [ "networkmanager" "wheel" ]; - packages = with pkgs; [ - kdePackages.kate - vscode - discord - alacritty - # thunderbird - ]; - }; - - # Install firefox. - programs.firefox.enable = true; - - # Allow unfree packages - nixpkgs.config.allowUnfree = true; - - - nix.settings.experimental-features = [ "nix-command" "flakes"]; - - - # List packages installed in system profile. To search, run: - # $ nix search wget - environment.systemPackages = with pkgs; [ - # vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. - wget - git - gnumake - zip - fish - trash-cli - tmux - zoxide - htop - unzip - tlrc - ]; - - # Some programs need SUID wrappers, can be configured further or are - # started in user sessions. - # programs.mtr.enable = true; - # programs.gnupg.agent = { - # enable = true; - # enableSSHSupport = true; - # }; - - # List services that you want to enable: - - # Enable the OpenSSH daemon. - # services.openssh.enable = true; - - # Open ports in the firewall. - # networking.firewall.allowedTCPPorts = [ ... ]; - # networking.firewall.allowedUDPPorts = [ ... ]; - # Or disable the firewall altogether. - # networking.firewall.enable = false; - - # This value determines the NixOS release from which the default - # settings for stateful data, like file locations and database versions - # on your system were taken. It‘s perfectly fine and recommended to leave - # this value at the release version of the first install of this system. - # Before changing this value read the documentation for this option - # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). - system.stateVersion = "24.05"; # Did you read the comment? - -} diff --git a/flake.lock b/flake.lock index b86cf5b..ce1f775 100644 --- a/flake.lock +++ b/flake.lock @@ -1,24 +1,952 @@ { "nodes": { - "nixpkgs": { + "agenix": { + "inputs": { + "darwin": "darwin", + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems" + }, "locked": { - "lastModified": 1728500571, - "narHash": "sha256-dOymOQ3AfNI4Z337yEwHGohrVQb4yPODCW9MDUyAc4w=", + "lastModified": 1761656077, + "narHash": "sha256-lsNWuj4Z+pE7s0bd2OKicOFq9bK86JE0ZGeKJbNqb94=", + "owner": "ryantm", + "repo": "agenix", + "rev": "9ba0d85de3eaa7afeab493fed622008b6e4924f5", + "type": "github" + }, + "original": { + "owner": "ryantm", + "repo": "agenix", + "type": "github" + } + }, + "blobs": { + "flake": false, + "locked": { + "lastModified": 1604995301, + "narHash": "sha256-wcLzgLec6SGJA8fx1OEN1yV/Py5b+U5iyYpksUY/yLw=", + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "rev": "2cccdf1ca48316f2cfd1c9a0017e8de5a7156265", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "blobs", + "type": "gitlab" + } + }, + "darwin": { + "inputs": { + "nixpkgs": [ + "agenix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1744478979, + "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=", + "owner": "lnl7", + "repo": "nix-darwin", + "rev": "43975d782b418ebf4969e9ccba82466728c2851b", + "type": "github" + }, + "original": { + "owner": "lnl7", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "disko": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762276996, + "narHash": "sha256-TtcPgPmp2f0FAnc+DMEw4ardEgv1SGNR3/WFGH0N19M=", + "owner": "nix-community", + "repo": "disko", + "rev": "af087d076d3860760b3323f6b583f4d828c1ac17", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "disko", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1761588595, + "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": [ + "osbm-nvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760948891, + "narHash": "sha256-TmWcdiUUaWk8J4lpjzu4gCGxWY6/Ok7mOK4fIFfBuU4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "864599284fc7c0ba6357ed89ed5e2cd5040f0c04", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "git-hooks": { + "inputs": { + "flake-compat": [ + "simple-nixos-mailserver", + "flake-compat" + ], + "gitignore": "gitignore", + "nixpkgs": [ + "simple-nixos-mailserver", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760663237, + "narHash": "sha256-BflA6U4AM1bzuRMR8QqzPXqh8sWVCNDzOdsxXEguJIc=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "ca5b894d3e3e151ffc1db040b6ce4dcc75d31c37", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "simple-nixos-mailserver", + "git-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "home-manager": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762463325, + "narHash": "sha256-33YUsWpPyeBZEWrKQ2a1gkRZ7i0XCC/2MYpU6BVeQSU=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "0562fef070a1027325dd4ea10813d64d2c967b39", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "home-manager_2": { + "inputs": { + "nixpkgs": [ + "nix-on-droid", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709445365, + "narHash": "sha256-DVv6nd9FQBbMWbOmhq0KVqmlc3y3FMSYl49UXmMcO+0=", + "owner": "nix-community", + "repo": "home-manager", + "rev": "4de84265d7ec7634a69ba75028696d74de9a44a7", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "home-manager", + "type": "github" + } + }, + "impermanence": { + "locked": { + "lastModified": 1737831083, + "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=", + "owner": "nix-community", + "repo": "impermanence", + "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "impermanence", + "type": "github" + } + }, + "ixx": { + "inputs": { + "flake-utils": [ + "osbm-nvim", + "nixvim", + "nuschtosSearch", + "flake-utils" + ], + "nixpkgs": [ + "osbm-nvim", + "nixvim", + "nuschtosSearch", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1754860581, + "narHash": "sha256-EM0IE63OHxXCOpDHXaTyHIOk2cNvMCGPqLt/IdtVxgk=", + "owner": "NuschtOS", + "repo": "ixx", + "rev": "babfe85a876162c4acc9ab6fb4483df88fa1f281", + "type": "github" + }, + "original": { + "owner": "NuschtOS", + "ref": "v0.1.1", + "repo": "ixx", + "type": "github" + } + }, + "libcamera-src": { + "flake": false, + "locked": { + "lastModified": 1725630279, + "narHash": "sha256-KH30jmHfxXq4j2CL7kv18DYECJRp9ECuWNPnqPZajPA=", + "owner": "raspberrypi", + "repo": "libcamera", + "rev": "69a894c4adad524d3063dd027f5c4774485cf9db", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "repo": "libcamera", + "rev": "69a894c4adad524d3063dd027f5c4774485cf9db", + "type": "github" + } + }, + "libpisp-src": { + "flake": false, + "locked": { + "lastModified": 1724944683, + "narHash": "sha256-Fo2UJmQHS855YSSKKmGrsQnJzXog1cdpkIOO72yYAM4=", + "owner": "raspberrypi", + "repo": "libpisp", + "rev": "28196ed6edcfeda88d23cc5f213d51aa6fa17bb3", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "v1.0.7", + "repo": "libpisp", + "type": "github" + } + }, + "mobile-nixos": { + "flake": false, + "locked": { + "lastModified": 1761853569, + "narHash": "sha256-miiMKVgC2WVi4ItD8rWD0ngou5WicEDAuZGhI0TfEIw=", + "owner": "mobile-nixos", + "repo": "mobile-nixos", + "rev": "1e38d4027bbb944f2af1b3241eabd9ad9c950c84", + "type": "github" + }, + "original": { + "owner": "mobile-nixos", + "repo": "mobile-nixos", + "type": "github" + } + }, + "nix-darwin": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762501326, + "narHash": "sha256-QbhsksHaIN6qU3oXhwUFbYycKX1GRxObpQSWAM5fhRY=", + "owner": "nix-darwin", + "repo": "nix-darwin", + "rev": "e2b82ebd0f990a5d1b68fcc761b3d6383c86ccfd", + "type": "github" + }, + "original": { + "owner": "nix-darwin", + "ref": "master", + "repo": "nix-darwin", + "type": "github" + } + }, + "nix-formatter-pack": { + "inputs": { + "nixpkgs": [ + "nix-on-droid", + "nixpkgs" + ], + "nmd": [ + "nix-on-droid", + "nmd" + ], + "nmt": "nmt" + }, + "locked": { + "lastModified": 1705252799, + "narHash": "sha256-HgSTREh7VoXjGgNDwKQUYcYo13rPkltW7IitHrTPA5c=", + "owner": "Gerschtli", + "repo": "nix-formatter-pack", + "rev": "2de39dedd79aab14c01b9e2934842051a160ffa5", + "type": "github" + }, + "original": { + "owner": "Gerschtli", + "repo": "nix-formatter-pack", + "type": "github" + } + }, + "nix-formatter-pack_2": { + "inputs": { + "nixpkgs": [ + "osbm-nvim", + "nixpkgs" + ], + "nmd": "nmd_2", + "nmt": "nmt_2" + }, + "locked": { + "lastModified": 1756744433, + "narHash": "sha256-6BSEvkprwEQDQQgW5UH/1GkBPGM8M9+qX6o9ePslr6E=", + "owner": "Gerschtli", + "repo": "nix-formatter-pack", + "rev": "63b748033a3fa0af80f8ed908521122e48858c30", + "type": "github" + }, + "original": { + "owner": "Gerschtli", + "repo": "nix-formatter-pack", + "type": "github" + } + }, + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1762055842, + "narHash": "sha256-Pu1v3mlFhRzZiSxVHb2/i/f5yeYyRNqr0RvEUJ4UgHo=", + "owner": "nix-community", + "repo": "nix-index-database", + "rev": "359ff6333a7b0b60819d4c20ed05a3a1f726771f", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-index-database", + "type": "github" + } + }, + "nix-on-droid": { + "inputs": { + "home-manager": "home-manager_2", + "nix-formatter-pack": "nix-formatter-pack", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-docs": "nixpkgs-docs", + "nixpkgs-for-bootstrap": "nixpkgs-for-bootstrap", + "nmd": "nmd" + }, + "locked": { + "lastModified": 1760773689, + "narHash": "sha256-TaRP+sx4EiqBcfdKVYKT+RbrRHioJF+HUmiaUaHj5I8=", + "owner": "nix-community", + "repo": "nix-on-droid", + "rev": "1c306c07b3e99ab79b967ead32f9af7b8672a7ef", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-on-droid", + "type": "github" + } + }, + "nixos-hardware": { + "locked": { + "lastModified": 1762463231, + "narHash": "sha256-hv1mG5j5PTbnWbtHHomzTus77pIxsc4x8VrMjc7+/YE=", "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d51c28603def282a24fa034bcb007e2bcb5b5dd0", + "repo": "nixos-hardware", + "rev": "52113c4f5cfd1e823001310e56d9c8d0699a6226", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-24.05", + "ref": "master", + "repo": "nixos-hardware", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1762363567, + "narHash": "sha256-YRqMDEtSMbitIMj+JLpheSz0pwEr0Rmy5mC7myl17xs=", + "owner": "NixOS", "repo": "nixpkgs", + "rev": "ae814fd3904b621d8ab97418f1d0f2eb0d3716f4", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-25_05": { + "locked": { + "lastModified": 1761999846, + "narHash": "sha256-IYlYnp4O4dzEpL77BD/lj5NnJy2J8qbHkNSFiPBCbqo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3de8f8d73e35724bf9abef41f1bdbedda1e14a31", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-25.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-docs": { + "locked": { + "lastModified": 1705957679, + "narHash": "sha256-Q8LJaVZGJ9wo33wBafvZSzapYsjOaNjP/pOnSiKVGHY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "9a333eaa80901efe01df07eade2c16d183761fa3", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-23.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-for-bootstrap": { + "locked": { + "lastModified": 1720244366, + "narHash": "sha256-WrDV0FPMVd2Sq9hkR5LNHudS3OSMmUrs90JUTN+MXpA=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "49ee0e94463abada1de470c9c07bfc12b36dcf40", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1761373498, + "narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1761656231, + "narHash": "sha256-EiED5k6gXTWoAIS8yQqi5mAX6ojnzpHwAQTS3ykeYMg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e99366c665bdd53b7b500ccdc5226675cfc51f45", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_4": { + "locked": { + "lastModified": 1736061677, + "narHash": "sha256-DjkQPnkAfd7eB522PwnkGhOMuT9QVCZspDpJJYyOj60=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cbd8ec4de4469333c82ff40d057350c30e9f7d36", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixvim": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs_3", + "nuschtosSearch": "nuschtosSearch", + "systems": "systems_3" + }, + "locked": { + "lastModified": 1761744315, + "narHash": "sha256-OknzyEoI+VEYgk/FWMyx3tvjb/MPPyqS+G/aemDz51w=", + "owner": "nix-community", + "repo": "nixvim", + "rev": "6233fc6b2c3f203d8a5970f4a2c1df5777902717", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixvim", + "type": "github" + } + }, + "nmd": { + "inputs": { + "nixpkgs": [ + "nix-on-droid", + "nixpkgs-docs" + ], + "scss-reset": "scss-reset" + }, + "locked": { + "lastModified": 1705050560, + "narHash": "sha256-x3zzcdvhJpodsmdjqB4t5mkVW22V3wqHLOun0KRBzUI=", + "owner": "~rycee", + "repo": "nmd", + "rev": "66d9334933119c36f91a78d565c152a4fdc8d3d3", + "type": "sourcehut" + }, + "original": { + "owner": "~rycee", + "repo": "nmd", + "type": "sourcehut" + } + }, + "nmd_2": { + "flake": false, + "locked": { + "lastModified": 1666190571, + "narHash": "sha256-Z1hc7M9X6L+H83o9vOprijpzhTfOBjd0KmUTnpHAVjA=", + "owner": "rycee", + "repo": "nmd", + "rev": "b75d312b4f33bd3294cd8ae5c2ca8c6da2afc169", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmd", + "type": "gitlab" + } + }, + "nmt": { + "flake": false, + "locked": { + "lastModified": 1648075362, + "narHash": "sha256-u36WgzoA84dMVsGXzml4wZ5ckGgfnvS0ryzo/3zn/Pc=", + "owner": "rycee", + "repo": "nmt", + "rev": "d83601002c99b78c89ea80e5e6ba21addcfe12ae", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmt", + "type": "gitlab" + } + }, + "nmt_2": { + "flake": false, + "locked": { + "lastModified": 1648075362, + "narHash": "sha256-u36WgzoA84dMVsGXzml4wZ5ckGgfnvS0ryzo/3zn/Pc=", + "owner": "rycee", + "repo": "nmt", + "rev": "d83601002c99b78c89ea80e5e6ba21addcfe12ae", + "type": "gitlab" + }, + "original": { + "owner": "rycee", + "repo": "nmt", + "type": "gitlab" + } + }, + "nuschtosSearch": { + "inputs": { + "flake-utils": "flake-utils", + "ixx": "ixx", + "nixpkgs": [ + "osbm-nvim", + "nixvim", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1761730856, + "narHash": "sha256-t1i5p/vSWwueZSC0Z2BImxx3BjoUDNKyC2mk24krcMY=", + "owner": "NuschtOS", + "repo": "search", + "rev": "e29de6db0cb3182e9aee75a3b1fd1919d995d85b", + "type": "github" + }, + "original": { + "owner": "NuschtOS", + "repo": "search", + "type": "github" + } + }, + "osbm-nvim": { + "inputs": { + "nix-formatter-pack": "nix-formatter-pack_2", + "nixpkgs": "nixpkgs_2", + "nixvim": "nixvim" + }, + "locked": { + "lastModified": 1761771567, + "narHash": "sha256-EC8Bpx6KIU0fHbhQVM6p8j+ZH56UfZ7mrVTl80d8Vcs=", + "owner": "osbm", + "repo": "osbm-nvim", + "rev": "8f08a58beafbcb94ddd6fb2d24975dd736e236d0", + "type": "github" + }, + "original": { + "owner": "osbm", + "repo": "osbm-nvim", + "type": "github" + } + }, + "raspberry-pi-nix": { + "inputs": { + "libcamera-src": "libcamera-src", + "libpisp-src": "libpisp-src", + "nixpkgs": "nixpkgs_4", + "rpi-bluez-firmware-src": "rpi-bluez-firmware-src", + "rpi-firmware-nonfree-src": "rpi-firmware-nonfree-src", + "rpi-firmware-src": "rpi-firmware-src", + "rpi-linux-6_12_17-src": "rpi-linux-6_12_17-src", + "rpi-linux-6_6_78-src": "rpi-linux-6_6_78-src", + "rpi-linux-stable-src": "rpi-linux-stable-src", + "rpicam-apps-src": "rpicam-apps-src" + }, + "locked": { + "lastModified": 1742223591, + "narHash": "sha256-ZNTz8r5jlJ1jvpqf5+aUYgpnYJSVX0iP14doOc1Hm0E=", + "owner": "nix-community", + "repo": "raspberry-pi-nix", + "rev": "3e8100d5e976a6a2be363015cb33463af9ef441a", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "raspberry-pi-nix", "type": "github" } }, "root": { "inputs": { - "nixpkgs": "nixpkgs" + "agenix": "agenix", + "disko": "disko", + "home-manager": "home-manager", + "impermanence": "impermanence", + "mobile-nixos": "mobile-nixos", + "nix-darwin": "nix-darwin", + "nix-index-database": "nix-index-database", + "nix-on-droid": "nix-on-droid", + "nixos-hardware": "nixos-hardware", + "nixpkgs": "nixpkgs", + "osbm-nvim": "osbm-nvim", + "raspberry-pi-nix": "raspberry-pi-nix", + "simple-nixos-mailserver": "simple-nixos-mailserver" + } + }, + "rpi-bluez-firmware-src": { + "flake": false, + "locked": { + "lastModified": 1708969706, + "narHash": "sha256-KakKnOBeWxh0exu44beZ7cbr5ni4RA9vkWYb9sGMb8Q=", + "owner": "RPi-Distro", + "repo": "bluez-firmware", + "rev": "78d6a07730e2d20c035899521ab67726dc028e1c", + "type": "github" + }, + "original": { + "owner": "RPi-Distro", + "ref": "bookworm", + "repo": "bluez-firmware", + "type": "github" + } + }, + "rpi-firmware-nonfree-src": { + "flake": false, + "locked": { + "lastModified": 1723266537, + "narHash": "sha256-T7eTKXqY9cxEMdab8Snda4CEOrEihy5uOhA6Fy+Mhnw=", + "owner": "RPi-Distro", + "repo": "firmware-nonfree", + "rev": "4b356e134e8333d073bd3802d767a825adec3807", + "type": "github" + }, + "original": { + "owner": "RPi-Distro", + "ref": "bookworm", + "repo": "firmware-nonfree", + "type": "github" + } + }, + "rpi-firmware-src": { + "flake": false, + "locked": { + "lastModified": 1728405098, + "narHash": "sha256-4gnK0KbqFnjBmWia9Jt2gveVWftmHrprpwBqYVqE/k0=", + "owner": "raspberrypi", + "repo": "firmware", + "rev": "7bbb5f80d20a2335066a8781459c9f33e5eebc64", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "1.20241008", + "repo": "firmware", + "type": "github" + } + }, + "rpi-linux-6_12_17-src": { + "flake": false, + "locked": { + "lastModified": 1740765145, + "narHash": "sha256-hoCsGc4+RC/2LmxDtswLBL5ZhWlw4vSiL4Vkl39r2MU=", + "owner": "raspberrypi", + "repo": "linux", + "rev": "5985ce32e511f4e8279a841a1b06a8c7d972b386", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "rpi-6.12.y", + "repo": "linux", + "type": "github" + } + }, + "rpi-linux-6_6_78-src": { + "flake": false, + "locked": { + "lastModified": 1740503700, + "narHash": "sha256-Y8+ot4Yi3UKwlZK3ap15rZZ16VZDvmeFkD46+6Ku7bE=", + "owner": "raspberrypi", + "repo": "linux", + "rev": "2e071057fded90e789c0101498e45a1778be93fe", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "rpi-6.6.y", + "repo": "linux", + "type": "github" + } + }, + "rpi-linux-stable-src": { + "flake": false, + "locked": { + "lastModified": 1728403745, + "narHash": "sha256-phCxkuO+jUGZkfzSrBq6yErQeO2Td+inIGHxctXbD5U=", + "owner": "raspberrypi", + "repo": "linux", + "rev": "5aeecea9f4a45248bcf564dec924965e066a7bfd", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "stable_20241008", + "repo": "linux", + "type": "github" + } + }, + "rpicam-apps-src": { + "flake": false, + "locked": { + "lastModified": 1727515047, + "narHash": "sha256-qCYGrcibOeGztxf+sd44lD6VAOGoUNwRqZDdAmcTa/U=", + "owner": "raspberrypi", + "repo": "rpicam-apps", + "rev": "a8ccf9f3cd9df49875dfb834a2b490d41d226031", + "type": "github" + }, + "original": { + "owner": "raspberrypi", + "ref": "v1.5.2", + "repo": "rpicam-apps", + "type": "github" + } + }, + "scss-reset": { + "flake": false, + "locked": { + "lastModified": 1631450058, + "narHash": "sha256-muDlZJPtXDIGevSEWkicPP0HQ6VtucbkMNygpGlBEUM=", + "owner": "andreymatin", + "repo": "scss-reset", + "rev": "0cf50e27a4e95e9bb5b1715eedf9c54dee1a5a91", + "type": "github" + }, + "original": { + "owner": "andreymatin", + "repo": "scss-reset", + "type": "github" + } + }, + "simple-nixos-mailserver": { + "inputs": { + "blobs": "blobs", + "flake-compat": "flake-compat", + "git-hooks": "git-hooks", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-25_05": "nixpkgs-25_05" + }, + "locked": { + "lastModified": 1762302830, + "narHash": "sha256-f3xe6CRPT51vCQFZotJOXi/JpGOiukz0WIa86arJSE8=", + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "rev": "58659fbdfd8aba9bd8f4517d3e5c388c4d8266c4", + "type": "gitlab" + }, + "original": { + "owner": "simple-nixos-mailserver", + "repo": "nixos-mailserver", + "type": "gitlab" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index e2e981d..34b0a22 100644 --- a/flake.nix +++ b/flake.nix @@ -1,19 +1,131 @@ { description = "My system configuration"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixConfig = { + extra-substituters = [ + "https://nix-community.cachix.org" + # "http://wallfacer.curl-boga.ts.net:7080/main" + ]; + extra-trusted-public-keys = [ + "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" + # "main:2AjPdIsbKyoTGuw+4x2ZXMUT/353CXosW9pdbTQtjqw=" + ]; }; - outputs = { self, nixpkgs, ... }: + inputs = { + agenix = { + url = "github:ryantm/agenix"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; + home-manager = { + url = "github:nix-community/home-manager"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nixos-hardware.url = "github:NixOS/nixos-hardware/master"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nix-darwin = { + url = "github:nix-darwin/nix-darwin/master"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + nix-on-droid = { + url = "github:nix-community/nix-on-droid"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + osbm-nvim.url = "github:osbm/osbm-nvim"; + raspberry-pi-nix = { + url = "github:nix-community/raspberry-pi-nix"; + }; + # colmena = { + # url = "github:zhaofengli/colmena"; + # inputs.nixpkgs.follows = "nixpkgs"; + # }; + nix-index-database = { + url = "github:nix-community/nix-index-database"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + disko = { + url = "github:nix-community/disko"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + impermanence.url = "github:nix-community/impermanence"; + mobile-nixos = { + url = "github:mobile-nixos/mobile-nixos"; + flake = false; + }; + simple-nixos-mailserver = { + url = "gitlab:simple-nixos-mailserver/nixos-mailserver"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + }; + + outputs = + { + self, + nixpkgs, + nix-on-droid, + nix-darwin, + ... + }@inputs: let - lib = nixpkgs.lib; - in { - nixosConfigurations = { - tartarus = lib.nixosSystem { - system = "x86_64-linux"; - modules = [ ./configuration.nix ]; + inherit (self) outputs; + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems f; + makePkgs = system: import nixpkgs { inherit system; }; + makeNixosConfig = + configName: + nixpkgs.lib.nixosSystem { + specialArgs = { inherit inputs outputs; }; + modules = [ ./hosts/nixos/${configName}/configuration.nix ]; }; + nixosConfigNames = builtins.attrNames (builtins.readDir ./hosts/nixos); + in + { + nixosConfigurations = nixpkgs.lib.genAttrs nixosConfigNames makeNixosConfig; + nixOnDroidConfigurations.default = nix-on-droid.lib.nixOnDroidConfiguration { + extraSpecialArgs = { inherit inputs outputs; }; + pkgs = import nixpkgs { system = "aarch64-linux"; }; + modules = [ ./hosts/nixOnDroidHosts/atreus/configuration.nix ]; }; + darwinConfigurations.prometheus = nix-darwin.lib.darwinSystem { + system = "x86_64-darwin"; + modules = [ ./hosts/darwinHosts/prometheus/configuration.nix ]; + specialArgs = { inherit inputs outputs; }; + }; + lib = import ./lib { inherit (nixpkgs) lib; }; + formatter = forAllSystems (system: (makePkgs system).nixfmt-tree); + + nixosModules.default = ./modules/nixos; + homeManagerModules.default = ./modules/home-manager; + # packages = forAllSystems ( + # system: + # let + # makeNixosConfigWithSystemOverride = + # configName: + # nixpkgs.lib.nixosSystem { + # specialArgs = { inherit inputs outputs; }; + # modules = [ + # ./hosts/nixos/${configName}/configuration.nix + # { nixpkgs.hostPlatform = nixpkgs.lib.mkForce system; } + # ]; + # }; + # dotfilesMachineNames = [ + # "ymir" + # "pochita" + # "tartarus" + # "wallfacer" + # ]; + # in + # builtins.listToAttrs ( + # map (name: { + # name = "${name}-dotfiles"; + # value = (makeNixosConfigWithSystemOverride name).config.home-manager.users.osbm.home-files; + # }) dotfilesMachineNames + # ) + # ); }; } diff --git a/hosts/darwinHosts/prometheus/configuration.nix b/hosts/darwinHosts/prometheus/configuration.nix new file mode 100644 index 0000000..2b30813 --- /dev/null +++ b/hosts/darwinHosts/prometheus/configuration.nix @@ -0,0 +1,59 @@ +{ + pkgs, + inputs, + ... +}: +{ + imports = [ + ../../../modules/nixos/options.nix + ../../../modules/nixos/programs/command-line.nix + ../../../modules/nixos/programs/neovim.nix + ../../../modules/nixos/system/nix-settings.nix + inputs.home-manager.darwinModules.home-manager + ]; + + osbmModules = { + desktopEnvironment = "none"; # fuckass darwin defaults + machineType = "laptop"; + programs.neovim.enable = true; + }; + + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + verbose = true; + backupFileExtension = "hmbak"; + users.osbm = { + imports = [ ../../../modules/home-manager ]; + home.stateVersion = "24.11"; + }; + }; + + services.tailscale = { + enable = true; + }; + + programs.fish.enable = true; + + # osbmModules.setUsers = false; + users.users.osbm = { + description = "osbm"; + shell = pkgs.fish; + home = "/Users/osbm"; + }; + environment.systemPackages = with pkgs; [ + alacritty + # ghostty + kitty + vscode + git + lazygit + # blender + # libreoffice + # ungoogled-chromium + code-cursor + ollama + ]; + system.stateVersion = 6; + nixpkgs.hostPlatform = "x86_64-darwin"; +} diff --git a/hosts/nixOnDroidHosts/atreus/configuration.nix b/hosts/nixOnDroidHosts/atreus/configuration.nix new file mode 100644 index 0000000..28c4c0f --- /dev/null +++ b/hosts/nixOnDroidHosts/atreus/configuration.nix @@ -0,0 +1,97 @@ +{ + pkgs, + ... +}: +{ + user.userName = "osbm"; + + # Read the changelog before changing this value + system.stateVersion = "24.05"; + # Set up nix for flakes + nix.extraOptions = '' + experimental-features = nix-command flakes + ''; + + build.activation.sshd = '' + if [ ! -e /etc/ssh/ssh_host_ed25519_key ]; then + $VERBOSE_ECHO "Generating host keys..." + $DRY_RUN_CMD ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -a 32 -f "/etc/ssh/ssh_host_ed25519_key" -N "" + fi + ''; + + environment = { + packages = with pkgs; [ + vim # or some other editor, e.g. nano or neovim + procps + inetutils + findutils + utillinux + tzdata + hostname + man + gnugrep + zip + unzip + fish + tmux + nano + ripgrep + git + openssh + just + nh + (pkgs.writeShellScriptBin "lg-rerouting" '' + ${pkgs.lazygit}/bin/lazygit --path /storage/emulated/0/Documents/rerouting + '') + (pkgs.writeShellScriptBin "sshd-start" '' + echo "Starting sshd on port 8022" + ${pkgs.openssh}/bin/sshd + '') + (pkgs.writeShellScriptBin "wake-ymir" '' + echo waking up ymir + ${pkgs.wakeonlan}/bin/wakeonlan 04:7c:16:e6:d9:13 + '') + # obsidian tools + # i need a background process that can just keep pulling and pushing changes just like the obsidian git plugin + # (pkgs.writeShellScriptBin "rerouting-sync-start" '' + # cd /storage/emulated/0/Documents/rerouting + # git pull + # git add --all + # git commit -m "Android sync" + # git push + # '') + (pkgs.writeShellScriptBin "rerouting-status" '' + cd /storage/emulated/0/Documents/rerouting + git fetch + git status + '') + (pkgs.writeShellScriptBin "rerouting-pull" '' + cd /storage/emulated/0/Documents/rerouting + git pull + '') + (pkgs.writeShellScriptBin "rerouting-push" '' + cd /storage/emulated/0/Documents/rerouting + git add --all + git commit -m "Android sync" + git push + '') + ani-cli + ]; + + # Backup etc files instead of failing to activate generation if a file already exists in /etc + etcBackupExtension = ".bak"; + + etc."ssh/sshd_config".text = '' + AcceptEnv LANG LC_* + KbdInteractiveAuthentication no + PasswordAuthentication no + PermitRootLogin no + Port 8022 + PrintMotd no + AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u + ''; + etc."ssh/authorized_keys.d/osbm".text = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k + ''; + }; +} diff --git a/hosts/nixOnDroidHosts/luoji/configuration.nix b/hosts/nixOnDroidHosts/luoji/configuration.nix new file mode 100644 index 0000000..3e1025d --- /dev/null +++ b/hosts/nixOnDroidHosts/luoji/configuration.nix @@ -0,0 +1,97 @@ +{ + pkgs, + ... +}: +{ + user.userName = "osbm"; + + # Read the changelog before changing this value + system.stateVersion = "25.11"; + # Set up nix for flakes + nix.extraOptions = '' + experimental-features = nix-command flakes + ''; + + build.activation.sshd = '' + if [ ! -e /etc/ssh/ssh_host_ed25519_key ]; then + $VERBOSE_ECHO "Generating host keys..." + $DRY_RUN_CMD ${pkgs.openssh}/bin/ssh-keygen -t ed25519 -a 32 -f "/etc/ssh/ssh_host_ed25519_key" -N "" + fi + ''; + + environment = { + packages = with pkgs; [ + vim # or some other editor, e.g. nano or neovim + procps + inetutils + findutils + utillinux + tzdata + hostname + man + gnugrep + zip + unzip + fish + tmux + nano + ripgrep + git + openssh + just + nh + (pkgs.writeShellScriptBin "lg-rerouting" '' + ${pkgs.lazygit}/bin/lazygit --path /storage/emulated/0/Documents/rerouting + '') + (pkgs.writeShellScriptBin "sshd-start" '' + echo "Starting sshd on port 8022" + ${pkgs.openssh}/bin/sshd + '') + (pkgs.writeShellScriptBin "wake-ymir" '' + echo waking up ymir + ${pkgs.wakeonlan}/bin/wakeonlan 04:7c:16:e6:d9:13 + '') + # obsidian tools + # i need a background process that can just keep pulling and pushing changes just like the obsidian git plugin + # (pkgs.writeShellScriptBin "rerouting-sync-start" '' + # cd /storage/emulated/0/Documents/rerouting + # git pull + # git add --all + # git commit -m "Android sync" + # git push + # '') + (pkgs.writeShellScriptBin "rerouting-status" '' + cd /storage/emulated/0/Documents/rerouting + git fetch + git status + '') + (pkgs.writeShellScriptBin "rerouting-pull" '' + cd /storage/emulated/0/Documents/rerouting + git pull + '') + (pkgs.writeShellScriptBin "rerouting-push" '' + cd /storage/emulated/0/Documents/rerouting + git add --all + git commit -m "Android sync" + git push + '') + ani-cli + ]; + + # Backup etc files instead of failing to activate generation if a file already exists in /etc + etcBackupExtension = ".bak"; + + etc."ssh/sshd_config".text = '' + AcceptEnv LANG LC_* + KbdInteractiveAuthentication no + PasswordAuthentication no + PermitRootLogin no + Port 8022 + PrintMotd no + AuthorizedKeysFile /etc/ssh/authorized_keys.d/%u + ''; + etc."ssh/authorized_keys.d/osbm".text = '' + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k + ''; + }; +} diff --git a/hosts/nixos/apollo/configuration.nix b/hosts/nixos/apollo/configuration.nix new file mode 100644 index 0000000..9f34390 --- /dev/null +++ b/hosts/nixos/apollo/configuration.nix @@ -0,0 +1,110 @@ +{ lib, ... }: +{ + imports = [ + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "none"; + machineType = "server"; + users = [ "osbm" ]; + services = { + glance.enable = true; + # anubis.enable = true; + mailserver.enable = true; + nginx.enable = true; + forgejo.enable = true; + vaultwarden.enable = true; + immich.enable = true; + actual.enable = true; + firefox-syncserver.enable = true; + # seafile.enable = true; + }; + + hardware = { + sound.enable = false; + hibernation.enable = false; + + disko = { + enable = true; + fileSystem = "zfs"; + + initrd-ssh = { + enable = true; + authorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k" + ]; + ethernetDrivers = [ + "virtio_pci" # QEMU support + "virtio_net" + "virtio_pci" + "virtio_blk" + "virtio_balloon" + "virtio_console" + "virtio_gpu" + ]; + }; + + zfs = { + enable = true; + hostID = "0f7de22e"; + root = { + useTmpfs = false; # Use ZFS root, not tmpfs + encrypt = true; + disk1 = "vda"; + impermanenceRoot = true; # Wipe root on boot with ZFS snapshots + }; + }; + }; + }; + }; + + system.stateVersion = "25.11"; + networking.hostName = "apollo"; + + # Enable zram swap + zramSwap.enable = true; + + users.mutableUsers = false; + + # Disable sudo lecture message + security.sudo.extraConfig = '' + Defaults lecture = never + ''; + + # server is in germany + time.timeZone = "Europe/Berlin"; # or "Europe/Amsterdam" + + # Network configuration + networking = { + useDHCP = false; + interfaces.eth0 = { + useDHCP = false; + ipv4.addresses = [ + { + address = "152.53.152.129"; + prefixLength = 22; + } + ]; + ipv6.addresses = [ + { + address = "2a00:11c0:47:3b2a::1"; + prefixLength = 64; + } + ]; + }; + defaultGateway = "152.53.152.1"; + defaultGateway6 = { + address = "fe80::1"; + interface = "eth0"; + }; + nameservers = [ + "1.1.1.1" + "8.8.8.8" + ]; # Cloudflare and Google DNS + }; + + # Override initrd kernel params for static IP + boot.kernelParams = [ "ip=152.53.152.129::152.53.152.1:255.255.252.0::eth0:none" ]; + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; +} diff --git a/hosts/nixos/artemis/configuration.nix b/hosts/nixos/artemis/configuration.nix new file mode 100644 index 0000000..8261289 --- /dev/null +++ b/hosts/nixos/artemis/configuration.nix @@ -0,0 +1,46 @@ +{ + inputs, + pkgs, + lib, + ... +}: +{ + imports = [ + (import "${inputs.mobile-nixos}/lib/configuration.nix" { device = "oneplus-enchilada"; }) + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "gnome"; + machineType = "mobile"; + hardware.systemd-boot.enable = false; # Mobile devices use different bootloader + programs.graphical.enable = false; + }; + + # mobile-nixos needs aliases (uses nettools instead of net-tools) + nixpkgs = { + config = { + allowAliases = true; + allowUnfreePredicate = + pkg: + builtins.elem (lib.getName pkg) [ + "oneplus-sdm845-firmware-zstd" + "oneplus-sdm845-firmware" + ]; + }; + system = "aarch64-linux"; + }; + # Minimal essential packages + environment.systemPackages = with pkgs; [ + git + vim + wget + curl + lazygit + asciiquarium + neovim + kitty + ]; + + system.stateVersion = "25.11"; +} diff --git a/hosts/nixos/harmonica-sd/configuration.nix b/hosts/nixos/harmonica-sd/configuration.nix new file mode 100644 index 0000000..e3a84f7 --- /dev/null +++ b/hosts/nixos/harmonica-sd/configuration.nix @@ -0,0 +1,48 @@ +{ + inputs, + ... +}: +{ + imports = [ + ./sd-image.nix + "${inputs.nixpkgs}/nixos/modules/installer/sd-card/sd-image-aarch64.nix" + ./hardware-configuration.nix + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "none"; + fonts.enable = false; + services.tailscale.enable = true; + hardware.systemd-boot.enable = false; # SD card uses extlinux + }; + + system.stateVersion = "25.05"; + + networking.hostName = "harmonica"; + + networking = { + interfaces."wlan0".useDHCP = true; + wireless = { + enable = true; + interfaces = [ "wlan0" ]; + networks = { + "House_Bayram" = { + psk = "PASSWORD"; + }; + "it_hurts_when_IP" = { + psk = "PASSWORD"; + }; + }; + }; + }; + + # NTP time sync. + services.timesyncd.enable = true; + + security.sudo = { + enable = true; + wheelNeedsPassword = false; + }; + services.getty.autologinUser = "osbm"; +} diff --git a/hosts/nixos/harmonica-sd/hardware-configuration.nix b/hosts/nixos/harmonica-sd/hardware-configuration.nix new file mode 100644 index 0000000..cc3ed25 --- /dev/null +++ b/hosts/nixos/harmonica-sd/hardware-configuration.nix @@ -0,0 +1,85 @@ +{ + pkgs, + lib, + ... +}: +{ + # Some packages (ahci fail... this bypasses that) https://discourse.nixos.org/t/does-pkgs-linuxpackages-rpi3-build-all-required-kernel-modules/42509 + nixpkgs.overlays = [ + (_final: super: { + makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; }); + }) + ]; + + zramSwap = { + enable = true; + algorithm = "zstd"; + }; + + image.fileName = "zero2.img"; + sdImage = { + # bzip2 compression takes loads of time with emulation, skip it. Enable this if you're low on space. + compressImage = false; + + extraFirmwareConfig = { + # Give up VRAM for more Free System Memory + # - Disable camera which automatically reserves 128MB VRAM + start_x = 0; + # - Reduce allocation of VRAM to 16MB minimum for non-rotated (32MB for rotated) + gpu_mem = 16; + + # Configure display to 800x600 so it fits on most screens + # * See: https://elinux.org/RPi_Configuration + hdmi_group = 2; + hdmi_mode = 8; + }; + }; + + hardware = { + enableRedistributableFirmware = lib.mkForce false; + firmware = [ pkgs.raspberrypiWirelessFirmware ]; # Keep this to make sure wifi works + i2c.enable = true; + deviceTree.filter = "bcm2837-rpi-zero*.dtb"; + deviceTree.overlays = [ + { + name = "enable-i2c"; + dtsText = '' + /dts-v1/; + /plugin/; + / { + compatible = "brcm,bcm2837"; + fragment@0 { + target = <&i2c1>; + __overlay__ { + status = "okay"; + }; + }; + }; + ''; + } + ]; + }; + + boot = { + kernelPackages = pkgs.linuxKernel.packages.linux_rpi3; + + initrd.availableKernelModules = [ + "xhci_pci" + "usbhid" + "usb_storage" + ]; + loader = { + grub.enable = false; + generic-extlinux-compatible.enable = true; + }; + extraModprobeConfig = '' + options brcmfmac roamoff=1 feature_disable=0x82000 + ''; + + # Avoids warning: mdadm: Neither MAILADDR nor PROGRAM has been set. This will cause the `mdmon` service to crash. + # See: https://github.com/NixOS/nixpkgs/issues/254807 + swraid.enable = lib.mkForce false; + }; + + nixpkgs.hostPlatform = "aarch64-linux"; +} diff --git a/hosts/nixos/harmonica-sd/sd-image.nix b/hosts/nixos/harmonica-sd/sd-image.nix new file mode 100644 index 0000000..d6de7d4 --- /dev/null +++ b/hosts/nixos/harmonica-sd/sd-image.nix @@ -0,0 +1,39 @@ +# This module extends the official sd-image.nix with the following: +# - ability to add options to the config.txt firmware +{ + config, + lib, + ... +}: +{ + options.sdImage = with lib; { + extraFirmwareConfig = mkOption { + type = types.attrs; + default = { }; + description = lib.mdDoc '' + Extra configuration to be added to config.txt. + ''; + }; + }; + + config = { + sdImage.populateFirmwareCommands = + lib.mkIf ((lib.length (lib.attrValues config.sdImage.extraFirmwareConfig)) > 0) + ( + let + # Convert the set into a string of lines of "key=value" pairs. + keyValueMap = name: value: name + "=" + toString value; + keyValueList = lib.mapAttrsToList keyValueMap config.sdImage.extraFirmwareConfig; + extraFirmwareConfigString = lib.concatStringsSep "\n" keyValueList; + in + lib.mkAfter '' + config=firmware/config.txt + # The initial file has just been created without write permissions. Add them to be able to append the file. + chmod u+w $config + echo "\n# Extra configuration" >> $config + echo "${extraFirmwareConfigString}" >> $config + chmod u-w $config + '' + ); + }; +} diff --git a/hosts/nixos/harmonica/configuration.nix b/hosts/nixos/harmonica/configuration.nix new file mode 100644 index 0000000..4bb24af --- /dev/null +++ b/hosts/nixos/harmonica/configuration.nix @@ -0,0 +1,25 @@ +{ + imports = [ + ./hardware-configuration.nix + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "none"; + machineType = "server"; + hardware.systemd-boot.enable = false; # Uses extlinux bootloader + }; + + system.stateVersion = "25.05"; + + networking.hostName = "harmonica"; + + # NTP time sync. + services.timesyncd.enable = true; + + security.sudo = { + enable = true; + wheelNeedsPassword = false; + }; + # services.getty.autologinUser = "osbm"; +} diff --git a/hosts/nixos/harmonica/hardware-configuration.nix b/hosts/nixos/harmonica/hardware-configuration.nix new file mode 100644 index 0000000..e1489ad --- /dev/null +++ b/hosts/nixos/harmonica/hardware-configuration.nix @@ -0,0 +1,71 @@ +{ + pkgs, + lib, + ... +}: +{ + # Some packages (ahci fail... this bypasses that) https://discourse.nixos.org/t/does-pkgs-linuxpackages-rpi3-build-all-required-kernel-modules/42509 + nixpkgs.overlays = [ + (_final: super: { + makeModulesClosure = x: super.makeModulesClosure (x // { allowMissing = true; }); + }) + ]; + + zramSwap = { + enable = true; + algorithm = "zstd"; + }; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888"; + fsType = "ext4"; + }; + + hardware = { + enableRedistributableFirmware = lib.mkForce false; + firmware = [ pkgs.raspberrypiWirelessFirmware ]; # Keep this to make sure wifi works + i2c.enable = true; + deviceTree.filter = "bcm2837-rpi-zero*.dtb"; + deviceTree.overlays = [ + { + name = "enable-i2c"; + dtsText = '' + /dts-v1/; + /plugin/; + / { + compatible = "brcm,bcm2837"; + fragment@0 { + target = <&i2c1>; + __overlay__ { + status = "okay"; + }; + }; + }; + ''; + } + ]; + }; + + boot = { + kernelPackages = pkgs.linuxKernel.packages.linux_rpi3; + + initrd.availableKernelModules = [ + "xhci_pci" + "usbhid" + "usb_storage" + ]; + loader = { + grub.enable = false; + generic-extlinux-compatible.enable = true; + }; + extraModprobeConfig = '' + options brcmfmac roamoff=1 feature_disable=0x82000 + ''; + + # Avoids warning: mdadm: Neither MAILADDR nor PROGRAM has been set. This will cause the `mdmon` service to crash. + # See: https://github.com/NixOS/nixpkgs/issues/254807 + swraid.enable = lib.mkForce false; + }; + + nixpkgs.hostPlatform = "aarch64-linux"; +} diff --git a/hosts/nixos/iso/configuration.nix b/hosts/nixos/iso/configuration.nix new file mode 100644 index 0000000..f1f82f9 --- /dev/null +++ b/hosts/nixos/iso/configuration.nix @@ -0,0 +1,39 @@ +{ + lib, + pkgs, + inputs, + ... +}: +{ + imports = [ + "${inputs.nixpkgs}/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma6.nix" + + ]; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + nixpkgs.config.allowUnfree = true; + # Set environment variable for allowing non-free packages + environment.sessionVariables = { + NIXPKGS_ALLOW_UNFREE = "1"; + }; + + environment.systemPackages = with pkgs; [ + # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default. + git + curl + parted + nano + comma + just + age + neovim + wget + ]; + + services.openssh.enable = true; +} diff --git a/hosts/nixos/pochita-sd/configuration.nix b/hosts/nixos/pochita-sd/configuration.nix new file mode 100644 index 0000000..ae3bbe0 --- /dev/null +++ b/hosts/nixos/pochita-sd/configuration.nix @@ -0,0 +1,57 @@ +{ + pkgs, + inputs, + ... +}: +{ + imports = [ + inputs.raspberry-pi-nix.nixosModules.raspberry-pi + inputs.raspberry-pi-nix.nixosModules.sd-image + ]; + # bcm2711 for rpi 3, 3+, 4, zero 2 w + # bcm2712 for rpi 5 + # See the docs at: + # https://www.raspberrypi.com/documentation/computers/linux_kernel.html#native-build-configuration + raspberry-pi-nix.board = "bcm2712"; + time.timeZone = "America/Chicago"; + users.users.root = { + initialPassword = "root"; + }; + # Define a user account. Don't forget to set a password with ‘passwd’. + users.users.osbm = { + isNormalUser = true; + extraGroups = [ "wheel" ]; # Enable ‘sudo’ for the user. + initialPassword = "changeme"; + }; + + networking = { + hostName = "pochita"; + }; + environment.systemPackages = with pkgs; [ + neovim + git-lfs + git + wakeonlan + htop + unzip + zip + wget + ]; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + + nix.settings.trusted-users = [ + "root" + "osbm" + ]; + + nixpkgs.hostPlatform = "aarch64-linux"; + + services.openssh = { + enable = true; + }; + system.stateVersion = "25.05"; +} diff --git a/hosts/nixos/pochita/configuration.nix b/hosts/nixos/pochita/configuration.nix new file mode 100644 index 0000000..5f0772b --- /dev/null +++ b/hosts/nixos/pochita/configuration.nix @@ -0,0 +1,41 @@ +{ + pkgs, + inputs, + ... +}: +{ + imports = [ + ./hardware-configuration.nix + ../../../modules/nixos + inputs.raspberry-pi-nix.nixosModules.raspberry-pi + inputs.nixos-hardware.nixosModules.raspberry-pi-5 + ]; + + osbmModules = { + desktopEnvironment = "none"; + machineType = "server"; + hardware.systemd-boot.enable = false; # Raspberry Pi uses init-script bootloader + services = { + wanikani-bypass-lessons.enable = true; + wanikani-fetch-data.enable = true; + wanikani-stats.enable = true; + }; + }; + + zramSwap.enable = true; + + networking.hostName = "pochita"; + # log of shame: osbm blamed nix when he wrote "hostname" instead of "hostName" + + environment.systemPackages = [ + pkgs.raspberrypi-eeprom + ]; + + # The board and wanted kernel version + raspberry-pi-nix = { + board = "bcm2712"; + #kernel-version = "v6_10_12"; + }; + + system.stateVersion = "25.05"; +} diff --git a/hosts/nixos/pochita/hardware-configuration.nix b/hosts/nixos/pochita/hardware-configuration.nix new file mode 100644 index 0000000..530fa03 --- /dev/null +++ b/hosts/nixos/pochita/hardware-configuration.nix @@ -0,0 +1,47 @@ +{ + lib, + modulesPath, + ... +}: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd = { + availableKernelModules = [ ]; + kernelModules = [ ]; + }; + kernelModules = [ ]; + extraModulePackages = [ ]; + }; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/44444444-4444-4444-8888-888888888888"; + fsType = "ext4"; + }; + + "/boot/firmware" = { + device = "/dev/disk/by-uuid/2178-694E"; + fsType = "vfat"; + options = [ + "fmask=0022" + "dmask=0022" + ]; + }; + }; + + swapDevices = [ ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.end0.useDHCP = lib.mkDefault true; + # networking.interfaces.wlan0.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "aarch64-linux"; +} diff --git a/hosts/nixos/tartarus/configuration.nix b/hosts/nixos/tartarus/configuration.nix new file mode 100644 index 0000000..c1f654d --- /dev/null +++ b/hosts/nixos/tartarus/configuration.nix @@ -0,0 +1,21 @@ +{ + imports = [ + ./hardware-configuration.nix + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "plasma"; + machineType = "laptop"; + emulation.aarch64.enable = true; + hardware.sound.enable = true; + programs.steam.enable = true; + }; + + networking.hostName = "tartarus"; # Define your hostname. + + # Enable networking + networking.networkmanager.enable = true; + + system.stateVersion = "24.05"; # lalalalala +} diff --git a/hosts/nixos/tartarus/hardware-configuration.nix b/hosts/nixos/tartarus/hardware-configuration.nix new file mode 100644 index 0000000..56ed1cc --- /dev/null +++ b/hosts/nixos/tartarus/hardware-configuration.nix @@ -0,0 +1,53 @@ +{ + config, + lib, + modulesPath, + ... +}: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ + "xhci_pci" + "ahci" + "nvme" + "usb_storage" + "sd_mod" + ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + + fileSystems."/" = { + device = "/dev/disk/by-uuid/246d3df7-3578-44b2-8aee-c1ed33581184"; + fsType = "ext4"; + }; + + fileSystems."/boot" = { + device = "/dev/disk/by-uuid/33D0-6524"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + + swapDevices = [ + { device = "/dev/disk/by-uuid/b74b04db-c7ea-44e7-b3fe-15cd6d0cd851"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.eno1.useDHCP = lib.mkDefault true; + # networking.interfaces.wlo1.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/wallfacer/configuration.nix b/hosts/nixos/wallfacer/configuration.nix new file mode 100644 index 0000000..f7a4912 --- /dev/null +++ b/hosts/nixos/wallfacer/configuration.nix @@ -0,0 +1,18 @@ +{ + imports = [ + ./hardware-configuration.nix + ../../../modules/nixos + ]; + osbmModules = { + desktopEnvironment = "none"; + machineType = "server"; + services = { + hydra.enable = true; + atticd.enable = true; + cloudflared.enable = true; + }; + }; + + networking.hostName = "wallfacer"; + system.stateVersion = "25.05"; +} diff --git a/hosts/nixos/wallfacer/hardware-configuration.nix b/hosts/nixos/wallfacer/hardware-configuration.nix new file mode 100644 index 0000000..08d8270 --- /dev/null +++ b/hosts/nixos/wallfacer/hardware-configuration.nix @@ -0,0 +1,68 @@ +{ + config, + lib, + modulesPath, + ... +}: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot = { + initrd.availableKernelModules = [ + "ahci" + "ehci_pci" + "megaraid_sas" + "nvme" + "usbhid" + "usb_storage" + "sd_mod" + ]; + initrd.kernelModules = [ ]; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/8270dba5-6d89-438a-90bd-d9f29b20cb5b"; + fsType = "ext4"; + }; + + "/boot" = { + device = "/dev/disk/by-uuid/A1EB-43F8"; + fsType = "vfat"; + options = [ + "fmask=0077" + "dmask=0077" + ]; + }; + "/data/atreus" = { + device = "/dev/disk/by-uuid/1840c2af-fdb2-48b6-8555-2cecd1afb106"; + fsType = "ext4"; + }; + # 500 gb nvme pcie + "/data/kasio" = { + device = "/dev/disk/by-uuid/af74aa48-8513-4e31-a4b7-9fdd138e0002"; + fsType = "ext4"; + }; + }; + + swapDevices = [ + { device = "/dev/disk/by-uuid/534ea30c-2664-498b-915f-41b037eba01b"; } + ]; + + # Enables DHCP on each ethernet and wireless interface. In case of scripted networking + # (the default) this is the recommended approach. When using systemd-networkd it's + # still possible to use this option, but it's recommended to use it in conjunction + # with explicit per-interface declarations with `networking.interfaces..useDHCP`. + networking.useDHCP = lib.mkDefault true; + # networking.interfaces.eno1np0.useDHCP = lib.mkDefault true; + # networking.interfaces.eno2np1.useDHCP = lib.mkDefault true; + # networking.interfaces.eno3.useDHCP = lib.mkDefault true; + # networking.interfaces.eno4.useDHCP = lib.mkDefault true; + + nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; +} diff --git a/hosts/nixos/ymir/configuration.nix b/hosts/nixos/ymir/configuration.nix new file mode 100644 index 0000000..c261256 --- /dev/null +++ b/hosts/nixos/ymir/configuration.nix @@ -0,0 +1,43 @@ +{ + imports = [ + ./hardware-configuration.nix + ../../../modules/nixos + ]; + + osbmModules = { + desktopEnvironment = "plasma"; + machineType = "desktop"; + programs = { + adbFastboot.enable = true; + steam.enable = true; + }; + emulation.aarch64.enable = true; + virtualisation.docker.enable = true; + hardware = { + hibernation.enable = false; + wakeOnLan.enable = true; + sound.enable = true; + nvidia.enable = true; + }; + services = { + ollama.enable = true; + }; + i18n.enable = true; + }; + + networking = { + hostName = "ymir"; # Define your hostname. + + firewall.allowedTCPPorts = [ + 8889 + 8000 + ]; + + # Enable networking + networkmanager.enable = true; + }; + + virtualisation.waydroid.enable = true; + + system.stateVersion = "25.05"; # changing this is a great taboo of the nixos world +} diff --git a/hardware-configuration.nix b/hosts/nixos/ymir/hardware-configuration.nix similarity index 52% rename from hardware-configuration.nix rename to hosts/nixos/ymir/hardware-configuration.nix index ed2d3bb..c056897 100644 --- a/hardware-configuration.nix +++ b/hosts/nixos/ymir/hardware-configuration.nix @@ -1,39 +1,58 @@ # Do not modify this file! It was generated by ‘nixos-generate-config’ # and may be overwritten by future invocations. Please make changes # to /etc/nixos/configuration.nix instead. -{ config, lib, pkgs, modulesPath, ... }: - { - imports = - [ (modulesPath + "/installer/scan/not-detected.nix") - ]; + config, + lib, + modulesPath, + ... +}: +{ + imports = [ + (modulesPath + "/installer/scan/not-detected.nix") + ]; - boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "sd_mod" ]; - boot.initrd.kernelModules = [ ]; - boot.kernelModules = [ "kvm-intel" ]; - boot.extraModulePackages = [ ]; - - fileSystems."/" = - { device = "/dev/disk/by-uuid/246d3df7-3578-44b2-8aee-c1ed33581184"; + boot = { + initrd = { + availableKernelModules = [ + "xhci_pci" + "ahci" + "nvme" + "usbhid" + "usb_storage" + "sd_mod" + ]; + kernelModules = [ ]; + }; + kernelModules = [ "kvm-intel" ]; + extraModulePackages = [ ]; + }; + fileSystems = { + "/" = { + device = "/dev/disk/by-uuid/fd6792b4-d1ec-493c-a686-64dbeaac3371"; fsType = "ext4"; }; - fileSystems."/boot" = - { device = "/dev/disk/by-uuid/33D0-6524"; + "/boot" = { + device = "/dev/disk/by-uuid/383D-1E8A"; fsType = "vfat"; - options = [ "fmask=0077" "dmask=0077" ]; + options = [ + "fmask=0077" + "dmask=0077" + ]; }; + }; - swapDevices = - [ { device = "/dev/disk/by-uuid/b74b04db-c7ea-44e7-b3fe-15cd6d0cd851"; } - ]; + swapDevices = [ + { device = "/dev/disk/by-uuid/33c6277d-eb0a-487d-8be0-829829a8a308"; } + ]; # Enables DHCP on each ethernet and wireless interface. In case of scripted networking # (the default) this is the recommended approach. When using systemd-networkd it's # still possible to use this option, but it's recommended to use it in conjunction # with explicit per-interface declarations with `networking.interfaces..useDHCP`. networking.useDHCP = lib.mkDefault true; - # networking.interfaces.eno1.useDHCP = lib.mkDefault true; + # networking.interfaces.enp3s0.useDHCP = lib.mkDefault true; # networking.interfaces.wlo1.useDHCP = lib.mkDefault true; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; diff --git a/justfile b/justfile new file mode 100644 index 0000000..e985ea2 --- /dev/null +++ b/justfile @@ -0,0 +1,78 @@ +_default: + @just --list --unsorted + +check-git: + # git must be clean + test -z "$(git status --porcelain)" + +[linux] +build *args: check-git + sudo nixos-rebuild build --flake . {{args}} |& nom + nvd diff /run/current-system ./result + +[linux] +switch *args: check-git remove-hm-backup-files + #!/usr/bin/env sh + if [[ "$(hostname)" == "localhost" ]]; then + nix-on-droid switch --flake . {{args}} + else + nh os switch . {{args}} --accept-flake-config + fi + +[macos] +switch *args: check-git + nh darwin switch . -- --accept-flake-config {{args}} + +remove-hm-backup-files: + #!/usr/bin/env sh + + if [ -f ~/.gtkrc-2.0.hmbak ]; then + rm ~/.gtkrc-2.0.hmbak + fi + +test: + nh os test . + +update: + nix flake update + +check: + nix flake check + +repl: + nix repl -f flake:nixpkgs + +collect-garbage: + sudo nix-env --profile /nix/var/nix/profiles/system --delete-generations old + # home-manager expire-generations now + sudo nix-collect-garbage --delete-older-than 3d + +list-generations: + nixos-rebuild list-generations + +build-sd-image-harmonica: check-git + nom build -L .#nixosConfigurations.harmonica-sd.config.system.build.sdImage + +build-sd-image-pochita: check-git + nom build -L .#nixosConfigurations.pochita-sd.config.system.build.sdImage + +build-iso: check-git + nom build -L .#nixosConfigurations.myISO.config.system.build.isoImage + +flash-sd-image-harmonica: + # raise error because this command should be edited before running + false + nom build -L .#nixosConfigurations.harmonica-sd.config.system.build.sdImage + sudo dd if=result/sd-image/nixos-image-sd-card-25.05.20250224.0196c01-aarch64-linux.img of=/dev/sda bs=4M status=progress conv=fsync + +setup-apollo-nixos: + nano /tmp/secret.key + sudo nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode destroy,format,mount --flake github:osbm/flake#apollo + + sudo mkdir -p /mnt/etc/ssh + sudo ssh-keygen -t ed25519 -N "" -f /mnt/etc/ssh/initrd + + sudo nixos-install --flake github:osbm/flake#apollo --root /mnt --no-root-passwd + +sweep *args: + nix run github:jzbor/nix-sweep -- {{args}} \ No newline at end of file diff --git a/lib/default.nix b/lib/default.nix new file mode 100644 index 0000000..a31945a --- /dev/null +++ b/lib/default.nix @@ -0,0 +1,9 @@ +{ lib, ... }: +{ + + importList = lib.mapAttrsToList (name: _path: ./. + "/${name}") ( + lib.filterAttrs ( + filename: kind: filename != "default.nix" && (kind == "regular" || kind == "directory") + ) (builtins.readDir ./.) + ); +} diff --git a/modules/default.nix b/modules/default.nix new file mode 100644 index 0000000..c3bdd53 --- /dev/null +++ b/modules/default.nix @@ -0,0 +1,7 @@ +# Main module entry point +# Import the new NixOS module system +{ + imports = [ + ./nixos + ]; +} diff --git a/modules/home-manager/default.nix b/modules/home-manager/default.nix new file mode 100644 index 0000000..aea89a7 --- /dev/null +++ b/modules/home-manager/default.nix @@ -0,0 +1,32 @@ +{ lib, ... }: +{ + # Import all home-manager modules + imports = [ + ./programs + # no home manager services yet + # ./services + + ]; + + # Basic home-manager configuration + home.sessionVariables = { + EDITOR = lib.mkDefault "nvim"; + }; + + home.shellAliases = { + c = "code ."; + l = "eza --all --long --git --icons --group --sort size --header --group-directories-first"; + ll = "eza --all --long --git --icons --group --sort name --header --group-directories-first"; + free = "free -h"; + df = "df -h"; + du = "du -h"; + lg = "lazygit"; + onefetch = "onefetch -T prose -T programming -T data"; + }; + + # Don't set stateVersion here - let it be set by the system configuration + # home.stateVersion should be set in the system's home-manager configuration + + # Enable basic programs that most users want + programs.home-manager.enable = true; +} diff --git a/modules/home-manager/programs/alacritty.nix b/modules/home-manager/programs/alacritty.nix new file mode 100644 index 0000000..4a98495 --- /dev/null +++ b/modules/home-manager/programs/alacritty.nix @@ -0,0 +1,40 @@ +{ + lib, + pkgs, + nixosConfig, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf (nixosConfig != null && nixosConfig.osbmModules.desktopEnvironment != "none") { + # Set enableAlacritty to true by default when there's a desktop environment + programs.alacritty.enable = lib.mkDefault true; + }) + + { + programs.alacritty = { + settings = { + font = { + size = 14.0; + normal.family = "Cascadia Code"; + }; + terminal.shell = { + args = [ + "new-session" + "-A" + "-s" + "general" + ]; + program = lib.getExe pkgs.tmux; + }; + window = { + decorations = "None"; + opacity = 1; + startup_mode = "Maximized"; + }; + env.TERM = "xterm-256color"; + }; + }; + } + ]; +} diff --git a/modules/home-manager/programs/bash.nix b/modules/home-manager/programs/bash.nix new file mode 100644 index 0000000..90649bc --- /dev/null +++ b/modules/home-manager/programs/bash.nix @@ -0,0 +1,10 @@ +{ + programs.bash = { + enable = true; + bashrcExtra = '' + if [ "dumb" == "$TERM" ] ; then + export TERM=xterm-256color + fi + ''; + }; +} diff --git a/modules/home-manager/programs/default.nix b/modules/home-manager/programs/default.nix new file mode 100644 index 0000000..9da3ac0 --- /dev/null +++ b/modules/home-manager/programs/default.nix @@ -0,0 +1,18 @@ +{ + imports = [ + ./alacritty.nix + ./bash.nix + ./direnv.nix + ./firefox.nix + ./fish.nix + ./ghostty.nix + ./git.nix + ./mpv.nix + ./ssh.nix + ./starship.nix + ./tlrc.nix + ./tmux.nix + ./wezterm.nix + ./zoxide.nix + ]; +} diff --git a/modules/home-manager/programs/direnv.nix b/modules/home-manager/programs/direnv.nix new file mode 100644 index 0000000..2b51c9d --- /dev/null +++ b/modules/home-manager/programs/direnv.nix @@ -0,0 +1,6 @@ +{ + programs.direnv = { + enable = true; + nix-direnv.enable = true; + }; +} diff --git a/modules/home-manager/programs/firefox.nix b/modules/home-manager/programs/firefox.nix new file mode 100644 index 0000000..76f315c --- /dev/null +++ b/modules/home-manager/programs/firefox.nix @@ -0,0 +1,115 @@ +{ + lib, + nixosConfig ? null, # Receive the NixOS config + pkgs, + ... +}: +{ + config = lib.mkMerge [ + # Auto-enable Firefox if system has a desktop environment + (lib.mkIf (nixosConfig != null && nixosConfig.osbmModules.desktopEnvironment != "none") { + # Set enableFirefox to true by default when there's a desktop environment + programs.firefox.enable = lib.mkDefault true; + }) + + # Firefox configuration + { + programs.firefox = { + # TODO Firefox fails as the closure contains a reference to stdenv.cc + # Relax this assertion until the underlying issue is fixed + # https://github.com/NixOS/nixpkgs/pull/457424 + package = pkgs.firefox.overrideAttrs { disallowedRequisites = [ ]; }; + languagePacks = [ + "ja" + "tr" + "en-US" + ]; + policies = { + DisableTelemetry = true; + DisableFirefoxStudies = true; + EnableTrackingProtection = { + Value = true; + Locked = true; + Cryptomining = true; + Fingerprinting = true; + }; + # DisablePocket = true; + DisableFirefoxAccounts = true; + DisableAccounts = true; + DisableFirefoxScreenshots = true; + StartPage = "previous-session"; + # OverrideFirstRunPage = ""; + # OverridePostUpdatePage = ""; + # DontCheckDefaultBrowser = true; + DisplayBookmarksToolbar = "always"; # alternatives: "never" or "newtab" + # DisplayMenuBar = "default-off"; # alternatives: "always", "never" or "default-on" + # SearchBar = "unified"; # alternat + ExtensionSettings = + let + extension = shortId: uuid: { + name = uuid; + value = { + install_url = "https://addons.mozilla.org/en-US/firefox/downloads/latest/${shortId}/latest.xpi"; + installation_mode = "normal_installed"; # i dont want to get the packages from a non-open source source + }; + }; + in + builtins.listToAttrs [ + (extension "tree-style-tab" "treestyletab@piro.sakura.ne.jp") + (extension "ublock-origin" "uBlock0@raymondhill.net") + (extension "bitwarden-password-manager" "{446900e4-71c2-419f-a6a7-df9c091e268b}") + (extension "motivation-new-tab" "") + (extension "return-youtube-dislikes" "{762f9885-5a13-4abd-9c77-433dcd38b8fd}") + (extension "violentmonkey" "{aecec67f-0d10-4fa7-b7c7-609a2db280cf}") + (extension "vimium-ff" "{d7742d87-e61d-4b78-b8a1-b469842139fa}") + (extension "i-dont-care-about-cookies" "jid1-KKzOGWgsW3Ao4Q@jetpack") + # (extension "tabliss" "extension@tabliss.io") + # (extension "umatrix" "uMatrix@raymondhill.net") + # (extension "libredirect" "7esoorv3@alefvanoon.anonaddy.me") + (extension "clearurls" "{74145f27-f039-47ce-a470-a662b129930a}") + (extension "youtube-shorts-block" "") + ]; + # To add additional extensions, find it on addons.mozilla.org, find + # the short ID in the url (like https://addons.mozilla.org/en-US/firefox/addon/!SHORT_ID!/) + # Then, download the XPI by filling it in to the install_url template, unzip it, + # run `jq .browser_specific_settings.gecko.id manifest.json` or + # `jq .applications.gecko.id manifest.json` to get the UUID + }; + profiles.default = { + id = 0; + name = "osbm"; + + userChrome = '' + #tabbrowser-tabs { + visibility: collapse; + } + ''; + settings = { + # "Open previous windows and tabs" + "browser.startup.page" = 3; + "browser.contentblocking.category" = true; + "extensions.pocket.enabled" = false; + "extensions.screenshots.disabled" = true; + "browser.topsites.contile.enabled" = false; + "browser.formfill.enable" = false; + "browser.search.suggest.enabled" = false; + "browser.search.suggest.enabled.private" = false; + "browser.urlbar.suggest.searches" = false; + "browser.urlbar.showSearchSuggestionsFirst" = false; + "browser.newtabpage.activity-stream.feeds.section.topstories" = false; + "browser.newtabpage.activity-stream.feeds.snippets" = false; + "browser.newtabpage.activity-stream.section.highlights.includePocket" = false; + "browser.newtabpage.activity-stream.section.highlights.includeBookmarks" = false; + "browser.newtabpage.activity-stream.section.highlights.includeDownloads" = false; + "browser.newtabpage.activity-stream.section.highlights.includeVisited" = false; + "browser.newtabpage.activity-stream.showSponsored" = false; + "browser.newtabpage.activity-stream.system.showSponsored" = false; + "browser.newtabpage.activity-stream.showSponsoredTopSites" = false; + "toolkit.legacyUserProfileCustomizations.stylesheets" = true; + "ui.key.menuAccessKeyFocuses" = false; + }; + }; + }; + } + ]; +} diff --git a/modules/home-manager/programs/fish.nix b/modules/home-manager/programs/fish.nix new file mode 100644 index 0000000..f6311f5 --- /dev/null +++ b/modules/home-manager/programs/fish.nix @@ -0,0 +1,15 @@ +{ + programs.fish = { + enable = true; + interactiveShellInit = '' + set -g fish_greeting + ''; + functions = { + gitu = '' + git add --all + git commit -m "$argv" + git push + ''; + }; + }; +} diff --git a/modules/home-manager/programs/ghostty.nix b/modules/home-manager/programs/ghostty.nix new file mode 100644 index 0000000..6c50f2e --- /dev/null +++ b/modules/home-manager/programs/ghostty.nix @@ -0,0 +1,9 @@ +{ lib, nixosConfig, ... }: +{ + config = lib.mkMerge [ + (lib.mkIf (nixosConfig != null && nixosConfig.osbmModules.desktopEnvironment != "none") { + # Set enableGhostty to true by default when there's a desktop environment + programs.ghostty.enable = lib.mkDefault true; + }) + ]; +} diff --git a/modules/home-manager/programs/git.nix b/modules/home-manager/programs/git.nix new file mode 100644 index 0000000..f3cadfd --- /dev/null +++ b/modules/home-manager/programs/git.nix @@ -0,0 +1,54 @@ +{ + programs.git = { + enable = true; + signing = { + format = "openpgp"; + }; + ignores = [ + "*.pyc" # python + "*.swp" # vim + "__pycache__" # python + ".DS_Store" # macOS + "result" # nix + "node_modules" # node + ]; + settings = { + user = { + email = "osbm@osbm.dev"; + name = "osbm"; + }; + credential = { + helper = "store"; + }; + core = { + editor = "vim"; + pager = "cat"; + }; + diff = { + wsErrorHighlight = "all"; + }; + init = { + defaultBranch = "main"; + }; + http = { + postBuffer = 1048576000; + }; + https = { + postBuffer = 1048576000; + }; + push = { + autoSetupRemote = true; + }; + filter.lfs = { + clean = "git-lfs clean -- %f"; + smudge = "git-lfs smudge -- %f"; + process = "git-lfs filter-process"; + required = true; + }; + signing = { + signByDefault = true; + key = "3A264839184185CF"; + }; + }; + }; +} diff --git a/modules/home-manager/programs/mpv.nix b/modules/home-manager/programs/mpv.nix new file mode 100644 index 0000000..0353ae2 --- /dev/null +++ b/modules/home-manager/programs/mpv.nix @@ -0,0 +1,18 @@ +{ lib, nixosConfig, ... }: +{ + config = lib.mkMerge [ + (lib.mkIf (nixosConfig != null && nixosConfig.osbmModules.desktopEnvironment != "none") { + programs.mpv.enable = lib.mkDefault true; + }) + + { + programs.mpv = { + config = { + hwdec = "auto"; + vo = "gpu"; + }; + }; + } + + ]; +} diff --git a/modules/home-manager/programs/ssh.nix b/modules/home-manager/programs/ssh.nix new file mode 100644 index 0000000..fcfeaa1 --- /dev/null +++ b/modules/home-manager/programs/ssh.nix @@ -0,0 +1,59 @@ +let + # define a block that just takes a hostname and returns attrset to not repeat the same fields + sshBlock = hostname: { + inherit hostname; + user = "osbm"; + identityFile = "~/.ssh/id_ed25519"; + extraOptions = { + # [ERROR] - (starship::print): Under a 'dumb' terminal (TERM=dumb). + "RemoteCommand" = "fish"; + "RequestTTY" = "force"; + }; + hashKnownHosts = true; + compression = true; + }; + # sshBlockAtreus is the same as sshBlock but with 8090 as the port + sshBlockAtreus = hostname: { + inherit hostname; + user = "osbm"; + identityFile = "~/.ssh/id_ed25519"; + port = 8022; + hashKnownHosts = true; + compression = true; + # fish not found error ??? + }; +in +{ + programs.ssh = { + enable = true; + enableDefaultConfig = false; + + matchBlocks = { + ymir = sshBlock "192.168.0.2"; + ymir-ts = sshBlock "ymir.curl-boga.ts.net"; + atreus = sshBlockAtreus "192.168.0.3"; + atreus-ts = sshBlockAtreus "atreus.curl-boga.ts.net"; + tartarus = sshBlock "192.168.0.4"; + tartarus-ts = sshBlock "tartarus.curl-boga.ts.net"; + pochita = sshBlock "192.168.0.9"; + pochita-ts = sshBlock "pochita.curl-boga.ts.net"; + harmonica = sshBlock "192.168.0.11"; + harmonica-ts = sshBlock "harmonica.curl-boga.ts.net"; + wallfacer = sshBlock "192.168.0.5"; + wallfacer-ts = sshBlock "wallfacer.curl-boga.ts.net"; + prometheus = sshBlock "192.168.0.12"; + prometheus-ts = sshBlock "prometheus.curl-boga.ts.net"; + apollo = sshBlock "152.53.152.129"; + apollo-ts = sshBlock "apollo.curl-boga.ts.net"; + apollo-initrd = { + hostname = "152.53.152.129"; + port = 2222; + user = "root"; + identityFile = "~/.ssh/id_ed25519"; + hashKnownHosts = true; + compression = true; + }; + # artemis + }; + }; +} diff --git a/modules/home-manager/programs/starship.nix b/modules/home-manager/programs/starship.nix new file mode 100644 index 0000000..44baeec --- /dev/null +++ b/modules/home-manager/programs/starship.nix @@ -0,0 +1,18 @@ +{ + programs.starship = { + enable = true; + enableFishIntegration = true; + settings = { + add_newline = false; + dart.disabled = true; + python.disabled = true; + nodejs.disabled = true; + c.disabled = true; + gradle.disabled = true; + java.disabled = true; + ruby.disabled = true; + rust.disabled = true; + typst.disabled = true; + }; + }; +} diff --git a/modules/home-manager/programs/tlrc.nix b/modules/home-manager/programs/tlrc.nix new file mode 100644 index 0000000..562273a --- /dev/null +++ b/modules/home-manager/programs/tlrc.nix @@ -0,0 +1,94 @@ +{ + pkgs, + config, + ... +}: +# stolen from https://github.com/dmarcoux/dotfiles +{ + home.packages = [ pkgs.tlrc ]; + xdg.configFile."tlrc/config.toml".text = '' + [cache] + dir = "${config.xdg.cacheHome}/tlrc" + mirror = "https://github.com/tldr-pages/tldr/releases/latest/download" + auto_update = true + max_age = 336 + languages = ["en", "tr", "ja"] + + [output] + show_title = false + platform_title = false + show_hyphens = false + example_prefix = "- " + compact = true + raw_markdown = false + + [indent] + title = 2 + description = 2 + bullet = 2 + example = 4 + + [style.title] + color = "magenta" + background = "default" + bold = true + underline = false + italic = false + dim = false + strikethrough = false + + [style.description] + color = "magenta" + background = "default" + bold = false + underline = false + italic = false + dim = false + strikethrough = false + + [style.bullet] + color = "green" + background = "default" + bold = false + underline = false + italic = false + dim = false + strikethrough = false + + [style.example] + color = "cyan" + background = "default" + bold = false + underline = false + italic = false + dim = false + strikethrough = false + + [style.url] + color = "red" + background = "default" + bold = false + underline = false + italic = true + dim = false + strikethrough = false + + [style.inline_code] + color = "yellow" + background = "default" + bold = false + underline = false + italic = true + dim = false + strikethrough = false + + [style.placeholder] + color = "red" + background = "default" + bold = false + underline = false + italic = true + dim = false + strikethrough = false + ''; +} diff --git a/modules/home-manager/programs/tmux.nix b/modules/home-manager/programs/tmux.nix new file mode 100644 index 0000000..4b6262e --- /dev/null +++ b/modules/home-manager/programs/tmux.nix @@ -0,0 +1,38 @@ +{ + pkgs, + lib, + ... +}: +{ + programs.tmux = { + enable = true; + historyLimit = 100000; + baseIndex = 1; + shortcut = "s"; + mouse = true; + shell = lib.getExe pkgs.fish; + plugins = with pkgs; [ + tmuxPlugins.sensible + tmuxPlugins.better-mouse-mode + { + plugin = tmuxPlugins.dracula; + extraConfig = '' + set -g @dracula-plugins "cpu-usage ram-usage gpu-usage battery" + set -g @dracula-show-left-icon hostname + set -g @dracula-git-show-current-symbol ✓ + set -g @dracula-git-no-repo-message "no-git" + set -g @dracula-show-timezone false + set -g @dracula-ignore-lspci true + ''; + } + ]; + extraConfig = '' + # Automatically renumber windows + set -g renumber-windows on + set -g allow-passthrough on + set -ga update-environment TERM + set -ga update-environment TERM_PROGRAM + set-option -g default-command "${lib.getExe pkgs.fish} -l" + ''; + }; +} diff --git a/modules/home-manager/programs/wezterm.nix b/modules/home-manager/programs/wezterm.nix new file mode 100644 index 0000000..2282220 --- /dev/null +++ b/modules/home-manager/programs/wezterm.nix @@ -0,0 +1,36 @@ +{ + lib, + pkgs, + nixosConfig, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf (nixosConfig != null && nixosConfig.osbmModules.desktopEnvironment != "none") { + programs.wezterm.enable = lib.mkDefault true; + }) + + { + programs.wezterm = { + extraConfig = '' + _G.shells = { + fish = '${lib.getExe pkgs.fish}' + }; + + wezterm.on('gui-startup', function(cmd) + local tab, pane, window = wezterm.mux.spawn_window(cmd or {}) + window:gui_window():maximize() + end) + + + return { + default_prog = { _G.shells.fish }, + window_decorations = "NONE", + hide_tab_bar_if_only_one_tab = true, + enable_wayland = false, + } + ''; + }; + } + ]; +} diff --git a/modules/home-manager/programs/zoxide.nix b/modules/home-manager/programs/zoxide.nix new file mode 100644 index 0000000..1c20b97 --- /dev/null +++ b/modules/home-manager/programs/zoxide.nix @@ -0,0 +1,6 @@ +{ + programs.zoxide = { + enable = true; + enableFishIntegration = true; + }; +} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix new file mode 100644 index 0000000..7d125ae --- /dev/null +++ b/modules/nixos/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./options.nix + ./programs + ./hardware + ./services + ./system + ]; +} diff --git a/modules/nixos/hardware/bluetooth.nix b/modules/nixos/hardware/bluetooth.nix new file mode 100644 index 0000000..ec44d02 --- /dev/null +++ b/modules/nixos/hardware/bluetooth.nix @@ -0,0 +1,7 @@ +{ config, lib, ... }: +{ + config = lib.mkIf config.osbmModules.hardware.bluetooth.enable { + hardware.bluetooth.enable = true; + hardware.bluetooth.powerOnBoot = true; + }; +} diff --git a/modules/nixos/hardware/boot.nix b/modules/nixos/hardware/boot.nix new file mode 100644 index 0000000..0fdbd96 --- /dev/null +++ b/modules/nixos/hardware/boot.nix @@ -0,0 +1,8 @@ +{ config, lib, ... }: + +{ + config = lib.mkIf config.osbmModules.hardware.systemd-boot.enable { + boot.loader.systemd-boot.enable = true; + boot.loader.efi.canTouchEfiVariables = true; + }; +} diff --git a/modules/nixos/hardware/default.nix b/modules/nixos/hardware/default.nix new file mode 100644 index 0000000..f916a3e --- /dev/null +++ b/modules/nixos/hardware/default.nix @@ -0,0 +1,11 @@ +{ + imports = [ + ./bluetooth.nix + ./boot.nix + ./sound.nix + ./nvidia.nix + ./hibernation.nix + ./wakeOnLan.nix + ./disko.nix + ]; +} diff --git a/modules/nixos/hardware/disko.nix b/modules/nixos/hardware/disko.nix new file mode 100644 index 0000000..d342c90 --- /dev/null +++ b/modules/nixos/hardware/disko.nix @@ -0,0 +1,341 @@ +{ + config, + inputs, + lib, + pkgs, + ... +}: +let + cfg = config.osbmModules.hardware.disko; + + # Default authorized keys for initrd SSH + defaultAuthorizedKeys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDF1TFwXbqdC1UyG75q3HO1n7/L3yxpeRLIq2kQ9DalI" + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHYSJ9ywFRJ747tkhvYWFkx/Y9SkLqv3rb7T1UuXVBWo" + ]; + + authorizedKeys = + if cfg.initrd-ssh.authorizedKeys != [ ] then + cfg.initrd-ssh.authorizedKeys + else + defaultAuthorizedKeys; +in +{ + imports = [ + inputs.disko.nixosModules.default + ]; + + config = lib.mkMerge [ + # Initrd SSH for remote unlocking + (lib.mkIf (cfg.enable && cfg.initrd-ssh.enable) { + boot = { + kernelParams = [ "ip=152.53.152.129::152.53.152.1:255.255.252.0::eth0:none" ]; + initrd = { + network.enable = true; + availableKernelModules = cfg.initrd-ssh.ethernetDrivers; + network.ssh = { + enable = true; + port = 2222; # different port to avoid conflicts + shell = "/bin/cryptsetup-askpass"; + inherit authorizedKeys; + hostKeys = [ "/etc/ssh/initrd" ]; + }; + secrets = { + "/etc/ssh/initrd" = "/etc/ssh/initrd"; + }; + }; + }; + }) + + # ZFS Configuration + (lib.mkIf (cfg.enable && cfg.zfs.enable) { + networking.hostId = cfg.zfs.hostID; + + environment.systemPackages = [ pkgs.zfs-prune-snapshots ]; + + boot = { + # ZFS does not support swapfiles + kernelParams = [ + "nohibernate" + "zfs.zfs_arc_max=17179869184" # 16GB ARC max + ]; + supportedFilesystems = [ + "vfat" + "zfs" + ]; + zfs = { + devNodes = "/dev/disk/by-id/"; + forceImportAll = true; + requestEncryptionCredentials = cfg.zfs.root.encrypt; + }; + }; + + services.zfs = { + autoScrub.enable = true; + trim.enable = true; + }; + + # Disko configuration for ZFS + disko.devices = { + disk = lib.mkMerge [ + # Storage pool disks (if enabled and not reinstalling) + (lib.mkIf (cfg.zfs.storage.enable && !cfg.amReinstalling) ( + lib.mkMerge ( + map (diskname: { + "${diskname}" = { + type = "disk"; + device = "/dev/${diskname}"; + content = { + type = "gpt"; + partitions = { + luks = { + size = "100%"; + content = { + type = "luks"; + name = "stg${diskname}"; + settings.allowDiscards = true; + passwordFile = "/tmp/secret.key"; + content = { + type = "zfs"; + pool = "zstorage"; + }; + }; + }; + }; + }; + }; + }) cfg.zfs.storage.disks + ) + )) + + # Root disk 1 (primary) + { + one = lib.mkIf (cfg.zfs.root.disk1 != "") { + type = "disk"; + device = "/dev/${cfg.zfs.root.disk1}"; + content = { + type = "gpt"; + partitions = { + ESP = { + label = "EFI"; + name = "ESP"; + size = "2048M"; + type = "EF00"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ + "defaults" + "umask=0077" + ]; + }; + }; + + # Encrypted root partition + luks = lib.mkIf cfg.zfs.root.encrypt { + size = "100%"; + content = { + type = "luks"; + name = "crypted1"; + settings.allowDiscards = true; + passwordFile = "/tmp/secret.key"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; + + # Unencrypted root partition + notluks = lib.mkIf (!cfg.zfs.root.encrypt) { + size = "100%"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; + }; + }; + + # Root disk 2 (mirror) + two = lib.mkIf (cfg.zfs.root.disk2 != "") { + type = "disk"; + device = "/dev/${cfg.zfs.root.disk2}"; + content = { + type = "gpt"; + partitions = { + luks = { + size = "100%"; + content = { + type = "luks"; + name = "crypted2"; + settings.allowDiscards = true; + passwordFile = "/tmp/secret.key"; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + }; + }; + }; + }; + } + ]; + + # ZFS pools + zpool = { + # Root pool + zroot = { + type = "zpool"; + mode = lib.mkIf cfg.zfs.root.mirror "mirror"; + rootFsOptions = { + canmount = "off"; + checksum = "edonr"; + compression = "zstd"; + dnodesize = "auto"; + mountpoint = "none"; + normalization = "formD"; + relatime = "on"; + "com.sun:auto-snapshot" = "false"; + }; + options = { + ashift = "12"; + autotrim = "on"; + }; + datasets = { + # Reserved space for ZFS CoW operations + reserved = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + inherit (cfg.zfs.root) reservation; + }; + }; + + # SSH keys dataset + etcssh = { + type = "zfs_fs"; + options.mountpoint = "legacy"; + mountpoint = "/etc/ssh"; + options."com.sun:auto-snapshot" = "false"; + postCreateHook = "zfs snapshot zroot/etcssh@empty"; + }; + + # Persistent data + persist = { + type = "zfs_fs"; + options.mountpoint = "legacy"; + mountpoint = "/persist"; + options."com.sun:auto-snapshot" = "false"; + postCreateHook = "zfs snapshot zroot/persist@empty"; + }; + + # Persistent save data + persistSave = { + type = "zfs_fs"; + options.mountpoint = "legacy"; + mountpoint = "/persist/save"; + options."com.sun:auto-snapshot" = "false"; + postCreateHook = "zfs snapshot zroot/persistSave@empty"; + }; + + # Nix store + nix = { + type = "zfs_fs"; + options.mountpoint = "legacy"; + mountpoint = "/nix"; + options = { + atime = "off"; + canmount = "on"; + "com.sun:auto-snapshot" = "false"; + }; + postCreateHook = "zfs snapshot zroot/nix@empty"; + }; + + # Root filesystem + root = { + type = "zfs_fs"; + options.mountpoint = "legacy"; + options."com.sun:auto-snapshot" = "false"; + mountpoint = "/"; + postCreateHook = "zfs snapshot zroot/root@empty"; + }; + }; + }; + + # Storage pool (if enabled and not reinstalling) + zstorage = lib.mkIf (cfg.zfs.storage.enable && !cfg.amReinstalling) { + type = "zpool"; + mode = lib.mkIf cfg.zfs.storage.mirror "mirror"; + rootFsOptions = { + canmount = "off"; + checksum = "edonr"; + compression = "zstd"; + dnodesize = "auto"; + mountpoint = "none"; + normalization = "formD"; + relatime = "on"; + "com.sun:auto-snapshot" = "false"; + }; + options = { + ashift = "12"; + autotrim = "on"; + }; + datasets = { + # Reserved space + reserved = { + type = "zfs_fs"; + options = { + canmount = "off"; + mountpoint = "none"; + inherit (cfg.zfs.storage) reservation; + }; + }; + + # Main storage + storage = { + type = "zfs_fs"; + mountpoint = "/storage"; + options = { + atime = "off"; + canmount = "on"; + "com.sun:auto-snapshot" = "false"; + }; + }; + + # Persistent save in storage + persistSave = { + type = "zfs_fs"; + mountpoint = "/storage/save"; + options = { + atime = "off"; + canmount = "on"; + "com.sun:auto-snapshot" = "false"; + }; + }; + }; + }; + }; + }; + + fileSystems = { + # Needed for agenix - SSH keys must be available before ZFS mounts + "/etc/ssh".neededForBoot = true; + # Needed for impermanence + "/persist".neededForBoot = true; + "/persist/save".neededForBoot = true; + }; + }) + + # Impermanence: wipe root on boot + (lib.mkIf (cfg.enable && cfg.zfs.enable && cfg.zfs.root.impermanenceRoot) { + boot.initrd.postResumeCommands = lib.mkAfter '' + zfs rollback -r zroot/root@empty + ''; + }) + ]; +} diff --git a/modules/nixos/hardware/hibernation.nix b/modules/nixos/hardware/hibernation.nix new file mode 100644 index 0000000..d52208f --- /dev/null +++ b/modules/nixos/hardware/hibernation.nix @@ -0,0 +1,12 @@ +{ lib, config, ... }: +{ + config = lib.mkIf (!config.osbmModules.hardware.hibernation.enable) { + # Disable hibernation/suspend + systemd.targets = { + sleep.enable = false; + suspend.enable = false; + hibernate.enable = false; + hybrid-sleep.enable = false; + }; + }; +} diff --git a/modules/nixos/hardware/nvidia.nix b/modules/nixos/hardware/nvidia.nix new file mode 100644 index 0000000..2762885 --- /dev/null +++ b/modules/nixos/hardware/nvidia.nix @@ -0,0 +1,68 @@ +{ + lib, + config, + pkgs, + ... +}: +{ + config = lib.mkIf config.osbmModules.hardware.nvidia.enable { + # Enable OpenGL + hardware.graphics = { + enable = true; + }; + + nixpkgs.config = { + cudaSupport = true; + cudaCapabilities = [ "8.9" ]; # 4090 + }; + + # Load nvidia driver for Xorg and Wayland + services.xserver.videoDrivers = [ "nvidia" ]; + + hardware = { + nvidia = { + # Modesetting is required. + modesetting.enable = true; + + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + # Enable this if you have graphical corruption issues or application crashes after waking + # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead + # of just the bare essentials. + powerManagement = { + enable = false; + + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + finegrained = false; + }; + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # Currently alpha-quality/buggy, so false is currently the recommended setting. + open = false; + + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings` + nvidiaSettings = true; + + # Optionally, you may need to select the appropriate driver version for your specific GPU. + package = config.boot.kernelPackages.nvidiaPackages.latest; + }; + nvidia-container-toolkit.enable = lib.mkIf config.osbmModules.virtualisation.docker.enable true; + }; + + environment.systemPackages = [ + pkgs.nvidia-container-toolkit + ]; + + # TODO explain why this is needed + programs.nix-required-mounts = { + enable = true; + presets.nvidia-gpu.enable = true; + }; + + }; +} diff --git a/modules/nixos/hardware/sound.nix b/modules/nixos/hardware/sound.nix new file mode 100644 index 0000000..3a18a6f --- /dev/null +++ b/modules/nixos/hardware/sound.nix @@ -0,0 +1,20 @@ +{ lib, config, ... }: +{ + config = lib.mkIf config.osbmModules.hardware.sound.enable { + # Disable PulseAudio + services.pulseaudio.enable = false; + + # Enable rtkit for realtime audio + security.rtkit.enable = true; + + # Enable PipeWire + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + # If you want to use JACK applications: + # jack.enable = true; + }; + }; +} diff --git a/modules/nixos/hardware/wakeOnLan.nix b/modules/nixos/hardware/wakeOnLan.nix new file mode 100644 index 0000000..b6bfaa9 --- /dev/null +++ b/modules/nixos/hardware/wakeOnLan.nix @@ -0,0 +1,25 @@ +{ + pkgs, + lib, + config, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.hardware.wakeOnLan.enable { + networking.interfaces.enp3s0.wakeOnLan.enable = true; + # The services doesn't actually work atm, define an additional service + # see https://github.com/NixOS/nixpkgs/issues/91352 + systemd.services.wakeonlan = { + description = "Reenable wake on lan every boot"; + after = [ "network.target" ]; + serviceConfig = { + Type = "simple"; + RemainAfterExit = "true"; + ExecStart = "${pkgs.ethtool}/sbin/ethtool -s enp3s0 wol g"; + }; + wantedBy = [ "default.target" ]; + }; + }) + ]; +} diff --git a/modules/nixos/options.nix b/modules/nixos/options.nix new file mode 100644 index 0000000..ff33971 --- /dev/null +++ b/modules/nixos/options.nix @@ -0,0 +1,411 @@ +{ lib, config, ... }: +{ + options.osbmModules = { + # Desktop Environment + desktopEnvironment = lib.mkOption { + type = lib.types.enum [ + "plasma" + "gnome" + "none" + ]; + default = "none"; + description = "Which desktop environment to use"; + }; + + # Machine Type + machineType = lib.mkOption { + type = lib.types.enum [ + "desktop" + "laptop" + "server" + "embedded" + "mobile" + ]; + default = "server"; + description = "Type of machine for appropriate defaults"; + }; + + # Users + users = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ + "osbm" + ] + ++ lib.optionals ( + config.osbmModules.machineType == "desktop" || config.osbmModules.machineType == "laptop" + ) [ "bayram" ]; + description = "List of users to create. `osbm` is my main user, and `bayram` is for my family (only on desktop/laptop)."; + }; + + defaultUser = lib.mkOption { + type = lib.types.str; + default = "osbm"; + description = "Default user for the system"; + }; + + # Home Manager + homeManager = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable home-manager integration"; + }; + }; + + # Agenix + agenix = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable agenix for secrets management"; + }; + }; + + # Nix Settings + nixSettings = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable custom nix settings"; + }; + }; + + # Programs + programs = { + steam = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Steam gaming platform"; + }; + }; + + graphical = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.osbmModules.desktopEnvironment != "none"; + description = "Enable graphical applications"; + }; + }; + + commandLine = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable common command line tools"; + }; + }; + + neovim = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable neovim with custom configuration"; + }; + }; + + arduino = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Arduino IDE and development tools"; + }; + }; + + adbFastboot = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable ADB and Fastboot for Android development"; + }; + }; + }; + + # Services + services = { + openssh = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable OpenSSH server"; + }; + }; + + tailscale = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable Tailscale VPN"; + }; + }; + + actual.enable = lib.mkEnableOption "actual"; + anubis.enable = lib.mkEnableOption "anubis"; + syncthing.enable = lib.mkEnableOption "syncthing"; + jellyfin.enable = lib.mkEnableOption "jellyfin"; + mailserver.enable = lib.mkEnableOption "mailserver"; + firefox-syncserver.enable = lib.mkEnableOption "firefox-syncserver"; + vaultwarden.enable = lib.mkEnableOption "vaultwarden"; + nginx.enable = lib.mkEnableOption "nginx"; + ollama.enable = lib.mkEnableOption "ollama"; + forgejo.enable = lib.mkEnableOption "forgejo"; + atticd.enable = lib.mkEnableOption "atticd"; + cloudflared.enable = lib.mkEnableOption "cloudflared"; + cloudflare-dyndns.enable = lib.mkEnableOption "cloudflare-dyndns"; + glance.enable = lib.mkEnableOption "glance"; + hydra.enable = lib.mkEnableOption "hydra"; + immich.enable = lib.mkEnableOption "immich"; + vscode-server.enable = lib.mkEnableOption "vscode-server"; + wanikani-bypass-lessons.enable = lib.mkEnableOption "wanikani-bypass-lessons"; + wanikani-fetch-data.enable = lib.mkEnableOption "wanikani-fetch-data"; + wanikani-stats.enable = lib.mkEnableOption "wanikani-stats"; + }; + + # Hardware + hardware = { + bluetooth = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.osbmModules.desktopEnvironment != "none"; + description = "Enable Bluetooth support"; + }; + }; + + sound = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable sound with pipewire"; + }; + }; + + nvidia = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable NVIDIA proprietary drivers"; + }; + }; + + hibernation = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable hibernation support"; + }; + }; + + wakeOnLan = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable wake-on-LAN support"; + }; + }; + + systemd-boot.enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Use systemd-boot bootloader"; + }; + + # Disko configuration (inspired by ZFS.nix) + disko = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable custom disk configuration with disko"; + }; + + amReinstalling = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Am I reinstalling and want to save the storage pool"; + }; + + fileSystem = lib.mkOption { + type = lib.types.enum [ + "zfs" + "ext4" + ]; + default = "ext4"; + description = "Root filesystem type"; + }; + + initrd-ssh = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable SSH in initrd for remote unlocking"; + }; + + authorizedKeys = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "SSH public keys for initrd access"; + }; + + ethernetDrivers = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Ethernet drivers to load in initrd"; + }; + }; + + zfs = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable ZFS filesystem"; + }; + + hostID = lib.mkOption { + type = lib.types.str; + default = ""; + description = "ZFS host ID (8 hex characters)"; + }; + + root = { + useTmpfs = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Use tmpfs for root instead of ZFS (with ZFS datasets for /nix and /persist)"; + }; + + tmpfsSize = lib.mkOption { + type = lib.types.str; + default = "2G"; + description = "Size of tmpfs root filesystem"; + }; + + encrypt = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Encrypt root ZFS pool"; + }; + + disk1 = lib.mkOption { + type = lib.types.str; + default = ""; + description = "First disk device name (e.g., nvme0n1)"; + }; + + disk2 = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Second disk device name for mirroring"; + }; + + reservation = lib.mkOption { + type = lib.types.str; + default = "20G"; + description = "ZFS reservation size"; + }; + + mirror = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Mirror the root ZFS pool"; + }; + + impermanenceRoot = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Wipe the root directory on boot (impermanence)"; + }; + }; + + storage = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable separate storage ZFS pool"; + }; + + disks = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = "Storage pool disk device names"; + }; + + reservation = lib.mkOption { + type = lib.types.str; + default = "20G"; + description = "Storage pool ZFS reservation"; + }; + + mirror = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Mirror the storage ZFS pool"; + }; + }; + }; + }; + }; + + virtualisation = { + docker = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Docker"; + }; + }; + + podman = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable Podman"; + }; + }; + + libvirt = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable libvirt/KVM"; + }; + }; + }; + + # Emulation + emulation = { + aarch64 = { + enable = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Enable aarch64 emulation via binfmt"; + }; + }; + }; + + # Internationalization + i18n = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable internationalization settings"; + }; + }; + + # Fonts + fonts = { + enable = lib.mkOption { + type = lib.types.bool; + default = config.osbmModules.desktopEnvironment != "none"; + description = "Enable custom fonts"; + }; + }; + + # Nix Index + nixIndex = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable nix-index for command-not-found"; + }; + }; + }; +} diff --git a/modules/nixos/programs/adb-fastboot.nix b/modules/nixos/programs/adb-fastboot.nix new file mode 100644 index 0000000..bf36df3 --- /dev/null +++ b/modules/nixos/programs/adb-fastboot.nix @@ -0,0 +1,9 @@ +{ lib, config, ... }: +{ + config = lib.mkIf config.osbmModules.programs.adbFastboot.enable { + programs.adb.enable = true; + + # Add default user to adbusers group + users.users.${config.osbmModules.defaultUser}.extraGroups = [ "adbusers" ]; + }; +} diff --git a/modules/nixos/programs/arduino.nix b/modules/nixos/programs/arduino.nix new file mode 100644 index 0000000..f5123eb --- /dev/null +++ b/modules/nixos/programs/arduino.nix @@ -0,0 +1,20 @@ +{ + pkgs, + lib, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.programs.arduino.enable { + environment.systemPackages = with pkgs; [ + arduino-ide + adafruit-nrfutil + python3 # some arduino libraries require python3 + ]; + + services.udev.extraRules = '' + KERNEL=="ttyUSB[0-9]*",MODE="0666" + KERNEL=="ttyACM[0-9]*",MODE="0666" + ''; + }; +} diff --git a/modules/nixos/programs/command-line.nix b/modules/nixos/programs/command-line.nix new file mode 100644 index 0000000..befd242 --- /dev/null +++ b/modules/nixos/programs/command-line.nix @@ -0,0 +1,75 @@ +{ + pkgs, + lib, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.programs.commandLine.enable { + environment.systemPackages = with pkgs; [ + # networking + wget + curl + dig + + # text editors + nano + + # version control + git + lazygit + git-lfs + gh + + # nix tools + nix-output-monitor + nixd + nix-inspect + comma + nh + + # information and vanity + neofetch + onefetch + pfetch + htop + btop + cloc + inxi + tlrc + pciutils + + # basic quality of life + eza + dysk + trash-cli + zoxide + lazysql + jq + ripgrep + dust + bat + just + tree + fd + yazi + duf + + # archives + zip + unzip + + # shell + fish + starship + + # multiplexers + tmux + + (pkgs.writeShellScriptBin "wake-ymir" '' + echo waking up ymir + ${pkgs.wakeonlan}/bin/wakeonlan 04:7c:16:e6:d9:13 + '') + ]; + }; +} diff --git a/modules/nixos/programs/default.nix b/modules/nixos/programs/default.nix new file mode 100644 index 0000000..f90fcd8 --- /dev/null +++ b/modules/nixos/programs/default.nix @@ -0,0 +1,10 @@ +{ + imports = [ + ./adb-fastboot.nix + ./arduino.nix + ./command-line.nix + ./graphical.nix + ./neovim.nix + ./steam.nix + ]; +} diff --git a/modules/nixos/programs/graphical.nix b/modules/nixos/programs/graphical.nix new file mode 100644 index 0000000..1dc2359 --- /dev/null +++ b/modules/nixos/programs/graphical.nix @@ -0,0 +1,23 @@ +{ + pkgs, + lib, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.programs.graphical.enable { + environment.systemPackages = with pkgs; [ + mpv + gimp + inkscape + libreoffice + discord + telegram-desktop + obs-studio + blender + vscode + chromium + thunderbird + ]; + }; +} diff --git a/modules/nixos/programs/neovim.nix b/modules/nixos/programs/neovim.nix new file mode 100644 index 0000000..4c0cc3b --- /dev/null +++ b/modules/nixos/programs/neovim.nix @@ -0,0 +1,19 @@ +{ + lib, + inputs, + config, + pkgs, + ... +}: +{ + config = lib.mkIf config.osbmModules.programs.neovim.enable { + environment.systemPackages = [ + inputs.osbm-nvim.packages."${pkgs.stdenv.hostPlatform.system}".default + ]; + # Environment variables + environment.variables = { + EDITOR = "nvim"; + VISUAL = "nvim"; + }; + }; +} diff --git a/modules/nixos/programs/steam.nix b/modules/nixos/programs/steam.nix new file mode 100644 index 0000000..21f6359 --- /dev/null +++ b/modules/nixos/programs/steam.nix @@ -0,0 +1,14 @@ +{ lib, config, ... }: +{ + config = lib.mkIf config.osbmModules.programs.steam.enable { + programs.steam = { + enable = true; + # Open ports in the firewall for Steam Remote Play + remotePlay.openFirewall = true; + # Open ports in the firewall for Source Dedicated Server + dedicatedServer.openFirewall = true; + # Open ports in the firewall for Steam Local Network Game Transfers + localNetworkGameTransfers.openFirewall = true; + }; + }; +} diff --git a/modules/nixos/services/actual.nix b/modules/nixos/services/actual.nix new file mode 100644 index 0000000..628c2c8 --- /dev/null +++ b/modules/nixos/services/actual.nix @@ -0,0 +1,54 @@ +{ config, lib, ... }: + +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.actual.enable { + services.actual = { + enable = true; + settings = { + port = 51514; + + # dataDir = "/var/lib/actual" + }; + }; + }) + + # actual and nginx + (lib.mkIf (config.osbmModules.services.nginx.enable && config.osbmModules.services.actual.enable) { + services.nginx.virtualHosts."actual.osbm.dev" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.actual.settings.port}"; + proxyWebsockets = true; + }; + }; + }) + + # # impermanence and immich + # (lib.mkIf + # ( + # config.osbmModules.services.immich.enable + # && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + # ) + # { + # environment.persistence."/persist" = { + # directories = [ + # { + # directory = "/var/lib/immich"; + # user = config.services.immich.user; + # group = config.services.immich.group; + # mode = "0750"; + # } + # { + # directory = "/var/lib/postgresql"; + # user = "postgres"; + # group = "postgres"; + # mode = "0750"; + # } + # ]; + # }; + # } + # ) + ]; +} diff --git a/modules/nixos/services/anubis.nix b/modules/nixos/services/anubis.nix new file mode 100644 index 0000000..0ec8662 --- /dev/null +++ b/modules/nixos/services/anubis.nix @@ -0,0 +1,14 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.anubis.enable { + services.anubis = { + # enable = true; + }; + }) + ]; +} diff --git a/modules/nixos/services/atticd.nix b/modules/nixos/services/atticd.nix new file mode 100644 index 0000000..58fdc2a --- /dev/null +++ b/modules/nixos/services/atticd.nix @@ -0,0 +1,43 @@ +{ + config, + lib, + ... +}: +let + atticdPort = 7080; +in +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.atticd.enable { + services.atticd = { + enable = true; + environmentFile = "/persist/attic.env"; + settings = { + listen = "[::]:${toString atticdPort}"; + compression = { + type = "zstd"; + level = 9; + }; + # jwt = { }; + # storage = { + # type = "local"; + # # path = "/data/atreus/attic"; + # # there is an issue + # }; + }; + }; + networking.firewall.allowedTCPPorts = [ atticdPort ]; + services.cloudflared.tunnels = { + "fa301a21-b259-4149-b3d0-b1438c7c81f8" = { + default = "http_status:404"; + credentialsFile = "/home/osbm/.cloudflared/fa301a21-b259-4149-b3d0-b1438c7c81f8.json"; + ingress = { + "cache.osbm.dev" = { + service = "http://localhost:${toString atticdPort}"; + }; + }; + }; + }; + }) + ]; +} diff --git a/modules/nixos/services/cloudflare-dyndns.nix b/modules/nixos/services/cloudflare-dyndns.nix new file mode 100644 index 0000000..9986a73 --- /dev/null +++ b/modules/nixos/services/cloudflare-dyndns.nix @@ -0,0 +1,19 @@ +{ + lib, + config, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.cloudflare-dyndns.enable { + services.cloudflare-dyndns = { + enable = true; + apiTokenFile = "/persist/cloudflare-dyndns"; + proxied = false; # TODO please revert + domains = [ + "git.osbm.dev" + ]; + }; + }) + ]; +} diff --git a/modules/nixos/services/cloudflared.nix b/modules/nixos/services/cloudflared.nix new file mode 100644 index 0000000..5d8fd72 --- /dev/null +++ b/modules/nixos/services/cloudflared.nix @@ -0,0 +1,15 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.cloudflared.enable { + services.cloudflared = { + enable = true; + certificateFile = "/home/osbm/.cloudflared/cert.pem"; + }; + }) + ]; +} diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix new file mode 100644 index 0000000..3ad6689 --- /dev/null +++ b/modules/nixos/services/default.nix @@ -0,0 +1,29 @@ +{ + imports = [ + ./actual.nix + ./anubis.nix + ./atticd.nix + ./cloudflare-dyndns.nix + ./cloudflared.nix + ./ollama.nix + ./openssh.nix + ./firefox-syncserver.nix + ./forgejo.nix + ./glance.nix + ./hydra.nix + ./immich.nix + ./jellyfin.nix + ./mailserver.nix + ./nginx.nix + ./syncthing.nix + ./tailscale.nix + ./vaultwarden.nix + ./vscode-server.nix + + # custom services + ./system-logger + ./wanikani-bypass-lessons.nix + ./wanikani-fetch-data + ./wanikani-stats + ]; +} diff --git a/modules/nixos/services/firefox-syncserver.nix b/modules/nixos/services/firefox-syncserver.nix new file mode 100644 index 0000000..aafd39d --- /dev/null +++ b/modules/nixos/services/firefox-syncserver.nix @@ -0,0 +1,69 @@ +{ + config, + lib, + pkgs, + ... +}: + +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.firefox-syncserver.enable { + services.mysql.package = pkgs.mariadb; # Use MariaDB as the database backend + services.firefox-syncserver = { + enable = true; + secrets = "/persist/firefox-syncserver-secrets.env"; # TODO: Make this into agenix secret + logLevel = "trace"; + singleNode = { + enable = true; + url = "https://firefox.osbm.dev"; + capacity = 1; + }; + settings = { + host = "0.0.0.0"; + # Override database URLs to use Unix socket for authentication + # This allows the firefox-syncserver user to authenticate via unix_socket + syncstorage.database_url = "mysql://firefox-syncserver@localhost/firefox_syncserver?socket=%2Frun%2Fmysqld%2Fmysqld.sock"; + tokenserver.database_url = "mysql://firefox-syncserver@localhost/firefox_syncserver?socket=%2Frun%2Fmysqld%2Fmysqld.sock"; + }; + }; + }) + + # firefox-syncserver and nginx + (lib.mkIf + (config.osbmModules.services.nginx.enable && config.osbmModules.services.firefox-syncserver.enable) + { + services.nginx.virtualHosts."firefox.osbm.dev" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.firefox-syncserver.settings.port}"; + }; + }; + } + ) + + # impermanence and firefox-syncserver + (lib.mkIf + ( + config.osbmModules.services.firefox-syncserver.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + systemd.services.firefox-syncserver.serviceConfig.ReadWritePaths = [ + "/var/lib/firefox-syncserver" + ]; + + environment.persistence."/persist" = { + directories = [ + { + directory = "/var/lib/firefox-syncserver"; + user = config.systemd.services.firefox-syncserver.serviceConfig.User; + group = config.systemd.services.firefox-syncserver.serviceConfig.Group; + mode = "0750"; + } + ]; + }; + } + ) + ]; +} diff --git a/modules/nixos/services/forgejo.nix b/modules/nixos/services/forgejo.nix new file mode 100644 index 0000000..65aab17 --- /dev/null +++ b/modules/nixos/services/forgejo.nix @@ -0,0 +1,91 @@ +{ + lib, + config, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.forgejo.enable { + services.forgejo = { + enable = true; + lfs.enable = true; + dump = { + enable = true; + type = "zip"; + interval = "01:01"; + }; + settings = { + DEFAULT = { + APP_NAME = "osbm's self hosted git service"; + }; + server = { + DOMAIN = "git.osbm.dev"; + ROOT_URL = "https://git.osbm.dev/"; + }; + "ui.meta" = { + AUTHOR = "osbm"; + DESCRIPTION = "\"After all, all devices have their dangers. The discovery of speech introduced communication and lies.\" -Isaac Asimov"; + KEYWORDS = "git,self-hosted,gitea,forgejo,osbm,open-source,nix,nixos"; + }; + service = { + DISABLE_REGISTRATION = true; + LANDING_PAGE = "/osbm"; + }; + }; + }; + }) + + (lib.mkIf + (config.osbmModules.services.cloudflared.enable && config.osbmModules.services.forgejo.enable) + { + services.cloudflared.tunnels = { + "eb9052aa-9867-482f-80e3-97a7d7e2ef04" = { + default = "http_status:404"; + credentialsFile = "/home/osbm/.cloudflared/eb9052aa-9867-482f-80e3-97a7d7e2ef04.json"; + ingress = { + "${config.services.forgejo.settings.server.DOMAIN}" = { + service = "http://localhost:3000"; + }; + }; + }; + }; + } + ) + (lib.mkIf (config.osbmModules.services.nginx.enable && config.osbmModules.services.forgejo.enable) { + services.nginx.virtualHosts."${config.services.forgejo.settings.server.DOMAIN}" = { + forceSSL = true; + enableACME = true; + locations."/".proxyPass = "http://localhost:3000"; + locations."/".proxyWebsockets = true; + }; + }) + + (lib.mkIf + ( + config.osbmModules.services.forgejo.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + # environment.persistence."/persist" = { + # directories = [ + # { + # directory = "/var/lib/forgejo"; + # user = config.services.forgejo.user; + # group = config.services.forgejo.group; + # mode = "0750"; + # } + # ]; + # }; + + # # forgejo-secrets service keep giving error + # systemd.services."forgejo-secrets" = { + # wants = [ "var-lib-forgejo.mount" ]; + # after = [ "var-lib-forgejo.mount" ]; + # }; + + # fuckass thing + services.forgejo.stateDir = "/persist/var/lib/forgejo"; + } + ) + ]; +} diff --git a/modules/nixos/services/glance.nix b/modules/nixos/services/glance.nix new file mode 100644 index 0000000..14c3fe1 --- /dev/null +++ b/modules/nixos/services/glance.nix @@ -0,0 +1,181 @@ +{ + lib, + config, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.glance.enable { + services.glance = { + enable = true; + openFirewall = true; + settings = { + server = { + port = 3838; + host = "0.0.0.0"; + }; + branding = { + # stolen from notohh/snowflake but i love it so much + custom-footer = ''

ᓚᘏᗢ

''; + }; + pages = [ + { + columns = [ + { + size = "small"; + widgets = [ + { type = "calendar"; } + { + type = "bookmarks"; + groups = [ + { + title = "My Profiles"; + same-tab = true; + color = "200 50 50"; + links = [ + { + title = "GitHub"; + url = "https://github.com/osbm"; + } + { + title = "Gitlab"; + url = "https://gitlab.com/osbm"; + } + { + title = "Crates.io"; + url = "https://crates.io/users/osbm"; + } + { + title = "HuggingFace"; + url = "https://huggingface.co/osbm"; + } + { + title = "Bluesky"; + url = "https://bsky.app/profile/osbm.dev"; + } + { + title = "Docker Hub"; + url = "https://hub.docker.com/u/osbm"; + } + { + title = "Kaggle"; + url = "https://www.kaggle.com/osmanf"; + } + ]; + } + { + title = "Documents"; + links = [ + { + title = "Nixos Search"; + url = "https://search.nixos.org"; + } + ]; + } + ]; + } + ]; + } + + { + size = "full"; + widgets = [ + { + type = "search"; + search-engine = "google"; + bangs = [ + { + title = "youtube"; + shortcut = "!yt"; + url = "https://www.youtube.com/results?search_query={QUERY}"; + } + { + title = "nixpkgs"; + shortcut = "!np"; + url = "https://search.nixos.org/packages?channel=unstable&query={QUERY}"; + } + { + title = "nixos"; + shortcut = "!no"; + url = "https://search.nixos.org/options?channel=unstable&query={QUERY}"; + } + ]; + } + { + cache = "1m"; + sites = [ + { + icon = "sh:forgejo"; + title = "Forgejo git server"; + url = "https://git.osbm.dev"; + } + { + icon = "sh:bitwarden"; + title = "Bitwarden Vault"; + url = "https://bitwarden.osbm.dev"; + } + { + icon = "sh:visual-studio-code"; + title = "Ymir Remote VSCode"; + url = "http://ymir.curl-boga.ts.net:4444/"; + } + { + icon = "sh:visual-studio-code"; + title = "Tartarus Remote VSCode"; + url = "http://tartarus.curl-boga.ts.net:4444/"; + } + { + icon = "sh:visual-studio-code"; + title = "Wallfacer Remote VSCode"; + url = "http://wallfacer.curl-boga.ts.net:4444/"; + } + { + icon = "si:json"; + title = "Wanikani Stats"; + url = "http://pochita:8501"; + } + ]; + title = "Services"; + type = "monitor"; + } + ]; + } + ]; + name = "Home"; + content = "Welcome to osbm's home page!"; + } + ]; + }; + }; + networking.firewall.allowedTCPPorts = [ config.services.glance.settings.server.port ]; + }) + (lib.mkIf + (config.osbmModules.services.cloudflared.enable && config.osbmModules.services.glance.enable) + { + services.cloudflared.tunnels = { + "91b13f9b-81be-46e1-bca0-db2640bf2d0a" = { + default = "http_status:404"; + credentialsFile = "/home/osbm/.cloudflared/91b13f9b-81be-46e1-bca0-db2640bf2d0a.json"; + ingress = { + "home.osbm.dev" = { + service = "http://localhost:${toString config.services.glance.settings.server.port}"; + }; + }; + }; + }; + } + ) + + # if nginx and glance are both enabled, set up a reverse proxy + (lib.mkIf (config.osbmModules.services.nginx.enable && config.osbmModules.services.glance.enable) { + services.nginx.virtualHosts."home.osbm.dev" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.glance.settings.server.port}"; + proxyWebsockets = true; + }; + }; + }) + ]; +} diff --git a/modules/nixos/services/hydra.nix b/modules/nixos/services/hydra.nix new file mode 100644 index 0000000..3cc6c55 --- /dev/null +++ b/modules/nixos/services/hydra.nix @@ -0,0 +1,22 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.hydra.enable { + services.hydra = { + enable = true; + port = 3000; + hydraURL = "http://${config.networking.hostName}.curl-boga.ts.net/hydra/"; + notificationSender = "hydra@localhost"; + buildMachinesFiles = [ ]; + useSubstitutes = true; + }; + networking.firewall.allowedTCPPorts = [ + config.services.hydra.port + ]; + }) + ]; +} diff --git a/modules/nixos/services/immich.nix b/modules/nixos/services/immich.nix new file mode 100644 index 0000000..1a67f90 --- /dev/null +++ b/modules/nixos/services/immich.nix @@ -0,0 +1,48 @@ +{ config, lib, ... }: + +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.immich.enable { + services.immich = { + enable = true; + }; + }) + + # immich and nginx + (lib.mkIf (config.osbmModules.services.nginx.enable && config.osbmModules.services.immich.enable) { + services.nginx.virtualHosts."immich.osbm.dev" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.immich.port}"; + proxyWebsockets = true; + }; + }; + }) + + # impermanence and immich + (lib.mkIf + ( + config.osbmModules.services.immich.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + environment.persistence."/persist" = { + directories = [ + { + directory = "/var/lib/immich"; + inherit (config.services.immich) user group; + mode = "0750"; + } + { + directory = "/var/lib/postgresql"; + user = "postgres"; + group = "postgres"; + mode = "0750"; + } + ]; + }; + } + ) + ]; +} diff --git a/modules/nixos/services/jellyfin.nix b/modules/nixos/services/jellyfin.nix new file mode 100644 index 0000000..caae383 --- /dev/null +++ b/modules/nixos/services/jellyfin.nix @@ -0,0 +1,20 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.jellyfin.enable { + services.jellyfin = { + enable = true; + openFirewall = true; + user = "osbm"; + group = "users"; + dataDir = "/home/osbm/.local/share/jellyfin"; + }; + + networking.firewall.allowedTCPPorts = [ 8096 ]; + }) + ]; +} diff --git a/modules/nixos/services/mailserver.nix b/modules/nixos/services/mailserver.nix new file mode 100644 index 0000000..c4a2457 --- /dev/null +++ b/modules/nixos/services/mailserver.nix @@ -0,0 +1,90 @@ +{ + config, + inputs, + lib, + ... +}: +{ + imports = [ + inputs.simple-nixos-mailserver.nixosModule + ]; + + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.mailserver.enable { + mailserver = { + enable = true; + stateVersion = 3; + fqdn = "mail.osbm.dev"; + domains = [ "osbm.dev" ]; + + # A list of all login accounts. To create the password hashes, use + # nix-shell -p mkpasswd --run 'mkpasswd -sm bcrypt' + loginAccounts = { + "osbm@osbm.dev" = { + hashedPasswordFile = "/persist/osbm.passwd"; # TODO: Make this into agenix secret + aliases = [ "postmaster@osbm.dev" ]; + }; + }; + + # Use Let's Encrypt certificates. Note that this needs to set up a stripped + # down nginx and opens port 80. + certificateScheme = "acme-nginx"; + }; + }) + + # mailserver and impermanence + (lib.mkIf + ( + config.osbmModules.services.mailserver.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + environment.persistence."/persist" = { + directories = [ + # Dovecot is an open source IMAP and POP3 server + # which means it handles email retrieval for users. + "/var/lib/dovecot" # owned by root + # Postfix is a open-source mail transfer agent (MTA) + "/var/lib/postfix" # owned by root + # Rspamd is a open-source spam filtering system. + { + directory = "/var/lib/rspamd"; + user = "rspamd"; + group = "rspamd"; + mode = "0700"; + } + # redis-rspamd is just a redis instance used by rspamd for caching + # TODO: what is the /var/spool folder? + { + directory = "/var/spool/redis-rspamd"; + user = "redis-rspamd"; + group = "redis-rspamd"; + mode = "0750"; + } + # Sieve is a scripting language for filtering email messages. + { + directory = config.mailserver.sieveDirectory; # /var/sieve by default + user = "virtualMail"; + group = "virtualMail"; + mode = "0770"; + } + # Mail folder + { + directory = config.mailserver.mailDirectory; # /var/vmail by default + user = config.mailserver.vmailUserName; + group = config.mailserver.vmailGroupName; + mode = "0700"; + } + # DKIM is used to sign outgoing emails to verify they are from the claimed domain. + { + directory = config.mailserver.dkimKeyDirectory; # /var/dkim by default + user = "rspamd"; + group = "rspamd"; + mode = "0755"; + } + ]; + }; + } + ) + ]; +} diff --git a/modules/nixos/services/nginx.nix b/modules/nixos/services/nginx.nix new file mode 100644 index 0000000..ec48e47 --- /dev/null +++ b/modules/nixos/services/nginx.nix @@ -0,0 +1,43 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.nginx.enable { + services.nginx = { + enable = true; + }; + + networking.firewall.allowedTCPPorts = [ + 80 + 443 + ]; + + security.acme = { + acceptTerms = true; + defaults.email = "osbm@osbm.dev"; + }; + }) + + (lib.mkIf + ( + config.osbmModules.services.nginx.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + # environment.persistence."/persist" = { + # directories = [ + # { + # directory = "/var/lib/acme"; + # user = "acme"; + # group = "nginx"; + # mode = "0750"; + # } + # ]; + # }; + } + ) + ]; +} diff --git a/modules/nixos/services/ollama.nix b/modules/nixos/services/ollama.nix new file mode 100644 index 0000000..b73333a --- /dev/null +++ b/modules/nixos/services/ollama.nix @@ -0,0 +1,33 @@ +{ + lib, + config, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.ollama.enable { + services.ollama = { + enable = true; + acceleration = "cuda"; + # loadModels = [ + # "deepseek-r1:7b" + # "deepseek-r1:14b" + # ]; + }; + + services.open-webui = { + enable = false; # TODO gives error fix later + port = 7070; + host = "0.0.0.0"; + openFirewall = true; + environment = { + SCARF_NO_ANALYTICS = "True"; + DO_NOT_TRACK = "True"; + ANONYMIZED_TELEMETRY = "False"; + WEBUI_AUTH = "False"; + ENABLE_LOGIN_FORM = "False"; + }; + }; + }) + ]; +} diff --git a/modules/nixos/services/openssh.nix b/modules/nixos/services/openssh.nix new file mode 100644 index 0000000..fd1db86 --- /dev/null +++ b/modules/nixos/services/openssh.nix @@ -0,0 +1,31 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.openssh.enable { + services.openssh = { + enable = true; + startWhenNeeded = true; + settings = { + PermitRootLogin = "no"; + + # only allow key based logins and not password + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + AuthenticationMethods = "publickey"; + PubkeyAuthentication = "yes"; + ChallengeResponseAuthentication = "no"; + UsePAM = false; + + # kick out inactive sessions + ClientAliveCountMax = 5; + ClientAliveInterval = 60; + }; + }; + + }) + ]; +} diff --git a/modules/nixos/services/syncthing.nix b/modules/nixos/services/syncthing.nix new file mode 100644 index 0000000..b831305 --- /dev/null +++ b/modules/nixos/services/syncthing.nix @@ -0,0 +1,16 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.syncthing.enable { + services.syncthing = { + enable = true; + openDefaultPorts = true; + # port is 8384 + }; + }) + ]; +} diff --git a/modules/nixos/services/system-logger/default.nix b/modules/nixos/services/system-logger/default.nix new file mode 100644 index 0000000..a6f72d3 --- /dev/null +++ b/modules/nixos/services/system-logger/default.nix @@ -0,0 +1,68 @@ +{ + pkgs, + config, + lib, + ... +}: +let + system-logger = pkgs.writeShellApplication { + name = "system-logger"; + runtimeInputs = with pkgs; [ + curl + jq + zip + gawk + systemd + ]; + text = builtins.readFile ./system-logger.sh; + }; +in +{ + options.services.system-logger = { + enable = lib.mkEnableOption { + description = "Enable System Logger Service"; + default = false; + }; + + logDirectory = lib.mkOption { + type = lib.types.path; + default = "/var/lib/system-logger"; + description = "Directory to store log archives"; + }; + + maxSizeMB = lib.mkOption { + type = lib.types.int; + default = 1; + description = "Maximum size of daily log archive in megabytes"; + }; + + retentionDays = lib.mkOption { + type = lib.types.int; + default = 30; + description = "Number of days to retain log archives"; + }; + }; + + config = lib.mkIf config.services.system-logger.enable { + systemd.timers.system-logger = { + description = "System Logger Timer"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "daily"; + Persistent = true; + }; + }; + + systemd.services.system-logger = { + description = "System Logger Service"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe system-logger}"; + Restart = "on-failure"; + RestartSec = 60; + User = "root"; + Group = "root"; + }; + }; + }; +} diff --git a/modules/nixos/services/system-logger/system-logger.sh b/modules/nixos/services/system-logger/system-logger.sh new file mode 100755 index 0000000..b31e9f7 --- /dev/null +++ b/modules/nixos/services/system-logger/system-logger.sh @@ -0,0 +1,136 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Configuration +LOG_DIR="/var/lib/system-logger" +MAX_SIZE_MB=1 +RETENTION_DAYS=30 +DATE=$(date +%Y-%m-%d) +HOSTNAME=$(hostname) +TEMP_DIR=$(mktemp -d) + +# Create log directory if it doesn't exist +mkdir -p "$LOG_DIR" + +# Check if today's log already exists +if [ -f "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip" ]; then + echo "Logs for today already exist. Exiting..." + exit 0 +fi + +echo "Starting system log collection for $DATE" + +# Function to collect logs with size limit +collect_logs() { + local source="$1" + local output="$2" + local max_lines="$3" + + if [ -f "$source" ]; then + # Get the last N lines to stay within size limit + tail -n "$max_lines" "$source" > "$output" 2>/dev/null || true + echo "Collected from $source" + else + echo "Source $source not found, skipping..." + fi +} + +# Function to get journal logs with filtering +get_journal_logs() { + local output="$1" + local filter="$2" + local max_lines="$3" + + journalctl --since "00:00:00" --until "23:59:59" \ + --no-pager --output=short \ + | grep -i "$filter" | tail -n "$max_lines" > "$output" 2>/dev/null || true + echo "Collected journal logs for $filter" +} + +# Calculate approximate lines per log type to stay under 1MB +# Assuming average line is ~100 bytes, we aim for ~10,000 total lines +TOTAL_LINES=10000 +SSH_LINES=2000 +KERNEL_LINES=2000 +LOGIN_LINES=1000 +SYSTEM_LINES=2000 +AUTH_LINES=1000 +FAILED_LOGIN_LINES=500 +DISK_LINES=500 +NETWORK_LINES=500 +MEMORY_LINES=500 + +# Collect SSH connections +get_journal_logs "$TEMP_DIR/ssh.log" "sshd" "$SSH_LINES" + +# Collect kernel warnings and errors +get_journal_logs "$TEMP_DIR/kernel.log" "kernel.*warning\|kernel.*error" "$KERNEL_LINES" + +# Collect login/logout events +get_journal_logs "$TEMP_DIR/login.log" "session.*opened\|session.*closed\|login\|logout" "$LOGIN_LINES" + +# Collect system messages +get_journal_logs "$TEMP_DIR/system.log" "systemd\|daemon" "$SYSTEM_LINES" + +# Collect authentication events +get_journal_logs "$TEMP_DIR/auth.log" "authentication\|auth" "$AUTH_LINES" + +# Collect failed login attempts +get_journal_logs "$TEMP_DIR/failed_login.log" "failed\|failure\|denied" "$FAILED_LOGIN_LINES" + +# Collect disk usage and errors +get_journal_logs "$TEMP_DIR/disk.log" "disk\|storage\|iostat" "$DISK_LINES" + +# Collect network events +get_journal_logs "$TEMP_DIR/network.log" "network\|connection\|interface" "$NETWORK_LINES" + +# Collect memory usage +get_journal_logs "$TEMP_DIR/memory.log" "memory\|oom\|swap" "$MEMORY_LINES" + +# Collect traditional log files if they exist +collect_logs "/var/log/auth.log" "$TEMP_DIR/auth_traditional.log" 1000 +collect_logs "/var/log/syslog" "$TEMP_DIR/syslog_traditional.log" 1000 +collect_logs "/var/log/messages" "$TEMP_DIR/messages_traditional.log" 1000 + +# Create a summary file +{ + echo "=== System Log Summary for $DATE ===" + echo "Hostname: $HOSTNAME" + echo "Collection time: $(date)" + echo "Total lines collected:" + wc -l "$TEMP_DIR"/*.log 2>/dev/null || true + echo "" + echo "=== System Information ===" + echo "Uptime: $(uptime)" + echo "Load average: $(cat /proc/loadavg)" + echo "Memory usage:" + free -h + echo "" + echo "Disk usage:" + df -h + echo "" + echo "Active users:" + who +} > "$TEMP_DIR/summary.txt" + +# Create the zip file +cd "$TEMP_DIR" +zip -r "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip" ./* > /dev/null + +# Check file size and warn if too large +FILE_SIZE=$(stat -c%s "$LOG_DIR/${DATE}-logs-${HOSTNAME}.zip") +FILE_SIZE_MB=$((FILE_SIZE / 1024 / 1024)) + +if [ "$FILE_SIZE_MB" -gt "$MAX_SIZE_MB" ]; then + echo "WARNING: Log file size ($FILE_SIZE_MB MB) exceeds limit ($MAX_SIZE_MB MB)" +fi + +echo "Log collection completed: $LOG_DIR/${DATE}-logs-${HOSTNAME}.zip ($FILE_SIZE_MB MB)" + +# Clean up old logs (older than RETENTION_DAYS) +find "$LOG_DIR" -name "*-logs-*.zip" -type f -mtime +$RETENTION_DAYS -delete 2>/dev/null || true + +# Clean up temporary directory +rm -rf "$TEMP_DIR" + +echo "System log collection finished successfully" diff --git a/modules/nixos/services/tailscale.nix b/modules/nixos/services/tailscale.nix new file mode 100644 index 0000000..ffd19b5 --- /dev/null +++ b/modules/nixos/services/tailscale.nix @@ -0,0 +1,32 @@ +{ + config, + lib, + pkgs, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.tailscale.enable { + services.tailscale = { + enable = true; + port = 51513; + }; + + networking.firewall.allowedUDPPorts = [ config.services.tailscale.port ]; + environment.systemPackages = [ pkgs.tailscale ]; + }) + + # tailscale and impermanence + (lib.mkIf + ( + config.osbmModules.services.tailscale.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + environment.persistence."/persist".directories = [ + "/var/lib/tailscale" + ]; + } + ) + ]; +} diff --git a/modules/nixos/services/vaultwarden.nix b/modules/nixos/services/vaultwarden.nix new file mode 100644 index 0000000..046ec8c --- /dev/null +++ b/modules/nixos/services/vaultwarden.nix @@ -0,0 +1,75 @@ +{ + config, + lib, + ... +}: +{ + config = lib.mkMerge [ + (lib.mkIf config.osbmModules.services.vaultwarden.enable { + services.vaultwarden = { + enable = true; + backupDir = "/persist/backup/vaultwarden"; + # in order to avoid having ADMIN_TOKEN in the nix store it can be also set with the help of an environment file + # be aware that this file must be created by hand (or via secrets management like sops) + environmentFile = config.age.secrets.vaultwarden.path; + config = { + # Refer to https://github.com/dani-garcia/vaultwarden/blob/main/.env.template + DOMAIN = "https://bitwarden.osbm.dev"; + SIGNUPS_ALLOWED = false; + + ROCKET_ADDRESS = "127.0.0.1"; + ROCKET_PORT = 8222; + ROCKET_LOG = "critical"; + + # This example assumes a mailserver running on localhost, + # thus without transport encryption. + # If you use an external mail server, follow: + # https://github.com/dani-garcia/vaultwarden/wiki/SMTP-configuration + SMTP_HOST = "127.0.0.1"; + SMTP_PORT = 25; + SMTP_SSL = false; + + SMTP_FROM = "osbm@osbm.dev"; + SMTP_FROM_NAME = "osbm.dev Bitwarden server"; + }; + }; + }) + + # vaultwarden reverse proxy via nginx + (lib.mkIf + (config.osbmModules.services.nginx.enable && config.osbmModules.services.vaultwarden.enable) + { + services.nginx.virtualHosts."bitwarden.osbm.dev" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.vaultwarden.config.ROCKET_PORT}"; + }; + }; + } + ) + + # impermanence with vaultwarden + (lib.mkIf + ( + config.osbmModules.services.vaultwarden.enable + && config.osbmModules.hardware.disko.zfs.root.impermanenceRoot + ) + { + systemd.services.vaultwarden.serviceConfig.ReadWritePaths = [ "/var/lib/vaultwarden" ]; + # TODO try if not using bindMounts fixes this + + environment.persistence."/persist" = { + directories = [ + { + directory = "/var/lib/vaultwarden"; + user = config.systemd.services.vaultwarden.serviceConfig.User; + group = config.systemd.services.vaultwarden.serviceConfig.Group; + mode = "0750"; + } + ]; + }; + } + ) + ]; +} diff --git a/modules/nixos/services/vscode-server.nix b/modules/nixos/services/vscode-server.nix new file mode 100644 index 0000000..7bad2a6 --- /dev/null +++ b/modules/nixos/services/vscode-server.nix @@ -0,0 +1,56 @@ +{ + config, + pkgs, + lib, + ... +}: +{ + config = lib.mkIf config.osbmModules.services.vscode-server.enable { + services.code-server = { + # only true if the machine is not pochita + enable = config.networking.hostName != "pochita"; + port = 4444; + disableTelemetry = true; + disableUpdateCheck = true; + user = "osbm"; + group = "users"; + # auth = "none"; + host = "${config.networking.hostName}.curl-boga.ts.net"; + hashedPassword = "$argon2i$v=19$m=4096,t=3,p=1$dGc0TStGMDNzSS9JRkJYUFp3d091Q2p0bXlzPQ$zvdE9BkclkJmyFaenzPy2E99SEqsyDMt4IQNZfcfFFQ"; + package = pkgs.vscode-with-extensions.override { + vscode = pkgs.code-server; + vscodeExtensions = + with pkgs.vscode-extensions; + [ + bbenoist.nix + catppuccin.catppuccin-vsc + catppuccin.catppuccin-vsc-icons + charliermarsh.ruff + davidanson.vscode-markdownlint + esbenp.prettier-vscode + foxundermoon.shell-format + github.copilot + github.vscode-github-actions + github.vscode-pull-request-github + jnoortheen.nix-ide + kamadorueda.alejandra + ms-azuretools.vscode-docker + ms-python.python + # ms-vscode-remote.remote-ssh + timonwong.shellcheck + tyriar.sort-lines + ] + ++ pkgs.vscode-utils.extensionsFromVscodeMarketplace [ + { + # Available in nixpkgs, but outdated (0.4.0) at the time of adding + name = "vscode-tailscale"; + publisher = "tailscale"; + sha256 = "sha256-MKiCZ4Vu+0HS2Kl5+60cWnOtb3udyEriwc+qb/7qgUg="; + version = "1.0.0"; + } + ]; + }; + }; + networking.firewall.allowedTCPPorts = [ config.services.code-server.port ]; + }; +} diff --git a/modules/nixos/services/wanikani-bypass-lessons.nix b/modules/nixos/services/wanikani-bypass-lessons.nix new file mode 100644 index 0000000..40fd4da --- /dev/null +++ b/modules/nixos/services/wanikani-bypass-lessons.nix @@ -0,0 +1,109 @@ +{ + lib, + config, + pkgs, + ... +}: +let + waniKani-bypass-lessons = pkgs.writeShellApplication { + name = "wanikani-bypass-lessons"; + runtimeInputs = with pkgs; [ + curl + jq + ]; + text = '' + #!/usr/bin/env bash + + # this token that starts with "2da24" is read only so i am keeping it public, i have nothing secret on my wanikani account + # but i need a write token for the second part of this script + + # i am going to read it from /persist/wanikani + + [ ! -e /persist/wanikani ] && echo "/persist/wanikani doesnt exist here :(" && exit 1 + + WANIKANI_TOKEN=$(< /persist/wanikani) + + # Maximum number of reviews to maintain + MAX_REVIEWS=200 + + echo "=== Checking current reviews ===" + + # Get current reviews (SRS stages 0-4) + current_reviews=0 + for i in {0..4}; do + stage_count=$(curl -s -H "Authorization: Bearer 2da24e4a-ba89-4c4a-9047-d08f21e9dd01" "https://api.wanikani.com/v2/assignments?srs_stages=$i" | jq '.total_count') + current_reviews=$((current_reviews + stage_count)) + echo "SRS stage $i: $stage_count items" + done + + echo "Current total reviews: $current_reviews" + echo "Maximum reviews target: $MAX_REVIEWS" + + if [ "$current_reviews" -ge "$MAX_REVIEWS" ]; then + echo "Reviews ($current_reviews) >= max ($MAX_REVIEWS). No lessons to bypass." + sleep 3600 + exit 0 + fi + + lessons_to_bypass=$((MAX_REVIEWS - current_reviews)) + echo "Need to bypass $lessons_to_bypass lessons to reach $MAX_REVIEWS total" + + # Get available lessons (limited to what we need) + ASSIGNMENT_IDS=$(curl -s -H "Authorization: Bearer 2da24e4a-ba89-4c4a-9047-d08f21e9dd01" "https://api.wanikani.com/v2/assignments?immediately_available_for_lessons=true" | jq -r ".data[] | .id" | head -n "$lessons_to_bypass") + + available_lessons=$(echo "$ASSIGNMENT_IDS" | wc -l) + echo "Available lessons: $available_lessons" + + if [ "$available_lessons" -eq 0 ]; then + echo "No lessons available to bypass." + sleep 3600 + exit 0 + fi + + # Limit to what we actually need + actual_bypass=$(echo "$ASSIGNMENT_IDS" | wc -l) + echo "Will bypass $actual_bypass lessons" + + # "2017-09-05T23:41:28.980679Z" i need to create this from current time + + TIME_STRING=$(date -u +"%Y-%m-%dT%H:%M:%S.%6NZ") + echo "Current time: $TIME_STRING" + + echo "=== Starting assignments ===" + for assignment_id in $ASSIGNMENT_IDS; do + echo "Starting assignment $assignment_id" + curl -s "https://api.wanikani.com/v2/assignments/$assignment_id/start" \ + -X "PUT" \ + -H "Wanikani-Revision: 20170710" \ + -H "Content-Type: application/json; charset=utf-8" \ + -H "Authorization: Bearer $WANIKANI_TOKEN" \ + -d "{\"assignment\": {\"started_at\": \"$TIME_STRING\" }}" + echo + sleep 1 + done + + echo "Successfully bypassed $actual_bypass lessons" + echo "New total should be approximately: $((current_reviews + actual_bypass))" + sleep 3600 + ''; + }; +in +{ + options.services.wanikani-bypass-lessons.enable = lib.mkEnableOption { + description = "Enable WaniKani Bypass Lessons"; + default = config.osbmModules.services.wanikani-bypass-lessons.enable or false; + }; + + config = lib.mkIf config.services.wanikani-bypass-lessons.enable { + systemd.services.wanikani-bypass-lessons = { + description = "WaniKani Bypass Lessons"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${lib.getExe waniKani-bypass-lessons}"; + Restart = "always"; + RestartSec = 60 * 60; + }; + }; + }; +} diff --git a/modules/nixos/services/wanikani-fetch-data/default.nix b/modules/nixos/services/wanikani-fetch-data/default.nix new file mode 100644 index 0000000..ff49fe5 --- /dev/null +++ b/modules/nixos/services/wanikani-fetch-data/default.nix @@ -0,0 +1,42 @@ +{ + pkgs, + config, + lib, + ... +}: +let + wanikani-fetcher = pkgs.writeShellApplication { + name = "wanikani-fetcher"; + runtimeInputs = with pkgs; [ + curl + jq + zip + ]; + text = builtins.readFile ./wanikani-fetcher.sh; + }; +in +{ + options.services.wanikani-fetch-data.enable = lib.mkEnableOption { + description = "Enable WaniKani Fetch Data"; + default = config.osbmModules.services.wanikani-fetch-data.enable or false; + }; + + config = lib.mkIf config.services.wanikani-fetch-data.enable { + systemd.timers.wanikani-fetch-data = { + description = "WaniKani Fetch Data"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "02:00"; + }; + }; + systemd.services.wanikani-fetch-data = { + description = "WaniKani Fetch Data"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${lib.getExe wanikani-fetcher}"; + Restart = "on-failure"; + RestartSec = 60; + }; + }; + }; +} diff --git a/modules/nixos/services/wanikani-fetch-data/wanikani-fetcher.sh b/modules/nixos/services/wanikani-fetch-data/wanikani-fetcher.sh new file mode 100755 index 0000000..219d4a6 --- /dev/null +++ b/modules/nixos/services/wanikani-fetch-data/wanikani-fetcher.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +shopt -s nullglob +API_TOKEN="2da24e4a-ba89-4c4a-9047-d08f21e9dd01" +date=$(date +%Y-%m-%d) + +# check if todays date is already in the logs folder +if [ -f "/var/lib/wanikani-logs/wanikani_data_$date.zip" ]; then + echo "Data for today already exists. Exiting..." + exit 0 +fi + +tmp_dir=$(mktemp -d) +echo "Temporary directory created at $tmp_dir" + +mkdir "$tmp_dir/data" +mkdir -p "/var/lib/wanikani-logs" + +fetch_and_merge() { + local topic="$1" + local counter=0 + local url="https://api.wanikani.com/v2/$topic" + local output_file="$tmp_dir/data/$topic.json" + local next_url="$url" + + echo "Fetching from $url..." + + while [[ -n "$next_url" ]]; do + local resp_file="$tmp_dir/$topic-page-$counter.json" + curl -s "$next_url" \ + -H "Wanikani-Revision: 20170710" \ + -H "Authorization: Bearer $API_TOKEN" \ + -o "$resp_file" + + echo -e "\n--- Page $((counter + 1)) (First 20 lines) ---" + head -n 20 <(jq . "$resp_file") + # jq . "$resp_file" 2>/dev/null | head -n 20 + + next_url=$(jq -r '.pages.next_url // empty' "$resp_file") + counter=$((counter + 1)) + done + + echo "Merging data..." + + local meta + meta=$(jq '{object, total_count, data_updated_at}' "$resp_file") + local files=("$tmp_dir/$topic-page-"*.json) + jq -cn \ + --argjson meta "$meta" \ + --slurpfile data <(jq -s '[.[] | .data[]]' "${files[@]}") \ + '$meta + {data: $data[0]}' > "$output_file" + + + echo "Saved to $output_file" +} + +fetch_and_merge assignments +fetch_and_merge level_progressions +fetch_and_merge resets +fetch_and_merge reviews +fetch_and_merge review_statistics +fetch_and_merge spaced_repetition_systems +fetch_and_merge study_materials +fetch_and_merge subjects + +curl -s "https://api.wanikani.com/v2/summary" \ + -H "Wanikani-Revision: 20170710" \ + -H "Authorization: Bearer $API_TOKEN" \ + -o "$tmp_dir/data/summary.json" + +curl -s "https://api.wanikani.com/v2/user" \ + -H "Wanikani-Revision: 20170710" \ + -H "Authorization: Bearer $API_TOKEN" \ + -o "$tmp_dir/data/user.json" + + +# get the date as a variable and use it to zip the data folder +zip -j -r "/var/lib/wanikani-logs/wanikani_data_$date.zip" "$tmp_dir/data" +echo "Data zipped to /var/lib/wanikani-logs/wanikani_data_$date.zip" + +echo "Cleaning up temporary files..." +rm -r "$tmp_dir" + diff --git a/modules/nixos/services/wanikani-stats/app.py b/modules/nixos/services/wanikani-stats/app.py new file mode 100644 index 0000000..3766221 --- /dev/null +++ b/modules/nixos/services/wanikani-stats/app.py @@ -0,0 +1,475 @@ +import zipfile +import json +from pathlib import Path +from flask import Flask, render_template_string, Response +import pandas as pd +import plotly.graph_objects as go +import plotly.express as px +from plotly.subplots import make_subplots +import plotly.io as pio +import functools + +# Set Plotly dark theme +pio.templates.default = "plotly_dark" + +app = Flask(__name__) +DATA_DIR = Path("/var/lib/wanikani-logs") + + +def get_zip_file_names(): + """Get a list of zip files in the data directory.""" + return [f for f in DATA_DIR.glob("*.zip") if f.is_file()] + + +# this is an expensive function so we will cache the results +@functools.lru_cache(maxsize=None) +def load_zip(zip_path): + print(f"Processing {zip_path}") + """Load a zip file and return its contents as a dictionary.""" + with zipfile.ZipFile(zip_path, "r") as z: + data = {} + # just read summary.json + with z.open("summary.json") as f: + summary_data = json.load(f) + num_reviews = len(summary_data["data"]["reviews"][0]["subject_ids"]) + num_lessons = len(summary_data["data"]["lessons"][0]["subject_ids"]) + data["num_reviews"] = num_reviews + data["num_lessons"] = num_lessons + # wanikani_data_2025-05-18.zip + data["date"] = zip_path.stem.split("_")[-1].replace(".zip", "") + + # with z.open("subjects.json") as f: + # subjects_data = json.load(f) + # print(f"Found total data subjects: {subjects_data['total_count']}") + # data["total_subjects"] = subjects_data['total_count'] + # so the subjects.json file is about 50 mb so we are just not gonna care if this value changes (doesnt change much) + data["total_subjects"] = 9300 + + with z.open("assignments.json") as f: + assignments_data = json.load(f) + print(f"Found total assignments: {assignments_data['total_count']}") + data["total_assignments"] = assignments_data["total_count"] + + # now the data key will give us all the srs stages + srs_stages = [0 for _ in range(10)] # 10 SRS stages + for assignment in assignments_data["data"]: + srs_stage = assignment["data"]["srs_stage"] + srs_stages[srs_stage] += 1 + + # add srs stages to data + for i, count in enumerate(srs_stages): + data[f"srs_stage_{i}"] = count + + print(data) + return data + + +def get_dataframe(list_of_daily_data): + """Convert a list of daily data dictionaries into a pandas DataFrame.""" + df = pd.DataFrame(list_of_daily_data) + + df["progression"] = df.apply( + lambda row: sum(row[f"srs_stage_{i}"] * (i + 1) for i in range(10)) + / (row["total_subjects"] * 10) + * 100, + axis=1, + ) + + df["apprentice"] = df.apply( + lambda row: row["srs_stage_1"] + + row["srs_stage_2"] + + row["srs_stage_3"] + + row["srs_stage_4"], + axis=1, + ) + + # Individual apprentice stages for distribution analysis + df["apprentice_1"] = df["srs_stage_1"] + df["apprentice_2"] = df["srs_stage_2"] + df["apprentice_3"] = df["srs_stage_3"] + df["apprentice_4"] = df["srs_stage_4"] + df["unlocked"] = df["srs_stage_0"] + + df["guru"] = df.apply(lambda row: row["srs_stage_5"] + row["srs_stage_6"], axis=1) + df["master"] = df["srs_stage_7"] + df["enlightened"] = df["srs_stage_8"] + df["burned"] = df["srs_stage_9"] + + return df + + +def get_plotly_html(df, column, title, ylabel): + """Generate an interactive Plotly HTML for a given DataFrame column.""" + fig = go.Figure() + + fig.add_trace( + go.Scatter( + x=df["date"], + y=df[column], + mode="lines+markers", + name=column.capitalize(), + line=dict(width=2), + marker=dict(size=6), + ) + ) + + fig.update_layout( + title=title, + xaxis_title="Date", + yaxis_title=ylabel, + template="plotly_dark", + plot_bgcolor="#151519", + paper_bgcolor="#151519", + width=1200, + height=600, + margin=dict(l=50, r=50, t=50, b=50), + ) + + # Show every 10th date label for better readability + date_indices = list(range(0, len(df), 10)) + fig.update_xaxes( + tickmode="array", + tickvals=[df.iloc[i]["date"] for i in date_indices], + ticktext=[df.iloc[i]["date"] for i in date_indices], + tickangle=45, + ) + + return fig.to_html(include_plotlyjs=True, div_id=f"plot_{column}") + + +def get_apprentice_distribution_html(df): + """Generate a stacked area chart showing apprentice stage distribution over time.""" + fig = go.Figure() + + # Add stacked area traces + fig.add_trace( + go.Scatter( + x=df["date"], + y=df["apprentice_1"], + mode="lines", + name="Apprentice I", + stackgroup="one", + fillcolor="rgba(255, 107, 107, 0.8)", + line=dict(width=0.5, color="#ff6b6b"), + ) + ) + + fig.add_trace( + go.Scatter( + x=df["date"], + y=df["apprentice_2"], + mode="lines", + name="Apprentice II", + stackgroup="one", + fillcolor="rgba(78, 205, 196, 0.8)", + line=dict(width=0.5, color="#4ecdc4"), + ) + ) + + fig.add_trace( + go.Scatter( + x=df["date"], + y=df["apprentice_3"], + mode="lines", + name="Apprentice III", + stackgroup="one", + fillcolor="rgba(69, 183, 209, 0.8)", + line=dict(width=0.5, color="#45b7d1"), + ) + ) + + fig.add_trace( + go.Scatter( + x=df["date"], + y=df["apprentice_4"], + mode="lines", + name="Apprentice IV", + stackgroup="one", + fillcolor="rgba(150, 206, 180, 0.8)", + line=dict(width=0.5, color="#96ceb4"), + ) + ) + + fig.update_layout( + title="Apprentice Stage Distribution Over Time", + xaxis_title="Date", + yaxis_title="Number of Items", + template="plotly_dark", + plot_bgcolor="#151519", + paper_bgcolor="#151519", + width=1200, + height=600, + margin=dict(l=50, r=50, t=50, b=50), + legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), + ) + + # Show every 10th date label for better readability + date_indices = list(range(0, len(df), 10)) + fig.update_xaxes( + tickmode="array", + tickvals=[df.iloc[i]["date"] for i in date_indices], + ticktext=[df.iloc[i]["date"] for i in date_indices], + tickangle=45, + ) + + return fig.to_html(include_plotlyjs=True, div_id="apprentice_distribution") + + +def generate_standalone_html(df, output_path=None): + """Generate a completely self-contained HTML file with all charts.""" + # Generate all chart HTML + reviews_html = get_plotly_html( + df, "num_reviews", "Daily Reviews", "Number of Reviews" + ) + lessons_html = get_plotly_html( + df, "num_lessons", "Daily Lessons", "Number of Lessons" + ) + progression_html = get_plotly_html( + df, "progression", "SRS Progression", "Progression (%)" + ) + apprentice_distribution_html = get_apprentice_distribution_html(df) + srs_stage_apprentice_html = get_plotly_html( + df, "apprentice", "Apprentice Stage", "Number of Subjects" + ) + srs_stage_guru_html = get_plotly_html( + df, "guru", "Guru Stage", "Number of Subjects" + ) + srs_stage_master_html = get_plotly_html( + df, "master", "Master Stage", "Number of Subjects" + ) + srs_stage_enlightened_html = get_plotly_html( + df, "enlightened", "Enlightened Stage", "Number of Subjects" + ) + srs_stage_burned_html = get_plotly_html( + df, "burned", "Burned Stage", "Number of Subjects" + ) + + # Create complete standalone HTML + html_content = f""" + + + + WaniKani Statistics Dashboard + + + + + +

WaniKani Statistics Dashboard

+
+ Interactive dashboard showing your WaniKani learning progress over time +
+ +
{reviews_html}
+
{lessons_html}
+
{progression_html}
+
{apprentice_distribution_html}
+
{srs_stage_apprentice_html}
+
{srs_stage_guru_html}
+
{srs_stage_master_html}
+
{srs_stage_enlightened_html}
+
{srs_stage_burned_html}
+ + + """ + + # Save to file if output_path is provided + if output_path: + with open(output_path, "w", encoding="utf-8") as f: + f.write(html_content) + print(f"Standalone HTML dashboard saved to: {output_path}") + + return html_content + + +@app.route("/download") +def download_dashboard(): + """Route to download a standalone HTML file.""" + file_names = get_zip_file_names() + + print(f"Found {len(file_names)} zip files in {DATA_DIR}") + list_of_daily_data = [] + for file_name in file_names: + daily_data = load_zip(file_name) + list_of_daily_data.append(daily_data) + + df = get_dataframe(list_of_daily_data) + df.sort_values(by="date", inplace=True) + + html_content = generate_standalone_html(df) + + response = Response(html_content, content_type="text/html") + response.headers["Content-Disposition"] = ( + "attachment; filename=wanikani_dashboard.html" + ) + return response + + +def render_html(df): + """Render the DataFrame as HTML with interactive Plotly charts.""" + reviews_html = get_plotly_html( + df, "num_reviews", "Daily Reviews", "Number of Reviews" + ) + lessons_html = get_plotly_html( + df, "num_lessons", "Daily Lessons", "Number of Lessons" + ) + progression_html = get_plotly_html( + df, "progression", "SRS Progression", "Progression (%)" + ) + + # apprentice distribution chart + apprentice_distribution_html = get_apprentice_distribution_html(df) + + # srs stages + srs_stage_apprentice_html = get_plotly_html( + df, "apprentice", "Apprentice Stage", "Number of Subjects" + ) + srs_stage_guru_html = get_plotly_html( + df, "guru", "Guru Stage", "Number of Subjects" + ) + srs_stage_master_html = get_plotly_html( + df, "master", "Master Stage", "Number of Subjects" + ) + srs_stage_enlightened_html = get_plotly_html( + df, "enlightened", "Enlightened Stage", "Number of Subjects" + ) + srs_stage_burned_html = get_plotly_html( + df, "burned", "Burned Stage", "Number of Subjects" + ) + + # Render HTML with embedded Plotly charts + html_content = f""" + + + + WaniKani Stats + + + + + +

WaniKani Statistics Dashboard

+
{reviews_html}
+
{lessons_html}
+
{progression_html}
+
{apprentice_distribution_html}
+
{srs_stage_apprentice_html}
+
{srs_stage_guru_html}
+
{srs_stage_master_html}
+
{srs_stage_enlightened_html}
+
{srs_stage_burned_html}
+ + + """ + return html_content + + +@app.route("/") +def index(): + """Index route""" + file_names = get_zip_file_names() + + print(f"Found {len(file_names)} zip files in {DATA_DIR}") + list_of_daily_data = [] + for file_name in file_names: + daily_data = load_zip(file_name) + list_of_daily_data.append(daily_data) + + df = get_dataframe(list_of_daily_data) + # sort by date string + df.sort_values(by="date", inplace=True) + + response = Response(render_html(df), content_type="text/html") + response.headers["Widget-Content-Type"] = "html" + response.headers["Widget-Title"] = "WaniKani Statistics" + return response + + +@app.route("/health") +def health(): + """Health check endpoint""" + return {"status": "ok", "service": "wanikani-stats"} + + +if __name__ == "__main__": + import sys + + # Check if user wants to generate standalone HTML + if len(sys.argv) > 1 and sys.argv[1] == "generate": + output_file = sys.argv[2] if len(sys.argv) > 2 else "wanikani_dashboard.html" + + print("Generating standalone HTML dashboard...") + file_names = get_zip_file_names() + + print(f"Found {len(file_names)} zip files in {DATA_DIR}") + list_of_daily_data = [] + for file_name in file_names: + daily_data = load_zip(file_name) + list_of_daily_data.append(daily_data) + + df = get_dataframe(list_of_daily_data) + df.sort_values(by="date", inplace=True) + + generate_standalone_html(df, output_file) + print(f"✅ Standalone HTML dashboard generated: {output_file}") + print( + "📊 You can now open this file in any web browser to view your interactive WaniKani stats!" + ) + + else: + # Start Flask server + port = int(sys.argv[1]) if len(sys.argv) > 1 else 8501 + print(f"Starting WaniKani Stats Flask app on port {port}") + print(f"📊 View dashboard at: http://localhost:{port}") + print(f"💾 Download standalone HTML at: http://localhost:{port}/download") + app.run(host="0.0.0.0", port=port, debug=False) diff --git a/modules/nixos/services/wanikani-stats/default.nix b/modules/nixos/services/wanikani-stats/default.nix new file mode 100644 index 0000000..efbac49 --- /dev/null +++ b/modules/nixos/services/wanikani-stats/default.nix @@ -0,0 +1,115 @@ +{ + pkgs, + config, + lib, + ... +}: +let + python = + # let + # packageOverrides = self: super: { + # imageio = super.imageio.overridePythonAttrs (old: { + # disabledTests = [ + # "test_read_stream" + # "test_uri_reading" + # "test_trim_filter" + # "test_process_termination" + # ]; + # }); + # plotly = super.plotly.overridePythonAttrs (old: { + # disabledTestPaths = (old.disabledTestPaths or [ ]) ++ [ + # "tests/test_optional/test_kaleido/test_kaleido.py" + # ]; + # }); + # }; + # in + pkgs.python3.override { + # inherit packageOverrides; + self = python; + }; + wanikani-stats-flask = pkgs.writeShellApplication { + name = "wanikani-stats-flask"; + runtimeInputs = [ + (python.withPackages ( + ppkgs: with ppkgs; [ + flask + pandas + numpy + jinja2 + matplotlib + seaborn + plotly + ] + )) + ]; + text = '' + #!/usr/bin/env bash + echo "Starting WaniKani Stats Flask app..." + exec python ${./app.py} ${toString config.services.wanikani-stats.port} + ''; + }; +in +{ + options.services.wanikani-stats = { + enable = lib.mkEnableOption { + description = "Enable WaniKani Stats Service"; + default = config.osbmModules.services.wanikani-stats.enable or false; + }; + + logDirectory = lib.mkOption { + type = lib.types.path; + default = "/var/lib/wanikani-logs"; + description = "Directory to get the log archives"; + }; + + port = lib.mkOption { + type = lib.types.port; + default = 8501; + description = "Port for the WaniKani Stats service"; + }; + }; + + config = lib.mkIf config.services.wanikani-stats.enable { + networking.firewall.allowedTCPPorts = [ + config.services.wanikani-stats.port + ]; + + systemd = { + services = { + wanikani-stats = { + description = "WaniKani Stats Service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + ExecStart = "${lib.getExe wanikani-stats-flask}"; + StateDirectory = "/var/lib/wanikani-stats"; + Restart = "on-failure"; + User = "root"; + Group = "root"; + }; + }; + + # Timer to restart the service every 12 hours + wanikani-stats-restart = { + description = "Restart WaniKani Stats Service"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.systemd}/bin/systemctl restart wanikani-stats.service"; + User = "root"; + }; + }; + }; + + timers.wanikani-stats-restart = { + description = "Timer to restart WaniKani Stats Service every 12 hours"; + wantedBy = [ "timers.target" ]; + timerConfig = { + OnCalendar = "*-*-* 00,12:00:00"; + Persistent = true; + RandomizedDelaySec = "5m"; + }; + }; + }; + }; +} diff --git a/modules/nixos/system/agenix.nix b/modules/nixos/system/agenix.nix new file mode 100644 index 0000000..c3e9661 --- /dev/null +++ b/modules/nixos/system/agenix.nix @@ -0,0 +1,39 @@ +{ + lib, + pkgs, + inputs, + config, + ... +}: +{ + imports = [ + inputs.agenix.nixosModules.default + ]; + + config = lib.mkIf config.osbmModules.agenix.enable { + environment.systemPackages = [ + inputs.agenix.packages.${pkgs.stdenv.hostPlatform.system}.agenix + pkgs.age + ]; + + age.secrets = { + vaultwarden.file = ../../../secrets/vaultwarden.age; + network-manager.file = ../../../secrets/network-manager.age; + ssh-key-private = { + file = ../../../secrets/ssh-key-private.age; + path = "/home/osbm/.ssh/id_ed25519"; + owner = "osbm"; + group = "users"; + mode = "600"; + }; + ssh-key-public = { + file = ../../../secrets/ssh-key-public.age; + path = "/home/osbm/.ssh/id_ed25519.pub"; + owner = "osbm"; + group = "users"; + mode = "644"; + }; + }; + + }; +} diff --git a/modules/nixos/system/default.nix b/modules/nixos/system/default.nix new file mode 100644 index 0000000..1f653ca --- /dev/null +++ b/modules/nixos/system/default.nix @@ -0,0 +1,15 @@ +{ + imports = [ + ./users.nix + ./desktop-environment.nix + ./nix-settings.nix + ./agenix.nix + ./home-manager.nix + ./virtualisation.nix + ./emulation.nix + ./i18n.nix + ./impermanence.nix + ./fonts.nix + ./nix-index.nix + ]; +} diff --git a/modules/nixos/system/desktop-environment.nix b/modules/nixos/system/desktop-environment.nix new file mode 100644 index 0000000..0e06e5b --- /dev/null +++ b/modules/nixos/system/desktop-environment.nix @@ -0,0 +1,95 @@ +{ + pkgs, + lib, + config, + ... +}: +let + cfg = config.osbmModules; +in +{ + config = lib.mkMerge [ + # Plasma Desktop Environment + (lib.mkIf (cfg.desktopEnvironment == "plasma") { + services = { + xserver.enable = true; + displayManager.sddm.enable = true; + desktopManager.plasma6.enable = true; + printing.enable = true; + }; + + environment = { + plasma6.excludePackages = with pkgs.kdePackages; [ + kate + konsole + yakuake + krunner # fuckass program keeps opening + ]; + systemPackages = with pkgs; [ + alacritty + ghostty + obsidian + mpv + kitty + qbittorrent + element-desktop + ]; + sessionVariables.NIXOS_OZONE_WL = "1"; + }; + }) + + # GNOME Desktop Environment + (lib.mkIf (cfg.desktopEnvironment == "gnome") { + + # Enable GNOME Desktop Environment + services = { + xserver.enable = true; + desktopManager.gnome.enable = true; + displayManager.gdm.enable = true; + gnome.gnome-keyring.enable = true; + }; + + # Enable dconf for GNOME settings + programs.dconf.enable = true; + + # Remove unwanted GNOME applications + environment.gnome.excludePackages = with pkgs; [ + baobab # disk usage analyzer + cheese # photo booth + eog # image viewer + epiphany # web browser + simple-scan # document scanner + totem # video player + yelp # help viewer + evince # document viewer + file-roller # archive manager + geary # email client + seahorse # password manager + gnome-calculator + gnome-calendar + gnome-characters + gnome-clocks + gnome-contacts + gnome-font-viewer + gnome-logs + gnome-maps + gnome-music + gnome-screenshot + gnome-system-monitor + gnome-weather + gnome-disk-utility + pkgs.gnome-connections + ]; + + }) + + # Common settings for any desktop environment + (lib.mkIf (cfg.desktopEnvironment != "none") { + # Enable X11 keymap + services.xserver.xkb = { + layout = lib.mkDefault "us"; + variant = lib.mkDefault ""; + }; + }) + ]; +} diff --git a/modules/nixos/system/emulation.nix b/modules/nixos/system/emulation.nix new file mode 100644 index 0000000..205474a --- /dev/null +++ b/modules/nixos/system/emulation.nix @@ -0,0 +1,7 @@ +{ lib, config, ... }: +{ + config = lib.mkIf config.osbmModules.emulation.aarch64.enable { + # Enable binfmt for aarch64 emulation + boot.binfmt.emulatedSystems = [ "aarch64-linux" ]; + }; +} diff --git a/modules/nixos/system/fonts.nix b/modules/nixos/system/fonts.nix new file mode 100644 index 0000000..214d66f --- /dev/null +++ b/modules/nixos/system/fonts.nix @@ -0,0 +1,57 @@ +{ + pkgs, + lib, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.fonts.enable { + fonts.packages = with pkgs; [ + cascadia-code + noto-fonts-cjk-sans + noto-fonts-color-emoji + liberation_ttf + fira-code + fira-code-symbols + mplus-outline-fonts.githubRelease + dina-font + nerd-fonts.fira-code + nerd-fonts.ubuntu + nerd-fonts.droid-sans-mono + proggyfonts + source-sans + source-han-sans + source-han-mono + source-sans-pro + source-serif-pro + font-awesome + font-awesome_5 + roboto + twitter-color-emoji + iosevka + dejavu_fonts + ]; + # fonts.fontconfig = { + # defaultFonts.emoji = ["Noto Color Emoji"]; + # }; + fonts.fontconfig.defaultFonts = { + serif = [ + "Source Han Serif SC" + "Source Han Serif TC" + "Noto Color Emoji" + ]; + sansSerif = [ + "Source Han Sans SC" + "Source Han Sans TC" + "Noto Color Emoji" + ]; + monospace = [ + "Droid Sans Mono" + "DejaVu Sans Mono" + "Source Han Mono" + "Cascadia Code" + ]; + emoji = [ "Noto Color Emoji" ]; + }; + }; +} diff --git a/modules/nixos/system/home-manager.nix b/modules/nixos/system/home-manager.nix new file mode 100644 index 0000000..9eda20c --- /dev/null +++ b/modules/nixos/system/home-manager.nix @@ -0,0 +1,52 @@ +{ + lib, + config, + inputs, + ... +}: + +{ + imports = [ + inputs.home-manager.nixosModules.home-manager + ]; + + config = lib.mkMerge [ + # Enable FUSE user_allow_other when impermanence is used + (lib.mkIf config.osbmModules.hardware.disko.zfs.root.impermanenceRoot { + programs.fuse.userAllowOther = true; + }) + + (lib.mkIf config.osbmModules.homeManager.enable { + home-manager = { + useGlobalPkgs = true; + useUserPackages = true; + backupFileExtension = ".nixbak"; + + # Pass inputs and outputs to home-manager modules + extraSpecialArgs = { + inherit inputs; + # Pass the NixOS system config to home-manager modules + nixosConfig = config; + }; + + # Configure home-manager for each user (excluding root) + users = + let + # Capture the NixOS system config before entering the home-manager scope + systemConfig = config; + in + lib.genAttrs (builtins.filter (u: u != "root") config.osbmModules.users) (_username: { + # Use the system's stateVersion for home-manager + home.stateVersion = lib.mkDefault systemConfig.system.stateVersion; + imports = [ + ../../home-manager + ] + ++ lib.optionals systemConfig.osbmModules.hardware.disko.zfs.root.impermanenceRoot [ + # Import impermanence home-manager module when impermanence is enabled + inputs.impermanence.homeManagerModules.impermanence + ]; + }); + }; + }) + ]; +} diff --git a/modules/nixos/system/i18n.nix b/modules/nixos/system/i18n.nix new file mode 100644 index 0000000..b053b2a --- /dev/null +++ b/modules/nixos/system/i18n.nix @@ -0,0 +1,45 @@ +{ + lib, + pkgs, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.i18n.enable { + time.timeZone = lib.mkDefault "Europe/Istanbul"; + + # Select internationalisation properties. + i18n = { + defaultLocale = "en_US.UTF-8"; + + extraLocaleSettings = { + LC_ADDRESS = "tr_TR.UTF-8"; + LC_IDENTIFICATION = "tr_TR.UTF-8"; + LC_MEASUREMENT = "tr_TR.UTF-8"; + LC_MONETARY = "tr_TR.UTF-8"; + LC_NAME = "tr_TR.UTF-8"; + LC_NUMERIC = "tr_TR.UTF-8"; + LC_PAPER = "tr_TR.UTF-8"; + LC_TELEPHONE = "tr_TR.UTF-8"; + LC_TIME = "ja_JP.UTF-8"; + # LC_ALL = "en_US.UTF-8"; + }; + + inputMethod = { + type = "fcitx5"; + enable = config.osbmModules.desktopEnvironment != "none"; + fcitx5.addons = with pkgs; [ + fcitx5-mozc + fcitx5-gtk + fcitx5-nord # a color theme + ]; + }; + }; + + services.xserver.xkb = { + layout = "us"; + variant = ""; + }; + + }; +} diff --git a/modules/nixos/system/impermanence.nix b/modules/nixos/system/impermanence.nix new file mode 100644 index 0000000..c97f947 --- /dev/null +++ b/modules/nixos/system/impermanence.nix @@ -0,0 +1,68 @@ +# impermanence +{ + lib, + inputs, + config, + ... +}: +let + # Filter out 'root' from the users list since it's a special system user + regularUsers = builtins.filter (u: u != "root") config.osbmModules.users; + + # Generate user persistence configuration + userPersistence = lib.genAttrs regularUsers (_username: { + directories = [ + "Documents" + { + directory = ".gnupg"; + mode = "0700"; + } + { + directory = ".ssh"; + mode = "0700"; + } + ".local/share/direnv" + ]; + # files = [ + # ".screenrc" + # ]; + }); +in +{ + imports = [ + inputs.impermanence.nixosModules.impermanence + ]; + + config = lib.mkMerge [ + # Enable impermanence root if configured + (lib.mkIf config.osbmModules.hardware.disko.zfs.root.impermanenceRoot { + environment.persistence."/persist" = { + hideMounts = true; + directories = [ + # systemd and other machine logs + "/var/log" + + # information about nixos users and groups + "/var/lib/nixos" + + # systemd coredumps to debug crashes + "/var/lib/systemd/coredump" + + # NetworkManager connection profiles and WiFi passwords + "/etc/NetworkManager/system-connections" + + ]; + files = [ + # the fuck is this file + # "/etc/machine-id" + + # user passwords + # "/etc/shadow" + # fuck me if i move the shadow file to the persist folder, + # i cant use sudo command to rebuild my system + ]; + users = userPersistence; + }; + }) + ]; +} diff --git a/modules/nixos/system/nix-index.nix b/modules/nixos/system/nix-index.nix new file mode 100644 index 0000000..6b1f8e9 --- /dev/null +++ b/modules/nixos/system/nix-index.nix @@ -0,0 +1,16 @@ +{ + lib, + config, + inputs, + ... +}: +{ + imports = [ + inputs.nix-index-database.nixosModules.nix-index + ]; + + config = lib.mkIf (config.osbmModules.nixIndex.enable && inputs ? nix-index-database) { + programs.nix-index-database.comma.enable = true; + programs.command-not-found.enable = false; + }; +} diff --git a/modules/nixos/system/nix-settings.nix b/modules/nixos/system/nix-settings.nix new file mode 100644 index 0000000..f210346 --- /dev/null +++ b/modules/nixos/system/nix-settings.nix @@ -0,0 +1,73 @@ +{ + inputs, + lib, + config, + ... +}: +{ + config = lib.mkIf config.osbmModules.nixSettings.enable { + # Allow unfree packages + nixpkgs = { + config = { + allowUnfreePredicate = + pkg: + builtins.elem (lib.getName pkg) [ + "vscode" + "discord" + "obsidian" + "steam" + "steam-unwrapped" + "open-webui" + "vscode-extension-github-copilot" + "spotify" + "cursor" + # NVIDIA related + "libcurand" + "nvidia-x11" + "cuda_cudart" + "cuda_nvcc" + "cuda_cccl" + "libcublas" + "libcusparse" + "libnvjitlink" + "libcufft" + "cudnn" + "cuda_nvrtc" + "libnpp" + "nvidia-settings" + # blender with cuda is not foss?!? + "blender" + ]; + allowAliases = false; + }; + }; + + # Enable Nix flakes + nix = { + settings = { + experimental-features = [ + "nix-command" + "flakes" + ]; + trusted-users = [ + "root" + config.osbmModules.defaultUser + ]; + }; + + optimise.automatic = true; + + channel.enable = false; + + registry = lib.mkIf (inputs ? self && inputs ? nixpkgs) { + self.flake = inputs.self; + nixpkgs.flake = inputs.nixpkgs; + osbm-nvim = lib.mkIf (inputs ? osbm-nvim) { + flake = inputs.osbm-nvim; + }; + }; + }; + + system.configurationRevision = inputs.self.rev or "dirty"; + }; +} diff --git a/modules/nixos/system/users.nix b/modules/nixos/system/users.nix new file mode 100644 index 0000000..643aa4d --- /dev/null +++ b/modules/nixos/system/users.nix @@ -0,0 +1,43 @@ +{ lib, config, ... }: +let + # Filter out 'root' from the users list since it's a special system user + regularUsers = builtins.filter (u: u != "root") config.osbmModules.users; +in +{ + config = lib.mkIf (config.osbmModules.users != [ ]) { + users.users = lib.mkMerge [ + # Create users based on the list (excluding root) + (lib.genAttrs regularUsers (username: { + isNormalUser = true; + description = username; + initialPassword = "changeme"; + extraGroups = [ + "networkmanager" + ] + ++ lib.optional (username == config.osbmModules.defaultUser) "wheel" + ++ lib.optional config.osbmModules.virtualisation.docker.enable "docker" + ++ lib.optional config.osbmModules.programs.adbFastboot.enable "adbusers"; + })) + + # Additional configuration for default user (including root if it's default) + { + ${config.osbmModules.defaultUser} = { + openssh.authorizedKeys.keys = lib.mkDefault [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k" + ]; + }; + } + + { + root = { + initialPassword = "changeme"; + openssh.authorizedKeys.keys = lib.mkDefault [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k" + ]; + }; + } + + ]; + + }; +} diff --git a/modules/nixos/system/virtualisation.nix b/modules/nixos/system/virtualisation.nix new file mode 100644 index 0000000..29fc84d --- /dev/null +++ b/modules/nixos/system/virtualisation.nix @@ -0,0 +1,28 @@ +{ lib, config, ... }: +let + cfg = config.osbmModules.virtualisation; +in +{ + config = lib.mkMerge [ + # Docker + (lib.mkIf cfg.docker.enable { + virtualisation.docker.enable = true; + virtualisation.docker.storageDriver = lib.mkDefault "overlay2"; + }) + + # Podman + (lib.mkIf cfg.podman.enable { + virtualisation.podman = { + enable = true; + dockerCompat = lib.mkDefault true; + defaultNetwork.settings.dns_enabled = true; + }; + }) + + # Libvirt/KVM + (lib.mkIf cfg.libvirt.enable { + virtualisation.libvirtd.enable = true; + programs.virt-manager.enable = true; + }) + ]; +} diff --git a/secrets/cloudflare.age b/secrets/cloudflare.age new file mode 100644 index 0000000..406ae1c --- /dev/null +++ b/secrets/cloudflare.age @@ -0,0 +1,18 @@ +age-encryption.org/v1 +-> ssh-ed25519 YVcKMQ m+TzH0uOU2/6ti8oabwOPMBRWC3X2GvY7JojIxvVIUE +mkeLDnnaXmh2E1q9ueYzkstzqRZBVqY1pJ1XYlOC+oo +-> ssh-ed25519 a9zBzw +qk1Gh0ocii1g/C2lDeZr447f9OMzmJM891ruFzoglM +n4kgDIZqDsuUOZqB15DHS7hJCijm+Ee+tlBsdgzdaHc +-> ssh-ed25519 /0F2+A D1s3AcvFmhsxSaRzgsXR4+C/epvCdYVDCA7bmtNmeyA +KqhvU1bsC44PYcBGX9k7ply5YILCIJkVBK2sWKPXUVc +-> ssh-ed25519 cs+R0A 1U34IFVZ/59q3rvTzYpb+fW0OZnbVB31moZzPj7UNXw +fX2eQ+M2nl+RbbKVpOP7N8a6v2zCBorOxmYFWW9gW/0 +-> ssh-ed25519 uTfCrQ vsWkwNohHmWosDB2oNl5OWfaQqz4MvdBo+lPdSzCrS0 +1J1uw5g7vP0zMC3MT/7kuNsSekANW1UAxBetWTMqZZA +-> ssh-ed25519 Ws1uag /9kr4cVp8bcLhZlvn08+6SH5zEKQ9LoLF235qThsJis +g/qs1nTGPk6TH75z7KyMCgimVPAkjSgaWBmgRNdTxWo +--- 1sGduFDJf3DfTO87Q3CecpHJ7A1dVqJWT1uMtBunk+Y +ۇ\[~.@dzLb4YשC +G6x +P +Υ^%zM:4bLf? \ No newline at end of file diff --git a/secrets/network-manager.age b/secrets/network-manager.age new file mode 100644 index 0000000..c79dfbc Binary files /dev/null and b/secrets/network-manager.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix new file mode 100644 index 0000000..a5f4648 --- /dev/null +++ b/secrets/secrets.nix @@ -0,0 +1,25 @@ +let + # cat /etc/ssh/ssh_host_ed25519_key.pub on each machine + ymir = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFgjjvukAG0RvQfHj5Iy64XOFh9YbdnNAmgFUvzlnAEt"; + tartarus = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMxbIyQnQFA1RFQKH4eHHWcT7Z0tCumerCsRMjlHgSPd"; + pochita = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHpE9pf7ZeNvpW1GxLLF8kB0Q8HQO7XSIea1Oe9qubKt"; + wallfacer = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOr8pQvLsNCHQdsBKWpziYTPjBkEcQy272kZ5Gqoaatt"; + apollo = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINsV8e8veX5/weeC8he+31aiNVZfQ82BpvSzARSM1uZF"; + + osbm = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPfnV+qqUCJf92npNW4Jy0hIiepCJFBDJHXBHnUlNX0k"; + + machines = [ + ymir + tartarus + pochita + wallfacer + apollo + ]; +in +{ + "network-manager.age".publicKeys = machines ++ [ osbm ]; + "ssh-key-private.age".publicKeys = machines ++ [ osbm ]; + "ssh-key-public.age".publicKeys = machines ++ [ osbm ]; + "cloudflare.age".publicKeys = machines ++ [ osbm ]; + "vaultwarden.age".publicKeys = machines ++ [ osbm ]; +} diff --git a/secrets/ssh-key-private.age b/secrets/ssh-key-private.age new file mode 100644 index 0000000..0ef0ecd Binary files /dev/null and b/secrets/ssh-key-private.age differ diff --git a/secrets/ssh-key-public.age b/secrets/ssh-key-public.age new file mode 100644 index 0000000..cd61285 Binary files /dev/null and b/secrets/ssh-key-public.age differ diff --git a/secrets/vaultwarden.age b/secrets/vaultwarden.age new file mode 100644 index 0000000..5088edc --- /dev/null +++ b/secrets/vaultwarden.age @@ -0,0 +1,17 @@ +age-encryption.org/v1 +-> ssh-ed25519 YVcKMQ 9A4o6YqSMG0WyCquZMCiTxZ13m4HYIsXAkA15SKGeGw +M3m60veZZpKYRJt+kE0cCnYtYVfsOXjyaQ4prYBlcsg +-> ssh-ed25519 a9zBzw UWTlT2YsgPxWQIAq3E6w3IpfQ1+a6jpTjPmheIOewyg +nJlk1ILkiwUapR4++UypLH5BNe+TwmIOZ3LPWZYjM7E +-> ssh-ed25519 /0F2+A K/PPN0iBb76hw5eU1wf9OLmdFVp6A1JlSjL4wdShoxI +sNWcIQTfukRCYaY9lPSZnZRtOZpwpNgWUDbvqe0ha/4 +-> ssh-ed25519 cs+R0A PFz9tm+oeFamg7XjVaUzYf1mFOJttGnqKhjFblShWAA +2O5pCPJnlA8kSUZUjAGzEIwPGPlcJVIYF7oCUI7NAQs +-> ssh-ed25519 uTfCrQ v+fSi0Vi0OzCqB69vpgpbts8FpIVAcFYwpbihZXguwo +BEGzhIxLV3Q6pfe27f2kx8N7W8H4zBPP2tJgyKLzCpQ +-> ssh-ed25519 Ws1uag kkvILCkApOxL2RLaEaT4uOfWBTKPcPlDX1aZwqmJ/Bg +OSUy2BqzP7FlAV1o757Lc+Ww4eO/UfvyiSDrGHMKOj4 +--- 5DwmbdRNElZykXb+HwILIEkcD3VKGkXBKF/uNMSTM4w +{(IF?HE}&:epN+z +hT(ށ[>嫢jh~ǿK8}9R s5cɎuf%ͪTÝx +N ( \ No newline at end of file