# vim: si ai sts=2 sw=2 { config, lib, pkgs, ... }: let wan = "wan0"; lan = "lan0"; hostName = "nano"; domain = "home.arpa"; tailnet = "hydra-pinecone.ts.net"; dnsmasqEnable = true; in { imports = [ ./settings/configuration/nix-linux.nix ]; age.secrets = { dyndns.file = ../secrets/dyndns.age; acme.file = ../secrets/acme.age; syncthing.file = ../secrets/syncthing.age; }; boot.loader.timeout = lib.mkForce 1; boot.loader.efi.canTouchEfiVariables = false; # is r/o for some reason boot.loader.systemd-boot = { installDeviceTree = true; edk2-uefi-shell = { enable = true; }; }; srvos.boot.consoles = [ "ttyS2,1500000" ]; boot.kernelPackages = pkgs.linuxWithBSDDisklabel; nixpkgs = { overlays = [ (self: super: { linuxWithBSDDisklabel = super.linuxPackagesFor (super.linux.override { structuredExtraConfig = with lib.kernel; { BSD_DISKLABEL = yes; }; ignoreConfigErrors = false; }); }) ]; }; hardware.deviceTree = { enable = true; name = "rockchip/rk3588s-nanopi-r6c.dtb"; }; boot.kernelModules = [ "tcp_lp" ]; boot.kernel.sysctl = { "net.ipv6.conf.all.accept_ra" = 0; "net.ipv6.conf.all.autoconf" = 0; "net.ipv6.conf.all.use_tempaddr" = 0; "net.ipv6.conf.${wan}.accept_ra" = 2; "net.ipv6.conf.${wan}.autoconf" = 1; "net.ipv4.tcp_slow_start_after_idle" = 0; "net.ipv4.tcp_ecn" = 1; "net.ipv4.tcp_fastopen" = "0x3"; "net.ipv4.tcp_allowed_congestion_control" = "reno cubic lp"; "net.core.default_qdisc" = "fq"; }; networking = { useDHCP = false; inherit domain hostName; hosts = { "fd7a:115c:a1e0::53" = [ "tailscale" "ts" ]; "192.168.100.1" = [ "modem" "pyur" ]; "192.168.4.1" = [ "lte" ]; }; nameservers = [ "2620::fe:fe" "2620::fe:9" "9.9.9.9" "149.112.112.112" ]; firewall = { trustedInterfaces = [ lan "tailscale0" ]; filterForward = true; }; nftables.enable = true; nat = { enable = true; externalInterface = wan; internalInterfaces = [ lan ]; }; resolvconf.enable = false; }; systemd.network = { enable = true; config = { networkConfig = { IPv6Forwarding = true; }; }; links = { "10-${lan}" = { matchConfig.Path = "platform-a40c00000.pcie-pci-0003:31:00.0"; linkConfig.Name = lan; }; "10-${wan}" = { matchConfig.Path = "platform-fe1c0000.ethernet"; linkConfig.Name = wan; }; }; networks = { "50-${lan}" = { matchConfig.Name = lan; address = [ "10.0.0.1/16" "fd12:d04f:65d:42::1/56" ]; addresses = [ { Address = "fe80::1/64"; Scope = "link"; } ]; networkConfig = { IPv6AcceptRA = false; DHCPPrefixDelegation = true; ConfigureWithoutCarrier = true; LLMNR = true; MulticastDNS = true; Domains = [ config.networking.domain ]; IPv6SendRA = !dnsmasqEnable; DHCPServer = !dnsmasqEnable; }; dhcpPrefixDelegationConfig = { UplinkInterface = wan; SubnetId = "42"; Assign = true; Token = "::1"; }; dhcpServerConfig = { DefaultLeaseTimeSec = 86400; MaxLeaseTimeSec = 86400; DNS = "_server_address"; IPv6OnlyPreferredSec = 900; }; }; "50-${wan}" = { matchConfig.Name = wan; networkConfig = { DHCP = true; IPv6AcceptRA = true; IPv4Forwarding = true; LLMNR = false; MulticastDNS = false; }; dhcpV4Config = { UseDNS = false; SendHostname = false; UseHostname = false; Label = "${wan}:1"; }; dhcpV6Config = { UseDNS = false; SendHostname = false; RapidCommit = true; PrefixDelegationHint = "::/56"; }; dhcpPrefixDelegationConfig = { UplinkInterface = ":self"; }; ipv6AcceptRAConfig = { UseDNS = false; }; addresses = [{ Address = "192.168.100.10/24"; Peer = "192.168.100.1/32"; Label = "${wan}:0"; Scope = "link"; }]; cakeConfig = { Bandwidth = "24M"; OverheadBytes = 18; MPUBytes = 64; CompensationMode = "none"; NAT = true; PriorityQueueingPreset = "diffserv8"; }; }; }; }; services.resolved = { enable = true; llmnr = "false"; fallbackDns = config.networking.nameservers; }; services.dnsmasq = { enable = dnsmasqEnable; alwaysKeepRunning = true; resolveLocalQueries = true; settings = { inherit domain; interface = lan; bind-interfaces = true; dhcp-fqdn = true; dhcp-authoritative = true; dhcp-rapid-commit = true; dhcp-range = [ "10.0.1.10,10.0.250.250,48h" "fd12:d04f:65d:42::,slaac,ra-names,48h" "::,constructor:${lan},ra-stateless" ]; quiet-dhcp = true; quiet-dhcp6 = true; quiet-ra = true; enable-ra = true; dnssec = true; trust-anchor = ".,20326,8,2,E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"; server = config.networking.nameservers; expand-hosts = true; localise-queries = true; interface-name = [ "${hostName}.${domain},${lan}" "ca.${domain},${lan}" "wan.${domain},${wan}" ]; }; }; systemd.services.dnsmasq.after = [ "network.target" ]; # TODO find script # systemd.services.dynamic-dns-update = { # enable = true; # startAt = [ "hourly" ]; # description = "Update IP addresses"; # path = with pkgs; [ curl iproute2 dig.dnsutils miller ]; # after = [ "sys-subsystem-net-devices-${wan}.device" ]; # bindsTo = [ "sys-subsystem-net-devices-${wan}.device" ]; # serviceConfig = { # Type = "oneshot"; # ExecStart = "/bin/sh /etc/nixos/update-ip ${config.age.secrets.dyndns.path}"; # }; # }; # services.networkd-dispatcher = { # # broken? # enable = true; # rules = { # update-home-address = { # onState = [ "configured" "configuring" ]; # script = '' # #!${pkgs.runtimeShell} # set -eu # if [[ $IFACE == "${wan}" && $OperationalState == "routable" ]] # then # systemctl start dynamic-dns-update.service # fi # exit 0 # ''; # }; # tailscale-subnet-router-optimisation = { # onState = [ "routable" ]; # script = '' # #!${pkgs.runtimeShell} # set -eu # if [[ $IFACE == "${wan}" && $OperationalState == "routable" ]] # then # ${pkgs.ethtool}/bin/ethtool -K $IFACE rx-udp-gro-forwarding on rx-gro-list off # fi # ''; # }; # }; # }; services.tailscale = { enable = true; extraUpFlags = [ "--accept-dns=false" "--advertise-exit-node" "--advertise-routes=10.0.0.0/16,fd12:d04f:65d:42::/56" ]; }; time.timeZone = "Europe/Berlin"; i18n.defaultLocale = "en_GB.UTF-8"; programs.vim.defaultEditor = false; programs.neovim = { enable = true; defaultEditor = true; vimAlias = true; viAlias = true; }; environment.systemPackages = with pkgs; [ file tree lsof knot-dns ethtool tcpdump conntrack-tools ]; programs.fish.enable = true; users.defaultUserShell = pkgs.fish; users.mutableUsers = lib.mkForce true; users.users.alan = { isNormalUser = true; packages = with pkgs; [ ]; openssh.authorizedKeys.keys = [ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJVREjPey2TOIPzfYJoG9yIR4Rui7tNJK2QIKa+pbgsyXg31hhPIw37LRRIic+l53mW8eahHxX3Y1IeTjcMw8IU= alan@secretive.marvin.local" ]; }; users.users.root = { openssh.authorizedKeys.keys = [ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHYUyDdw92TNXguAxcmcmZmn/7ECGdRp6ckjxU+5zCw3BCnsS5+xEvHBVnnFdJRoH2XpfMeJjE+fi67zFVhlbn4= root@secretive.marvin.local" ]; }; services.sshguard = { enable = true; }; services.caddy = { enable = true; globalConfig = '' pki { ca home { name "Home CA" } } ''; virtualHosts = { "${hostName}.${domain}" = { serverAliases = [ "${hostName}.${tailnet}" ]; extraConfig = '' tls { issuer internal { ca home } } root /var/lib/caddy/ca file_server browse ''; }; "ca.${domain}" = { extraConfig = '' tls { issuer internal { ca home } } acme_server { allow { domains *.test *.${domain} } } ''; }; }; }; users.groups.linde.members = [ ]; users.users.linde = { group = "linde"; description = "Backup user for system 'linde'"; isSystemUser = true; shell = "/bin/sh"; home = "/srv/backup/linde"; homeMode = "755"; createHome = true; packages = with pkgs; [ rdiff-backup ]; openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJ74cPdIX9OlDkzHb6Y1E5sWqtIqMaf0z/SN3Tfy1Fjl root@linde" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINNXwIdGcP1vKyjmgeLw/sJntn7lajaZivepgdzaXvOt rdiff-backup" ]; }; systemd.services.backup-golink = { enable = true; startAt = "daily"; description = "Export short links from golink"; path = with pkgs; [ curl gitMinimal ]; script = '' [ -d golink ] || git init --quiet golink --initial-branch=main --shared=world git config --global user.email linde@alanpearce.eu cd golink curl https://go.${tailnet}/.export > links.json git add links.json git commit -m $(date +%F) ''; serviceConfig = { Type = "oneshot"; User = "linde"; WorkingDirectory = config.users.users.linde.home; }; }; nix = { distributedBuilds = true; buildMachines = [ { protocol = "ssh-ng"; sshUser = "nixremote"; hostName = "linde.alanpearce.eu"; system = "aarch64-linux"; # TODO make secret sshKey = "/root/.ssh/id_buche.alanpearce.eu_nixremote"; maxJobs = 2; speedFactor = 4; supportedFeatures = [ ]; } ]; settings = { max-jobs = 2; builders-use-substitutes = true; trusted-public-keys = [ "mba-1:CxokFjx7YAQWPWMJJKcP50ZpcPUCAFEOrtWdNUMTVjw=" ]; }; }; system.autoUpgrade = { dates = "04:15"; randomizedDelaySec = "59 min"; flake = "git+https://git.alanpearce.eu/nixfiles"; allowReboot = true; rebootWindow = { lower = "01:00"; upper = "06:00"; }; }; users.users.syncthing = { isSystemUser = true; group = "syncthing"; homeMode = "0755"; }; users.groups.syncthing.members = [ "alan" ]; services.syncthing = { enable = true; openDefaultPorts = true; dataDir = "/srv/syncthing"; user = "syncthing"; group = "syncthing"; key = config.age.secrets.syncthing.path; cert = toString (pkgs.writeText "syncthing.crt" '' -----BEGIN CERTIFICATE----- MIIBmjCCASCgAwIBAgIIUOEmXGFrrX0wCgYIKoZIzj0EAwIwFDESMBAGA1UEAxMJ c3luY3RoaW5nMB4XDTIyMDcxMzEwMzIxOVoXDTQ5MTIzMTIzNTk1OVowFDESMBAG A1UEAxMJc3luY3RoaW5nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEPiJT41NqucQf UXiBwt+yPYnMg9G8oTt9XNA72V99K46D7mIs1F/5oESlDiCSAngXPsajxRY7wyZV VoiWegfiaBOGZmq+TyaLlQ5bq/hm/Mp/jVED/rUA+BggohoZZMa2oz8wPTAOBgNV HQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud EwEB/wQCMAAwCgYIKoZIzj0EAwIDaAAwZQIwLp4Gv5EEmjRO9EphbYJ4jxEJks7E oblgnTmhfWmVWmf9avJyeGB212VYu4X8cCKDAjEAn7tTB9Y6LZvYPaLSwUKY3EzF hKTYCb7VA/P1dU3tTR1vSQxnu1DsiliD/XcKe2IK -----END CERTIFICATE----- ''); overrideFolders = false; overrideDevices = false; settings = { options = { maxRecvKbps = 10240; maxSendKbps = 1024; globalAnnounceEnabled = false; relaysEnabled = false; natEnabled = false; urAccepted = 4; trafficClass = 1; }; }; }; services.chrony = { enable = true; extraConfig = '' rtcdevice /dev/rtc0 rtcfile /var/lib/chrony/rtc rtcautotrim 30 allow 10.0.0.0/8 allow fd12:d04f:65d:42::0/56 ''; }; services.samba = { # TODO restore /srv enable = false; nmbd.enable = false; settings = { global = { "log level" = 1; "interfaces" = lan; "min protocol" = "SMB2"; "disable netbios" = true; "smb ports" = 445; "socket options" = "IPTOS_LOWDELAY TCP_NODELAY SO_KEEPALIVE SO_RCVBUF=65536 SO_SNDBUF=65536"; "max xmit" = 131072; "min receivefile size" = 131072; "aio read size" = 1; "aio write size" = 1; "load printers" = false; "disable spoolss" = true; "mdns name" = "mdns"; "follow symlinks" = true; "veto files" = "/Thumbs.db/.DS_Store/._.DS_Store/.apdisk/"; "delete veto files" = true; }; public = { path = "/srv/public"; browseable = "yes"; "guest ok" = "yes"; "create mask" = "0666"; "directory mask" = "0777"; "read only" = "no"; }; Homes = { "read only" = "no"; "valid users" = "%S"; "inherit acls" = "yes"; }; Videos = { path = "/srv/videos"; "valid users" = "alan"; "create mask" = "0664"; "directory mask" = "0775"; "writeable" = "yes"; }; }; }; services.samba-wsdd = { enable = true; interface = lan; }; system.stateVersion = "24.11"; }