From 2a2edf13f9ae47c04e6a416229e8236f850b2e4a Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Sat, 9 Dec 2023 17:15:50 +0100 Subject: [PATCH] update robi and started with orbi --- nixos/machines/cream/packages.nix | 2 +- nixos/machines/orbi/borg.nix | 18 + nixos/machines/orbi/cache.nix | 13 + nixos/machines/orbi/codimd.nix | 34 + nixos/machines/orbi/configuration.nix | 112 +++ nixos/machines/orbi/disko-config.nix | 150 ++++ nixos/machines/orbi/finance.nix | 58 ++ nixos/machines/orbi/gitea.nix | 37 + nixos/machines/orbi/grafana.nix | 24 + nixos/machines/orbi/graylog.nix | 130 ++++ nixos/machines/orbi/grocy.nix | 16 + .../machines/orbi/hardware-configuration.nix | 38 + nixos/machines/orbi/hetzner.nix | 123 ++++ nixos/machines/orbi/kibana.nix | 25 + nixos/machines/orbi/loki-promtail.nix | 41 ++ nixos/machines/orbi/loki.nix | 99 +++ nixos/machines/orbi/mail-fetcher.nix | 663 ++++++++++++++++++ nixos/machines/orbi/media-arr.nix | 80 +++ nixos/machines/orbi/media-jellyfin.nix | 41 ++ nixos/machines/orbi/media-share.nix | 21 + nixos/machines/orbi/media-syncthing.nix | 79 +++ nixos/machines/orbi/media-tdarr.nix | 54 ++ nixos/machines/orbi/media-transmission.nix | 259 +++++++ nixos/machines/orbi/media-transmission2.nix | 136 ++++ nixos/machines/orbi/media-unmanic.nix | 40 ++ nixos/machines/orbi/mysql.nix | 20 + nixos/machines/orbi/network-tinc.nix | 15 + nixos/machines/orbi/network-wireguard.nix | 55 ++ nixos/machines/orbi/nextcloud.nix | 301 ++++++++ nixos/machines/orbi/nginx-wkd.nix | 30 + nixos/machines/orbi/nginx.nix | 158 +++++ nixos/machines/orbi/packages.nix | 14 + nixos/machines/orbi/prometheus.nix | 70 ++ nixos/machines/orbi/property.nix | 43 ++ nixos/machines/orbi/screeps.nix | 73 ++ nixos/machines/orbi/social-jitsi.nix | 60 ++ nixos/machines/orbi/sync-opentracker.nix | 5 + nixos/machines/orbi/sync-torrent.nix | 111 +++ nixos/machines/orbi/taskserver.nix | 19 + nixos/machines/orbi/telegraf.nix | 28 + nixos/machines/orbi/terranix-dendrite.nix | 109 +++ nixos/machines/orbi/vaultwarden.nix | 32 + nixos/machines/orbi/webhook-ring.nix | 45 ++ nixos/machines/orbi/weechat.nix | 38 + nixos/machines/robi/media-syncthing.nix | 10 +- nixos/machines/robi/nextcloud.nix | 4 +- 46 files changed, 3525 insertions(+), 8 deletions(-) create mode 100644 nixos/machines/orbi/borg.nix create mode 100644 nixos/machines/orbi/cache.nix create mode 100644 nixos/machines/orbi/codimd.nix create mode 100644 nixos/machines/orbi/configuration.nix create mode 100644 nixos/machines/orbi/disko-config.nix create mode 100644 nixos/machines/orbi/finance.nix create mode 100644 nixos/machines/orbi/gitea.nix create mode 100644 nixos/machines/orbi/grafana.nix create mode 100644 nixos/machines/orbi/graylog.nix create mode 100644 nixos/machines/orbi/grocy.nix create mode 100644 nixos/machines/orbi/hardware-configuration.nix create mode 100644 nixos/machines/orbi/hetzner.nix create mode 100644 nixos/machines/orbi/kibana.nix create mode 100644 nixos/machines/orbi/loki-promtail.nix create mode 100644 nixos/machines/orbi/loki.nix create mode 100644 nixos/machines/orbi/mail-fetcher.nix create mode 100644 nixos/machines/orbi/media-arr.nix create mode 100644 nixos/machines/orbi/media-jellyfin.nix create mode 100644 nixos/machines/orbi/media-share.nix create mode 100644 nixos/machines/orbi/media-syncthing.nix create mode 100644 nixos/machines/orbi/media-tdarr.nix create mode 100644 nixos/machines/orbi/media-transmission.nix create mode 100644 nixos/machines/orbi/media-transmission2.nix create mode 100644 nixos/machines/orbi/media-unmanic.nix create mode 100644 nixos/machines/orbi/mysql.nix create mode 100644 nixos/machines/orbi/network-tinc.nix create mode 100644 nixos/machines/orbi/network-wireguard.nix create mode 100644 nixos/machines/orbi/nextcloud.nix create mode 100644 nixos/machines/orbi/nginx-wkd.nix create mode 100644 nixos/machines/orbi/nginx.nix create mode 100644 nixos/machines/orbi/packages.nix create mode 100644 nixos/machines/orbi/prometheus.nix create mode 100644 nixos/machines/orbi/property.nix create mode 100644 nixos/machines/orbi/screeps.nix create mode 100644 nixos/machines/orbi/social-jitsi.nix create mode 100644 nixos/machines/orbi/sync-opentracker.nix create mode 100644 nixos/machines/orbi/sync-torrent.nix create mode 100644 nixos/machines/orbi/taskserver.nix create mode 100644 nixos/machines/orbi/telegraf.nix create mode 100644 nixos/machines/orbi/terranix-dendrite.nix create mode 100644 nixos/machines/orbi/vaultwarden.nix create mode 100644 nixos/machines/orbi/webhook-ring.nix create mode 100644 nixos/machines/orbi/weechat.nix diff --git a/nixos/machines/cream/packages.nix b/nixos/machines/cream/packages.nix index 7818f1d..6e64f4c 100644 --- a/nixos/machines/cream/packages.nix +++ b/nixos/machines/cream/packages.nix @@ -84,7 +84,7 @@ in #fractal #legacy_2205.mirage-im #cinny-desktop - #fluffychat + fluffychat #(fluffychat.overrideAttrs # (old: rec { # version = "1.13.0"; diff --git a/nixos/machines/orbi/borg.nix b/nixos/machines/orbi/borg.nix new file mode 100644 index 0000000..324f6ca --- /dev/null +++ b/nixos/machines/orbi/borg.nix @@ -0,0 +1,18 @@ +{ lib, config, pkgs, ... }: { + + backup.enable = true; + + # provide repository + services.borgbackup.repos = { + default = { + quota = "300G"; + allowSubRepos = true; + authorizedKeys = [ + (lib.fileContents ../../assets/ssh/borg_access.pub) + (lib.fileContents ../../assets/ssh/palo_rsa.pub) + ]; + }; + }; + + +} diff --git a/nixos/machines/orbi/cache.nix b/nixos/machines/orbi/cache.nix new file mode 100644 index 0000000..baa4944 --- /dev/null +++ b/nixos/machines/orbi/cache.nix @@ -0,0 +1,13 @@ +{ ... }: +{ + services.nix-serve = { + enable = true; + + # needed if i want to trust my own build packages and dirivations + # nix-store --generate-binary-cache-key key-name secret-key-file public-key-file + # secretKeyFile = sops.nixServeSecretKeyFile.path + + }; + + +} diff --git a/nixos/machines/orbi/codimd.nix b/nixos/machines/orbi/codimd.nix new file mode 100644 index 0000000..c44a0d8 --- /dev/null +++ b/nixos/machines/orbi/codimd.nix @@ -0,0 +1,34 @@ +{ config, lib, pkgs, ... }: +let + domain = "md.ingolf-wagner.de"; +in +{ + + services.nginx.enable = true; + services.nginx.virtualHosts.hedgedoc = { + enableACME = true; + forceSSL = true; + serverName = domain; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.hedgedoc.settings.port}"; + proxyWebsockets = true; + }; + }; + + services.hedgedoc = { + enable = true; + settings = { + db = { + dialect = "sqlite"; + storage = "/var/lib/hedgedoc/db.sqlite"; + useCDN = false; + }; + allowFreeURL = true; + domain = domain; + port = 3091; + useCDN = false; + }; + }; + +} + diff --git a/nixos/machines/orbi/configuration.nix b/nixos/machines/orbi/configuration.nix new file mode 100644 index 0000000..d1690e8 --- /dev/null +++ b/nixos/machines/orbi/configuration.nix @@ -0,0 +1,112 @@ +{ lib, config, pkgs, ... }: { + imports = [ + + ../../system/all/nginx.nix + ../../system/all/borg-jobs.nix + ../../system/all/defaults.nix + ../../system/all/syncthing.nix + ../../system/server/netdata.nix + ../../system/server/packages.nix + + ../../components + + ../../modules + + ./hetzner.nix + + # services + ./borg.nix + ./codimd.nix + ./gitea.nix + ./nextcloud.nix + ./packages.nix + ./taskserver.nix + ./vaultwarden.nix + ./nginx.nix + ./nginx-wkd.nix + + ./network-tinc.nix + ./network-wireguard.nix + + ./media-share.nix + ./media-jellyfin.nix + ./media-syncthing.nix + ./media-transmission.nix + ./media-transmission2.nix + ./media-arr.nix + #./media-tdarr.nix + #./media-unmanic.nix + + ./sync-opentracker.nix + ./sync-torrent.nix + + #./social-jitsi.nix + + # matrix + ./terranix-dendrite.nix + + # logging + ./loki.nix + ./loki-promtail.nix + ./prometheus.nix + ./grafana.nix + ./telegraf.nix + + ./cache.nix + ]; + + components.terminal.enable = true; + components.mainUser.enable = true; + components.gui.enable = false; + + components.network.enable = true; + components.network.wifi.enable = false; + + # 2 hours = 2 * 60 * 60 = 7200 seconds + #services.netdata.config.global.history = 7200; + # 4 hours = 4 * 60 * 60 = 14440 seconds + services.netdata.config.global.history = 14440; + # 24 hours = 24 * 60 * 60 = 86400 seconds + #services.netdata.config.global.history = 86400; + + services.sshguard.enable = true; + + # Shell configuration + # ------------------- + #programs.custom. zsh.enable = true; + users.users.root.shell = pkgs.zsh; + + security.acme.acceptTerms = true; + security.acme.defaults.email = "contact@ingolf-wagner.de"; + + sops.defaultSopsFile = ../../secrets/robi.yaml; + # virtualisation.docker.enable = false; + services.printing.enable = false; + services.smartd.enable = true; + + # chungus rsync + users.users.root.openssh.authorizedKeys.keys = [ "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJkqVvuJSvRMO5pG2CHNNBxjB7HlJudK4TQs3BhbOWOD" ]; + fileSystems."/var/lib/nextcloud" = + { + device = "/dev/vg/nextcloud"; + fsType = "ext4"; + }; + + fileSystems."/var/lib/borgbackup" = + { + device = "/dev/vg/borg"; + fsType = "ext4"; + }; + + fileSystems."/media" = + { + device = "/dev/vg/media"; + fsType = "ext4"; + }; + + # usually part of the wifi.nix module + # because Networkd-wait-online is just failing. + #systemd.services.systemd-networkd-wait-online.enable = false; + systemd.services.NetworkManager-wait-online.enable = false; + +} diff --git a/nixos/machines/orbi/disko-config.nix b/nixos/machines/orbi/disko-config.nix new file mode 100644 index 0000000..1d489ad --- /dev/null +++ b/nixos/machines/orbi/disko-config.nix @@ -0,0 +1,150 @@ +# nix run github:nix-community/disko -- --mode zap_create_mount ./disko-config.nix +# nixos-generate-config --no-filesystems --root /mnt +# vim /mnt/configuration.nix +# nixos-install +{ config, lib, ... }: +let + disks = [ "sda" "sdb" ]; +in +{ + # ZFS already has its own scheduler. Without this my(@Artturin) computer froze for a second when i nix build something. + # copied from : https://github.com/numtide/srvos/blob/main/nixos/common/zfs.nix + + services.udev.extraRules = lib.optionalString (config.boot.zfs.enabled) '' + ACTION=="add|change", KERNEL=="sd[a-z]*[0-9]*|mmcblk[0-9]*p[0-9]*|nvme[0-9]*n[0-9]*p[0-9]*", ENV{ID_FS_TYPE}=="zfs_member", ATTR{../queue/scheduler}="none" + ''; + + disko.devices = { + disk = + lib.genAttrs disks (disk: { + name = disk; + type = "disk"; + device = "/dev/${disk}"; + content = { + type = "table"; + format = "gpt"; + partitions = [ + { + name = "ESP"; + start = "0"; + end = "500MiB"; + bootable = true; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot_${disk}"; + mountOptions = [ "defaults" ]; + }; + } + { + name = "zfs"; + start = "500MiB"; + size = "500GB"; + content = { + type = "luks"; + name = "root_${disk}"; + settings = { + # if you want to use the key for interactive login be sure there is no trailing newline + # for example use `echo -n "password" > /tmp/secret.key` + keyFile = "/tmp/secret.key"; + allowDiscards = true; + }; + content = { + type = "zfs"; + pool = "zroot"; + }; + }; + } + { + name = "zfs"; + size = "100%"; + content = { + type = "luks"; + settings = { + # if you want to use the key for interactive login be sure there is no trailing newline + # for example use `echo -n "password" > /tmp/secret.key` + keyFile = "/tmp/secret.key"; + allowDiscards = true; + }; + name = "media_${disk}"; + content = { + type = "zfs"; + pool = "zmedia"; + }; + }; + } + ]; + }; + } + ); + + + zpool = { + + zroot = { + type = "zpool"; + mode = "mirror"; + rootFsOptions = { + mountpoint = "none"; + canmount = "off"; + compression = "lz4"; + }; + datasets = { + "root" = { + type = "zfs_fs"; + mountpoint = "/"; + options = { + mountpoint = "legacy"; + compression = "lz4"; + }; + }; + "store" = { + type = "zfs_fs"; + mountpoint = "/nix/store"; + options = { + mountpoint = "legacy"; + compression = "lz4"; + }; + }; + }; + }; + + # `zpool import -f zraid` once on the first boot and reboot + zmedia = { + type = "zpool"; + rootFsOptions = { + mountpoint = "none"; + canmount = "off"; + }; + datasets = { + "media" = { + type = "zfs_fs"; + mountpoint = "/media"; + options = { + mountpoint = "legacy"; + compression = "lz4"; + "com.sun:auto-snapshot:daily" = false; + "com.sun:auto-snapshot:weekly" = false; + "com.sun:auto-snapshot:monthly" = false; + }; + }; + # todo make sure this disk has some minimum space + "nextcloud" = { + type = "zfs_fs"; + mountpoint = "/var/lib/nextcloud/"; + options = { + mountpoint = "legacy"; + compression = "lz4"; + "com.sun:auto-snapshot:hourly" = true; + "com.sun:auto-snapshot:daily" = true; + "com.sun:auto-snapshot:weekly" = false; + "com.sun:auto-snapshot:monthly" = false; + }; + }; + }; + }; + }; + }; + +} + diff --git a/nixos/machines/orbi/finance.nix b/nixos/machines/orbi/finance.nix new file mode 100644 index 0000000..76de251 --- /dev/null +++ b/nixos/machines/orbi/finance.nix @@ -0,0 +1,58 @@ +{ lib, config, pkgs, ... }: +let + + # find symbols with + # https://www.alphavantage.co/query?function=SYMBOL_SEARCH&apikey=&keywords= + # as described here : https://www.alphavantage.co/documentation/#symbolsearch + # + # example: + # -------- + # stocks = [ + # { + # friendly_name = "google"; + # symbol = "GOOGL.DEX"; + # name = "google"; + # currency = "$"; + # } + # ]; + # results in + # P 2020-01-30 GOOGL $123 + stocks = import ../../private_assets/finance/stocks; + stocksFile = toString /home/syncthing/finance/hledger/stocks.journal; + +in +{ + + systemd.services.pull_stocks = { + enable = true; + description = "pull stocks for hledger"; + serviceConfig = { + User = "syncthing"; + Type = "oneshot"; + }; + + script = + let + command = { symbol, name, currency, ... }: '' + APIKEY=${lib.fileContents ../../private_assets/finance/alphavantage/apiKey} + SYMBOL="${symbol}" + ${pkgs.curl}/bin/curl --location --silent \ + "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=$SYMBOL&apikey=$APIKEY" \ + | ${pkgs.jq}/bin/jq --raw-output '.["Global Quote"] + | "P \(.["07. latest trading day"]) ${name} ${currency}\(.["05. price"] | tonumber)"' \ + >> ${stocksFile} + sleep 1 + ''; + in + lib.concatStringsSep "\n" (map command stocks); + }; + + systemd.timers.pull_stocks = { + enable = true; + wantedBy = [ "multi-user.target" ]; + timerConfig = { + OnCalendar = "weekly"; + Persistent = "true"; + }; + }; +} diff --git a/nixos/machines/orbi/gitea.nix b/nixos/machines/orbi/gitea.nix new file mode 100644 index 0000000..fc45e44 --- /dev/null +++ b/nixos/machines/orbi/gitea.nix @@ -0,0 +1,37 @@ +{ config, lib, pkgs, ... }: +{ + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "git.ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.gogs.httpPort}"; + }; + }; + }; + }; + + services.gitea = { + enable = true; + appName = "git.ingolf-wagner.de"; + #cookieSecure = true; + #disableRegistration = true; + settings = { + server.ROOT_URL = "https://git.ingolf-wagner.de/"; + server.DOMAIN = "git.ingolf-wagner.de"; + service.DISABLE_REGISTRATION = true; + session.COOKIE_SECURE = true; + log.LEVEL = "Warn"; + other = { + SHOW_FOOTER_VERSION = false; + }; + }; + }; + + backup.dirs = [ "/var/lib/gitea" ]; + +} diff --git a/nixos/machines/orbi/grafana.nix b/nixos/machines/orbi/grafana.nix new file mode 100644 index 0000000..d8f5642 --- /dev/null +++ b/nixos/machines/orbi/grafana.nix @@ -0,0 +1,24 @@ +{ config, ... }: +{ + + services.nginx.virtualHosts.${config.services.grafana.settings.server.domain} = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.grafana.settings.server.http_port}"; + proxyWebsockets = true; + }; + }; + + services.grafana = { + enable = true; + settings.server = { + domain = "grafana.robi.private"; + http_port = 2342; + http_addr = "localhost"; + }; + }; + +} diff --git a/nixos/machines/orbi/graylog.nix b/nixos/machines/orbi/graylog.nix new file mode 100644 index 0000000..8a31746 --- /dev/null +++ b/nixos/machines/orbi/graylog.nix @@ -0,0 +1,130 @@ +{ config, lib, pkgs, ... }: +let port = 9000; +in { + # configure nginx + services.nginx = { + enable = true; + virtualHosts = { + "graylog.workhorse.private" = { + locations."/" = { + proxyPass = "http://localhost:${toString port}"; + extraConfig = '' + proxy_set_header Host $host:$server_port; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 90; + proxy_redirect http://localhost:${ + toString port + } https://graylog.workhorse.private/; + ''; + }; + }; + }; + }; + + services.mongodb.enable = true; + services.elasticsearch = { + enable = true; + listenAddress = "${config.networking.hostName}.private"; + extraJavaOptions = [ "-Des.http.cname_in_publish_address=true" ]; + }; + + services.graylog.enable = true; + services.graylog.elasticsearchHosts = + [ "http://${config.services.elasticsearch.listenAddress}:9200" ]; + + # https://docs.graylog.org/en/3.0/pages/configuration/server.conf.html + services.graylog.extraConfig = '' + http_bind_address = 0.0.0.0:${toString port} + http_publish_uri = http://workhorse.private:${toString port}/ + ''; + + # other wise this does not work + services.graylog.nodeIdFile = "/var/lib/graylog/node-id"; + + # pwgen -N 1 -s 96 + services.graylog.passwordSecret = + lib.fileContents ../../private_assets/graylog/password-secret; + + # echo -n yourpassword | shasum -a 256 + services.graylog.rootPasswordSha2 = + lib.fileContents ../../private_assets/graylog/root-password-hash; + + services.graylog.plugins = [ pkgs.graylogPlugins.slack ]; + + # not working at the moment + #services.geoip-updater.enable = true; + + # https://wiki.splunk.com/Http_status.csv + environment.etc."graylog/server/httpCodes.csv" = { + enable = true; + text = '' + status,status_description,status_type + 100,Continue,Informational + 101,Switching Protocols,Informational + 200,OK,Successful + 201,Created,Successful + 202,Accepted,Successful + 203,Non-Authoritative Information,Successful + 204,No Content,Successful + 205,Reset Content,Successful + 206,Partial Content,Successful + 300,Multiple Choices,Redirection + 301,Moved Permanently,Redirection + 302,Found,Redirection + 303,See Other,Redirection + 304,Not Modified,Redirection + 305,Use Proxy,Redirection + 307,Temporary Redirect,Redirection + 400,Bad Request,Client Error + 401,Unauthorized,Client Error + 402,Payment Required,Client Error + 403,Forbidden,Client Error + 404,Not Found,Client Error + 405,Method Not Allowed,Client Error + 406,Not Acceptable,Client Error + 407,Proxy Authentication Required,Client Error + 408,Request Timeout,Client Error + 409,Conflict,Client Error + 410,Gone,Client Error + 411,Length Required,Client Error + 412,Precondition Failed,Client Error + 413,Request Entity Too Large,Client Error + 414,Request-URI Too Long,Client Error + 415,Unsupported Media Type,Client Error + 416,Requested Range Not Satisfiable,Client Error + 417,Expectation Failed,Client Error + 500,Internal Server Error,Server Error + 501,Not Implemented,Server Error + 502,Bad Gateway,Server Error + 503,Service Unavailable,Server Error + 504,Gateway Timeout,Server Error + 505,HTTP Version Not Supported,Server Error + ''; + }; + + environment.etc."graylog/server/known_servers.csv" = { + enable = true; + text = '' + "ip","host_name" + "95.216.1.150","lassul.us" + ''; + }; + + environment.etc."graylog/systemd/loglevel.csv" = { + enable = true; + text = '' + "value","Servity","Description" + "0","emergency","System is unusable" + "1","alert","Should be corrected immediately" + "2","cirtical","Critical conditions" + "3","error","Error Condition" + "4","warning","May indicate that an error will occur if action is not taken." + "5","notice","Events that are unusual, but not error conditions." + "6","info","Normal operational messages that require no action." + "7","debug","Information useful to developers for debugging the application." + ''; + }; + +} diff --git a/nixos/machines/orbi/grocy.nix b/nixos/machines/orbi/grocy.nix new file mode 100644 index 0000000..614a8b9 --- /dev/null +++ b/nixos/machines/orbi/grocy.nix @@ -0,0 +1,16 @@ +{ config, lib, pkgs, ... }: + +{ + services.grocy = { + enable = true; + settings = { + culture = "de"; + currency = "EUR"; + }; + hostName = "grocy.ingolf-wagner.de"; + nginx.enableSSL = true; + }; + + backup.dirs = [ config.services.grocy.dataDir ]; + +} diff --git a/nixos/machines/orbi/hardware-configuration.nix b/nixos/machines/orbi/hardware-configuration.nix new file mode 100644 index 0000000..31cbc51 --- /dev/null +++ b/nixos/machines/orbi/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 = [ "ahci" "sd_mod" ]; + boot.initrd.kernelModules = [ "dm-snapshot" ]; + boot.kernelModules = [ "kvm-intel" ]; + boot.extraModulePackages = [ ]; + + fileSystems."/" = + { + device = "/dev/disk/by-uuid/d6a794d2-1da4-4457-9a9a-a39bf9521ae4"; + fsType = "ext4"; + }; + + fileSystems."/boot-1" = + { + device = "/dev/disk/by-uuid/519D-F289"; + fsType = "vfat"; + }; + + fileSystems."/boot-2" = + { + device = "/dev/disk/by-uuid/519E-6EF1"; + fsType = "vfat"; + }; + + swapDevices = [ ]; + + powerManagement.cpuFreqGovernor = lib.mkDefault "ondemand"; +} diff --git a/nixos/machines/orbi/hetzner.nix b/nixos/machines/orbi/hetzner.nix new file mode 100644 index 0000000..0adbb30 --- /dev/null +++ b/nixos/machines/orbi/hetzner.nix @@ -0,0 +1,123 @@ +{ config, pkgs, modulesPath, lib, ... }: + +let + + hostName = "robi"; + + # apt install -y lshw + # lshw -C network | grep -Poh 'driver=[[:alnum:]]+' + + networkInterfaceModule = "r8169"; + + networkInterface = "enp3s0"; + + # From the Hetzner control panel + ipv4 = { + address = "144.76.13.147"; # the ip address + gateway = "144.76.13.129"; # the gateway ip address + netmask = "255.255.255.224"; # the netmask -- might not be the same for you! + prefixLength = 27; # must match the netmask, see + }; + ipv6 = { + address = "2a01:4f8:190:9147::1"; # the ipv6 addres + gateway = "fe80::1"; # the ipv6 gateway + prefixLength = 64; # shown in the control panel + }; + +in + +{ + imports = + [ + # Include the results of the hardware scan. + ./hardware-configuration.nix + ]; + + # needed lvm for raid + boot.initrd.kernelModules = [ + "dm-snapshot" + "dm_mirror" + "dm_raid" + "dm_region_hash" + ]; + + # Use GRUB2 as the boot loader. + # We don't use systemd-boot because Hetzner uses BIOS legacy boot. + boot.loader.systemd-boot.enable = false; + boot.loader.grub = { + enable = true; + efiSupport = false; + }; + + # This will mirror all UEFI files, kernels, grub menus and + # things needed to boot to the other drive. + boot.loader.grub.mirroredBoots = [ + { path = "/boot-1"; devices = [ "/dev/sda" ]; } + { path = "/boot-2"; devices = [ "/dev/sdb" ]; } + ]; + + # We want to still be able to boot without one of these + fileSystems."/boot-1".options = [ "nofail" ]; + fileSystems."/boot-2".options = [ "nofail" ]; + + boot.initrd.luks.reusePassphrases = true; + boot.initrd.luks.devices = { + a_encrypted = { + device = "/dev/sda3"; + preLVM = true; + }; + b_encrypted = { + device = "/dev/sdb3"; + preLVM = true; + }; + }; + + networking.hostName = hostName; + + # Network configuration (Hetzner uses static IP assignments, and we don't use DHCP here) + networking.useDHCP = false; + networking.interfaces.${networkInterface} = { + ipv4 = { addresses = [{ address = ipv4.address; prefixLength = ipv4.prefixLength; }]; }; + ipv6 = { addresses = [{ address = ipv6.address; prefixLength = ipv6.prefixLength; }]; }; + }; + networking.defaultGateway = ipv4.gateway; + networking.defaultGateway6 = { address = ipv6.gateway; interface = networkInterface; }; + networking.nameservers = [ "8.8.8.8" ]; + + # Initial empty root password for easy login: + users.users.root.initialHashedPassword = ""; + services.openssh.settings.PermitRootLogin = "prohibit-password"; + services.openssh.settings.PasswordAuthentication = false; + + environment.systemPackages = [ pkgs.mosh ]; + + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6uza62+Go9sBFs3XZE2OkugBv9PJ7Yv8ebCskE5WYPcahMZIKkQw+zkGI8EGzOPJhQEv2xk+XBf2VOzj0Fto4nh8X5+Llb1nM+YxQPk1SVlwbNAlhh24L1w2vKtBtMy277MF4EP+caGceYP6gki5+DzlPUSdFSAEFFWgN1WPkiyUii15Xi3QuCMR8F18dbwVUYbT11vwNhdiAXWphrQG+yPguALBGR+21JM6fffOln3BhoDUp2poVc5Qe2EBuUbRUV3/fOU4HwWVKZ7KCFvLZBSVFutXCj5HuNWJ5T3RuuxJSmY5lYuFZx9gD+n+DAEJt30iXWcaJlmUqQB5awcB1S2d9pJ141V4vjiCMKUJHIdspFrI23rFNYD9k2ZXDA8VOnQE33BzmgF9xOVh6qr4G0oEpsNqJoKybVTUeSyl4+ifzdQANouvySgLJV/pcqaxX1srSDIUlcM2vDMWAs3ryCa0aAlmAVZIHgRhh6wa+IXW8gIYt+5biPWUuihJ4zGBEwkyVXXf2xsecMWCAGPWPDL0/fBfY9krNfC5M2sqxey2ShFIq+R/wMdaI7yVjUCF2QIUNiIdFbJL6bDrDyHnEXJJN+rAo23jUoTZZRv7Jq3DB/A5H7a73VCcblZyUmwMSlpg3wos7pdw5Ctta3zQPoxoAKGS1uZ+yTeZbPMmdbw==" + ]; + + services.openssh.enable = true; + + system.stateVersion = "21.05"; + + # enable ssh on init + # ------------------ + + boot.kernelParams = [ + # See for docs on this + # ip=::::::::: + # The server ip refers to the NFS server -- we don't need it. + "ip=${ipv4.address}::${ipv4.gateway}:${ipv4.netmask}:${hostName}-initrd:${networkInterface}:off:8.8.8.8" + ]; + boot.initrd.availableKernelModules = [ networkInterfaceModule ]; + boot.initrd.network.enable = true; + boot.initrd.network.ssh = { + enable = true; + authorizedKeys = config.users.users.root.openssh.authorizedKeys.keys; + port = 2222; + hostKeys = [ + /etc/secrets/initrd/ssh_host_rsa_key + /etc/secrets/initrd/ssh_host_ed25519_key + ]; + }; + +} diff --git a/nixos/machines/orbi/kibana.nix b/nixos/machines/orbi/kibana.nix new file mode 100644 index 0000000..279aea1 --- /dev/null +++ b/nixos/machines/orbi/kibana.nix @@ -0,0 +1,25 @@ +{ config, ... }: { + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "kibana.${config.networking.hostName}.private" = { + serverAliases = [ ]; + locations."/" = { + proxyPass = "http://${config.networking.hostName}.private:${ + toString config.services.kibana.port + }"; + }; + }; + }; + }; + + services.elasticsearch.enable = true; + services.elasticsearch.listenAddress = "workhorse.private"; + + services.kibana.enable = true; + services.kibana.elasticsearch.hosts = [ "http://workhorse.private:9200" ]; + services.kibana.listenAddress = "workhorse.private"; + services.kibana.port = 5601; + +} diff --git a/nixos/machines/orbi/loki-promtail.nix b/nixos/machines/orbi/loki-promtail.nix new file mode 100644 index 0000000..1c64287 --- /dev/null +++ b/nixos/machines/orbi/loki-promtail.nix @@ -0,0 +1,41 @@ +{ config, ... }: +{ + services.promtail = { + enable = true; + configuration = { + server = { + http_listen_port = 28183; + grpc_listen_port = 0; + }; + positions.filename = "/tmp/positions.yaml"; + clients = [ + { url = "http://127.0.0.1:3100/loki/api/v1/push"; } + ]; + + scrape_configs = [ + { + job_name = "journal"; + journal = { + max_age = "12h"; + labels = { + job = "systemd-journal"; + host = config.networking.hostName; + }; + }; + relabel_configs = [ + { + source_labels = [ "__journal__systemd_unit" ]; + target_label = "unit"; + } + { + source_labels = [ "__journal__transport" ]; + target_label = "transport"; + } + ]; + } + ]; + + }; + + }; +} diff --git a/nixos/machines/orbi/loki.nix b/nixos/machines/orbi/loki.nix new file mode 100644 index 0000000..c0eba2c --- /dev/null +++ b/nixos/machines/orbi/loki.nix @@ -0,0 +1,99 @@ +{ config, pkgs, ... }: +{ + + services.loki = { + enable = true; + configuration = { + server = { + http_listen_port = 3100; + log_level = "warn"; + }; + auth_enabled = false; + + ingester = { + lifecycler = { + address = "127.0.0.1"; + ring = { + kvstore = { + store = "inmemory"; + }; + replication_factor = 1; + }; + }; + chunk_idle_period = "1h"; + max_chunk_age = "1h"; + chunk_target_size = 999999; + chunk_retain_period = "30s"; + max_transfer_retries = 0; + }; + + schema_config = { + configs = [{ + from = "2022-06-06"; + store = "boltdb-shipper"; + object_store = "filesystem"; + schema = "v11"; + index = { + prefix = "index_"; + period = "24h"; + }; + }]; + }; + + storage_config = { + boltdb_shipper = { + active_index_directory = "/var/lib/loki/boltdb-shipper-active"; + cache_location = "/var/lib/loki/boltdb-shipper-cache"; + cache_ttl = "24h"; + shared_store = "filesystem"; + }; + + filesystem = { + directory = "/var/lib/loki/chunks"; + }; + }; + + limits_config = { + reject_old_samples = true; + reject_old_samples_max_age = "168h"; + }; + + chunk_store_config = { + max_look_back_period = "0s"; + }; + + table_manager = { + retention_deletes_enabled = false; + retention_period = "0s"; + }; + + compactor = { + working_directory = "/var/lib/loki"; + shared_store = "filesystem"; + compactor_ring = { + kvstore = { + store = "inmemory"; + }; + }; + }; + }; + # user, group, dataDir, extraFlags, (configFile) + }; + + #services.nginx = { + # enable = true; + # virtualHosts.loki = { + # serverName = "loki.pepe.private"; + # locations."/" = { + # proxyWebsockets = true; + # proxyPass = "http://127.0.0.1:3100"; + # #extraConfig = '' + # # access_log off; + # # allow ${config.tinc.private.subnet}; + # # deny all; + # #''; + # }; + # }; + #}; + +} diff --git a/nixos/machines/orbi/mail-fetcher.nix b/nixos/machines/orbi/mail-fetcher.nix new file mode 100644 index 0000000..d8ca3dd --- /dev/null +++ b/nixos/machines/orbi/mail-fetcher.nix @@ -0,0 +1,663 @@ +# fetches mails for me +{ lib, pkgs, config, ... }: +let + junk_filter = [ + "from:booking.com" + "subject:Gewinn" + "from:brompton.com" + "from:circleci.com OR (from:noreply@github.com AND to:audio-overlay@googlegroups.com)" + "from:codepen.io" + "from:congstarnews.de" + "from:cronullasurfingacademy.com" + "from:cryptohopper.com" + "from:digitalo.de" + "from:facebook.com OR from:facebookmail.com" + "from:fitnessfirst.de" + "from:flixbus.de" + "from:getdigital.de" + "from:getpocket.com" + "from:ghostinspector.com" + "from:globetrotter.de" + "from:hackster.io" + "from:hostelworld.com" + "from:immobilienscout24.de" + "from:kvraudio.com" + "from:letterboxd.com" + "from:linkedin.com" + "from:magix.net" + "from:mailings.gmx.net" + "from:mailings.web.de" + "from:matrix.org" + "from:menospese.com" + "from:microsoftstoreemail.com" + "from:mixcloudmail.com AND subject:Weekly Update" + "from:oknotify2.com AND NOT subject:New message" + "from:paulaschoice.com" + "from:puppet.com" + "from:runtastic.com" + "from:samplemagic.com OR from:wavealchemy.co.uk OR from:creators.gumroad.com" + "from:ticketmaster.de" + "from:trade4less.de" + "from:tumblr.com" + "from:turners.co.nz" + "from:twitch.tv" + "from:vstbuzz.com" + ]; + filters = [ + { + query = "from:hv-geelen.de"; + tags = [ "+wohnung" ]; + } + { + query = "from:computerfutures.com OR from:computerfutures.de"; + tags = [ "+jobs" "-inbox" ]; + } + { + query = "from:seek.com.au or from:seek.co.nz"; + tags = [ "+jobs" ]; + } + { + query = "from:xing.com"; + tags = [ "+jobs" "-inbox" ]; + } + { + query = "from:no-reply@backtrace.io OR to:sononym@noreply.github.com"; + tags = [ "+sononym" "-inbox" ]; + } + { + query = "from:ebay.com OR from:ebay.de OR from:ebay.net"; + tags = [ "+ebay" "+shop" "+billing" ]; + } + { + query = "from:bahn.de"; + tags = [ "+billing" "+bahn" ]; + } + { + query = + "from:fysitech.atlassian.net OR to:engiadina-pwa@noreply.github.com"; + tags = [ "+mia" "+work" "-unread" "-inbox" ]; + } + { + query = + "from:space-left.org OR to:space-left.org OR subject:/\\[space-left\\]/"; + tags = [ "+spaceleft" "+space-left" ]; + } + { + query = "from:landr.com"; + tags = [ "+landr" "+music" ]; + } + { + query = "tag:landr and tag:billing"; + tags = [ "+billing" ]; + } + { + query = "from:oknotify2.com"; + tags = [ "+okcupid" ]; + } + { + query = "from:taxback.de OR to:taxback.de"; + tags = [ "+steuer" ]; + } + { + query = "from:campact.de"; + tags = [ "+campact" "+politics" ]; + } + { + query = "from:aliexpress.com"; + tags = [ "+shop" "+aliexpress" ]; + } + { + query = "from:congstar.de"; + tags = [ "+billing" "+congstar" "-inbox" "-unread" ]; + } + { + query = + "from:steampowered.com AND NOT ( subject:purchase OR subject:received )"; + tags = [ "-inbox" "-unread" ]; + } + { + query = + "from:steampowered.com AND ( subject:purchase OR subject:received )"; + tags = [ "+billing" "+steam" ]; + } + { + query = "from:gog.com AND NOT subject:Bestellung"; + tags = [ "-inbox" "-unread" ]; + } + { + query = "from:gog.com AND subject:Bestellung"; + tags = [ "+billing" "+gog" ]; + } + { + query = "from:stadtmobil.de"; + tags = [ "+billing" "+stadtmobil" "-inbox" "-unread" ]; + } + { + query = "from:drive-now.com"; + tags = [ "+billing" "+drivenow" "-inbox" "-unread" ]; + } + { + query = "from:data-treuhand.de"; + tags = [ "+mindcurv" "+work" "-inbox" "-unread" "-junk" ]; + } + { + query = "from:immocation.de"; + tags = [ "+immobilien" "-inbox" ]; + } + { + query = "from:tinc-vpn.org"; + tags = [ "+tinc" ]; + } + { + query = "from:mindfactory.de"; + tags = [ "+shop" "+billing" ]; + } + { + query = "from:zalando.de"; + tags = [ "+shop" "+billing" "+zalando" ]; + } + { + query = "from:ing.de"; + tags = [ "+bank" "+ingdiba" ]; + } + { + query = "from:nab.com.au"; + tags = [ "+bank" "+nab" "-inbox" "-unread" ]; + } + { + query = "from:dkb.de"; + tags = [ "+bank" "+dkb" ]; + } + { + query = "from:o2online.de"; + tags = [ "+billing" "+o2" ]; + } + { + query = "from:betfair.com"; + tags = [ "+work" "+betfair" ]; + } + { + query = "from:notifications@github.com"; + tags = [ "+github" ]; + } + { + query = "to:NUR@noreply.github.com"; + tags = [ "+nur" "+nixos" "+list" ]; + } + { + query = "to:nixpkgs@noreply.github.com"; + tags = [ "+nixpkgs" "+nixos" "+list" ]; + } + { + query = "from:travis-ci.org AND subject:mrVanDalo/navi"; + tags = [ "+development" "+navi" ]; + } + { + query = "from:travis-ci.org AND subject:nur-packages"; + tags = [ "+development" "+nixos" "+nur-packages" ]; + } + { + query = "from:travis-ci.org AND subject:csv-to-qif"; + tags = [ "+development" "+csv-to-qif" ]; + } + { + query = "to:proaudio@lists.tuxfamily.org"; + tags = [ "-inbox" "-unread" ]; + } + { + query = "from:nixos1@discoursemail.com"; + tags = [ "+nixos" "+discourse" "+list" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Development"; + tags = [ "+nixos" "+discourse" "+development" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Français"; + tags = [ "+nixos" "+discourse" "-inbox" "-unread" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Announcements"; + tags = [ "+nixos" "+discourse" "+announcements" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Links"; + tags = [ "+nixos" "+discourse" "+links" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Games"; + tags = [ "+nixos" "+discourse" "+games" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Meta"; + tags = [ "+nixos" "+discourse" "+meta" ]; + } + { + query = "from:nixos1@discoursemail.com AND subject:Events"; + tags = [ "+nixos" "+discourse" "+events" ]; + } + { + query = "from:limebike.com AND (subject:Funds OR subject:Receipt)"; + tags = [ "-inbox" "-unread" "+billing" "+limebike" ]; + } + { + query = "from:freemusicarchive.org"; + tags = [ "+FMA" ]; + } + { + query = "from:namecheap.com and subject:auto-renewal"; + tags = [ "+namecheap" "+billing" ]; + } + { + query = "from:namecheap.com and subject:order"; + tags = [ "+namecheap" "+billing" ]; + } + { + query = "tag:namecheap.com and tag:billing and body:gaykraft.com"; + tags = [ "+namecheap" "+billing" ]; + } + { + query = "from:nintendo.com"; + tags = [ "+nintendo" "+billing" ]; + } + { + query = "from:oculus.com AND subject:receipt"; + tags = [ "+oculus" "+billing" ]; + } + { + query = "from:car2go.com"; + tags = [ "-inbox" "-unread" ]; + } + { + query = "from:sixt.de"; + tags = [ "-inbox" "-unread" ]; + } + { + query = "from:meetup.com"; + tags = [ "-inbox" "-unread" "+meetup" ]; + } + { + query = "from:slack.com"; + tags = [ "+slack" ]; + } + { + query = "from:keybase.io"; + tags = [ "+keybase" ]; + } + { + query = "from:jobs2web.com"; + tags = [ "+newzealand" "+jobs" "-inbox" ]; + } + { + query = "from:paypal.de AND subject:Bestätigung"; + tags = [ "-unread" "+paypal" "+billing" ]; + } + { + query = "to:c-base.org"; + tags = [ "+cbase" "+list" ]; + } + { + query = "to:c-base.org AND subject=[auto-report]"; + tags = [ "-unread" "-inbox" ]; + } + { + query = "from:browserstack.com"; + tags = [ "+browserstack" ]; + } + { + query = + "to:renoise@ingolf-wagner.de OR to:root@renoise.com OR from:renoise.com OR to:admin@renoise.com"; + tags = [ "+renoise" ]; + } + { + query = "from:amazon.de OR from:amazon.com AND NOT to:renoise.com"; + tags = [ "+shop" "+amazon" "+billing" ]; + } + { + query = "from:hetzner.com OR from:hetzner.de"; + tags = [ "+hetzner" ]; + } + { + query = + "to:renoise.com AND NOT ( from:renoise.com OR from:root OR from:hetzner.com OR from:hetzner.de OR from:amazon.com OR from:gmail.com )"; + tags = [ "-inbox" "-unread" "+junk" "+renoise" ]; + } + { + query = "tag:hetzner and subject:Invoice"; + tags = [ "+billing" ]; + } + # final rules to make imap sync stuff easier + # there can only be one output folder tag, and theses rules are prioritized + { + query = "tag:fraud"; + tags = [ "-inbox" "-archive" "-junk" "-unread" ]; + message = "clean up tag fraud"; + } + { + query = "tag:junk"; + tags = [ "-inbox" "-archive" "-fraud" "-unread" ]; + message = "clean up tag junk"; + } + { + query = "tag:archive"; + tags = [ "-inbox" "-junk" "-fraud" "-unread" ]; + message = "clean up tag archive"; + } + { + query = "tag:inbox"; + tags = [ "-archive" "-junk" "-fraud" ]; + message = "clean up inbox"; + } + { + query = "tag:killed"; + tags = [ "-inbox" "-unread" ]; + message = "clean up tag killed"; + } + { + query = "tag:muted"; + tags = [ "-inbox" "-unread" ]; + } + # remove new tag at the end + { + query = "tag:new"; + tags = [ "-new" ]; + message = "remove new tag at the end"; + } + ]; + + notmuchTagging = + let + + template = index: + { tags, query, message ? "generic", ... }: + let + command = '' + ${pkgs.notmuch}/bin/notmuch tag ${lib.concatStringsSep " " tags} -- "${query}" + ''; + in + '' + echo '${command}' + ${command} + ''; + junk_template = index: query: + template index { + tags = [ "+junk" "-unread" "-inbox" ]; + query = query; + message = "generic junk filter"; + }; + + in + pkgs.writers.writeBash "notmuch-tagging" (lib.concatStringsSep "\n" + ((lib.imap0 junk_template junk_filter) ++ (lib.imap0 template filters))); + + notmuchTaggingNew = + let + + template = index: + { tags, query, message ? "generic", ... }: + let + command = '' + ${pkgs.notmuch}/bin/notmuch tag ${ + lib.concatStringsSep " " tags + } -- "${query} AND tag:new" + ''; + in + '' + echo '${command}' + ${command} + ''; + + junk_template = index: query: + template index { + tags = [ "+junk" "-unread" "-inbox" ]; + query = query; + message = "generic junk filter"; + }; + in + pkgs.writers.writeBash "notmuch-tagging-new" (lib.concatStringsSep "\n" + ((lib.imap0 junk_template junk_filter) ++ (lib.imap0 template filters))); + +in +{ + + backup.dirs = [ "/home/mailfetcher" ]; + + users.users.mailUser = { + isNormalUser = true; + description = "collects mails for me"; + hashedPassword = "!"; + name = "mailfetcher"; + home = "/home/mailfetcher"; + openssh.authorizedKeys.keyFiles = + config.users.users.root.openssh.authorizedKeys.keyFiles; + group = "mailfetcher"; + }; + + users.groups.mailUser = { + name = "mailfetcher"; + }; + + sops.secrets.mail_terranix = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + sops.secrets.mail_gmail = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + sops.secrets.mail_gmx_palo = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + sops.secrets.mail_gmx_ingolf = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + sops.secrets.mail_web = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + sops.secrets.mail_siteground = { + owner = config.users.users.mailUser.name; + group = config.users.users.mailUser.group; + }; + + environment.systemPackages = [ pkgs.muchsync ]; + + # configure accounts + home-manager.users.mailUser.accounts.email = { + accounts = { + + palo_van_dalo-gmx = { + primary = false; + address = "palo_van_dalo@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palo_van_dalo@gmx.de"; + passwordCommand = + "cat ${toString config.sops.secrets.mail_gmx_palo.path }"; + imap = { + host = "imap.gmx.net"; + tls.enable = true; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + + ingolf-wagner-gmx = { + primary = false; + address = "ingolf.wagner@gmx.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "ingolf.wagner@gmx.de"; + passwordCommand = + "cat ${toString config.sops.secrets.mail_gmx_ingolf.path }"; + imap = { + host = "imap.gmx.net"; + tls.enable = true; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + + pali_palo = { + primary = false; + address = "pali_palo@web.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "pali_palo@web.de"; + passwordCommand = + "cat ${toString config.sops.secrets.mail_web.path }"; + imap = { + host = "imap.web.de"; + tls.enable = true; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + + gmail = { + # for google accounts you have to allow 'less secure apps' in accounts.google.com + primary = true; + address = "palipalo9@googlemail.com"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palipalo9@googlemail.com"; + passwordCommand = + "cat ${toString config.sops.secrets.mail_gmail.path }"; + imap = { + host = "imap.gmail.com"; + tls.enable = true; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + + terranix_org = { + primary = false; + address = "palo@terranix.org"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "palo@terranix.org"; + passwordCommand = "cat ${toString config.sops.secrets.mail_terranix.path }"; + imap = { + host = "mail.privateemail.com"; + tls.enable = true; + port = 993; + }; + mbsync = { + enable = true; + create = "both"; + }; + notmuch.enable = true; + }; + + ingolf-wagner-de = { + primary = false; + address = "contact@ingolf-wagner.de"; + aliases = [ ]; + realName = "Ingolf Wagner"; + userName = "contact@ingolf-wagner.de"; + passwordCommand = + "cat ${toString config.sops.secrets.mail_siteground.path }"; + imap = { + host = "securees5.sgcpanel.com"; + port = 993; + tls.enable = true; + #tls.useStartTls = true; + }; + # make sure the upstream mail is deleted + getmail = { + enable = true; + delete = true; + readAll = false; + mailboxes = [ "ALL" ]; + }; + notmuch.enable = true; + }; + + }; + }; + + home-manager.users.mailUser.home.stateVersion = "22.11"; + + # configure mbsync + home-manager.users.mailUser.programs.mbsync.enable = true; + + # re-tag everything once a day + systemd.services.retagmail = { + enable = true; + serviceConfig = { User = config.users.users.mailUser.name; }; + environment.NOTMUCH_CONFIG = + "${config.users.users.mailUser.home}/.config/notmuch/notmuchrc"; + script = "${notmuchTagging}"; + }; + systemd.timers.retagmail = { + enable = true; + timerConfig = { + OnCalendar = "daily"; + Persistent = "true"; + }; + wantedBy = [ "multi-user.target" ]; + }; + + # fetch mails every 10 minutes + systemd.services.fetchmail = + let + threadTag = tag: '' + echo "tag threads with ${tag}" + ${pkgs.notmuch}/bin/notmuch tag +${tag} $(${pkgs.notmuch}/bin/notmuch search --output=threads tag:${tag}) + ''; + in + { + enable = true; + serviceConfig = { User = config.users.users.mailUser.name; }; + environment.NOTMUCH_CONFIG = + "${config.users.users.mailUser.home}/.config/notmuch/notmuchrc"; + script = '' + echo "run mbsync" + ${pkgs.isync}/bin/mbsync \ + --all + echo "run getmail" + ${pkgs.getmail}/bin/getmail \ + --quiet \ + --rcfile getmailingolf-wagner-de + + echo "run notmuch" + ${pkgs.notmuch}/bin/notmuch new + ${notmuchTaggingNew} + ${threadTag "muted"} + ${threadTag "wohnung"} + ${threadTag "flagged"} + ''; + }; + systemd.timers.fetchmail = { + enable = true; + # timerConfig.OnCalendar = " *-*-* *:00:00"; + timerConfig.OnCalendar = "*:0/10"; + wantedBy = [ "multi-user.target" ]; + }; + + # configure notmuch + home-manager.users.mailUser.programs.notmuch = { + enable = true; + new.tags = [ "unread" "inbox" "new" ]; + }; + +} diff --git a/nixos/machines/orbi/media-arr.nix b/nixos/machines/orbi/media-arr.nix new file mode 100644 index 0000000..4fd1632 --- /dev/null +++ b/nixos/machines/orbi/media-arr.nix @@ -0,0 +1,80 @@ +{ config, ... }: +{ + networking.firewall.interfaces.wg0.allowedTCPPorts = [ 7878 8989 ]; + + # download series + services.sonarr = { + enable = true; + group = "media"; + user = "media"; + }; + + # download movies + services.radarr = { + enable = true; + group = "media"; + user = "media"; + }; + + # better indexer apis + services.prowlarr = { + enable = true; + #group = "media"; + #user = "media"; + }; + + services.jellyseerr = { + enable = true; + }; + + services.permown."/media/arr" = { + owner = "media"; + group = "media"; + directory-mode = "770"; + file-mode = "770"; + }; + + services.nginx.virtualHosts = { + "radarr.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:7878"; + proxyWebsockets = true; + }; + }; + "sonarr.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:8989"; + proxyWebsockets = true; + }; + }; + "prowlarr.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:9696"; + proxyWebsockets = true; + }; + }; + "jellyseerr.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.jellyseerr.port}"; + proxyWebsockets = true; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/media-jellyfin.nix b/nixos/machines/orbi/media-jellyfin.nix new file mode 100644 index 0000000..39f0af4 --- /dev/null +++ b/nixos/machines/orbi/media-jellyfin.nix @@ -0,0 +1,41 @@ +{ config, lib, pkgs, ... }: +{ + + services.jellyfin = { + enable = true; + openFirewall = true; + group = "media"; + user = "media"; + }; + + hardware.opengl = { + enable = true; + driSupport = true; + driSupport32Bit = true; + }; + + services.nginx = + let + flixConfig = { + forceSSL = true; + enableACME = true; + extraConfig = '' + # Security / XSS Mitigation Headers + # NOTE: X-Frame-Options may cause issues with the webOS app + add_header X-Frame-Options "SAMEORIGIN"; + add_header X-XSS-Protection "1; mode=block"; + add_header X-Content-Type-Options "nosniff"; + ''; + locations."/" = { + recommendedProxySettings = true; + proxyWebsockets = true; + proxyPass = "http://localhost:8096"; + }; + }; + in + { + enable = true; + virtualHosts. "flix.ingolf-wagner.de" = flixConfig; + virtualHosts. "video.ingolf-wagner.de" = flixConfig; + }; +} diff --git a/nixos/machines/orbi/media-share.nix b/nixos/machines/orbi/media-share.nix new file mode 100644 index 0000000..86a1080 --- /dev/null +++ b/nixos/machines/orbi/media-share.nix @@ -0,0 +1,21 @@ +{ config, ... }: +{ + + users.groups."media".gid = config.ids.gids.transmission; + users.users."media" = { + uid = config.ids.uids.transmission; + useDefaultShell = true; + home = "/home/media"; + createHome = true; + group = "media"; + }; + + services.permown."/media/media" = { + owner = "media"; + group = "media"; + directory-mode = "770"; + file-mode = "770"; + }; + + +} diff --git a/nixos/machines/orbi/media-syncthing.nix b/nixos/machines/orbi/media-syncthing.nix new file mode 100644 index 0000000..ae5629d --- /dev/null +++ b/nixos/machines/orbi/media-syncthing.nix @@ -0,0 +1,79 @@ +{ config, pkgs, lib, ... }: { + + imports = [ ../../system/all/syncthing.nix ]; + + sops.secrets.syncthing_cert = { }; + sops.secrets.syncthing_key = { }; + + networking.firewall.allowedTCPPorts = [ 22000 ]; + networking.firewall.allowedUDPPorts = [ 22000 ]; + + services.syncthing = { + enable = true; + openDefaultPorts = false; + dataDir = "/media/syncthing/config"; + configDir = "/media/syncthing/config"; + overrideDevices = true; + overrideFolders = true; + cert = toString config.sops.secrets.syncthing_cert.path; + key = toString config.sops.secrets.syncthing_key.path; + + settings.folders = { + # on media hard drive (not encrypted) + # ----------------------------------- + #borg-mirror = { + # enable = true; + # path = "/media/syncthing/borg"; + # rescanInterval = 36 * 3600; + # type = "sendonly"; + #}; + #video-material = { + # enable = true; + # path = "/home/syncthing/video-material"; + #}; + books = { + enable = true; + path = "/media/syncthing/books"; + }; + lost-fotos = { + enable = true; + path = "/media/syncthing/lost-fotos.ct"; + rescanIntervalS = 40 * 24 * 3600; + }; + #media = { + # enable = true; + # watch = false; + # type = "sendonly"; + # path = "/media/syncthing/media"; + # rescanInterval = 27 * 24 * 3600; + #}; + music-projects = { + enable = true; + #watch = true; + path = "/media/syncthing/music-projects"; + }; + nextcloud_backup = { + enable = true; + #watch = true; + path = "/media/syncthing/nextcloud_backup"; + rescanIntervalS = 23 * 3600; + }; + }; + }; + + services.permown."/media/syncthing" = { + # not managed by syncthing anymore + owner = "syncthing"; + group = "syncthing"; + umask = "0002"; + }; + systemd.services."permown._media_syncthing" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + systemd.services."syncthing" = { + bindsTo = [ "media.mount" ]; + after = [ "media.mount" ]; + }; + +} diff --git a/nixos/machines/orbi/media-tdarr.nix b/nixos/machines/orbi/media-tdarr.nix new file mode 100644 index 0000000..84c0fb0 --- /dev/null +++ b/nixos/machines/orbi/media-tdarr.nix @@ -0,0 +1,54 @@ +{ config, lib, pkgs, ... }: +{ + + # https://docs.tdarr.io/docs/installation/docker/run-compose + virtualisation.oci-containers = { + containers.tdarr = { + volumes = [ + "/media/arr/tdarr/server:/app/server" + "/media/arr/tdarr/configs:/app/configs" + "/media/arr/tdarr/logs:/app/logs" + "/media/arr/tdarr/transcode_cache:/temp" + "/media:/media" + ]; + environment = { + serverIP = "0.0.0.0"; + serverPort = "8266"; + webUIPort = "8265"; + internalNode = "true"; + inContainer = "true"; + nodeName = "robi"; + TZ = "Europe/Berlin"; + PUID = toString config.users.users.media.uid; + PGID = toString config.users.groups.media.gid; + }; + ports = [ + "127.0.0.1:8265:8265" # WebUI + # "8266:8266" # server port + ]; + image = "ghcr.io/haveagitgat/tdarr:latest"; # Warning: if the tag does not change, the image will not be updated + extraOptions = [ + #"--network=bridge" + #"--privileged" + ]; + }; + }; + + #networking.firewall.interfaces.wq0.allowedTCPPorts = [ 8266 ]; + #networking.firewall.interfaces.wq0.allowedUDPPorts = [ 8266 ]; + + #networking.firewall.interfaces.enp0s31f6.allowedTCPPorts = [ 8266 ]; + #networking.firewall.interfaces.enp0s31f6.allowedUDPPorts = [ 8266 ]; + + services.nginx.virtualHosts."tdarr.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:8265"; + proxyWebsockets = true; + }; + }; + +} diff --git a/nixos/machines/orbi/media-transmission.nix b/nixos/machines/orbi/media-transmission.nix new file mode 100644 index 0000000..3b6d13d --- /dev/null +++ b/nixos/machines/orbi/media-transmission.nix @@ -0,0 +1,259 @@ +{ lib, pkgs, config, ... }: +let + hostInterface = "enp3s0"; + hostAddress = "192.168.100.30"; + containerAddress = "192.168.100.31"; + uiPort = 9091; +in +{ + + sops.secrets.nordvpn = { }; + sops.secrets.transmissionPushover = { }; + + containers.torrent = { + + # mount host folders + bindMounts = { + #password = { + # hostPath = "/run/secrets/transmission_password"; + # mountPoint = "/run/secrets/transmission_password"; + # isReadOnly = true; + #}; + transmissionPushover = { + hostPath = "/run/secrets/transmissionPushover"; + mountPoint = "/run/secrets/transmissionPushover"; + isReadOnly = true; + }; + nordvpnPassword = { + hostPath = "/run/secrets/nordvpn"; + mountPoint = "/run/secrets/nordvpn"; + isReadOnly = true; + }; + media = { + hostPath = "/media"; + mountPoint = "/media"; # must be here otherwise transmission can't see the folder + isReadOnly = false; + }; + lib = { + hostPath = "/media/torrent/torrent1_config"; + mountPoint = "/var/lib/transmission/.config"; + isReadOnly = false; + }; + }; + + # container network setup + # see also nating on host system. + privateNetwork = true; + hostAddress = hostAddress; + localAddress = containerAddress; + autoStart = true; + + # needed for openvpn + enableTun = true; + + config = { config, pkgs, lib, ... }: { + + system.stateVersion = "21.05"; + services.journald.extraConfig = "SystemMaxUse=1G"; + + # allow transmission to write in syncthing folders + users.groups.syncthing = { + gid = config.ids.gids.syncthing; + members = [ "transmission" ]; + }; + + services.transmission = { + enable = true; + settings = { + download-dir = "/media/torrent/downloads"; + incomplete-dir = "/media/torrent/incomplete"; + incomplete-dir-enabled = true; + message-level = 1; + umask = 2; + rpc-whitelist-enabled = false; + rpc-host-whitelist-enabled = false; + rpc-port = uiPort; + rpc-enable = true; + rpc-bind-address = "0.0.0.0"; + + # "normal" speed limits + speed-limit-down-enabled = false; + speed-limit-down = 800; + speed-limit-up-enabled = true; + speed-limit-up = 3000; + upload-slots-per-torrent = 8; + # Queuing + # When true, Transmission will only download + # download-queue-size non-stalled torrents at once. + download-queue-enabled = true; + download-queue-size = 3; + + # When true, torrents that have not shared data for + # queue-stalled-minutes are treated as 'stalled' + # and are not counted against the queue-download-size + # and seed-queue-size limits. + queue-stalled-enabled = true; + queue-stalled-minutes = 60; + + # When true. Transmission will only seed seed-queue-size + # non-stalled torrents at once. + seed-queue-enabled = false; + seed-queue-size = 10; + + # Enable UPnP or NAT-PMP. + peer-port = 51413; + port-forwarding-enabled = false; + + # Start torrents as soon as they are added + start-added-torrents = true; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 51413 ]; + allowedUDPPorts = [ 51413 ]; + # only allow access via nginx (proxy to localhost) + interfaces.eth0 = { + allowedTCPPorts = [ uiPort ]; + allowedUDPPorts = [ uiPort ]; + }; + }; + + # bind transmission to openvpn + systemd.services.transmission = { + bindsTo = [ "openvpn-nordvpn.service" ]; + after = [ "openvpn-nordvpn.service" ]; + serviceConfig = { + Restart = "always"; + EnvironmentFile = [ + "/run/secrets/transmissionPushover" + ]; + BindPaths = lib.mkForce [ + "/media" # this is needed otherwise cp -l is not working + "/var/lib/transmission/.config/transmission-daemon" + ]; + }; + }; + services.openvpn.servers.nordvpn.updateResolvConf = true; + services.openvpn.servers.nordvpn.config = '' + client + dev tun + proto udp + remote 152.89.163.99 1194 + dhcp-option DNS 8.8.8.8 + remote-random + nobind + tun-mtu 1500 + tun-mtu-extra 32 + mssfix 1450 + persist-key + persist-tun + ping 15 + ping-restart 0 + ping-timer-rem + reneg-sec 0 + comp-lzo no + + remote-cert-tls server + + auth-user-pass /run/secrets/nordvpn + + verb 3 + pull + resolv-retry infinite + fast-io + cipher AES-256-CBC + auth SHA512 + + + -----BEGIN CERTIFICATE----- + MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQ + MA4GA1UEChMHTm9yZFZQTjEYMBYGA1UEAxMPTm9yZFZQTiBSb290IENBMB4XDTE2 + MDEwMTAwMDAwMFoXDTM1MTIzMTIzNTk1OVowOTELMAkGA1UEBhMCUEExEDAOBgNV + BAoTB05vcmRWUE4xGDAWBgNVBAMTD05vcmRWUE4gUm9vdCBDQTCCAiIwDQYJKoZI + hvcNAQEBBQADggIPADCCAgoCggIBAMkr/BYhyo0F2upsIMXwC6QvkZps3NN2/eQF + kfQIS1gql0aejsKsEnmY0Kaon8uZCTXPsRH1gQNgg5D2gixdd1mJUvV3dE3y9FJr + XMoDkXdCGBodvKJyU6lcfEVF6/UxHcbBguZK9UtRHS9eJYm3rpL/5huQMCppX7kU + eQ8dpCwd3iKITqwd1ZudDqsWaU0vqzC2H55IyaZ/5/TnCk31Q1UP6BksbbuRcwOV + skEDsm6YoWDnn/IIzGOYnFJRzQH5jTz3j1QBvRIuQuBuvUkfhx1FEwhwZigrcxXu + MP+QgM54kezgziJUaZcOM2zF3lvrwMvXDMfNeIoJABv9ljw969xQ8czQCU5lMVmA + 37ltv5Ec9U5hZuwk/9QO1Z+d/r6Jx0mlurS8gnCAKJgwa3kyZw6e4FZ8mYL4vpRR + hPdvRTWCMJkeB4yBHyhxUmTRgJHm6YR3D6hcFAc9cQcTEl/I60tMdz33G6m0O42s + Qt/+AR3YCY/RusWVBJB/qNS94EtNtj8iaebCQW1jHAhvGmFILVR9lzD0EzWKHkvy + WEjmUVRgCDd6Ne3eFRNS73gdv/C3l5boYySeu4exkEYVxVRn8DhCxs0MnkMHWFK6 + MyzXCCn+JnWFDYPfDKHvpff/kLDobtPBf+Lbch5wQy9quY27xaj0XwLyjOltpiST + LWae/Q4vAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqG + SIb3DQEBDQUAA4ICAQC9fUL2sZPxIN2mD32VeNySTgZlCEdVmlq471o/bDMP4B8g + nQesFRtXY2ZCjs50Jm73B2LViL9qlREmI6vE5IC8IsRBJSV4ce1WYxyXro5rmVg/ + k6a10rlsbK/eg//GHoJxDdXDOokLUSnxt7gk3QKpX6eCdh67p0PuWm/7WUJQxH2S + DxsT9vB/iZriTIEe/ILoOQF0Aqp7AgNCcLcLAmbxXQkXYCCSB35Vp06u+eTWjG0/ + pyS5V14stGtw+fA0DJp5ZJV4eqJ5LqxMlYvEZ/qKTEdoCeaXv2QEmN6dVqjDoTAo + k0t5u4YRXzEVCfXAC3ocplNdtCA72wjFJcSbfif4BSC8bDACTXtnPC7nD0VndZLp + +RiNLeiENhk0oTC+UVdSc+n2nJOzkCK0vYu0Ads4JGIB7g8IB3z2t9ICmsWrgnhd + NdcOe15BincrGA8avQ1cWXsfIKEjbrnEuEk9b5jel6NfHtPKoHc9mDpRdNPISeVa + wDBM1mJChneHt59Nh8Gah74+TM1jBsw4fhJPvoc7Atcg740JErb904mZfkIEmojC + VPhBHVQ9LHBAdM8qFI2kRK0IynOmAZhexlP/aT/kpEsEPyaZQlnBn3An1CRz8h0S + PApL8PytggYKeQmRhl499+6jLxcZ2IegLfqq41dzIjwHwTMplg+1pKIOVojpWA== + -----END CERTIFICATE----- + + key-direction 1 + + # + # 2048 bit OpenVPN static key + # + -----BEGIN OpenVPN Static key V1----- + e685bdaf659a25a200e2b9e39e51ff03 + 0fc72cf1ce07232bd8b2be5e6c670143 + f51e937e670eee09d4f2ea5a6e4e6996 + 5db852c275351b86fc4ca892d78ae002 + d6f70d029bd79c4d1c26cf14e9588033 + cf639f8a74809f29f72b9d58f9b8f5fe + fc7938eade40e9fed6cb92184abb2cc1 + 0eb1a296df243b251df0643d53724cdb + 5a92a1d6cb817804c4a9319b57d53be5 + 80815bcfcb2df55018cc83fc43bc7ff8 + 2d51f9b88364776ee9d12fc85cc7ea5b + 9741c4f598c485316db066d52db4540e + 212e1518a9bd4828219e24b20d88f598 + a196c9de96012090e333519ae18d3509 + 9427e7b372d348d352dc4c85e18cd4b9 + 3f8a56ddb2e64eb67adfc9b337157ff4 + -----END OpenVPN Static key V1----- + + ''; + + }; + }; + + # give containers internet access + networking.nat.enable = true; + networking.nat.internalInterfaces = [ "ve-torrent" ]; + networking.nat.externalInterface = hostInterface; + + # open ports for logging + #networking.firewall.interfaces."ve-torrent".allowedTCPPorts = + # [ 5044 12304 12305 ]; + #networking.firewall.interfaces."ve-torrent".allowedUDPPorts = + # [ 5044 12304 12305 ]; + + # host nginx setup + + # curl -H "Host: transmission.robi.private" https://robi.private/ < will work + # curl -H "Host: transmission.robi.private" https://144.76.13.147/ < wont work + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "transmission.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://${containerAddress}:${toString uiPort}"; + }; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/media-transmission2.nix b/nixos/machines/orbi/media-transmission2.nix new file mode 100644 index 0000000..2e51ac2 --- /dev/null +++ b/nixos/machines/orbi/media-transmission2.nix @@ -0,0 +1,136 @@ +{ lib, pkgs, config, ... }: +let + uiPort = 9091; +in +{ + + containers.torrent2 = { + + # mount host folders + bindMounts = { + media = { + hostPath = "/media"; + mountPoint = "/media"; # must be here otherwise transmission can't see the folder + isReadOnly = false; + }; + lib = { + hostPath = "/media/torrent/torrent2_config"; + mountPoint = "/var/lib/transmission/.config"; + isReadOnly = false; + }; + }; + + autoStart = true; + + config = { config, pkgs, lib, ... }: { + + system.stateVersion = "21.05"; + services.journald.extraConfig = "SystemMaxUse=1G"; + + # allow transmission to write in syncthing folders + users.groups.syncthing = { + gid = config.ids.gids.syncthing; + members = [ "transmission" ]; + }; + + services.transmission = { + enable = true; + settings = { + download-dir = "/media/torrent/downloads"; + incomplete-dir = "/media/torrent/incomplete"; + incomplete-dir-enabled = true; + message-level = 1; + umask = 2; + rpc-whitelist-enabled = false; + rpc-host-whitelist-enabled = false; + rpc-port = uiPort; + rpc-enable = true; + rpc-bind-address = "127.0.0.1"; + + # "normal" speed limits + speed-limit-down-enabled = false; + speed-limit-down = 800; + speed-limit-up-enabled = true; + speed-limit-up = 3000; + upload-slots-per-torrent = 8; + # Queuing + # When true, Transmission will only download + # download-queue-size non-stalled torrents at once. + download-queue-enabled = true; + download-queue-size = 3; + + # When true, torrents that have not shared data for + # queue-stalled-minutes are treated as 'stalled' + # and are not counted against the queue-download-size + # and seed-queue-size limits. + queue-stalled-enabled = true; + queue-stalled-minutes = 60; + + # When true. Transmission will only seed seed-queue-size + # non-stalled torrents at once. + seed-queue-enabled = false; + seed-queue-size = 10; + + # Enable UPnP or NAT-PMP. + peer-port = 51413; + port-forwarding-enabled = false; + + # Start torrents as soon as they are added + start-added-torrents = true; + + # Encryption preference. + # 0 = Prefer unencrypted connections, + # 1 = Prefer encrypted connections, + # 2 = Require encrypted connections; + # default = 1 + # Encryption may help get around some ISP filtering, but at the cost of slightly + # higher CPU use + encryption = 2; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 51413 ]; + allowedUDPPorts = [ 51413 ]; + }; + + # bind transmission to openvpn + systemd.services.transmission = { + serviceConfig = { + Restart = "always"; + BindPaths = lib.mkForce [ + "/media" # this is needed otherwise cp -l is not working + "/var/lib/transmission/.config/transmission-daemon" + ]; + }; + }; + }; + }; + + networking.firewall = { + allowedTCPPorts = [ 51413 ]; + allowedUDPPorts = [ 51413 ]; + }; + + # host nginx setup + # ---------------- + + # curl -H "Host: transmission.robi.private" https://robi.private/ < will work + # curl -H "Host: transmission.robi.private" https://144.76.13.147/ < wont work + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "transmission2.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString uiPort}"; + }; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/media-unmanic.nix b/nixos/machines/orbi/media-unmanic.nix new file mode 100644 index 0000000..1d85089 --- /dev/null +++ b/nixos/machines/orbi/media-unmanic.nix @@ -0,0 +1,40 @@ +{ config, lib, pkgs, ... }: +{ + + virtualisation.oci-containers = { + containers.unmanic = { + volumes = [ + "/media/arr/unmanic/config:/config" + #"/media/arr/unmanic/library:/library" + "/media/arr/unmanic/tmp:/tmp/unmanic" + "/media:/library" + ]; + environment = { + PUID = toString config.users.users.media.uid; + PGID = toString config.users.groups.media.gid; + }; + ports = [ + "127.0.0.1:8889:8888" + ]; + image = "josh5/unmanic:latest"; + }; + }; + + #networking.firewall.interfaces.wq0.allowedTCPPorts = [ 8266 ]; + #networking.firewall.interfaces.wq0.allowedUDPPorts = [ 8266 ]; + + #networking.firewall.interfaces.enp0s31f6.allowedTCPPorts = [ 8266 ]; + #networking.firewall.interfaces.enp0s31f6.allowedUDPPorts = [ 8266 ]; + + services.nginx.virtualHosts."unmanic.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://localhost:8889"; + proxyWebsockets = true; + }; + }; + +} diff --git a/nixos/machines/orbi/mysql.nix b/nixos/machines/orbi/mysql.nix new file mode 100644 index 0000000..727df98 --- /dev/null +++ b/nixos/machines/orbi/mysql.nix @@ -0,0 +1,20 @@ +{ pkgs, lib, config, ... }: { + + services.mysql = { + enable = true; + package = pkgs.mysql80; + initialScript = pkgs.writeText "initScript" '' + CREATE USER 'admin'@'%' IDENTIFIED BY 'admin'; + GRANT ALL PRIVILEGES ON * . * TO 'admin'@'%'; + ''; + }; + + services.mysqlBackup = { + enable = true; + databases = [ "property" ]; + #user = "admin"; + }; + + backup.dirs = [ config.services.mysqlBackup.location ]; + +} diff --git a/nixos/machines/orbi/network-tinc.nix b/nixos/machines/orbi/network-tinc.nix new file mode 100644 index 0000000..0bf4df2 --- /dev/null +++ b/nixos/machines/orbi/network-tinc.nix @@ -0,0 +1,15 @@ +{ + + + networking.firewall = { + allowedTCPPorts = [ 655 721 ]; + allowedUDPPorts = [ 655 721 ]; + }; + + tinc.private.enable = true; + tinc.private.ipv4 = "10.23.42.111"; + + tinc.secret.enable = true; + tinc.secret.ipv4 = "10.123.42.123"; + +} diff --git a/nixos/machines/orbi/network-wireguard.nix b/nixos/machines/orbi/network-wireguard.nix new file mode 100644 index 0000000..4ee5cf4 --- /dev/null +++ b/nixos/machines/orbi/network-wireguard.nix @@ -0,0 +1,55 @@ +{ pkgs, config, ... }: +{ + # networking.firewall.trustedInterfaces = [ "wg0" ]; + networking.firewall.allowedUDPPorts = [ 51820 ]; + sops.secrets.wireguard_private = { }; + boot.kernel.sysctl."net.ipv4.ip_forward" = true; + + # Enable WireGuard + networking.wg-quick.interfaces = { + # Hub and Spoke Setup + # https://www.procustodibus.com/blog/2020/11/wireguard-hub-and-spoke-config/ + wg0 = { + address = [ "10.100.0.1/32" ]; + listenPort = 51820; # to match firewall allowedUDPPorts (without this wg uses random port numbers) + privateKeyFile = config.sops.secrets.wireguard_private.path; + mtu = 1280; + + postUp = '' + ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT + ''; + postDown = '' + ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT + ''; + + # clients + peers = [ + { + # chungus + publicKey = "wb54y/fG8ocSH9QrDmfajez/fUcJBZK369xLu37XBHk="; + allowedIPs = [ "10.100.0.2/32" ]; + } + { + # sterni + publicKey = "SdMRgC5IM7dywzZxLAHm45cpj9J3IENTMClZm1BxbV4="; + allowedIPs = [ "10.100.0.3/32" ]; + } + { + # iphone + publicKey = "XPVzH+wBLsqukTHHjngkGJhYN0nRdQ7esadiimMJQnI="; + allowedIPs = [ "10.100.0.4/32" ]; + } + { + # tina + publicKey = "RZsuQfWfAQLMm45ZiuNLBwcpL+GEbPYTRTrASFzMCFQ="; + allowedIPs = [ "10.100.0.5/32" ]; + } + { + # cream + publicKey = "R1Vk1DDG/LsVU0HHRDmOJshXOVnNzPVbuv5hP7ZSGEQ="; + allowedIPs = [ "10.100.0.6/32" ]; + } + ]; + }; + }; +} diff --git a/nixos/machines/orbi/nextcloud.nix b/nixos/machines/orbi/nextcloud.nix new file mode 100644 index 0000000..455f00c --- /dev/null +++ b/nixos/machines/orbi/nextcloud.nix @@ -0,0 +1,301 @@ +{ pkgs, config, ... }: + +# don't forget the database backup before upgrading +# ------------------------------------------------- +# https://docs.nextcloud.com/server/stable/admin_manual/maintenance/backup.html +# https://docs.nextcloud.com/server/stable/admin_manual/maintenance/upgrade.html +# +# ! use lvm snapshots to do rollback ! + +let + + hostInterface = "enp3s0"; + hostAddress = "192.168.100.10"; + containerAddress = "192.168.100.11"; + nextcloudUid = 1000; + borg_backup_folder = "/media/syncthing/nextcloud_backup/robi"; + +in +{ + + + # Host Setup + # ========== + + # give containers internet access + networking.nat.enable = true; + networking.nat.internalInterfaces = [ "ve-nextcloud" ]; + networking.nat.externalInterface = hostInterface; + + # don't let networkmanager manger container network + networking.networkmanager.unmanaged = [ "interface-name:ve-*" ]; + + # open ports for logging + #networking.firewall.interfaces."ve-nextcloud".allowedTCPPorts = + # [ 5044 12304 12305 ]; + #networking.firewall.interfaces."ve-nextcloud".allowedUDPPorts = + # [ 5044 12304 12305 ]; + + # host nginx + # ---------- + + networking.firewall.allowedTCPPorts = [ 80 443 ]; + networking.firewall.allowedUDPPorts = [ 80 443 ]; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "nextcloud.ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + locations = { + "/" = { + proxyPass = "http://${containerAddress}"; + extraConfig = '' + sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; + # used for view/edit office file via Office Online Server + client_max_body_size 0; + proxy_buffering off; # to download files bigger than 1GB + ''; + }; + "= /.well-known/carddav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + "= /.well-known/caldav" = { + priority = 210; + extraConfig = "return 301 $scheme://$host/remote.php/dav;"; + }; + #"~ .(?:css|js|svg|gif)$" = { + # proxyPass = "http://${containerAddress}$request_uri"; + # extraConfig = '' + # expires 6M; # Cache-Control policy borrowed from `.htaccess` + # access_log off; # Optional: Don't log access to assets + # sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; + # sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de"; + # # used for view/edit office file via Office Online Server + # client_max_body_size 0; + # ''; + #}; + #"~ .woff2?$" = { + # proxyPass = "http://${containerAddress}$request_uri"; + # extraConfig = '' + # expires 7d; # Cache-Control policy borrowed from `.htaccess` + # access_log off; # Optional: Don't log access to assets + # sub_filter "http://nextcloud.ingolf-wagner.de" "https://nextcloud.ingolf-wagner.de"; + # sub_filter "nextcloud.workhorse.private" "nextcloud.ingolf-wagner.de"; + # # used for view/edit office file via Office Online Server + # client_max_body_size 0; + # ''; + #}; + }; + }; + }; + }; + + sops.secrets.nextcloud_database_password.owner = "nextcloud"; + sops.secrets.nextcloud_root_password.owner = "nextcloud"; + + users.users.nextcloud = { + isSystemUser = true; + uid = nextcloudUid; + group = "nextcloud"; + }; + users.groups.nextcloud = { }; + + + # Container Setup + # =============== + # + # running: + # * nextcloud (php) + # * mysql + containers.nextcloud = { + + # mount host folders + bindMounts = { + rootpassword = { + hostPath = "/run/secrets/nextcloud_root_password"; + mountPoint = "/run/secrets/nextcloud_root_password"; + isReadOnly = true; + }; + databasepassword = { + hostPath = "/run/secrets/nextcloud_database_password"; + mountPoint = "/run/secrets/nextcloud_database_password"; + isReadOnly = true; + }; + + home = { + # make sure this folder exist on the host + hostPath = toString "/var/lib/nextcloud"; + mountPoint = "/var/lib/nextcloud"; + isReadOnly = false; + }; + db = { + # make sure this folder exist on the host + hostPath = toString "/var/lib/nextcloud_mysql"; + mountPoint = "/var/lib/mysql"; + isReadOnly = false; + }; + media = { + #mountPoint = toString config.services.syncthing.folders.media.path; + #hostPath = toString config.services.syncthing.folders.media.path; + mountPoint = "/media/syncthing/media"; + hostPath = "/media/media"; + isReadOnly = true; + }; + }; + + # container network setup + # see also nating on host system. + privateNetwork = true; + hostAddress = hostAddress; + localAddress = containerAddress; + + + autoStart = true; + + config = { config, pkgs, lib, ... }: { + + # Configuring nameservers for containers is currently broken. + # Therefore in some cases internet connectivity can be broken inside the containers. + # A temporary workaround is to manually write the /etc/nixos/resolv.conf file like this: + environment.etc."resolv.conf".text = "nameserver 8.8.8.8"; + + system.stateVersion = "21.05"; + + users.users.nextcloud.uid = nextcloudUid; + + services.nginx = { + # Use recommended settings + recommendedGzipSettings = lib.mkDefault true; + recommendedOptimisation = lib.mkDefault true; + recommendedProxySettings = lib.mkDefault true; + recommendedTlsSettings = lib.mkDefault true; + }; + + networking.firewall.allowedTCPPorts = [ 80 ]; + networking.firewall.allowedUDPPorts = [ 80 ]; + + # nextcloud database + # ================== + # + # set user password: + # ----------------- + # #> mysql + # mysql> ALTER USER 'nextcloud'@'localhost' IDENTIFIED BY 'nextcloud-password'; + # + # recreate database: + # ------------------ + # mysql> DROP DATABASE nextcloud; + # mysql> CREATE DATABASE nextcloud; + # + # migration: + # ---------- + # nextcloud-occ db:convert-type --all-apps mysql nextcloud 127.0.0.1 nextcloud + # + # 4-byte stuff: + # ------------- + # https://docs.nextcloud.com/server/18/admin_manual/configuration_database/mysql_4byte_support.html + # if you do this don't forget --default-character-set=utf8mb4 for mysqldump + services.mysql = { + enable = true; + package = pkgs.mysql; + # https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-20.09-incompatibilities + ensureDatabases = [ "nextcloud" ]; + ensureUsers = [{ + name = "nextcloud"; + ensurePermissions = { "nextcloud.*" = "ALL PRIVILEGES"; }; + }]; + settings.mysqld = { + innodb_large_prefix = true; + innodb_file_format = "barracuda"; + innodb_file_per_table = 1; + innodb_read_only_compressed = 0; + }; + }; + + # Backup database + # --------------- + services.mysqlBackup = { + enable = true; + databases = config.services.mysql.ensureDatabases; + singleTransaction = true; + location = "/var/lib/nextcloud/database_backups"; + }; + systemd.services."mysql-backup".serviceConfig = { + ExecStartPre = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --on" ]; + ExecStopPost = [ "+/run/current-system/sw/bin/nextcloud-occ maintenance:mode --off" ]; + }; + + # in php + services.phpfpm = { + phpPackage = pkgs.php73; + phpOptions = '' + opcache.revalidate_freq = 10 + ''; + }; + + # nextcloud setup + services.nextcloud = { + enable = true; + package = pkgs.nextcloud27; + autoUpdateApps.enable = true; + # nginx.enable = true; + # enableBrokenCiphersForSSE = false; # see https://github.com/NixOS/nixpkgs/pull/198470 + hostName = "nextcloud.ingolf-wagner.de"; + logLevel = 2; + https = true; + config = { + adminpassFile = "/run/secrets/nextcloud_root_password"; + overwriteProtocol = "https"; + trustedProxies = [ "144.76.13.147" hostAddress ]; + dbtype = "mysql"; + dbpassFile = "/run/secrets/nextcloud_database_password"; + dbport = 3306; + defaultPhoneRegion = "DE"; + }; + }; + }; + }; + + + # Backup Config + # ------------- + #backup.dirs = [ + # "/home/nextcloud/config" + # "/home/nextcloud/database_backups" # created by mysqlBackup + #]; + + # Backup Files + # ------------ + services.borgbackup.jobs = { + "nextcloud-to-media" = { + repo = borg_backup_folder; + # make sure syncthing is capable of reading the files + postHook = '' + chown -R syncthing:syncthing ${borg_backup_folder} + ''; + compression = "lz4"; + paths = [ + "/var/lib/nextcloud/data/tina/files" + "/var/lib/nextcloud/data/palo/files" + "/var/lib/nextcloud/data/palo-windows/files" + ]; + doInit = true; + encryption = { + mode = "repokey-blake2"; + passCommand = "cat ${config.sops.secrets.backup_repository_passphrase.path}"; + }; + startAt = "0/3:00:00"; + prune.keep = { + within = "2d"; # Keep all backups in the last 10 days. + daily = 10; # Keep 10 additional end of day archives + weekly = 8; # Keep 8 additional end of week archives. + month = 8; # Keep 8 additional end of month archives. + }; + }; + }; + +} diff --git a/nixos/machines/orbi/nginx-wkd.nix b/nixos/machines/orbi/nginx-wkd.nix new file mode 100644 index 0000000..78bd195 --- /dev/null +++ b/nixos/machines/orbi/nginx-wkd.nix @@ -0,0 +1,30 @@ +{ config, pkgs, lib, assets, ... }: +let + server_name = "ingolf-wagner.de"; +in +{ + # check : + # - https://metacode.biz/openpgp/web-key-directory + # - $> gpg --homedir "$(mktemp -d)" -v --auto-key-locate clear,wkd,nodefault --locate-key contact@ingolf-wagner.de + services.nginx.virtualHosts.${server_name}.locations = + let + wkd = + { + extraConfig = '' + default_type application/octet-stream; + add_header Access-Control-Allow-Origin * always; + ''; + #alias = pkgs.runCommand "contact@ingolf-wagner.de" { } '' + # cat ${assets}/contact@ingolf-wagner.de.gpg | ${pkgs.gnupg}/bin/gpg --dearmor > $out + #''; + alias = toString "${assets}/contact@ingolf-wagner.de.gpg"; + }; + in + { + "= /.well-known/openpgpkey/policy".return = "200"; + # hashes generated by : gpg --with-wkd-hash --fingerprint contact@ingolf-wagner.de + "= /.well-known/openpgpkey/hu/dj3498u4hyyarh35rkjfnghbjxug6b19" = wkd; + }; + + # todo openpgpkey.ingolf-wagner.de noch einrichten +} diff --git a/nixos/machines/orbi/nginx.nix b/nixos/machines/orbi/nginx.nix new file mode 100644 index 0000000..b05b49d --- /dev/null +++ b/nixos/machines/orbi/nginx.nix @@ -0,0 +1,158 @@ +{ config, lib, pkgs, private_assets, ... }: +let + # todo create flake for this + errorPages = pkgs.fetchFromGitHub { + owner = "mrvandalo"; + repo = "http-errors"; + rev = "74b8e4c1d9bbba3db6ad858b888e1867318af1f0"; + sha256 = "0czdzafx4k76q773lyf3vsjm74g1995iz542dhw15kpy5xbivsrg"; + }; + error = { + extraConfig = '' + error_page 400 /errors/400.html; + error_page 401 /errors/401.html; + error_page 402 /errors/402.html; + error_page 403 /errors/403.html; + error_page 404 /errors/404.html; + error_page 405 /errors/405.html; + error_page 406 /errors/406.html; + error_page 500 /errors/500.html; + error_page 501 /errors/501.html; + error_page 502 /errors/502.html; + error_page 503 /errors/503.html; + error_page 504 /errors/504.html; + ''; + locations."^~ /errors/" = { + extraConfig = "internal;"; + root = "${errorPages}/"; + }; + }; +in + +{ + networking.firewall.allowedTCPPorts = [ 80 443 ]; + networking.firewall.allowedUDPPorts = [ 80 443 ]; + + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + + "ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + extraConfig = error.extraConfig; + locations = { + "/" = { + root = pkgs.landingpage.override { + jsonConfig = [ + { + title = "Ingolf Wagner"; + text = '' + I'm a freelancing mathematician, musician and programmer. + + My PGP fingerprint is 42AC 51C9 482D 0834 CF48 8AF1 389E C2D6 4AC7 1EAC + ''; + } + { + text = '' + Here are some of my projects you might enjoy: + ''; + items = [ + { + label = "terranix"; + href = "https://terranix.org"; + image = "https://raw.githubusercontent.com/terranix/terranix-artwork/main/terranix-logo.svg"; + } + { + label = "Sononym"; + href = "https://www.sononym.net/"; + image = "https://www.sononym.net/press/logos/sononym-logo-symbol-black.png"; + } + { + label = "LandingPage"; + href = "https://github.com/mrVanDalo/landingpage"; + image = "https://media.giphy.com/media/2vNGq1w3nsJri/giphy.gif"; + } + { + label = "My Blog"; + href = "https://tech.ingolf-wagner.de/"; + image = "https://media.giphy.com/media/11I8v5lE8uq79C/giphy.gif"; + } + ]; + } + ]; + title = "Ingolf Wagner"; + max-width = "1010px"; + background-color = "#FEFAE0"; + title-color = "black"; + title-background-color = "#E9EDC9"; + text-color = "black"; + text-background-color = "#FAEDCD"; + item-color = "black"; + item-background-color = "#E9EDC9"; + image-width = "250px"; + image-height = "200px"; + }; + }; + "= /palo.pgp" = { + root = pkgs.writeText "key" (lib.fileContents ../../assets/pgp.key); + }; + "= /palo.gpg" = { + root = pkgs.writeText "key" (lib.fileContents ../../assets/pgp.key); + }; + "= /palo_rsa.pub" = { + root = pkgs.writeText "key" (lib.fileContents ../../assets/ssh/palo_rsa.pub); + }; + }; + }; + + "travel.ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + extraConfig = error.extraConfig; + locations = { + "/" = { + root = "/srv/www/travel"; + extraConfig = '' + if (-d $request_filename) { + rewrite [^/]$ $scheme://$http_host$request_uri/ permanent; + } + ''; + }; + } // error.locations; + }; + "tech.ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + extraConfig = error.extraConfig; + locations = { + "/" = { + root = "/srv/www/tech"; + extraConfig = '' + if (-d $request_filename) { + rewrite [^/]$ $scheme://$http_host$request_uri/ permanent; + } + ''; + }; + } // error.locations; + }; + "terranix.org" = { + forceSSL = true; + enableACME = true; + extraConfig = error.extraConfig; + locations = { + "/" = { + root = "/srv/www/terranix"; + extraConfig = '' + if (-d $request_filename) { + rewrite [^/]$ $scheme://$http_host$request_uri/ permanent; + } + ''; + }; + } // error.locations; + }; + }; + }; +} diff --git a/nixos/machines/orbi/packages.nix b/nixos/machines/orbi/packages.nix new file mode 100644 index 0000000..fb47b8c --- /dev/null +++ b/nixos/machines/orbi/packages.nix @@ -0,0 +1,14 @@ +{ config, pkgs, ... }: { + environment.systemPackages = with pkgs; [ + mosh + mediainfo + youtube-dl + ipset # for sshguard + + unstable.vulnix + (pkgs.writers.writeBashBin "vulnix-system" '' + ${pkgs.unstable.vulnix}/bin/vulnix --profile /nix/var/nix/profiles/system + '') + + ]; +} diff --git a/nixos/machines/orbi/prometheus.nix b/nixos/machines/orbi/prometheus.nix new file mode 100644 index 0000000..2fa4218 --- /dev/null +++ b/nixos/machines/orbi/prometheus.nix @@ -0,0 +1,70 @@ +{ config, pkgs, lib, ... }: { + + services.nginx = { + enable = true; + statusPage = true; + virtualHosts = { + "prometheus.robi.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { proxyPass = "http://localhost:${toString config.services.prometheus.port}"; }; + }; + }; + }; + + services.prometheus = { + enable = true; + # keep data for 30 days + extraFlags = [ "--storage.tsdb.retention.time=30d" ]; + + exporters = { + node = { + enable = true; + enabledCollectors = [ "systemd" ]; + port = 9002; + }; + }; + + scrapeConfigs = [ + { + job_name = "netdata"; + metrics_path = "/api/v1/allmetrics"; + params.format = [ "prometheus" ]; + scrape_interval = "5s"; + static_configs = [ + { + targets = [ "localhost:19999" ]; + labels = { + service = "netdata"; + server = "robi"; + }; + } + ]; + } + { + job_name = "systemd"; + static_configs = [{ + targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; + labels = { + service = "node-exporter"; + server = "robi"; + }; + }]; + } + { + # see https://www.home-assistant.io/integrations/prometheus/ + job_name = "telgraf"; + metrics_path = "/metrics"; + static_configs = [{ + targets = [ "localhost:9273" ]; + labels = { + service = "telegraf"; + server = "robi"; + }; + }]; + } + ]; + }; +} diff --git a/nixos/machines/orbi/property.nix b/nixos/machines/orbi/property.nix new file mode 100644 index 0000000..169f2c2 --- /dev/null +++ b/nixos/machines/orbi/property.nix @@ -0,0 +1,43 @@ +{ lib, pkgs, config, ... }: { + + users.users.property = { isSystemUser = true; }; + + systemd.services.property = { + enable = true; + wantedBy = [ "multi-user.target" ]; + path = [ + (pkgs.python3.withPackages (ps: + with ps; [ + flask + selenium + beautifulsoup4 + urllib3 + sqlalchemy + mysqlclient + pytest + dateparser + geopy + nltk + click + ])) + ]; + + serviceConfig = { User = "property"; }; + script = '' + FLASK_APP=${}/server.py \ + FLASK_RUN_PORT=7888 \ + flask run --host 0.0.0.0 \ + "$@" + ''; + }; + + services.nginx = { + enable = true; + virtualHosts = { + "property.workhorse.private" = { + locations."/" = { proxyPass = "http://localhost:7888"; }; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/screeps.nix b/nixos/machines/orbi/screeps.nix new file mode 100644 index 0000000..d597ae4 --- /dev/null +++ b/nixos/machines/orbi/screeps.nix @@ -0,0 +1,73 @@ +{ config, lib, pkgs, ... }: +with lib; +let + debug = true; + #version = "latest"; + # version = "142c079"; # 2 years ago. + # version = "v1.14.0"; # 2 years ago. + version = "v1.13.2"; # 2 years ago. +in +{ + virtualisation.oci-containers = { + containers.screeps = { + volumes = [ + "/srv/screeps:/screeps" + (optionalString debug "/srv/screeps-tmp:/tmp") + ]; + environment.TZ = "Europe/Berlin"; + image = "screepers/screeps-launcher:${version}"; + ports = [ "21025:21025" ]; + }; + }; + + systemd.services.docker-screeps = + let + configuration = builtins.toJSON { + steamKey = "keyFromStep3"; + version = "latest"; + mods = [ + #"screepsmod-auth" + #"screepsmod-admin-utils" + #"screepsmod-mongo" + ]; + bots = { + simplebot = "screepsbot-zeswarm"; + }; + serverConfig = { + welcomeText = "

