diff --git a/flake.nix b/flake.nix index 2598f977..886a15ab 100644 --- a/flake.nix +++ b/flake.nix @@ -118,7 +118,8 @@ suites = with profiles; rec { base = [ core users.root users.anish ]; sealight = [ base server ]; # matrix rsshub backup wireguard - mossnet = [ base server ]; # shaarli wallabag nextcloud taskwarrior headphones + mossnet = [ base server ]; # taskd nextcloud networking wireguard shaarli mod-wallabag wallabag headphones dns backup monitoring dev gonic module-gonic cron nfs + cube = [ base site server ]; graphical = [ base bluetooth music sync wireguard wifi desktop ]; curve = [ graphical secrets ]; diff --git a/hosts/box/configuration.nix b/hosts/box/configuration.nix new file mode 100644 index 00000000..36064e25 --- /dev/null +++ b/hosts/box/configuration.nix @@ -0,0 +1,96 @@ +# Edit this configuration file to define what should be installed on +# your system. Help is available in the configuration.nix(5) man page +# and in the NixOS manual (accessible by running ‘nixos-help’). + +{ config, pkgs, ... }: + +{ + imports = + [ # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # Use the GRUB 2 boot loader. + boot.loader.efi.canTouchEfiVariables = false; + boot.loader.efi.efiSysMountPoint = "/boot/efi"; + boot.loader.grub = { + enable = true; + device = "nodev"; + version = 2; + efiSupport = true; + enableCryptodisk = true; + efiInstallAsRemovable = true; + }; + + boot.initrd.secrets = { + "/keyfile0.bin" = /etc/secrets/initrd/keyfile0.bin; + "/keyfile1.bin" = /etc/secrets/initrd/keyfile1.bin; + }; + + boot.initrd.luks.devices = { + "root" = { + #name = "root"; + device = "/dev/disk/by-uuid/f37f3222-47d7-42d8-b400-363320a31853"; # UUID for /dev/nvme01np2 + preLVM = true; + allowDiscards = true; + keyFile = "/keyfile0.bin"; + }; + }; + + # Data mount + fileSystems."/data" = { + device = "/dev/disk/by-uuid/3276a297-9ee4-4998-b262-1ed100366c06"; # UUID for /dev/mapper/crypted-data + encrypted = { + enable = true; + label = "crypted-data"; + blkDev = "/dev/disk/by-uuid/8a317bf4-fe13-4334-a6df-5fe5a5048b5e"; # UUID for /dev/sda1 + keyFile = "/keyfile1.bin"; + }; + }; + + networking.interfaces.enp2s0 = { + ipv4.addresses = [{ + address = "192.168.1.240"; + prefixLength = 24; + } ]; + ipv4.routes = [ { address = "192.168.1.0"; prefixLength = 24; via = "192.168.1.1"; }]; + useDHCP = false; + }; + #networking.nameservers = [ "172.16.11.240" ]; + networking.nameservers = [ "192.168.1.1" ]; + networking.defaultGateway = { + address = "192.168.1.1"; + interface = "enp2s0"; + }; + + networking.hostName = "box"; # Define your hostname. + networking.wireless.enable = true; # Enables wireless support via wpa_supplicant. + + # The global useDHCP flag is deprecated, therefore explicitly set to false here. + # Per-interface useDHCP will be mandatory in the future, so this generated config + # replicates the default behaviour. + networking.useDHCP = false; + networking.interfaces.wlp3s0.useDHCP = true; + networking.interfaces.enp2s0.useDHCP = false; + + # Set your time zone. + time.timeZone = "Australia/Brisbane"; + + # Enable the OpenSSH daemon. + services.openssh.enable = true; + services.openssh.permitRootLogin = "yes"; + networking.firewall.allowedTCPPorts = [ 22 ]; + sound.enable = false; + + programs.gnupg.agent.enable = true; + programs.gnupg.agent.pinentryFlavor = "curses"; + programs.gnupg.agent.enableSSHSupport = true; + + # This value determines the NixOS release with which your system is to be + # compatible, in order to avoid breaking some software such as database + # servers. You should change this only after NixOS release notes say you + # should. + system.stateVersion = "19.09"; # Did you read the comment? + +} + diff --git a/hosts/box/hardware-configuration.nix b/hosts/box/hardware-configuration.nix new file mode 100644 index 00000000..5a3f3976 --- /dev/null +++ b/hosts/box/hardware-configuration.nix @@ -0,0 +1,38 @@ +# 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 = [ "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { device = "/dev/disk/by-uuid/ade0752d-84d3-4e39-865b-9027ba2d5c67"; + fsType = "ext4"; + }; + + fileSystems."/boot/efi" = + { device = "/dev/disk/by-uuid/1715-278E"; + fsType = "vfat"; + }; + + fileSystems."/data" = + { device = "/dev/disk/by-uuid/3276a297-9ee4-4998-b262-1ed100366c06"; + fsType = "ext4"; + }; + + boot.initrd.luks.devices."crypted-data".device = "/dev/disk/by-uuid/8a317bf4-fe13-4334-a6df-5fe5a5048b5e"; + + swapDevices = + [ { device = "/dev/disk/by-uuid/b790abb4-ba5f-4476-8f09-b0fc575414aa"; } + ]; + + powerManagement.cpuFreqGovernor = lib.mkDefault "powersave"; +} diff --git a/modules/gonic.nix b/modules/gonic.nix new file mode 100644 index 00000000..f3a32fca --- /dev/null +++ b/modules/gonic.nix @@ -0,0 +1,109 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.gonic; + configFile = "/etc/gonic/config"; + dataFolder = "/var/lib/gonic"; +in { + options = { + + services.gonic = { + enable = mkEnableOption "Gonic music server and streamer"; + + settings = lib.mkOption { + type = types.str; + default = {}; + example = literalExample '' + music-path + podcast-path + cache-path + ''; + description = '' + Configuration for Gonic, see for supported values. + ''; + }; + + user = mkOption { + type = types.str; + default = "gonic"; + description = "User account under which gonic runs."; + }; + + group = mkOption { + type = types.str; + default = "gonic"; + description = "Group account under which gonic runs."; + }; + + }; + }; + + config = mkIf cfg.enable { + + environment.etc."gonic/config".text = cfg.settings; + + systemd.services.gonic = { + description = "gonic Music Server and Streamer compatible with Subsonic/Airsonic"; + after = [ "remote-fs.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + #GONIC_MUSIC_PATH + #GONIC_PODCAST_PATH + #GONIC_CACHE_PATH + #GONIC_DB_PATH + GONIC_SCAN_INTERVAL="800"; + #... + }; + serviceConfig = { + ExecStart = "${pkgs.gonic}/bin/gonic -config-path /etc/gonic/config"; + WorkingDirectory = dataFolder; + TimeoutStopSec = "20"; + KillMode = "process"; + Restart = "on-failure"; + RestartSec = "10"; + User = cfg.user; + Group = cfg.group; + DevicePolicy = "closed"; + NoNewPrivileges= " yes"; + PrivateTmp = "yes"; + PrivateUsers = "yes"; + ProtectControlGroups = "yes"; + ProtectKernelModules = "yes"; + ProtectKernelTunables = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; + RestrictNamespaces = "yes"; + RestrictRealtime = "yes"; + SystemCallFilter = "~@clock @debug @module @mount @obsolete @privileged @reboot @setuid @swap"; + ReadWritePaths = dataFolder; + StateDirectory = baseNameOf dataFolder; + }; + }; + + users.users = optionalAttrs (cfg.user == "gonic") ({ + gonic = { + description = "gonic service user"; + name = cfg.user; + group = cfg.group; + isSystemUser = true; + }; + }); + + users.groups = optionalAttrs (cfg.group == "gonic") ({ + gonic = {}; + }); + + services.nginx.virtualHosts."music.mossnet.lan" = { + enableACME = false; + forceSSL = false; + + locations."/" = { + extraConfig = '' + proxy_pass http://localhost:4747/; + proxy_set_header X-Forwarded-Host $host; + ''; + }; + }; + }; +} diff --git a/modules/grasp.nix b/modules/grasp.nix new file mode 100644 index 00000000..4318650a --- /dev/null +++ b/modules/grasp.nix @@ -0,0 +1,12 @@ +{ config, lib, pkgs, ...}: + +{ + systemd.services.grasp = { + description = "grasp server"; + wantedBy = [ "default.target" ]; + + serviceConfig = { + ExecStart = "{$pkgs.grasp}/server/grasp_server.py --path /data/grasp/capture.org"; + }; + }; +} diff --git a/modules/wallabag.nix b/modules/wallabag.nix new file mode 100644 index 00000000..dda36c14 --- /dev/null +++ b/modules/wallabag.nix @@ -0,0 +1,220 @@ +{ config, options, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.wallabag; + + poolName = "wallabag"; + + configFile = pkgs.writeTextFile { + name = "wallabag-config"; + text = cfg.conf; + destination = "/config/parameters.yml"; + }; + + appDir = pkgs.buildEnv { + name = "wallabag-app-dir"; + ignoreCollisions = true; + checkCollisionContents = false; + paths = [ configFile "${cfg.package}/app" ]; + }; + +in { + + options = { + + services.wallabag = { + enable = mkEnableOption "wallabag"; + + user = mkOption { + type = types.str; + default = "nginx"; + description = '' + User account under which both the update daemon and the web-application run. + ''; + }; + + dataDir = mkOption { + type = types.path; + default = "/var/lib/wallabag"; + description = '' + Data directory. + ''; + }; + + package = mkOption { + type = types.package; + default = pkgs.wallabag; + description = '' + Wallabag package to use. + ''; + }; + + hostName = mkOption { + type = types.str; + description = '' + Name of the nginx virtualhost to use and setup. + ''; + }; + + poolConfig = mkOption { + type = types.lines; + default = '' + pm = dynamic + pm.max_children = 75 + pm.start_servers = 1 + pm.min_spare_servers = 1 + pm.max_spare_servers = 20 + pm.max_requests = 500 + catch_workers_output = 1 + ''; + description = '' + Options for wallabag's PHP pool. See the documentation on php-fpm.conf for details on configuration directives. + ''; + }; + + conf = mkOption { + type = types.str; + description = '' + Contents of the wallabag configuration file (parameters.yml) + ''; + }; + }; + }; + + + config = mkIf cfg.enable { + + services.phpfpm.pools."${poolName}" = { + user = "${cfg.user}"; + group = "nginx"; + settings = { + "listen.owner" = "nginx"; + "listen.group" = "nginx"; + "listen.mode" = "0600"; + "user" = "${cfg.user}"; + "group" = "nginx"; + "env[WALLABAG_DATA]" = "${cfg.dataDir}"; + "pm" = "dynamic"; + "pm.max_children" = "75"; + "pm.min_spare_servers" = "5"; + "pm.max_spare_servers" = "20"; + "pm.max_requests" = "10"; + "catch_workers_output" = "1"; + "php_admin_value[error_log]" = "/var/log/nginx/${poolName}-phpfpm-error.log"; + }; + }; + services.phpfpm.phpOptions = '' + max_execution_time = 120 + ''; + + services.nginx.enable = mkDefault true; + + services.nginx.virtualHosts."${cfg.hostName}" = { + enableACME = false; + forceSSL = false; + root = "${cfg.package}/web"; + + extraConfig = '' + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + ''; + + locations."/" = { + extraConfig = '' + try_files $uri /app.php$is_args$args; + ''; + }; + + locations."/assets".root = "${cfg.dataDir}/web"; + + locations."~ ^/app\\.php(/|$)" = { + extraConfig = '' + fastcgi_pass unix:${config.services.phpfpm.pools."${poolName}".socket}; + fastcgi_split_path_info ^(.+\.php)(/.*)$; + + fastcgi_param SCRIPT_FILENAME ${cfg.package}/web/$fastcgi_script_name; + fastcgi_param DOCUMENT_ROOT ${cfg.package}/web; + fastcgi_read_timeout 120; + + fastcgi_param QUERY_STRING $query_string; + fastcgi_param REQUEST_METHOD $request_method; + fastcgi_param CONTENT_TYPE $content_type; + fastcgi_param CONTENT_LENGTH $content_length; + + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param SCRIPT_NAME $fastcgi_script_name; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info; + fastcgi_param REQUEST_URI $request_uri; + fastcgi_param DOCUMENT_URI $document_uri; + fastcgi_param SERVER_PROTOCOL $server_protocol; + + fastcgi_param GATEWAY_INTERFACE CGI/1.1; + fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; + + fastcgi_param REMOTE_ADDR $remote_addr; + fastcgi_param REMOTE_PORT $remote_port; + fastcgi_param SERVER_ADDR $server_addr; + fastcgi_param SERVER_PORT $server_port; + fastcgi_param SERVER_NAME $server_name; + + internal; + ''; + }; + + locations."~ /(?!app)\\.php$" = { + extraConfig = '' + return 404; + ''; + }; + }; + + systemd.services.wallabag-install = { + description = "Wallabag install service"; + wantedBy = [ "multi-user.target" ]; + before = [ "phpfpm-wallabag.service" ]; + after = [ "mysql.service" "postgresql.service" ]; + path = with pkgs; [ coreutils php phpPackages.composer ]; + + serviceConfig = { + User = cfg.user; + Type = "oneshot"; + RemainAfterExit = "yes"; + PermissionsStartOnly = true; + }; + + preStart = '' + mkdir -p "${cfg.dataDir}" + chown ${cfg.user}:nginx "${cfg.dataDir}" + ''; + + script = '' + echo "Setting up wallabag files in ${cfg.dataDir} ..." + cd "${cfg.dataDir}" + + rm -rf var/cache/* + rm -f app + ln -sf ${appDir} app + ln -sf ${cfg.package}/composer.{json,lock} . + + export WALLABAG_DATA="${cfg.dataDir}" + if [ ! -f installed ]; then + php ${cfg.package}/bin/console --env=prod doctrine:database:create --if-not-exists --no-interaction + php ${cfg.package}/bin/console --env=prod doctrine:migrations:migrate --no-interaction + # Until https://github.com/wallabag/wallabag/issues/3662 is fixed + # yes no | php ${cfg.package}/bin/console --env=prod wallabag:install + touch installed + else + php ${cfg.package}/bin/console --env=prod doctrine:migrations:migrate --no-interaction + fi + php ${cfg.package}/bin/console --env=prod cache:clear + ''; + }; + }; + + meta = with stdenv.lib; { + maintainers = with maintainers; [ nadrieril ]; + }; +} diff --git a/pkgs/grasp.nix b/pkgs/grasp.nix new file mode 100644 index 00000000..4beffb36 --- /dev/null +++ b/pkgs/grasp.nix @@ -0,0 +1,22 @@ +{ python3, fetchFromGitHub, lib }: + +python3.pkgs.buildPythonApplication rec { + pname = "grasp"; + version = "0.6.6"; + + src = fetchFromGitHub { + owner = "karlicoss"; + repo = pname; + rev = "grasp-${version}"; + sha256 = "0000000000000000000000000000000000000000000000000000"; + }; + + meta = with lib; { + description = "grasp server"; + # License is complicated... + #license = licenses.agpl3; + homepage = "https://github.com/karlicoss/grasp"; + platforms = platforms.all; + maintainers = with stdenv.lib.maintainers; [ chickensoupwithrice ]; + }; +} diff --git a/pkgs/navidrome.nix b/pkgs/navidrome.nix new file mode 100644 index 00000000..5bcd3789 --- /dev/null +++ b/pkgs/navidrome.nix @@ -0,0 +1,9 @@ +{ config, lib, pkgs, ... }: +{ + services.navidrome.enable = true; + services.navidrome.settings = { + MusicFolder = "/data/music"; + Port = 4433; + }; + networking.firewall.allowedTCPPorts = [ 4433 ]; +} diff --git a/pkgs/wallabag.nix b/pkgs/wallabag.nix new file mode 100644 index 00000000..243569b4 --- /dev/null +++ b/pkgs/wallabag.nix @@ -0,0 +1,31 @@ +diff --git a/app/AppKernel.php b/app/AppKernel.php +index 347197e..902b558 100644 +--- a/app/AppKernel.php ++++ b/app/AppKernel.php +@@ -69,19 +69,24 @@ class AppKernel extends Kernel + return __DIR__; + } + ++ public function getProjectDir() ++ { ++ return getenv('WALLABAG_DATA') ?: dirname(__DIR__); ++ } ++ + public function getCacheDir() + { +- return dirname(__DIR__) . '/var/cache/' . $this->getEnvironment(); ++ return $this->getProjectDir() . '/var/cache/' . $this->getEnvironment(); + } + + public function getLogDir() + { +- return dirname(__DIR__) . '/var/logs'; ++ return $this->getProjectDir() . '/var/logs'; + } + + public function registerContainerConfiguration(LoaderInterface $loader) + { +- $loader->load($this->getRootDir() . '/config/config_' . $this->getEnvironment() . '.yml'); ++ $loader->load($this->getProjectDir() . '/app/config/config_' . $this->getEnvironment() . '.yml'); + + $loader->load(function ($container) { diff --git a/profiles/backup/backup.nix b/profiles/backup/backup.nix new file mode 100644 index 00000000..8fa6f01c --- /dev/null +++ b/profiles/backup/backup.nix @@ -0,0 +1,34 @@ +{ + # Assumes the remote borg backup server has already been initialized + # borg init --encryption-key=repokey-blake2 -rsh 'ssh -i /run/keys/id_ed25519_borgbase' 20779@hk-s020.rsync.net: + services.borgbackup.jobs = { + backupTaskwarriorRsync = { + paths = [ "/var/lib/taskserver" ]; + doInit = true; + repo = "20779@hk-s020.rsync.net:taskwarrior" ; + encryption = { + mode = "repokey-blake2"; + passCommand = "cat /run/keys/rsync"; + }; + environment = { BORG_RSH = "ssh -i /run/keys/id_ed25519_borgbase"; }; + compression = "auto,lzma"; + startAt = "weekly"; + extraArgs = "--remote-path=borg1"; + }; + }; + services.borgbackup.jobs = { + backupShaarliRsync = { + paths = [ "/var/www/shaarli-config/data/datastore.php" "/var/www/shaarli-config/config" "/var/www/shaarli-config/.json.config" ]; + doInit = true; + repo = "20779@hk-s020.rsync.net:shaarli" ; + encryption = { + mode = "repokey-blake2"; + passCommand = "cat /run/keys/rsync"; + }; + environment = { BORG_RSH = "ssh -i /run/keys/id_ed25519_borgbase"; }; + compression = "auto,lzma"; + startAt = "weekly"; + extraArgs = "--remote-path=borg1"; + }; + }; +} diff --git a/profiles/box-zone/box.nix b/profiles/box-zone/box.nix new file mode 100644 index 00000000..553460ae --- /dev/null +++ b/profiles/box-zone/box.nix @@ -0,0 +1,28 @@ +{ config, pkgs, ... }: + +{ + imports = [ + ./common.nix + ./mossnet.nix + ]; + + users.extraUsers."anish".extraGroups = [ "jackaudio" ]; + +# services.xserver = { +# enable = true; +# displayManager.gdm.enable = true; +# desktopManager.gnome3.enable = true; +# }; + + # task whisperer broken + #nixpkgs.config.allowBroken = true; + + # virtual box + virtualisation.virtualbox.host.enable = true; + + # ErgoDox Firmware (doesn't compile) + # environment.systemPackages = with pkgs; [ + # qmk_firmware + # ]; +} + diff --git a/profiles/box-zone/common.nix b/profiles/box-zone/common.nix new file mode 100644 index 00000000..0790f579 --- /dev/null +++ b/profiles/box-zone/common.nix @@ -0,0 +1,120 @@ +{ config, pkgs, ... }: + +{ + imports = [ + ./nvim.nix +# ./unstable.nix + ]; + + + environment.systemPackages = with pkgs; [ + tailscale + htop + fzf + iftop + wget + curl + exa + bat + fd + ag + wpa_supplicant + tcpdump + whois + mtr + file + lsof + atool + inotify-tools + strace + zip + unzip + rsync + tmux + pwgen + glow + jq + gitAndTools.gitFull + #neovim defined in ./nvim.nix + # wofi + # firefox + # fractal + # pinentry_gnome + pinentry_curses + pass + gcc + less + # mpv + # zathura + #qmk_firmware + python3 + gdb + # vcv-rack + #xdotool + #neofetch + #calibre + #openvpn + #gimp + xxd + # tilix + # kitty + taskwarrior + gnupg + openjdk + glslviewer + #filezilla + # signal-desktop + # wire-desktop + # tdesktop + # feedreader + #newsflash +# syncthing + dijo + #ssb-patchwork + #gnomeExtensions.taskwhisperer + #gnome3.networkmanager-openvpn + #python3Packages.youtube-dl + #appimage-run + home-manager + libreoffice + fontconfig + #hugo + #processing + #nextcloud-client + zsh-powerlevel10k + powerline-fonts + supercollider + haskellPackages.tidal + pandoc + # calibre + ]; + + programs.bash.enableCompletion = true; + + programs.gnupg.agent.enable = true; + programs.gnupg.agent.pinentryFlavor = "curses"; + programs.gnupg.agent.enableSSHSupport = true; + # needed for vcv-rack + nixpkgs.config.allowUnfree = true; + + system.copySystemConfiguration = true; + #services.syncthing = { + # enable = true; + # openDefaultPorts = true; + # systemService = true; + # user = "anish"; + # dataDir = "/home/anish/usr/syncthing"; + #}; + + #zsh powerlevel10k + #programs.zsh.enable = true; + #programs.zsh.promptInit = "source ${pkgs.zsh-powerlevel10k}/share/zsh-powerlevel10k/powerlevel10k.zsh-theme"; + users.users.anish.shell = pkgs.bash; + + #android + programs.adb.enable = true; + users.users.anish.extraGroups = ["adbusers"]; + + #ssh + services.sshd.enable = true; +} diff --git a/profiles/box-zone/mossnet.nix b/profiles/box-zone/mossnet.nix new file mode 100644 index 00000000..3cb80308 --- /dev/null +++ b/profiles/box-zone/mossnet.nix @@ -0,0 +1,28 @@ +{config, pkgs, ...}: + +{ + imports = [ + ./taskd.nix + ./nextcloud.nix + ./networking.nix + ./wireguard.nix + ./shaarli.nix +## ./navidrome.nix +## ./pkg-navidrome.nix + ./mod-wallabag.nix + ./wallabag.nix + ./headphones.nix + ./dns.nix + ./backup.nix + ./monitoring.nix + ./dev.nix + ./gonic.nix + ./module-gonic.nix +# ./rss-bridge.nix +# ./pkg-grasp.nix +# ./mod-grasp.nix + ./cron.nix + ./ftp.nix + ./nfs.nix + ]; +} diff --git a/profiles/dns/dns.nix b/profiles/dns/dns.nix new file mode 100644 index 00000000..96800e0a --- /dev/null +++ b/profiles/dns/dns.nix @@ -0,0 +1,16 @@ +{ config, pkgs, lib, ... }: +{ + services.dnsmasq.enable = true; + services.dnsmasq.extraConfig = '' + domain-needed + no-resolv + local=/lan/ + local=/moss/ + cache-size=5000 + addn-hosts=/ec/adblock.hosts + ''; + services.dnsmasq.servers = [ "45.90.30.49" "45.90.28.49" "1.1.1.1" "8.8.8.8" ]; + networking.hosts = {"192.168.1.240" = ["mossnet.lan" "links.mossnet.lan" "read.mossnet.lan" "stats.mossnet.lan" "music.moss" "tasks.moss" "headphones.moss" "cloud.moss" "links.moss" "read.moss" "stats.moss" "rss.moss"];}; + networking.firewall.allowedTCPPorts = [ 53 ]; + networking.firewall.allowedUDPPorts = [ 53 ]; +} diff --git a/profiles/ftp/default.nix b/profiles/ftp/default.nix new file mode 100644 index 00000000..4b0da48a --- /dev/null +++ b/profiles/ftp/default.nix @@ -0,0 +1,20 @@ +{ pkgs, lib, ... }: + +{ + networking.firewall.allowedTCPPorts = [ 20 21 ]; + networking.firewall.allowedTCPPortRanges = [ { from = 51000; to = 51999; } ]; + services.vsftpd = { + enable = true; + writeEnable = true; + anonymousUser = true; + anonymousUserNoPassword = true; + anonymousUploadEnable = true; + anonymousMkdirEnable = true; + anonymousUserHome = "/home/ftp"; + extraConfig = '' + pasv_enable=Yes + pasv_min_port=51000 + pasv_max_port=51999 + ''; + }; +} diff --git a/profiles/gonic/default.nix b/profiles/gonic/default.nix index 5238eb42..11bed1f2 100644 --- a/profiles/gonic/default.nix +++ b/profiles/gonic/default.nix @@ -5,7 +5,7 @@ music-path /data/music podcast-path /data/music cache-path /data/cache - ''; + ''; services.gonic.group = "audio"; services.gonic.user = "headphones"; networking.firewall.allowedTCPPorts = [ 4747 ]; diff --git a/profiles/headphones/default.nix b/profiles/headphones/default.nix index d33f5912..a4211f76 100644 --- a/profiles/headphones/default.nix +++ b/profiles/headphones/default.nix @@ -1,4 +1,4 @@ -{ config, lib, pkgs, ... }: +{config, lib, pkgs, ... }: { services.headphones = { enable = true; diff --git a/profiles/monitoring/default.nix b/profiles/monitoring/default.nix index 4c35a48e..793ac393 100644 --- a/profiles/monitoring/default.nix +++ b/profiles/monitoring/default.nix @@ -6,12 +6,12 @@ port = 2342; addr = "127.0.0.1"; }; - + # nginx reverse proxy services.nginx.virtualHosts.${config.services.grafana.domain} = { locations."/" = { - proxyPass = "http://127.0.0.1:${toString config.services.grafana.port}"; - proxyWebsockets = true; + proxyPass = "http://127.0.0.1:${toString config.services.grafana.port}"; + proxyWebsockets = true; }; }; @@ -42,18 +42,18 @@ }; services.loki = { - enable = true; - configFile = /var/loki-config.yaml; + #enable = true; + #configFile = /var/loki-config.yaml; }; - systemd.services.promtail = { - description = "Promtail service for Loki"; - wantedBy = [ "multi-user.target" ]; + #systemd.services.promtail = { + # description = "Promtail service for Loki"; + # wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = '' - ${pkgs.grafana-loki}/bin/promtail --config.file ${/var/promtail.yaml} - ''; - }; - }; + # serviceConfig = { + # ExecStart = '' + # ${pkgs.grafana-loki}/bin/promtail --config.file ${/var/promtail.yaml} + # ''; + # }; + #}; } diff --git a/profiles/navidrome/default.nix b/profiles/navidrome/default.nix new file mode 100644 index 00000000..be4fe9c5 --- /dev/null +++ b/profiles/navidrome/default.nix @@ -0,0 +1,101 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.navidrome; + configFile = "/etc/navidrome/settings.json"; + dataFolder = "/var/lib/navidrome"; +in { + options = { + + services.navidrome = { + enable = mkEnableOption "Navidrome music server and streamer"; + + settings = lib.mkOption { + type = with types; attrsOf (oneOf [ int str ]); + default = {}; + example = literalExample '' + { + LogLevel = "INFO"; + BaseURL = "/music"; + ScanInterval = "10s"; + TranscodingCacheSize = "15MB"; + MusicFolder = "/data/music"; + }; + ''; + description = '' + Configuration for Navidrome, see for supported values. + ''; + }; + + user = mkOption { + type = types.str; + default = "navidrome"; + description = "User account under which Navidrome runs."; + }; + + group = mkOption { + type = types.str; + default = "navidrome"; + description = "Group account under which Navidrome runs."; + }; + + }; + }; + + config = mkIf cfg.enable { + + environment.etc."navidrome/settings.json".text = builtins.toJSON cfg.settings; + + services.navidrome.settings = { + DataFolder = dataFolder; + ConfigFile = configFile; + }; + + systemd.services.navidrome = { + description = "Navidrome Music Server and Streamer compatible with Subsonic/Airsonic"; + after = [ "remote-fs.target" "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + ND_CONFIGFILE = configFile; + }; + serviceConfig = { + ExecStart = "${pkgs.navidrome}/bin/navidrome"; + WorkingDirectory = dataFolder; + TimeoutStopSec = "20"; + KillMode = "process"; + Restart = "on-failure"; + User = cfg.user; + Group = cfg.group; + DevicePolicy = "closed"; + NoNewPrivileges= " yes"; + PrivateTmp = "yes"; + PrivateUsers = "yes"; + ProtectControlGroups = "yes"; + ProtectKernelModules = "yes"; + ProtectKernelTunables = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6"; + RestrictNamespaces = "yes"; + RestrictRealtime = "yes"; + SystemCallFilter = "~@clock @debug @module @mount @obsolete @privileged @reboot @setuid @swap"; + ReadWritePaths = dataFolder; + StateDirectory = baseNameOf dataFolder; + }; + }; + + users.users = optionalAttrs (cfg.user == "navidrome") ({ + navidrome = { + description = "Navidrome service user"; + name = cfg.user; + group = cfg.group; + isSystemUser = true; + }; + }); + + users.groups = optionalAttrs (cfg.group == "navidrome") ({ + navidrome = {}; + }); + + }; +} diff --git a/profiles/nextcloud/default.nix b/profiles/nextcloud/default.nix index 529d9760..f378579f 100644 --- a/profiles/nextcloud/default.nix +++ b/profiles/nextcloud/default.nix @@ -1,7 +1,5 @@ { pkgs, config, ... }: { - age.secrets.nextcloud-db.file = "/etc/nixos/secrets/nextcloud-db.age"; - age.secrets.nextcloud-admin.file = "/etc/nixos/secrets/nextcloud-admin.age"; services.nextcloud = { enable = true; hostName = "mossnet.lan"; @@ -10,7 +8,7 @@ # Use HTTPS for links https = false; - + # Auto-update Nextcloud Apps autoUpdateApps.enable = true; # Set what time makes sense for you @@ -25,8 +23,9 @@ dbuser = "nextcloud"; dbhost = "/run/postgresql"; # nextcloud will add /.s.PGSQL.5432 by itself dbname = "nextcloud"; - dbpassFile = "/run/secrets/nextcloud-db"; - adminpassFile = "/run/secrets/nextcloud-admin"; + dbpassFile = "/var/nextcloud-db-pass"; + + adminpassFile = "/var/nextcloud-admin-pass"; adminuser = "admin"; }; }; @@ -38,17 +37,16 @@ # Ensure the database, user, and permissions always exist ensureDatabases = [ "nextcloud" ]; ensureUsers = [ - { - name = "nextcloud"; - ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; - } + { name = "nextcloud"; + ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; + } ]; }; # Ensure that postgres is running before running the setup systemd.services."nextcloud-setup" = { - requires = [ "postgresql.service" ]; - after = [ "postgresql.service" ]; + requires = ["postgresql.service"]; + after = ["postgresql.service"]; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; diff --git a/profiles/nfs/default.nix b/profiles/nfs/default.nix new file mode 100644 index 00000000..ba9e9970 --- /dev/null +++ b/profiles/nfs/default.nix @@ -0,0 +1,32 @@ +{ + #fileSystems."/export/" = { + # device = "/mnt/mafuyu"; + # options = [ "bind" ]; + #}; + + services.nfs.server = { + enable = true; + # fixed rpc.statd port; for firewall + lockdPort = 4001; + mountdPort = 4002; + statdPort = 4000; + extraNfsdConfig = ''''; + exports = '' + /home/ftp 192.168.1.0/24(rw) + ''; + }; + + networking.firewall = { + allowedTCPPorts = [ 111 2049 4000 4001 4002 20048 ]; + allowedUDPPorts = [ 111 2049 4000 4001 4002 20048 ]; + }; + + #systemd.services.create-mount-dir = { + # serviceConfig = { + # ExecStart = "mkdir /export"; + # }; + # wantedBy = [ "multi-user.target" ]; + # after = [ "remote-fs.target" ]; + # description = "Create a directory we can mount on fs"; + #}; +} diff --git a/profiles/rss-bridge/default.nix b/profiles/rss-bridge/default.nix new file mode 100644 index 00000000..796dfd02 --- /dev/null +++ b/profiles/rss-bridge/default.nix @@ -0,0 +1,8 @@ +{pkgs, lib, config, ...}: +{ + services.rss-bridge = { + enable = true; + virtualHost = "rss.moss"; + whitelist = [ "Facebook" "Bandcamp" "Twitter" "Telegram"]; + }; +} diff --git a/profiles/shaarli/default.nix b/profiles/shaarli/default.nix index ae6d128c..56a9055a 100644 --- a/profiles/shaarli/default.nix +++ b/profiles/shaarli/default.nix @@ -1,5 +1,5 @@ { pkgs, config, ... }: -let +let dataDir = "/var/www/shaarli-config"; name = "shaarli"; in @@ -12,14 +12,14 @@ in enableACME = false; root = "${dataDir}"; extraConfig = '' - index index.php; - ''; + index index.php; + ''; locations = { - "/".extraConfig = '' - try_files $uri $uri/ index.php$is_args$args; - ''; + "/".extraConfig = '' + try_files $uri $uri/ index.php$is_args$args; + ''; - "~ (index)\\.php$".extraConfig = '' + "~ (index)\\.php$".extraConfig = '' try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; @@ -74,24 +74,24 @@ in user = "nginx"; group = "nginx"; #listen = "/run/phpfpm/php.sock"; - settings = { - "listen.owner" = "nginx"; - "listen.group" = "nginx"; - "user" = "nginx"; - "pm" = "dynamic"; - "pm.max_children" = "4"; - "pm.min_spare_servers" = "1"; - "pm.max_spare_servers" = "4"; - "pm.max_requests" = "32"; - "catch_workers_output" = "1"; - "php_admin_value[error_log]" = "/var/log/nginx/${name}-phpfpm-error.log"; - }; + settings = { + "listen.owner" = "nginx"; + "listen.group" = "nginx"; + "user" = "nginx"; + "pm" = "dynamic"; + "pm.max_children" = "4"; + "pm.min_spare_servers" = "1"; + "pm.max_spare_servers" = "4"; + "pm.max_requests" = "32"; + "catch_workers_output" = "1"; + "php_admin_value[error_log]" = "/var/log/nginx/${name}-phpfpm-error.log"; + }; }; }; }; users.extraUsers."${name}" = { group = "${name}"; }; users.extraGroups."${name}" = { }; - users.users.shaarli.isSystemUser = true; + users.users.shaarli.isSystemUser = true; systemd.services.shaarli-install = { serviceConfig.Type = "oneshot"; wantedBy = [ "multi-user.target" ]; @@ -102,7 +102,7 @@ in #cp -R ${pkgs.shaarli}/data.orig/.htaccess ${dataDir}/pagecache/ #cp -R ${pkgs.shaarli}/data.orig/.htaccess ${dataDir}/tmp/ mkdir -p ${dataDir}/{cache,data,pagecache,tmp} - ln -s ${pkgs.shaarli}/* ${dataDir} + ln -s ${pkgs.shaarli}/* ${dataDir} fi chown -Rc nginx:nginx ${dataDir} find ${dataDir} -type d ! -perm 0700 -exec chmod 0700 {} \; -exec chmod g-s {} \; diff --git a/profiles/sync/get-music.nix b/profiles/sync/get-music.nix new file mode 100644 index 00000000..acb3d9d3 --- /dev/null +++ b/profiles/sync/get-music.nix @@ -0,0 +1,10 @@ +{ pkgs, lib, ... }: + +{ + services.cron = { + enable = true; + systemCronJobs = [ + "* */24 * * * * anish ~/get-music.sh" + ]; + }; +} diff --git a/profiles/sync/get-music.sh b/profiles/sync/get-music.sh new file mode 100755 index 00000000..2269bb89 --- /dev/null +++ b/profiles/sync/get-music.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +rsync -r --ignore-existing --log-file=/data/incoming/download-log hypercube@talos.feralhosting.com:private/transmission/data/* /data/incoming + +# you need to set defaults for beets +# if already imported -> Skip +# Auto accept changes +# also install it lmao +#beet import /data/incoming + diff --git a/profiles/taskd/default.nix b/profiles/taskd/default.nix index c960c1a8..55e179aa 100644 --- a/profiles/taskd/default.nix +++ b/profiles/taskd/default.nix @@ -1,9 +1,61 @@ -{ config, pkgs, ... }: +{ config, pkgs, lib, ... }: { - services.taskserver.enable = true; - services.taskserver.fqdn = "task.moss"; - services.taskserver.listenHost = "172.16.11.240"; - services.taskserver.listenPort = 53589; - services.taskserver.organisations.mossnet.users = [ "anish" ]; + services.tailscale.enable = true; + networking.firewall.allowedUDPPorts = [ 60990 ]; + + # Enable WireGuard + networking.wireguard.interfaces = { + # "wg0" is the network interface name. You can name the interface arbitrarily. + wg0 = { + # Determines the IP address and subnet of the client's end of the tunnel interface. + ips = [ "10.0.69.4/24" ]; + listenPort = 60990; # to match firewall allowedUDPPorts (without this wg uses random port numbers) + + # Path to the private key file. + # + # Note: The private key can also be included inline via the privateKey option, + # but this makes the private key world-readable; thus, using privateKeyFile is + # recommended. + privateKeyFile = "/home/anish/wg/privkey"; + + peers = [ + # For a client configuration, one peer entry for the server will suffice. + { + # Public key of the server (not a file path). + publicKey = "c1J4p63rD3IlszugMZiki7UBV3YmDdqa3DU4UejXzAI="; + + # Forward all the traffic via VPN. + allowedIPs = [ "10.0.69.0/24" ]; + # Or forward only particular subnets + #allowedIPs = [ "10.100.0.1" "91.108.12.0/22" ]; + + # Set this to the server IP and port. + endpoint = "sealight.xyz:60990"; # ToDo: route to endpoint not automatically configured https://wiki.archlinux.org/index.php/WireGuard#Loop_routing https://discourse.nixos.org/t/solved-minimal-firewall-setup-for-wireguard-client/7577 + + # Send keepalives every 25 seconds. Important to keep NAT tables alive. + persistentKeepalive = 25; + } + ]; + }; + }; + +# boot.extraModulePackages = with config.boot.kernelPackages; [ wireguard ]; +# environment.systemPackages = [ pkgs.wireguard ]; +# networking.wireguard.enable = true; +# networking.wireguard.interfaces = { +# wg0 = { +# ips = [ "10.0.69.4/32" ]; +# privateKeyFile = "/home/anish/wg/privkey"; +# listenPort = 60990; +# +# peers = [ +# { # helix - server +# publicKey = "{c1J4p63rD3IlszugMZiki7UBV3YmDdqa3DU4UejXzAI=}"; +# allowedIPs = [ "10.0.69.1/24" ]; +# endpoint = "sealight.xyz:60990"; +# persistentKeepalive = 25; +# } ]; +# }; +# }; } diff --git a/profiles/wallabag/default.nix b/profiles/wallabag/default.nix index ce6c2c7d..6adfca0d 100644 --- a/profiles/wallabag/default.nix +++ b/profiles/wallabag/default.nix @@ -7,93 +7,92 @@ # Ensure the database, user, and permissions always exist ensureDatabases = [ "wallabag" ]; ensureUsers = [ - { - name = "wallabag"; - ensurePermissions."DATABASE wallabag" = "ALL PRIVILEGES"; - } + { name = "wallabag"; + ensurePermissions."DATABASE wallabag" = "ALL PRIVILEGES"; + } ]; }; services.wallabag = { enable = true; hostName = "read.mossnet.lan"; - package = pkgs.callPackage ./pkg-wallabag.nix { }; + package = pkgs.callPackage ./pkg-wallabag.nix {}; conf = '' - # This file is a "template" of what your parameters.yml file should look like - parameters: - # Uncomment these settings or manually update your parameters.yml - # to use docker-compose - # - # database_driver: %env.database_driver% - # database_host: %env.database_host% - # database_port: %env.database_port% - # database_name: %env.database_name% - # database_user: %env.database_user% - # database_password: %env.database_password% +# This file is a "template" of what your parameters.yml file should look like +parameters: + # Uncomment these settings or manually update your parameters.yml + # to use docker-compose + # + # database_driver: %env.database_driver% + # database_host: %env.database_host% + # database_port: %env.database_port% + # database_name: %env.database_name% + # database_user: %env.database_user% + # database_password: %env.database_password% - database_driver: pdo_pgsql - database_host: localhost - database_port: ~ - database_name: wallabag - database_user: wallabag - database_password: wallabag - # For SQLite, database_path should be "%kernel.project_dir%/data/db/wallabag.sqlite" - database_path: ~ - database_table_prefix: wallabag_ - database_socket: null - # with PostgreSQL and SQLite, you must set "utf8" - database_charset: utf8 + database_driver: pdo_pgsql + database_host: localhost + database_port: ~ + database_name: wallabag + database_user: wallabag + database_password: wallabag + # For SQLite, database_path should be "%kernel.project_dir%/data/db/wallabag.sqlite" + database_path: ~ + database_table_prefix: wallabag_ + database_socket: null + # with PostgreSQL and SQLite, you must set "utf8" + database_charset: utf8 - domain_name: http://read.mossnet.lan - server_name: "mossnet wallabag instance" + domain_name: http://read.mossnet.lan + server_name: "mossnet wallabag instance" - mailer_transport: smtp - mailer_user: ~ - mailer_password: ~ - mailer_host: 127.0.0.1 - mailer_port: false - mailer_encryption: ~ - mailer_auth_mode: ~ + mailer_transport: smtp + mailer_user: ~ + mailer_password: ~ + mailer_host: 127.0.0.1 + mailer_port: false + mailer_encryption: ~ + mailer_auth_mode: ~ - locale: en + locale: en - # A secret key that's used to generate certain security-related tokens - secret: SAFGOECRIlfal89oe6u0(*^dsaaih961 + # A secret key that's used to generate certain security-related tokens + secret: SAFGOECRIlfal89oe6u0(*^dsaaih961 - # two factor stuff - twofactor_auth: true - twofactor_sender: no-reply@wallabag.org + # two factor stuff + twofactor_auth: true + twofactor_sender: no-reply@wallabag.org - # fosuser stuff - fosuser_registration: true - fosuser_confirmation: true + # fosuser stuff + fosuser_registration: true + fosuser_confirmation: true - # how long the access token should live in seconds for the API - fos_oauth_server_access_token_lifetime: 3600 - # how long the refresh token should life in seconds for the API - fos_oauth_server_refresh_token_lifetime: 1209600 + # how long the access token should live in seconds for the API + fos_oauth_server_access_token_lifetime: 3600 + # how long the refresh token should life in seconds for the API + fos_oauth_server_refresh_token_lifetime: 1209600 - from_email: no-reply@wallabag.org + from_email: no-reply@wallabag.org - rss_limit: 50 + rss_limit: 50 - # RabbitMQ processing - rabbitmq_host: localhost - rabbitmq_port: 5672 - rabbitmq_user: guest - rabbitmq_password: guest - rabbitmq_prefetch_count: 10 + # RabbitMQ processing + rabbitmq_host: localhost + rabbitmq_port: 5672 + rabbitmq_user: guest + rabbitmq_password: guest + rabbitmq_prefetch_count: 10 - # Redis processing - redis_scheme: tcp - redis_host: localhost - redis_port: 6379 - redis_path: null - redis_password: null + # Redis processing + redis_scheme: tcp + redis_host: localhost + redis_port: 6379 + redis_path: null + redis_password: null - # sentry logging - sentry_dsn: ~ - ''; + # sentry logging + sentry_dsn: ~ +''; }; # networking.firewall.allowedTCPPorts = [ 8080 ]; }