#+title: Nix Configuration This file holds the entirety of all configuration files for both NixOS as well as home manager across all machines that I currently use. The only exception is my Emacs configuration which is held in its own .org file - this is done because that allows for upon-switch parsing of that file and installation of all emacs-packages through home-manager. The init.el file cannot be used there as it contains UTF-8 characters that would break the nix function responsible for handling the emacs-package building process. * Noweb-Ref blocks These blocks are used in several places throughout the configurations, but not on all machines necessarily. For example, the themeing section needs to be in a NixOS block on NixOS machines but in a home-manager block on non-NixOS. This serves to reduce code duplication. ** All systems *** Themeing This is where the theme for the whole OS is defined. This noweb-ref section cannot be copied to the general NixOS config for now since they are on different levels in the config, which would make the flake impure. #+begin_src nix :noweb-ref theme stylix = { base16Scheme = ../../wallpaper/swarsel.yaml; # base16Scheme = "${pkgs.base16-schemes}/share/themes/shapeshifter.yaml"; polarity = "dark"; opacity.popups = 0.5; cursor = { package = pkgs.capitaine-cursors; name = "capitaine-cursors"; size = 16; }; fonts = { sizes = { terminal = 10; applications = 11; }; serif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); package = pkgs.cantarell-fonts; # package = pkgs.montserrat; name = "Cantarell"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; sansSerif = { # package = (pkgs.nerdfonts.override { fonts = [ "FiraMono" "FiraCode"]; }); package = pkgs.cantarell-fonts; # package = pkgs.montserrat; name = "Cantarell"; # name = "FiraCode Nerd Font Propo"; # name = "Montserrat"; }; monospace = { package = (pkgs.nerdfonts.override { fonts = [ "FiraCode"]; }); name = "FiraCode Nerd Font Mono"; }; emoji = { package = pkgs.noto-fonts-emoji; name = "Noto Color Emoji"; }; }; }; #+end_src *** Waybar items - LAPTOPS #+begin_src nix :noweb-ref waybarlaptop programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark" "mpris" "custom/left-arrow-light" "network" "custom/left-arrow-dark" "pulseaudio" "custom/left-arrow-light" "custom/pseudobat" "battery" "custom/left-arrow-dark" "group/hardware" "custom/left-arrow-light" "clock#2" "custom/left-arrow-dark" "clock#1" ]; #+end_src *** Waybar items - PC #+begin_src nix :noweb-ref waybarpc programs.waybar.settings.mainBar."custom/pseudobat"= { format= ""; on-click-right= "wlogout -p layer-shell"; }; programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark" "mpris" "custom/left-arrow-light" "network" "custom/left-arrow-dark" "pulseaudio" "custom/left-arrow-light" "custom/pseudobat" "battery" "custom/left-arrow-dark" "group/hardware" "custom/left-arrow-light" "clock#2" "custom/left-arrow-dark" "clock#1" ]; #+end_src ** NixOS *** Sway Startup commands #+begin_src nix :noweb-ref startupnixos { command = "nextcloud --background";} # { command = "spotify";} { command = "discord --start-minimized";} # { command = "element-desktop --hidden";} { command = "element-desktop --hidden -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds";} { command = "ANKI_WAYLAND=1 anki";} { command = "OBSIDIAN_USE_WAYLAND=1 obsidian";} { command = "nm-applet";} # { command = "sleep 60 && syncthingtray --wait"; } #+end_src *** gpg-agent #+begin_src nix :noweb-ref gpgagent services.gpg-agent = { enable = true; enableSshSupport = true; enableExtraSocket = true; pinentryPackage = pkgs.pinentry-gtk2; extraConfig = '' allow-emacs-pinentry allow-loopback-pinentry ''; }; #+end_src *** Wrap with hardware-configuration #+begin_src nix :noweb-ref wrap imports = [ ./hardware-configuration.nix ]; #+end_src *** Virtual hosts init #+begin_src nix :noweb-ref vminitbare services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.useDHCP = true; networking.enableIPv6 = false; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; listenAddresses = [{ port = 22; addr = "0.0.0.0"; }]; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; #+end_src #+begin_src nix :noweb yes :noweb-ref vminit imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix ]; <> #+end_src ** flake.nix *** Inputs & Inputs@Outputs #+begin_src nix :noweb-ref flakeinputsatoutputs nixpkgs, home-manager, nix-on-droid, nixos-generators, emacs-overlay, nur, nixgl, stylix, sops-nix, lanzaboote, pia, nixpkgs-mautrix-signal, nix-gaming, nixos-hardware, nix-alien, #+end_src #+begin_src nix :noweb-ref flakeinputs nixpkgs.url = github:nixos/nixpkgs/nixos-unstable; # user-level configuration home-manager = { url = github:nix-community/home-manager; inputs.nixpkgs.follows = "nixpkgs"; }; # overlay to access bleeding edge emacs emacs-overlay = { url = github:nix-community/emacs-overlay; inputs.nixpkgs.follows = "nixpkgs"; }; # nix user repository # i use this mainly to not have to build all firefox extensions # myself as well as for the emacs-init package (tbd) nur.url = github:nix-community/NUR; # provides GL to non-NixOS hosts nixgl.url = github:guibou/nixGL; # manages all themeing using Home-Manager stylix.url = github:danth/stylix; # nix secrets management sops-nix.url = github:Mic92/sops-nix; # enable secure boot on NixOS lanzaboote.url = github:nix-community/lanzaboote; # nix for android nix-on-droid = { url = github:t184256/nix-on-droid/release-23.05; inputs.nixpkgs.follows = "nixpkgs"; }; # generate NixOS images nixos-generators = { url = github:nix-community/nixos-generators; inputs.nixpkgs.follows = "nixpkgs"; }; # privateinternetaccess nixos integration - not sure if I will keep using pia = { url = "git+https://git.sr.ht/~rprospero/nixos-pia?ref=development"; inputs.nixpkgs.follows = "nixpkgs"; }; # provides expressions for mautrix-signal nixpkgs-mautrix-signal ={ url = github:niklaskorz/nixpkgs/nixos-23.11-mautrix-signal; }; # patches for gaming on nix nix-gaming = { url = github:fufexan/nix-gaming; }; # hardware quirks on nix nixos-hardware = { url = github:NixOS/nixos-hardware/master; }; # dynamic library loading nix-alien = { url = github:thiagokokada/nix-alien; }; #+end_src *** let #+begin_src nix :noweb-ref flakelet system = "x86_64-linux"; # not very portable, but I do not use other architectures at the moment pkgs = import nixpkgs { inherit system; overlays = [ emacs-overlay.overlay nur.overlay nixgl.overlay ]; config.allowUnfree = true; }; # for ovm arm hosts armpkgs = import nixpkgs { system = "aarch64-linux"; overlays = [ emacs-overlay.overlay nur.overlay nixgl.overlay ]; config.allowUnfree = true; }; pkgsmautrix = import nixpkgs-mautrix-signal { inherit system; config.allowUnfree = true; }; # NixOS modules that can only be used on NixOS systems nixModules = [ stylix.nixosModules.stylix ./profiles/common/nixos.nix # dynamic library loading ({ self, system, ... }: { environment.systemPackages = with self.inputs.nix-alien.packages.${system}; [ nix-alien ]; # needed for `nix-alien-ld` programs.nix-ld.enable = true; }) ]; # Home-Manager modules wanted on non-NixOS systems homeModules = [ stylix.homeManagerModules.stylix ]; # Home-Manager modules wanted on both NixOS and non-NixOS systems mixedModules = [ sops-nix.homeManagerModules.sops ./profiles/common/home.nix ]; #+end_src *** nixosConfigurations #+begin_src nix :noweb-ref flakenixosconf onett = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = nixModules ++ [ ./profiles/onett/nixos.nix home-manager.nixosModules.home-manager { home-manager.users.swarsel.imports = mixedModules ++ [ ./profiles/onett/home.nix ]; } ]; }; sandbox = nixpkgs.lib.nixosSystem { pkgs = pkgsmautrix; specialArgs.unstable = nixpkgs-mautrix-signal; modules = [ sops-nix.nixosModules.sops ./profiles/sandbox/nixos.nix ]; }; twoson = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = nixModules ++ [ ./profiles/twoson/nixos.nix home-manager.nixosModules.home-manager { home-manager.users.swarsel.imports = mixedModules ++ [ ./profiles/twoson/home.nix ]; } ]; }; threed = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = nixModules ++ [ lanzaboote.nixosModules.lanzaboote ./profiles/threed/nixos.nix home-manager.nixosModules.home-manager { home-manager.users.swarsel.imports = mixedModules ++ [ ./profiles/threed/home.nix ]; } ]; }; fourside = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = nixModules ++ [ nixos-hardware.nixosModules.lenovo-thinkpad-p14s-amd-gen2 ./profiles/fourside/nixos.nix home-manager.nixosModules.home-manager { home-manager.users.swarsel.imports = mixedModules ++ [ ./profiles/fourside/home.nix ]; } ]; }; stand = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = nixModules ++ [ ./profiles/stand/nixos.nix home-manager.nixosModules.home-manager { home-manager.users.homelen.imports = mixedModules ++ [ ./profiles/stand/home.nix ]; } ]; }; nginx = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/server1/nginx/nixos.nix ]; }; calibre = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/server1/calibre/nixos.nix ]; }; jellyfin = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ # sops-nix.nixosModules.sops ./profiles/server1/jellyfin/nixos.nix ]; }; transmission = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops pia.nixosModule ./profiles/server1/transmission/nixos.nix ]; }; matrix = nixpkgs.lib.nixosSystem { # specialArgs = {inherit pkgsmautrix; }; pkgs = pkgsmautrix; # this is to import a service module that is not on nixpkgs # this way avoids infinite recursion errors specialArgs.unstable = nixpkgs-mautrix-signal; modules = [ sops-nix.nixosModules.sops ./profiles/server1/matrix/nixos.nix ]; }; sound = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/server1/sound/nixos.nix ]; }; spotifyd = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/server1/spotifyd/nixos.nix ]; }; paperless = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/server1/paperless/nixos.nix ]; }; #ovm swarsel sync = nixpkgs.lib.nixosSystem { specialArgs = {inherit inputs pkgs; }; modules = [ sops-nix.nixosModules.sops ./profiles/remote/oracle/sync/nixos.nix ]; }; #ovm swarsel swatrix = nixpkgs.lib.nixosSystem { # specialArgs = {inherit pkgsmautrix; }; pkgs = pkgsmautrix; # this is to import a service module that is not on nixpkgs # this way avoids infinite recursion errors specialArgs.unstable = nixpkgs-mautrix-signal; modules = [ sops-nix.nixosModules.sops ./profiles/remote/oracle/matrix/nixos.nix ]; }; #+end_src *** homeConfigurations #+begin_src nix :noweb-ref flakehomeconf "leons@PCisLee" = home-manager.lib.homeManagerConfiguration { inherit pkgs; modules = homeModules ++ mixedModules ++ [ ./profiles/surface/home.nix ]; }; #+end_src *** nixOnDroidConfigurations #+begin_src nix :noweb-ref flakedroidconf default = nix-on-droid.lib.nixOnDroidConfiguration { modules = [ ./profiles/mysticant/configuration.nix ]; }; #+end_src *** nixos-generators #+begin_src nix :noweb-ref flakenixosgenerators proxmox-lxc = nixos-generators.nixosGenerate { inherit system; modules = [ ./profiles/server1/TEMPLATE/nixos.nix ]; format = "proxmox-lxc"; }; #+end_src * TODO System specific configuration This section mainly exists house different `configuration.nix` files for system level configurations of NixOS systems as well as `home.nix` for user level configurations on all systems. Important: Think about if a settings really needs to go into this area - chances are that the settings can also go to the general settings. ** Template (for new machines) This section holds the minimum configuration that is needed on a new host. These assume a NixOS machine (so not standalone home-manager on a non-NixOS host), as this is the setting that I will most likely use in the future now. All of these blocks need to be updated, with entries called TEMPLATE mostly needed to be filled with host-/user-specific values or other inputs. If TEMPLATE is given in a comment section, see the provided values as likely defaults. The TEMPLATE comments should afterwards be deleted for clarity. If a non-NixOS host must be used, check the Surface configuration for pointers. Most likely the waybar settings need to be adjusted, since non-NixOS (as of writing this) fails to display drawers in the waybar properly. No matter what you do, check the initial /etc/nixos/configuration.nix for notable changes that might emerge in future versions of nix. *** NixOS #+begin_src nix :noweb yes :tangle profiles/TEMPLATE/nixos.nix { config, lib, pkgs, inputs, ... }: { <> services = { getty.autologinUser = "TEMPLATE"; greetd.settings.initial_session.user="TEMPLATE"; }; # Bootloader boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/sda"; # TEMPLATE - if only one disk, this will work boot.loader.grub.useOSProber = true; # -------------------------------------- # you might need a configuration like this instead: # Bootloader # boot.loader.grub.enable = true; # boot.loader.grub.devices = ["nodev" ]; # boot.loader.grub.useOSProber = true; # boot.kernelPackages = pkgs.linuxPackages_latest; # -------------------------------------- networking.hostName = "TEMPLATE"; # Define your hostname. stylix.image = ../../wallpaper/TEMPLATEwp.png; <> # Configure keymap in X11 (only used for login) services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; users.users.TEMPLATE = { isNormalUser = true; description = "TEMPLATE"; extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ]; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change } #+end_src *** Home Manager #+begin_src nix :noweb yes :tangle profiles/TEMPLATE/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "TEMPLATE"; homeDirectory = "/home/TEMPLATE"; stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing. keyboard.layout = "us"; # TEMPLATE home.packages = with pkgs; [ # --------------------------------------------------------------- # if schildichat works on this machine, use it, otherwise go for element # element-desktop # --------------------------------------------------------------- ]; }; # update path if the sops private key is stored somewhere else sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; # waybar config - TEMPLATE - update for cores and temp programs.waybar.settings.mainBar = { #cpu.format = "{icon0} {icon1} {icon2} {icon3}"; cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}"; temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input"; }; # ----------------------------------------------------------------- # is this machine always connected to power? If yes, use this block: # <> # ----------------------------------------------------------------- # ----------------------------------------------------------------- # if not always connected to power (laptop), use this (default): <> # ----------------------------------------------------------------- wayland.windowManager.sway= { config = rec { # update for actual inputs here, input = { "36125:53060:splitkb.com_Kyria_rev3" = { xkb_layout = "us"; xkb_variant = "altgr-intl"; }; "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE xkb_layout = "us"; xkb_options = "grp:win_space_toggle"; # xkb_options = "ctrl:nocaps,grp:win_space_toggle"; xkb_variant = "altgr-intl"; }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { DP-1 = { mode = "2560x1440"; # TEMPLATE scale = "1"; bg = "~/.dotfiles/wallpaper/TEMPLATE.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { # TEMPLATE "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\""; # "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\""; }; startup = [ <> ]; }; }; } #+end_src ** Physical hosts *** TODO Surface My Surface Pro 3, only used for on-the-go university work. Be careful when pushing largechanges to this machine, as it easily runs out of memory on large switches. At the moment the only machine running non-NixOS, so special care must be taken not to break this one during updates. **** TODO Channel setup This installs nixGL, which is needed to run GL apps installed through home-manager, since this machine is not using NixOS. - TODO: move this to flake.nix by using an overlay 1) Install nixGL: #+begin_src nix nix-channel --add https://github.com/guibou/nixGL/archive/main.tar.gz nixgl && nix-channel --update nix-env -iA nixgl.auto.nixGLDefault # or replace `nixGLDefault` with your desired wrapper #+end_src This is needed in order to use EGL. Prefix programs that use it with `nixGL` **** Home manager #+begin_src nix :noweb yes :tangle profiles/surface/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { programs.home-manager.enable = true; home.username = "leons"; home.homeDirectory = "/home/leons"; home.stateVersion = "23.05"; # Please read the comment before changing. stylix.image = ../../wallpaper/surfacewp.png; <> nixpkgs = { config = { allowUnfree = true; allowUnfreePredicate = (_: true); }; }; services.xcape = { enable = true; mapExpression = { Control_L = "Escape"; }; }; #keyboard config home.keyboard.layout = "us"; sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; # waybar config programs.waybar.settings.mainBar.cpu.format = "{icon0} {icon1} {icon2} {icon3}"; programs.waybar.settings.mainBar.temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input"; programs.waybar.settings.mainBar.modules-right = ["custom/outer-left-arrow-dark" "mpris" "custom/left-arrow-light" "network" "custom/left-arrow-dark" "pulseaudio" "custom/left-arrow-light" "battery" "custom/left-arrow-dark" "temperature" "custom/left-arrow-light" "disk" "custom/left-arrow-dark" "memory" "custom/left-arrow-light" "cpu" "custom/left-arrow-dark" "tray" "custom/left-arrow-light" "clock#2" "custom/left-arrow-dark" "clock#1" ]; services.blueman-applet.enable = true; home.packages = with pkgs; [ # nixgl.auto.nixGLDefault evince # nodejs_20 # messaging # we use gomuks for RAM preservation, but keep schildi around for files and images ]; programs.zsh.initExtra = " export GPG_TTY=\"$(tty)\" export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket) gpgconf --launch gpg-agent "; # sway config wayland.windowManager.sway= { config = rec { input = { "*" = { xkb_layout = "us"; xkb_options = "ctrl:nocaps,grp:win_space_toggle"; xkb_variant = "altgr-intl"; }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { eDP-1 = { mode = "2160x1440@59.955Hz"; scale = "1"; bg = "~/.dotfiles/wallpaper/surfacewp.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+F2" = "exec brightnessctl set +5%"; "${modifier}+F1"= "exec brightnessctl set 5%-"; "${modifier}+n" = "exec sway output eDP-1 transform normal, splith"; "${modifier}+Ctrl+p" = "exec nixGL wl-mirror eDP-1"; "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv"; "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkgomuks.sh\""; }; startup = [ { command = "sleep 60 && nixGL nextcloud --background";} # { command = "sleep 60 && nixGL spotify";} { command = "sleep 60 && nixGL discord --start-minimized -enable-features=UseOzonePlatform -ozone-platform=wayland";} # { command = "sleep 60 && nixGL schildichat-desktop --hidden";} { command = "sleep 60 && nixGL syncthingtray --wait"; } { command = "sleep 60 && ANKI_WAYLAND=1 nixGL anki";} { command = "nm-applet --indicator";} { command = "sleep 60 && OBSIDIAN_USE_WAYLAND=1 nixGL obsidian -enable-features=UseOzonePlatform -ozone-platform=wayland";} ]; keycodebindings = { "124" = "exec systemctl suspend"; }; }; extraConfig = " exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1 exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1 "; }; } #+end_src *** Onett (Lenovo Y510P) My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately. **** NixOS #+begin_src nix :noweb yes :tangle profiles/onett/nixos.nix { config, lib, pkgs, inputs, ... }: { <> services = { greetd.settings.initial_session.user ="swarsel"; xserver.videoDrivers = ["nvidia"]; }; hardware = { nvidia = { modesetting.enable = true; powerManagement.enable = true; prime = { intelBusId = "PCI:0:2:0"; nvidiaBusId = "PCI:1:0:0"; sync.enable = true; }; }; pulseaudio.configFile = pkgs.runCommand "default.pa" {} '' sed 's/module-udev-detect$/module-udev-detect tsched=0/' \ ${pkgs.pulseaudio}/etc/pulse/default.pa > $out ''; bluetooth.enable = true; }; stylix.image = ../../wallpaper/lenovowp.png; <> boot.loader.grub = { enable = true; device = "/dev/sda"; useOSProber = true; }; networking.hostName = "onett"; # Define your hostname. networking.enableIPv6 = false; users.users.swarsel = { isNormalUser = true; description = "Leon S"; extraGroups = [ "networkmanager" "wheel" "lp"]; packages = with pkgs; []; }; system.stateVersion = "23.05"; # Did you read the comment? environment.systemPackages = with pkgs; [ ]; } #+end_src **** Home Manager #+begin_src nix :noweb yes :tangle profiles/onett/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "swarsel"; homeDirectory = "/home/swarsel"; stateVersion = "23.05"; # Please read the comment before changing. keyboard.layout = "de"; packages = with pkgs; [ ]; }; sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; # # waybar config programs.waybar.settings.mainBar = { cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}"; temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon3/temp3_input"; }; <> services.blueman-applet.enable = true; wayland.windowManager.sway= { config = rec { input = { "1:1:AT_Translated_Set_2_keyboard" = { xkb_layout = "us"; xkb_options = "grp:win_space_toggle"; # xkb_options = "ctrl:nocaps,grp:win_space_toggle"; xkb_variant = "altgr-intl"; }; "2362:33538:ipad_keyboard_Keyboard" = { xkb_layout = "us"; xkb_options = "altwin:swap_lalt_lwin,ctrl:nocaps,grp:win_space_toggle"; xkb_variant = "colemak_dh"; }; "36125:53060:splitkb.com_Kyria_rev3" = { xkb_layout = "us"; xkb_variant = "altgr-intl"; }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { eDP-1 = { mode = "1920x1080"; scale = "1"; bg = "~/.dotfiles/wallpaper/lenovowp.png fill"; position = "1920,0"; }; VGA-1 = { mode = "1920x1080"; scale = "1"; bg = "~/.dotfiles/wallpaper/lenovowp.png fill"; position = "0,0"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+F2" = "exec brightnessctl set +5%"; "${modifier}+F1"= "exec brightnessctl set 5%-"; "XF86MonBrightnessUp" = "exec brightnessctl set +5%"; "XF86MonBrightnessDown"= "exec brightnessctl set 5%-"; "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1"; "XF86HomePage" = "exec wtype -P Escape -p Escape"; "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\""; }; keycodebindings = { "94" = "exec wtype c"; "Shift+94" = "exec wtype C"; "Ctrl+94" = "exec wtype -M ctrl c -m ctrl"; "Ctrl+Shift+94" = "exec wtype -M ctrl -M shift c -m ctrl -m shift"; }; startup = [ <> ]; }; extraConfig = " "; }; } #+end_src *** Twoson (Lenovo Thinkpad T14s Gen3) **** NixOS #+begin_src nix :noweb yes :tangle profiles/twoson/nixos.nix { config, lib, pkgs, inputs, ... }: { <> services = { getty.autologinUser = "swarsel"; greetd.settings.initial_session.user="swarsel"; }; # Bootloader # boot.loader.grub.enable = true; # boot.loader.grub.device = "/dev/sda"; # TEMPLATE - if only one disk, this will work # boot.loader.grub.useOSProber = true; # -------------------------------------- # you might need a configuration like this instead: # Bootloader # boot.loader.grub.enable = true; # boot.loader.grub.devices = ["nodev" ]; # boot.loader.grub.useOSProber = true; # boot.kernelPackages = pkgs.linuxPackages_latest; # -------------------------------------- networking.hostName = "twoson"; # Define your hostname. stylix.image = ../../wallpaper/t14swp.png; <> # Configure keymap in X11 (only used for login) services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; users.users.swarsel = { isNormalUser = true; description = "TEMPLATE"; extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ]; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change } #+end_src **** Home Manager #+begin_src nix :noweb yes :tangle profiles/twoson/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "swarsel"; homeDirectory = "/home/swarsel"; stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing. keyboard.layout = "us"; # TEMPLATE home.packages = with pkgs; [ # --------------------------------------------------------------- # if schildichat works on this machine, use it, otherwise go for element # element-desktop # --------------------------------------------------------------- ]; }; # update path if the sops private key is stored somewhere else sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; # waybar config - TEMPLATE - update for cores and temp programs.waybar.settings.mainBar = { #cpu.format = "{icon0} {icon1} {icon2} {icon3}"; cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}"; temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input"; }; # ----------------------------------------------------------------- # is this machine always connected to power? If yes, use this block: # <> # ----------------------------------------------------------------- # ----------------------------------------------------------------- # if not always connected to power (laptop), use this (default): <> # ----------------------------------------------------------------- wayland.windowManager.sway= { config = rec { # update for actual inputs here, input = { "36125:53060:splitkb.com_Kyria_rev3" = { xkb_layout = "us"; xkb_variant = "altgr-intl"; }; # "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE # xkb_layout = "us"; # xkb_options = "grp:win_space_toggle"; # # xkb_options = "ctrl:nocaps,grp:win_space_toggle"; # xkb_variant = "altgr-intl"; # }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { DP-1 = { mode = "1920x1280"; # TEMPLATE scale = "1"; bg = "~/.dotfiles/wallpaper/t14swp.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { # TEMPLATE "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\""; # "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\""; }; startup = [ <> ]; }; }; } #+end_src *** Threed (Surface Pro 3) New setup for the SP3, this time using NixOS - another machine will take over the HM-only config for compatibility in the future. **** NixOS #+begin_src nix :noweb yes :tangle profiles/threed/nixos.nix { config, lib, pkgs, inputs, ... }: { <> services = { getty.autologinUser = "swarsel"; greetd.settings.initial_session.user="swarsel"; }; hardware.bluetooth.enable = true; # Bootloader boot = { loader.systemd-boot.enable = lib.mkForce false; lanzaboote = { enable = true; pkiBundle = "/etc/secureboot"; }; loader.efi.canTouchEfiVariables = true; # use bootspec instead of lzbt for secure boot. This is not a generally needed setting bootspec.enable = true; # kernelPackages = pkgs.linuxPackages_latest; }; networking = { hostName = "threed"; enableIPv6 = false; firewall.enable = false; }; stylix.image = ../../wallpaper/surfacewp.png; <> users.users.swarsel = { isNormalUser = true; description = "Leon S"; extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ]; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ ]; system.stateVersion = "23.05"; } #+end_src **** Home Manager #+begin_src nix :noweb yes :tangle profiles/threed/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "swarsel"; homeDirectory = "/home/swarsel"; stateVersion = "23.05"; # Please read the comment before changing. keyboard.layout = "us"; packages = with pkgs; [ ]; }; sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; programs.waybar.settings.mainBar = { cpu.format = "{icon0} {icon1} {icon2} {icon3}"; temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input"; }; <> wayland.windowManager.sway= { config = rec { input = { "*" = { xkb_layout = "us"; xkb_options = "grp:win_space_toggle"; xkb_variant = "altgr-intl"; }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { eDP-1 = { mode = "2160x1440@59.955Hz"; scale = "1"; bg = "~/.dotfiles/wallpaper/surfacewp.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+F2" = "exec brightnessctl set +5%"; "${modifier}+F1"= "exec brightnessctl set 5%-"; "${modifier}+n" = "exec sway output eDP-1 transform normal, splith"; "${modifier}+Ctrl+p" = "exec wl-mirror eDP-1"; "${modifier}+t" = "exec sway output eDP-1 transform 90, splitv"; "${modifier}+XF86AudioLowerVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; "${modifier}+XF86AudioRaiseVolume" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\""; }; startup = [ <> ]; keycodebindings = { "124" = "exec systemctl suspend"; }; }; extraConfig = " exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05 map_to_output eDP-1 exec swaymsg input 7062:6917:NTRG0001:01_1B96:1B05_Stylus map_to_output eDP-1 "; }; } #+end_src *** Fourside (Lenovo Thinkpad P14s Gen2) **** NixOS #+begin_src nix :noweb yes :tangle profiles/fourside/nixos.nix { config, lib, pkgs, inputs, ... }: { # <> imports = [ ./hardware-configuration.nix ]; services = { getty.autologinUser = "swarsel"; greetd.settings.initial_session.user="swarsel"; }; boot = { loader.systemd-boot.enable = true; loader.efi.canTouchEfiVariables = true; # kernelPackages = pkgs.linuxPackages_latest; }; networking = { hostName = "fourside"; # Define your hostname. nftables.enable = true; enableIPv6 = false; firewall.checkReversePath = false; firewall = { enable = true; allowedUDPPorts = [ 4380 27036 14242 34197 51820 ]; # 34197: factorio; 4380 27036 14242: barotrauma; 51820: wireguard allowedTCPPortRanges = [ {from = 27015; to = 27030;} # barotrauma {from = 27036; to = 27037;} # barotrauma ]; allowedUDPPortRanges = [ {from = 27000; to = 27031;} # barotrauma {from = 58962; to = 58964;} # barotrauma ]; }; }; virtualisation.virtualbox = { host = { enable = true; enableExtensionPack = true; }; guest = { enable = true; }; }; stylix.image = ../../wallpaper/lenovowp.png; <> hardware = { opengl = { enable = true; driSupport = true; driSupport32Bit = true; extraPackages = with pkgs; [ vulkan-loader vulkan-validation-layers vulkan-extension-layer ]; }; bluetooth.enable = true; }; programs.steam = { enable = true; extraCompatPackages = [ pkgs.proton-ge-bin ]; }; # Configure keymap in X11 (only used for login) services.thinkfan = { enable = false; }; services.power-profiles-daemon.enable = true; users.users.swarsel = { isNormalUser = true; description = "Leon S"; extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" "vboxusers" "scanner" ]; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ # gog games installing heroic # minecraft temurin-bin-17 (prismlauncher.override { glfw = pkgs.glfw-wayland-minecraft; }) ]; system.stateVersion = "23.05"; } #+end_src **** Home Manager #+begin_src nix :noweb yes :tangle profiles/fourside/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "swarsel"; homeDirectory = "/home/swarsel"; stateVersion = "23.05"; # TEMPLATE -- Please read the comment before changing. keyboard.layout = "us"; # TEMPLATE packages = with pkgs; [ ]; }; sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; # waybar config - TEMPLATE - update for cores and temp programs.waybar.settings.mainBar = { cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}"; # temperature.hwmon-path = "/sys/devices/pci0000:00/0000:00:18.3/hwmon/hwmon4/temp1_input"; temperature.hwmon-path.abs = "/sys/devices/platform/thinkpad_hwmon/hwmon/"; temperature.input-filename = "temp1_input"; }; <> wayland.windowManager.sway= { config = rec { # update for actual inputs here, input = { "36125:53060:splitkb.com_Kyria_rev3" = { xkb_layout = "us"; xkb_variant = "altgr-intl"; }; "1:1:AT_Translated_Set_2_keyboard" = { # TEMPLATE xkb_layout = "us"; xkb_options = "grp:win_space_toggle"; xkb_variant = "altgr-intl"; }; "type:touchpad" = { dwt = "enabled"; tap = "enabled"; natural_scroll = "enabled"; middle_emulation = "enabled"; }; }; output = { DP-1 = { mode = "2560x1440"; # TEMPLATE scale = "1"; #bg = "~/.dotfiles/wallpaper/lenovowp.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkelement.sh\""; "XF86MonBrightnessUp" = "exec brightnessctl set +5%"; "XF86MonBrightnessDown"= "exec brightnessctl set 5%-"; "XF86Display" = "exec wl-mirror eDP-1"; # these are left open to use # "XF86WLAN" = "exec wl-mirror eDP-1"; # "XF86Messenger" = "exec wl-mirror eDP-1"; # "XF86Go" = "exec wl-mirror eDP-1"; # "XF86Favorites" = "exec wl-mirror eDP-1"; # "XF86HomePage" = "exec wtype -P Escape -p Escape"; # "XF86AudioLowerVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink -5%"; # "XF86AudioRaiseVolume" = "pactl set-sink-volume alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink +5% "; "XF86AudioMute" = "pactl set-sink-mute alsa_output.pci-0000_08_00.6.HiFi__hw_Generic_1__sink toggle"; }; startup = [ <> ]; }; }; } #+end_src *** Stand My home PC, the most powerful machine. Sadly Sway cannot make good use out of it's NVIDIA card, so it runs a dual boot setup with a kind of broken GRUB that does not autodetect the windows partition. **** NixOS #+begin_src nix :noweb yes :tangle profiles/stand/nixos.nix { config, lib, pkgs, inputs, ... }: { <> services = { getty.autologinUser = "homelen"; greetd.settings.initial_session.user="homelen"; }; stylix.image = ../../wallpaper/standwp.png; <> # Bootloader. boot.loader.grub = { enable = true; devices = ["nodev" ]; useOSProber = true; }; # boot.kernelPackages = pkgs.linuxPackages_latest; networking = { hostName = "stand"; # Define your hostname. enableIPv6 = false; firewall.enable = false; # networkmanager.enable = true; }; hardware = { bluetooth.enable = true; }; users.users.homelen = { isNormalUser = true; description = "Leon S"; extraGroups = [ "networkmanager" "wheel" "lp" "audio" "video" ]; packages = with pkgs; []; }; environment.systemPackages = with pkgs; [ ]; system.stateVersion = "23.05"; # Did you read the comment? Dont change this basically } #+end_src **** Home Manager #+begin_src nix :noweb yes :tangle profiles/stand/home.nix { config, pkgs, lib, fetchFromGitHub, ... }: { <> home = { username = "homelen"; homeDirectory = "/home/homelen"; stateVersion = "23.05"; # Please read the comment before changing. keyboard.layout = "us"; packages = with pkgs; [ ]; }; sops.age.sshKeyPaths = [ "${config.home.homeDirectory}/.ssh/sops" ]; services.blueman-applet.enable = true; # waybar config programs.waybar.settings.mainBar = { cpu.format = "{icon0} {icon1} {icon2} {icon3} {icon4} {icon5} {icon6} {icon7}"; temperature.hwmon-path = "/sys/devices/platform/coretemp.0/hwmon/hwmon1/temp3_input"; }; <> wayland.windowManager.sway= { config = rec { input = { "36125:53060:splitkb.com_Kyria_rev3" = { xkb_layout = "us"; xkb_variant = "altgr-intl"; }; }; output = { DP-1 = { mode = "2560x1440"; scale = "1"; bg = "~/.dotfiles/wallpaper/standwp.png fill"; }; }; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+w" = "exec \"bash ~/.dotfiles/scripts/checkschildi.sh\""; }; startup = [ <> ]; }; }; } #+end_src ** Virtual hosts My server setup is built on Proxmox VE; back when I started, I created all kinds of wild Debian/Ubuntu/etc. KVMs and LXCs on there. However, the root disk has suffered a weird failure where it has become unable to be cloned, but it is still functional for now. I am currently rewriting all machines on there to use NixOS instead; this is a ongoing process. In the long run, I am thinking about a transition to kubernetes or using just a server running NixOS and using the built-in container functionality. For now however, I like the network management provided by Proxmox, as I am a bit intimidated by doing that from scratch. *** TEMPLATE **** NixOS #+begin_src nix :tangle profiles/server1/TEMPLATE/nixos.nix { pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age ]; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.hostName = "TEMPLATE"; # Define your hostname. networking.useDHCP = true; networking.enableIPv6 = false; networking.firewall.enable = false; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; # users.users.root.password = "TEMPLATE"; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change } #+end_src *** NGINX **** NixOS #+begin_src nix :tangle profiles/server1/nginx/nixos.nix { config, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age lego nginx ]; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/.dotfiles/secrets/nginx/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.dnstokenfull = {owner="acme";}; sops.templates."certs.secret".content = '' CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull} ''; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.hostName = "nginx"; # Define your hostname. networking.useDHCP = true; networking.enableIPv6 = false; networking.firewall.enable = false; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; # users.users.root.password = "TEMPLATE"; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change security.acme = { acceptTerms = true; preliminarySelfsigned = false; defaults.email = "mrswarsel@gmail.com"; defaults.dnsProvider = "cloudflare"; defaults.environmentFile = "${config.sops.templates."certs.secret".path}"; }; environment.shellAliases = { nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; services.nginx = { enable = true; recommendedProxySettings = true; recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; virtualHosts = { "stash.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "https://192.168.1.5"; extraConfig = '' client_max_body_size 0; ''; }; # "/push/" = { # proxyPass = "http://192.168.2.5:7867"; # }; "/.well-known/carddav" = { return = "301 $scheme://$host/remote.php/dav"; }; "/.well-known/caldav" = { return = "301 $scheme://$host/remote.php/dav"; }; }; }; "matrix2.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "~ ^(/_matrix|/_synapse/client)" = { proxyPass = "http://192.168.1.23:8008"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "sound.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://192.168.1.13:4040"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; proxy_read_timeout 600s; proxy_send_timeout 600s; proxy_buffering off; proxy_request_buffering off; client_max_body_size 0; ''; }; }; }; "scan.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://192.168.1.24:28981"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "screen.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://192.168.1.16:8096"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "matrix.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "~ ^(/_matrix|/_synapse/client)" = { proxyPass = "http://192.168.1.20:8008"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "scroll.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://192.168.1.22:8080"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "blog.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "https://192.168.1.7"; extraConfig = '' client_max_body_size 0; ''; }; }; }; }; }; } #+end_src *** [Manual steps required] Calibre This machine requires manual setup: 1) Set up calibre-web: - Create metadata.db with 664 permissions, make sure parent directory is writeable - Login @ books.swarsel.win using initial creds: - user: admin - pw: admin123 - point to metadata.db file, make sure you can upload - Change pw, create normal user 2) Setup kavita: - Login @ scrolls.swarsel.win - Create admin user - Import Libraries - Create normal user In general, I am not amazed by this setup; Kavita is the reader of choice, calibre-web mostly is there to have a convenient way to fullfill the opinionated folder structure when uploading ebooks (calibre-web does not work on its own since it forces sqlite which does not work nicely with my NFS book store). I hope that in the future Kavita will implement ebook upload, or that calibre-web will ditch the sqlite constraints. **** NixOS #+begin_src nix :tangle profiles/server1/calibre/nixos.nix { config, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age calibre ]; users.groups.lxc_shares = { gid = 10000; members = [ "kavita" "calibre-web" "root" ]; }; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/.dotfiles/secrets/calibre/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.kavita = { owner = "kavita";}; # sops.secrets.smbuser = { }; # sops.secrets.smbpassword = { }; # sops.secrets.smbdomain = { }; # sops.templates."smb.cred".content = '' # user=${config.sops.placeholder.smbuser} # password=${config.sops.placeholder.smbpassword} # domain=${config.sops.placeholder.smbdomain} # ''; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.hostName = "calibre"; # Define your hostname. networking.useDHCP = true; networking.enableIPv6 = false; networking.firewall.enable = false; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; # services.calibre-server = { # enable = true; # user = "calibre-server"; # auth.enable = true; # auth.userDb = "/srv/calibre/users.sqlite"; # libraries = [ # /media/Books/main # /media/Books/diverse # /media/Books/language # /media/Books/science # /media/Books/sport # /media/Books/novels # ]; # }; # services.calibre-web = { # enable = true; # user = "calibre-web"; # group = "calibre-web"; # listen.port = 8083; # listen.ip = "0.0.0.0"; # options = { # enableBookUploading = true; # enableKepubify = true; # enableBookConversion = true; # }; # }; services.kavita = { enable = true; user = "kavita"; port = 8080; tokenKeyFile = config.sops.secrets.kavita.path; }; } #+end_src *** Jellyfin **** NixOS #+begin_src nix :tangle profiles/server1/jellyfin/nixos.nix { config, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age ]; users.groups.lxc_shares = { gid = 10000; members = [ "jellyfin" "root" ]; }; users.users.jellyfin = { extraGroups = [ "video" "render" ]; }; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; # sops.defaultSopsFile = "/.dotfiles/secrets/jellyfin/secrets.yaml"; # sops.validateSopsFiles = false; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.hostName = "jellyfin"; # Define your hostname. networking.useDHCP = true; networking.enableIPv6 = false; networking.firewall.enable = false; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; nixpkgs.config.packageOverrides = pkgs: { vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; }; hardware.opengl = { enable = true; extraPackages = with pkgs; [ intel-media-driver # LIBVA_DRIVER_NAME=iHD vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) vaapiVdpau libvdpau-va-gl ]; }; services.jellyfin = { enable = true; user = "jellyfin"; # openFirewall = true; # this works only for the default ports }; } #+end_src *** [WIP/Incomplete/Untested] Transmission This stuff just does not work, I seem to be unable to create a working VPN Split Tunneling on NixOS. Maybe this is introduced by the wonky Proxmox-NixOS container interaction, I am not sure. For now, this machine does not work at all and I am stuck with my Debian Container that does this for me ... **** NixOS #+begin_src nix :tangle profiles/server1/transmission/nixos.nix { config, pkgs, modulesPath, ... }: { imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix # ./openvpn.nix #this file holds the vpn login data ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age openvpn jq iptables busybox wireguard-tools ]; users.groups.lxc_shares = { gid = 10000; members = [ "vpn" "radarr" "sonarr" "lidarr" "readarr" "root" ]; }; users.groups.vpn = {}; users.users.vpn = { isNormalUser = true; group = "vpn"; home = "/home/vpn"; }; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/.dotfiles/secrets/transmission/secrets.yaml"; sops.validateSopsFiles = false; boot.kernelModules = [ "tun" ]; proxmoxLXC.manageNetwork = true; # manage network myself proxmoxLXC.manageHostName = false; # manage hostname myself networking.hostName = "transmission"; # Define your hostname. networking.useDHCP = true; networking.enableIPv6 = false; networking.firewall.enable = false; services.radarr = { enable = true; }; services.readarr = { enable = true; }; services.sonarr = { enable = true; }; services.lidarr = { enable = true; }; services.prowlarr = { enable = true; }; # networking.interfaces = { # lo = { # useDHCP = false; # ipv4.addresses = [ # { address = "127.0.0.1"; prefixLength = 8; } # ]; # }; # # eth0 = { # useDHCP = true; # }; # }; # networking.firewall.extraCommands = '' # sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP # ''; networking.iproute2 = { enable = true; rttablesExtraConfig = '' 200 vpn ''; }; # boot.kernel.sysctl = { # "net.ipv4.conf.all.rp_filter" = 2; # "net.ipv4.conf.default.rp_filter" = 2; # "net.ipv4.conf.eth0.rp_filter" = 2; # }; environment.etc = { "openvpn/iptables.sh" = { source = ../../../scripts/server1/iptables.sh; mode = "0755"; }; "openvpn/update-resolv-conf" = { source = ../../../scripts/server1/update-resolv-conf; mode = "0755"; }; "openvpn/routing.sh" = { source = ../../../scripts/server1/routing.sh; mode = "0755"; }; "openvpn/ca.rsa.2048.crt" = { source = ../../../secrets/certs/ca.rsa.2048.crt; mode = "0644"; }; "openvpn/crl.rsa.2048.pem" = { source = ../../../secrets/certs/crl.rsa.2048.pem; mode = "0644"; }; }; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; listenAddresses = [{ port = 22; addr = "0.0.0.0"; }]; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change # users.users.root.password = "TEMPLATE"; environment.shellAliases = { nswitch = "cd /.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; sops.secrets.vpnuser = {}; sops.secrets.rpcuser = {owner="vpn";}; sops.secrets.vpnpass = {}; sops.secrets.rpcpass = {owner="vpn";}; sops.secrets.vpnprot = {}; sops.secrets.vpnloc = {}; # sops.secrets.crlpem = {}; # sops.secrets.capem = {}; sops.templates."transmission-rpc".owner = "vpn"; sops.templates."transmission-rpc".content = builtins.toJSON { rpc-username = config.sops.placeholder.rpcuser; rpc-password = config.sops.placeholder.rpcpass; }; sops.templates.pia.content = '' ${config.sops.placeholder.vpnuser} ${config.sops.placeholder.vpnpass} ''; sops.templates.vpn.content = '' client dev tun proto ${config.sops.placeholder.vpnprot} remote ${config.sops.placeholder.vpnloc} resolv-retry infinite nobind persist-key persist-tun cipher aes-128-cbc auth sha1 tls-client remote-cert-tls server auth-user-pass ${config.sops.templates.pia.path} compress verb 1 reneg-sec 0 crl-verify /etc/openvpn/crl.rsa.2048.pem ca /etc/openvpn/ca.rsa.2048.crt disable-occ dhcp-option DNS 209.222.18.222 dhcp-option DNS 209.222.18.218 dhcp-option DNS 8.8.8.8 route-noexec ''; # services.pia.enable = true; # services.pia.authUserPass.username = "na"; # services.pia.authUserPass.password = "na"; # systemd.services.openvpn-vpn = { # wantedBy = [ "multi-user.target" ]; # after = [ "network.target" ]; # description = "OpenVPN connection to pia"; # serviceConfig = { # Type = "forking"; # RuntimeDirectory="openvpn"; # PrivateTmp=true; # KillMode="mixed"; # ExecStart = ''@${pkgs.openvpn}/sbin/openvpn openvpn --daemon ovpn-pia --status /run/openvpn/pia.status 10 --cd /etc/openvpn --script-security 2 --config ${config.sops.templates.vpn.path} --writepid /run/openvpn/pia.pid''; # PIDFile=''/run/openvpn/pia.pid''; # ExecReload=''/run/current-system/sw/bin/kill -HUP $MAINPID''; # WorkingDirectory="/etc/openvpn"; # Restart="on-failure"; # RestartSec=30; # ProtectSystem="yes"; # DeviceAllow=["/dev/null rw" "/dev/net/tun rw"]; # }; # }; services.openvpn.servers = { pia = { autoStart = false; updateResolvConf = true; # up = '' # export INTERFACE="tun0" # export VPNUSER="vpn" # export LOCALIP="192.168.1.191" # export NETIF="eth0" # export VPNIF="tun0" # export GATEWAYIP=$(ifconfig $VPNIF | egrep -o '([0-9]{1,3}\.){3}[0-9]{1,3}' | egrep -v '255|(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})' | tail -n1) # iptables -F -t nat # iptables -F -t mangle # iptables -F -t filter # iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark # iptables -t mangle -A OUTPUT ! --dest $LOCALIP -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1 # iptables -t mangle -A OUTPUT --dest $LOCALIP -p udp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1 # iptables -t mangle -A OUTPUT --dest $LOCALIP -p tcp --dport 53 -m owner --uid-owner $VPNUSER -j MARK --set-mark 0x1 # iptables -t mangle -A OUTPUT ! --src $LOCALIP -j MARK --set-mark 0x1 # iptables -t mangle -A OUTPUT -j CONNMARK --save-mark # iptables -A INPUT -i $INTERFACE -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # iptables -A INPUT -i $INTERFACE -j REJECT # iptables -A OUTPUT -o lo -m owner --uid-owner $VPNUSER -j ACCEPT # iptables -A OUTPUT -o $INTERFACE -m owner --uid-owner $VPNUSER -j ACCEPT # iptables -t nat -A POSTROUTING -o $INTERFACE -j MASQUERADE # iptables -A OUTPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT # iptables -A OUTPUT ! --src $LOCALIP -o $NETIF -j REJECT # if [[ `ip rule list | grep -c 0x1` == 0 ]]; then # ip rule add from all fwmark 0x1 lookup $VPNUSER # fi # ip route replace default via $GATEWAYIP table $VPNUSER # ip route append default via 127.0.0.1 dev lo table $VPNUSER # ip route flush cache # ''; # down = "bash /etc/openvpn/update-resolv-conf"; # these are outsourced to a local file, I am not sure if it can be done with sops-nix # authUserPass = { # username = "TODO:secrets"; # password = "TODO:secrets"; # }; config = "config ${config.sops.templates.vpn.path}"; }; }; services.transmission = { enable = true; credentialsFile = config.sops.templates."transmission-rpc".path; user = "vpn"; group = "lxc_shares"; settings = { alt-speed-down= 8000; alt-speed-enabled= false; alt-speed-time-begin= 0; alt-speed-time-day= 127; alt-speed-time-enabled= true; alt-speed-time-end= 360; alt-speed-up= 2000; bind-address-ipv4= "0.0.0.0"; bind-address-ipv6= "::"; blocklist-enabled= false; blocklist-url= "http://www.example.com/blocklist"; cache-size-mb= 4; dht-enabled= false; download-dir= "/media/Eternor/New"; download-limit= 100; download-limit-enabled= 0; download-queue-enabled= true; download-queue-size= 5; encryption= 2; idle-seeding-limit= 30; idle-seeding-limit-enabled= false; incomplete-dir= "/var/lib/transmission-daemon/Downloads"; incomplete-dir-enabled= false; lpd-enabled= false; max-peers-global= 200; message-level= 1; peer-congestion-algorithm= ""; peer-id-ttl-hours= 6; peer-limit-global= 100; peer-limit-per-torrent= 40; peer-port= 22371; peer-port-random-high= 65535; peer-port-random-low= 49152; peer-port-random-on-start= false; peer-socket-tos= "default"; pex-enabled= false; port-forwarding-enabled= false; preallocation= 1; prefetch-enabled= true; queue-stalled-enabled= true; queue-stalled-minutes= 30; ratio-limit= 2; ratio-limit-enabled= false; rename-partial-files= true; rpc-authentication-required= true; rpc-bind-address= "0.0.0.0"; rpc-enabled= true; rpc-host-whitelist= ""; rpc-host-whitelist-enabled= true; rpc-port= 9091; rpc-url= "/transmission/"; rpc-whitelist= "127.0.0.1,192.168.3.2"; rpc-whitelist-enabled= true; scrape-paused-torrents-enabled= true; script-torrent-done-enabled= false; seed-queue-enabled= false; seed-queue-size= 10; speed-limit-down= 6000; speed-limit-down-enabled= true; speed-limit-up= 500; speed-limit-up-enabled= true; start-added-torrents= true; trash-original-torrent-files= false; umask= 2; upload-limit= 100; upload-limit-enabled= 0; upload-slots-per-torrent= 14; utp-enabled= false; }; }; # services.nginx = { # enable = true; # virtualHosts = { # "192.168.1.192" = { # locations = { # "/transmission" = { # proxyPass = "http://127.0.0.1:9091"; # extraConfig = '' # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # ''; # }; # }; # }; # }; # }; } #+end_src *** [Manual steps needed] Matrix 1) After the initial setup, run the - /run/secrets-generated/matrix_user_register.sh command to register a new admin user. 2) All bridges will fail on first start, copy the registration files using: - cp /var/lib/mautrix-telegram/telegram-registration.yaml /var/lib/matrix-synapse/ - chown matrix-synapse:matrix-synapse var/lib/matrix-synapse/telegram-registration.yaml Make sure to also do this for doublepuppet.yaml 3) Restart postgresql.service, matrix-synapse.service, mautrix-whatsapp.service, mautrix-telegram.service **** NixOS #+begin_src nix :noweb yes :tangle profiles/server1/matrix/nixos.nix { config, pkgs, modulesPath, unstable, sops, ... }: let matrixDomain = "matrix2.swarsel.win"; in { <> imports = [ (modulesPath + "/virtualisation/proxmox-lxc.nix") ./hardware-configuration.nix # we import here a service that is not available yet on normal nixpkgs # this module is hence not in the modules list, we add it ourselves (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") ]; networking.hostName = "matrix"; # Define your hostname. networking.firewall.enable = false; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age matrix-synapse lottieconverter ffmpeg ]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/.dotfiles/secrets/matrix/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.matrixsharedsecret = {owner="matrix-synapse";}; sops.templates."matrix_user_register.sh".content = '' register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 ''; sops.templates.matrixshared.owner = "matrix-synapse"; sops.templates.matrixshared.content = '' registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} ''; sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";}; sops.templates.mautrixtelegram.owner = "matrix-synapse"; sops.templates.mautrixtelegram.content = '' MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id} MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash} ''; # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";}; # sops.templates.mautrixwhatsapp.owner = "matrix-synapse"; # sops.templates.mautrixwhatsapp.content = '' # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared} # ''; services.postgresql.enable = true; services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram'; CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal'; CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; ''; services.matrix-synapse = { settings.app_service_config_files = [ "/var/lib/matrix-synapse/telegram-registration.yaml" "/var/lib/matrix-synapse/whatsapp-registration.yaml" "/var/lib/matrix-synapse/signal-registration.yaml" "/var/lib/matrix-synapse/doublepuppet.yaml" ]; enable = true; settings.server_name = matrixDomain; settings.public_baseurl = "https://${matrixDomain}"; extraConfigFiles = [ config.sops.templates.matrixshared.path ]; settings.listeners = [ { port = 8008; bind_addresses = [ "0.0.0.0" ]; type = "http"; tls = false; x_forwarded = true; resources = [ { names = [ "client" "federation" ]; compress = true; } ]; } ]; }; services.mautrix-telegram = { enable = true; environmentFile = config.sops.templates.mautrixtelegram.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29317"; hostname = "0.0.0.0"; port = "29317"; provisioning.enabled = true; id = "telegram"; # ephemeral_events = true; # not needed due to double puppeting public = { enabled = false; }; database = "postgresql:///mautrix-telegram?host=/run/postgresql"; }; bridge = { # login_shared_secret_map = { # matrixDomain = "as_token:doublepuppet"; # }; relaybot.authless_portals = true; allow_avatar_remove = true; allow_contact_info = true; sync_channel_members = true; startup_sync = true; sync_create_limit = 0; sync_direct_chats = true; telegram_link_preview = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; # Animated stickers conversion requires additional packages in the # service's path. # If this isn't a fresh installation, clearing the bridge's uploaded # file cache might be necessary (make a database backup first!): # delete from telegram_file where \ # mime_type in ('application/gzip', 'application/octet-stream') animated_sticker = { target = "gif"; args = { width = 256; height = 256; fps = 30; # only for webm background = "020202"; # only for gif, transparency not supported }; }; }; }; }; systemd.services.mautrix-telegram.path = with pkgs; [ lottieconverter # for animated stickers conversion, unfree package ffmpeg # if converting animated stickers to webm (very slow!) ]; services.mautrix-whatsapp = { enable = true; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29318"; hostname = "0.0.0.0"; port = 29318; database = { type = "postgres"; uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .FullName .PushName .JID}} (WA)"; history_sync = { backfill = true; max_initial_conversations = -1; message_count = -1; request_full_sync = true; full_sync_config = { days_limit = 900; size_mb_limit = 5000; storage_quota_mb = 5000; }; }; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; sync_manual_marked_unread = true; send_presence_on_typing = true; parallel_member_sync = true; url_previews = true; caption_in_message = true; extev_polls = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; services.mautrix-signal = { enable = true; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29328"; hostname = "0.0.0.0"; port = 29328; database = { type = "postgres"; uri = "postgresql:///mautrix-signal?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)"; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; caption_in_message = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; # restart the bridges daily. this is done for the signal bridge mainly which stops carrying # messages out after a while. systemd.timers."restart-bridges" = { wantedBy = [ "timers.target" ]; timerConfig = { OnBootSec = "1d"; OnUnitActiveSec = "1d"; Unit = "restart-bridges.service"; }; }; systemd.services."restart-bridges" = { script = '' systemctl restart mautrix-whatsapp.service systemctl restart mautrix-signal.service systemctl restart mautrix-telegram.service ''; serviceConfig = { Type = "oneshot"; User = "root"; }; }; } #+end_src *** Sound **** NixOS #+begin_src nix :noweb yes :tangle profiles/server1/sound/nixos.nix { config, pkgs, modulesPath, ... }: { <> proxmoxLXC.privileged = true; # manage hostname myself users.groups.lxc_pshares = { gid = 110000; members = [ "navidrome" "mpd" "root" ]; }; users.groups.navidrome = { gid = 61593; }; users.groups.mpd = {}; users.users.navidrome = { isSystemUser = true; uid = 61593; group = "navidrome"; extraGroups = [ "audio" "utmp" ]; }; users.users.mpd = { isSystemUser = true; group = "mpd"; extraGroups = [ "audio" "utmp" ]; }; sound = { enable = true; }; hardware.enableAllFirmware = true; networking.hostName = "sound"; # Define your hostname. networking.firewall.enable = false; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age pciutils alsa-utils mpv ]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/.dotfiles/secrets/sound/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.mpdpass = { owner = "mpd";}; services.navidrome = { enable = true; settings = { Address = "0.0.0.0"; Port = 4040; MusicFolder = "/media"; EnableSharing = true; EnableTranscodingConfig = true; Scanner.GroupAlbumReleases = true; ScanSchedule = "@every 1d"; # Insert these values locally as sops-nix does not work for them LastFM.ApiKey = TEMPLATE; LastFM.Secret = TEMPLATE; Spotify.ID = TEMPLATE; Spotify.Secret = TEMPLATE; UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png"; UIWelcomeMessage = "~SwarselSound~"; }; }; services.mpd = { enable = true; musicDirectory = "/media"; user = "mpd"; group = "mpd"; network = { port = 3254; listenAddress = "any"; }; credentials = [ { passwordFile = config.sops.secrets.mpdpass.path; permissions = [ "read" "add" "control" "admin" ]; } ]; }; } #+end_src *** Spotifyd **** NixOS #+begin_src nix :noweb yes :tangle profiles/server1/spotifyd/nixos.nix { config, pkgs, modulesPath, ... }: { <> proxmoxLXC.privileged = true; # manage hostname myself users.groups.spotifyd = { gid = 65136; }; users.users.spotifyd = { isSystemUser = true; uid = 65136; group = "spotifyd"; extraGroups = [ "audio" "utmp" ]; }; sound = { enable = true; }; hardware.enableAllFirmware = true; networking.hostName = "spotifyd"; # Define your hostname. networking.firewall.enable = false; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age ]; # sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; # sops.defaultSopsFile = "/.dotfiles/secrets/spotifyd/secrets.yaml"; # sops.validateSopsFiles = false; services.spotifyd = { enable = true; settings = { global = { dbus_type = "session"; use_mpris = false; device = "default:CARD=PCH"; device_name = "SwarselSpot"; mixer = "alsa"; zeroconf_port = 1025; }; }; }; } #+end_src *** Sync **** NixOS #+begin_src nix :tangle profiles/remote/oracle/sync/nixos.nix { config, pkgs, modulesPath, ... }: { imports = [ ./hardware-configuration.nix ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age ]; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/root/.dotfiles/secrets/sync/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.swarsel = { owner = "root";}; sops.secrets.dnstokenfull = {owner="acme";}; sops.templates."certs.secret".content = '' CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull} ''; security.acme = { acceptTerms = true; preliminarySelfsigned = false; defaults.email = "mrswarsel@gmail.com"; defaults.dnsProvider = "cloudflare"; defaults.environmentFile = "${config.sops.templates."certs.secret".path}"; }; services.nginx = { enable = true; recommendedProxySettings = true; recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; virtualHosts = { "synki.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://localhost:27701"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "sync.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://localhost:8384/"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "swagit.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://localhost:3000"; extraConfig = '' client_max_body_size 0; ''; }; }; }; }; }; boot.tmp.cleanOnBoot = true; zramSwap.enable = false; networking.hostName = "sync"; networking.enableIPv6 = false; networking.domain = "subnet03112148.vcn03112148.oraclevcn.com"; networking.firewall.extraCommands = '' iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 27701 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 8384 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 3000 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 22000 -j ACCEPT iptables -I INPUT -m state --state NEW -p udp --dport 22000 -j ACCEPT iptables -I INPUT -m state --state NEW -p udp --dport 21027 -j ACCEPT ''; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; boot.loader.grub.device = "nodev"; services.anki-sync-server = { enable = true; port = 27701; address = "0.0.0.0"; openFirewall = true; users = [ { username = "Swarsel"; passwordFile = config.sops.secrets.swarsel.path; } ]; }; services.syncthing = { enable = true; guiAddress = "0.0.0.0:8384"; openDefaultPorts = true; }; services.forgejo = { enable = true; settings = { DEFAULT = { APP_NAME = "~SwaGit~"; }; server = { PROTOCOL = "http"; HTTP_PORT = 3000; HTTP_ADDR = "0.0.0.0"; DOMAIN = "swagit.swarsel.win"; ROOT_URL = "https://swagit.swarsel.win"; }; service = { DISABLE_REGISTRATION = true; SHOW_REGISTRATION_BUTTON = false; }; }; }; } #+end_src *** Swatrix **** NixOS #+begin_src nix :tangle profiles/remote/oracle/matrix/nixos.nix { config, pkgs, modulesPath, unstable, sops, ... }: let matrixDomain = "swatrix.swarsel.win"; in { imports = [ ./hardware-configuration.nix (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") ]; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age matrix-synapse lottieconverter ffmpeg ]; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/root/.dotfiles/secrets/omatrix/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.dnstokenfull = {owner="acme";}; sops.templates."certs.secret".content = '' CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull} ''; documentation = { enable = false; }; security.acme = { acceptTerms = true; preliminarySelfsigned = false; defaults.email = "mrswarsel@gmail.com"; defaults.dnsProvider = "cloudflare"; defaults.environmentFile = "${config.sops.templates."certs.secret".path}"; }; services.nginx = { enable = true; recommendedProxySettings = true; recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; virtualHosts = { "swatrix.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "~ ^(/_matrix|/_synapse/client)" = { proxyPass = "http://localhost:8008"; extraConfig = '' client_max_body_size 0; ''; }; }; }; }; }; boot.tmp.cleanOnBoot = true; zramSwap.enable = false; networking.hostName = "swatrix"; networking.enableIPv6 = false; # networking.domain = "subnet03112148.vcn03112148.oraclevcn.com"; networking.domain = "swarsel.win"; networking.firewall.extraCommands = '' iptables -I INPUT -m state --state NEW -p tcp --dport 80 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 443 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 8008 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 29317 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 29318 -j ACCEPT iptables -I INPUT -m state --state NEW -p tcp --dport 29328 -j ACCEPT ''; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../../../secrets/keys/authorized_keys ]; system.stateVersion = "23.11"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; boot.loader.grub.device = "nodev"; sops.secrets.matrixsharedsecret = {owner="matrix-synapse";}; sops.templates."matrix_user_register.sh".content = '' register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 ''; sops.templates.matrixshared.owner = "matrix-synapse"; sops.templates.matrixshared.content = '' registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} ''; sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";}; sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";}; sops.templates.mautrixtelegram.owner = "matrix-synapse"; sops.templates.mautrixtelegram.content = '' MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id} MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash} ''; # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";}; # sops.templates.mautrixwhatsapp.owner = "matrix-synapse"; # sops.templates.mautrixwhatsapp.content = '' # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared} # ''; services.postgresql.enable = true; services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram'; CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal'; CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; ''; services.matrix-synapse = { settings.app_service_config_files = [ "/var/lib/matrix-synapse/telegram-registration.yaml" "/var/lib/matrix-synapse/whatsapp-registration.yaml" "/var/lib/matrix-synapse/signal-registration.yaml" "/var/lib/matrix-synapse/doublepuppet.yaml" ]; enable = true; settings.server_name = matrixDomain; settings.public_baseurl = "https://${matrixDomain}"; extraConfigFiles = [ config.sops.templates.matrixshared.path ]; settings.listeners = [ { port = 8008; bind_addresses = [ "0.0.0.0" ]; type = "http"; tls = false; x_forwarded = true; resources = [ { names = [ "client" "federation" ]; compress = true; } ]; } ]; }; services.mautrix-telegram = { enable = true; environmentFile = config.sops.templates.mautrixtelegram.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29317"; hostname = "0.0.0.0"; port = "29317"; provisioning.enabled = true; id = "telegram"; # ephemeral_events = true; # not needed due to double puppeting public = { enabled = false; }; database = "postgresql:///mautrix-telegram?host=/run/postgresql"; }; bridge = { # login_shared_secret_map = { # matrixDomain = "as_token:doublepuppet"; # }; relaybot.authless_portals = true; allow_avatar_remove = true; allow_contact_info = true; sync_channel_members = true; startup_sync = true; sync_create_limit = 0; sync_direct_chats = true; telegram_link_preview = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; # Animated stickers conversion requires additional packages in the # service's path. # If this isn't a fresh installation, clearing the bridge's uploaded # file cache might be necessary (make a database backup first!): # delete from telegram_file where \ # mime_type in ('application/gzip', 'application/octet-stream') animated_sticker = { target = "gif"; args = { width = 256; height = 256; fps = 30; # only for webm background = "020202"; # only for gif, transparency not supported }; }; }; }; }; systemd.services.mautrix-telegram.path = with pkgs; [ lottieconverter # for animated stickers conversion, unfree package ffmpeg # if converting animated stickers to webm (very slow!) ]; services.mautrix-whatsapp = { enable = true; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29318"; hostname = "0.0.0.0"; port = 29318; database = { type = "postgres"; uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .FullName .PushName .JID}} (WA)"; history_sync = { backfill = true; max_initial_conversations = -1; message_count = -1; request_full_sync = true; full_sync_config = { days_limit = 900; size_mb_limit = 5000; storage_quota_mb = 5000; }; }; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; sync_manual_marked_unread = true; send_presence_on_typing = true; parallel_member_sync = true; url_previews = true; caption_in_message = true; extev_polls = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; services.mautrix-signal = { enable = true; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29328"; hostname = "0.0.0.0"; port = 29328; database = { type = "postgres"; uri = "postgresql:///mautrix-signal?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)"; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; caption_in_message = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; # restart the bridges daily. this is done for the signal bridge mainly which stops carrying # messages out after a while. systemd.timers."restart-bridges" = { wantedBy = [ "timers.target" ]; timerConfig = { OnBootSec = "1d"; OnUnitActiveSec = "1d"; Unit = "restart-bridges.service"; }; }; systemd.services."restart-bridges" = { script = '' systemctl restart mautrix-whatsapp.service systemctl restart mautrix-signal.service systemctl restart mautrix-telegram.service ''; serviceConfig = { Type = "oneshot"; User = "root"; }; }; } #+end_src *** Paperless **** NixOS #+begin_src nix :noweb yes :tangle profiles/server1/paperless/nixos.nix { config, pkgs, modulesPath, ... }: { <> users.groups.lxc_shares = { gid = 10000; members = [ "paperless" "root" ]; }; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age ]; networking.hostName = "paperless"; # Define your hostname. networking.firewall.enable = false; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/root/.dotfiles/secrets/paperless/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.admin = { owner = "paperless";}; services.paperless = { enable = true; mediaDir = "/media"; user = "paperless"; port = 28981; passwordFile = config.sops.secrets.admin.path; address = "0.0.0.0"; extraConfig = { PAPERLESS_OCR_LANGUAGE = "deu+eng"; PAPERLESS_URL = "scan.swarsel.win"; PAPERLESS_OCR_USER_ARGS = builtins.toJSON { optimize = 1; pdfa_image_compression = "lossless"; }; }; }; } #+end_src *** Sandbox (Lenovo Y510P) My laptop, sadly soon to be replaced by a new one, since most basic functions are stopping to work lately. **** NixOS #+begin_src nix :noweb yes :tangle profiles/sandbox/nixos.nix { config, pkgs, modulesPath, unstable, sops, ... }: let matrixDomain = "swatrix.swarsel.win"; in { imports = [ ./hardware-configuration.nix # we import here a service that is not available yet on normal nixpkgs # this module is hence not in the modules list, we add it ourselves (unstable + "/nixos/modules/services/matrix/mautrix-signal.nix") ]; boot.loader.grub = { enable = true; device = "/dev/sda"; useOSProber = true; }; users.users.swarsel = { isNormalUser = true; description = "Leon S"; extraGroups = [ "networkmanager" "wheel" "lp"]; packages = with pkgs; []; }; # actual config starts here fileSystems."/mnt/Eternor" = { device = "//192.168.1.3/Eternor"; fsType = "cifs"; options = let # this line prevents hanging on network split automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"; in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"]; }; environment.systemPackages = with pkgs; [ git gnupg ssh-to-age lego nginx calibre openvpn jq iptables busybox wireguard-tools matrix-synapse lottieconverter ffmpeg pciutils alsa-utils mpv zfs ]; services.xserver = { layout = "us"; xkbVariant = "altgr-intl"; }; nix.settings.experimental-features = ["nix-command" "flakes"]; services.openssh = { enable = true; settings.PermitRootLogin = "yes"; listenAddresses = [{ port = 22; addr = "0.0.0.0"; }]; }; users.users.root.openssh.authorizedKeys.keyFiles = [ ../../secrets/keys/authorized_keys ]; system.stateVersion = "23.05"; # TEMPLATE - but probably no need to change environment.shellAliases = { nswitch = "cd ~/.dotfiles; git pull; nixos-rebuild --flake .#$(hostname) switch; cd -;"; }; boot.supportedFilesystems = [ "zfs" ]; boot.zfs.forceImportRoot = false; networking.hostId = "8a8ad84a"; networking.hostName = "sandbox"; # Define your hostname. networking.enableIPv6 = true; networking.firewall.enable = false; documentation = { enable = false; }; sops.age.sshKeyPaths = [ "/etc/ssh/sops" ]; sops.defaultSopsFile = "/root/.dotfiles/secrets/sandbox/secrets.yaml"; sops.validateSopsFiles = false; sops.secrets.dnstokenfull = {owner="acme";}; sops.templates."certs.secret".content = '' CF_DNS_API_TOKEN=${config.sops.placeholder.dnstokenfull} ''; security.acme = { acceptTerms = true; preliminarySelfsigned = false; defaults.email = "mrswarsel@gmail.com"; defaults.dnsProvider = "cloudflare"; defaults.environmentFile = "${config.sops.templates."certs.secret".path}"; }; services.nginx = { enable = true; recommendedProxySettings = true; recommendedTlsSettings = true; recommendedOptimisation = true; recommendedGzipSettings = true; virtualHosts = { "stash.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "https://192.168.1.5"; extraConfig = '' client_max_body_size 0; ''; }; # "/push/" = { # proxyPass = "http://192.168.2.5:7867"; # }; "/.well-known/carddav" = { return = "301 $scheme://$host/remote.php/dav"; }; "/.well-known/caldav" = { return = "301 $scheme://$host/remote.php/dav"; }; }; }; "swatrix.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "~ ^(/_matrix|/_synapse/client)" = { proxyPass = "http://127.0.0.1:8008"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "sound.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://127.0.0.1:4040"; proxyWebsockets = true; extraConfig = '' proxy_redirect http:// https://; proxy_read_timeout 600s; proxy_send_timeout 600s; proxy_buffering off; proxy_request_buffering off; client_max_body_size 0; ''; }; }; }; "scan.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://127.0.0.1:28981"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "screen.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://127.0.0.1:8096"; extraConfig = '' client_max_body_size 0; ''; }; }; }; "scroll.swarsel.win" = { enableACME = true; forceSSL = true; acmeRoot = null; locations = { "/" = { proxyPass = "http://127.0.0.1:8080"; extraConfig = '' client_max_body_size 0; ''; }; }; }; }; }; sops.secrets.kavita = { owner = "kavita";}; services.kavita = { enable = true; user = "kavita"; port = 8080; tokenKeyFile = config.sops.secrets.kavita.path; }; users.users.jellyfin = { extraGroups = [ "video" "render" ]; }; # nixpkgs.config.packageOverrides = pkgs: { # vaapiIntel = pkgs.vaapiIntel.override { enableHybridCodec = true; }; # }; hardware.opengl = { enable = true; extraPackages = with pkgs; [ intel-media-driver # LIBVA_DRIVER_NAME=iHD vaapiIntel # LIBVA_DRIVER_NAME=i965 (older but works better for Firefox/Chromium) vaapiVdpau libvdpau-va-gl ]; }; services.jellyfin = { enable = true; user = "jellyfin"; # openFirewall = true; # this works only for the default ports }; users.groups.vpn = {}; users.users.vpn = { isNormalUser = true; group = "vpn"; home = "/home/vpn"; }; boot.kernelModules = [ "tun" ]; services.radarr = { enable = true; }; services.readarr = { enable = true; }; services.sonarr = { enable = true; }; services.lidarr = { enable = true; }; services.prowlarr = { enable = true; }; networking.firewall.extraCommands = '' sudo iptables -A OUTPUT ! -o lo -m owner --uid-owner vpn -j DROP ''; networking.iproute2 = { enable = true; rttablesExtraConfig = '' 200 vpn ''; }; boot.kernel.sysctl = { "net.ipv4.conf.all.rp_filter" = 2; "net.ipv4.conf.default.rp_filter" = 2; "net.ipv4.conf.enp7s0.rp_filter" = 2; }; environment.etc = { "openvpn/iptables.sh" = { source = ../../scripts/server1/iptables.sh; mode = "0755"; }; "openvpn/update-resolv-conf" = { source = ../../scripts/server1/update-resolv-conf; mode = "0755"; }; "openvpn/routing.sh" = { source = ../../scripts/server1/routing.sh; mode = "0755"; }; "openvpn/ca.rsa.2048.crt" = { source = ../../secrets/certs/ca.rsa.2048.crt; mode = "0644"; }; "openvpn/crl.rsa.2048.pem" = { source = ../../secrets/certs/crl.rsa.2048.pem; mode = "0644"; }; }; sops.secrets.vpnuser = {}; sops.secrets.rpcuser = {owner="vpn";}; sops.secrets.vpnpass = {}; sops.secrets.rpcpass = {owner="vpn";}; sops.secrets.vpnprot = {}; sops.secrets.vpnloc = {}; # sops.secrets.crlpem = {}; # sops.secrets.capem = {}; sops.templates."transmission-rpc".owner = "vpn"; sops.templates."transmission-rpc".content = builtins.toJSON { rpc-username = config.sops.placeholder.rpcuser; rpc-password = config.sops.placeholder.rpcpass; }; sops.templates.pia.content = '' ${config.sops.placeholder.vpnuser} ${config.sops.placeholder.vpnpass} ''; sops.templates.vpn.content = '' client dev tun proto ${config.sops.placeholder.vpnprot} remote ${config.sops.placeholder.vpnloc} resolv-retry infinite nobind persist-key persist-tun cipher aes-128-cbc auth sha1 tls-client remote-cert-tls server auth-user-pass ${config.sops.templates.pia.path} compress verb 1 reneg-sec 0 crl-verify /etc/openvpn/crl.rsa.2048.pem ca /etc/openvpn/ca.rsa.2048.crt disable-occ ''; services.openvpn.servers = { pia = { autoStart = true; updateResolvConf = false; config = "config ${config.sops.templates.vpn.path}"; }; }; services.transmission = { enable = true; credentialsFile = config.sops.templates."transmission-rpc".path; user = "vpn"; settings = { alt-speed-down= 8000; alt-speed-enabled= false; alt-speed-time-begin= 0; alt-speed-time-day= 127; alt-speed-time-enabled= true; alt-speed-time-end= 360; alt-speed-up= 2000; bind-address-ipv4= "0.0.0.0"; bind-address-ipv6= "::"; blocklist-enabled= false; blocklist-url= "http://www.example.com/blocklist"; cache-size-mb= 256; dht-enabled= false; download-dir= "/test"; download-limit= 100; download-limit-enabled= 0; download-queue-enabled= true; download-queue-size= 5; encryption= 2; idle-seeding-limit= 30; idle-seeding-limit-enabled= false; incomplete-dir= "/var/lib/transmission-daemon/Downloads"; incomplete-dir-enabled= false; lpd-enabled= false; max-peers-global= 200; message-level= 1; peer-congestion-algorithm= ""; peer-id-ttl-hours= 6; peer-limit-global= 100; peer-limit-per-torrent= 40; peer-port= 22371; peer-port-random-high= 65535; peer-port-random-low= 49152; peer-port-random-on-start= false; peer-socket-tos= "default"; pex-enabled= false; port-forwarding-enabled= false; preallocation= 1; prefetch-enabled= true; queue-stalled-enabled= true; queue-stalled-minutes= 30; ratio-limit= 2; ratio-limit-enabled= false; rename-partial-files= true; rpc-authentication-required= true; rpc-bind-address= "0.0.0.0"; rpc-enabled= true; rpc-host-whitelist= ""; rpc-host-whitelist-enabled= true; rpc-port= 9091; rpc-url= "/transmission/"; rpc-whitelist= "127.0.0.1,192.168.3.2"; rpc-whitelist-enabled= true; scrape-paused-torrents-enabled= true; script-torrent-done-enabled= false; seed-queue-enabled= false; seed-queue-size= 10; speed-limit-down= 6000; speed-limit-down-enabled= true; speed-limit-up= 500; speed-limit-up-enabled= true; start-added-torrents= true; trash-original-torrent-files= false; umask= 2; upload-limit= 100; upload-limit-enabled= 0; upload-slots-per-torrent= 14; utp-enabled= false; }; }; # services.nginx = { # enable = true; # virtualHosts = { # "192.168.1.192" = { # locations = { # "/transmission" = { # proxyPass = "http://127.0.0.1:9091"; # extraConfig = '' # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # ''; # }; # }; # }; # }; # }; # sops.secrets.matrixsharedsecret = {owner="matrix-synapse";}; # sops.templates."matrix_user_register.sh".content = '' # register_new_matrix_user -k ${config.sops.placeholder.matrixsharedsecret} http://localhost:8008 # ''; # sops.templates.matrixshared.owner = "matrix-synapse"; # sops.templates.matrixshared.content = '' # registration_shared_secret: ${config.sops.placeholder.matrixsharedsecret} # ''; # sops.secrets.mautrixtelegram_as = {owner="matrix-synapse";}; # sops.secrets.mautrixtelegram_hs = {owner="matrix-synapse";}; # sops.secrets.mautrixtelegram_api_id = {owner="matrix-synapse";}; # sops.secrets.mautrixtelegram_api_hash = {owner="matrix-synapse";}; # sops.templates.mautrixtelegram.owner = "matrix-synapse"; # sops.templates.mautrixtelegram.content = '' # MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN=${config.sops.placeholder.mautrixtelegram_as} # MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN=${config.sops.placeholder.mautrixtelegram_hs} # MAUTRIX_TELEGRAM_TELEGRAM_API_ID=${config.sops.placeholder.mautrixtelegram_api_id} # MAUTRIX_TELEGRAM_TELEGRAM_API_HASH=${config.sops.placeholder.mautrixtelegram_api_hash} # ''; # ---------------- # sops.secrets.mautrixwhatsapp_shared = {owner="matrix-synapse";}; # sops.templates.mautrixwhatsapp.owner = "matrix-synapse"; # sops.templates.mautrixwhatsapp.content = '' # MAUTRIX_WHATSAPP_BRIDGE_LOGIN_SHARED_SECRET=${config.sops.placeholder.mautrixwhatsapp_shared} # ''; services.postgresql.enable = true; services.postgresql.initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-telegram" WITH LOGIN PASSWORD 'telegram'; CREATE DATABASE "mautrix-telegram" WITH OWNER "mautrix-telegram" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-whatsapp" WITH LOGIN PASSWORD 'whatsapp'; CREATE DATABASE "mautrix-whatsapp" WITH OWNER "mautrix-whatsapp" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; CREATE ROLE "mautrix-signal" WITH LOGIN PASSWORD 'signal'; CREATE DATABASE "mautrix-signal" WITH OWNER "mautrix-signal" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; ''; services.matrix-synapse = { settings.app_service_config_files = [ "/var/lib/matrix-synapse/telegram-registration.yaml" "/var/lib/matrix-synapse/whatsapp-registration.yaml" "/var/lib/matrix-synapse/signal-registration.yaml" "/var/lib/matrix-synapse/doublepuppet.yaml" ]; enable = false; settings.server_name = matrixDomain; settings.public_baseurl = "https://${matrixDomain}"; extraConfigFiles = [ config.sops.templates.matrixshared.path ]; settings.listeners = [ { port = 8008; bind_addresses = [ "0.0.0.0" ]; type = "http"; tls = false; x_forwarded = true; resources = [ { names = [ "client" "federation" ]; compress = true; } ]; } ]; }; services.mautrix-telegram = { enable = false; environmentFile = config.sops.templates.mautrixtelegram.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29317"; hostname = "0.0.0.0"; port = "29317"; provisioning.enabled = true; id = "telegram"; # ephemeral_events = true; # not needed due to double puppeting public = { enabled = false; }; database = "postgresql:///mautrix-telegram?host=/run/postgresql"; }; bridge = { # login_shared_secret_map = { # matrixDomain = "as_token:doublepuppet"; # }; relaybot.authless_portals = true; allow_avatar_remove = true; allow_contact_info = true; sync_channel_members = true; startup_sync = true; sync_create_limit = 0; sync_direct_chats = true; telegram_link_preview = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; # Animated stickers conversion requires additional packages in the # service's path. # If this isn't a fresh installation, clearing the bridge's uploaded # file cache might be necessary (make a database backup first!): # delete from telegram_file where \ # mime_type in ('application/gzip', 'application/octet-stream') animated_sticker = { target = "gif"; args = { width = 256; height = 256; fps = 30; # only for webm background = "020202"; # only for gif, transparency not supported }; }; }; }; }; # systemd.services.mautrix-telegram.path = with pkgs; [ # lottieconverter # for animated stickers conversion, unfree package # ffmpeg # if converting animated stickers to webm (very slow!) # ]; services.mautrix-whatsapp = { enable = false; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29318"; hostname = "0.0.0.0"; port = 29318; database = { type = "postgres"; uri = "postgresql:///mautrix-whatsapp?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .FullName .PushName .JID}} (WA)"; history_sync = { backfill = true; max_initial_conversations = -1; message_count = -1; request_full_sync = true; full_sync_config = { days_limit = 900; size_mb_limit = 5000; storage_quota_mb = 5000; }; }; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; sync_manual_marked_unread = true; send_presence_on_typing = true; parallel_member_sync = true; url_previews = true; caption_in_message = true; extev_polls = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; services.mautrix-signal = { enable = false; # environmentFile = config.sops.templates.mautrixwhatsapp.path; settings = { homeserver = { address = "http://localhost:8008"; domain = matrixDomain; }; appservice = { address= "http://localhost:29328"; hostname = "0.0.0.0"; port = 29328; database = { type = "postgres"; uri = "postgresql:///mautrix-signal?host=/run/postgresql"; }; }; bridge = { displayname_template = "{{or .ContactName .ProfileName .PhoneNumber}} (Signal)"; login_shared_secret_map = { matrixDomain = "as_token:doublepuppet"; }; caption_in_message = true; permissions = { "*" = "relaybot"; "@swarsel:${matrixDomain}" = "admin"; }; }; }; }; # restart the bridges daily. this is done for the signal bridge mainly which stops carrying # messages out after a while. systemd.timers."restart-bridges" = { wantedBy = [ "timers.target" ]; timerConfig = { OnBootSec = "1d"; OnUnitActiveSec = "1d"; Unit = "restart-bridges.service"; }; }; systemd.services."restart-bridges" = { script = '' systemctl restart mautrix-whatsapp.service systemctl restart mautrix-signal.service systemctl restart mautrix-telegram.service ''; serviceConfig = { Type = "oneshot"; User = "root"; }; }; users.groups.navidrome = { gid = 61593; }; users.groups.mpd = {}; users.users.navidrome = { isSystemUser = true; uid = 61593; group = "navidrome"; extraGroups = [ "audio" "utmp" ]; }; users.users.mpd = { isSystemUser = true; group = "mpd"; extraGroups = [ "audio" "utmp" ]; }; sound = { enable = true; }; hardware.enableAllFirmware = true; sops.secrets.mpdpass = { owner = "mpd";}; services.navidrome = { enable = true; settings = { Address = "0.0.0.0"; Port = 4040; MusicFolder = "/mnt/"; EnableSharing = true; EnableTranscodingConfig = true; Scanner.GroupAlbumReleases = true; ScanSchedule = "@every 24h"; # Insert these values locally as sops-nix does not work for them # LastFM.ApiKey = TEMPLATE; # LastFM.Secret = TEMPLATE; # Spotify.ID = TEMPLATE; # Spotify.Secret = TEMPLATE; UILoginBackgroundUrl = "https://i.imgur.com/OMLxi7l.png"; UIWelcomeMessage = "~SwarselSound~"; }; }; services.mpd = { enable = true; musicDirectory = "/mnt/Eternor/Musik"; user = "mpd"; group = "mpd"; network = { port = 3254; listenAddress = "any"; }; credentials = [ { passwordFile = config.sops.secrets.mpdpass.path; permissions = [ "read" "add" "control" "admin" ]; } ]; }; users.groups.spotifyd = { gid = 65136; }; users.users.spotifyd = { isSystemUser = true; uid = 65136; group = "spotifyd"; extraGroups = [ "audio" "utmp" ]; }; services.spotifyd = { enable = true; settings = { global = { dbus_type = "session"; use_mpris = false; device = "default:CARD=PCH"; device_name = "SwarselSpot"; mixer = "alsa"; zeroconf_port = 1025; }; }; }; # Network shares # add a user with sudo smbpasswd -a services.samba = { package = pkgs.samba4Full; extraConfig = '' workgroup = WORKGROUP server role = standalone server dns proxy = no pam password change = yes map to guest = bad user create mask = 0664 force create mode = 0664 directory mask = 0775 force directory mode = 0775 follow symlinks = yes ''; # ^^ `samba4Full` is compiled with avahi, ldap, AD etc support compared to the default package, `samba` # Required for samba to register mDNS records for auto discovery # See https://github.com/NixOS/nixpkgs/blob/592047fc9e4f7b74a4dc85d1b9f5243dfe4899e3/pkgs/top-level/all-packages.nix#L27268 enable = true; # openFirewall = true; shares.test = { browseable = "yes"; "read only" = "no"; "guest ok" = "no"; path = "/test2"; writable = "true"; comment = "Eternor"; "valid users" = "@smbtest2"; }; }; services.avahi = { publish.enable = true; publish.userServices = true; # ^^ Needed to allow samba to automatically register mDNS records without the need for an `extraServiceFile` nssmdns = true; # ^^ Not one hundred percent sure if this is needed- if it aint broke, don't fix it enable = true; }; services.samba-wsdd = { # This enables autodiscovery on windows since SMB1 (and thus netbios) support was discontinued enable = true; }; } #+end_src * Common NixOS These are system-level settings specific to NixOS machines. All settings that are required on all machines go here. ** General Section for all settings that are not really deserving of their own section. #+begin_src nix :tangle profiles/common/nixos.nix { config, lib, pkgs, inputs, ... }: { home-manager.useGlobalPkgs = true; home-manager.useUserPackages = true; # login keymap services.xserver = { xkb.layout = "us"; xkb.variant = "altgr-intl"; }; # mount NAS drive # works only at home, but w/e # fileSystems."/mnt/smb" = { # device = "//192.168.1.3/Eternor"; # fsType = "cifs"; # options = let # # this line prevents hanging on network split # automount_opts = "x-systemd.automount,noauto,x-systemd.idle-timeout=60,x-systemd.device-timeout=5s,x-systemd.mount-timeout=5s"; # in ["${automount_opts},credentials=/etc/nixos/smb-secrets,uid=1000,gid=100"]; # }; # # enable flakes - urgent line!! nix.settings.experimental-features = ["nix-command" "flakes"]; environment.sessionVariables.NIXOS_OZONE_WL = "1"; # wordlist for look environment.wordlist.enable = true; # gstreamer plugins for nautilus (used for file metadata) environment.sessionVariables.GST_PLUGIN_SYSTEM_PATH_1_0 = lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (with pkgs.gst_all_1; [ gst-plugins-good gst-plugins-bad gst-plugins-ugly gst-libav ]); # correct time between linux and windows time.hardwareClockInLocalTime = true; # dont style GRUB with stylix stylix.targets.grub.enable = false; # the styling makes grub more ugly # cura fix # xdg.portal = { # enable = true; # extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; # wlr.enable = true; # config = { # common = { # default = [ # "*" # ]; # }; # }; # }; # wayland-related security.polkit.enable = true; hardware.opengl = { enable = true; driSupport = true; driSupport32Bit = true; }; # audio sound.enable = true; # nixpkgs.config.pulseaudio = true; hardware.pulseaudio= { enable = true; package = pkgs.pulseaudioFull; }; hardware.enableAllFirmware = true; hardware.bluetooth.powerOnBoot = true; hardware.bluetooth.settings = { General = { Enable = "Source,Sink,Media,Socket"; }; }; # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. networking.networkmanager.enable = true; time.timeZone = "Europe/Vienna"; i18n.defaultLocale = "en_US.UTF-8"; i18n.extraLocaleSettings = { LC_ADDRESS = "de_AT.UTF-8"; LC_IDENTIFICATION = "de_AT.UTF-8"; LC_MEASUREMENT = "de_AT.UTF-8"; LC_MONETARY = "de_AT.UTF-8"; LC_NAME = "de_AT.UTF-8"; LC_NUMERIC = "de_AT.UTF-8"; LC_PAPER = "de_AT.UTF-8"; LC_TELEPHONE = "de_AT.UTF-8"; LC_TIME = "de_AT.UTF-8"; }; #+end_src ** System Packages Mostly used to install some compilers and lps's that I want to have available when not using a devShell flake. #+begin_src nix :tangle profiles/common/nixos.nix environment.systemPackages = with pkgs; [ # yubikey packages gnupg yubikey-personalization yubikey-personalization-gui yubico-pam # yubioath-flutter # yubikey-manager # yubikey-manager-qt yubico-piv-tool # pinentry # theme related gnome.adwaita-icon-theme # kde-connect xdg-desktop-portal # bluetooth bluez # lsp-related ------------------------------- # nix # latex texlab ghostscript_headless # wireguard wireguard-tools # rust rust-analyzer clippy rustfmt # cpp clang-tools # + cuda cudatoolkit #lsp-bridge / python gcc gdb (python3.withPackages(ps: with ps; [ jupyter ipython pyqt5 epc orjson sexpdata six setuptools paramiko numpy pandas scipy matplotlib requests debugpy flake8 gnureadline python-lsp-server])) # (python3.withPackages(ps: with ps; [ jupyter ipython pyqt5 numpy pandas scipy matplotlib requests debugpy flake8 gnureadline python-lsp-server])) # -------------------------------------------- (stdenv.mkDerivation { name = "oama"; src = pkgs.fetchurl { name = "oama"; url = "https://github.com/pdobsan/oama/releases/download/0.13.1/oama-0.13.1-Linux-x86_64-static.tgz"; sha256 = "sha256-OTdCObVfnMPhgZxVtZqehgUXtKT1iyqozdkPIV+i3Gc="; }; phases = [ "unpackPhase" ]; unpackPhase = '' mkdir -p $out/bin tar xvf $src -C $out/ mv $out/oama-0.13.1-Linux-x86_64-static/oama $out/bin/ ''; }) ]; #+end_src ** Programs (including zsh setup) Some programs profit from being installed through dedicated NixOS settings on system-level; these go here. Notably the zsh setup goes here and cannot be deleted under any circumstances. #+begin_src nix :tangle profiles/common/nixos.nix programs.dconf.enable = true; programs.evince.enable = true; programs.kdeconnect.enable = true; # zsh section, do not delete ------ programs.zsh.enable = true; users.defaultUserShell = pkgs.zsh; environment.shells = with pkgs; [ zsh ]; environment.pathsToLink = [ "/share/zsh" ]; # --------------------------------- #+end_src ** Services Setting up some hardware services as well as keyboard related settings. Here we make sure that we can use the CAPS key as a ESC/CTRL double key, which is a lifesaver. #+begin_src nix :tangle profiles/common/nixos.nix services.blueman.enable = true; # enable scanners over network hardware.sane = { enable = true; extraBackends = [ pkgs.sane-airscan ]; }; # enable discovery and usage of network devices (esp. printers) services.printing.enable = true; services.printing.drivers = [ pkgs.gutenprint pkgs.gutenprintBin ]; services.printing.browsedConf = '' BrowseDNSSDSubTypes _cups,_print BrowseLocalProtocols all BrowseRemoteProtocols all CreateIPPPrinterQueues All BrowseProtocols all ''; services.avahi = { enable = true; nssmdns4 = true; openFirewall = true; }; # nautilus file manager services.gvfs.enable = true; # Make CAPS work as a dual function ESC/CTRL key services.interception-tools = { enable = true; udevmonConfig = let dualFunctionKeysConfig = builtins.toFile "dual-function-keys.yaml" '' TIMING: TAP_MILLISEC: 200 DOUBLE_TAP_MILLISEC: 0 MAPPINGS: - KEY: KEY_CAPSLOCK TAP: KEY_ESC HOLD: KEY_LEFTCTRL ''; in '' - JOB: | ${pkgs.interception-tools}/bin/intercept -g $DEVNODE \ | ${pkgs.interception-tools-plugins.dual-function-keys}/bin/dual-function-keys -c ${dualFunctionKeysConfig} \ | ${pkgs.interception-tools}/bin/uinput -d $DEVNODE DEVICE: EVENTS: EV_KEY: [KEY_CAPSLOCK] ''; }; #+end_src ** Yubikey settings It makes sense to house these settings in their own section, since they are all needed really. Note that the starting of the gpg-agent is done in the sway settings, to also perform this step of the setup for non NixOS-machines at the same time. The exception is the system packages, since that cannot be defined twice in the same file (common.nix). The comment is left in as a remider for that. #+begin_src nix :tangle profiles/common/nixos.nix programs.ssh.startAgent = false; services.pcscd.enable = true; # environment.systemPackages = with pkgs; [ # --- IN SYSTEM PACKAGES SECTION --- # ]; services.udev.packages = with pkgs; [ yubikey-personalization ]; #+end_src ** System Login This section houses the greetd related settings. I do not really want to use a display manager, but it is useful to have setup in some ways - in my case for starting sway on system startup. Notably the default user login setting that is commented out here goes into the *system specific* settings, make sure to update it there #+begin_src nix :tangle profiles/common/nixos.nix services.greetd = { enable = true; settings = { initial_session.command = "sway"; # initial_session.user ="swarsel"; default_session.command = '' ${pkgs.greetd.tuigreet}/bin/tuigreet \ --time \ --asterisks \ --user-menu \ --cmd sway ''; }; }; environment.etc."greetd/environments".text = '' sway ''; #+end_src * Common Home-Manager ** Installed packages Here are defined some packages that I would like to use across all my machines. Most of these should not require further setup. Notably the cura package is severely outdated on nixpkgs, so I just fetch a more recent AppImage and run that instead. Also, I define some useful shell scripts here. #+begin_src nix :tangle profiles/common/home.nix { config, pkgs, lib, fetchFromGitHub , ... }: { home.packages = with pkgs; [ # audio stuff spek # spectrum analyzer losslessaudiochecker ffmpeg_5-full flac mediainfo picard audacity sox # printing cups gnome.simple-scan # dict (aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ])) # utilities util-linux nmap # b2 backup @backblaze restic # "big" programs filebot gimp zoom-us # nomacs libreoffice-qt xournalpp obsidian spotify discord nextcloud-client spotify-player element-desktop-wayland nicotine-plus transmission mktorrent hexchat hugo # kyria qmk qmk-udev-rules # games lutris wine libudev-zero dwarfs fuse-overlayfs # steam # steam-run patchelf gamescope vulkan-tools moonlight-qt # firefox related tridactyl-native # mako related mako libnotify # general utilities unrar samba cifs-utils zbar # qr codes readline autotiling brightnessctl libappindicator-gtk3 sqlite speechd networkmanagerapplet psmisc # kill etc lm_sensors # jq # used for searching the i3 tree in check.sh files # specifically needed for anki # mpv anki-bin # dirvish file previews fd imagemagick poppler ffmpegthumbnailer mediainfo gnutar unzip #nautilus gnome.nautilus xfce.tumbler libgsf # wayland stuff wtype wl-clipboard wl-mirror # screenshotting tools grim slurp # the following packages are used (in some way) by waybar playerctl pavucontrol pamixer # gnome.gnome-clocks # wlogout # jdiskreport syncthingtray # monitor #keychain qalculate-gtk gcr # needed for gnome-secrets to work gnome.seahorse # sops-related sops ssh-to-age # mail related packages mu # latex and related packages (pkgs.texlive.combine { inherit (pkgs.texlive) scheme-full dvisvgm dvipng # for preview and export as html wrapfig amsmath ulem hyperref capt-of; }) # font stuff (nerdfonts.override { fonts = [ "FiraMono" "FiraCode" "NerdFontsSymbolsOnly"]; }) noto-fonts-emoji font-awesome_5 noto-fonts noto-fonts-cjk-sans # cura (let cura5 = appimageTools.wrapType2 rec { name = "cura5"; version = "5.4.0"; src = fetchurl { url = "https://github.com/Ultimaker/Cura/releases/download/${version}/UltiMaker-Cura-${version}-linux-modern.AppImage"; hash = "sha256-QVv7Wkfo082PH6n6rpsB79st2xK2+Np9ivBg/PYZd74="; }; extraPkgs = pkgs: with pkgs; [ ]; }; in writeScriptBin "cura" '' #! ${pkgs.bash}/bin/bash # AppImage version of Cura loses current working directory and treats all paths relateive to $HOME. # So we convert each of the files passed as argument to an absolute path. # This fixes use cases like `cd /path/to/my/files; cura mymodel.stl anothermodel.stl`. args=() for a in "$@"; do if [ -e "$a" ]; then a="$(realpath "$a")" fi args+=("$a") done exec "${cura5}/bin/cura5" "''${args[@]}" '') #E: hides scratchpad depending on state, calls emacsclient for edit and then restores the scratchpad state (pkgs.writeShellScriptBin "e" '' bash ~/.dotfiles/scripts/editor_nowait.sh "$@" '') (pkgs.writeShellScriptBin "timer" '' sleep "$1"; while true; do spd-say "$2"; sleep 0.5; done; '') (pkgs.writeScriptBin "project" '' #! ${pkgs.bash}/bin/bash if [ "$1" == "rust" ]; then cp ~/.dotfiles/templates/rust_flake.nix ./flake.nix cp ~/.dotfiles/templates/toolchain.toml . elif [ "$1" == "cpp" ]; then cp ~/.dotfiles/templates/cpp_flake.nix ./flake.nix elif [ "$1" == "python" ]; then cp ~/.dotfiles/templates/py_flake.nix ./flake.nix elif [ "$1" == "cuda" ]; then cp ~/.dotfiles/templates/cu_flake.nix ./flake.nix elif [ "$1" == "other" ]; then cp ~/.dotfiles/templates/other_flake.nix ./flake.nix elif [ "$1" == "latex" ]; then if [ "$2" == "" ]; then echo "No filename specified, usage: 'project latex '" exit 0 fi cp ~/.dotfiles/templates/tex_standard.tex ./"$2".tex exit 0 else echo "No valid argument given. Valid arguments are rust cpp python, cuda" exit 0 fi echo "use flake" >> .envrc direnv allow '') (pkgs.writeShellApplication { name = "pass-fuzzel"; runtimeInputs = [ pkgs.pass pkgs.fuzzel ]; text = '' shopt -s nullglob globstar typeit=0 if [[ $# -ge 1 && $1 == "--type" ]]; then typeit=1 shift fi export PASSWORD_STORE_DIR=~/.local/share/password-store prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store} password_files=( "$prefix"/**/*.gpg ) password_files=( "''${password_files[@]#"$prefix"/}" ) password_files=( "''${password_files[@]%.gpg}" ) password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@") [[ -n $password ]] || exit if [[ $typeit -eq 0 ]]; then pass show -c "$password" &>/tmp/pass-fuzzel else pass show "$password" | { IFS= read -r pass; printf %s "$pass"; } | wtype - fi notify-send -u critical -a pass -t 1000 "Copied/Typed Password" ''; }) (pkgs.writeShellApplication { name = "pass-fuzzel-otp"; runtimeInputs = [ pkgs.fuzzel (pkgs.pass.withExtensions (exts: [exts.pass-otp]))]; text = '' shopt -s nullglob globstar typeit=0 if [[ $# -ge 1 && $1 == "--type" ]]; then typeit=1 shift fi export PASSWORD_STORE_DIR=~/.local/share/password-store prefix=''${PASSWORD_STORE_DIR-~/.local/share/password-store} password_files=( "$prefix"/otp/**/*.gpg ) password_files=( "''${password_files[@]#"$prefix"/}" ) password_files=( "''${password_files[@]%.gpg}" ) password=$(printf '%s\n' "''${password_files[@]}" | fuzzel --dmenu "$@") [[ -n $password ]] || exit if [[ $typeit -eq 0 ]]; then pass otp -c "$password" &>/tmp/pass-fuzzel else pass otp "$password" | { IFS= read -r pass; printf %s "$pass"; } | wtype - fi notify-send -u critical -a pass -t 1000 "Copied/Typed OTPassword" ''; }) ]; # MIGHT NEED TO ENABLE THIS ON SURFACE!! #+end_src ** sops I use sops-nix to handle secrets that I want to have available on my machines at all times. Procedure to add a new machine: - `ssh-keygen -t ed25519 -C "NAME sops"` in .ssh directory (or wherever) - name e.g. "sops" - cat ~/.ssh/sops.pub | ssh-to-age | wl-copy - add the output to .sops.yaml - cp ~/.ssh/sops.pub ~/.dotfiles/secrets/keys/NAME.pub - update entry for sops.age.sshKeyPaths #+begin_src nix :tangle profiles/common/home.nix sops.defaultSopsFile = "${config.home.homeDirectory}/.dotfiles/secrets/general/secrets.yaml"; sops.validateSopsFiles = false; # sops.age.keyFile = "${config.home.homeDirectory}/.ssh/key.txt"; # This will generate a new key if the key specified above does not exist # sops.age.generateKey = true; # sops.gnupg.home = "/home/swarsel/.dotfiles/secrets/keys"; # since we are using the home-manager implementation, we need to specify the runtime path for each secret sops.secrets.mrswarsel = {path = "/run/user/1000/secrets/mrswarsel";}; sops.secrets.nautilus = {path = "/run/user/1000/secrets/nautilus";}; sops.secrets.leon = {path = "/run/user/1000/secrets/leon";}; sops.secrets.swarselmail = {path = "/run/user/1000/secrets/swarselmail";}; sops.secrets.caldav = {path = "${config.home.homeDirectory}/.emacs.d/.caldav";}; # sops.secrets.leon = { }; # sops.secrets.nautilus = { }; # sops.secrets.mrswarsel = { }; #+end_src ** SSH Machines It is very convenient to have SSH aliases in place for machines that I use. This is mainly used for some server machines and some university clusters. #+begin_src nix :tangle profiles/common/home.nix programs.ssh= { enable = true; extraConfig = "SetEnv TERM=xterm-256color"; matchBlocks = { "nginx" = { hostname = "192.168.1.14"; user = "root"; }; "jellyfin" = { hostname = "192.168.1.16"; user = "root"; }; "pfsense" = { hostname = "192.168.1.1"; user = "root"; }; "proxmox" = { hostname = "192.168.1.2"; user = "root"; }; "transmission" = { hostname = "192.168.1.6"; user = "root"; }; "fetcher" = { hostname = "192.168.1.7"; user = "root"; }; "omv" = { hostname = "192.168.1.3"; user = "root"; }; "webbot" = { hostname = "192.168.1.11"; user = "root"; }; "nextcloud" = { hostname = "192.168.1.5"; user = "root"; }; "sound" = { hostname = "192.168.1.13"; user = "root"; }; "spotify" = { hostname = "192.168.1.17"; user = "root"; }; "wordpress" = { hostname = "192.168.1.9"; user = "root"; }; "turn" = { hostname = "192.168.1.18"; user = "root"; }; "hugo" = { hostname = "192.168.1.19"; user = "root"; }; "matrix" = { hostname = "192.168.1.23"; user = "root"; }; "scroll" = { hostname = "192.168.1.22"; user = "root"; }; "minecraft" = { hostname = "130.61.119.129"; user = "opc"; }; "sync" = { hostname = "193.122.53.173"; user = "root"; #this is a oracle vm server but needs root due to nixos-infect }; "pkv" = { hostname = "46.232.248.161"; user = "root"; }; "nebula" = { hostname = "128.131.171.15"; user = "amp23s56"; compression = true; identityFile = "~/.ssh/id_ed25519"; proxyCommand = "ssh -p 1022 -i ~/.ssh/id_ed25519 -q -W %h:%p %r@venus.par.tuwien.ac.at"; extraOptions = { "TCPKeepAlive" = "yes"; }; }; "efficient" = { hostname = "g0.complang.tuwien.ac.at"; forwardAgent = true; user = "ep01427399"; # leaving the below lines in for future reference # remoteForwards = [ # { # bind.address = "/run/user/21217/gnupg/S.gpg-agent"; # host.address = "/run/user/1000/gnupg/S.gpg-agent.extra"; # } # { # bind.address = "/run/user/21217/gnupg/S.gpg-agent.ssh"; # host.address = "/run/user/1000/gnupg/S.gpg-agent.ssh"; # } # ]; # extraOptions = { # "RemoteForward" = "/run/user/21217/gnupg/S.gpg-agent /run/user/1000/gnupg/S.gpg-agent.extra"; # "StreamLocalBindUnlink" = "yes"; # "RemoteForward" = "/run/user/21217/gnupg/S.gpg-agent.ssh /run/user/1000/gnupg/S.gpg-agent.ssh"; # }; # setEnv = { # "TERM" = "xterm"; # }; }; "hydra" = { hostname = "128.131.171.215"; user = "hpc23w33"; compression = true; forwardAgent = true; # identityFile = "~/.ssh/id_tuwien_hpc"; # proxyCommand = "ssh -p 1022 -i ~/.ssh/id_tuwien_hpc -q -W %h:%p %r@venus.par.tuwien.ac.at"; proxyCommand = "ssh -p 1022 -q -W %h:%p %r@venus.par.tuwien.ac.at"; extraOptions = { "TCPKeepAlive" = "yes"; }; }; }; }; #+end_src ** Fonts + Theme These section allows home-manager to allow theme settings, and handles some other appearance-related settings like cursor styles. Interestingly, system icons (adwaita) still need to be setup on system-level, and will break if defined here. #+begin_src nix :tangle profiles/common/home.nix stylix.targets.emacs.enable = false; # fonts.fontconfig.enable = true; # gtk = { # enable = true; # theme = { # name = "Arc-Dark"; # package = pkgs.arc-theme; # }; # cursorTheme = { # name = "capitaine-cursors"; # package = pkgs.capitaine-cursors; # }; # gtk3.extraConfig = { # Settings = '' # gtk-application-prefer-dark-theme=1 # ''; # }; # gtk4.extraConfig = { # Settings = '' # gtk-application-prefer-dark-theme=1 # ''; # }; # }; #+end_src ** TODO Desktop Entries Some programs lack a dmenu launcher - I define them myself here. TODO: Non-NixOS machines (=sp3) should not use these by default, but instead the programs prefixed with "nixGL". I need to figure out how to automate this process, as it is not feasible to write desktop entries for all programs installed on that machine. #+begin_src nix :tangle profiles/common/home.nix xdg.desktopEntries = { cura = { name = "Ultimaker Cura"; genericName = "Cura"; exec = "cura"; terminal = false; categories = [ "Application"]; }; anki = { name = "Anki Flashcards"; genericName = "Anki"; exec = "anki"; terminal = false; categories = [ "Application"]; }; # schlidichat = { # name = "SchildiChat Matrix Client"; # genericName = "SchildiChat"; # exec = "schildichat-desktop -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; # terminal = false; # categories = [ "Application"]; # }; # currently unused but kept for possible future use-case # not needed as long as schildichat is working properly element = { name = "Element Matrix Client"; genericName = "Element"; exec = "element-desktop -enable-features=UseOzonePlatform -ozone-platform=wayland --disable-gpu-driver-bug-workarounds"; terminal = false; categories = [ "Application"]; }; }; #+end_src ** TODO Sourcing dotfiles and environment variables This section should be used in order to symlink already existing configuration files using `home.file` and setting session variables using `home.sessionVariables`. TODO At the moment this is only used for emacs' init.el and early-init.el - I plan to migrate them to a NUR emacs-init setup at some point in the future, but that is a lot of work and will take possibly more time than I am able to spend on this right now As for the `home.sessionVariables`, it should be noted that environment variables that are needed at system start should NOT be loaded here, but instead in `programs.zsh.config.extraSessionCommands` (in the home-manager programs section). This is also where all the wayland related variables are stored. #+begin_src nix :tangle profiles/common/home.nix home.file = { "init.el" = { source = ../../programs/emacs/init.el; target = ".emacs.d/init.el"; }; "early-init.el" = { source = ../../programs/emacs/early-init.el; target = ".emacs.d/early-init.el"; }; # on NixOS, Emacs does not find the aspell dicts easily. Write the configuration manually ".aspell.conf" = { source = ../../programs/config/.aspell.conf; target = ".aspell.conf"; }; }; home.sessionVariables = { EDITOR = "bash ~/.dotfiles/scripts/editor.sh"; EDITORBAK = "bash ~/.dotfiles/scripts/editor.sh"; # GTK_THEME = "Arc-Dark"; }; #+end_src ** Programs *** General #+begin_src nix :tangle profiles/common/home.nix programs.password-store = { enable = true; package = pkgs.pass.withExtensions (exts: [exts.pass-otp]); }; # zsh Integration is enabled by default for these programs.bottom.enable = true; programs.imv.enable = true; programs.sioyek.enable = true; programs.bat.enable = true; programs.carapace.enable = true; programs.wlogout.enable = true; programs.swayr.enable = true; programs.yt-dlp.enable = true; programs.mpv.enable = true; programs.jq.enable = true; programs.nix-index.enable = true; programs.ripgrep.enable = true; programs.pandoc.enable = true; programs.fzf.enable = true; programs.direnv = { enable = true; nix-direnv.enable = true; }; programs.zoxide.enable = true; programs.eza = { enable = true; icons = true; git = true; extraOptions = [ "-l" "--group-directories-first" ]; }; programs.git = { enable = true; aliases = { a = "add"; c = "commit"; cl = "clone"; co = "checkout"; b = "branch"; i = "init"; m = "merge"; s = "status"; r = "restore"; p = "pull"; pp = "push"; }; signing = { key = "0x76FD3810215AE097"; signByDefault = true; }; userEmail = "leon.schwarzaeugl@gmail.com"; userName = "Swarsel"; }; #+end_src *** Fuzzel #+begin_src nix :tangle profiles/common/home.nix programs.fuzzel = { enable = true; settings = { main = { layer = "overlay"; # font = "Monospace:size=8"; lines = "10"; width = "40"; }; colors = { # background="293744dd"; # text="f8f8f2ff"; # match="8be9fdff"; # selection-match="8be9fdff"; # selection="44475add"; # selection-text="f8f8f2ff"; # border="ffd700ff"; }; border.radius = "0"; }; }; #+end_src *** Starship #+begin_src nix :tangle profiles/common/home.nix programs.starship = { enable = true; enableZshIntegration = true; settings = { add_newline = false; format = "$character"; right_format = "$all"; command_timeout = 3000; directory.substitutions = { "Documents" = "󰈙 "; "Downloads" = " "; "Music" = " "; "Pictures" = " "; }; git_status = { style = "bg:#394260"; format = "[[($all_status$ahead_behind )](fg:#769ff0 bg:#394260)]($style)"; }; character = { success_symbol = "[λ](bold green)"; error_symbol = "[λ](bold red)"; }; aws.symbol = " "; buf.symbol = " "; c.symbol = " "; conda.symbol = " "; dart.symbol = " "; directory.read_only = " 󰌾"; docker_context.symbol = " "; elixir.symbol = " "; elm.symbol = " "; fossil_branch.symbol = " "; git_branch.symbol = " "; golang.symbol = " "; guix_shell.symbol = " "; haskell.symbol = " "; haxe.symbol = " "; hg_branch.symbol = " "; hostname.ssh_symbol = " "; java.symbol = " "; julia.symbol = " "; lua.symbol = " "; memory_usage.symbol = "󰍛 "; meson.symbol = "󰔷 "; nim.symbol = "󰆥 "; nix_shell.symbol = " "; nodejs.symbol = " "; os.symbols = { Alpaquita = " "; Alpine = " "; Amazon = " "; Android = " "; Arch = " "; Artix = " "; CentOS = " "; Debian = " "; DragonFly = " "; Emscripten = " "; EndeavourOS = " "; Fedora = " "; FreeBSD = " "; Garuda = "󰛓 "; Gentoo = " "; HardenedBSD = "󰞌 "; Illumos = "󰈸 "; Linux = " "; Mabox = " "; Macos = " "; Manjaro = " "; Mariner = " "; MidnightBSD = " "; Mint = " "; NetBSD = " "; NixOS = " "; OpenBSD = "󰈺 "; openSUSE = " "; OracleLinux = "󰌷 "; Pop = " "; Raspbian = " "; Redhat = " "; RedHatEnterprise = " "; Redox = "󰀘 "; Solus = "󰠳 "; SUSE = " "; Ubuntu = " "; Unknown = " "; Windows = "󰍲 "; }; package.symbol = "󰏗 "; pijul_channel.symbol = " "; python.symbol = " "; rlang.symbol = "󰟔 "; ruby.symbol = " "; rust.symbol = " "; scala.symbol = " "; }; }; #+end_src *** Kitty Kitty is the terminal emulator of choice for me, it is nice to configure using nix, fast, and has a nice style. #+begin_src nix :tangle profiles/common/home.nix programs.kitty = { enable = true; keybindings = { "ctrl+shift+left" = "no_op"; "ctrl+shift+right" = "no_op"; "ctrl+shift+home" = "no_op"; "ctrl+shift+end" = "no_op"; }; # theme = "citylights"; }; #+end_src *** zsh zsh is clearly the most convenient shell for me and it happens to be super neat to configure within home manager. #+begin_src nix :tangle profiles/common/home.nix programs.zsh = { enable = true; shellAliases = { hg = "history | grep"; hmswitch = "cd ~/.dotfiles; home-manager --flake .#$(whoami)@$(hostname) switch; cd -;"; nswitch = "cd ~/.dotfiles; sudo nixos-rebuild --flake .#$(hostname) switch; cd -;"; edithome = "bash ~/.dotfiles/scripts/editor.sh ~/.dotfiles/Nix.org"; magit = "emacsclient -nc -e \"(magit-status)\""; config="git --git-dir=$HOME/.cfg/ --work-tree=$HOME"; g="git"; c="git --git-dir=$HOME/.dotfiles/.git --work-tree=$HOME/.dotfiles/"; passpush = "cd ~/.local/share/password-store; git add .; git commit -m 'pass file changes'; git push; cd -;"; passpull = "cd ~/.local/share/password-store; git pull; cd -;"; hotspot = "nmcli connection up local; nmcli device wifi hotspot password 12345678;"; }; autosuggestion.enable = true; enableCompletion = true; syntaxHighlighting.enable = true; autocd = false; cdpath = [ "~/.dotfiles" # "~/Documents/GitHub" ]; defaultKeymap = "emacs"; dirHashes = { dl = "$HOME/Downloads"; }; history = { expireDuplicatesFirst = true; path = "$HOME/.histfile"; save = 10000; size = 10000; }; historySubstringSearch.enable = true; initExtra = '' bindkey "^[[1;5D" backward-word bindkey "^[[1;5C" forward-word ''; }; #+end_src *** Mail #+begin_src nix :tangle profiles/common/home.nix programs.mbsync = { enable = true; }; # this is needed so that mbsync can use the passwords from sops systemd.user.services.mbsync.Unit.After = [ "sops-nix.service" ]; programs.msmtp = { enable = true; }; programs.mu = { enable = true; }; accounts.email = { maildirBasePath = "Mail"; accounts.leon = { primary = true; address = "leon.schwarzaeugl@gmail.com"; userName = "leon.schwarzaeugl@gmail.com"; realName = "Leon Schwarzäugl"; passwordCommand = "cat ${config.sops.secrets.leon.path}"; # passwordCommand = "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.local/share/password-store/mail/mbsync/leon.schwarzaeugl@gmail.com.gpg"; gpg = { key = "0x76FD3810215AE097"; signByDefault = true; }; imap.host = "imap.gmail.com"; smtp.host = "smtp.gmail.com"; mu.enable = true; msmtp = { enable = true; }; mbsync = { enable = true; create= "maildir"; expunge = "both"; patterns = ["*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail"]; extraConfig = { channel = { Sync = "All"; }; account = { Timeout = 120; PipelineDepth = 1; }; }; }; }; accounts.swarsel = { address = "leon@swarsel.win"; userName = "8227dc594dd515ce232eda1471cb9a19"; realName = "Leon Schwarzäugl"; passwordCommand = "cat ${config.sops.secrets.swarselmail.path}"; smtp = { host = "in-v3.mailjet.com"; port = 587; tls = { enable = true; useStartTls = true; }; }; mu.enable = false; msmtp = { enable = true; }; mbsync = { enable = false; }; }; accounts.nautilus = { primary = false; address = "nautilus.dw@gmail.com"; userName = "nautilus.dw@gmail.com"; realName = "Nautilus"; passwordCommand = "cat ${config.sops.secrets.nautilus.path}"; # passwordCommand = "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.local/share/password-store/mail/mbsync/nautilus.dw@gmail.com.gpg"; imap.host = "imap.gmail.com"; smtp.host = "smtp.gmail.com"; msmtp.enable = true; mu.enable = true; mbsync = { enable = true; create= "maildir"; expunge = "both"; patterns = ["*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail"]; extraConfig = { channel = { Sync = "All"; }; account = { Timeout = 120; PipelineDepth = 1; }; }; }; }; accounts.mrswarsel = { primary = false; address = "mrswarsel@gmail.com"; userName = "mrswarsel@gmail.com"; realName = "Swarsel"; # passwordCommand = "gpg --quiet --for-your-eyes-only --no-tty --decrypt ~/.local/share/password-store/mail/mbsync/mrswarsel@gmail.com.gpg"; passwordCommand = "cat ${config.sops.secrets.mrswarsel.path}"; imap.host = "imap.gmail.com"; smtp.host = "smtp.gmail.com"; msmtp.enable = true; mu.enable = true; mbsync = { enable = true; create= "maildir"; expunge = "both"; patterns = ["*" "![Gmail]*" "[Gmail]/Sent Mail" "[Gmail]/Starred" "[Gmail]/All Mail"]; extraConfig = { channel = { Sync = "All"; }; account = { Timeout = 120; PipelineDepth = 1; }; }; }; }; }; #+end_src *** Emacs #+begin_src nix :tangle profiles/common/home.nix # enable emacs overlay for bleeding edge features # also read init.el file and install use-package packages programs.emacs = { enable = true; package = (pkgs.emacsWithPackagesFromUsePackage { config = ../../Emacs.org; # tangling my Emacs.org file here instead of directly putting init.el allows avoidance of automatically installing packages in blocks using UTF-8 characters, which would break the nix evaluation happening in this line. This line is also the reason why (for now) the Emacs configuration lives in a different .org file package = pkgs.emacs-pgtk; alwaysEnsure = true; alwaysTangle = true; extraEmacsPackages = epkgs: [ epkgs.mu4e epkgs.use-package epkgs.lsp-bridge epkgs.doom-themes # build the rest of the packages myself # org-calfw is severely outdated on MELPA and throws many warnings on emacs startup # build the package from the haji-ali fork, which is well-maintained (epkgs.trivialBuild rec { pname = "calfw"; version = "1.0.0-20231002"; src = pkgs.fetchFromGitHub { owner = "haji-ali"; repo = "emacs-calfw"; rev = "bc99afee611690f85f0cd0bd33300f3385ddd3d3"; hash = "sha256-0xMII1KJhTBgQ57tXJks0ZFYMXIanrOl9XyqVmu7a7Y="; }; packageRequires = [ epkgs.howm ]; }) (epkgs.trivialBuild rec { pname = "fast-scroll"; version = "1.0.0-20191016"; src = pkgs.fetchFromGitHub { owner = "ahungry"; repo = "fast-scroll"; rev = "3f6ca0d5556fe9795b74714304564f2295dcfa24"; hash = "sha256-w1wmJW7YwXyjvXJOWdN2+k+QmhXr4IflES/c2bCX3CI="; }; packageRequires = []; }) ]; }); }; #+end_src *** Waybar Again I am just using the first bar option here that I was able to find good understandable documentation for. Of note is that the `cpu` section's `format` is not defined here, but in section 1 (since not every machine has the same number of cores) #+begin_src nix :tangle profiles/common/home.nix programs.waybar = { enable = true; # systemd.enable = true; settings = { mainBar = { layer = "top"; position = "top"; modules-left = [ "sway/workspaces" "custom/outer-right-arrow-dark" "sway/window"]; modules-center = [ "sway/mode" "custom/configwarn" ]; "sway/mode" = { format = "{}"; }; "custom/configwarn" = { exec= "bash ~/.dotfiles/scripts/checkconfigstatus.sh"; interval= 60; }; "group/hardware" = { orientation = "inherit"; drawer = { "transition-left-to-right" = false; }; modules = [ "tray" "temperature" "power-profiles-daemon" "custom/left-arrow-light" "disk" "custom/left-arrow-dark" "memory" "custom/left-arrow-light" "cpu" "custom/left-arrow-dark" ]; }; power-profiles-daemon = { format= "{icon}"; tooltip-format= "Power profile: {profile}\nDriver: {driver}"; tooltip= true; format-icons= { "default"= ""; "performance"= ""; "balanced"= ""; "power-saver"= ""; }; }; temperature = { critical-threshold = 80; format-critical = " {temperatureC}°C"; format = " {temperatureC}°C"; }; mpris = { format= "{player_icon} {title} [{position}/{length}]"; format-paused= "{player_icon} {title} [{position}/{length}]"; player-icons= { "default" = "▶ "; "mpv" = "🎵 "; "spotify" = " "; }; status-icons= { "paused"= " "; }; interval = 1; title-len = 20; artist-len = 20; album-len = 10; }; "custom/left-arrow-dark" = { format = ""; tooltip = false; }; "custom/outer-left-arrow-dark"= { format = ""; tooltip = false; }; "custom/left-arrow-light"= { format= ""; tooltip= false; }; "custom/right-arrow-dark"= { format= ""; tooltip= false; }; "custom/outer-right-arrow-dark"= { format= ""; tooltip= false; }; "custom/right-arrow-light"= { format= ""; tooltip= false; }; "sway/workspaces"= { disable-scroll= true; format= "{name}"; }; "clock#1"= { min-length= 8; interval= 1; format= "{:%H:%M:%S}"; # on-click-right= "gnome-clocks"; tooltip-format= "{:%Y %B}\n{calendar}"; }; "clock#2"= { format= "{:%d. %B %Y}"; # on-click-right= "gnome-clocks"; tooltip-format= "{:%Y %B}\n{calendar}"; }; pulseaudio= { format= "{icon} {volume:2}%"; format-bluetooth= "{icon} {volume}%"; format-muted= "MUTE"; format-icons= { headphones= ""; default= [ "" "" ]; }; scroll-step= 1; on-click= "pamixer -t"; on-click-right= "pavucontrol"; }; memory= { interval= 5; format= " {}%"; tooltip-format= "Memory: {used:0.1f}G/{total:0.1f}G\nSwap: {swapUsed}G/{swapTotal}G"; }; cpu= { min-length= 6; interval= 5; format-icons = ["▁" "▂" "▃" "▄" "▅" "▆" "▇" "█"]; # on-click-right= "com.github.stsdc.monitor"; on-click-right= "kitty -o confirm_os_window_close=0 btm"; }; battery= { states= { "warning"= 60; "error"= 30; "critical"= 15; }; interval=5; format= "{icon} {capacity}%"; format-charging= "{capacity}% "; format-plugged= "{capacity}% "; format-icons= [ "" "" "" "" "" ]; on-click-right= "wlogout -p layer-shell"; }; disk= { interval= 30; format= "Disk {percentage_used:2}%"; path= "/"; states= { "warning"= 80; "critical"= 90; }; tooltip-format = "{used} used out of {total} on {path} ({percentage_used}%)\n{free} free on {path} ({percentage_free}%)"; }; tray= { icon-size= 20; }; network= { interval = 5; format-wifi= "{signalStrength}% "; format-ethernet= ""; format-linked= "{ifname} (No IP) "; format-disconnected= "Disconnected ⚠"; format-alt= "{ifname}: {ipaddr}/{cidr}"; tooltip-format-ethernet= "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr}\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; tooltip-format-wifi= "{ifname} via {gwaddr}: {essid} {ipaddr}/{cidr} \n{signaldBm}dBm @ {frequency}MHz\n\n⇡{bandwidthUpBytes} ⇣{bandwidthDownBytes}"; }; }; }; style = '' @define-color foreground #fdf6e3; @define-color background #1a1a1a; @define-color background-alt #292b2e; @define-color foreground-warning #268bd2; @define-color background-warning @background; @define-color foreground-error red; @define-color background-error @background; @define-color foreground-critical gold; @define-color background-critical blue; ,* { border: none; border-radius: 0; font-family: "FiraCode Nerd Font Propo", "Font Awesome 5 Free"; font-size: 14px; min-height: 0; margin: -1px 0px; } window#waybar { background: transparent; color: @foreground; transition-duration: .5s; } window#waybar.hidden { opacity: 0.2; } #mpris { padding: 0 10px; background-color: transparent; color: #1DB954; font-family: Monospace; font-size: 12px; } #custom-right-arrow-dark, #custom-left-arrow-dark { color: @background; background: @background-alt; font-size: 24px; } #window { font-size: 12px; padding: 0 20px; } #mode { background: @background-critical; color: @foreground-critical; padding: 0 3px; } #custom-configwarn { color: black; padding: 0 3px; animation-name: configblink; animation-duration: 0.5s; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } #custom-outer-right-arrow-dark, #custom-outer-left-arrow-dark { color: @background; font-size: 24px; } #custom-outer-left-arrow-dark, #custom-left-arrow-dark, #custom-left-arrow-light { margin: 0 -1px; } #custom-right-arrow-light, #custom-left-arrow-light { color: @background-alt; background: @background; font-size: 24px; } #workspaces, #clock.1, #clock.2, #clock.3, #pulseaudio, #memory, #cpu, #temperature, #power-profiles-daemon, #mpris, #tray { background: @background; } #network, #clock.2, #battery, #cpu, #custom-pseudobat, #disk { background: @background-alt; } #workspaces button { padding: 0 2px; color: #fdf6e3; } #workspaces button.focused { color: @foreground-warning; } #workspaces button:hover { background: @foreground; color: @background; border: @foreground; padding: 0 2px; box-shadow: inherit; text-shadow: inherit; } #workspaces button.urgent { color: @background-critical; background: @foreground-critical; } #network { color: #cc99c9; } #temperature, #power-profiles-daemon { color: #9ec1cf; } #disk { /*color: #b58900;*/ color: #9ee09e; } #disk.warning { color: @foreground-error; background-color: @background-error; } #disk.critical, #temperature.critical { color: @foreground-critical; background-color: @background-critical; animation-name: blink; animation-duration: 0.5s; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } #pulseaudio.muted { color: @foreground-error; } #memory { /*color: #2aa198;*/ color: #fdfd97; } #cpu { /*color: #6c71c4;*/ color: #feb144; } #pulseaudio { /*color: #268bd2;*/ color: #ff6663; } #battery, #custom-pseudobat { color: cyan; } #battery.discharging { color: #859900; } @keyframes blink { to { color: @foreground-error; background-color: @background-error; } } @keyframes configblink { to { color: @foreground-error; background-color: transparent; } } #battery.critical:not(.charging) { color: @foreground-critical; background-color: @background-critical; animation-name: blink; animation-duration: 0.5s; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate; } #clock.1, #clock.2, #clock.3 { font-family: Monospace; } #clock, #pulseaudio, #memory, #cpu, #tray, #temperature, #power-profiles-daemon, #network, #mpris, #battery, #custom-pseudobat, #disk { padding: 0 3px; } ''; }; #+end_src *** Firefox #+begin_src nix :tangle profiles/common/home.nix programs.firefox = { enable = true; package = pkgs.firefox.override { nativeMessagingHosts = [ pkgs.tridactyl-native pkgs.browserpass pkgs.plasma5Packages.plasma-browser-integration ]; }; policies = { CaptivePortal = false; DisableFirefoxStudies = true; DisablePocket = true; DisableTelemetry = true; DisableFirefoxAccounts = false; NoDefaultBookmarks = true; OfferToSaveLogins = false; OfferToSaveLoginsDefault = false; EnableTrackingProtection = true; }; profiles.default = { isDefault = true; extensions = with pkgs.nur.repos.rycee.firefox-addons; [ tridactyl browserpass clearurls darkreader enhancer-for-youtube istilldontcareaboutcookies translate-web-pages ublock-origin reddit-enhancement-suite pushbullet sponsorblock web-archives single-file widegithub enhanced-github unpaywall # fastforwardteam don-t-fuck-with-paste plasma-integration # build the rest of my firefox addons myself # app id can be found in the manifest.json file of the .xpi # (.xpi is just a normal archive) # url can be found by copy url of the "add extension" button on the addon page # the rest of the information is also found in the manifest.json, but might not be # needed # (let version = "3.4.5.0"; # in buildFirefoxXpiAddon { # pname = "bypass-paywalls-clean"; # inherit version; # addonId = "magnolia@12.34"; # url = # "https://gitlab.com/magnolia1234/bpc-uploads/-/raw/master/bypass_paywalls_clean-3.4.5.0.xpi"; # sha256 = "703d30c15b88291bd0305cc59013693aea5f75a40ea98fb8e252d1c7bfb43514"; # meta = with lib; { # homepage = # "https://gitlab.com/magnolia1234/bypass-paywalls-firefox-clean"; # description = "Bypass Paywalls of (custom) news sites"; # license = licenses.mit; # platforms = platforms.all; # }; # }) (buildFirefoxXpiAddon { pname = ":emoji:"; version = "0.1.3"; addonId = "gonelf@gmail.com"; url = "https://addons.mozilla.org/firefox/downloads/file/3365324/emojidots-0.1.3.xpi"; sha256 = "4f7cc25c478fe52eb82f37c9ff4978dcaa3f95020398c5b184e517f6efa2c201"; meta = with lib; { description = "emoji autocomplete anywhere on the internet"; mozPermissions = [ "https://gist.githubusercontent.com/gonelf/d8ae3ccb7902b501c4a5dd625d4089da/raw/5eeda197ba92f8c8139e846a1225d5640077e06f/emoji_pretty.json" "tabs" "storage"]; platforms = platforms.all; }; }) ]; search.engines = { "Nix Packages" = { urls = [{ template = "https://search.nixos.org/packages"; params = [ { name = "type"; value = "packages"; } { name = "query"; value = "{searchTerms}"; } ]; }]; icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; definedAliases = [ "@np" ]; }; "NixOS Wiki" = { urls = [{ template = "https://nixos.wiki/index.php?search={searchTerms}"; }]; iconUpdateURL = "https://nixos.wiki/favicon.png"; updateInterval = 24 * 60 * 60 * 1000; # every day definedAliases = [ "@nw" ]; }; "NixOS Options" = { urls = [{ template = "https://search.nixos.org/options"; params = [ { name = "query"; value = "{searchTerms}"; } ]; }]; icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; definedAliases = [ "@no" ]; }; "Home Manager Options" = { urls = [{ template = "https://home-manager-options.extranix.com/"; params = [ { name = "query"; value = "{searchTerms}"; } ]; }]; icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg"; definedAliases = [ "@hm" "@ho" "@hmo" ]; }; "Google".metaData.alias = "@g"; }; search.force = true; # this is required because otherwise the search.json.mozlz4 symlink gets replaced on every firefox restart }; }; #+end_src *** Browserpass #+begin_src nix :tangle profiles/common/home.nix # programs.browserpass = { # enable = true; # browsers = [ # "firefox" # ]; # }; #+end_src ** Services Services that can be defined through home-manager should be defined here. *** General #+begin_src nix :tangle profiles/common/home.nix services.gnome-keyring = { enable = true; }; services.mbsync = { enable = true; }; services.kdeconnect = { enable = true; indicator = true; }; services.syncthing = { enable = true; tray = { enable = false; # we enable this by installing the syncthingtray package instead, it works better. }; }; # this enables the emacs server services.emacs = { enable = true; # socketActivation.enable = false; # startWithUserSession = "graphical"; }; #+end_src *** Mako The `extraConfig` section here CANNOT be reindented. This has something to do with how nix handles multiline strings, when indented Mako will fail to start. This might be a mako bug as well. #+begin_src nix :tangle profiles/common/home.nix services.mako = { enable = true; # backgroundColor = "#2e3440"; # borderColor = "#88c0d0"; borderRadius = 15; borderSize = 1; defaultTimeout = 5000; height = 150; icons = true; ignoreTimeout = true; layer = "overlay"; maxIconSize = 64; sort = "-time"; width = 300; # font = "monospace 10"; extraConfig = "[urgency=low] border-color=#cccccc [urgency=normal] border-color=#d08770 [urgency=high] border-color=#bf616a default-timeout=3000 [category=mpd] default-timeout=2000 group-by=category "; }; #+end_src ** Sway I am currently using SwayFX, which adds some nice effects to sway, like rounded corners and hiding the separator between title and content of a window. #+begin_src nix :tangle profiles/common/home.nix wayland.windowManager.sway = { enable = true; checkConfig = false; # delete this line once SwayFX is fixed upstream package = pkgs.swayfx; # package = pkgs.sway; systemd.enable = true; systemd.xdgAutostart = true; wrapperFeatures.gtk = true; config = rec { modifier = "Mod4"; terminal = "kitty"; menu = "fuzzel"; bars = [{ command = "waybar";}]; keybindings = let modifier = config.wayland.windowManager.sway.config.modifier; in { "${modifier}+q" = "kill"; "${modifier}+f" = "exec firefox"; "${modifier}+Space" = "exec fuzzel"; "${modifier}+Shift+Space" = "floating toggle"; "${modifier}+e" = "exec emacsclient -nquc -a emacs -e \"(dashboard-open)\""; "${modifier}+Shift+m" = "exec emacsclient -nquc -a emacs -e \"(mu4e)\""; "${modifier}+Shift+c" = "exec emacsclient -nquc -a emacs -e \"(swarsel/open-calendar)\""; "${modifier}+Shift+s" = "exec \"bash ~/.dotfiles/scripts/checkspotify.sh\""; "${modifier}+m" = "exec \"bash ~/.dotfiles/scripts/checkspotifytui.sh\""; "${modifier}+x" = "exec \"bash ~/.dotfiles/scripts/checkkitty.sh\""; "${modifier}+d" = "exec \"bash ~/.dotfiles/scripts/checkdiscord.sh\""; "${modifier}+Shift+r" = "exec \"bash ~/.dotfiles/scripts/restart.sh\""; "${modifier}+Shift+t" = "exec \"bash ~/.dotfiles/scripts/toggle_opacity.sh\""; "${modifier}+Shift+F12" = "move scratchpad"; "${modifier}+F12" = "scratchpad show"; "${modifier}+c" = "exec qalculate-gtk"; "${modifier}+p" = "exec pass-fuzzel"; "${modifier}+o" = "exec pass-fuzzel-otp"; "${modifier}+Shift+p" = "exec pass-fuzzel --type"; "${modifier}+Shift+o" = "exec pass-fuzzel-otp --type"; "${modifier}+Escape" = "mode $exit"; # "${modifier}+Shift+Escape" = "exec com.github.stsdc.monitor"; "${modifier}+Shift+Escape" = "exec kitty -o confirm_os_window_close=0 btm"; "${modifier}+s" = "exec grim -g \"$(slurp)\" -t png - | wl-copy -t image/png"; "${modifier}+i" = "exec \"bash ~/.dotfiles/scripts/startup.sh\""; "${modifier}+1" = "workspace 1:一"; "${modifier}+Shift+1" = "move container to workspace 1:一"; "${modifier}+2" = "workspace 2:二"; "${modifier}+Shift+2" = "move container to workspace 2:二"; "${modifier}+3" = "workspace 3:三"; "${modifier}+Shift+3" = "move container to workspace 3:三"; "${modifier}+4" = "workspace 4:四"; "${modifier}+Shift+4" = "move container to workspace 4:四"; "${modifier}+5" = "workspace 5:五"; "${modifier}+Shift+5" = "move container to workspace 5:五"; "${modifier}+6" = "workspace 6:六"; "${modifier}+Shift+6" = "move container to workspace 6:六"; "${modifier}+7" = "workspace 7:七"; "${modifier}+Shift+7" = "move container to workspace 7:七"; "${modifier}+8" = "workspace 8:八"; "${modifier}+Shift+8" = "move container to workspace 8:八"; "${modifier}+9" = "workspace 9:九"; "${modifier}+Shift+9" = "move container to workspace 9:九"; "${modifier}+0" = "workspace 10:十"; "${modifier}+Shift+0" = "move container to workspace 10:十"; "XF86AudioRaiseVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ +5%"; "XF86AudioLowerVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ -5%"; "${modifier}+Left" = "focus left"; "${modifier}+Right" = "focus right"; "${modifier}+Down" = "focus down"; "${modifier}+Up" = "focus up"; "${modifier}+Shift+Left" = "move left 40px"; "${modifier}+Shift+Right" = "move right 40px"; "${modifier}+Shift+Down" = "move down 40px"; "${modifier}+Shift+Up" = "move up 40px"; "${modifier}+h" = "focus left"; "${modifier}+l" = "focus right"; "${modifier}+j" = "focus down"; "${modifier}+k" = "focus up"; "${modifier}+Shift+h" = "move left 40px"; "${modifier}+Shift+l" = "move right 40px"; "${modifier}+Shift+j" = "move down 40px"; "${modifier}+Shift+k" = "move up 40px"; "${modifier}+Ctrl+Shift+c" = "reload"; "${modifier}+Shift+e" = "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; "${modifier}+r" = "mode resize"; "${modifier}+Return" = "exec kitty"; }; modes = { resize = { Down = "resize grow height 10 px or 10 ppt"; Escape = "mode default"; Left = "resize shrink width 10 px or 10 ppt"; Return = "mode default"; Right = "resize grow width 10 px or 10 ppt"; Up = "resize shrink height 10 px or 10 ppt"; }; }; defaultWorkspace = "workspace 1:一"; startup = [ { command = "kitty -T kittyterm";} { command = "sleep 60; kitty -T spotifytui -o confirm_os_window_close=0 spotify_player";} ]; window = { border = 1; titlebar = false; }; assigns = { # disabled, this is too annoying to be of use # "1:一" = [{ app_id = "^firefox$"; }]; }; colors = { focused = { # background = "#080808"; # border = "#80a0ff"; # childBorder = "#80a0ff"; # indicator = "#080808"; # text = "#ffd700"; }; unfocused = { # background = "#080808"; # border = "#80a0ff"; # childBorder = "#303030"; # indicator = "#80a0ff"; # text = "#c6c6c6"; }; }; floating = { border = 1; criteria = [ {title = "^Picture-in-Picture$";} {app_id = "qalculate-gtk";} {app_id = "org.gnome.clocks";} {app_id = "com.github.stsdc.monitor";} {app_id = "blueman";} {app_id = "pavucontrol";} {app_id = "syncthingtray";} {title = "Syncthing Tray";} {app_id = "SchildiChat";} {app_id = "Element";} {app_id = "com.nextcloud.desktopclient.nextcloud";} {app_id = "gnome-system-monitor";} {title = "(?:Open|Save) (?:File|Folder|As)";} {title = "^Add$";} {title = "com-jgoodies-jdiskreport-JDiskReport";} {app_id = "discord";} {window_role = "pop-up";} {window_role = "bubble";} {window_role = "dialog";} {window_role = "task_dialog";} {window_role = "menu";} {window_role = "Preferences";} ]; titlebar = false; }; window = { commands = [ { command = "opacity 0.95"; criteria = { class = ".*"; }; } { command = "opacity 0.95"; criteria = { app_id = ".*"; }; } { command = "opacity 1"; criteria = { app_id = "Gimp-2.10"; }; } { command = "opacity 0.99"; criteria = { app_id = "firefox"; }; } { command = "sticky enable, shadows enable"; criteria = { title="^Picture-in-Picture$"; }; } { command = "opacity 0.8, sticky enable, border normal, move container to scratchpad"; criteria = { title="kittyterm"; }; } { command = "opacity 0.95, sticky enable, border normal, move container to scratchpad"; criteria = { title="spotifytui"; }; } # { # command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; # criteria = { # app_id="^$"; # class="^$"; # }; # } { command = "resize set width 60 ppt height 60 ppt, sticky enable, move container to scratchpad"; criteria = { class="Spotify"; }; } { command = "sticky enable"; criteria = { app_id = "discord"; }; } { command = "resize set width 60 ppt height 60 ppt, sticky enable"; criteria = { class = "Element"; }; } { command = "resize set width 60 ppt height 60 ppt, sticky enable"; criteria = { app_id = "SchildiChat"; }; } ]; }; gaps = { inner = 5; }; }; extraSessionCommands ='' export SDL_VIDEODRIVER=wayland export QT_QPA_PLATFORM=wayland export QT_WAYLAND_DISABLE_WINDOWDECORATION="1" export _JAVA_AWT_WM_NONREPARENTING=1 export XDG_CURRENT_DESKTOP=sway export XDG_SESSION_DESKTOP=sway export QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox"; export ANKI_WAYLAND=1; export OBSIDIAN_USE_WAYLAND=1; ''; # extraConfigEarly = " # exec systemctl --user import-environment DISPLAY WAYLAND_DISPLAY SWAYSOCK # exec hash dbus-update-activation-environment 2>/dev/null && dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK # "; extraConfig =let modifier = config.wayland.windowManager.sway.config.modifier; swayfxSettings = " blur enable blur_xray disable blur_passes 1 blur_radius 1 shadows enable corner_radius 2 titlebar_separator disable default_dim_inactive 0.02 "; swayfxSettingsOff = ""; in " exec_always autotiling set $exit \"exit: [s]leep, [p]oweroff, [r]eboot, [l]ogout\" mode $exit { bindsym --to-code { s exec \"systemctl suspend\", mode \"default\" p exec \"systemctl poweroff\" r exec \"systemctl reboot\" l exec \"swaymsg exit\" Return mode \"default\" Escape mode \"default\" ${modifier}+x mode \"default\" } } exec systemctl --user import-environment ${swayfxSettings} "; }; #+end_src * TODO Manual tasks, Useful bits, flake.nix skeleton and Closing Parenthesis (this needs to be the last heading) Here are listed some tasks that I was not able to automate yet, these need to be done automatically for now. Also, this section exists to add an extra closing parenthesis to common.nix so that I do not need to think about this anymore if I ever decide to add more headings towards the end of this file ;) - TODO: Check if the below tasks can be automated 1) In blueman, toggle the `ConnectionNotifier` plugin to off (since it is highly annoing) The last blocks exist to close the opening parenthesis of modules/common.nix (home-manager) and profiles/common.nix (NixOS): ** Useful bits Here I have gathered some snippets that I have deleted from my configuration but figured they might be of use to someone still :) *** let-block for overriding a package in nixpkgs (here: replacing airsonic with airsonic-advanced) This can be useful if a module does not let you use your own package yourself. #+begin_src nix pkgs = import nixpkgs { inherit system; overlays = [ emacs-overlay.overlay nur.overlay nixgl.overlay (self: super: { airsonic = super.airsonic.overrideAttrs (_: rec { version = "11.0.2-kagemomiji"; name = "airsonic-advanced-${version}"; src = super.fetchurl { url = "https://github.com/kagemomiji/airsonic-advanced/releases/download/11.0.2/airsonic.war"; sha256 = "PgErtEizHraZgoWHs5jYJJ5NsliDd9VulQfS64ackFo="; }; }); }) ]; config.allowUnfree = true; }; #+end_src ** Closing parentheses for common/home.nix and common/nixos.nix #+begin_src nix :tangle profiles/common/home.nix } #+end_src #+begin_src nix :tangle profiles/common/nixos.nix } #+end_src ** flake.nix This tangles the flake.nix file; This block only needs to be touched when updating the general structure of the flake. For everything else, see the respective noweb-ref block. #+begin_src nix :noweb yes :tangle flake.nix { description = "SwarseFlake - Nix Flake for all SwarselSystems"; inputs = { <> }; outputs = inputs@{ self, <> ... }: let <> in { # NixOS setups - run home-manager as a NixOS module for better compatibility # another benefit - full rebuild on nixos-rebuild switch # run rebuild using `nswitch` # NEW HOSTS: For a new host, decide whether a NixOS (nixosConfigurations) or non-NixOS (homeConfigurations) is used. # Make sure to move hardware-configuration to the appropriate location, by default it is found in /etc/nixos/. nixosConfigurations = { <> }; # pure Home Manager setups - for non-NixOS machines # run rebuild using `hmswitch` homeConfigurations = { <> }; nixOnDroidConfigurations = { <> }; packages.x86_64-linux = { <> }; }; } #+end_src