# Edit this configuration file to define what should be installed on # your system. Help is available in the configuration.nix(5) man page # and in the NixOS manual (accessible by running ‘nixos-help’). { config, lib, nixpkgs, pkgs, home-manager, ... }: let my_python = (pkgs.python3.withPackages (ps: with ps; [ git_plan ])); my_emacs = (pkgs.emacsWithPackagesFromUsePackage { config = ./emacs.el; defaultInitFile = true; package = pkgs.emacs29-pgtk.overrideAttrs (old: { withTreeSitter = true; }); #alwaysEnsure = true; extraEmacsPackages = epkgs: [ pkgs.mu pkgs.mu.mu4e epkgs.treesit-grammars.with-all-grammars epkgs.evil-collection ]; }); in { imports = [ #./gnupg.nix ]; nix.settings.experimental-features = [ "nix-command" "flakes" ]; nix.extraOptions = '' !include ${config.sops.secrets.github_token.path} bash-prompt = (nix:$name)\040\[\033[1;32m\][\u@\h:\w]\$\[\033[0m\]\040 extra-sandbox-paths = /nix/var/cache/ccache ''; sops = { environment.SOPS_GPG_EXEC = "${pkgs.gnupg}/bin/gpg"; defaultSopsFile = ./secrets.yaml; secrets = { fastmail_password = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; github_token = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; git_plan_config = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; git_plan_credentials = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; syncthing_key = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; syncthing_cert = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; mullvad_account = { }; kagi_api_key = { owner = config.users.users.knazarov.name; group = config.users.users.knazarov.group; }; }; }; # networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. # Configure network proxy if necessary # networking.proxy.default = "http://user:password@proxy:port/"; # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain"; # Enable networking networking.networkmanager.enable = true; # Set your time zone. time.timeZone = "Europe/London"; # Select internationalisation properties. i18n.defaultLocale = "en_US.UTF-8"; i18n.extraLocaleSettings = { LC_ADDRESS = "en_US.UTF-8"; LC_IDENTIFICATION = "en_US.UTF-8"; LC_MEASUREMENT = "en_US.UTF-8"; LC_MONETARY = "en_US.UTF-8"; LC_NAME = "en_US.UTF-8"; LC_NUMERIC = "en_US.UTF-8"; LC_PAPER = "en_US.UTF-8"; LC_TELEPHONE = "en_US.UTF-8"; LC_TIME = "en_US.UTF-8"; }; # Mainly to access SMB shares on local network services.gvfs = { enable = true; package = lib.mkForce pkgs.gnome3.gvfs; }; # Configure keymap in X11 services.xserver = { xkb.layout = "us"; xkb.variant = ""; }; # Define a user account. Don't forget to set a password with ‘passwd’. users.users.knazarov = { isNormalUser = true; description = "Konstantin Nazarov"; extraGroups = [ "networkmanager" "wheel" config.users.groups.keys.name ]; packages = with pkgs; [ ]; openssh.authorizedKeys.keys = [ "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGxebDydOcs7URJjXFHMU++ruaZOJpXbK4ixH19pWTsX7WtxxriZxD4+RQ3oyllGG/8sEFzEe0NoTHUPU6YrBpfwT/ekGDmCJHtvZ+rZs+cRQd6tObfAUip1B1Mcvhuaj0prnrbfohOuHpvQ/L8TogIKuHgczDmud4KGUu0mxCsUHbD5tlKpsgN+dJXkvjxsO7JhhF9JpFTrYAU0gTuBPTt3ynpnZKrE1NgnE0iy+CEr/v41dLqxw3fUjT3nOFUQ1l/VKTw5mLt5Iw7XmBLuFGLRAVrwzXxeBCfYqKGYgY4QV8HCcVpcqC8zWmRskiRetzQ/5HwRagm4yZr0I+LZ305nGB0cSJzLWXXOUF6SDg2cqAXFpF/o2LoFCmaV5h3jmCGOUrowF7oV4mYwBMWfabrbZx21z/R56GkAOOEKc2h+Qh5wIj4yayX081SkqJK3J9+3vGG4VvXnwGnPnWQFqrzeedyV74maffGBGFYm0UOcD+oG6EwM+7MEUBpJm9m4c= knazarov" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHkDvP2BO1uV0AwEjABYFEiA2BbGo1IsSht4emYMRLgi root@mira" ]; }; nixpkgs.config.allowUnfree = true; environment.systemPackages = with pkgs; [ # needed to request polkit access (for instance, for SMB shares) lxqt.lxqt-policykit vim waybar foot wayland xdg-utils glib dracula-theme adwaita-icon-theme swaylock swayidle wl-clipboard keyd tdesktop git source-code-pro pavucontrol brightnessctl sops age ssh-to-age syncthing pass pkgs.gnupg pciutils slack q-sh notes-sh transmission_4-gtk mpv imv okular yt-dlp evince # document viewer firefox gthumb unzip somafm-cli yubikey-manager yubikey-manager-qt ripgrep file zoom-us obs-studio nautilus xfce.thunar zig mullvad-vpn mullvad usbutils wf-recorder xournalpp dnsutils graphviz fzf fd nixfmt my_emacs libreoffice gcc neovim go gopls lazygit guile solc kdenlive kooha # screen capture # ---------- # mainly needed for npm which decided to play hardball automake autoconf # ---------- (pkgs.callPackage ./nil_cli.nix {}) #network-manager-applet #(clang-tools.override { #llvmPackages = llvmPackages_17; #enableLibcxx = false; #}) # mainly for clang-format clang-tools # wget my_python # latex basics (pkgs.texlive.combine { inherit (pkgs.texlive) scheme-basic dvisvgm dvipng beamer metafont wrapfig amsmath ulem hyperref capt-of; }) nodejs networkmanagerapplet ]; services.blueman.enable = true; services.tailscale.enable = true; services.mullvad-vpn = { enable = true; }; systemd.services."mullvad-daemon".postStart = let mullvad = config.services.mullvad-vpn.package; in '' while ! ${mullvad}/bin/mullvad status >/dev/null; do sleep 1; done ${mullvad}/bin/mullvad account login `cat /var/run/secrets/mullvad_account` ${mullvad}/bin/mullvad auto-connect set on ${mullvad}/bin/mullvad tunnel set ipv6 on ''; services.fwupd.enable = true; services.gnome.gnome-keyring.enable = true; #services.emacs.package = nixpkgs.emacsUnstablePgtk; # Enables wayland support in electron apps (e.g. slack) environment.sessionVariables.NIXOS_OZONE_WL = "1"; # Enable screen sharing on Wayland xdg = { portal = { enable = true; wlr.enable = true; extraPortals = with pkgs; [ xdg-desktop-portal-wlr xdg-desktop-portal-gtk ]; }; }; # Some programs need SUID wrappers, can be configured further or are # started in user sessions. # programs.mtr.enable = true; programs.gnupg.package = pkgs.gnupg; programs.gnupg.agent = { enable = true; enableSSHSupport = true; enableExtraSocket = true; }; programs.sway = { enable = true; wrapperFeatures.gtk = true; }; # List services that you want to enable: services.pipewire = { enable = true; alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; wireplumber.enable = true; }; services.pipewire.wireplumber.extraConfig.bluetoothEnhancements = { "monitor.bluez.properties" = { "bluez5.enable-sbc-xq" = true; "bluez5.enable-msbc" = true; "bluez5.enable-hw-volume" = true; "bluez5.roles" = [ "hsp_hs" "hsp_ag" "hfp_hf" "hfp_ag" ]; }; }; programs.steam = { enable = true; }; # Disable unneeded PipeWire devices and rename the ones I use to more recognizable names environment.etc."wireplumber/main.lua.d/51-device-rename.lua".text = '' table.insert(alsa_monitor.rules, { matches = { { { "node.name", "equals", "alsa_output.usb-Audioengine_LLC_Audioengine_2__AE202010001A2002-00.analog-stereo" }, }, }, apply_properties = { ["node.description"] = "Speakers", ["node.nick"] = "Speakers", }, }) table.insert(alsa_monitor.rules, { matches = { { { "node.name", "equals", "alsa_output.usb-SteelSeries_SteelSeries_Arctis_5_00000000-00.analog-chat" }, }, }, apply_properties = { ["node.description"] = "Headphones", ["node.nick"] = "Headphones", }, }) table.insert(alsa_monitor.rules, { matches = { { { "node.name", "equals", "alsa_input.usb-SteelSeries_SteelSeries_Arctis_5_00000000-00.analog-chat" }, }, }, apply_properties = { ["node.description"] = "Headphone Mic", ["node.nick"] = "Headphone Mic", }, }) table.insert(alsa_monitor.rules, { matches = { {{ "node.name", "equals", "alsa_output.usb-SteelSeries_SteelSeries_Arctis_5_00000000-00.analog-game" },}, }, apply_properties = { ["node.disabled"] = true, }, }) table.insert(alsa_monitor.rules, { matches = { {{ "node.name", "equals", "alsa_output.pci-0000_14_00.1.hdmi-stereo" },}, }, apply_properties = { ["node.disabled"] = true, }, }) table.insert(alsa_monitor.rules, { matches = { {{ "node.name", "equals", "alsa_input.usb-MACROSILICON_USB_Video-02.analog-stereo" },}, }, apply_properties = { ["node.disabled"] = true, }, }) ''; services.dbus.enable = true; services.greetd = { enable = true; settings = rec { initial_session = { command = "${pkgs.sway}/bin/sway"; user = "knazarov"; }; default_session = initial_session; }; }; services.keyd = { enable = true; keyboards = { default = { ids = [ "*" ]; settings = { main = { capslock = "overload(control, esc)"; leftalt = "layer(meta_mac)"; leftmeta = "layer(alt)"; }; "meta_mac:M" = { c = "C-insert"; v = "S-insert"; }; }; }; }; }; # Enable the OpenSSH daemon. services.openssh = { enable = true; # settings = { # passwordAuthentication = false; # kbdInteractiveAuthentication = false; # }; }; services.jellyfin = { enable = true; openFirewall = true; }; networking.firewall.allowedTCPPorts = [ 8096 # Syncthing 8384 22000 ]; networking.firewall.allowedUDPPorts = [ # Syncthing 22000 21027 ]; # This value determines the NixOS release from which the default # settings for stateful data, like file locations and database versions # on your system were taken. It‘s perfectly fine and recommended to leave # this value at the release version of the first install of this system. # Before changing this value read the documentation for this option # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). system.stateVersion = "23.11"; # Did you read the comment? # needed for sway security.polkit.enable = true; # needed for pipewire security.rtkit.enable = true; # allow remote rebuilds nix.settings.trusted-users = [ "@wheel" ]; # needed for YubiKey smartcard support services.pcscd.enable = true; fonts.fontDir.enable = true; fonts.packages = with pkgs; [ dejavu_fonts (nerdfonts.override { fonts = [ "SourceCodePro" ]; }) source-code-pro font-awesome # for waybar indicators ]; services.syncthing = { enable = true; user = "knazarov"; configDir = "/home/knazarov/.config/syncthing"; key = config.sops.secrets.syncthing_key.path; cert = config.sops.secrets.syncthing_cert.path; }; home-manager.users.knazarov = { # The home.stateVersion option does not have a default and must be set home.stateVersion = "24.11"; home.sessionVariables = { EDITOR = "emacs -nw --no-splash"; GUILE_LOAD_PATH = "${config.users.users.knazarov.home}/guile"; }; home.file.".guile" = { source = ./guile-config; }; programs.lf = { enable = true; extraConfig = '' set sixel true set previewer ${pkgs.chafa}/bin/chafa ''; }; programs.bash = { enable = true; bashrcExtra = '' if [[ "$INSIDE_EMACS" = 'vterm' ]] \ && [[ -n ''${EMACS_VTERM_PATH} ]] \ && [[ -f ''${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh ]]; then source ''${EMACS_VTERM_PATH}/etc/emacs-vterm-bash.sh fi ''; shellAliases = { nn = "notes.sh -n"; ne = ''notes.sh -l | fzf --tac --with-nth="2..-1" | xargs -o notes.sh -e''; vim = "emacs -nw --no-splash"; }; }; xdg.mimeApps = { enable = true; defaultApplications = { "text/html" = "firefox.desktop"; "x-scheme-handler/http" = "firefox.desktop"; "x-scheme-handler/https" = "firefox.desktop"; "x-scheme-handler/about" = "firefox.desktop"; "x-scheme-handler/unknown" = "firefox.desktop"; }; }; gtk = { enable = true; gtk3.extraConfig = { gtk-enable-animations = "0"; }; gtk4.extraConfig = { gtk-enable-animations = "0"; }; }; # Workaround for https://github.com/nix-community/home-manager/issues/5146 services.gpg-agent = { enable = true; pinentryPackage = pkgs.pinentry-gnome3; enableExtraSocket = true; }; programs.gpg = { enable = true; package = pkgs.gnupg; publicKeys = [ { source = ./gpg_public_key.asc; trust = "ultimate"; } { source = ./pgp_keys/FB4809DC51A4F483.asc; trust = "ultimate"; } { source = ./pgp_keys/60B2FF168764BED2D4ADE1BF7DE090DD4DB68232.asc; trust = "ultimate"; } { source = ./pgp_keys/8311DCF21B41308C743FBFEA44B0C3FE7CD9EAE3.asc; trust = "ultimate"; } ]; settings = { default-key = "0x0560020C9C577C1B"; }; mutableKeys = false; mutableTrust = false; }; programs.git = { enable = true; package = pkgs.gitAndTools.gitFull; # needed for git send-email support userName = "Konstantin Nazarov"; userEmail = "mail@knazarov.com"; signing = { gpgPath = "${pkgs.gnupg}/bin/gpg2"; key = "0x0560020C9C577C1B"; signByDefault = true; }; extraConfig = { push = { autoSetupRemote = true; }; }; }; accounts.email = { maildirBasePath = "${config.users.users.knazarov.home}/Maildir"; accounts = { personal = let account = "mail@knazarov.com"; in { primary = true; flavor = "fastmail.com"; address = account; userName = account; realName = "Konstantin Nazarov"; passwordCommand = "cat /run/secrets/fastmail_password"; gpg = { key = "0x0560020C9C577C1B"; signByDefault = true; }; mu.enable = true; msmtp.enable = true; mbsync = { enable = true; # Folders existing on the server, but not locally, will be created. create = "maildir"; }; neomutt = { enable = true; }; }; }; }; programs.neomutt = { enable = true; }; programs.mu = { enable = true; }; programs.msmtp.enable = true; programs.mbsync = { enable = true; }; #services.easyeffects = { # enable = true; #}; services.swayidle = { enable = true; timeouts = [ { timeout = 300; command = "${pkgs.swaylock}/bin/swaylock -f -c 000000"; } { timeout = 600; command = ''${pkgs.sway}/bin/swaymsg "output * dpms off"''; resumeCommand = ''${pkgs.sway}/bin/swaymsg "output * dpms on"''; } ]; events = [{ event = "before-sleep"; command = "${pkgs.swaylock}/bin/swaylock -f -c 000000"; }]; }; services.emacs = { enable = true; package = my_emacs; client.enable = true; }; wayland.windowManager.sway = { enable = true; xwayland = true; config = rec { modifier = "Mod4"; terminal = "foot"; bars = [{ "command" = "waybar"; }]; keybindings = pkgs.lib.mkOptionDefault { "XF86AudioRaiseVolume" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"; "XF86AudioLowerVolume" = "exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"; "XF86AudioMute" = "exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"; "XF86AudioMicMute" = "exec pactl set-source-mute @DEFAULT_SOURCE@ toggle"; "XF86MonBrightnessUp" = "exec brightnessctl s +5%"; "XF86MonBrightnessDown" = "exec brightnessctl s 5%-"; #"Mod4+Return" = #"exec emacs --eval '(progn (setq confirm-kill-processes nil) (vterm))'"; #"Mod4+Return" = "exec emacsclient -c"; "Mod4+Return" = "exec foot"; "Mod4+space" = "exec ${pkgs.foot}/bin/foot -T mylauncher -a mylauncher ${pkgs.q-sh}/bin/q"; "Mod4+p" = "exec '${pkgs.grim}/bin/grim -g \"$$(${pkgs.slurp}/bin/slurp)\" - | ${pkgs.wl-clipboard}/bin/wl-copy -t image/png'"; "Mod4+o" = "exec '${pkgs.kooha}/bin/kooha'"; }; output = { "*" = { bg = "${./wallpaper.jpg} fill"; }; "Lenovo Group Limited LEN T32p-20 VNA4VRNY" = { scale = "1.5"; }; "LG Electronics LG TV SSCR2 0x01010101" = { mode = "1920x1080@60Hz"; }; }; input = { "type:keyboard" = { xkb_layout = "us,ru"; xkb_options = "grp:alt_space_toggle"; }; }; gaps = { inner = 10; outer = 5; }; colors.unfocused = { border = "#dddddd"; background = "#dddddd"; text = "#888888"; indicator = "#888888"; childBorder = "#888888"; }; }; extraConfig = '' for_window [title="as_toolbar"] floating enable for_window [title="mylauncher"] floating enable for_window [title="Firefox.*Sharing Indicator"] floating enable; default_border pixel 3 input 1386:885:Wacom_Intuos_M_Pen map_to_output DP-1 exec_always ${pkgs.networkmanagerapplet}/bin/nm-applet --indicator ''; }; programs.foot = { enable = true; settings = { main = { font = "Source Code Pro:size=12"; }; colors = { background = "ffffff"; foreground = "000000"; regular0 = "000000"; regular1 = "a60000"; regular2 = "005e00"; regular3 = "813e00"; regular4 = "0031a9"; regular5 = "721045"; regular6 = "00538b"; regular7 = "bfbfbf"; bright0 = "595959"; bright1 = "972500"; bright2 = "315b00"; bright3 = "70480f"; bright4 = "2544bb"; bright5 = "5317ac"; bright6 = "005a5f"; bright7 = "ffffff"; }; key-bindings = { clipboard-copy = "Control+Insert"; clipboard-paste = "Shift+Insert"; primary-paste = "Control+Shift+v"; }; }; }; programs.waybar = { enable = true; settings = [{ layer = "top"; position = "top"; height = 24; modules-left = [ "sway/workspaces" "sway/mode" ]; modules-center = [ "sway/window" ]; modules-right = [ "idle_inhibitor" "battery" "clock" "tray" ]; clock.format = "{:%Y-%m-%d %H:%M}"; battery = { states = { # good = 95; warning = 30; critical = 15; }; format = "{capacity}% {icon}"; format-charging = "{capacity}% "; format-plugged = "{capacity}% "; format-alt = "{time} {icon}"; format-icons = [ "" "" "" "" "" ]; }; idle_inhibitor = { format = "{icon}"; format-icons = { activated = ""; deactivated = ""; }; }; }]; }; #services.syncthing = { enable = true; }; home.pointerCursor = { name = "Adwaita"; package = pkgs.adwaita-icon-theme; size = 24; x11 = { enable = true; defaultCursor = "Adwaita"; }; }; }; virtualisation = { podman = { enable = true; dockerCompat = true; defaultNetwork.settings = { dns_enabled = true; }; }; }; services.udev.packages = [ pkgs.android-udev-rules (pkgs.callPackage ./zsa-udev-rules.nix {})]; #udevadm info --query=all --name=/dev/sda1 | grep ID_SERIAL services.udev.extraRules = ''ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", '' + '' ENV{ID_FS_USAGE}=="filesystem", ENV{ID_SERIAL_SHORT}=="Hidizs_AP80PRO", '' + ''RUN{program}+="${pkgs.systemd}/bin/systemd-mount --owner knazarov '' + ''--no-block --automount=yes --collect $devnode /media"''; systemd.timers."git_plan" = { wantedBy = [ "timers.target" ]; timerConfig = { OnBootSec = "1h"; OnUnitActiveSec = "1h"; Unit = "git_plan.service"; }; }; systemd.services."git_plan" = { script = '' ${my_python}/bin/python3 -m git_plan -c /var/run/secrets/git_plan_config -r /var/run/secrets/git_plan_credentials oneshot ''; serviceConfig = { Type = "oneshot"; User = "knazarov"; StateDirectory = "git_plan"; Environment = "PYTHONUNBUFFERED=1"; }; }; systemd.timers."git_plan_pr" = { wantedBy = [ "timers.target" ]; timerConfig = { OnCalendar = "Mon,Tue,Wed,Thu,Fri *-*-* 10:00:00"; Unit = "git_plan_pr.service"; }; }; systemd.services."git_plan_pr" = { script = '' ${my_python}/bin/python3 -m git_plan -c /var/run/secrets/git_plan_config -r /var/run/secrets/git_plan_credentials pr ''; serviceConfig = { Type = "oneshot"; User = "knazarov"; StateDirectory = "git_plan"; Environment = "PYTHONUNBUFFERED=1"; }; }; }