nixos-config

NixOS configs for my systems
Log | Files | Refs

default.nix (21451B)


      1 {
      2   config,
      3   home-manager,
      4   lib,
      5   pkgs,
      6   inputs,
      7   llama-cpp,
      8   ...
      9 }:
     10 
     11 {
     12   imports = [
     13     ./hardware.nix
     14     ../../modules/common.nix
     15     ../../modules/desktop.nix
     16     home-manager.nixosModules.default
     17   ];
     18 
     19   # nixpkgs stuff
     20   nixpkgs = {
     21     config = {
     22       # selectively allow unfree packages
     23       allowUnfreePredicate =
     24         pkg:
     25         builtins.elem (lib.getName pkg) [
     26           "open-webui"
     27           "steam"
     28           "steam-unwrapped"
     29         ];
     30 
     31       # selectively allow insecure packages
     32       permittedInsecurePackages = [
     33         "dotnet-sdk-6.0.428"
     34         "aspnetcore-runtime-6.0.36"
     35       ];
     36 
     37       cudaSupport = false;
     38     };
     39 
     40     overlays = [
     41       (self: super: {
     42         alvr = super.alvr.overrideAttrs (old: {
     43           buildInputs = old.buildInputs ++ [
     44             super.android-tools
     45             super.usbutils
     46             super.zenity
     47           ];
     48           nativeBuildInputs = old.nativeBuildInputs ++ [ super.makeWrapper ];
     49           postInstall = (old.postInstall or "") + ''
     50             wrapProgram $out/bin/alvr_dashboard --prefix PATH : "${
     51               super.lib.makeBinPath [
     52                 super.android-tools
     53                 super.usbutils
     54                 super.zenity
     55               ]
     56             }"
     57           '';
     58         });
     59       })
     60     ];
     61   };
     62 
     63   # decrypt agenix secrets
     64   age.secrets = {
     65     wg0_demiurge.file = ../../secrets/wg0_demiurge.age;
     66     wg1_demiurge.file = ../../secrets/wg1_demiurge.age;
     67   };
     68 
     69   # boot options
     70   boot = {
     71     # force monitor to always be connected
     72     kernelParams = [ "video=DP-4:3440x1440@100e" ];
     73 
     74     zfs.extraPools = [
     75       "data_nvme"
     76       "data_hdd"
     77     ];
     78   };
     79 
     80   # disable wifi and open some ports
     81   networking = {
     82     hostName = "demiurge";
     83     hostId = "cafebabe";
     84 
     85     wireless.enable = false;
     86 
     87     firewall = {
     88       allowedTCPPorts = [
     89         22
     90         80
     91         443
     92         9943
     93         9944
     94       ];
     95       allowedUDPPorts = [ 9943 9944 51413 51820 ];
     96     };
     97 
     98     interfaces.eth0 = {
     99       ipv4.addresses = [
    100         {
    101           address = "192.168.1.2";
    102           prefixLength = 24;
    103         }
    104       ];
    105     };
    106     defaultGateway = {
    107       address = "192.168.1.1";
    108       interface = "eth0";
    109     };
    110 
    111     # mullvad
    112     wg-quick.interfaces = {
    113       wg0 = {
    114         address = [
    115           "10.68.117.111/32"
    116           "fc00:bbbb:bbbb:bb01::5:756e/128"
    117         ];
    118         privateKeyFile = config.age.secrets.wg0_demiurge.path;
    119 
    120         peers = [
    121           {
    122             allowedIPs = [
    123               "0.0.0.0/0"
    124               "::0/0"
    125             ];
    126             endpoint = "45.134.142.206:51820";
    127             publicKey = "H5t7PsMDnUAHrR8D2Jt3Mh6N6w43WmCzrOHShlEU+zw=";
    128           }
    129         ];
    130       };
    131       wg1 = {
    132         address = [
    133           "10.0.13.2/24"
    134           "fd00:b0ba:cafe:babe::2/64"
    135         ];
    136         privateKeyFile = config.age.secrets.wg1_demiurge.path;
    137         listenPort = 51820;
    138         mtu = 1420;
    139         table = null;
    140         postUp = ''
    141 # IPv4 NAT
    142 iptables -t nat -I POSTROUTING 1 -s 10.0.13.4/32 -o wg0 -j MASQUERADE
    143 # IPv6 NAT
    144 ip6tables -t nat -I POSTROUTING 1 -s fd00:b0ba:cafe:babe::4/128 -o wg0 -j MASQUERADE
    145 
    146 # IPv4 Forwarding Chain
    147 iptables -N WG1-FWD
    148 iptables -I FORWARD 1 -j WG1-FWD
    149 iptables -A WG1-FWD -i wg1 -o wg1 -j ACCEPT
    150 iptables -A WG1-FWD -i wg1 -o wg0 -j ACCEPT
    151 iptables -A WG1-FWD -i wg0 -o wg1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    152 
    153 # IPv6 Forwarding Chain
    154 ip6tables -N WG1-FWD
    155 ip6tables -I FORWARD 1 -j WG1-FWD
    156 ip6tables -A WG1-FWD -i wg1 -o wg1 -j ACCEPT
    157 ip6tables -A WG1-FWD -i wg1 -o wg0 -j ACCEPT
    158 ip6tables -A WG1-FWD -i wg0 -o wg1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
    159         '';
    160         preDown = ''
    161 # IPv4 NAT
    162 iptables -t nat -D POSTROUTING -s 10.0.13.4/32 -o wg0 -j MASQUERADE
    163 # IPv6 NAT
    164 ip6tables -t nat -D POSTROUTING -s fd00:b0ba:cafe:babe::4/128 -o wg0 -j MASQUERADE
    165 
    166 # IPv4 Forwarding Chain
    167 iptables -D FORWARD -j WG1-FWD
    168 iptables -F WG1-FWD
    169 iptables -X WG1-FWD
    170 
    171 # IPv6 Forwarding Chain
    172 ip6tables -D FORWARD -j WG1-FWD
    173 ip6tables -F WG1-FWD
    174 ip6tables -X WG1-FWD
    175         '';
    176 
    177         peers = [
    178           {
    179             # saklas.epistemia
    180             publicKey = "XvRailvccuc7LJIF4aaYM/MLkU4upiprwFlCfBllhl0=";
    181             endpoint = "157.180.125.215:51820";
    182             allowedIPs = [ "10.0.13.1/32" "fd00:b0ba:cafe:babe::1/128" ];
    183             persistentKeepalive = 25;
    184           }
    185           {
    186             # hastur.epistemia
    187             publicKey = "1ketYziRhoUmpbrj/60O5DYbcPacvmEoFQqa/NntSnc=";
    188             allowedIPs = [ "10.0.13.3/32" "fd00:b0ba:cafe:babe::3/128" ];
    189             persistentKeepalive = 25;
    190           }
    191           {
    192             # iphonebob.epistemia
    193             publicKey = "Xn0EmeRZdpMejBgzr98mYtb/2f5O58GAzQLNZV/SS30=";
    194             allowedIPs = [ "10.0.13.4/32" "fd00:b0ba:cafe:babe::4/128" ];
    195             persistentKeepalive = 25;
    196           }
    197           {
    198             # lab.epistemia
    199             publicKey = "iMDEwvXjPAlQH8ZCmP63FM5ICYIFIX5XIyGxjnXoNVE=";
    200             allowedIPs = [ "10.0.13.5/32" "fd00:b0ba:cafe:babe::5/128" ];
    201             persistentKeepalive = 25;
    202           }
    203         ];
    204       };
    205     };
    206   };
    207 
    208   users.users = {
    209     vin.packages = with pkgs; [
    210       alvr
    211       bs-manager
    212       (llama-cpp.packages.x86_64-linux.rocm.override {
    213         useMetalKit = false;
    214         useVulkan = true;
    215       })
    216       #(vllm.override { cudaSupport = false; rocmSupport = true; gpuTargets = [ "gfx906" "gfx1100" ]; })
    217     ];
    218 
    219     radarr.extraGroups = [ "transmission" ];
    220     sonarr.extraGroups = [ "transmission" ];
    221   };
    222 
    223   services = {
    224     # media server
    225     jellyfin = {
    226       enable = true;
    227       openFirewall = true;
    228     };
    229 
    230     lidarr = {
    231       enable = true;
    232       openFirewall = true;
    233     };
    234 
    235     prowlarr = {
    236       enable = true;
    237       openFirewall = true;
    238     };
    239 
    240     radarr = {
    241       enable = true;
    242       openFirewall = true;
    243     };
    244 
    245     sonarr = {
    246       enable = true;
    247       openFirewall = true;
    248     };
    249 
    250     transmission = {
    251       enable = true;
    252 	    package = pkgs.transmission_4;
    253       downloadDirPermissions = "770";
    254       openPeerPorts = true;
    255       user = "vin";
    256 
    257       settings = {
    258         download-dir = "/data_wd/torrents/complete/";
    259         incomplete-dir = "/data_wd/torrents/incomplete/";
    260         incomplete-dir-enabled = true;
    261         peer-port = 51413;
    262         umask = 2;
    263       };
    264     };
    265 
    266     # music streaming to phone
    267     navidrome = {
    268       enable = true;
    269       settings = {
    270         MusicFolder = "/data_wd/music";
    271         EnableInsightsCollector = false;
    272       };
    273     };
    274 
    275     # reverse proxy
    276     nginx = {
    277       enable = true;
    278 
    279       defaultListenAddresses = [
    280         "100.64.0.2"
    281         #"10.0.13.2"
    282         #"fd00:b0ba:cafe:babe::2"
    283       ];
    284 
    285       recommendedGzipSettings = true;
    286       recommendedOptimisation = true;
    287       recommendedProxySettings = true;
    288       recommendedTlsSettings = true;
    289 
    290       virtualHosts = {
    291         "searx.demiurge.epistemia" = {
    292           addSSL = true;
    293           sslCertificate = "/var/demiurge.epistemia.crt";
    294           sslCertificateKey = "/var/demiurge.epistemia.key";
    295           locations."/".proxyPass = "http://127.0.0.1:8081";
    296         };
    297 
    298         "redlib.demiurge.epistemia" = {
    299           addSSL = true;
    300           sslCertificate = "/var/demiurge.epistemia.crt";
    301           sslCertificateKey = "/var/demiurge.epistemia.key";
    302           locations."/".proxyPass = "http://127.0.0.1:8085";
    303         };
    304 
    305         "navidrome.demiurge.epistemia" = {
    306           addSSL = true;
    307           sslCertificate = "/var/demiurge.epistemia.crt";
    308           sslCertificateKey = "/var/demiurge.epistemia.key";
    309           locations."/".proxyPass = "http://127.0.0.1:4533";
    310         };
    311 
    312         "sdui.demiurge.epistemia" = {
    313           addSSL = true;
    314           sslCertificate = "/var/demiurge.epistemia.crt";
    315           sslCertificateKey = "/var/demiurge.epistemia.key";
    316           locations."/" = {
    317             proxyPass = "http://127.0.0.1:7860";
    318             proxyWebsockets = true;
    319           };
    320         };
    321       };
    322     };
    323 
    324     # ssh
    325     openssh.listenAddresses = [
    326       { addr = "127.0.0.1"; port = 22; }
    327       { addr = "192.168.1.2"; port = 22; }
    328       { addr = "10.0.13.2"; port = 22; }
    329     ];
    330 
    331     # reddit
    332     redlib = {
    333       enable = true;
    334 
    335       address = "127.0.0.1";
    336       port = 8085;
    337 
    338       settings = {
    339         # Instance-specific settings
    340         # Enable SFW-only mode for the instance
    341         REDLIB_SFW_ONLY = false;
    342         # Set a banner message for the instance
    343         REDLIB_BANNER = "";
    344         # Disable search engine indexing
    345         REDLIB_ROBOTS_DISABLE_INDEXING = true;
    346         # Set the Pushshift frontend for "removed" links
    347         REDLIB_PUSHSHIFT_FRONTEND = "undelete.pullpush.io";
    348 
    349         # Default user settings
    350         # Set the default theme (options: system, light, dark, black, dracula, nord, laserwave, violet, gold, rosebox, gruvboxdark, gruvboxlight)
    351         REDLIB_DEFAULT_THEME = "black";
    352         # Set the default front page (options: default, popular, all)
    353         REDLIB_DEFAULT_FRONT_PAGE = "default";
    354         # Set the default layout (options: card, clean, compact)
    355         REDLIB_DEFAULT_LAYOUT = "compact";
    356         # Enable wide mode by default
    357         REDLIB_DEFAULT_WIDE = true;
    358         # Set the default post sort method (options: hot, new, top, rising, controversial)
    359         REDLIB_DEFAULT_POST_SORT = "hot";
    360         # Set the default comment sort method (options: confidence, top, new, controversial, old)
    361         REDLIB_DEFAULT_COMMENT_SORT = "confidence";
    362         # Enable blurring Spoiler content by default
    363         REDLIB_DEFAULT_BLUR_SPOILER = false;
    364         # Enable showing NSFW content by default
    365         REDLIB_DEFAULT_SHOW_NSFW = false;
    366         # Enable blurring NSFW content by default
    367         REDLIB_DEFAULT_BLUR_NSFW = false;
    368         # Enable HLS video format by default
    369         REDLIB_DEFAULT_USE_HLS = false;
    370         # Hide HLS notification by default
    371         REDLIB_DEFAULT_HIDE_HLS_NOTIFICATION = false;
    372         # Disable autoplay videos by default
    373         REDLIB_DEFAULT_AUTOPLAY_VIDEOS = false;
    374         # Define a default list of subreddit subscriptions (format: sub1+sub2+sub3)
    375         REDLIB_DEFAULT_SUBSCRIPTIONS = "ergomechkeyboards+localllama+elitedangerous";
    376         # Define a default list of subreddit filters (format: sub1+sub2+sub3)
    377         REDLIB_DEFAULT_FILTERS = "popular+all+funny+memes";
    378         # Hide awards by default
    379         REDLIB_DEFAULT_HIDE_AWARDS = true;
    380         # Hide sidebar and summary
    381         REDLIB_DEFAULT_HIDE_SIDEBAR_AND_SUMMARY = false;
    382         # Disable the confirmation before visiting Reddit
    383         REDLIB_DEFAULT_DISABLE_VISIT_REDDIT_CONFIRMATION = false;
    384         # Hide score by default
    385         REDLIB_DEFAULT_HIDE_SCORE = false;
    386         # Enable fixed navbar by default
    387         REDLIB_DEFAULT_FIXED_NAVBAR = true;
    388       };
    389     };
    390 
    391     # searching
    392     searx = {
    393       enable = true;
    394 
    395       settings = {
    396         use_default_settings = false;
    397         general.debug = true;
    398 
    399         search.default_lang = "en";
    400 
    401         server = {
    402           base_url = "https://searx.demiurge.epistemia";
    403           bind_address = "127.0.0.1";
    404           port = 8081;
    405           secret_key = "sJ8oFeH9sC+wriftl2DqVaPC0QDoBDBpqrcOw4Ixw1M=";
    406         };
    407 
    408         ui.theme_args.simple_style = "dark";
    409 
    410         enabled_plugins = [
    411           "Hostnames plugin"
    412           "Open Access DOI rewrite"
    413           "Tracker URL remover"
    414         ];
    415 
    416         hostnames = {
    417           replace = {
    418             "(.*\.)?youtube\.com$" = "yewtu.be";
    419             "(.*\.)?youtu\.be$" = "yewtu.be";
    420             "(.*\.)?reddit\.com$" = "redlib.demiurge.epistemia";
    421             "(.*\.)?redd\.it$" = "redlib.demiurge.epistemia";
    422           };
    423 
    424           remove = [
    425             "geeksforgeeks.org"
    426             "tutorialpoint.com"
    427             "chegg.com"
    428             "numerade.com"
    429             "study.com"
    430           ];
    431         };
    432 
    433         engines = [
    434           {
    435             name = "arch linux wiki";
    436             engine = "archlinux";
    437             shortcut = "al";
    438             categories = "it";
    439           }
    440 
    441           {
    442             name = "arxiv";
    443             engine = "arxiv";
    444             shortcut = "arx";
    445             timeout = 4.0;
    446             categories = "science";
    447           }
    448 
    449           {
    450             name = "wikipedia";
    451             engine = "wikipedia";
    452             shortcut = "wp";
    453             # add "list" to the array to get results in the results list
    454             display_type = "infobox";
    455             categories = "general";
    456           }
    457 
    458           {
    459             name = "btdigg";
    460             engine = "btdigg";
    461             shortcut = "bt";
    462             categories = "files";
    463           }
    464 
    465           {
    466             name = "cppreference";
    467             engine = "cppreference";
    468             shortcut = "cpp";
    469             paging = false;
    470             categories = "it";
    471           }
    472 
    473           {
    474             name = "free software directory";
    475             engine = "mediawiki";
    476             shortcut = "fsd";
    477             categories = [
    478               "it"
    479               "software wikis"
    480             ];
    481             base_url = "https://directory.fsf.org/";
    482             search_type = "title";
    483             timeout = 5.0;
    484             about = {
    485               website = "https://directory.fsf.org/";
    486               wikidata_id = "Q2470288";
    487             };
    488           }
    489 
    490           {
    491             name = "gentoo";
    492             engine = "mediawiki";
    493             shortcut = "ge";
    494             categories = [
    495               "it"
    496               "software wikis"
    497             ];
    498             base_url = "https://wiki.gentoo.org/";
    499             api_path = "api.php";
    500             search_type = "text";
    501             timeout = 10;
    502           }
    503 
    504           {
    505             name = "gitlab";
    506             engine = "gitlab";
    507             base_url = "https://gitlab.com";
    508             shortcut = "gl";
    509             about = {
    510               website = "https://gitlab.com/";
    511               wikidata_id = "Q16639197";
    512             };
    513           }
    514 
    515           {
    516             name = "github";
    517             engine = "github";
    518             shortcut = "gh";
    519           }
    520 
    521           {
    522             name = "codeberg";
    523             # https://docs.searxng.org/dev/engines/online/gitea.html
    524             engine = "gitea";
    525             base_url = "https://codeberg.org";
    526             shortcut = "cb";
    527           }
    528 
    529           {
    530             name = "gitea.com";
    531             engine = "gitea";
    532             base_url = "https://gitea.com";
    533             shortcut = "gitea";
    534           }
    535 
    536           {
    537             name = "google images";
    538             engine = "google_images";
    539             shortcut = "goi";
    540           }
    541 
    542           {
    543             name = "google scholar";
    544             engine = "google_scholar";
    545             shortcut = "gos";
    546           }
    547 
    548           {
    549             name = "invidious";
    550             engine = "invidious";
    551             base_url = [
    552               "https://invidious.demiurge.epistemia"
    553             ];
    554             shortcut = "iv";
    555             timeout = 3.0;
    556           }
    557 
    558           {
    559             name = "library genesis";
    560             engine = "xpath";
    561             search_url = "https://libgen.is/search.php?req={query}";
    562             url_xpath = "//a[contains(@href,\"book/index.php?md5\")]/@href";
    563             title_xpath = "//a[contains(@href,\"book/\")]/text()[1]";
    564             content_xpath = "//td/a[1][contains(@href,\"=author\")]/text()";
    565             categories = "files";
    566             timeout = 7.0;
    567             shortcut = "lg";
    568             about = {
    569               website = "https://libgen.fun/";
    570               wikidata_id = "Q22017206";
    571               official_api_documentation = "";
    572               use_official_api = false;
    573               require_api_key = false;
    574               results = "HTML";
    575             };
    576           }
    577 
    578           {
    579             name = "z-library";
    580             engine = "zlibrary";
    581             shortcut = "zlib";
    582             categories = "files";
    583             timeout = 7.0;
    584           }
    585 
    586           {
    587             name = "nyaa";
    588             engine = "nyaa";
    589             shortcut = "nt";
    590           }
    591 
    592           {
    593             name = "openlibrary";
    594             engine = "openlibrary";
    595             shortcut = "ol";
    596             timeout = 5;
    597           }
    598 
    599           {
    600             name = "stackoverflow";
    601             engine = "stackexchange";
    602             shortcut = "st";
    603             api_site = "stackoverflow";
    604             categories = [
    605               "it"
    606               "q&a"
    607             ];
    608           }
    609 
    610           {
    611             name = "askubuntu";
    612             engine = "stackexchange";
    613             shortcut = "ubuntu";
    614             api_site = "askubuntu";
    615             categories = [
    616               "it"
    617               "q&a"
    618             ];
    619           }
    620 
    621           {
    622             name = "superuser";
    623             engine = "stackexchange";
    624             shortcut = "su";
    625             api_site = "superuser";
    626             categories = [
    627               "it"
    628               "q&a"
    629             ];
    630           }
    631 
    632           {
    633             name = "nixos.discourse";
    634             engine = "discourse";
    635             shortcut = "dnos";
    636             base_url = "https://discourse.nixos.org";
    637             categories = [
    638               "it"
    639               "q&a"
    640             ];
    641           }
    642 
    643           {
    644             name = "unsplash";
    645             engine = "unsplash";
    646             shortcut = "us";
    647           }
    648 
    649           {
    650             name = "wiby";
    651             engine = "json_engine";
    652             paging = true;
    653             weight = 0.5;
    654             search_url = "https://wiby.me/json/?q={query}&p={pageno}";
    655             url_query = "URL";
    656             title_query = "Title";
    657             content_query = "Snippet";
    658             categories = [
    659               "general"
    660               "web"
    661             ];
    662             shortcut = "wib";
    663             about.website = "https://wiby.me/";
    664           }
    665 
    666           {
    667             name = "wikibooks";
    668             engine = "mediawiki";
    669             weight = 0.5;
    670             shortcut = "wb";
    671             categories = [
    672               "general"
    673               "wikimedia"
    674             ];
    675             base_url = "https://{language}.wikibooks.org/";
    676             search_type = "text";
    677             about = {
    678               website = "https://www.wikibooks.org/";
    679               wikidata_id = "Q367";
    680             };
    681           }
    682 
    683           {
    684             name = "wiktionary";
    685             engine = "mediawiki";
    686             shortcut = "wt";
    687             categories = [
    688               "dictionaries"
    689               "wikimedia"
    690             ];
    691             base_url = "https://{language}.wiktionary.org/";
    692             search_type = "text";
    693             about = {
    694               website = "https://www.wiktionary.org/";
    695               wikidata_id = "Q151";
    696             };
    697           }
    698 
    699           {
    700             name = "wikiversity";
    701             engine = "mediawiki";
    702             weight = 0.5;
    703             shortcut = "wv";
    704             categories = [
    705               "general"
    706               "wikimedia"
    707             ];
    708             base_url = "https://{language}.wikiversity.org/";
    709             search_type = "text";
    710             about = {
    711               website = "https://www.wikiversity.org/";
    712               wikidata_id = "Q370";
    713             };
    714           }
    715 
    716           {
    717             name = "peertube";
    718             engine = "peertube";
    719             shortcut = "ptb";
    720             paging = true;
    721             # alternatives see = "https://instances.joinpeertube.org/instances
    722             # base_url = "https://tube.4aem.com
    723             categories = "videos";
    724             timeout = 6.0;
    725           }
    726 
    727           {
    728             name = "brave";
    729             engine = "brave";
    730             shortcut = "br";
    731             time_range_support = true;
    732             paging = true;
    733             categories = [
    734               "general"
    735               "web"
    736             ];
    737             brave_category = "search";
    738           }
    739 
    740           {
    741             name = "brave.images";
    742             engine = "brave";
    743             network = "brave";
    744             shortcut = "brimg";
    745             categories = [
    746               "images"
    747               "web"
    748             ];
    749             brave_category = "images";
    750           }
    751 
    752           {
    753             name = "sourcehut";
    754             shortcut = "srht";
    755             engine = "xpath";
    756             paging = true;
    757             search_url = "https://sr.ht/projects?page={pageno}&search={query}";
    758             results_xpath = "(//div[@class=\"event-list\"])[1]/div[@class=\"event\"]";
    759             url_xpath = "./h4/a[2]/@href";
    760             title_xpath = "./h4/a[2]";
    761             content_xpath = "./p";
    762             first_page_num = 1;
    763             categories = [
    764               "it"
    765               "repos"
    766             ];
    767             about = {
    768               website = "https://sr.ht";
    769               wikidata_id = "Q78514485";
    770               official_api_documentation = "https://man.sr.ht/";
    771               use_official_api = false;
    772               require_api_key = false;
    773               results = "HTML";
    774             };
    775           }
    776         ];
    777 
    778         doi_resolvers = {
    779           "oadoi.org" = "https://oadoi.org/";
    780           "doi.org" = "https://doi.org/";
    781           "sci-hub.se" = "https://sci-hub.se/";
    782           "sci-hub.st" = "https://sci-hub.st/";
    783           "sci-hub.ru" = "https://sci-hub.ru/";
    784         };
    785 
    786         default_doi_resolver = "sci-hub.st";
    787       };
    788     };
    789 
    790     # udev rules
    791     udev = {
    792       enable = true;
    793       extraRules = ''
    794         # Oculus Quest 2
    795         SUBSYSTEM=="usb", ATTR{idVendor}=="2833", ATTR{idProduct}=="0186", MODE="0660",
    796         GROUP="input", SYMLINK+="ocuquest%n"
    797       '';
    798     };
    799   };
    800 
    801   system.stateVersion = "24.05";
    802 }