commit 4a8bb042c8bf920873943575b7de2f7e9446640a
parent db5b06a9c63223aeb81cb8d0c51fa1cc9950cbc9
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sun, 23 Jan 2022 23:58:57 +0100
parent db5b06a9c63223aeb81cb8d0c51fa1cc9950cbc9
Author: Leah (ctucx) <leah@ctu.cx>
Date: Sun, 23 Jan 2022 23:58:57 +0100
add host: lollo (router and home-server)
22 files changed, 1372 insertions(+), 0 deletions(-)
A
|
121
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
83
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
124
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
361
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
150
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
87
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
|
115
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/machines/lollo/configuration.nix b/machines/lollo/configuration.nix @@ -0,0 +1,41 @@ +{ config, pkgs, ... }: + +{ + imports = [ + ./hardware-configuration.nix + ../../configurations/common.nix + ./node-exporter.nix + + ./router + ./smarthome + ./websites + + ../../configurations/programs/pipewire.nix + ../../configurations/programs/spotifyd.nix + ./syncthing.nix + ./restic-server.nix + ]; + + boot.loader = { + systemd-boot.enable = true; + efi.canTouchEfiVariables = true; + }; + + time.timeZone = "Europe/Berlin"; + + networking = { + hostName = "lollo"; + domain = "home.ctu.cx"; + useDHCP = false; + }; + + users.users.leah.extraGroups = [ "audio" ]; + + environment.systemPackages = with pkgs; [ + wireguard-tools + ]; + + system.stateVersion = "21.11"; # Did you read the comment? + home-manager.users.leah.home.stateVersion = "21.11"; +} +
diff --git a/machines/lollo/hardware-configuration.nix b/machines/lollo/hardware-configuration.nix @@ -0,0 +1,31 @@ +# Do not modify this file! It was generated by ‘nixos-generate-config’ +# and may be overwritten by future invocations. Please make changes +# to /etc/nixos/configuration.nix instead. +{ config, lib, pkgs, modulesPath, ... }: + +{ + imports = + [ (modulesPath + "/installer/scan/not-detected.nix") + ]; + + boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "nvme" "usbhid" "usb_storage" "sd_mod" "sr_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/53f739d1-5668-422e-81b5-34c1f60ecba8"; + fsType = "ext4"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/1344-D403"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; + # high-resolution display + hardware.video.hidpi.enable = lib.mkDefault true; +}
diff --git a/machines/lollo/node-exporter.nix b/machines/lollo/node-exporter.nix @@ -0,0 +1,19 @@ +{config, lib, pkgs, ...}: + +{ + + services = { + prometheus.exporters.node.enable = true; + nginx = { + enable = true; + virtualHosts."lollo.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations."/node-exporter" = { + proxyPass = "http://127.0.0.1:9100/metrics"; + }; + }; + }; + }; + +}
diff --git a/machines/lollo/restic-server.nix b/machines/lollo/restic-server.nix @@ -0,0 +1,30 @@ +{config, lib, pkgs, ...}: + +{ + + services = { + restic.server = { + enable = true; + appendOnly = true; + extraFlags = [ "--no-auth" ]; + dataDir = "/var/lib/restic"; + }; + + nginx = { + enable = true; + virtualHosts."restic.lollo.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8000/"; + extraConfig = '' + client_max_body_size 10G; + auth_basic Auth; + auth_basic_user_file /var/lib/secrets/restic-auth; + ''; + }; + }; + }; + }; + +}
diff --git a/machines/lollo/router/default.nix b/machines/lollo/router/default.nix @@ -0,0 +1,21 @@ +{ ... }: + +{ + + imports = [ + ./systemd-networkd.nix + ./nftables.nix + ./dnsmasq.nix + ./hostapd.nix + ]; + + boot = { + kernel.sysctl."net.ipv4.ip_forward" = true; + kernel.sysctl."net.ipv6.conf.all.forwarding" = true; + }; + + services.avahi.interfaces = [ "brlan" ]; + networking.useDHCP = false; + +} +
diff --git a/machines/lollo/router/dnsmasq.nix b/machines/lollo/router/dnsmasq.nix @@ -0,0 +1,121 @@ +{ config, pkgs, ... }: + +let + dnsmasq-lease-overview = pkgs.fetchgit { + url = "https://cgit.ctu.cx/dnsmasq-lease-overview/"; + rev = "84c47b17361fd3273f5d7902a407d467ae937cfd"; + sha256 = "1vs589r2ff31lf8wp4kh84ckzfd72wc1bxjf7kxwl8sgm18rijnp"; + }; + +in { + services.resolved.enable = false; + services.dnsmasq = { + enable = true; + extraConfig = '' + local-service + no-resolv + no-hosts + domain-needed + bogus-priv + + + server=1.1.1.1 + server=1.0.0.1 + server=8.8.8.8 + server=8.8.4.4 + + + local=/home.ctu.cx/ + domain=home.ctu.cx + + auth-ttl=600 + auth-server=home.ctu.cx, wg-pbb + auth-zone=home.ctu.cx, 10.0.0.1/24, 195.39.246.32/28, 2a0f:4ac0:acab::1/64 + + host-record=home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=lollo.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=lollo.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=legacy.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=dnsmasq.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=music.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=influx.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=wiki.home.ctu.cx, 195.39.246.41, 2a0f:4ac0:acab::1 + host-record=pbx.home.ctu.cx, 195.39.246.46 + + address=/fritz.box/192.168.178.1 + address=/lollo/10.0.0.1 + + + enable-ra + quiet-ra + + dhcp-authoritative + dhcp-rapid-commit + dhcp-sequential-ip + + dhcp-range=private, 10.0.0.100, 10.0.0.200, 255.255.255.0, 48h + dhcp-range=public, 195.39.246.34, static, 255.255.255.240, 195.39.246.47, 48h + dhcp-range= 2a0f:4ac0:acab::100, 2a0f:4ac0:acab::01ff, ra-names,slaac, 64, 48h + + dhcp-option=option6:information-refresh-time, 6h + dhcp-option=option6:dns-server, [2a0f:4ac0:acab::1] + dhcp-option=private, option:router, 10.0.0.1 + dhcp-option=private, option:dns-server, 10.0.0.1 + dhcp-option=public, option:router, 195.39.246.41 + dhcp-option=public, option:dns-server, 195.39.246.41 + + dhcp-host=f4:06:8d:df:1f:e3, accesspoint, 10.0.0.2 + dhcp-host=2a0f:4ac0:acab::12a, garmin-vivo-3, 10.0.0.210 + + dhcp-host=id:04:ea:56:f2:b4:6c, isa-x390, [2a0f:4ac0:acab::36] + dhcp-host=04:ea:56:f2:b4:6c, isa-x390, 195.39.246.36 + + dhcp-host=id:ac:67:5d:12:2f:5a, isa-p2max, [2a0f:4ac0:acab::37] + dhcp-host=ac:67:5d:12:2f:5a, isa-p2max, 195.39.246.37 + + dhcp-host=id:00:01:00:01:29:1c:39:07:f4:5c:89:c1:dc:b1, isabelles-mbp, [2a0f:4ac0:acab::38] + dhcp-host=f4:5c:89:c1:dc:b1, isabelles-mbp, 195.39.246.38 + + dhcp-host=id:e8:6a:64:f4:49:e7, stasicontainer, [2a0f:4ac0:acab::42] + dhcp-host=e8:6a:64:f4:49:e7, stasicontainer, 195.39.246.42 + + dhcp-host=id:04:ea:56:f3:0b:5b, coladose, [2a0f:4ac0:acab::43] + dhcp-host=04:ea:56:f3:0b:5b, e8:6a:64:d6:e3:33, coladose, 195.39.246.43 + + dhcp-host=34:31:c4:46:88:31, fritz7312, 195.39.246.46 + ''; + }; + + services.phpfpm.pools.dnsmasq = { + user = "dnsmasq"; + group = "dnsmasq"; + settings = { + pm = "dynamic"; + "listen.owner" = config.services.nginx.user; + "pm.max_children" = 1; + "pm.start_servers" = 1; + "pm.min_spare_servers" = 1; + "pm.max_spare_servers" = 1; + "pm.max_requests" = 500; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."dnsmasq.home.ctu.cx" = { + enableACME = true; + forceSSL = true; + root = dnsmasq-lease-overview; + locations = { + "/".tryFiles = "$uri $uri/ /index.php?$query_string"; + "/".index = "index.php index.html"; + "~ \.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools.dnsmasq.socket}; + fastcgi_index index.php; + ''; + }; + }; + }; + +} +
diff --git a/machines/lollo/router/hostapd.nix b/machines/lollo/router/hostapd.nix @@ -0,0 +1,17 @@ +{ ... }: + +let + secrets = import ../../../secrets; + +in { + + services.hostapd = { + enable = false; + ssid = "hostapd.home.ctu.cx"; + wpaPassphrase = secrets.hosts.lollo.hostapd.passphrase; + interface = "wlp3s0"; + extraConfig = "bridge=brlan"; + }; + +} +
diff --git a/machines/lollo/router/nftables.nix b/machines/lollo/router/nftables.nix @@ -0,0 +1,15 @@ +{ config, pkgs, ... }: + +{ + + networking = { + firewall.enable = false; + + nftables = { + enable = true; + rulesetFile = ./ruleset.nft; + }; + }; + +} +
diff --git a/machines/lollo/router/ruleset.nft b/machines/lollo/router/ruleset.nft @@ -0,0 +1,83 @@ +flush ruleset + +table inet firewall { + chain inbound { + # By default, drop all traffic unless it meets a filter + # criteria specified by the rules that follow below. + type filter hook input priority 0; + policy drop; + + # Allow traffic from established and related packets. + ct state established,related accept + + # Drop invalid packets. + ct state invalid drop + + # Allow local connections. + iifname lo accept + iifname brlan accept + + # Allow all ICMP and IGMP traffic, but enforce a rate limit + # to help prevent some types of flood attacks. + ip protocol icmp limit rate 5/second accept + ip protocol igmp limit rate 5/second accept + #ip6 protocol ipv6-icmp icmpv6-type redirect drop + #ip6 protocol ipv6-icmp icmpv6-type 139 drop + ip6 nexthdr ipv6-icmp limit rate 5/second accept + + # Allow some ports + tcp dport ssh accept comment "ssh" + tcp dport domain accept comment "dns (tcp)" + udp dport domain accept comment "dns (udp)" + tcp dport http accept comment "http" + tcp dport https accept comment "https" + tcp dport 22000 accept comment "syncthing" + udp dport 21027 accept comment "syncthing" + tcp dport 5201 accept comment "iperf3 (tcp)" + udp dport 5201 accept comment "iperf3 (udp)" + } + + chain forward { + # By default, drop all traffic unless it meets a filter + type filter hook forward priority 0; + policy drop; + + # Allow traffic from established and related packets. + ct state established,related accept + + # Drop invalid packets. + ct state invalid drop + + # local clients can do whatever + iifname brlan accept + + # Allow all ICMP and IGMP traffic, but enforce a rate limit + # to help prevent some types of flood attacks. + ip protocol icmp limit rate 5/second accept + ip6 nexthdr ipv6-icmp limit rate 5/second accept + ip protocol igmp limit rate 5/second accept + + #make public ips world accessible + ip daddr 195.39.246.33/28 accept + } + + chain outbound { + # Allow all outbound traffic + type filter hook output priority 0 + policy accept + } + +} + +table ip nat { + chain prerouting { + type nat hook prerouting priority -100 + policy accept + } + + chain postrouting { + type nat hook postrouting priority 0 + policy accept + oifname enp2s0 masquerade + } +}
diff --git a/machines/lollo/router/systemd-networkd.nix b/machines/lollo/router/systemd-networkd.nix @@ -0,0 +1,124 @@ +{ ... }: + +{ + + systemd.network = { + enable = true; + netdevs = { + + "20-brlan" = { + netdevConfig = { + Kind = "bridge"; + Name = "brlan"; + }; + }; + + "30-enp2s0.5" = { + netdevConfig = { + Kind = "vlan"; + Name = "enp2s0.5"; + }; + vlanConfig = { + Id = 5; + }; + }; + + "40-wg-pbb" = { + netdevConfig = { + Kind = "wireguard"; + Name = "wg-pbb"; + }; + wireguardConfig = { + PrivateKeyFile = "/var/lib/secrets/wg-pbb.privkey"; + ListenPort = 51820; + FirewallMark = 51820; + }; + wireguardPeers = [{ + wireguardPeerConfig={ + Endpoint = "195.39.247.172:51820"; + PublicKey = "QOQTpxvT122fiKBcN4QDADOjoDDzEW9sMWn/qngVF0Q="; + AllowedIPs = [ "0.0.0.0/0" "::/0" ]; + PersistentKeepalive = 1; +# RouteTable = "off"; + }; + }]; + }; + + }; + + networks = { + + "10-enp2s0" = { + matchConfig = { + Name = "enp2s0"; + }; + DHCP = "yes"; + vlan = [ "enp2s0.5" ]; + }; + + "20-brlan" = { + matchConfig = { + Name = "brlan"; + Driver = "bridge"; + }; + DHCP = "no"; + address = [ + "10.0.0.1/24" + "195.39.246.41/28" + "2a0f:4ac0:acab::1/62" + ]; + routingPolicyRules = [ + { routingPolicyRuleConfig = { + From = "195.39.246.32/28"; + Table = 254; + Priority = 1900; + SuppressPrefixLength = 0; + };} + { routingPolicyRuleConfig = { + From = "2a0f:4ac0:acab::/62"; + Table = 254; + Priority = 1900; + SuppressPrefixLength = 0; + };} + { routingPolicyRuleConfig = { + From = "195.39.246.32/28"; + Table = 1234; + Priority = 2000; + };} + { routingPolicyRuleConfig = { + From = "2a0f:4ac0:acab::/62"; + Table = 1234; + Priority = 2000; + };} + ]; + }; + + "30-enp2s0.5" = { + matchConfig = { + Name = "enp2s0.5"; + }; + bridge = [ "brlan" ]; + }; + + "40-wg-pbb" = { + matchConfig = { + Name = "wg-pbb"; + }; + linkConfig = { + MTUBytes = "1472"; + }; + routes = [ + { routeConfig = { + Destination = "0.0.0.0/0"; + Table = "1234"; + };} + { routeConfig = { + Destination = "::/0"; + Table = "1234"; + };} + ]; + }; + + }; + }; +}
diff --git a/machines/lollo/smarthome/default.nix b/machines/lollo/smarthome/default.nix @@ -0,0 +1,14 @@ +{config, lib, pkgs, ...}: + +{ + + imports = [ + ./zigbee2mqtt.nix + ./mbusd.nix + ./serial2tcp.nix + + ./influxdb2.nix + ./smartied.nix + ]; + +}
diff --git a/machines/lollo/smarthome/influxdb2.nix b/machines/lollo/smarthome/influxdb2.nix @@ -0,0 +1,18 @@ +{config, lib, pkgs, ...}: + +{ + + systemd.services.influxdb2.serviceConfig.ExecStartPost = "${pkgs.bash}/bin/bash -c 'until ${pkgs.netcat}/bin/nc -z 127.0.0.1 8086; do sleep 0.2; done'"; + + services.influxdb2.enable = true; + + services.nginx = { + enable = true; + virtualHosts."influx.home.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations."/".proxyPass = "http://127.0.0.1:8086/"; + }; + }; + +}
diff --git a/machines/lollo/smarthome/mbusd.nix b/machines/lollo/smarthome/mbusd.nix @@ -0,0 +1,37 @@ +{config, lib, pkgs, ...}: + +let + mbusd = pkgs.stdenv.mkDerivation rec { + pname = "mbusd"; + version = "0.5.0"; + + src = pkgs.fetchFromGitHub { + owner = "3cky"; + repo = pname; + rev = "v${version}"; + sha256 = "1mvrwr02vcsgf9lc9bq4mhr0s6ww5z7ml7lwpyrl4axpz59i4l9s"; + }; + + nativeBuildInputs = with pkgs; [ cmake pkgconfig ]; + }; + +in { + + services.udev.extraRules = ''SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{serial}=="1337", SYMLINK+="modbus0"''; + + systemd.services.mbusd = { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" "dev-modbus0.device" ]; + wants = [ "network-online.target" "dev-modbus0.device" ]; + after = [ "network-online.target" "dev-modbus0.device" ]; + + serviceConfig = { + ExecStart = "${mbusd}/bin/mbusd -d -v2 -L - -p /dev/modbus0 -s 9600 -m 8n1 -C 32 -N 3 -R 100 -W 500 -T 60"; + Restart = "on-failure"; + RestartSec = "1"; + StandardOutput = "journal"; + StandardError = "journal"; + }; + }; + +}
diff --git a/machines/lollo/smarthome/serial2tcp.nix b/machines/lollo/smarthome/serial2tcp.nix @@ -0,0 +1,39 @@ +{ pkgs, ...}: + +let + serial2tcp = pkgs.nimPackages.buildNimPackage { + pname = "serial2tcp"; + version = "0.1.0"; + nimBinOnly = true; + + src = pkgs.fetchgit { + url = "https://cgit.ctu.cx/serial2tcp"; + rev = "6a81ddbc0e68cbb4e020a3ddc81cd93947a8da5f"; + sha256 = "1b8iigq3r21sg02wqsxs26y74m44q92phn18510y3nxm617s5k5w"; + }; + }; + +in { + + services.udev.extraRules = ''SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="tempsensors0"''; + + systemd.services.serial2tcp = { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" "dev-tempsensors0.device" ]; + wants = [ "network-online.target" "dev-tempsensors0.device" ]; + after = [ "network-online.target" "dev-tempsensors0.device" ]; + + serviceConfig = { + ExecStartPre = "${pkgs.coreutils}/bin/stty -F /dev/tempsensors0 raw -echo -echoe -echok speed 9600"; + ExecStart = "${serial2tcp}/bin/serial2tcp"; + Restart = "on-failure"; + RestartSec = "5"; + }; + + environment = { + PORT = "2342"; + SERIAL_DEVICE = "/dev/tempsensors0"; + }; + }; + +}
diff --git a/machines/lollo/smarthome/smartied.nix b/machines/lollo/smarthome/smartied.nix @@ -0,0 +1,361 @@ +{ pkgs, ...}: + +let + secrets = import ../../../secrets; + + ws = pkgs.fetchFromGitHub { + owner = "treeform"; + repo = "ws"; + rev = "0.4.3"; + sha256 = "03dyd36y5r8zbvcwih3nsvd7fa13vm6hdz7v0wglgv7mjpwpfik5"; + }; + + nmqtt = pkgs.fetchFromGitHub { + owner = "zevv"; + repo = "nmqtt"; + rev = "v1.0.4"; + sha256 = "1by0xyqz754dny19lf8rpkg42passnj0rs6rk3jr763m1zr803mc"; + }; + + smartied = pkgs.nimPackages.buildNimPackage { + pname = "smartied"; + version = "0.1.0"; + nimBinOnly = true; + buildInputs = [ pkgs.libmodbus ws nmqtt ]; + + src = pkgs.fetchgit { + url = "https://cgit.ctu.cx/smartied"; + rev = "6b0b4163a30caf95468f1bf724b53b9e02344b29"; + sha256 = "0zv91hxhxsqs1qrijlkqkr81w4p14qrn33xh0kj4sxiplgxfz78v"; + }; + }; + + smartiePWA = import "${pkgs.fetchgit { + url = "https://cgit.ctu.cx/smartie-pwa/"; + rev = "3fe40dfd8211f05751c3df98402eb2367636a6f7"; + sha256 = "1zvhgmbbfxgxjaq8wbw3b8k95h5p5rqk28g55av7rpxxgmkcmz7y"; + }}" {}; + + config = { + devices = { + "modbus-20" = { + type = "RelayBoard"; + firstRegister = 0; + count = 4; + address = 20; + }; + + "modbus-60" = { + type = "PowerMeter"; + model = "SDM120"; + address = 60; + }; + + "lacrosse-l1" = { + type = "LacrosseTempSensor"; + id = "27"; + }; + + "lacrosse-l2" = { + type = "LacrosseTempSensor"; + id = "3a"; + }; + + "lacrosse-kuehlschrank" = { + type = "LacrosseTempSensor"; + id = "33"; + }; + + "lacrosse-bad" = { + type = "LacrosseTempSensor"; + id = "5"; + }; + + "tradfri-lamp-l" = { + type = "Zigbee2MqttLamp"; + lampType = "WhiteSpectrum"; + deviceName = "ikea_lamp_l"; + }; + + "tradfri-lamp-i" = { + type = "Zigbee2MqttLamp"; + lampType = "WhiteSpectrum"; + deviceName = "ikea_lamp_i"; + }; + + "tradfri-lamp-hallway" = { + type = "Zigbee2MqttLamp"; + lampType = "WhiteSpectrum"; + deviceName = "ikea_lamp_hallway"; + }; + + "tradfri-lamp-kitchen" = { + type = "Zigbee2MqttLamp"; + lampType = "WhiteSpectrum"; + deviceName = "ikea_lamp_kitchen"; + }; + + "tradfri-lamp-bathroom" = { + type = "Zigbee2MqttLamp"; + lampType = "WhiteSpectrum"; + deviceName = "ikea_lamp_bathroom"; + }; + + "tradfri-lamp-i-rgb" = { + type = "Zigbee2MqttLamp"; + lampType = "RGB"; + deviceName = "ikea_lamp_i_rgb"; + }; + + "tradfri-co-l" = { + type = "Zigbee2MqttRelay"; + deviceName = "ikea_control_outlet_l"; + }; + + "tradfri-co-i-desk" = { + type = "Zigbee2MqttRelay"; + deviceName = "ikea_control_outlet_i_desk"; + }; + + "tradfri-button-l-desk" = { + type = "Zigbee2MqttRemote"; + deviceName = "ikea_button_l_desk"; + actions = { + on = [{ + type = "SwitchStateAction"; + deviceName = "tradfri-co-l"; + toggle = true; + }]; + }; + }; + + "tradfri-motion-sensor" = { + type = "Zigbee2MqttMotionSensor"; + deviceName = "ikea_motionsensor"; + occupyActions = [{ + type = "SwitchStateAction"; + deviceName = "tradfri-lamp-bathroom"; + relay = 0; + state = true; + }]; + clearActions = [{ + type = "SwitchStateAction"; + deviceName = "tradfri-lamp-bathroom"; + relay = 0; + state = false; + }]; + }; + }; + + clientConfigs = { + "smarthome-pwa" = { + views = [ + { + url = "room_l"; + name = "Room (L)"; + icon = "lightbulb"; + type = "switches"; + switches = [ + { + name = "Ceiling Light"; + device = "tradfri-lamp-l"; + relay = 0; + } + { + name = "Lights under Desk"; + device = "modbus-20"; + relay = 1; + } + { + name = "Bed"; + device = "tradfri-co-l"; + relay = 0; + } + { + name = "PC-Speaker"; + device = "modbus-20"; + relay = 0; + } + ]; + } + { + url = "room_i"; + name = "Room (I)"; + icon = "lightbulb"; + type = "switches"; + switches = [ + { + name = "Ceiling Light"; + device = "tradfri-lamp-i"; + relay = 0; + } + { + name = "RGB Lamp"; + device = "tradfri-lamp-i-rgb"; + relay = 0; + } + { + name = "Desk"; + device = "tradfri-co-i-desk"; + relay = 0; + } + ]; + } + { + url = "room_others"; + name = "Other Rooms"; + icon = "lightbulb"; + type = "switches"; + switches = [ + { + name = "Hallway: Ceiling Light"; + device = "tradfri-lamp-hallway"; + relay = 0; + } + { + name = "Kitchen: Ceiling Light"; + device = "tradfri-lamp-kitchen"; + relay = 0; + } + { + name = "Bathroom: Ceiling Light"; + device = "tradfri-lamp-bathroom"; + relay = 0; + } + ]; + } + { + url = "powermeter"; + name = "Power Meter"; + icon = "power"; + type = "powermeter"; + meters = [ + { + name = "Zimmer"; + device = "modbus-60"; + } + ]; + } + { + url = "temperature"; + name = "Temperature"; + icon = "brightness_7"; + type = "temperature"; + sensors = [ + { + name = "Kühlschrank"; + device = "lacrosse-kuehlschrank"; + } + { + name = "L Zimmer"; + device = "lacrosse-l1"; + } + { + name = "L Zimmer2"; + device = "lacrosse-l2"; + } + { + name = "Bad"; + device = "lacrosse-bad"; + } + ]; + } + { + url = "departures"; + name = "Departures"; + icon = "departure_board"; + type = "departures"; + source = "https://f2k1.de/haltestellen.php"; + } + { + url = "fritzbox"; + name = "Fritz!Box"; + icon = "router"; + type = "redirect"; + destination = "http://192.168.178.1/"; + } + { + url = "grafana"; + name = "Grafana-Dashboard"; + icon = "multiline_chart"; + type = "redirect"; + destination = "https://grafana.ctu.cx"; + } + { + url = "fahrrad"; + name = "Fahrradkarte"; + icon = "directions_bike"; + type = "redirect"; + destination = "https://www.nextbike.de/de/kielregion/"; + } + { + url = "settings"; + name = "Settings"; + icon = "settings"; + type = "settings"; + sourceLink = "https://cgit.ctu.cx/smarthome-pwa"; + } + ]; + }; + }; + + serverConfig = { + frontendPort = 5000; + accessToken = secrets.hosts.lollo.smartied.accessToken; + modbus.host = "10.0.0.1"; + modbus.port = 502; + mqtt.host = "10.0.0.1"; + mqtt.port = 1883; + lacrosse.host = "10.0.0.1"; + lacrosse.port = 2342; + powermeterUpdateIntervalSec = 20; + + influx = { + host = "10.0.0.1"; + port = 8086; + authToken = secrets.hosts.lollo.smartied.influxToken; + powermetersDatabase = "powermeters"; + sensorsDatabase = "sensors"; + }; + }; + }; + + configFile = pkgs.writeText "smartied-config.json" (builtins.toJSON config); + +in { + + systemd.services.smartied = { + wantedBy = [ "multi-user.target" ]; + requires = [ "network-online.target" "mbusd.service" "serial2tcp.service" "influxdb2.service" "zigbee2mqtt.service" ]; + after = [ "network-online.target" "mbusd.service" "serial2tcp.service" "influxdb2.service" "zigbee2mqtt.service" ]; + + serviceConfig = { + ExecStart = "${smartied}/bin/smartied"; + Restart = "on-failure"; + RestartSec = "5"; + }; + + environment = { + CONFIG_PATH = configFile; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."home.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations = { + "/" = { + root = smartiePWA; + index = "index.html"; + }; + "/ws" = { + proxyPass = "http://127.0.0.1:5000/ws"; + proxyWebsockets = true; + }; + }; + }; + }; + +}
diff --git a/machines/lollo/smarthome/zigbee2mqtt.nix b/machines/lollo/smarthome/zigbee2mqtt.nix @@ -0,0 +1,150 @@ +{config, lib, pkgs, ...}: + +let + pkgsUnstable = import <nixpkgsUnstable> {}; + secrets = import ../../../secrets; + +in { + + systemd.services.zigbee2mqtt = { + requires = [ "mosquitto.service" ]; + after = [ "mosquitto.service" ]; + }; + + services = { + udev.extraRules = '' + ATTR{idVendor}=="0451", ATTR{idProduct}=="16a8", ENV{ID_MM_DEVICE_IGNORE}="1" + SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="16a8", SYMLINK+="zigbee0" + ''; + + mosquitto = { + enable = true; + persistence = false; + settings = { + max_keepalive = 60; + }; + listeners = [{ + port = 1883; + omitPasswordAuth = true; + users = {}; + settings = { + allow_anonymous = true; + }; + acl = [ "topic readwrite #" "pattern readwrite #" ]; + }]; + }; + + zigbee2mqtt = { + enable = true; + package = pkgsUnstable.zigbee2mqtt; + settings = { + homeassistant = false; + permit_join = false; + + mqtt = { + base_topic = "zigbee2mqtt"; + server = "mqtt://127.0.0.1"; + }; + + serial = { + port = "/dev/zigbee0"; + disable_led = true; + }; + + frontend = { + port = 8422; + host = "0.0.0.0"; + }; + + advanced = { + log_level = "info"; + log_output = [ "console" ]; + network_key = secrets.hosts.lollo.zigbee2mqtt.network_key; + }; + + devices = { + "0x84fd27fffeaaa597".friendly_name = "ikea_lamp_i"; + "0x84fd27fffe6b9ddd".friendly_name = "ikea_lamp_l"; + "0x84fd27fffe44369e".friendly_name = "ikea_lamp_kitchen"; + "0x84fd27fffe3a0b93".friendly_name = "ikea_lamp_bathroom"; + "0x84fd27fffea515fc".friendly_name = "ikea_lamp_hallway"; + "0x842e14fffe57daae".friendly_name = "ikea_lamp_i_rgb"; + + "0x5c0272fffec9006c".friendly_name = "ikea_remote_i_door"; + "0x804b50fffe42a74e".friendly_name = "ikea_remote_l_door"; + "0x5c0272fffeca585a".friendly_name = "ikea_remote_kitchen_door"; + "0x842e14fffe1ab485".friendly_name = "ikea_remote_bathroom"; + "0x804b50fffe7df0be".friendly_name = "ikea_remote_hallway_entrancedoor"; + "0x0c4314fffe194a18".friendly_name = "ikea_remote_hallway"; + "0x0c4314fffe194ca3".friendly_name = "ikea_remote_i_desk"; + + + "0x588e81fffe3ec895".friendly_name = "ikea_button_l_desk"; + + "0xcc86ecfffe8bf621".friendly_name = "ikea_control_outlet_i_desk"; + "0x588e81fffebcdc1e".friendly_name = "ikea_control_outlet_l"; + + "0x847127fffecd89b6".friendly_name = "ikea_motionsensor"; + }; + + groups = { + "1" = { + friendly_name = "room_i"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_lamp_i" + "ikea_lamp_i_rgb" + ]; + }; + "2" = { + friendly_name = "room_l"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_lamp_l" + ]; + }; + "3" = { + friendly_name = "room_kitchen"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_lamp_kitchen" + ]; + }; + "4" = { + friendly_name = "room_bathroom"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_lamp_bathroom" + ]; + }; + "5" = { + friendly_name = "room_hallway"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_lamp_hallway" + ]; + }; + "6" = { + friendly_name = "room_i_desk"; + retain = false; + transition = 2; + optimistic = true; + devices = [ + "ikea_control_outlet_i_desk" + ]; + }; + }; + }; + }; + }; +}
diff --git a/machines/lollo/syncthing.nix b/machines/lollo/syncthing.nix @@ -0,0 +1,26 @@ +{config, lib, pkgs, ...}: + +{ + + imports = [ + ../../configurations/programs/syncthing.nix + ]; + + services = { + syncthing = { + guiAddress = "0.0.0.0:8384"; + }; + + nginx = { + enable = true; + virtualHosts."syncthing.lollo.ctu.cx" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8384/"; + }; + }; + }; + }; + +}
diff --git a/machines/lollo/websites/default.nix b/machines/lollo/websites/default.nix @@ -0,0 +1,11 @@ +{ ... }: + +{ + + imports = [ + ./wiki.home.ctu.cx.nix + ./music.home.ctu.cx.nix + ]; + +} +
diff --git a/machines/lollo/websites/music.home.ctu.cx.nix b/machines/lollo/websites/music.home.ctu.cx.nix @@ -0,0 +1,87 @@ +{ config, pkgs, lib, ... }: + +let + webmusic-nginx = pkgs.fetchgit { + url = "https://cgit.ctu.cx/webmusic-nginx"; + rev = "ac42fd4ab6820f5e840b13cbd03f3cdf0ae149ff"; + sha256 = "00griw6qn3qw2g3ga5nn5p7dk0xac9wa2ni35n4a4yasd1y71xx8"; + }; + +in { + + systemd.services.nginx.serviceConfig.ProtectHome = lib.mkForce false; + + environment.systemPackages = [ pkgs.bindfs ]; + + fileSystems."/mnt/music_originals" = { + device = "/home/leah/syncthing/Music (Originals)"; + fsType = "fuse.bindfs"; + options = [ "ro" "perms=0000:a+rX" ]; + }; + + services.nginx = { + enable = true; + virtualHosts."music.home.ctu.cx" = { + enableACME = true; + forceSSL = true; + root = "/mnt/music_originals"; + locations = { + + "~ ^(.*/)$".extraConfig = '' + autoindex on; + autoindex_exact_size off; + autoindex_format xml; + + xslt_string_param path $uri; + xslt_stylesheet ${webmusic-nginx}/webmusic.xslt; + + auth_basic 'Auth required'; + auth_basic_user_file /var/lib/secrets/music-auth; + ''; + + "~(.*)playlist.m3u$".extraConfig = '' + set $url http://127.0.0.1:81$1; + proxy_pass $url; + proxy_set_header Domain $scheme://$host; + proxy_hide_header 'Content-Type'; + add_header 'Content-Type' 'text/plain'; + ''; + + "/assets/".alias = "${webmusic-nginx}/"; + }; + + extraConfig = '' + satisfy any; + allow 2a0f:4ac0:acab::/48; + allow 10.0.0.0/8; + allow 195.39.246.32/28; + allow 195.39.247.48/29; + ''; + }; + + appendHttpConfig = '' + server { + server_name webmusic.local; + listen 81; + access_log off; + + allow 127.0.0.1; + deny all; + + root /mnt/music_originals; + + location / { + autoindex on; + autoindex_exact_size off; + autoindex_format xml; + + xslt_string_param domain $http_domain; + xslt_string_param path $uri; + xslt_stylesheet ${webmusic-nginx}/webmusic-playlist.xslt; + } + } + ''; + }; + +} +
diff --git a/machines/lollo/websites/wiki.home.ctu.cx.nix b/machines/lollo/websites/wiki.home.ctu.cx.nix @@ -0,0 +1,115 @@ +{ config, pkgs, lib, ... }: + +let + PineDocsConfig = { + title = "ctucx.wiki"; + content_dir = "/home/leah/syncthing/Wiki"; + index = "index.md"; + layout = "wiki"; + color_scheme = "pinedocs"; + highlight_theme = "darcula"; + code_transparent_bg = false; + open_dirs = "all"; + render_footer = true; + exclude_files = [ ".git" ".db" ".swp" ".stfolder" ".stversions" ]; + show_file_extension = true; + menu_link_format = "default"; + render_max_file_size = 50; + }; + + fetcher = (args: pkgs.fetchurl { inherit (args) name urls sha256; }); + cacheEntries = [ + { name = "stephank_composer-plugin-nixify-1.1.0.0"; filename = "stephank/composer-plugin-nixify/6b00aedf28221acbb64a87222a0eb819404901f2.zip"; sha256 = "ac7cc480698f8717fb9fce4077b81303d37fe6ab2b89c8547cd7f9451598ee1e"; urls = [ "https://api.github.com/repos/stephank/composer-plugin-nixify/zipball/d93c4348388d714d7d81b41e34ccb2ae9c2131c2" ]; } + { name = "symfony_deprecation-contracts-2.2.0.0"; filename = "symfony/deprecation-contracts/99b9801994a098b194130905f1f0df2d1f43254c.zip"; sha256 = "20bc7b59da2900146ab95c1b7340b2b934e3ca54a773539254f846a5404fc55b"; urls = [ "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665" ]; } + { name = "symfony_polyfill-ctype-1.18.1.0"; filename = "symfony/polyfill-ctype/6b6206c0107a01483ce3308f2596bf1b08154055.zip"; sha256 = "dbd2243692a5c57b9b902c4f87dbe1f5eefc340170347ed8049035b8cde7f19e"; urls = [ "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454" ]; } + { name = "symfony_polyfill-mbstring-1.18.1.0"; filename = "symfony/polyfill-mbstring/f5074ca4813832ac106584ce48b1812575d61847.zip"; sha256 = "a4f0b3117da1ca3fddefac6e8fd04f37c8d033aa3d3a79aef50323f19484cec4"; urls = [ "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a" ]; } + { name = "symfony_yaml-5.1.7.0"; filename = "symfony/yaml/c1cfb60fb6318351d391fcd682a08fdc1711e238.zip"; sha256 = "4c811349d0a57fafc04a1dac58832f08aa7df4fc4f94732d3bd6136aeb4ea15e"; urls = [ "https://api.github.com/repos/symfony/yaml/zipball/e147a68cb66a8b510f4b7481fe4da5b2ab65ec6a" ]; } + { name = "twig_twig-3.1.0.0"; filename = "twig/twig/ad4f94d1500e3eb72e2a188822192a144b07a2b5.zip"; sha256 = "43dab6f872af1c8e5bc4efc93a9fe40503eaa821f4969a03ef0d87eb2ff5b16d"; urls = [ "https://api.github.com/repos/twigphp/Twig/zipball/9a29e1fa7b5431969f96878b8662e3fcb18601b7" ]; } + ]; + + # Shell snippet to collect all project dependencies. + collectCacheScript = pkgs.writeText "collect-cache.sh" ( + pkgs. lib.strings.concatMapStrings (args: '' + ( + cacheFile=${lib.strings.escapeShellArg args.filename} + cacheFilePath="$COMPOSER_CACHE_DIR/files/$cacheFile" + mkdir -p "$(dirname "$cacheFilePath")" + cp ${lib.strings.escapeShellArg (fetcher args)} "$cacheFilePath" + ) + '') cacheEntries + ); + + PineDocs = pkgs.stdenv.mkDerivation rec { + pname = "PineDocs"; + version = "1.2.2"; + src = pkgs.fetchFromGitHub { + owner = "xy2z"; + repo = "PineDocs"; + rev = "${version}"; + sha256 = "0khxhgp4gnjgcabd14bkpqy9597xzm022ha28g2k1mslhazbs4sv"; + }; + + buildInputs = with pkgs; [ php unzip ]; + + # Defines the shell alias to run Composer. + postHook = ''composer () { + php "$NIX_COMPOSER_PATH" "$@" + }''; + + configurePhase = '' + # Set the cache directory for Composer. + export COMPOSER_CACHE_DIR="$NIX_BUILD_TOP/.composer/cache"; + + # Build the cache directory contents. + source ${collectCacheScript}; + + # Store the absolute path to Composer for the 'composer' alias. + export NIX_COMPOSER_PATH="$(readlink -f ${lib.strings.escapeShellArg pkgs.phpPackages.composer.src})"; + + # Run normal Composer install to complete dependency installation. + composer install; + ''; + + installPhase = '' + mv $PWD $out; + touch $out/config/config.yaml; + echo '${builtins.toJSON PineDocsConfig}' > $out/config/config.yaml; + ''; + }; + +in { + + systemd.services.phpfpm-pinedocs.serviceConfig.ProtectHome = lib.mkForce false; + + services.phpfpm.pools.pinedocs = { + user = "leah"; + group = "users"; + settings = { + pm = "dynamic"; + "listen.owner" = config.services.nginx.user; + "pm.max_children" = 2; + "pm.start_servers" = 2; + "pm.min_spare_servers" = 1; + "pm.max_spare_servers" = 2; + "pm.max_requests" = 500; + }; + }; + + services.nginx = { + enable = true; + virtualHosts."wiki.home.ctu.cx" = { + enableACME = true; + forceSSL = true; + root = "${PineDocs}/public"; + locations = { + "/".index = "index.php index.html"; + "~ \.php$".extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools.pinedocs.socket}; + fastcgi_index index.php; + ''; + }; + }; + }; + +} +
diff --git a/nix/sources.json b/nix/sources.json @@ -34,5 +34,17 @@ "type": "tarball", "url": "https://github.com/NixOS/nixpkgs/archive/330da7601fd570b9e5e5d19f32789c57df4ddceb.tar.gz", "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz" + }, + "nixpkgsUnstable": { + "branch": "nixpkgs-unstable", + "description": "Nix Packages collection", + "homepage": "", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a3d847c3bd3a3b75b3057d7b3730d3308dd8fd59", + "sha256": "1s9afl5kg8fv8vkd5b42mckiswgmbqj7aqhaxg246glwhy405iy1", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a3d847c3bd3a3b75b3057d7b3730d3308dd8fd59.tar.gz", + "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz" } }