Last active
July 25, 2023 04:30
-
-
Save fraichu/2d03340b0d9f13e64a1e7ef484671fdb to your computer and use it in GitHub Desktop.
Raspberry Pi NixOS Config
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| configuration.nix | |
| { config, pkgs, libs, lib, ... }: | |
| let secrets = import ./secrets.nix; | |
| in | |
| { | |
| imports = [ | |
| ./inadyn.nix | |
| ]; | |
| nixpkgs.overlays = [ | |
| (self: super: { | |
| linuxPackages_rpi4_custom = super.linuxPackagesFor (super.linux_rpi4.override { | |
| argsOverride = rec { | |
| src = super.fetchFromGitHub { | |
| owner = "raspberrypi"; | |
| repo = "linux"; | |
| rev = "dc6771425e9604650d1d57f7c69948be405f59a5"; | |
| sha256 = "162qqwrv11nj6fs9zq2411lkkf7yz1f8jzl8iianpzk74kkblm94"; | |
| }; | |
| version = "${modDirVersion}-${tag}"; | |
| tag = "1.20220308"; | |
| modDirVersion = "5.10.103"; | |
| }; | |
| }); | |
| }) | |
| ]; | |
| boot = { | |
| extraModulePackages = [ ]; | |
| initrd = { | |
| availableKernelModules = [ "xhci_pci" "usbhid" ]; | |
| kernelModules = [ ]; | |
| }; | |
| kernelPackages = pkgs.linuxPackages_rpi4_custom; | |
| loader = { | |
| generic-extlinux-compatible.enable = true; | |
| grub.enable = false; | |
| raspberryPi = { | |
| enable = true; | |
| version = 4; | |
| }; | |
| }; | |
| tmpOnTmpfs = false; | |
| }; | |
| environment.systemPackages = with pkgs; [ | |
| bind | |
| curl | |
| elinks | |
| file | |
| fzf | |
| gcc | |
| git | |
| hdparm | |
| htop | |
| inadyn | |
| libraspberrypi | |
| lsof | |
| nginx | |
| nmon | |
| parted | |
| php | |
| pstree | |
| python | |
| python3 | |
| ripgrep | |
| ncdu | |
| nixpkgs-fmt | |
| raspberrypi-eeprom | |
| shadowsocks-libev | |
| stress-ng | |
| tmux | |
| tree | |
| vim | |
| usbutils | |
| wireguard | |
| wget | |
| ]; | |
| environment.variables = { | |
| EDITOR = "vim"; | |
| }; | |
| fileSystems = { | |
| "/" = { | |
| device = "/dev/disk/by-label/NIXOS_SD"; | |
| fsType = "ext4"; | |
| options = [ "noatime" ]; | |
| }; | |
| "/n" = { | |
| device = "/dev/disk/by-uuid/9622cbd4-eca3-408e-8600-84f6bc3b3e02"; | |
| fsType = "ext4"; | |
| options = [ "noatime" ]; | |
| neededForBoot = true; | |
| }; | |
| "/var/log" = { | |
| device = "/n/root/var/log"; | |
| options = [ "bind" ]; | |
| depends = [ "/n" ]; | |
| neededForBoot = true; | |
| }; | |
| "/var/lib/jellyfin" = { | |
| device = "/n/root/var/lib/jellyfin"; | |
| options = [ "bind" ]; | |
| depends = [ "/n" ]; | |
| }; | |
| "/var/lib/docker" = { | |
| device = "/n/root/var/lib/docker"; | |
| options = [ "bind" ]; | |
| depends = [ "/n" ]; | |
| }; | |
| "/tmp" = { | |
| device = "/n/root/tmp"; | |
| options = [ "bind" ]; | |
| depends = [ "/n" ]; | |
| }; | |
| }; | |
| hardware.enableRedistributableFirmware = true; | |
| i18n.defaultLocale = "en_US.UTF-8"; | |
| console = { | |
| font = "Lat2-Terminus16"; | |
| keyMap = "us"; | |
| }; | |
| networking = { | |
| nameservers = [ "1.1.1.1" "1.0.0.1" "2606:4700:4700::1111" "2606:4700:4700::1001" ]; | |
| wireless = { | |
| enable = true; | |
| interfaces = [ "wlan0" ]; | |
| networks = { | |
| "${secrets.wifiSSID}" = { | |
| psk = "${secrets.wifiPassword}"; | |
| }; | |
| }; | |
| extraConfig = "country=${secrets.wifiCountry}"; | |
| }; | |
| firewall = { | |
| allowedTCPPorts = [ 22 80 443 ]; | |
| allowedUDPPorts = [ 51820 ]; | |
| trustedInterfaces = [ "wg0" "ve-${secrets.containerHostName}" ]; | |
| }; | |
| hostName = "${secrets.hostName}"; | |
| useDHCP = false; | |
| interfaces = { | |
| eth0.useDHCP = true; | |
| wlan0.useDHCP = true; | |
| }; | |
| # 2. WireGuard Setup | |
| nat = { | |
| enable = true; | |
| externalInterface = "eth0"; | |
| internalInterfaces = [ "wg0" "ve-${secrets.containerHostName}" ]; | |
| }; | |
| wg-quick.interfaces = { | |
| wg0 = { | |
| address = [ "192.168.100.1/24" "fdc9:281f:04d7:9ee9::1/64" ]; | |
| listenPort = 51820; | |
| privateKeyFile = "/root/wireguard-keys/server.key"; | |
| postUp = '' | |
| ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT | |
| ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 192.168.100.1/24 -o eth0 -j MASQUERADE | |
| ${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT | |
| ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE | |
| ''; | |
| preDown = '' | |
| ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT | |
| ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 192.168.100.1/24 -o eth0 -j MASQUERADE | |
| ${pkgs.iptables}/bin/ip6tables -D FORWARD -i wg0 -j ACCEPT | |
| ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE | |
| ''; | |
| peers = [ | |
| { | |
| # p1 | |
| publicKey = "${secrets.wg0Peer1PublicKey}"; | |
| allowedIPs = [ "192.168.100.2/32" "fdc9:281f:04d7:9ee9::2/128" ]; | |
| } | |
| # More peers can be added here. | |
| ]; | |
| }; | |
| }; | |
| }; | |
| nix = { | |
| autoOptimiseStore = true; | |
| gc = { | |
| automatic = true; | |
| dates = "weekly"; | |
| options = "--delete-older-than 30d"; | |
| }; | |
| # Free up to 1GiB whenever there is less than 100MiB left. | |
| extraOptions = '' | |
| min-free = ${toString (100 * 1024 * 1024)} | |
| max-free = ${toString (1024 * 1024 * 1024)} | |
| ''; | |
| #builders-use-substitutes = true # Move this inside extraOptions after max-free above | |
| #buildMachines = [ { | |
| # hostName = "[email protected]"; | |
| # systems = ["x86_64-linux" "aarch64-linux"]; | |
| # maxJobs = 15; | |
| # speedFactor = 9001; | |
| # supportedFeatures = [ ]; | |
| # mandatoryFeatures = [ ]; | |
| #} ]; | |
| #distributedBuilds = true; | |
| }; | |
| nixpkgs.config = { | |
| allowUnfree = true; | |
| }; | |
| powerManagement.cpuFreqGovernor = "ondemand"; | |
| security.acme = { | |
| certs = { | |
| "${secrets.internetHostName}" = { | |
| extraDomainNames = [ "track.${secrets.internetHostName}" "watch.${secrets.internetHostName}" "nextcloud.${secrets.internetHostName}" "manage.${secrets.internetHostName}" "get.${secrets.internetHostName}" ]; | |
| email = "acme@${secrets.internetHostName}"; | |
| }; | |
| }; | |
| acceptTerms = true; | |
| }; | |
| # Enable the OpenSSH daemon. | |
| services.openssh = { | |
| enable = true; | |
| permitRootLogin = "no"; | |
| passwordAuthentication = false; | |
| }; | |
| services.nginx = { | |
| enable = true; | |
| # Root domain | |
| virtualHosts."${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| enableACME = true; | |
| root = "/var/www/${secrets.internetHostName}"; | |
| }; | |
| # Catch-All | |
| virtualHosts."_" = { | |
| root = "/var/www/${secrets.internetHostName}"; | |
| }; | |
| # Services | |
| virtualHosts."nextcloud.${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| useACMEHost = "${secrets.internetHostName}"; | |
| }; | |
| virtualHosts."manage.${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| useACMEHost = "${secrets.internetHostName}"; | |
| locations."/" = { | |
| proxyPass = "http://127.0.0.1:8989"; | |
| proxyWebsockets = true; | |
| extraConfig = '' | |
| allow 192.168.100.0/24; | |
| allow fdc9:281f:04d7:9ee9::/64; | |
| deny all; | |
| ''; | |
| }; | |
| }; | |
| virtualHosts."get.${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| useACMEHost = "${secrets.internetHostName}"; | |
| locations."/" = { | |
| proxyPass = "http://192.168.101.2:9091"; | |
| proxyWebsockets = true; | |
| extraConfig = '' | |
| allow 192.168.100.0/24; | |
| allow fdc9:281f:04d7:9ee9::/64; | |
| deny all; | |
| proxy_buffering off; | |
| ''; | |
| }; | |
| }; | |
| virtualHosts."track.${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| useACMEHost = "${secrets.internetHostName}"; | |
| locations."/" = { | |
| proxyPass = "http://192.168.101.2:9117"; | |
| proxyWebsockets = true; | |
| extraConfig = '' | |
| allow 192.168.100.0/24; | |
| allow fdc9:281f:04d7:9ee9::/64; | |
| deny all; | |
| ''; | |
| }; | |
| }; | |
| virtualHosts."watch.${secrets.internetHostName}" = { | |
| forceSSL = true; | |
| useACMEHost = "${secrets.internetHostName}"; | |
| locations."/" = { | |
| proxyPass = "http://127.0.0.1:8096"; | |
| proxyWebsockets = true; | |
| }; | |
| }; | |
| #appendHttpConfig = "types_hash_max_size 4096;"; | |
| }; | |
| services.nextcloud = { | |
| enable = true; | |
| package = pkgs.nextcloud22; | |
| hostName = "nextcloud.${secrets.internetHostName}"; | |
| home = "/n/nextcloud"; | |
| config = { | |
| dbtype = "pgsql"; | |
| dbuser = "nextcloud"; | |
| dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself | |
| dbname = "nextcloud"; | |
| dbpassFile = "/var/nextcloud-db-pass"; | |
| adminuser = "root"; | |
| adminpassFile = "/var/nextcloud-admin-pass"; | |
| overwriteProtocol = "https"; | |
| defaultPhoneRegion = "IN"; | |
| }; | |
| }; | |
| services.postgresql = { | |
| enable = true; | |
| ensureDatabases = [ "nextcloud" ]; | |
| dataDir = "/n/postgresql/13"; | |
| ensureUsers = [ | |
| { | |
| name = "nextcloud"; | |
| ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; | |
| } | |
| ]; | |
| }; | |
| services.dnsmasq = { | |
| enable = true; | |
| extraConfig = '' | |
| interface=wg0 | |
| address=/${secrets.internetHostName}/192.168.100.1 | |
| local=/${secrets.internetHostName}/ | |
| domain=${secrets.internetHostName},192.168.100.0/24,local | |
| expand-hosts | |
| ''; | |
| }; | |
| services.sonarr = { | |
| enable = true; | |
| }; | |
| services.transmission = { | |
| enable = true; | |
| }; | |
| services.jellyfin = { | |
| enable = true; | |
| }; | |
| services.inadyn = { | |
| enable = true; | |
| inadynConf = '' | |
| period = 300 | |
| allow-ipv6 = true | |
| custom dynv6_http_api { | |
| username = ${secrets.dynv6_username} | |
| password = n/a | |
| hostname = dyn.${secrets.internetHostName} | |
| ddns-server = "dynv6.com" | |
| ddns-path = "/api/update?hostname=%h&ipv6=%i&token=%u" | |
| checkip-command = "ip -6 addr list scope global -deprecated -noprefixroute eth0 | grep inet6" | |
| } | |
| ''; | |
| }; | |
| services.fail2ban = { | |
| enable = true; | |
| maxretry = 5; | |
| ignoreIP = [ | |
| "127.0.0.0/8" | |
| "10.0.0.0/8" | |
| "172.16.0.0/12" | |
| "192.168.0.0/16" | |
| ]; | |
| }; | |
| services.journald.extraConfig = '' | |
| SystemMaxUse=4G | |
| ''; | |
| systemd = { | |
| services."nextcloud-setup" = { | |
| requires = [ "postgresql.service" ]; | |
| after = [ "postgresql.service" ]; | |
| }; | |
| services."container@${secrets.containerHostName}" = { | |
| requires = [ "network-online.target" ]; | |
| after = [ "network-online.target" ]; | |
| }; | |
| services."wg-quick-wg0" = { | |
| requires = [ "network-online.target" ]; | |
| after = [ "network-online.target" ]; | |
| }; | |
| services."transmission" = { | |
| wantedBy = lib.mkForce [ ]; | |
| }; | |
| }; | |
| system.stateVersion = "21.11"; | |
| time.timeZone = "${secrets.timeZone}"; | |
| users.users = { | |
| "${secrets.primary_username}" = { | |
| isNormalUser = true; | |
| home = "/home/${secrets.primary_username}"; | |
| extraGroups = [ "video" "wheel" "sonarr" "transmission" ]; | |
| openssh.authorizedKeys.keys = [ "${secrets.ssh_key}" ]; | |
| }; | |
| sonarr.extraGroups = [ "transmission" ]; | |
| }; | |
| containers."${secrets.containerHostName}" = { | |
| ephemeral = true; | |
| autoStart = true; | |
| privateNetwork = true; | |
| enableTun = true; | |
| hostAddress = "192.168.101.1"; | |
| localAddress = "192.168.101.2"; | |
| bindMounts = { | |
| "/host" = { | |
| hostPath = "/n/systemd_containers/${secrets.containerHostName}"; | |
| isReadOnly = false; | |
| }; | |
| "/n/torrents" = { | |
| hostPath = "/n/torrents"; | |
| isReadOnly = false; | |
| }; | |
| }; | |
| config = { config, pkgs, ... }: { | |
| networking.firewall = { | |
| extraCommands = '' | |
| iptables -A INPUT -s 192.168.101.0/24 -j ACCEPT | |
| iptables -A OUTPUT -d 192.168.101.0/24 -j ACCEPT | |
| iptables -A INPUT -s ${secrets.vpn_ip} -i eth0 -j ACCEPT | |
| iptables -A OUTPUT -d ${secrets.vpn_ip} -o eth0 -j ACCEPT | |
| iptables -A INPUT -i eth0 -j REJECT | |
| ip6tables -A INPUT -i eth0 -j REJECT | |
| iptables -A OUTPUT -o eth0 -j REJECT | |
| ip6tables -A OUTPUT -o eth0 -j REJECT | |
| ''; | |
| }; | |
| environment.etc = { | |
| "resolv.conf".text = "nameserver 1.1.1.1\n"; | |
| }; | |
| environment.systemPackages = with pkgs; [ | |
| curl | |
| elinks | |
| file | |
| htop | |
| nmon | |
| pstree | |
| ripgrep | |
| tmux | |
| tree | |
| vim | |
| wget | |
| ]; | |
| services = { | |
| openvpn.servers = { | |
| nordvpn = { | |
| config = '' config /host/${secrets.vpn_config_path} ''; | |
| authUserPass = { | |
| username = "${secrets.vpn_username}"; | |
| password = "${secrets.vpn_password}"; | |
| }; | |
| }; | |
| }; | |
| transmission = { | |
| enable = true; | |
| openPeerPorts = true; | |
| home = "/host/transmission"; | |
| settings = { | |
| download-dir = "/n/torrents"; | |
| incomplete-dir = "/n/torrents/.incomplete"; | |
| incomplete-dir-enabled = true; | |
| rpc-bind-address = "192.168.101.2"; | |
| rpc-whitelist = "192.168.101.1"; | |
| }; | |
| }; | |
| jackett = { | |
| enable = true; | |
| dataDir = "/host/jackett"; | |
| }; | |
| }; | |
| systemd = { | |
| services."transmission" = { | |
| requires = [ "network-online.target" "openvpn-nordvpn.service" "firewall.service" ]; | |
| after = [ "network-online.target" "openvpn-nordvpn.service" "firewall.service" ]; | |
| }; | |
| services."jackett" = { | |
| requires = [ "network-online.target" "openvpn-nordvpn.service" "firewall.service" ]; | |
| after = [ "network-online.target" "openvpn-nordvpn.service" "firewall.service" ]; | |
| }; | |
| }; | |
| }; | |
| }; | |
| } | |
| inadyn.nix | |
| { config, pkgs, lib, ... }: | |
| with lib; | |
| let | |
| cfg = config.services.inadyn; | |
| inadynConf = pkgs.writeText "inadyn.conf" '' | |
| ${cfg.inadynConf} | |
| ''; | |
| in | |
| { | |
| options = { | |
| services.inadyn = { | |
| enable = mkOption { | |
| default = false; | |
| type = types.bool; | |
| description = '' | |
| Internet Dynamic DNS Client | |
| ''; | |
| }; | |
| inadynConf = mkOption { | |
| default = ""; | |
| type = types.lines; | |
| description = '' | |
| Configuration lines in inadyn.conf | |
| ''; | |
| }; | |
| }; | |
| }; | |
| config = mkIf cfg.enable { | |
| systemd.services.inadyn = { | |
| wantedBy = [ "multi-user.target" ]; | |
| requires = [ "network-online.target" ]; | |
| after = [ "network-online.target" ]; | |
| path = [ | |
| pkgs.inadyn | |
| pkgs.iproute2 | |
| ]; | |
| description = "Internet Dynamic DNS Client"; | |
| documentation = [ "man:inadyn" "man:inadyn.conf" "https://github.com/troglobit/inadyn" ]; | |
| serviceConfig = { | |
| Type = "forking"; | |
| ExecStart = ''${pkgs.inadyn}/bin/inadyn --config ${inadynConf} --cache-dir /var/cache/inadyn --pidfile /var/run/inadyn.pid''; | |
| Restart = "always"; | |
| RestartSec = "10min"; | |
| }; | |
| }; | |
| environment.systemPackages = [ | |
| pkgs.inadyn | |
| pkgs.iproute2 | |
| ]; | |
| }; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment