diff options
Diffstat (limited to 'nixos')
46 files changed, 1921 insertions, 1231 deletions
diff --git a/nixos/configurations/adm-mpd.nix b/nixos/configurations/adm-mpd.nix deleted file mode 100644 index ac3b4de..0000000 --- a/nixos/configurations/adm-mpd.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ - config, - lib, - ... -}: let - inherit (lib) filterAttrs; -in { - nixpkgs.hostPlatform.system = "aarch64-linux"; - - fileSystems = { - "/" = { - device = "/dev/mmcblk0p2"; - options = ["compress=lzo" "subvol=@nix"]; - }; - "/home" = { - device = "/dev/mmcblk0p2"; - options = ["compress=lzo" "subvol=@home"]; - }; - "/boot" = { - device = "/dev/mmcblk0p1"; - }; - }; - - networking.wireless = { - enable = true; - networks = filterAttrs (n: _: n == "Nela") config.secrets.wifiNetworks; - environmentFile = "/run/secrets/wifi.env"; - userControlled.enable = true; - }; - - #services.pipewire = { - #enable = true; - #alsa.enable = true; - #pulse.enable = true; - #}; - hardware.pulseaudio = { - enable = true; - systemWide = true; - zeroconf.publish.enable = true; - }; - - services.spotifyd = { - enable = true; - settings.global = { - device_name = "Adámkovi"; - device = "sysdefault"; - mixer = "Master"; - bitrate = 320; - cache_path = "/var/cahe/spotify"; - no_audio_cache = true; - volume_normalisation = true; - normalisation_pregain = -10; - initial_volume = 60; - }; - }; -} diff --git a/nixos/configurations/adm-omnia.nix b/nixos/configurations/adm-omnia.nix index 069dfb0..6df1098 100644 --- a/nixos/configurations/adm-omnia.nix +++ b/nixos/configurations/adm-omnia.nix @@ -1,10 +1,13 @@ {config, ...}: let hosts = config.cynerd.hosts.adm; in { + system.stateVersion = "24.05"; + turris.board = "omnia"; deploy = { - enable = false; - ssh.host = "omnia.adm"; + enable = true; + ssh.host = "adm.cynerd.cz"; + configurationLimit = 16; }; cynerd = { @@ -13,51 +16,55 @@ in { wan = "pppoe-wan"; lanIP = hosts.omnia; staticLeases = { - "70:85:c2:4a:59:f2" = hosts.ridcully; - "7c:b0:c2:bb:9c:ca" = hosts.albert; "4c:d5:77:0d:85:d9" = hosts.binky; - "b8:27:eb:49:54:5a" = hosts.mpd; - }; - guestStaticLeases = { "f4:a9:97:a4:bd:59" = hosts.printer; }; }; wifiAP.adm = { - enable = false; + enable = true; ar9287 = { - interface = "wlp1s0"; - bssids = ["04:f0:21:23:3d:ce" "08:f0:21:23:3d:ce" "0c:f0:21:23:3d:ce"]; - channel = 11; + interface = "wlp2s0"; + bssids = config.secrets.wifiMacs.adm-omnia.ar9287; + channel = 7; }; qca988x = { - interface = "wlp3s0"; - bssids = ["04:f0:21:24:0b:4e" "08:f0:21:24:0b:4e" "0c:f0:21:24:0b:4e"]; - channel = 36; + interface = "wlp1s0"; + bssids = config.secrets.wifiMacs.adm-omnia.qca988x; + channel = 44; }; }; wireguard = true; monitoring.speedtest = true; }; - services.journald.extraConfig = '' - SystemMaxUse=8G - ''; + services = { + journald.settings.Journal = { + SystemMaxUse = "8G"; + }; - services.btrfs.autoScrub = { - enable = true; - fileSystems = ["/"]; - }; + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; - networking = { - useNetworkd = true; - useDHCP = false; + fail2ban = { + enable = true; + ignoreIP = ["10.8.0.0/24" "10.8.1.0/24"]; + }; }; + + # Warning: This Omnia has broker WAN port thus LAN4 is used for WAN!!!!!!!! + networking.useDHCP = false; systemd.network = { networks = { + "lan4" = { + matchConfig.Name = "lan4"; # Ensure that it is managed by systemd-networkd + networkConfig.IPv6AcceptRA = false; + }; "pppoe-wan" = { matchConfig.Name = "pppoe-wan"; networkConfig = { - BindCarrier = "end2"; + BindCarrier = "lan4"; DHCP = "ipv6"; IPv6AcceptRA = "no"; DHCPPrefixDelegation = "yes"; @@ -75,7 +82,7 @@ in { linkConfig.RequiredForOnline = "routable"; }; "lan-brlan" = { - matchConfig.Name = "lan[1-4]"; + matchConfig.Name = "lan0 lan1 lan2 lan3"; networkConfig.Bridge = "brlan"; bridgeVLANs = [ { @@ -85,23 +92,13 @@ in { {VLAN = 2;} ]; }; - "lan-guest" = { - matchConfig.Name = "lan0"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; }; }; services.pppd = { enable = true; peers."wan".config = '' - plugin pppoe.so end2 + plugin pppoe.so lan4 ifname pppoe-wan lcp-echo-interval 1 lcp-echo-failure 5 @@ -114,10 +111,21 @@ in { password 02 ''; }; - systemd.services."pppd-wan".after = ["sys-subsystem-net-devices-end2.device"]; + systemd.services = { + "pppd-wan" = { + after = ["sys-subsystem-net-devices-lan4.device"]; + partOf = ["systemd-networkd.service"]; + serviceConfig = { + Restart = "always"; + StartLimitBurst = 0; + }; + }; + "systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug"; + }; # TODO limit NSS clamping to just pppoe-wan networking.firewall.extraForwardRules = '' tcp flags syn tcp option maxseg size set rt mtu comment "Needed for PPPoE to fix IPv4" - iifname {"home", "personalvpn", "wg"} oifname {"home", "personalvpn", "wg"} accept + iifname "wg" oifname "home" accept + iifname "home" oifname "guest" accept comment "Allow home to access guest devices" ''; } diff --git a/nixos/configurations/adm-omnia2.nix b/nixos/configurations/adm-omnia2.nix index 45b8dc4..317ee62 100644 --- a/nixos/configurations/adm-omnia2.nix +++ b/nixos/configurations/adm-omnia2.nix @@ -1,8 +1,11 @@ {config, ...}: { + system.stateVersion = "24.05"; + turris.board = "omnia"; deploy = { enable = true; ssh.host = "omnia2.adm"; + configurationLimit = 16; }; cynerd = { @@ -15,24 +18,26 @@ enable = true; ar9287 = { interface = "wlp2s0"; - bssids = ["12:f0:21:23:2b:00" "12:f0:21:23:2b:01" "12:f0:21:23:2b:02"]; + bssids = config.secrets.wifiMacs.adm-omnia2.ar9287; channel = 11; }; qca988x = { interface = "wlp1s0"; - bssids = ["12:f0:21:23:2b:03" "12:f0:21:23:2b:04" "12:f0:21:23:2b:05"]; + bssids = config.secrets.wifiMacs.adm-omnia2.qca988x; channel = 36; }; }; }; - services.journald.extraConfig = '' - SystemMaxUse=8G - ''; + services = { + journald.settings.Journal = { + SystemMaxUse = "8G"; + }; - services.btrfs.autoScrub = { - enable = true; - fileSystems = ["/"]; + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; }; networking = { diff --git a/nixos/configurations/albert.nix b/nixos/configurations/albert.nix deleted file mode 100644 index a6a4ee1..0000000 --- a/nixos/configurations/albert.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ - nixpkgs.hostPlatform.system = "x86_64-linux"; - - cynerd = { - desktop = { - enable = true; - laptop = true; - }; - wifiClient = true; - openvpn = { - oldpersonal = true; - }; - }; - - boot.initrd.availableKernelModules = ["xhci_pci" "usb_storage" "sd_mod"]; - - hardware.cpu.intel.updateMicrocode = true; - - fileSystems = { - "/" = { - device = "/dev/disk/by-uuid/1c9bafac-fcf8-41c4-b394-bca5917ca82d"; - fsType = "btrfs"; - options = ["compress=lzo" "subvol=@nix"]; - }; - "/home" = { - device = "/dev/disk/by-uuid/1c9bafac-fcf8-41c4-b394-bca5917ca82d"; - fsType = "btrfs"; - options = ["compress=lzo" "subvol=@home"]; - }; - "/boot" = { - device = "/dev/disk/by-uuid/E403-124B"; - fsType = "vfat"; - }; - - "/home2" = { - device = "/dev/disk/by-uuid/55e177a1-215e-475b-ba9c-771b5fa3f8f0"; - fsType = "btrfs"; - options = ["compress=lzo" "subvol=@home"]; - }; - }; -} diff --git a/nixos/configurations/binky.nix b/nixos/configurations/binky.nix index 7765d01..f4f82fb 100644 --- a/nixos/configurations/binky.nix +++ b/nixos/configurations/binky.nix @@ -1,15 +1,10 @@ -{ - lib, - pkgs, - ... -}: let - inherit (lib) mkDefault; -in { +{lib, ...}: { + system.stateVersion = "24.05"; nixpkgs.hostPlatform.system = "x86_64-linux"; deploy = { enable = true; default = false; - ssh.host = "binky.spt"; + ssh.host = "binky"; }; cynerd = { @@ -19,6 +14,7 @@ in { }; wifiClient = true; develop = true; + gaming = true; wireguard = true; openvpn.elektroline = true; }; @@ -88,16 +84,8 @@ in { services.syncthing = { enable = true; - user = mkDefault "cynerd"; - group = mkDefault "cynerd"; - openDefaultPorts = true; - - overrideDevices = false; - overrideFolders = false; - dataDir = "/home/cynerd"; - configDir = "/home/cynerd/.config/syncthing"; }; - environment.systemPackages = [pkgs.heroic]; + programs.steam.enable = lib.mkForce false; } diff --git a/nixos/configurations/dean.nix b/nixos/configurations/dean.nix index 187e148..a1ec788 100644 --- a/nixos/configurations/dean.nix +++ b/nixos/configurations/dean.nix @@ -1,8 +1,17 @@ -{pkgs, ...}: { +{ + lib, + pkgs, + ... +}: { + system.stateVersion = "24.05"; turris.board = "mox"; - deploy.enable = true; + deploy = { + enable = true; + configurationLimit = 8; + }; cynerd = { + devmin = true; wireguard = true; monitoring = { speedtest = true; @@ -10,6 +19,20 @@ }; }; + boot.initrd.availableKernelModules = ["dm-mod"]; + + hardware.enableAllFirmware = false; # No wifi so we do not need firmwares + services = { + journald.settings.Journal = { + SystemMaxUse = "512M"; + }; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; + }; + networking = { useNetworkd = true; useDHCP = false; @@ -39,5 +62,29 @@ environment.systemPackages = with pkgs; [ #openocd tio + gnupg + ]; + + programs = { + fuse = { + enable = true; + userAllowOther = true; + }; + nix-ld.enable = true; + }; + boot.binfmt = { + emulatedSystems = ["x86_64-linux"]; + }; + environment.sessionVariables = { + NIX_LD_x86_64_linux = "${pkgs.buildPackages.glibc}/lib/ld-linux-x86-64.so.2"; + NIX_LD_LIBRARY_PATH_x86_64_linux = lib.makeLibraryPath (with pkgs.buildPackages; [ + stdenv.cc.cc + glibc + zlib + ]); + }; + systemd.tmpfiles.rules = [ + "d /lib64 0755 root root -" + "L+ /lib64/ld-linux-x86-64.so.2 - - - - ${pkgs.buildPackages.nix-ld}/libexec/nix-ld" ]; } diff --git a/nixos/configurations/dribbler.nix b/nixos/configurations/dribbler.nix new file mode 100644 index 0000000..038f455 --- /dev/null +++ b/nixos/configurations/dribbler.nix @@ -0,0 +1,112 @@ +{pkgs, ...}: { + system.stateVersion = "25.11"; + nixpkgs.hostPlatform.system = "x86_64-linux"; + deploy = { + enable = true; + default = false; + ssh.host = "dribbler"; + }; + + cynerd = { + wifiClient = true; + }; + + boot = { + initrd.availableKernelModules = ["nvme" "xhci_pci" "usb_storage" "sd_mod"]; + kernelModules = ["kvm-intel"]; + kernelParams = ["video=eDP-1:d"]; # Disable internal display for kodi to use HDMI + }; + + hardware.cpu.intel.updateMicrocode = true; + + cynerd.autounlock = { + "encroot" = "/dev/disk/by-uuid/f791f524-0552-487b-9bf9-5c20ca78651b"; + }; + fileSystems = { + "/" = { + device = "/dev/mapper/encroot"; + fsType = "btrfs"; + options = ["compress=lzo"]; + }; + "/boot" = { + device = "/dev/disk/by-uuid/7143-1EE7"; + fsType = "vfat"; + }; + }; + services.btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; + + networking = { + useNetworkd = true; + useDHCP = false; + }; + systemd.network = { + networks = { + "dhcp" = { + matchConfig.Name = "enp1s0"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = "yes"; + }; + linkConfig.RequiredForOnline = "routable"; + }; + "dhcp-wlan" = { + matchConfig.Name = "wlp2s0"; + networkConfig = { + DHCP = "yes"; + IPv6AcceptRA = "yes"; + }; + routes = [{Metric = 1088;}]; + linkConfig.RequiredForOnline = "routable"; + }; + }; + wait-online.enable = false; + }; + + # Kodi + environment.systemPackages = with pkgs; [ + kodi-gbm + ]; + hardware = { + graphics = { + enable = true; + enable32Bit = true; + extraPackages = with pkgs; [ + intel-media-driver + libvdpau-va-gl + ]; + }; + bluetooth.enable = true; + }; + services.pipewire = { + enable = true; + alsa.enable = true; + alsa.support32Bit = true; + pulse.enable = true; + }; + security.rtkit.enable = true; + #nixpkgs.config.kodi.enableAdvancedLauncher = true; + users.extraUsers.kodi = { + isNormalUser = true; + extraGroups = ["audio" "video" "input"]; + }; + systemd.services.kodi = { + description = "Kodi standalone (GBM)"; + wantedBy = ["multi-user.target"]; + conflicts = ["getty@tty1.service"]; + serviceConfig = { + User = "kodi"; + TTYPath = "/dev/tty1"; + ExecStart = "${pkgs.kodi-gbm}/bin/kodi-standalone"; + Restart = "on-abort"; + StandardInput = "tty"; + StandardOutput = "journal"; + }; + }; + networking.firewall = { + allowedTCPPorts = [8080]; + allowedUDPPorts = [8080]; + }; +} diff --git a/nixos/configurations/errol.nix b/nixos/configurations/errol.nix index fd348e8..e45fae5 100644 --- a/nixos/configurations/errol.nix +++ b/nixos/configurations/errol.nix @@ -1,31 +1,24 @@ -{ - config, - lib, - pkgs, - ... -}: let - inherit (lib) mkDefault; -in { +{pkgs, ...}: { + system.stateVersion = "24.05"; nixpkgs.hostPlatform.system = "x86_64-linux"; deploy.enable = true; - cynerd = { - desktop.enable = true; - develop = true; - gaming = true; - openvpn.elektroline = true; - }; - boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "usb_storage"]; boot.kernelModules = ["kvm-amd"]; hardware.cpu.amd.updateMicrocode = true; services.hardware.openrgb.motherboard = "amd"; + zramSwap = { + enable = true; + memoryPercent = 50; + }; + cynerd.autounlock = { "encroot" = "/dev/disk/by-uuid/7c412ae6-6016-45af-8c2a-8fcc394dbbe6"; "enchdd1" = "/dev/disk/by-uuid/87f16080-5ff6-43dd-89f3-307455a46fbe"; "enchdd2" = "/dev/disk/by-uuid/be4a33fa-8bc6-431d-a3ac-787668f223ed"; + #"encback" = "/dev/disk/by-uuid/1bd8c637-f71e-4fb0-96de-b660c4f1afaf"; }; fileSystems = { "/" = { @@ -53,6 +46,11 @@ in { fsType = "btrfs"; options = ["compress=lzo" "subvol=@home"]; }; + #"/back" = { + # device = "/dev/mapper/encback"; + # fsType = "btrfs"; + # options = ["compress=lzo"]; + #}; }; services.btrfs.autoScrub = { enable = true; @@ -83,75 +81,11 @@ in { pkgs.nvtopPackages.amd ]; - services.syncthing = { - enable = true; - user = mkDefault "cynerd"; - group = mkDefault "cynerd"; - openDefaultPorts = true; - - overrideDevices = false; - overrideFolders = false; - - dataDir = "/home/cynerd"; - configDir = "/home/cynerd/.config/syncthing"; - }; - - nixpkgs.config.permittedInsecurePackages = ["openssl-1.1.1w"]; # TODO - services.home-assistant = { - enable = true; - openFirewall = true; - configDir = "/var/lib/hass"; - config = { - homeassistant = { - name = "SPT"; - latitude = "!secret latitude"; - longitude = "!secret longitude"; - elevation = "!secret elevation"; - time_zone = "Europe/Prague"; - country = "CZ"; - }; - http.server_port = 8808; - mqtt = { - sensor = import ../modules/home-assistant/sensors.nix; - light = import ../modules/home-assistant/light.nix; - }; - default_config = {}; - automation = "!include automations.yaml"; - }; - extraComponents = ["met"]; - package = pkgs.home-assistant.override { - extraPackages = pkgs: - with pkgs; [ - securetar - pyipp - ]; - }; - }; - - services.zigbee2mqtt = { - enable = true; - settings = { - serial.port = "/dev/serial/by-id/usb-ITEAD_SONOFF_Zigbee_3.0_USB_Dongle_Plus_V2_20220812153849-if00"; - mqtt = { - server = "mqtt://${config.cynerd.hosts.spt.mox}:1883"; - user = "zigbee2mqtt"; - password = "!secret.yaml mqtt_password"; - }; - advanced = { - network_key = "!secret.yaml network_key"; - homeassistant_legacy_entity_attributes = false; - legacy_api = false; - legacy_availability_payload = false; - last_seen = "epoch"; - }; - frontend = true; - availability = true; - homeassistant = { - legacy_triggers = false; - }; - device_options.legacy = false; - permit_join = false; - devices = config.secrets.zigbee2mqttDevices; + ############################################################################## + services = { + syncthing = { + enable = true; + dataDir = "/home/cynerd"; }; }; } diff --git a/nixos/configurations/gaspode.nix b/nixos/configurations/gaspode.nix deleted file mode 100644 index 78d8277..0000000 --- a/nixos/configurations/gaspode.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ - nixpkgs.hostPlatform.system = "armv7l-linux"; - - fileSystems = { - "/" = { - device = "/dev/mmcblk0p2"; - options = ["compress=lzo" "subvol=@nix"]; - }; - "/home" = { - device = "/dev/mmcblk0p2"; - options = ["compress=lzo" "subvol=@home"]; - }; - "/boot" = { - device = "/dev/mmcblk0p1"; - }; - }; -} diff --git a/nixos/configurations/lipwig.nix b/nixos/configurations/lipwig.nix index 1a137db..e0992f2 100644 --- a/nixos/configurations/lipwig.nix +++ b/nixos/configurations/lipwig.nix @@ -2,11 +2,13 @@ config, pkgs, inputModules, + lib, ... }: { imports = [inputModules.vpsadminos]; config = { + system.stateVersion = "24.05"; nixpkgs.hostPlatform.system = "x86_64-linux"; deploy = { @@ -19,12 +21,15 @@ hw = false; drives = false; }; - syncthing = { - enable = false; - baseDir = "/nas"; - }; wireguard = true; - openvpn.oldpersonal = true; + borgjobs = { + # TODO backup influx + postgresql.dumpCommand = pkgs.writeScript "postgreqsl-backup.sh" '' + /run/wrappers/bin/sudo -u postgres /run/current-system/sw/bin/pg_dumpall + ''; + nextcloud_data.paths = "/nas/nextcloud/data"; + sync_data.paths = "/sync"; + }; }; boot.loader.systemd-boot.enable = false; @@ -39,24 +44,10 @@ ]; }; "/nas/nextcloud-sync" = { - device = "/nas/sync"; + device = "/sync"; fsType = "fuse.bindfs"; options = ["map=syncthing/nextcloud:@syncthing/@nextcloud"]; }; - "/nas/spt" = { - device = "nas@omnia.spt:/data/nas"; - fsType = "fuse.sshfs"; - options = [ - "allow_other" - "_netdev" - "x-systemd.automount" - "reconnect" - "identityfile=/run/secrets/nas.ssh.priv" - "idmap=user" - "uid=nextcloud" - "gid=nextcloud" - ]; - }; }; networking = { @@ -84,68 +75,71 @@ ]; # Web ###################################################################### - services.nginx = { - enable = true; - virtualHosts = { - "cynerd.cz" = { - forceSSL = true; - enableACME = true; - locations = { - "/".root = ../../web; - "/radicale/" = { - proxyPass = "http://127.0.0.1:5232/"; - extraConfig = '' - proxy_set_header X-Script-Name /radicale; - proxy_pass_header Authorization; - ''; + services = { + nginx = { + enable = true; + virtualHosts = { + "cynerd.cz" = { + forceSSL = true; + enableACME = true; + locations = { + "/".root = ../../web; + "/radicale/" = { + proxyPass = "http://127.0.0.1:5232/"; + extraConfig = '' + proxy_set_header X-Script-Name /radicale; + proxy_pass_header Authorization; + ''; + }; }; }; - }; - "git.cynerd.cz" = { - forceSSL = true; - useACMEHost = "cynerd.cz"; - root = "${pkgs.cgit}/cgit"; - locations."/".tryFiles = "$uri @cgit"; - locations."@cgit".extraConfig = '' - fastcgi_pass unix:${config.services.fcgiwrap.instances.cgit.socket.address}; - fastcgi_param SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi; - fastcgi_param PATH_INFO $uri; - fastcgi_param QUERY_STRING $args; - fastcgi_param HTTP_HOST $server_name; - ''; - }; - "cloud.cynerd.cz" = { - forceSSL = true; - useACMEHost = "cynerd.cz"; - }; - "grafana.cynerd.cz" = { - forceSSL = true; - useACMEHost = "cynerd.cz"; - locations."/" = { - proxyPass = "http://127.0.0.1:${toString config.services.grafana.settings.server.http_port}/"; - extraConfig = "proxy_set_header Host $host;"; - proxyWebsockets = true; + "git.cynerd.cz" = { + forceSSL = true; + useACMEHost = "cynerd.cz"; + root = "${pkgs.cgit}/cgit"; + locations."/".tryFiles = "$uri @cgit"; + locations."@cgit".extraConfig = '' + fastcgi_pass unix:${config.services.fcgiwrap.instances.cgit.socket.address}; + fastcgi_param SCRIPT_FILENAME ${pkgs.cgit}/cgit/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + ''; + }; + "cloud.cynerd.cz" = { + forceSSL = true; + useACMEHost = "cynerd.cz"; + }; + "grafana.cynerd.cz" = { + forceSSL = true; + useACMEHost = "cynerd.cz"; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; + proxyWebsockets = true; + recommendedProxySettings = true; + }; + }; + "searx.cynerd.cz" = { + forceSSL = true; + useACMEHost = "cynerd.cz"; + locations."/".extraConfig = '' + uwsgi_pass "unix://${config.services.searx.uwsgiConfig.socket}"; + include ${config.services.nginx.package}/conf/uwsgi_params; + ''; }; - }; - "searx.cynerd.cz" = { - forceSSL = true; - useACMEHost = "cynerd.cz"; - locations."/".extraConfig = '' - uwsgi_pass "unix:///run/searx/searx.sock"; - include ${config.services.nginx.package}/conf/uwsgi_params; - ''; }; }; - }; - services.fcgiwrap.instances.cgit = { - process.user = "git"; - socket = {inherit (config.services.nginx) user group;}; + fcgiwrap.instances.cgit = { + process.user = "git"; + socket = {inherit (config.services.nginx) user group;}; + }; }; security.acme = { acceptTerms = true; defaults.email = "cynerd+acme@email.cz"; certs."cynerd.cz".extraDomainNames = [ "cloud.cynerd.cz" + "office.cynerd.cz" "git.cynerd.cz" "grafana.cynerd.cz" "searx.cynerd.cz" @@ -205,7 +199,7 @@ # Nextcloud ################################################################ services.nextcloud = { enable = true; - package = pkgs.nextcloud28; + package = pkgs.nextcloud34; https = true; hostName = "cloud.cynerd.cz"; datadir = "/nas/nextcloud"; @@ -214,11 +208,25 @@ adminpassFile = "/run/secrets/nextcloud.admin.pass"; dbtype = "pgsql"; dbhost = "/run/postgresql"; - dbtableprefix = "oc_"; }; settings = { #log_type = "systemd"; + default_locale = "CZ"; default_phone_region = "CZ"; + default_timezone = "Europe/Prague"; + enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\GIF" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\MP3" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PNG" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + "OC\\Preview\\HEIC" + ]; }; phpExtraExtensions = php: [php.pgsql php.pdo_pgsql]; phpOptions = { @@ -226,59 +234,60 @@ }; maxUploadSize = "1G"; appstoreEnable = false; - extraApps = { - inherit - (config.services.nextcloud.package.packages.apps) - bookmarks - calendar - contacts - cookbook - deck - forms - groupfolders - impersonate - maps - memories - notes - phonetrack - previewgenerator - spreed - tasks - twofactor_nextcloud_notification - twofactor_webauthn - ; - # Additional modules can be fetched with: - # NEXTCLOUD_VERSIONS=28 nix run nixpkgs#nc4nix -- -apps "passwords,integration_homeassistant,integration_github,integration_gitlab" - passwords = pkgs.fetchNextcloudApp { - url = "https://git.mdns.eu/api/v4/projects/45/packages/generic/passwords/2024.7.0/passwords.tar.gz"; - sha256 = "1RwLOE2aUwISMF/WcYmL8sKs+KXBlYv0OHw8PizrGCY="; - license = "agpl3Plus"; - }; - integration_github = pkgs.fetchNextcloudApp { - url = "https://github.com/nextcloud-releases/integration_github/releases/download/v2.0.7/integration_github-v2.0.7.tar.gz"; - sha256 = "x4BrBdrvmbdwZcZL6FLAY27B5OpkXIsw92XsD076Aqg="; - license = "agpl3Plus"; - }; - integration_gitlab = pkgs.fetchNextcloudApp { - url = "https://github.com/nextcloud-releases/integration_gitlab/releases/download/v3.0.1/integration_gitlab-v3.0.1.tar.gz"; - sha256 = "FAF5CHwAVm55QS9NO8B5zsvJ0BWa7Mwfw6kYr2js0Es="; - license = "agpl3Plus"; - }; - }; + extraApps = + { + inherit + (config.services.nextcloud.package.packages.apps) + bookmarks + calendar + contacts + cookbook + deck + forms + groupfolders + impersonate + #maps + memories + notes + phonetrack + previewgenerator + spreed + tasks + twofactor_webauthn + ; + } + // (lib.mapAttrs (n: v: + pkgs.fetchNextcloudApp { + inherit (v) url hash; + license = "agpl3Plus"; + }) + # Additional modules can be fetched with: + # NEXTCLOUD_VERSIONS=33 nix run .#nc4nix -- -apps "passwords,money,integration_github,integration_gitlab,fileslibreofficeedit" + (lib.importJSON ../nextcloud-extra-apps.json)); }; # Postgresql ############################################################### services.postgresql = { enable = true; + enableTCPIP = true; ensureUsers = [ - {name = "cynerd";} + { + name = "cynerd"; + ensureClauses = { + login = true; + createdb = true; + createrole = true; + bypassrls = true; + replication = true; + }; + } { name = "nextcloud"; ensureDBOwnership = true; } ]; - ensureDatabases = ["nextcloud"]; - extraPlugins = ps: with ps; [timescaledb]; + ensureDatabases = ["nextcloud" "monitoring"]; + #extensions = ps: [ps.timescaledb]; }; # SearX #################################################################### @@ -348,7 +357,7 @@ } ]; }; - runInUwsgi = true; + configureUwsgi = true; uwsgiConfig = { socket = "/run/searx/searx.sock"; chmod-socket = "660"; @@ -357,16 +366,12 @@ }; users.groups.searx.members = ["nginx"]; - # Old Syncthing ############################################################ + # Syncthing ################################################################ services.syncthing = { enable = true; - openDefaultPorts = true; - - overrideDevices = false; - overrideFolders = false; - - dataDir = "/nas/sync"; - configDir = "/nas/sync/.syncthing"; + user = "syncthing"; + group = "syncthing"; + dataDir = "/sync"; }; }; } diff --git a/nixos/configurations/ridcully.nix b/nixos/configurations/ridcully.nix index 2be1a7a..e454b2c 100644 --- a/nixos/configurations/ridcully.nix +++ b/nixos/configurations/ridcully.nix @@ -1,10 +1,5 @@ -{ - lib, - pkgs, - ... -}: let - inherit (lib) mkDefault; -in { +{pkgs, ...}: { + system.stateVersion = "24.05"; nixpkgs.hostPlatform.system = "x86_64-linux"; deploy.enable = true; @@ -15,17 +10,26 @@ in { openvpn = { elektroline = true; }; + borgjobs = { + hetzner-s3.paths = "/back/hetzner-s3-sync"; + }; }; - boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "usb_storage"]; + boot.initrd.availableKernelModules = ["nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod"]; boot.kernelModules = ["kvm-amd"]; hardware.cpu.amd.updateMicrocode = true; services.hardware.openrgb.motherboard = "amd"; + zramSwap = { + enable = true; + memoryPercent = 50; + }; + cynerd.autounlock = { "encroot" = "/dev/disk/by-uuid/bc7d2ba4-6e04-4c49-b40c-3aecd1a86c71"; "enchdd" = "/dev/disk/by-uuid/7fee3cda-efa0-47cd-8832-fdead9a7e6db"; + "encback" = "/dev/disk/by-uuid/b426cbe7-fba2-473b-90f9-9ebe3e34b76e"; }; fileSystems = { "/" = { @@ -48,6 +52,11 @@ in { fsType = "btrfs"; options = ["compress=lzo" "subvol=@home"]; }; + "/back" = { + device = "/dev/mapper/encback"; + fsType = "btrfs"; + options = ["compress=lzo"]; + }; }; services.btrfs.autoScrub = { enable = true; @@ -61,28 +70,54 @@ in { systemd.network = { wait-online.enable = false; }; - #networking.vlans."enp6s0.adm" = { - #id = 2; - #interface = "enp6s0"; - #}; environment.systemPackages = [ pkgs.nvtopPackages.amd + #sbctl ]; - services.syncthing = { - enable = true; - user = mkDefault "cynerd"; - group = mkDefault "cynerd"; - openDefaultPorts = true; + # Force nix to use less jobs + nix.settings.max-jobs = 4; + + ############################################################################## + services = { + syncthing = { + enable = true; + dataDir = "/home/cynerd"; + }; - overrideDevices = false; - overrideFolders = false; + #octoprint = { + # enable = true; + # openFirewall = true; + #}; - dataDir = "/home/cynerd"; - configDir = "/home/cynerd/.config/syncthing"; + #mjpg-streamer = { + # enable = true; + # inputPlugin = "input_uvc.so -d /dev/video2 -r 1920x1080 -f 30"; + # outputPlugin = "output_http.so -p 5001 -w @www@"; + #}; }; + networking.firewall.allowedTCPPorts = [5001]; - # Force nix to use less jobs - nix.settings.max-jobs = 8; + # Service to synchronize local copy of Hetzner S3 + systemd = { + services."hetzner-sync" = { + script = '' + /run/current-system/sw/bin/rclone --config /run/secrets/rclone-hetzner.conf \ + sync hetzner: /back/hetzner-s3-sync + ''; + serviceConfig = { + Type = "oneshot"; + User = "root"; + }; + }; + timers."hetzner-sync" = { + wantedBy = ["timers.target"]; + timerConfig.Unit = "hetzner-sync.service"; + timerConfig = { + OnCalendar = "daily"; + Persistent = false; + }; + }; + }; } diff --git a/nixos/configurations/spt-mox.nix b/nixos/configurations/spt-mox.nix index 0bc7627..d1e9208 100644 --- a/nixos/configurations/spt-mox.nix +++ b/nixos/configurations/spt-mox.nix @@ -1,12 +1,17 @@ -{config, ...}: { +{ + config, + pkgs, + ... +}: { + system.stateVersion = "24.05"; turris.board = "mox"; deploy = { enable = true; ssh.host = "mox.spt"; + configurationLimit = 8; }; cynerd = { - home-assistant = true; monitoring.drives = false; switch = { enable = true; @@ -17,19 +22,23 @@ enable = true; qca988x = { interface = "wlp1s0"; - bssids = ["04:f0:21:24:24:d2" "08:f0:21:24:24:d2"]; + bssids = config.secrets.wifiMacs.spt-mox.qca988x; channel = 7; }; }; }; - services.journald.extraConfig = '' - SystemMaxUse=512M - ''; + boot.initrd.availableKernelModules = ["dm-mod"]; - services.btrfs.autoScrub = { - enable = true; - fileSystems = ["/"]; + services = { + journald.settings.Journal = { + SystemMaxUse = "512M"; + }; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; }; networking = { @@ -49,4 +58,104 @@ ]; }; }; + + ############################################################################## + networking.firewall.allowedTCPPorts = [ + 1883 # Mosquitto + ]; + services = { + mosquitto = { + enable = true; + listeners = [ + { + users = { + cynerd = { + acl = ["readwrite #"]; + passwordFile = "/run/secrets/mosquitto.cynerd.pass"; + }; + telegraf = { + acl = ["read bigclown/node/#"]; + passwordFile = "/run/secrets/mosquitto.telegraf.pass"; + }; + bigclown = { + acl = ["readwrite bigclown/#"]; + passwordFile = "/run/secrets/mosquitto.bigclown.pass"; + }; + }; + } + ]; + }; + + telegraf.extraConfig = { + outputs.influxdb_v2 = [ + { + urls = ["http://cynerd.cz:8086"]; + token = "$INFLUX_TOKEN"; + organization = "personal"; + bucket = "bigclown"; + tagpass.source = ["bigclown"]; + } + ]; + inputs.mqtt_consumer = let + consumer = data_type: topics: { + tags = {source = "bigclown";}; + servers = ["tcp://localhost:1883"]; + inherit topics; + username = "telegraf"; + password = "$MQTT_PASSWORD"; + data_format = "value"; + inherit data_type; + topic_parsing = [ + { + topic = "bigclown/node/+/+/+/+"; + measurement = "_/_/_/_/_/measurement"; + tags = "_/_/device/field/_/_"; + } + ]; + }; + in [ + (consumer "float" [ + "bigclown/node/+/battery/+/voltage" + "bigclown/node/+/thermometer/+/temperature" + "bigclown/node/+/hygrometer/+/relative-humidity" + "bigclown/node/+/lux-meter/+/illuminance" + "bigclown/node/+/barometer/+/pressure" + "bigclown/node/+/pir/+/event-count" + "bigclown/node/+/push-button/+/event-count" + ]) + (consumer "boolean" [ + "bigclown/node/+/flood-detector/+/alarm" + ]) + ]; + processors.pivot = [ + { + tag_key = "field"; + value_key = "value"; + tagpass.source = ["bigclown"]; + } + ]; + }; + + bcg = { + enable = true; + device = "/dev/ttyUSB0"; + baseTopicPrefix = "bigclown/"; + environmentFiles = ["/run/secrets/bigclown.env"]; + mqtt = { + username = "bigclown"; + password = "\${MQTT_PASSWORD}"; + }; + }; + }; + + systemd.services = { + telegraf.wants = ["mosquitto.service"]; + + bigclown-leds = { + description = "Bigclown LEDs control"; + wantedBy = ["multi-user.target"]; + wants = ["mosquitto.service"]; + serviceConfig.ExecStart = "${pkgs.bigclown-leds}/bin/bigclown-leds /run/secrets/bigclown-leds.ini"; + }; + }; } diff --git a/nixos/configurations/spt-mox2.nix b/nixos/configurations/spt-mox2.nix index af0796c..1ddf23a 100644 --- a/nixos/configurations/spt-mox2.nix +++ b/nixos/configurations/spt-mox2.nix @@ -1,12 +1,10 @@ -{ - config, - pkgs, - ... -}: { +{config, ...}: { + system.stateVersion = "24.05"; turris.board = "mox"; deploy = { enable = true; ssh.host = "mox2.spt"; + configurationLimit = 8; }; cynerd = { @@ -20,19 +18,23 @@ enable = true; qca988x = { interface = "wlp1s0"; - bssids = ["04:f0:21:45:d3:47" "08:f0:21:45:d3:47"]; + bssids = config.secrets.wifiMacs.spt-mox2.qca988x; channel = 1; }; }; }; - services.journald.extraConfig = '' - SystemMaxUse=512M - ''; + boot.initrd.availableKernelModules = ["dm-mod"]; - services.btrfs.autoScrub = { - enable = true; - fileSystems = ["/"]; + services = { + journald.settings.Journal = { + SystemMaxUse = "512M"; + }; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; }; networking = { diff --git a/nixos/configurations/spt-mpd.nix b/nixos/configurations/spt-mpd.nix deleted file mode 100644 index b212932..0000000 --- a/nixos/configurations/spt-mpd.nix +++ /dev/null @@ -1,15 +0,0 @@ -{inputModules, ...}: { - imports = [inputModules.nixos-hardware.raspberry-pi-2]; - - config = { - nixpkgs.hostPlatform.system = "armv7l-linux"; - - fileSystems = { - "/" = { - device = "/dev/mmcblk0p1"; - fsType = "btrfs"; - options = ["compress=lzo"]; - }; - }; - }; -} diff --git a/nixos/configurations/spt-omnia.nix b/nixos/configurations/spt-omnia.nix index 29fe8c4..e2d56e8 100644 --- a/nixos/configurations/spt-omnia.nix +++ b/nixos/configurations/spt-omnia.nix @@ -1,14 +1,12 @@ -{ - config, - pkgs, - ... -}: let +{config, ...}: let hosts = config.cynerd.hosts.spt; in { + system.stateVersion = "24.05"; turris.board = "omnia"; deploy = { enable = true; - ssh.host = "omnia.spt"; + ssh.host = "spt.cynerd.cz"; + configurationLimit = 16; }; cynerd = { @@ -21,19 +19,18 @@ in { "7c:b0:c2:bb:9c:ca" = hosts.albert; "4c:d5:77:0d:85:d9" = hosts.binky; "b8:27:eb:57:a2:31" = hosts.mpd; - "74:bf:c0:42:82:19" = hosts.printer; }; }; wifiAP.spt = { enable = true; ar9287 = { interface = "wlp1s0"; - bssids = ["04:f0:21:24:21:93" "08:f0:21:24:21:93"]; + bssids = config.secrets.wifiMacs.spt-omnia.ar9287; channel = 11; }; qca988x = { - interface = "wlp3s0"; - bssids = ["04:f0:21:23:16:64" "08:f0:21:23:16:64"]; + interface = "wlp2s0"; + bssids = config.secrets.wifiMacs.spt-omnia.qca988x; channel = 36; }; }; @@ -41,75 +38,21 @@ in { monitoring.speedtest = true; }; - services.journald.extraConfig = '' - SystemMaxUse=8G - ''; - - environment = { - etc.crypttab.text = '' - nas UUID=3472bef9-cbae-48bd-873e-fd4858a0b72f /run/secrets/luks-spt-omnia-nas.key luks - nassec UUID=016e9e75-bbc8-4b24-8bb7-c800c8f6a500 /run/secrets/luks-spt-omnia-nas.key luks - ''; - systemPackages = with pkgs; [ - cryptsetup - ]; - }; - fileSystems = { - "/data" = { - device = "/dev/mapper/nas"; - fsType = "btrfs"; - options = ["compress=lzo" "subvol=@data" "nofail"]; + services = { + journald.settings.Journal = { + SystemMaxUse = "8G"; }; - "/srv" = { - device = "/dev/mapper/nas"; - fsType = "btrfs"; - options = ["compress=lzo" "subvol=@srv" "nofail"]; - depends = ["/data"]; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; }; - }; - services.btrfs.autoScrub = { - enable = true; - fileSystems = ["/" "/data"]; - }; - services.udev.packages = [ - (pkgs.writeTextFile rec { - name = "queue_depth_sata.rules"; - destination = "/etc/udev/rules.d/50-${name}"; - text = '' - SUBSYSTEMS=="pci", DRIVER=="ahci", ATTR{device}!="0x0612", GOTO="turris_pci_end" - ACTION=="add|change", SUBSYSTEM=="scsi", ATTR{vendor}=="ATA", ATTR{queue_depth}="1" - LABEL="turris_pci_end" - ''; - }) - ]; - users = { - groups.nas = {}; - users = { - nas = { - group = "nas"; - openssh.authorizedKeys.keyFiles = [ - (config.personal-secrets + "/unencrypted/nas.pub") - (config.personal-secrets + "/unencrypted/nas-spt.pub") - ]; - isNormalUser = true; - home = "/data/nas"; - homeMode = "770"; - }; - cynerd.extraGroups = ["nas"]; + fail2ban = { + enable = true; + ignoreIP = ["10.8.1.0/24" "10.8.2.0/24"]; }; }; - services.openssh = { - settings.Macs = ["hmac-sha2-256"]; # Allow sha2-256 for Nexcloud access - extraConfig = '' - Match User nas - X11Forwarding no - AllowTcpForwarding no - AllowAgentForwarding no - ForceCommand internal-sftp -d /data/nas - ''; - }; - services.fail2ban.enable = true; networking.useDHCP = false; systemd.network = { @@ -177,24 +120,32 @@ in { defaultroute6 #usepeerdns maxfail 1 + #holdoff 5 + #persist user metronet password metronet ''; }; - systemd.services."pppd-wan".after = ["sys-subsystem-net-devices-end2.848.device"]; + systemd.services."pppd-wan" = { + after = ["sys-subsystem-net-devices-end2.848.device"]; + partOf = ["systemd-networkd.service"]; + serviceConfig = { + Restart = "always"; + StartLimitBurst = 0; + }; + }; # TODO limit NSS clamping to just pppoe-wan networking.firewall.extraForwardRules = '' tcp flags syn tcp option maxseg size set rt mtu comment "Needed for PPPoE to fix IPv4" - iifname {"home", "personalvpn", "wg"} oifname {"home", "personalvpn", "wg"} accept + iifname {"home", "wg"} oifname {"home", "wg"} accept ''; - services.syncthing = { - enable = false; - openDefaultPorts = true; - - overrideDevices = false; - overrideFolders = false; - - dataDir = "/data"; # TODO this can't be the location + ############################################################################## + cynerd.ha = { + enable = true; + domain = "spt.cynerd.cz"; + extraOptions = [ + "--device=/dev/serial/by-id/usb-ITEAD_SONOFF_Zigbee_3.0_USB_Dongle_Plus_V2_20220812153849-if00:/dev/ttyACM0" + ]; }; } diff --git a/nixos/configurations/zd-mox.nix b/nixos/configurations/zd-mox.nix new file mode 100644 index 0000000..225f13f --- /dev/null +++ b/nixos/configurations/zd-mox.nix @@ -0,0 +1,164 @@ +{ + config, + pkgs, + ... +}: let + hosts = config.cynerd.hosts.zd; +in { + system.stateVersion = "25.05"; + turris.board = "mox"; + deploy = { + enable = true; + ssh.host = "zd.cynerd.cz"; + configurationLimit = 8; + }; + + cynerd = { + router = { + enable = true; + wan = "pppoe-wan"; + lanIP = hosts.mox; + staticLeases = { + "4c:d5:77:0d:85:d9" = hosts.binky; + "70:85:c2:4a:59:f2" = hosts.ridcully; + "74:bf:c0:42:82:19" = hosts.printer; + "f8:dc:7a:79:00:e6" = hosts.tc; + "34:94:54:33:6b:48" = hosts.vb; + }; + }; + wireguard = true; + monitoring.speedtest = true; + }; + + boot.initrd.availableKernelModules = ["dm-mod"]; + + services = { + journald.settings.Journal = { + SystemMaxUse = "512M"; + }; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; + + fail2ban = { + enable = true; + ignoreIP = ["10.8.0.0/24" "10.8.1.0/24" "10.8.2.0/24"]; + }; + }; + + networking.useDHCP = false; + systemd.network = { + netdevs = { + "end0.848" = { + netdevConfig = { + Kind = "vlan"; + Name = "end0.848"; + }; + vlanConfig.Id = 848; + }; + }; + networks = { + "end0" = { + matchConfig.Name = "end0"; + networkConfig.VLAN = ["end0.848"]; + }; + "end0.848" = { + matchConfig.Name = "end0.848"; + networkConfig.BindCarrier = "end0"; + }; + "pppoe-wan" = { + matchConfig.Name = "pppoe-wan"; + networkConfig = { + BindCarrier = "end0.848"; + DHCP = "ipv6"; + IPv6AcceptRA = "no"; + DHCPPrefixDelegation = "yes"; + #DNS = ["84.19.64.3" "84.19.64.4" "1.1.1.1"]; + DNS = "1.1.1.1"; + }; + dhcpV6Config = { + PrefixDelegationHint = "::/56"; + UseDNS = "no"; + }; + dhcpPrefixDelegationConfig = { + UplinkInterface = ":self"; + SubnetId = 0; + Announce = "no"; + }; + linkConfig.RequiredForOnline = "routable"; + }; + "lan-brlan" = { + matchConfig.Name = "lan*"; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + {VLAN = 2;} + ]; + }; + }; + }; + + services.pppd = { + enable = true; + peers."wan".config = '' + plugin pppoe.so end0.848 + ifname pppoe-wan + lcp-echo-interval 1 + lcp-echo-failure 5 + lcp-echo-adaptive + defaultroute + defaultroute6 + maxfail 1 + #holdoff 5 + #persist + # user and password added in secrets + ''; + }; + systemd.services = { + "pppd-wan" = { + requires = ["sys-subsystem-net-devices-end0.848.device"]; + partOf = ["systemd-networkd.service"]; + serviceConfig = { + Restart = "always"; + StartLimitBurst = 0; + }; + }; + "systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug"; + }; + # TODO limit NSS clamping to just pppoe-wan + networking.firewall.extraForwardRules = '' + tcp flags syn tcp option maxseg size set rt mtu comment "Needed for PPPoE to fix IPv4" + iifname {"home", "wg"} oifname {"home", "wg"} accept + ''; + + services.nginx = { + enable = true; + virtualHosts = { + "zd.cynerd.cz" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://${hosts.one0}:8123"; + proxyWebsockets = true; + recommendedProxySettings = true; + }; + }; + }; + }; + security.acme = { + acceptTerms = true; + defaults.email = "cynerd+acme@email.cz"; + certs."zd.cynerd.cz" = {}; + }; + networking.firewall.allowedTCPPorts = [80 443]; + + environment.systemPackages = with pkgs; [ + nmap + tcpdump + ]; +} diff --git a/nixos/configurations/zd-one0.nix b/nixos/configurations/zd-one0.nix new file mode 100644 index 0000000..dc261cd --- /dev/null +++ b/nixos/configurations/zd-one0.nix @@ -0,0 +1,65 @@ +{config, ...}: { + system.stateVersion = "25.11"; + deploy = { + enable = true; + #ssh.host = "zd-one0"; + ssh.host = "one0nix"; + }; + + cynerd = { + openwrtone = true; + switch = { + enable = true; + lanAddress = "${config.cynerd.hosts.zd.one0nix}/24"; + lanGateway = config.cynerd.hosts.zd.mox; + }; + wifiAP.zd = { + enable = false; + wlan0 = { + bssids = [ + "20:05:b7:00:4c:02" + "20:05:b7:04:4c:02" + "20:05:b7:08:4c:02" + ]; + channel = 7; + }; + }; + }; + + boot.initrd.availableKernelModules = ["dm-mod"]; + boot.consoleLogLevel = 7; + + services = { + journald.settings.Journal = { + SystemMaxUse = "32G"; + }; + + btrfs.autoScrub = { + enable = true; + fileSystems = ["/"]; + }; + + fail2ban = { + enable = true; + ignoreIP = ["10.8.0.0/24" "10.8.1.0/24" "10.8.2.0/24"]; + }; + }; + + networking = { + useNetworkd = true; + useDHCP = false; + }; + systemd.network.networks = { + "lan-brlan" = { + matchConfig.Name = "end*"; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + {VLAN = 2;} + ]; + }; + }; +} diff --git a/nixos/modules/autounlock.nix b/nixos/modules/autounlock.nix index d7d6a7c..912f55f 100644 --- a/nixos/modules/autounlock.nix +++ b/nixos/modules/autounlock.nix @@ -18,6 +18,7 @@ in { config = mkIf (cnf != {}) { environment.systemPackages = [pkgs.luks-hw-password]; boot.initrd = { + systemd.enable = false; extraFiles."/luks-hw-password".source = pkgs.luks-hw-password; luks.devices = mapAttrs (name: value: { diff --git a/nixos/modules/backup.nix b/nixos/modules/backup.nix new file mode 100644 index 0000000..3f5042b --- /dev/null +++ b/nixos/modules/backup.nix @@ -0,0 +1,63 @@ +{ + config, + lib, + ... +}: let + inherit (builtins) elem readFile readDir; + inherit (lib) mkOption types mkIf hasSuffix removeSuffix hasAttr filterAttrs mapAttrs mapAttrs' nameValuePair mergeAttrsList recursiveUpdate; + + servers = ["ridcully"]; # TODO "errol" + clients = + mapAttrs' (fname: _: + nameValuePair (removeSuffix ".pub" fname) + (readFile (config.personal-secrets + "/unencrypted/backup/${fname}"))) + (filterAttrs (n: v: v == "regular" && hasSuffix ".pub" n) + (readDir (config.personal-secrets + "/unencrypted/backup"))); + edpersonal = readFile (config.personal-secrets + "/unencrypted/edpersonal.pub"); +in { + options.cynerd = { + borgjobs = mkOption { + type = with types; attrsOf anything; + description = "Job to be backed up for this "; + }; + }; + + config = { + services.borgbackup = { + repos = mkIf (elem config.networking.hostName servers) ( + mapAttrs (name: key: { + path = "/back/${name}"; + authorizedKeys = [key edpersonal]; + allowSubRepos = true; + }) + clients + ); + + jobs = mkIf (hasAttr config.networking.hostName clients) (mergeAttrsList + (map (server: (mapAttrs' (n: v: + nameValuePair "${server}-${n}" + (recursiveUpdate + (recursiveUpdate { + encryption.mode = "none"; + prune = { + keep = { + daily = 7; + weekly = 4; + monthly = -1; + }; + prefix = n; + }; + } + v) + { + repo = "borg@${server}:./${n}"; + environment = { + BORG_RSH = "ssh -i /run/secrets/borgbackup.key"; + }; + archiveBaseName = null; + })) + config.cynerd.borgjobs)) + servers)); + }; + }; +} diff --git a/nixos/modules/compile.nix b/nixos/modules/compile.nix index 3c90345..332a095 100644 --- a/nixos/modules/compile.nix +++ b/nixos/modules/compile.nix @@ -20,7 +20,10 @@ in { cores = 0; }; - boot.binfmt.emulatedSystems = ["armv7l-linux" "aarch64-linux" "riscv32-linux"]; + boot.binfmt = { + emulatedSystems = ["armv7l-linux" "aarch64-linux" "riscv32-linux"]; + preferStaticEmulators = true; + }; environment.systemPackages = with pkgs; [ # Tools @@ -28,9 +31,6 @@ in { bash #uroot qemu - - # Python - python3Packages.pip ]; }; } diff --git a/nixos/modules/desktop.nix b/nixos/modules/desktop.nix index 4a8c7dd..a321577 100644 --- a/nixos/modules/desktop.nix +++ b/nixos/modules/desktop.nix @@ -37,6 +37,8 @@ in { wrapperFeatures.gtk = true; extraPackages = with pkgs; [ + appimage-run + dconf-editor glib gsettings-desktop-schemas @@ -47,17 +49,19 @@ in { waybar swaybackground myswaylock + brightnessctl alacritty nautilus kanshi + shikane wdisplays wayvnc wl-mirror slurp grim - wf-recorder + #wf-recorder wl-clipboard wl-color-picker swayidle @@ -67,13 +71,11 @@ in { resources isync + davmail msmtp notmuch - astroid + dodo taskwarrior3 - vdirsyncer - khal - khard gnupg pinentry-gnome3 pinentry-curses @@ -81,15 +83,22 @@ in { exts.pass-otp exts.pass-audit ])) + ranger chromium + tangram ferdium signal-desktop - libreoffice mupdf zathura pdfgrep + libreoffice-qt6-fresh + hunspell + hunspellDicts.en_US-large + hunspellDicts.en_GB-large + hunspellDicts.cs_CZ + xdg-utils xdg-launch mesa-demos @@ -97,8 +106,8 @@ in { pulsemixer mpd - mpc-cli - ncmpcpp + mpc + #ncmpcpp feh shotwell id3lib @@ -107,7 +116,6 @@ in { yt-dlp spotify - nordic nordzy-cursor-theme nordzy-icon-theme adwaita-icon-theme @@ -123,7 +131,6 @@ in { tigervnc freerdp - plasma5Packages.kdeconnect-kde gnome-firmware hdparm @@ -143,28 +150,31 @@ in { gimp inkscape blender - kdenlive + tenacity + kdePackages.kdenlive + qrrs # GStreamer - gst_all_1.gst-libav - gst_all_1.gst-plugins-bad + gst_all_1.gstreamer gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good + gst_all_1.gst-plugins-bad gst_all_1.gst-plugins-ugly - gst_all_1.gst-plugins-viperfx + gst_all_1.gst-plugins-rs + gst_all_1.gst-libav # Writing typst - typst-fmt - typst-live - typst-lsp + typstyle + tinymist vale # CAD - freecad + #freecad kicad sweethome3d.application qelectrotech + super-slicer ] ++ (optionals cnf.laptop [ # Power management @@ -179,11 +189,9 @@ in { nativeMessagingHosts.packages = with pkgs; [browserpass]; }; - light.enable = mkIf cnf.laptop true; - - nix-ld = { + fuse = { enable = true; - libraries = with pkgs; [xorg.libXpm]; + userAllowOther = true; }; usbkey = { @@ -198,7 +206,16 @@ in { enable = true; enableSSHSupport = true; enableBrowserSocket = true; + pinentryPackage = pkgs.writeShellScriptBin "pinentry-auto" '' + if [ -n "$WAYLAND_DISPLAY" ] || [ -n "$DISPLAY" ]; then + exec ${pkgs.pinentry-gnome3}/bin/pinentry-gnome3 "$@" + else + exec ${pkgs.pinentry-gnome3}/bin/pinentry-curses "$@" + fi + ''; }; + + kdeconnect.enable = true; }; xdg = { @@ -237,17 +254,24 @@ in { xserver.xkb.options = "grp:alt_shift_toggle,caps:escape"; # Gnome crypto services (GnuPG) - dbus.packages = [pkgs.gcr]; + dbus.packages = [pkgs.gcr_4]; pipewire = { enable = true; alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; - extraConfig.pipewire."10-zeroconf" = { - "context.modules" = [{name = "libpipewire-module-zeroconf-discover";}]; - }; + configPackages = [ + (pkgs.writeTextDir "share/pipewire/pipewire.conf.d/10-zeroconf-discover.conf" '' + context.modules = [ + { name = libpipewire-module-zeroconf-discover + args = { } + } + ] + '') + ]; }; + playerctld.enable = true; upower.enable = true; hardware.openrgb = { @@ -263,14 +287,46 @@ in { cnijfilter2 ]; }; + saned.enable = true; avahi.enable = true; + samba = { + enable = false; + openFirewall = true; + settings = { + global = { + "workgroup" = "WORKGROUP"; + "server string" = "smbnix"; + "netbios name" = "smbnix"; + "security" = "user"; + "hosts allow" = "0.0.0.0/0"; + "guest account" = "nobody"; + "map to guest" = "bad user"; + }; + public = { + "path" = "/mnt/public"; + "browseable" = "yes"; + "read only" = "no"; + "guest ok" = "yes"; + "create mask" = "0644"; + "directory mask" = "0755"; + "force user" = "cynerd"; + "force group" = "cynerd"; + }; + }; + }; samba-wsdd = { - enable = true; + enable = false; discovery = true; }; - davfs2.enable = true; + #davfs2.enable = true; TODO!!! locate.enable = true; + + gnome = { + at-spi2-core.enable = true; + gnome-keyring.enable = true; + gnome-online-accounts.enable = true; + }; }; # Beneficial for Pipewire @@ -282,22 +338,30 @@ in { allowedUDPPorts = [3702]; }; - fonts.packages = with pkgs; [ - (nerdfonts.override {fonts = ["Hack"];}) - arkpandora_ttf - corefonts - dejavu_fonts - font-awesome - freefont_ttf - hack-font - liberation_ttf - libertine - noto-fonts - noto-fonts-emoji - terminus_font_ttf - ubuntu_font_family - unifont - ]; + fonts = { + enableDefaultPackages = true; + packages = with pkgs; [ + arkpandora_ttf + corefonts + dejavu_fonts + fira-code + fira-code-symbols + fira-math + fira-mono + fira-sans + font-awesome + freefont_ttf + hack-font + liberation_ttf + libertine + nerd-fonts.hack + noto-fonts + noto-fonts-color-emoji + terminus_font_ttf + ubuntu-classic + unifont + ]; + }; documentation = { enable = true; @@ -330,13 +394,13 @@ in { }; # Support running app images - boot.binfmt.registrations.appimage = { - wrapInterpreterInShell = false; - interpreter = "${pkgs.appimage-run}/bin/appimage-run"; - recognitionType = "magic"; - offset = 0; - mask = ''\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff''; - magicOrExtension = ''\x7fELF....AI\x02''; - }; + #boot.binfmt.registrations.appimage = { + # wrapInterpreterInShell = false; + # interpreter = "${pkgs.appimage-run}/bin/appimage-run"; + # recognitionType = "magic"; + # offset = 0; + # mask = ''\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff''; + # magicOrExtension = ''\x7fELF....AI\x02''; + #}; }; } diff --git a/nixos/modules/develop.nix b/nixos/modules/develop.nix index 446d205..8b413a9 100644 --- a/nixos/modules/develop.nix +++ b/nixos/modules/develop.nix @@ -15,10 +15,13 @@ in { }; config = mkIf config.cynerd.develop { - cynerd.compile = true; - environment.enableDebugInfo = true; + cynerd = { + devmin = true; + compile = true; + }; environment.systemPackages = with pkgs; [ # Tools + git-lfs gitlint tig gitg @@ -30,8 +33,10 @@ in { openssl tio vim-vint - nodePackages.vim-language-server + vim-language-server vale + can-utils + unixtools.xxd # Required for neovim plugins editorconfig-checker @@ -43,11 +48,13 @@ in { cachix nurl nil + nixfmt alejandra statix deadnix agenix nix-tree + nix-output-monitor # Shell dash # Posix shell @@ -61,12 +68,14 @@ in { # C clang-tools - massif-visualizer - qcachegrind + bear + #massif-visualizer + elf-size-analyze # Python (python3.withPackages (pypkgs: with pypkgs; [ + pip ipython python-lsp-server @@ -82,11 +91,12 @@ in { pygraphviz matplotlib + seaborn plotly pygal python-gitlab - PyGithub + pygithub schema jinja2 @@ -105,8 +115,14 @@ in { pyserial pylibftdi + pyusb + usbtmc + pylxd selenium + + pyvisa + pyvisa-py ])) ruff geckodriver @@ -123,11 +139,17 @@ in { # Julia julia + # XML + libxml2 + # Qemmu qemu virt-manager cdrtools + # Docker + docker-credential-helpers + # U-Boot ubootTools tftp-hpa @@ -151,13 +173,59 @@ in { linux-manual stdmanpages + # Writing documentation + docstrfmt + # SHV - shvcli + (shvcli.withPlugins [python3Packages.shvcli-ell]) # Images imagemagick + + # S3 + rclone ]; - programs.wireshark.package = pkgs.wireshark; + #programs.wireshark = { + # enable = true; + # package = pkgs.wireshark; + #}; + + programs.nix-ld = { + enable = true; + libraries = with pkgs; [ + alsa-lib + at-spi2-atk + cairo + cups + dbus + expat + gdk-pixbuf + glib + gtk3 + libGL + libXpm + libdrm + libgbm + libgcrypt + libsoup_3 + libudev0-shim + libusb1 + libx11 + libxcb + libxcomposite + libxdamage + libxext + libxfixes + libxkbcommon + libxrandr + nspr + nss + openssl + pango + udev + webkitgtk_4_1 + ]; + }; documentation = { nixos = { @@ -168,12 +236,18 @@ in { doc.enable = true; }; - services.udev.extraRules = '' - SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE:="0660", GROUP="develop", SYMLINK+="stlinkv2_%n" - SUBSYSTEMS=="usb", ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a003", MODE:="0660", GROUP="develop", SYMLINK+="aix_forte_%n" - SUBSYSTEMS=="usb", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE:="0660", GROUP="develop", SYMLINK+="jlink_%n" - SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE:="0660", GROUP="develop", SYMLINK+="cmsip_dap_%n" - ''; + services.guix.enable = true; + #environment.etc."guix/machines.scm".text = '' + # (list (build-machine + # (name "czellembsrv.elektroline.cz") + # (systems (list "x86_64-linux" "i686-linux")) + # (host-key "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICQZIwdzBo5CvMjS0M9tKYG2ikqPmSgSKRa/UPAoyhBC root@embsrv") + # (user "kkoci") + # (private-key "/home/cynerd/.ssh/elektroline-emb") + # (parallel-builds 16) + # (speed 2.0) + # )) + #''; virtualisation = { containers.enable = true; @@ -182,20 +256,21 @@ in { autoPrune.enable = true; storageDriver = "btrfs"; }; - lxd = { + lxc.enable = true; + libvirtd = { enable = true; - recommendedSysctlSettings = true; + qemu = { + swtpm.enable = true; + vhostUserPackages = with pkgs; [virtiofsd]; + }; }; - lxc.enable = true; - libvirtd.enable = true; spiceUSBRedirection.enable = true; }; + networking.firewall.trustedInterfaces = ["virbr0"]; - users.groups.develop = {}; users.users.cynerd.extraGroups = [ "docker" "lxd" - "develop" "libvirtd" ]; }; diff --git a/nixos/modules/devmin.nix b/nixos/modules/devmin.nix new file mode 100644 index 0000000..767cf2c --- /dev/null +++ b/nixos/modules/devmin.nix @@ -0,0 +1,37 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkOption mkIf types; +in { + options = { + cynerd.devmin = mkOption { + type = types.bool; + default = false; + description = "If machine is about to be used for remote development."; + }; + }; + + config = mkIf config.cynerd.devmin { + environment.enableDebugInfo = true; + + users.groups.develop = {}; + users.users.cynerd.extraGroups = [ + "develop" + ]; + + services.udev.extraRules = '' + SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="3748", MODE:="0660", GROUP="develop", SYMLINK+="stlinkv2_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="a600", ATTRS{idProduct}=="a003", MODE:="0660", GROUP="develop", SYMLINK+="aix_forte_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="1366", ATTRS{idProduct}=="0105", MODE:="0660", GROUP="develop", SYMLINK+="jlink_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2111", MODE:="0660", GROUP="develop", SYMLINK+="cmsip_dap_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="bef3", MODE:="0660", GROUP="develop", SYMLINK+="xds110_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00ff", MODE:="0660", GROUP="develop", SYMLINK+="xds110_update_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a2", MODE:="0660", GROUP="develop", SYMLINK+="ccdebugger_%n" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="1ab1", ATTRS{idProduct}=="0e11", MODE:="0660", GROUP="develop" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE:="0660", GROUP="develop", TAG+="uaccess" + SUBSYSTEMS=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1002", MODE:="0660", GROUP="develop", TAG+="uaccess" + ''; + }; +} diff --git a/nixos/modules/gaming.nix b/nixos/modules/gaming.nix index 64af068..e939bf2 100644 --- a/nixos/modules/gaming.nix +++ b/nixos/modules/gaming.nix @@ -18,7 +18,14 @@ in { config = mkIf cnf { cynerd.desktop.enable = true; - environment.systemPackages = [pkgs.heroic]; + environment.systemPackages = with pkgs; [ + heroic + prismlauncher + ]; + + nixpkgs.config.permittedInsecurePackages = [ + "SDL_ttf-2.0.11" # TODO + ]; programs.steam = { enable = true; @@ -30,9 +37,29 @@ in { extraPkgs = pkgs: with pkgs; [ ncurses - xorg.libXpm - flac1_3 + libxpm + flac134 + libopus + ]; + }; + heroic = pkgs.heroic.override { + extraPkgs = pkgs: + with pkgs; [ + ncurses + libxpm + flac134 # For Nebuchadnezzar libopus + SDL + SDL2_image + SDL2_mixer + SDL2_ttf + SDL_image + SDL_mixer + SDL_ttf + glew_1_10 + libdrm + libidn + tbb ]; }; }; diff --git a/nixos/modules/generic.nix b/nixos/modules/generic.nix index 02afd17..3e8abaf 100644 --- a/nixos/modules/generic.nix +++ b/nixos/modules/generic.nix @@ -6,20 +6,10 @@ inherit (lib) mkOverride mkDefault; in { config = { - system.stateVersion = "24.05"; - nix = { - extraOptions = "experimental-features = nix-command flakes repl-flake"; + extraOptions = "experimental-features = nix-command flakes"; settings = { auto-optimise-store = true; - substituters = [ - "https://thefloweringash-armv7.cachix.org" - "https://arm.cachix.org" - ]; - trusted-public-keys = [ - "thefloweringash-armv7.cachix.org-1:v+5yzBD2odFKeXbmC+OPWVqx4WVoIVO6UXgnSAWFtso=" - "arm.cachix.org-1:K3XjAeWPgWkFtSS9ge5LJSLw3xgnNqyOaG7MDecmTQ8=" - ]; trusted-users = ["@wheel"]; }; registry = { @@ -31,13 +21,16 @@ in { }; boot = { - loader.systemd-boot.enable = mkOverride 1100 true; - loader.efi.canTouchEfiVariables = mkDefault true; + loader = { + systemd-boot.enable = mkOverride 1100 true; + efi.canTouchEfiVariables = mkDefault true; + grub.enable = mkOverride 1100 false; + }; kernelPackages = mkOverride 1100 pkgs.linuxPackages_latest; kernelParams = ["boot.shell_on_fail"]; }; - hardware.enableAllFirmware = true; - services.fwupd.enable = mkDefault (pkgs.system == "x86_64-linux"); + hardware.enableAllFirmware = mkDefault true; + services.fwupd.enable = mkDefault (pkgs.stdenv.hostPlatform.system == "x86_64-linux"); systemd.oomd.enable = false; networking = { @@ -59,11 +52,6 @@ in { }) ]; - system.extraSystemBuilderCmds = '' - substituteAll ${./nixos-system.sh} $out/bin/nixos-system - chmod +x $out/bin/nixos-system - ''; - documentation = { enable = mkDefault false; doc.enable = mkDefault false; diff --git a/nixos/modules/home-assistant.nix b/nixos/modules/home-assistant.nix deleted file mode 100644 index ab16e8a..0000000 --- a/nixos/modules/home-assistant.nix +++ /dev/null @@ -1,164 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: let - inherit (lib) mkIf mkEnableOption; -in { - options = { - cynerd.home-assistant = mkEnableOption "Enable Home Assistant and Bigclown"; - }; - - config = mkIf config.cynerd.home-assistant { - services.mosquitto = { - enable = true; - listeners = [ - { - users = { - cynerd = { - acl = ["readwrite #"]; - passwordFile = "/run/secrets/mosquitto.cynerd.pass"; - }; - telegraf = { - acl = ["read bigclown/node/#"]; - passwordFile = "/run/secrets/mosquitto.telegraf.pass"; - }; - homeassistant = { - acl = [ - "readwrite homeassistant/#" - "readwrite bigclown/#" - "readwrite zigbee2mqtt/#" - ]; - passwordFile = "/run/secrets/mosquitto.homeassistant.pass"; - }; - bigclown = { - acl = ["readwrite bigclown/#"]; - passwordFile = "/run/secrets/mosquitto.bigclown.pass"; - }; - zigbee2mqtt = { - acl = [ - "readwrite homeassistant/#" - "readwrite zigbee2mqtt/#" - ]; - passwordFile = "/run/secrets/mosquitto.zigbee2mqtt.pass"; - }; - }; - } - ]; - }; - networking.firewall.allowedTCPPorts = [ - 1883 # Mosquitto - ]; - - services.bcg = { - enable = true; - device = "/dev/ttyUSB0"; - baseTopicPrefix = "bigclown/"; - environmentFiles = ["/run/secrets/bigclown.env"]; - mqtt = { - username = "bigclown"; - password = "\${MQTT_PASSWORD}"; - }; - }; - - systemd.services.bigclown-leds = { - description = "Bigclown LEDs control"; - wantedBy = ["multi-user.target"]; - wants = ["mosquitto.service"]; - serviceConfig.ExecStart = "${pkgs.bigclown-leds}/bin/bigclown-leds /run/secrets/bigclown-leds.ini"; - }; - - services.telegraf.extraConfig = { - outputs.influxdb_v2 = [ - { - urls = ["http://cynerd.cz:8086"]; - token = "$INFLUX_TOKEN"; - organization = "personal"; - bucket = "bigclown"; - tagpass.source = ["bigclown"]; - } - ]; - inputs.mqtt_consumer = let - consumer = data_type: topics: { - tags = {source = "bigclown";}; - servers = ["tcp://localhost:1883"]; - inherit topics; - username = "telegraf"; - password = "$MQTT_PASSWORD"; - data_format = "value"; - inherit data_type; - topic_parsing = [ - { - topic = "bigclown/node/+/+/+/+"; - measurement = "_/_/_/_/_/measurement"; - tags = "_/_/device/field/_/_"; - } - ]; - }; - in [ - (consumer "float" [ - "bigclown/node/+/battery/+/voltage" - "bigclown/node/+/thermometer/+/temperature" - "bigclown/node/+/hygrometer/+/relative-humidity" - "bigclown/node/+/lux-meter/+/illuminance" - "bigclown/node/+/barometer/+/pressure" - "bigclown/node/+/pir/+/event-count" - "bigclown/node/+/push-button/+/event-count" - ]) - (consumer "boolean" [ - "bigclown/node/+/flood-detector/+/alarm" - ]) - ]; - processors.pivot = [ - { - tag_key = "field"; - value_key = "value"; - tagpass.source = ["bigclown"]; - } - ]; - }; - systemd.services.telegraf.wants = ["mosquitto.service"]; - - #nixpkgs.config.permittedInsecurePackages = ["openssl-1.1.1w"]; # TODO - services.home-assistant = { - enable = false; - openFirewall = true; - configDir = "/var/lib/hass"; - config = { - homeassistant = { - name = "SPT"; - latitude = "!secret latitude"; - longitude = "!secret longitude"; - elevation = "!secret elevation"; - time_zone = "Europe/Prague"; - country = "CZ"; - }; - http.server_port = 8808; - mqtt = { - sensor = import ./home-assistant/sensors.nix; - light = import ./home-assistant/light.nix; - }; - default_config = {}; - automation = "!include automations.yaml"; - }; - extraComponents = ["met"]; - package = pkgs.home-assistant.override { - extraPackages = pkgs: - with pkgs; [ - securetar - pyipp - ]; - packageOverrides = _: super: { - scapy = super.scapy.override { - withPlottingSupport = false; - }; - s3transfer = super.s3transfer.overridePythonAttrs { - dontUsePytestCheck = true; - dontUseSetuptoolsCheck = true; - }; - }; - }; - }; - }; -} diff --git a/nixos/modules/home-assistant/light.nix b/nixos/modules/home-assistant/light.nix deleted file mode 100644 index a9d158b..0000000 --- a/nixos/modules/home-assistant/light.nix +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - name = "RGB Osvětlení"; - command_topic = "homeassistant/led-strip"; - brightness_scale = 100; - brightness_command_topic = "bigclown/node/power-controller:0/led-strip/-/brightness/set"; - #brightness_state_topic = "bigclown/node/power-controller:0/led-strip/-/brightness/set"; - rgb_command_template = ''"#{{"%02x" % red}}{{"%02x" % green}}{{"%02x" % blue}}"''; - rgb_command_topic = "bigclown/node/power-controller:0/led-strip/-/color/set"; - #rgb_value_template = ''{{int(value[2:4],16)}},{{int(value[5:7],16)}},{{int(value[8:10],16)}}''; - #rgb_state_topic = "bigclown/node/power-controller:0/led-strip/-/color/set"; - } -] diff --git a/nixos/modules/home-assistant/sensors.nix b/nixos/modules/home-assistant/sensors.nix deleted file mode 100644 index fadd4eb..0000000 --- a/nixos/modules/home-assistant/sensors.nix +++ /dev/null @@ -1,19 +0,0 @@ -[ - { - name = "Teplota"; - state_class = "measurement"; - state_topic = "bigclown/node/climate-monitor:0/thermometer/0:0/temperature"; - unit_of_measurement = "°C"; - } - { - name = "Vlhkost"; - state_class = "measurement"; - state_topic = "bigclown/node/climate-monitor:0/hygrometer/0:4/relative-humidity"; - unit_of_measurement = "%"; - } - { - name = "Osvětlení"; - state_class = "measurement"; - state_topic = "bigclown/node/climate-monitor:0/lux-meter/0:0/illuminance"; - } -] diff --git a/nixos/modules/homeassistant.nix b/nixos/modules/homeassistant.nix new file mode 100644 index 0000000..f7ebe9c --- /dev/null +++ b/nixos/modules/homeassistant.nix @@ -0,0 +1,57 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkOption mkEnableOption types mkIf; + cnf = config.cynerd.ha; +in { + options.cynerd.ha = { + enable = mkEnableOption "Home assistant setup on the primary router."; + domain = mkOption { + type = with types; str; + description = "The domain name of the system."; + }; + extraOptions = mkOption { + type = with types; listOf str; + default = []; + description = "Extra options passed to the container."; + }; + }; + + config = mkIf cnf.enable { + virtualisation.oci-containers = { + backend = "podman"; + containers.homeassistant = { + volumes = ["home-assistant:/config" "/run/dbus:/run/dbus:ro"]; + environment.TZ = "Europe/Prague"; + image = "ghcr.io/home-assistant/armv7-homeassistant:latest"; + extraOptions = + ["--privileged" "--network=host"] + ++ cnf.extraOptions; + }; + }; + + services.nginx = { + enable = true; + virtualHosts = { + "${cnf.domain}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:8123"; + proxyWebsockets = true; + recommendedProxySettings = true; + }; + }; + }; + }; + security.acme = { + acceptTerms = true; + defaults.email = "cynerd+acme@email.cz"; + certs."${cnf.domain}" = {}; + }; + + networking.firewall.allowedTCPPorts = [80 443]; + }; +} diff --git a/nixos/modules/hosts.nix b/nixos/modules/hosts.nix index f53fd8c..0aafb12 100644 --- a/nixos/modules/hosts.nix +++ b/nixos/modules/hosts.nix @@ -19,7 +19,7 @@ in { default = true; description = "Use my personal static hosts"; }; - vpn = staticZoneOption; + zd = staticZoneOption; wg = staticZoneOption; spt = staticZoneOption; adm = staticZoneOption; @@ -28,9 +28,21 @@ in { config = { cynerd.hosts = { - vpn = { - "lipwig" = "10.8.0.1"; - "adm-omnia" = "10.8.0.51"; + zd = { + # Network + "mox" = "10.8.0.1"; + "one0" = "10.8.0.2"; + "one0nix" = "10.8.0.3"; + "camera1" = "10.8.0.21"; + "camera2" = "10.8.0.22"; + # Local + "ridcully" = "10.8.0.59"; + "dribbler" = "10.8.0.60"; + "tc" = "10.8.0.99"; + "vb" = "10.8.0.98"; + "printer" = "10.8.0.90"; + # Portable + "binky" = "10.8.0.63"; }; wg = { "lipwig" = "10.8.1.1"; @@ -40,6 +52,7 @@ in { # Endpoints "spt-omnia" = "10.8.1.50"; "adm-omnia" = "10.8.1.51"; + "zd-mox" = "10.8.1.52"; # Endpoints without routing "dean" = "10.8.1.59"; }; @@ -51,7 +64,6 @@ in { # Local "mpd" = "10.8.2.51"; "errol" = "10.8.2.60"; - "printer" = "10.8.2.90"; # Portable "albert" = "10.8.2.61"; "binky" = "10.8.2.63"; @@ -61,26 +73,27 @@ in { "omnia" = "10.8.3.1"; "omnia2" = "10.8.3.3"; # Local - "ridcully" = "10.8.3.60"; "3dprint" = "10.8.3.80"; - "mpd" = "10.8.3.51"; - "printer" = "192.168.0.20"; + "printer" = "10.8.3.20"; # Portable - "albert" = "10.8.3.61"; "binky" = "10.8.3.63"; }; }; networking.hosts = mkIf cnf.enable { - # VPN - "${cnf.vpn.lipwig}" = ["lipwig.vpn"]; - "${cnf.vpn.adm-omnia}" = ["adm.vpn"]; + # Zd + "${cnf.zd.mox}" = ["mox.zd"]; + "${cnf.zd.one0}" = ["one0.zd"]; + "${cnf.zd.ridcully}" = ["ridcully"]; + "${cnf.zd.tc}" = ["tc.zd"]; + "${cnf.zd.binky}" = ["binky.zd"]; # Wireguard "${cnf.wg.lipwig}" = ["lipwig.wg"]; "${cnf.wg.binky}" = ["binky.wg"]; "${cnf.wg.android}" = ["android.wg"]; "${cnf.wg.spt-omnia}" = ["spt.wg"]; "${cnf.wg.adm-omnia}" = ["adm.wg"]; + "${cnf.wg.zd-mox}" = ["zd.wg"]; "${cnf.wg.dean}" = ["dean" "dean.wg"]; # Spt "${cnf.spt.omnia}" = ["omnia.spt"]; @@ -88,18 +101,15 @@ in { "${cnf.spt.mox2}" = ["mox2.spt"]; "10.8.2.4" = ["mi3g.spt"]; "${cnf.spt.mpd}" = ["mpd.spt"]; - "${cnf.spt.errol}" = ["errol" "desktop.spt"]; + "${cnf.spt.errol}" = ["errol"]; "${cnf.spt.albert}" = ["albert.spt"]; "${cnf.spt.binky}" = ["binky.spt"]; # Adm "${cnf.adm.omnia}" = ["omnia.adm"]; "10.8.3.2" = ["redmi.adm"]; "${cnf.adm.omnia2}" = ["omnia2.adm"]; - "${cnf.adm.ridcully}" = ["ridcully" "desktop.adm"]; - "${cnf.adm.albert}" = ["albert.adm"]; "${cnf.adm.binky}" = ["binky.adm"]; - "${cnf.adm."3dprint"}" = ["3dprint"]; - "${cnf.adm.mpd}" = ["mpd.adm"]; + "${cnf.adm.printer}" = ["printer.adm"]; }; }; } diff --git a/nixos/modules/monitoring.nix b/nixos/modules/monitoring.nix index e4fa195..96761b9 100644 --- a/nixos/modules/monitoring.nix +++ b/nixos/modules/monitoring.nix @@ -32,6 +32,12 @@ in { config = mkMerge [ (mkIf cnf.enable { + # Glances + services.glances = { + enable = true; + openFirewall = true; + }; + # Telegraf configuration services.telegraf = { enable = true; @@ -136,8 +142,8 @@ in { }) (mkIf (config.networking.hostName == "lipwig") { - # InfluxDB services = { + # InfluxDB influxdb2.enable = true; telegraf.extraConfig.inputs.prometheus = { urls = ["http://localhost:8086/metrics"]; @@ -150,6 +156,7 @@ in { security = { admin_user = "cynerd"; admin_password = "$__file{/run/secrets/grafana.admin.pass}"; + secret_key = "SW2YcwTIb9zpOOhoPsMm"; }; server = { domain = "grafana.cynerd.cz"; diff --git a/nixos/modules/nixos-system.sh b/nixos/modules/nixos-system.sh deleted file mode 100644 index 7a220bb..0000000 --- a/nixos/modules/nixos-system.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!@shell@ -# Simple script handy to be used for activation - -while getopts "s" opt; do - case "$opt" in - s) - if [ ! -v NIXOS_SYSTEM_GNU_SCREEN ]; then - export NIXOS_SYSTEM_GNU_SCREEN=1 - exec @out@/sw/bin/screen "$0" "$@" - fi - ;; - *) - echo "Invalid argument: $1" >&2 - exit 1 - ;; - esac -done -shift $((OPTIND - 1)) - - -@out@/sw/bin/nix-env --profile /nix/var/nix/profiles/system --set '@out@' - -@out@/bin/switch-to-configuration "$@" || { - echo "Switch failed!" >&2 - read -r _ - exit 1 -} diff --git a/nixos/modules/openvpn.nix b/nixos/modules/openvpn.nix index 6a21721..8837904 100644 --- a/nixos/modules/openvpn.nix +++ b/nixos/modules/openvpn.nix @@ -9,11 +9,6 @@ in { options = { cynerd.openvpn = { - oldpersonal = mkOption { - type = types.bool; - default = false; - description = "My personal old OpenVPN"; - }; elektroline = mkOption { type = types.bool; default = false; @@ -24,9 +19,6 @@ in { config = { services.openvpn.servers = { - oldpersonal = mkIf cnf.oldpersonal { - config = "config /run/secrets/old.ovpn"; - }; elektroline = mkIf cnf.elektroline { config = "config /run/secrets/elektroline.ovpn"; up = '' @@ -48,6 +40,10 @@ in { ${pkgs.systemd}/bin/resolvectl domain "$dev" "~$domain" ''; }; + ellshv = mkIf cnf.elektroline { + config = "config /run/secrets/ellshv.ovpn"; + autoStart = false; + }; }; }; } diff --git a/nixos/modules/openwrtone.nix b/nixos/modules/openwrtone.nix new file mode 100644 index 0000000..b4ffe06 --- /dev/null +++ b/nixos/modules/openwrtone.nix @@ -0,0 +1,119 @@ +{ + config, + lib, + pkgs, + modulesPath, + extendModules, + ... +}: let + inherit (lib) mkEnableOption mkIf mkDefault; + variant = extendModules { + modules = [ + { + boot.postBootCommands = '' + # On the first boot do some maintenance tasks + if [ -f /nix-path-registration ]; then + set -euo pipefail + + # Register the contents of the initial Nix store + ${config.nix.package.out}/bin/nix-store --load-db < /nix-path-registration + + # nixos-rebuild also requires a "system" profile and an /etc/NIXOS tag. + touch /etc/NIXOS + ${config.nix.package.out}/bin/nix-env -p /nix/var/nix/profiles/system --set /run/current-system + + # Prevents this from running on later boots. + rm -f /nix-path-registration + fi + ''; + # We do not have generations in the initial image + boot.loader.generic-extlinux-compatible.configurationLimit = 0; + } + ]; + }; + inherit (variant.config.system.build) toplevel; +in { + options.cynerd.openwrtone = mkEnableOption "Configuration for OpenWrt One"; + + config = mkIf config.cynerd.openwrtone { + nixpkgs = { + hostPlatform = { + config = "aarch64-unknown-linux-gnu"; + system = "aarch64-linux"; + }; + buildPlatform = { + config = "x86_64-unknown-linux-gnu"; + system = "x86_64-linux"; + }; + }; + + # We do not need Grub as U-Boot supports boot using extlinux like file + boot = { + loader = { + grub.enable = mkDefault false; + systemd-boot.enable = mkDefault false; + generic-extlinux-compatible.enable = mkDefault true; + }; + + # Use OpenWrt One specific kernel. It fixes SError with patch. + kernelPackages = mkDefault (pkgs.linuxPackagesFor pkgs.linux_7_2); + kernelParams = [ + "fw_devlink=permissive" + "clk_ignore_unused" + ]; + + initrd = { + kernelModules = ["pcie-mediatek-gen3" "nvme"]; + # This includes modules to support common PC manufacturers but is not + # something required on embedded device. + includeDefaultModules = false; + supportedFilesystems = ["btrfs"]; + }; + supportedFilesystems = ["btrfs"]; + }; + hardware.deviceTree.name = mkDefault "mediatek/mt7981b-openwrt-one.dtb"; + + # Cover nix memory consumption peaks by compressing the RAM + zramSwap = mkDefault { + enable = true; + memoryPercent = 80; + }; + + fileSystems = { + "/boot" = mkDefault { + device = "/dev/nvme0n1p1"; + fsType = "vfat"; + }; + "/" = mkDefault { + device = "/dev/nvme0n1p2"; + fsType = "btrfs"; + }; + }; + + environment.systemPackages = with pkgs; [ + iw + ]; + + # No need for installer tools in standard system + system.disableInstallerTools = true; + # No need for NixOS documentation in headless system + documentation.nixos.enable = mkDefault false; + + system.build.tarball = pkgs.callPackage "${modulesPath}/../lib/make-system-tarball.nix" { + extraCommands = pkgs.buildPackages.writeShellScript "tarball-extra-commands" '' + ${variant.config.boot.loader.generic-extlinux-compatible.populateCmd} \ + -c ${toplevel} -d ./boot + ''; + contents = []; + + storeContents = + map (x: { + object = x; + symlink = "none"; + }) [ + toplevel + pkgs.stdenv + ]; + }; + }; +} diff --git a/nixos/modules/packages.nix b/nixos/modules/packages.nix index d321901..a85f14a 100644 --- a/nixos/modules/packages.nix +++ b/nixos/modules/packages.nix @@ -1,11 +1,11 @@ { - config, lib, pkgs, ... }: let inherit (lib) optionals; - isNative = config.nixpkgs.hostPlatform == config.nixpkgs.buildPlatform; + inherit (pkgs.stdenv.hostPlatform) isx86_64; + isNative = pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform; in { nixpkgs = { config.allowUnfree = true; @@ -41,14 +41,12 @@ in { btop iotop mc - screen - tmux - pv # ls tools tree lsof strace + ripgrep sourceHighlight # Colors for less unrar @@ -65,13 +63,16 @@ in { wakeonlan speedtest-cli librespeed-cli - termshark + #termshark + w3m lm_sensors ] - ++ optionals (system == "x86_64-linux") [ + ++ optionals isx86_64 [ nmap ltrace + pv + screen ] ++ optionals (!isNative) [ ncdu_1 diff --git a/nixos/modules/router.nix b/nixos/modules/router.nix index 224037b..b01c94a 100644 --- a/nixos/modules/router.nix +++ b/nixos/modules/router.nix @@ -178,12 +178,11 @@ in { services.resolved = { enable = true; - dnssec = "true"; - fallbackDns = ["1.1.1.1" "8.8.8.8"]; - extraConfig = '' - DNSStubListenerExtra=${cnf.lanIP} - DNSStubListenerExtra=192.168.1.1 - ''; + settings.Resolve = { + FallbackDNS = ["1.1.1.1" "8.8.8.8"]; + DNSStubListenerExtra = [cnf.lanIP "192.168.1.1"]; + # TODO possibly enforce DNSSEC again + }; }; }; } diff --git a/nixos/modules/rpi.md b/nixos/modules/rpi.md new file mode 100644 index 0000000..43b172f --- /dev/null +++ b/nixos/modules/rpi.md @@ -0,0 +1,25 @@ +# Raspberry Pi SD card preparation steps + +``` +~# parted /dev/sdx +(parted) mktable msdos +(parted) mkpart primary fat16 0% 120M +(parted) mkpart primary btrfs 120M 100% +(parted) set 2 boot on +(parted) quit +~# mkfs.vfat -F16 /dev/sdx1 +~# mkfs.btrfs /dev/sdx2 + +~# mount /dev/sdx1 /mnt +~# nix build .#firmware-HOST +~# cp -r result/* /mnt/ +~# umount mnt + +~# mount /dev/sdx2 /mnt +~# nix copy --to /mnt .#toplevel-HOST +~# nix build --print-out-paths .#toplevel-HOST +~# nix eval .#nixosConfigurations.HOST.config.boot.loader.generic-extlinux-compatible.populateCmd +"/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-extlinux-conf-builder.sh -g 20 -t 5" +~# /nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-extlinux-conf-builder.sh -c -d ./mnt/boot +~# umount mnt +``` diff --git a/nixos/modules/rpi.nix b/nixos/modules/rpi.nix new file mode 100644 index 0000000..08a2e91 --- /dev/null +++ b/nixos/modules/rpi.nix @@ -0,0 +1,88 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib) mkOption types mkMerge mkIf; + + configTxt = pkgs.writeText "config.txt" '' + [pi3] + kernel=u-boot-rpi3.bin + + # Boot in 64-bit mode. + arm_64bit=1 + + # Otherwise the serial output will be garbled. + core_freq=250 + # Boot in 64-bit mode. + arm_64bit=1 + + [all] + # U-Boot needs this to work, regardless of whether UART is actually used or not. + # Look in arch/arm/mach-bcm283x/Kconfig in the U-Boot tree to see if this is still + # a requirement in the future. + enable_uart=1 + + # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel + # when attempting to show low-voltage or overtemperature warnings. + avoid_warnings=1 + ''; +in { + options.cynerd.rpi = mkOption { + type = with types; nullOr (enum [2 3]); + default = null; + description = "If machine is RaspberryPi and which version"; + }; + + config = mkMerge [ + (mkIf (config.cynerd.rpi == 2) { + nixpkgs.hostPlatform.system = "armv7l-linux"; + }) + (mkIf (config.cynerd.rpi == 3) { + nixpkgs.hostPlatform.system = "aarch64-linux"; + boot.kernelParams = ["console=ttyS1,115200n8"]; + }) + (mkIf (config.cynerd.rpi != null) { + boot.loader = { + systemd-boot.enable = false; + efi.canTouchEfiVariables = false; + generic-extlinux-compatible.enable = true; + }; + boot.consoleLogLevel = 7; + + fileSystems = { + "/" = { + device = "/dev/mmcblk0p2"; + fsType = "ext4"; + }; + #"/" = { + # device = "/dev/mmcblk0p2"; + # fsType = "btrfs"; + # options = ["compress=lzo"]; + #}; + "/boot/firmware" = { + device = "/dev/mmcblk0p1"; + fsType = "vfat"; + options = ["nofail"]; + }; + }; + + services.journald.settings.Journal = { + SystemMaxUse = "512M"; + }; + + system.build.firmware = pkgs.callPackage ({stdenvNoCC}: + stdenvNoCC.mkDerivation { + name = "${config.system.name}-firmware"; + buildCommand = '' + mkdir $out + cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/* $out/ + cp ${configTxt} $out/config.txt + # TODO support rpi2 + cp ${pkgs.ubootRaspberryPi3_btrfs}/u-boot.bin $out/u-boot-rpi3.bin + ''; + }) {}; + }) + ]; +} diff --git a/nixos/modules/syncthing.nix b/nixos/modules/syncthing.nix index 91736ca..eab61c7 100644 --- a/nixos/modules/syncthing.nix +++ b/nixos/modules/syncthing.nix @@ -3,119 +3,96 @@ lib, ... }: let - inherit (lib) filterAttrs mkOption types mkIf any mkDefault recursiveUpdate genAttrs; - cnf = config.cynerd.syncthing; - inherit (config.networking) hostName; + inherit (lib) elem filterAttrs mkIf any mkDefault recursiveUpdate genAttrs; + allDevices = [ - "albert" "binky" "errol" "lipwig" "ridcully" - "spt-omnia" - ]; - mediaDevices = [ - "lipwig" - "binky" - "errol" - "ridcully" - "spt-omnia" ]; bigStorageDevices = [ "errol" "ridcully" - "spt-omnia" ]; + + inherit (config.networking) hostName; + baseDir = config.services.syncthing.dataDir; filterDevice = filterAttrs (_: v: any (d: d == hostName) v.devices); in { - options = { - cynerd.syncthing = { - enable = mkOption { - type = types.bool; - default = false; - description = "My personal Syncthing configuration"; - }; - - baseDir = mkOption { - type = types.str; - default = "/home/cynerd"; - description = "Base directory for all folders being synced."; - }; - }; - }; - - config = mkIf cnf.enable { + config = mkIf (config.services.syncthing.enable && elem hostName allDevices) { services.syncthing = { - enable = any (n: n == hostName) allDevices; user = mkDefault "cynerd"; + group = mkDefault "cynerd"; + key = "/run/secrets/syncthing.key.pem"; cert = "/run/secrets/syncthing.cert.pem"; openDefaultPorts = true; - overrideFolders = true; - folders = filterDevice { - "${cnf.baseDir}/documents" = { - label = "Documents"; - id = "documents"; - devices = allDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/notes" = { - label = "Notes"; - id = "notes"; - devices = allDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/projects" = { - label = "Projects"; - id = "projects"; - devices = allDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/pictures" = { - label = "Pictures"; - id = "pictures"; - devices = mediaDevices; - ignorePerms = false; - }; - # TODO phone-photos - "${cnf.baseDir}/music/primary" = { - label = "Music-primary"; - id = "music-primary"; - devices = mediaDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/music/secondary" = { - label = "Music-secondary"; - id = "music-secondary"; - devices = bigStorageDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/music/flac" = { - label = "Music-flac"; - id = "music-flac"; - devices = bigStorageDevices; - ignorePerms = false; - }; - "${cnf.baseDir}/video" = { - label = "Video"; - id = "video"; - devices = bigStorageDevices; - ignorePerms = false; - }; - }; - overrideDevices = true; - devices = - recursiveUpdate - (genAttrs allDevices (name: { - id = config.secrets.syncthingIDs."${name}"; - })) - { - lipwig.addresses = ["tcp://cynerd.cz"]; + + settings = { + folders = filterDevice { + "${baseDir}/documents" = { + label = "Documents"; + id = "documents"; + devices = allDevices; + ignorePerms = false; + }; + "${baseDir}/notes" = { + label = "Notes"; + id = "notes"; + devices = allDevices; + ignorePerms = false; + }; + "${baseDir}/projects" = { + label = "Projects"; + id = "projects"; + devices = allDevices; + ignorePerms = false; + }; + "${baseDir}/elektroline" = { + label = "Elektroline"; + id = "elektroline"; + devices = allDevices; + ignorePerms = false; + }; + "${baseDir}/images" = { + label = "Images"; + id = "pictures"; + devices = bigStorageDevices; + ignorePerms = false; + }; + "${baseDir}/music" = { + label = "Music"; + id = "music"; + devices = bigStorageDevices; + ignorePerms = false; + }; + "${baseDir}/video" = { + label = "Video"; + id = "video"; + devices = bigStorageDevices; + ignorePerms = false; + }; + "${baseDir}/turris" = { + label = "Turris"; + id = "turris"; + devices = bigStorageDevices; + ignorePerms = false; + }; }; - # TODO phone + + devices = + recursiveUpdate + (genAttrs allDevices (name: { + id = config.secrets.syncthingIDs."${name}"; + })) + { + lipwig.addresses = ["tcp://cynerd.cz"]; + }; + }; }; }; } diff --git a/nixos/modules/users.nix b/nixos/modules/users.nix index 1c143bb..24eedb5 100644 --- a/nixos/modules/users.nix +++ b/nixos/modules/users.nix @@ -3,8 +3,8 @@ config, ... }: let - isNative = config.nixpkgs.hostPlatform == config.nixpkgs.buildPlatform; - isArm = config.nixpkgs.hostPlatform.isAarch; + isNative = pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform; + isArm = pkgs.stdenv.hostPlatform.isAarch; in { users = { mutableUsers = false; @@ -43,12 +43,25 @@ in { }; }; - security.sudo.extraRules = [ - { - groups = ["wheel"]; - commands = ["ALL"]; - } - ]; + security = { + doas = { + enable = true; + extraRules = [ + { + groups = ["wheel"]; + keepEnv = true; + persist = true; + } + ]; + }; + + sudo.extraRules = [ + { + groups = ["wheel"]; + commands = ["ALL"]; + } + ]; + }; services.openssh = { enable = true; @@ -72,9 +85,9 @@ in { enable = !isArm; defaultEditor = !isArm; withNodeJs = true; + withPython3 = true; + withRuby = true; }; - - wireshark.enable = true; }; programs.fuse.userAllowOther = true; diff --git a/nixos/modules/wifi-adm.nix b/nixos/modules/wifi-adm.nix index 1db730c..e69afd1 100644 --- a/nixos/modules/wifi-adm.nix +++ b/nixos/modules/wifi-adm.nix @@ -3,9 +3,55 @@ lib, ... }: let - inherit (lib) mkOption mkEnableOption types mkIf hostapd elemAt; + inherit (lib) mkOption mkEnableOption types mkIf mkMerge hostapd elemAt; cnf = config.cynerd.wifiAP.adm; + wifi-networks = name: { + "${cnf."${name}".interface}" = { + bssid = elemAt cnf."${name}".bssids 0; + ssid = "TurrisAdamkovi"; + authentication = { + mode = "wpa3-sae-transition"; + wpaPasswordFile = "/run/secrets/hostapd-TurrisAdamkovi.pass"; + saePasswordsFile = "/run/secrets/hostapd-TurrisAdamkovi.pass"; + }; + }; + "${cnf."${name}".interface}.milan" = { + bssid = elemAt cnf."${name}".bssids 1; + ssid = "MILAN-AC"; + authentication = { + mode = "wpa2-sha1"; + wpaPasswordFile = "/run/secrets/hostapd-MILAN-AC.pass"; + }; + }; + }; + + net-networks = name: { + "lan-${cnf."${name}".interface}" = { + matchConfig = { + Name = cnf."${name}".interface; + WLANInterfaceType = "ap"; + }; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + ]; + }; + "lan-${cnf."${name}".interface}.milan" = { + matchConfig.Name = "${cnf."${name}".interface}.milan"; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + ]; + }; + }; + wOptions = card: channelDefault: { interface = mkOption { type = with types; nullOr str; @@ -43,32 +89,7 @@ in { enable = true; inherit (hostapd.qualcomAtherosAR9287.wifi4) capabilities; }; - networks = { - "${cnf.ar9287.interface}" = { - bssid = elemAt cnf.ar9287.bssids 0; - ssid = "TurrisAdamkovi"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-TurrisAdamkovi.pass"; - }; - }; - "${cnf.ar9287.interface}-nela" = { - bssid = elemAt cnf.ar9287.bssids 1; - ssid = "Nela"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-Nela.pass"; - }; - }; - "${cnf.ar9287.interface}.milan" = { - bssid = elemAt cnf.ar9287.bssids 2; - ssid = "MILAN-AC"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-MILAN-AC.pass"; - }; - }; - }; + networks = wifi-networks "ar9287"; }; "${cnf.qca988x.interface}" = mkIf (cnf.qca988x.interface != null) { countryCode = "CZ"; @@ -82,96 +103,13 @@ in { enable = true; inherit (hostapd.qualcomAtherosQCA988x.wifi5) capabilities; }; - networks = { - "${cnf.qca988x.interface}" = { - bssid = elemAt cnf.qca988x.bssids 0; - ssid = "TurrisAdamkovi"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-TurrisAdamkovi.pass"; - }; - }; - "${cnf.qca988x.interface}-nela" = { - bssid = elemAt cnf.qca988x.bssids 1; - ssid = "Nela"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-Nela.pass"; - }; - }; - "${cnf.qca988x.interface}.milan" = { - bssid = elemAt cnf.qca988x.bssids 2; - ssid = "MILAN-AC"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-MILAN-AC.pass"; - }; - }; - }; + networks = wifi-networks "qca988x"; }; }; }; - systemd.network.networks = { - "lan-${cnf.ar9287.interface}" = { - matchConfig.Name = cnf.ar9287.interface; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 1; - PVID = 1; - } - ]; - }; - "lan-${cnf.ar9287.interface}-nela" = { - matchConfig.Name = "${cnf.ar9287.interface}-nela"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - "lan-${cnf.ar9287.interface}.milan" = { - matchConfig.Name = "${cnf.ar9287.interface}.milan"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - "lan-${cnf.qca988x.interface}" = { - matchConfig.Name = cnf.qca988x.interface; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 1; - PVID = 1; - } - ]; - }; - "lan-${cnf.qca988x.interface}-nela" = { - matchConfig.Name = "${cnf.qca988x.interface}-nela"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - "lan-${cnf.qca988x.interface}.milan" = { - matchConfig.Name = "${cnf.qca988x.interface}.milan"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - }; + systemd.network.networks = mkMerge [ + (mkIf (cnf.ar9287.interface != null) (net-networks "ar9287")) + (mkIf (cnf.qca988x.interface != null) (net-networks "qca988x")) + ]; }; } diff --git a/nixos/modules/wifi-client.nix b/nixos/modules/wifi-client.nix index 8fc803d..07eb686 100644 --- a/nixos/modules/wifi-client.nix +++ b/nixos/modules/wifi-client.nix @@ -21,8 +21,9 @@ in { networking.wireless = { enable = true; networks = config.secrets.wifiNetworks; - environmentFile = "/run/secrets/wifi.env"; - userControlled.enable = true; + secretsFile = "/run/secrets/wifi.secrets"; + userControlled = true; }; + users.users.cynerd.extraGroups = ["wpa_supplicant"]; }; } diff --git a/nixos/modules/wifi-spt.nix b/nixos/modules/wifi-spt.nix index d013473..dc1de09 100644 --- a/nixos/modules/wifi-spt.nix +++ b/nixos/modules/wifi-spt.nix @@ -6,6 +6,61 @@ inherit (lib) mkOption mkEnableOption types mkIf mkForce mkMerge hostapd elemAt; cnf = config.cynerd.wifiAP.spt; + wifi-networks = name: let + is2g = cnf."${name}".channel <= 14; + in { + "${cnf."${name}".interface}" = { + bssid = elemAt cnf."${name}".bssids 0; + ssid = "TurrisRules${ + if is2g + then "" + else "5" + }"; + authentication = { + mode = "wpa2-sha256"; + wpaPasswordFile = "/run/secrets/hostapd-TurrisRules.pass"; + }; + settings = mkIf is2g { + ieee80211w = mkForce 0; + wpa_key_mgmt = mkForce "WPA-PSK"; # force use without sha256 + }; + }; + "${cnf."${name}".interface}.guest" = { + bssid = elemAt cnf."${name}".bssids 1; + ssid = "Kocovi"; + authentication = { + mode = "wpa2-sha256"; + wpaPasswordFile = "/run/secrets/hostapd-Kocovi.pass"; + }; + }; + }; + + net-networks = name: { + "lan-${cnf."${name}".interface}" = { + matchConfig = { + Name = cnf."${name}".interface; + WLANInterfaceType = "ap"; + }; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + ]; + }; + "lan-${cnf."${name}".interface}-guest" = { + matchConfig.Name = "${cnf."${name}".interface}.guest"; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 2; + PVID = 2; + } + ]; + }; + }; + wOptions = card: channelDefault: { interface = mkOption { type = with types; nullOr str; @@ -48,28 +103,7 @@ in { enable = true; inherit (hostapd.qualcomAtherosAR9287.wifi4) capabilities; }; - networks = { - "${cnf.ar9287.interface}" = { - bssid = elemAt cnf.ar9287.bssids 0; - ssid = "TurrisRules"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-TurrisRules.pass"; - }; - settings = { - ieee80211w = 0; - wpa_key_mgmt = mkForce "WPA-PSK"; # force use without sha256 - }; - }; - "${cnf.ar9287.interface}.guest" = { - bssid = elemAt cnf.ar9287.bssids 1; - ssid = "Kocovi"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-Kocovi.pass"; - }; - }; - }; + networks = wifi-networks "ar9287"; }; }) (mkIf (cnf.qca988x.interface != null) { @@ -90,87 +124,14 @@ in { enable = !is2g; inherit (hostapd.qualcomAtherosQCA988x.wifi5) capabilities; }; - networks = { - "${cnf.qca988x.interface}" = { - bssid = elemAt cnf.qca988x.bssids 0; - ssid = "TurrisRules${ - if is2g - then "" - else "5" - }"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-TurrisRules.pass"; - }; - settings = mkIf is2g { - ieee80211w = 0; - wpa_key_mgmt = mkForce "WPA-PSK"; # force use without sha256 - }; - }; - "${cnf.qca988x.interface}.guest" = { - bssid = elemAt cnf.qca988x.bssids 1; - ssid = "Kocovi"; - authentication = { - mode = "wpa2-sha256"; - wpaPasswordFile = "/run/secrets/hostapd-Kocovi.pass"; - }; - }; - }; + networks = wifi-networks "qca988x"; }; }) ]; }; systemd.network.networks = mkMerge [ - (mkIf (cnf.ar9287.interface != null) { - "lan-${cnf.ar9287.interface}" = { - matchConfig = { - Name = cnf.ar9287.interface; - WLANInterfaceType = "ap"; - }; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 1; - PVID = 1; - } - ]; - }; - "lan-${cnf.ar9287.interface}-guest" = { - matchConfig.Name = "${cnf.ar9287.interface}.guest"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - }) - (mkIf (cnf.qca988x.interface != null) { - "lan-${cnf.qca988x.interface}" = { - matchConfig = { - Name = cnf.qca988x.interface; - WLANInterfaceType = "ap"; - }; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 1; - PVID = 1; - } - ]; - }; - "lan-${cnf.qca988x.interface}-guest" = { - matchConfig.Name = "${cnf.qca988x.interface}.guest"; - networkConfig.Bridge = "brlan"; - bridgeVLANs = [ - { - EgressUntagged = 2; - PVID = 2; - } - ]; - }; - }) + (mkIf (cnf.ar9287.interface != null) (net-networks "ar9287")) + (mkIf (cnf.qca988x.interface != null) (net-networks "qca988x")) ]; }; } diff --git a/nixos/modules/wifi-zd.nix b/nixos/modules/wifi-zd.nix new file mode 100644 index 0000000..c275fc3 --- /dev/null +++ b/nixos/modules/wifi-zd.nix @@ -0,0 +1,112 @@ +{ + config, + lib, + ... +}: let + inherit (lib) mkOption mkEnableOption types mkIf mkForce elemAt; + cnf = config.cynerd.wifiAP.zd; + + wOptions = { + bssids = mkOption { + type = with types; listOf str; + default = []; + description = "BSSIDs for networks."; + }; + channel = mkOption { + type = types.ints.positive; + description = "Channel to be used"; + }; + }; +in { + options = { + cynerd.wifiAP.zd = { + enable = mkEnableOption "Enable Wi-Fi Access Point support (OpenWrt One)"; + wlan0 = wOptions; + wlan1 = wOptions; + }; + }; + + config = mkIf cnf.enable { + # TODO regdom doesn't work for some reason + boot.extraModprobeConfig = '' + options cfg80211 ieee80211_regdom="CZ" + ''; + services.hostapd = { + enable = true; + radios = { + "wlan0" = { + inherit (cnf.wlan0) channel; + countryCode = "CZ"; + wifi4 = { + enable = true; + capabilities = [ + "HT40" + "SHORT-GI-20" + "SHORT-GI-40" + "TX-STBC" + "RX-STBC1" + "MAX-AMSDU-7935" + ]; + }; + networks = { + "wlan0" = { + bssid = elemAt cnf.wlan0.bssids 0; + ssid = "UNas"; + authentication = { + mode = "wpa2-sha256"; + wpaPasswordFile = "/run/secrets/hostapd-UNas.pass"; + }; + }; + "wlan0.guest" = { + bssid = elemAt cnf.wlan0.bssids 1; + ssid = "Koci"; + authentication = { + mode = "wpa2-sha256"; + wpaPasswordFile = "/run/secrets/hostapd-Koci.pass"; + }; + }; + "wlan0.iotd" = { + bssid = elemAt cnf.wlan0.bssids 2; + ssid = "IOTD"; + authentication = { + mode = "wpa2-sha256"; + wpaPasswordFile = "/run/secrets/hostapd-IOTD.pass"; + }; + settings = { + ieee80211w = mkForce 0; + wpa_key_mgmt = mkForce "WPA-PSK"; # force use without sha256 + }; + }; + }; + }; + #"wlan1" = { + #}; + }; + }; + systemd.network.networks = { + "lan-wlan0" = { + matchConfig = { + Name = "wlan0 wlan0.iotd"; + WLANInterfaceType = "ap"; + }; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 1; + PVID = 1; + } + ]; + }; + "lan-wlan0-guest" = { + matchConfig.Name = "wlan0.guest"; + networkConfig.Bridge = "brlan"; + bridgeVLANs = [ + { + EgressUntagged = 2; + PVID = 2; + } + ]; + }; + }; + }; +} diff --git a/nixos/modules/wireguad.nix b/nixos/modules/wireguard.nix index 1b1db90..4fd942c 100644 --- a/nixos/modules/wireguad.nix +++ b/nixos/modules/wireguard.nix @@ -6,7 +6,7 @@ }: let inherit (lib) any all mkEnableOption mkIf mapAttrsToList optional optionals optionalAttrs filterAttrs; inherit (config.networking) hostName; - endpoints = ["lipwig" "spt-omnia" "adm-omnia"]; + endpoints = ["lipwig" "spt-omnia" "adm-omnia" "zd-mox"]; is_endpoint = any (v: v == hostName) endpoints; in { options = { @@ -44,18 +44,24 @@ in { PublicKey = config.secrets.wireguardPubs.spt-omnia; } // (optionalAttrs (!is_endpoint) {PersistentKeepalive = 25;})) - #{ - # wireguardPeerConfig = - # { - # Endpoint = "adm.cynerd.cz:51820"; - # AllowedIPs = [ - # "${config.cynerd.hosts.wg.adm-omnia}/32" - # "10.8.3.0/24" - # ]; - # PublicKey = config.secrets.wireguardPubs.adm-omnia; - # } - # // (optionalAttrs (!is_endpoint) {PersistentKeepalive = 25;}); - #} + ({ + Endpoint = "adm.cynerd.cz:51820"; + AllowedIPs = [ + "${config.cynerd.hosts.wg.adm-omnia}/32" + "10.8.3.0/24" + ]; + PublicKey = config.secrets.wireguardPubs.adm-omnia; + } + // (optionalAttrs (!is_endpoint) {PersistentKeepalive = 25;})) + ({ + Endpoint = "zd.cynerd.cz:51820"; + AllowedIPs = [ + "${config.cynerd.hosts.wg.zd-mox}/32" + "10.8.0.0/24" + ]; + PublicKey = config.secrets.wireguardPubs.zd-mox; + } + // (optionalAttrs (!is_endpoint) {PersistentKeepalive = 25;})) ] ++ (optionals is_endpoint (mapAttrsToList (n: v: { AllowedIPs = "${config.cynerd.hosts.wg."${n}"}/32"; @@ -69,23 +75,23 @@ in { IPv4Forwarding = "yes"; }; routes = - (optional (hostName != "lipwig") { - # OpenVPN network - Gateway = config.cynerd.hosts.wg.lipwig; - Destination = "10.8.0.0/24"; - Metric = 2048; - }) - ++ (optional (hostName != "spt-omnia") { + (optional (hostName != "spt-omnia") { # SPT network Gateway = config.cynerd.hosts.wg.spt-omnia; Destination = "10.8.2.0/24"; Metric = 2048; }) - ++ (optional (hostName != "adm-omnia" && hostName != "lipwig") { - # Adamkovi network + ++ (optional (hostName != "adm-omnia") { + # ADM network Gateway = config.cynerd.hosts.wg.adm-omnia; Destination = "10.8.3.0/24"; Metric = 2048; + }) + ++ (optional (hostName != "zd-mox") { + # ZD network + Gateway = config.cynerd.hosts.wg.zd-mox; + Destination = "10.8.0.0/24"; + Metric = 2048; }); }; }; diff --git a/nixos/nextcloud-extra-apps.json b/nixos/nextcloud-extra-apps.json new file mode 100644 index 0000000..29be7b0 --- /dev/null +++ b/nixos/nextcloud-extra-apps.json @@ -0,0 +1,52 @@ +{ + "fileslibreofficeedit": { + "hash": "sha256-Xqx5snQWintYJG3Q1Crw22TkNw18DdADXkurMQqt3X8=", + "url": "https://github.com/allotropia/nextcloud_files_libreoffice_edit/releases/download/v2.0.1/fileslibreofficeedit.tar.gz", + "version": "2.0.1", + "description": "This adds a new context menu item to the Files dropdown menu \"Edit with LibreOffice\".\nClicking that item will open the file in LibreOffice via WebDAV (the file can then be edited and saved back directly in LibreOffice).\n\nThis greatly improves the user experience when working with Office files in the browser. No need to download, edit, reupload. Instead use the \"Edit with LibreOffice\" item.\n\nThis app requires at least LibreOffice 7.2 on Linux and macOS. On Windows it also works with older LibreOffice versions (since LibreOffice 5.3).", + "homepage": "https://github.com/allotropia/nextcloud_files_libreoffice_edit", + "licenses": [ + "agpl" + ] + }, + "integration_github": { + "hash": "sha256-7fdQzM4yaFJ9To8lIoiQ4IgfKPGqh8ZXnVxy0Xzo+q8=", + "url": "https://github.com/nextcloud-releases/integration_github/releases/download/v3.2.6/integration_github-v3.2.6.tar.gz", + "version": "3.2.6", + "description": "GitHub integration provides a dashboard widget displaying your most important notifications\n and a unified search provider for repositories, issues and pull requests. It also provides a link reference provider\n to render links to issues, pull requests and comments in Talk and Text.", + "homepage": "https://github.com/nextcloud/integration_github", + "licenses": [ + "agpl" + ] + }, + "integration_gitlab": { + "hash": "sha256-f0D9UrlX8bsf4BSTCzb9bN1gYKDlSY9JxmgO6el7HZw=", + "url": "https://github.com/nextcloud-releases/integration_gitlab/releases/download/v5.0.0/integration_gitlab-v5.0.0.tar.gz", + "version": "5.0.0", + "description": "GitLab integration provides a dashboard widget displaying your most important notifications\n and a unified search provider for repositories, issues and merge requests.", + "homepage": "https://github.com/nextcloud/integration_gitlab", + "licenses": [ + "agpl" + ] + }, + "money": { + "hash": "sha256-bEcKzgItP/Bs336qXAI72cGFXkPVNSfzMjrYQ5212K8=", + "url": "https://github.com/powerpaul17/nc_money/releases/download/v0.32.0/money.tar.gz", + "version": "0.32.0", + "description": "Finance manager for Nextcloud.", + "homepage": "https://github.com/powerpaul17/nc_money", + "licenses": [ + "agpl" + ] + }, + "passwords": { + "hash": "sha256-8ER2MqyePpERD7RRfw8Hq5xNx+s8vUhPbDyJ2JvU/ho=", + "url": "https://git.mdns.eu/api/v4/projects/45/packages/generic/passwords/2026.7.0/passwords.tar.gz", + "version": "2026.7.20", + "description": "Passwords is the most advanced password manager for Nextcloud and allows you to manage and store your passwords safely in your own cloud.\nThe intuitive and modern web interface of the app makes it easy to update and add new passwords from anywhere.\nIncluded security checks help you to keep your online accounts safe and up-to-date.\nYou can also share passwords with other Nextcloud users.\n\n**Features**\n * Intuitive and modern user interface\n * Password security monitor\n * Secure encryption\n * Folders & tags\n * Sharing\n * Dashboard Widget\n * API for apps\n * Extensive handbook\n * Import & Export\n * Browser extensions & Apps\n * ... and many more to come\n\n**Support**\n * [Official Chat](https://matrix.to/#/#nextcloud-passwords:chat.passwordsapp.org)\n * [Official Forum](https://help.nextcloud.com/tag/passwords-app)\n * [User Handbook](https://git.mdns.eu/nextcloud/passwords/-/wikis/Users/Index)\n * [Administrator Handbook](https://git.mdns.eu/nextcloud/passwords/-/wikis/Administrators/Index)\n\n**Apps & Extensions**\n * [Official Firefox Add-On](https://addons.mozilla.org/de/firefox/addon/nextcloud-passwords?utm_source=app&utm_medium=nc-apps)\n * [Official Chrome Extension](https://chrome.google.com/webstore/detail/nextcloud-passwords/mhajlicjhgoofheldnmollgbgjheenbi)\n * [Official Microsoft Edge Extension](https://microsoftedge.microsoft.com/addons/detail/cjmlcljdpphgdfpkngjcmeepdpcgpffk)\n * [Android App](https://play.google.com/store/apps/details?id=de.jbservices.nc_passwords_app) by [joleaf](https://gitlab.com/joleaf/nc-passwords-app)\n * [Android App](https://play.google.com/store/apps/details?id=com.hegocre.nextcloudpasswords) by [hegocre](https://github.com/hegocre/NextcloudPasswords)\n * [Windows App (WIP)](https://www.microsoft.com/store/apps/9NXVZ0ZP6D5Z) by [j0chn](https://gitlab.com/j0chn/nextcloud_password_client)\n * [Linux App (WIP)](https://gitlab.com/j0chn/nextcloud_password_client/-/tree/main#linux) by [j0chn](https://gitlab.com/j0chn/nextcloud_password_client)\n * [macOS App (WIP)](https://gitlab.com/j0chn/nextcloud_password_client/-/tree/main#mac-os) by [j0chn](https://gitlab.com/j0chn/nextcloud_password_client)\n * [iOS App](https://apps.apple.com/app/id1546212226) by [Johannes Schliephake](https://github.com/johannes-schliephake/nextcloud-passwords-ios)", + "homepage": "https://passwordsapp.org/", + "licenses": [ + "agpl" + ] + } +} |