My Cool Server

"; + constants = { + "TEST_CONSTANT" = 123; + }; + tickRate = 1000; + }; + }; + in + { + + unitConfig = { + StartLimitInterval = 200; + StartLimitBurst = 2; + }; + + serviceConfig = { + Restart = mkForce (if debug then "no" else "always"); + RestartSec = 30; + ExecStartPre = [ + (toString (pkgs.writers.writeDash "create-screeps-config" '' + mkdir -p /srv/screeps/ + chown 1000:1000 -R /srv/screeps + ${optionalString debug "mkdir -p /srv/screeps-tmp"} + ${optionalString debug "chown 1000:1000 -R /srv/screeps-tmp"} + echo '${configuration}' > /srv/screeps/config.yaml + '')) + ]; + }; + }; + + #networking.firewall.allowedTCPPorts = [ 8123 ]; + #networking.firewall.allowedUDPPorts = [ 8123 ]; + + #networking.firewall.interfaces.wg0.allowedTCPPorts = [ 8123 ]; + #networking.firewall.interfaces.wg0.allowedUDPPorts = [ 8123 ]; + +} diff --git a/nixos/machines/orbi/social-jitsi.nix b/nixos/machines/orbi/social-jitsi.nix new file mode 100644 index 0000000..fc308d2 --- /dev/null +++ b/nixos/machines/orbi/social-jitsi.nix @@ -0,0 +1,60 @@ +{ config, ... }: { + # + + + # | | + # | | + # v v + # 80, 443 TCP 443 TCP, 10000 UDP + # +--------------+ +---------------------+ + # | nginx | 5222, 5347 TCP | | + # | jitsi-meet |<-------------------+| jitsi-videobridge | + # | prosody | | | | + # | jicofo | | +---------------------+ + # +--------------+ | + # | +---------------------+ + # | | | + # +----------+| jitsi-videobridge | + # | | | + # | +---------------------+ + # | + # | +---------------------+ + # | | | + # +----------+| jitsi-videobridge | + # | | + # +---------------------+ + + # This is a one server setup + services.jitsi-meet = { + enable = true; + hostName = "meet.ingolf-wagner.de"; + + # JItsi COnference FOcus is a server side focus component used in Jitsi Meet conferences. + # https://github.com/jitsi/jicofo + jicofo.enable = true; + + # Whether to enable nginx virtual host that will serve the javascript application and act as a proxy for the XMPP server. + # Further nginx configuration can be done by adapting services.nginx.virtualHosts.. When this is enabled, ACME + # will be used to retrieve a TLS certificate by default. To disable this, set the + # services.nginx.virtualHosts..enableACME to false and if appropriate do the same for + # services.nginx.virtualHosts..forceSSL. + nginx.enable = true; + + # https://github.com/jitsi/jitsi-meet/blob/master/config.js + config = { + enableWelcomePage = false; + defaultLang = "en"; + }; + + # https://github.com/jitsi/jitsi-meet/blob/master/interface_config.js + interfaceConfig = { + SHOW_JITSI_WATERMARK = false; + SHOW_WATERMARK_FOR_GUESTS = false; + }; + + }; + + networking.firewall = { + allowedTCPPorts = [ 80 443 ]; + allowedUDPPorts = [ 10000 ]; + }; + +} diff --git a/nixos/machines/orbi/sync-opentracker.nix b/nixos/machines/orbi/sync-opentracker.nix new file mode 100644 index 0000000..aaec2bd --- /dev/null +++ b/nixos/machines/orbi/sync-opentracker.nix @@ -0,0 +1,5 @@ +{ + services.opentracker = { + enable = true; + }; +} diff --git a/nixos/machines/orbi/sync-torrent.nix b/nixos/machines/orbi/sync-torrent.nix new file mode 100644 index 0000000..ee40fe4 --- /dev/null +++ b/nixos/machines/orbi/sync-torrent.nix @@ -0,0 +1,111 @@ +{ lib, pkgs, config, ... }: +let + uiPort = 9099; + announceIp = "10.23.42.111"; + peerPort = 51433; +in +{ + + containers.sync-torrent = { + + # mount host folders + bindMounts = { + media = { + hostPath = "/media/new"; + mountPoint = "/media"; # must be here otherwise transmission can't see the folder + isReadOnly = false; + }; + lib = { + hostPath = "/srv/sync-torrent"; + mountPoint = "/var/lib/transmission"; + isReadOnly = false; + }; + }; + + autoStart = true; + + config = { config, pkgs, lib, ... }: { + + system.stateVersion = "22.11"; + services.journald.extraConfig = "SystemMaxUse=1G"; + + services.transmission = { + enable = true; + settings = { + download-dir = "/media"; + incomplete-dir = "/var/lib/transmission/incomplete"; # todo put this somewhere with frequent snapshots but low keep. + incomplete-dir-enabled = true; + message-level = 1; + umask = 2; + rpc-whitelist-enabled = false; + rpc-host-whitelist-enabled = false; + rpc-port = uiPort; + rpc-enable = true; + rpc-bind-address = "0.0.0.0"; + + # "normal" speed limits + speed-limit-down-enabled = false; + speed-limit-down = 800; + speed-limit-up-enabled = true; + speed-limit-up = 3000; + upload-slots-per-torrent = 8; + # Queuing + # When true, Transmission will only download + # download-queue-size non-stalled torrents at once. + download-queue-enabled = true; + download-queue-size = 3; + + # When true, torrents that have not shared data for + # queue-stalled-minutes are treated as 'stalled' + # and are not counted against the queue-download-size + # and seed-queue-size limits. + queue-stalled-enabled = true; + queue-stalled-minutes = 60; + + # When true. Transmission will only seed seed-queue-size + # non-stalled torrents at once. + seed-queue-enabled = false; + seed-queue-size = 10; + + # Enable UPnP or NAT-PMP. + peer-port = peerPort; + port-forwarding-enabled = false; + announce-ip = announceIp; + announce-ip-enabled = true; + + # Start torrents as soon as they are added + start-added-torrents = true; + + }; + }; + + }; + }; + + # open ports for logging + #networking.firewall.interfaces."ve-torrent".allowedTCPPorts = + # [ 5044 12304 12305 ]; + #networking.firewall.interfaces."ve-torrent".allowedUDPPorts = + # [ 5044 12304 12305 ]; + + # host nginx setup + # ---------------- + # curl -H "Host: sync.robi.private" https://robi.private/ < will work + # curl -H "Host: sync.robi.private" https://144.76.13.147/ < wont work + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + "sync.${config.networking.hostName}.private" = { + extraConfig = '' + allow ${config.tinc.private.subnet}; + deny all; + ''; + locations."/" = { + proxyPass = "http://127.0.0.1:${toString uiPort}"; + }; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/taskserver.nix b/nixos/machines/orbi/taskserver.nix new file mode 100644 index 0000000..778a975 --- /dev/null +++ b/nixos/machines/orbi/taskserver.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, ... }: { + + services.taskserver = { + enable = true; + fqdn = "taskd.ingolf-wagner.de"; + listenHost = "0.0.0.0"; + requestLimit = 104857600; + trust = "strict"; + dataDir = "/var/lib/taskserver"; + organisations."1337".users = [ "palo" "beta" ]; + ciphers = "SECURE256"; + }; + + networking.firewall.allowedTCPPorts = [ config.services.taskserver.listenPort ]; + networking.firewall.allowedUDPPorts = [ config.services.taskserver.listenPort ]; + + backup.dirs = [ config.services.taskserver.dataDir ]; + +} diff --git a/nixos/machines/orbi/telegraf.nix b/nixos/machines/orbi/telegraf.nix new file mode 100644 index 0000000..5e7c662 --- /dev/null +++ b/nixos/machines/orbi/telegraf.nix @@ -0,0 +1,28 @@ +{ + services.telegraf = { + enable = true; + extraConfig = { + outputs.prometheus_client = { + listen = ":9273"; + metric_version = 2; + }; + # https://github.com/influxdata/telegraf/tree/master/plugins/inputs < all them plugins + inputs = { + cpu = { + percpu = true; + totalcpu = true; + }; + disk = { }; + diskio = { }; + kernel = { }; + mem = { }; + processes = { }; + netstat = { }; + net = { }; + system = { }; + systemd_units = { }; + nginx.urls = [ "http://localhost/nginx_status" ]; + }; + }; + }; +} diff --git a/nixos/machines/orbi/terranix-dendrite.nix b/nixos/machines/orbi/terranix-dendrite.nix new file mode 100644 index 0000000..118fcb6 --- /dev/null +++ b/nixos/machines/orbi/terranix-dendrite.nix @@ -0,0 +1,109 @@ +{ config, pkgs, ... }: +let + + inherit (config.services.dendrite.settings.global) server_name; + + nginx-vhost = "matrix.terranix.org"; + element-web-terranix.org = + pkgs.runCommand "element-web-with-config" + { + nativeBuildInputs = [ pkgs.buildPackages.jq ]; + } '' + cp -r ${pkgs.element-web} $out + chmod -R u+w $out + jq '."default_server_config"."m.homeserver" = { "base_url": "https://${nginx-vhost}:443", "server_name": "${server_name}" }' \ + > $out/config.json < ${pkgs.element-web}/config.json + ln -s $out/config.json $out/config.${nginx-vhost}.json + ''; +in +{ + + # $ nix-shell -p dendrite --run 'generate-keys --private-key /tmp/key' + sops.secrets.matrix-server-key = { }; + + services.dendrite = { + enable = true; + httpPort = 8043; + settings = { + global = { + server_name = "terranix.org"; + # `private_key` has the type `path` + # prefix a `/` to make `path` happy + private_key = "/$CREDENTIALS_DIRECTORY/matrix-server-key"; + trusted_third_party_id_servers = [ + "matrix.org" + "vector.im" + "xaos.space" + "lassul.us" + "thalheim.io" + "nixos.org" + ]; + metrics.enabled = false; + }; + logging = [ + { + type = "std"; + level = "warn"; + } + ]; + client_api = { + registration_disabled = true; + rate_limiting.enabled = false; + # set only for the first admin account, than remove. + #registration_shared_secret = ""; # disable once first admin account is created + }; + media_api = { + dynamic_thumbnails = true; + }; + mscs = { + mscs = [ "msc2836" "msc2946" ]; + }; + sync_api = { + real_ip_header = "X-Real-IP"; + }; + federation_api = { + key_perspectives = [ + { + server_name = "matrix.org"; + keys = [ + { + key_id = "ed25519:auto"; + public_key = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw"; + } + { + key_id = "ed25519:a_RXGa"; + public_key = "l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ"; + } + ]; + } + ]; + prefer_direct_fetch = false; + }; + }; + }; + + systemd.services.dendrite.serviceConfig.LoadCredential = [ + "matrix-server-key:${config.sops.secrets.matrix-server-key.path}" + ]; + + services.nginx.virtualHosts.${nginx-vhost} = { + forceSSL = true; + enableACME = true; + extraConfig = '' + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 600; + ''; + locations."/_matrix".proxyPass = "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; + # for remote admin access + locations."/_synapse".proxyPass = "http://127.0.0.1:${toString config.services.dendrite.httpPort}"; + locations."/".root = element-web-terranix.org; + }; + + services.nginx.virtualHosts.${server_name} = { + locations."= /.well-known/matrix/server".alias = + pkgs.writeText "matrix-server" (builtins.toJSON { "m.server" = "${nginx-vhost}:443"; }); + locations."= /.well-known/matrix/client".alias = + pkgs.writeText "matrix-client" (builtins.toJSON { "m.homeserver".base_url = "https://${nginx-vhost}"; }); + }; +} diff --git a/nixos/machines/orbi/vaultwarden.nix b/nixos/machines/orbi/vaultwarden.nix new file mode 100644 index 0000000..076242c --- /dev/null +++ b/nixos/machines/orbi/vaultwarden.nix @@ -0,0 +1,32 @@ +{ config, pkgs, lib, ... }: { + services.vaultwarden = { + enable = true; + # backupDir = + config = { + domain = "https://bitwarden.ingolf-wagner.de"; + signupsAllowed = false; + rocketPort = 8222; + rocketLog = "critical"; + }; + }; + + backup.dirs = [ "/var/lib/bitwarden_rs" ]; + + services.nginx = { + enable = true; + recommendedProxySettings = true; + virtualHosts = { + + "bitwarden.ingolf-wagner.de" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://localhost:${ + toString config.services.vaultwarden.config.rocketPort + }"; + }; + }; + }; + }; + +} diff --git a/nixos/machines/orbi/webhook-ring.nix b/nixos/machines/orbi/webhook-ring.nix new file mode 100644 index 0000000..5bf5cd0 --- /dev/null +++ b/nixos/machines/orbi/webhook-ring.nix @@ -0,0 +1,45 @@ +{ config, pkgs, ... }: +# To create a sign at the door +# "Sorry Doorbell is broken, please scan this QR Code +# +# create QR Code with: +# qrencode -o ./test.png http://ring.ingolf-wagner.de +# +# for secure urls check +# https://www.nginx.com/blog/securing-urls-secure-link-module-nginx-plus/ +{ + + sops.secrets.ringPushover = { + owner = config.services.webhook.user; + }; + + services.webhook = { + enable = true; + hooks = { + ring = { + execute-command = + let + script = pkgs.writers.writeBash "ring-script" '' + . ${config.sops.secrets.ringPushover.path} + ${pkgs.curl}/bin/curl -s \ + --form-string "token=$API_KEY" \ + --form-string "user=$USER_KEY" \ + --form-string "title=Klingeling" \ + --form-string "message=Jemand an der Tür" \ + https://api.pushover.net/1/messages.json + ''; + in + toString script; + response-message = "It's ringing"; + }; + }; + }; + + services.nginx.virtualHosts."ring.ingolf-wagner.de" = { + enableACME = true; + forceSSL = true; + locations."/" = { + proxyPass = "http://localhost:${toString config.services.webhook.port}/${config.services.webhook.urlPrefix}/ring"; + }; + }; +} diff --git a/nixos/machines/orbi/weechat.nix b/nixos/machines/orbi/weechat.nix new file mode 100644 index 0000000..f008033 --- /dev/null +++ b/nixos/machines/orbi/weechat.nix @@ -0,0 +1,38 @@ +{ config, pkgs, lib, ... }: + +# how to setup a relay +# * ssh on the maching +# * sudo -u weechat screen -r +# /set relay.network.password "mypassword" +# /relay add weechat 10000 + +{ + + # configure weechat + services.weechat = { enable = true; }; + + # configure bitlbee + services.bitlbee = { + enable = true; + libpurple_plugins = [ + #pkgs.pidgin-otr + #pkgs.purple-facebook + #pkgs.purple-discord + #pkgs.purple-matrix + #pkgs.purple-hangouts + #pkgs.pidgin-latex + #pkgs.pidgin-opensteamworks + #pkgs.pidgin-skypeweb + pkgs.telegram-purple + #pkgs.purple-lurch + ]; + plugins = + [ pkgs.bitlbee-facebook pkgs.bitlbee-steam pkgs.bitlbee-mastodon ]; + }; + + # otherwise xterm is the only thing that works + environment.systemPackages = [ pkgs.rxvt_unicode ]; + + backup.dirs = [ config.services.weechat.root ]; + +} diff --git a/nixos/machines/robi/media-syncthing.nix b/nixos/machines/robi/media-syncthing.nix index d863c2d..ae5629d 100644 --- a/nixos/machines/robi/media-syncthing.nix +++ b/nixos/machines/robi/media-syncthing.nix @@ -18,7 +18,7 @@ cert = toString config.sops.secrets.syncthing_cert.path; key = toString config.sops.secrets.syncthing_key.path; - folders = { + settings.folders = { # on media hard drive (not encrypted) # ----------------------------------- #borg-mirror = { @@ -38,7 +38,7 @@ lost-fotos = { enable = true; path = "/media/syncthing/lost-fotos.ct"; - rescanInterval = 40 * 24 * 3600; + rescanIntervalS = 40 * 24 * 3600; }; #media = { # enable = true; @@ -49,14 +49,14 @@ #}; music-projects = { enable = true; - watch = true; + #watch = true; path = "/media/syncthing/music-projects"; }; nextcloud_backup = { enable = true; - watch = true; + #watch = true; path = "/media/syncthing/nextcloud_backup"; - rescanInterval = 23 * 3600; + rescanIntervalS = 23 * 3600; }; }; }; diff --git a/nixos/machines/robi/nextcloud.nix b/nixos/machines/robi/nextcloud.nix index f2bd0b3..455f00c 100644 --- a/nixos/machines/robi/nextcloud.nix +++ b/nixos/machines/robi/nextcloud.nix @@ -242,8 +242,8 @@ in enable = true; package = pkgs.nextcloud27; autoUpdateApps.enable = true; - #nginx.enable = true; - enableBrokenCiphersForSSE = false; # see https://github.com/NixOS/nixpkgs/pull/198470 + # nginx.enable = true; + # enableBrokenCiphersForSSE = false; # see https://github.com/NixOS/nixpkgs/pull/198470 hostName = "nextcloud.ingolf-wagner.de"; logLevel = 2; https = true;