From 9d34f3321f292477e792b57872c2c81837b1af41 Mon Sep 17 00:00:00 2001 From: Ingolf Wagner Date: Wed, 29 Dec 2021 19:46:20 +0100 Subject: [PATCH] transmission works but is not nice --- flake.lock | 2 +- nixos/configs/robi/configuration.nix | 14 +- nixos/configs/robi/nextcloud.nix | 95 ++++++++----- nixos/configs/robi/syncthing.nix | 2 +- nixos/configs/robi/taskserver.nix | 5 +- nixos/configs/robi/transmission.nix | 205 ++++++++++++++++++--------- 6 files changed, 211 insertions(+), 112 deletions(-) diff --git a/flake.lock b/flake.lock index 30d960b..739a495 100644 --- a/flake.lock +++ b/flake.lock @@ -62,7 +62,7 @@ "secrets": { "flake": false, "locked": { - "narHash": "sha256-nl0nvXupyQ5mIdc9pVd0quWZwDJNcudUcbusp8Im+cM=", + "narHash": "sha256-OlWM45xthVFn2NnXrIYRslLFt1m+q2ytMuasN8zXfNs=", "path": "/home/palo/dev/secrets", "type": "path" }, diff --git a/nixos/configs/robi/configuration.nix b/nixos/configs/robi/configuration.nix index 67da02d..2406ebe 100644 --- a/nixos/configs/robi/configuration.nix +++ b/nixos/configs/robi/configuration.nix @@ -6,17 +6,19 @@ ./hetzner.nix - #./nextcloud.nix + # todo + ./nextcloud.nix ./packages.nix ./tinc.nix ./syncthing.nix + ./taskserver.nix + ./transmission.nix #../../system/server #./hardware-configuration.nix #./mail-fetcher.nix - #./transmission.nix #./borg.nix #./finance.nix #./gogs.nix @@ -26,12 +28,18 @@ #./kibana.nix #./mysql.nix #./prometheus.nix - #./taskserver.nix #./weechat.nix #./property.nix # flask sucks, find something else ]; + # Shell configuration + # ------------------- + programs.custom = { + bash.enable = true; + zsh.enable = true; + }; + security.acme = { acceptTerms = true; email = "contact@ingolf-wagner.de"; diff --git a/nixos/configs/robi/nextcloud.nix b/nixos/configs/robi/nextcloud.nix index 438d87c..37c27ce 100644 --- a/nixos/configs/robi/nextcloud.nix +++ b/nixos/configs/robi/nextcloud.nix @@ -1,10 +1,16 @@ { pkgs, config, lib, ... }: +let + nextcloudUid = 1000; +in { + users.users.nextcloud = { + isSystemUser = true; + uid = nextcloudUid; + }; - networking.firewall.allowedTCPPorts = [ 80 443 ]; - networking.firewall.allowedUDPPorts = [ 80 443 ]; - + #networking.firewall.allowedTCPPorts = [ 80 443 ]; + #networking.firewall.allowedUDPPorts = [ 80 443 ]; # host nginx setup services.nginx = { @@ -13,17 +19,16 @@ recommendedOptimisation = lib.mkDefault true; recommendedTlsSettings = lib.mkDefault true; recommendedProxySettings = true; - sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; + #sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; - virtualHosts = { - "nextcloud.ingolf-wagner.de" = { - forceSSL = true; - enableACME = true; - }; - }; + #virtualHosts = { + # "nextcloud.ingolf-wagner.de" = { + # forceSSL = true; + # enableACME = true; + # }; + #}; }; - # nextcloud database # ================== # @@ -45,44 +50,56 @@ # ------------- # 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"; }; + containers.nextcloudmysql = { + autoStart = true; + forwardPorts = [{ + containerPort = 3336; + hostPort = 3336; + protocol = "tcp"; }]; - settings.mysqld = { - innodb_large_prefix = true; - innodb_file_format = "barracuda"; - innodb_file_per_table = 1; + + config = { config, pkgs, lib, ... }: { + 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; + }; + }; + + # 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" ]; + #}; + }; }; - # 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; # nextcloud setup services.nextcloud = { - enable = true; + enable = false; hostName = "nextcloud.ingolf-wagner.de"; package = pkgs.nextcloud22; autoUpdateApps.enable = true; diff --git a/nixos/configs/robi/syncthing.nix b/nixos/configs/robi/syncthing.nix index 370a48d..599eac5 100644 --- a/nixos/configs/robi/syncthing.nix +++ b/nixos/configs/robi/syncthing.nix @@ -109,7 +109,7 @@ system.permown."/media/syncthing" = { owner = "syncthing"; group = "syncthing"; - umask = "0022"; + umask = "0002"; }; systemd.services."permown._media_syncthing" = { bindsTo = [ "media.mount" ]; diff --git a/nixos/configs/robi/taskserver.nix b/nixos/configs/robi/taskserver.nix index c3c6e99..a79fc55 100644 --- a/nixos/configs/robi/taskserver.nix +++ b/nixos/configs/robi/taskserver.nix @@ -11,6 +11,9 @@ ciphers = "SECURE256"; }; - backup.dirs = [ config.services.taskserver.dataDir ]; + networking.firewall.allowedTCPPorts = [ config.services.taskserver.listenPort ]; + networking.firewall.allowedUDPPorts = [ config.services.taskserver.listenPort ]; + + #backup.dirs = [ config.services.taskserver.dataDir ]; } diff --git a/nixos/configs/robi/transmission.nix b/nixos/configs/robi/transmission.nix index 83031de..5fa9e3f 100644 --- a/nixos/configs/robi/transmission.nix +++ b/nixos/configs/robi/transmission.nix @@ -1,9 +1,75 @@ -{ pkgs, config, ... }: +{ lib, pkgs, config, ... }: +# +# cp -avl (to create hardlinks instead of copy) +# ============================================= +# +#┌──────────────────────────────────┐ ┌──────────────────────────────────────┐ +#│/media/torrent/downloads/music ├─────►│/media/syncthing/music/incomming │ +#└──────────────────────────────────┘ └──────────────────────────────────────┘ +#┌──────────────────────────────────┐ ┌──────────────────────────────────────┐ +#│/media/torrent/downloads/movies ├─────►│/media/syncthing/movies/incoming │ +#└──────────────────────────────────┘ └──────────────────────────────────────┘ +#┌──────────────────────────────────┐ ┌──────────────────────────────────────┐ +#│/media/torrent/downloads ├─────►│/media/torrent/incoming │ +#└──────────────────────────────────┘ └──────────────────────────────────────┘ + let + hostInterface = "enp3s0"; hostAddress = "192.168.100.30"; containerAddress = "192.168.100.31"; + uiPort = 9091; + + ############################################# + # These are inherited from Transmission. # + # Do not declare these. Just use as needed. # + # # + # TR_APP_VERSION # + # TR_TIME_LOCALTIME # + # TR_TORRENT_DIR # + # TR_TORRENT_HASH # + # TR_TORRENT_ID # + # TR_TORRENT_NAME # + # # + ############################################# + completionScript = let + copy_map = { + "/media/torrent/downloads/movies" = "/media/syncthing/movies/incoming"; + "/media/torrent/downloads" = "/media/torrent/incoming"; + }; + copy_script = lib.concatStringsSep "\n" (lib.mapAttrsToList (source: target: '' + if [[ "$TR_TORRENT_DIR" == "${source}" ]] + then + cp -val "$TR_TORRENT_DIR/$TR_TORRENT_NAME" "${target}/$TR_TORRENT_NAME" + fi + '') copy_map); + in + pkgs.writers.writeBash "torrent-finished" '' + + ${copy_script} + + ${pkgs.jq}/bin/jq '{ + "token": "'"$PUSHOVER_API_KEY"'", + "user": "'"$PUSHOVER_USER_KEY"'", + "titel": "transmission", + "message": "'"$TR_TORRENT_NAME finished"'" + }' >> /media/torrent/finish.log + + ${pkgs.jq}/bin/jq '{ + "token": "'"$PUSHOVER_API_KEY"'", + "user": "'"$PUSHOVER_USER_KEY"'", + "titel": "transmission", + "message": "'"$TR_TORRENT_NAME finished"'" + }' \ + | ${pkgs.curl}/bin/curl \ + -sS \ + -X POST \ + -H 'Content-Type: application/json' \ + -d @- \ + https://api.pushover.net/1/messages.json + ''; + in { @@ -13,6 +79,7 @@ in #}; sops.secrets.nordvpn = { }; + sops.secrets.transmissionPushover= { }; containers.torrent = { @@ -23,24 +90,23 @@ in # 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; }; - home = { - hostPath = "/home/torrent"; - mountPoint = "/home/torrent"; - isReadOnly = false; - }; media = { hostPath = "/media"; - mountPoint = - "/home/torrent/downloads/media"; # must be here otherwise transmission can't see the folder + mountPoint = "/media"; # must be here otherwise transmission can't see the folder isReadOnly = false; }; lib = { - hostPath = "/home/torrent/.config"; + hostPath = "/media/torrent/.config"; mountPoint = "/var/lib/transmission/.config"; isReadOnly = false; }; @@ -52,57 +118,61 @@ in hostAddress = hostAddress; localAddress = containerAddress; autoStart = true; + # needed for openvpn enableTun = true; config = { config, pkgs, lib, ... }: { - services.journalbeat = { - enable = true; - extraConfig = '' - journalbeat.inputs: - - paths: [] - # Position to start reading from journal. Valid values: head, tail, cursor - seek: cursor - # Fallback position if no cursor data is available. - cursor_seek_fallback: tail - output.logstash: - # Boolean flag to enable or disable the output module. - enabled: true - # Graylog host and the beats input - hosts: ["${hostAddress}:5044"] - - # If enabled only a subset of events in a batch of events is transferred per - # transaction. The number of events to be sent increases up to `bulk_max_size` - # if no error is encountered. - slow_start: true - - # The number of seconds to wait before trying to reconnect to Graylog - # after a network error. After waiting backoff.init seconds, the Beat - # tries to reconnect. If the attempt fails, the backoff timer is increased - # exponentially up to backoff.max. After a successful connection, the backoff - # timer is reset. The default is 1s. - backoff.init: 1s - - # The maximum number of seconds to wait before attempting to connect to - # Graylog after a network error. The default is 60s. - backoff.max: 60s - ''; - }; + #services.journalbeat = { + # enable = true; + # extraConfig = '' + # journalbeat.inputs: + # - paths: [] + # # Position to start reading from journal. Valid values: head, tail, cursor + # seek: cursor + # # Fallback position if no cursor data is available. + # cursor_seek_fallback: tail + # output.logstash: + # # Boolean flag to enable or disable the output module. + # enabled: true + # # Graylog host and the beats input + # hosts: ["${hostAddress}:5044"] + # # If enabled only a subset of events in a batch of events is transferred per + # # transaction. The number of events to be sent increases up to `bulk_max_size` + # # if no error is encountered. + # slow_start: true + # # The number of seconds to wait before trying to reconnect to Graylog + # # after a network error. After waiting backoff.init seconds, the Beat + # # tries to reconnect. If the attempt fails, the backoff timer is increased + # # exponentially up to backoff.max. After a successful connection, the backoff + # # timer is reset. The default is 1s. + # backoff.init: 1s + # # The maximum number of seconds to wait before attempting to connect to + # # Graylog after a network error. The default is 60s. + # backoff.max: 60s + # ''; + #}; 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 = "/home/torrent/downloads"; - incomplete-dir = "/home/torrent/incomplete"; + download-dir = "/media/torrent/downloads"; + incomplete-dir = "/media/torrent/incomplete"; incomplete-dir-enabled = true; message-level = 1; umask = "002"; rpc-whitelist-enabled = false; rpc-host-whitelist-enabled = false; - rpc-port = 9091; + rpc-port = uiPort; rpc-enable = true; rpc-bind-address = "0.0.0.0"; @@ -110,7 +180,7 @@ in speed-limit-down-enabled = false; speed-limit-down = 800; speed-limit-up-enabled = true; - speed-limit-up = 50; + speed-limit-up = 3000; upload-slots-per-torrent = 8; # Queuing # When true, Transmission will only download @@ -139,27 +209,17 @@ in # notify me when download finished script-torrent-done-enabled = true; - #script-torrent-done-filename = - # (pkgs.writers.writeBash "torrent-finished" '' - # JSON_STRING=$( ${pkgs.jq}/bin/jq -n --arg torrent_name "$TR_TORRENT_NAME" \ - # '{text: ":tada: finished : \($torrent_name)", channel: "torrent"}' ) - # ${pkgs.curl}/bin/curl \ - # --include \ - # --request POST \ - # --data-urlencode \ - # "payload=$JSON_STRING" \ - # - # ''); - + script-torrent-done-filename = completionScript; }; }; networking.firewall = { allowedTCPPorts = [ 51413 ]; allowedUDPPorts = [ 51413 ]; + # only allow access via nginx (proxy to localhost) interfaces.eth0 = { - allowedTCPPorts = [ 9091 ]; - allowedUDPPorts = [ 9091 ]; + allowedTCPPorts = [ uiPort ]; + allowedUDPPorts = [ uiPort ]; }; }; @@ -167,7 +227,16 @@ in systemd.services.transmission = { bindsTo = [ "openvpn-nordvpn.service" ]; after = [ "openvpn-nordvpn.service" ]; - serviceConfig.Restart = "always"; + serviceConfig = { + Restart = "always"; + EnvironmentFile = [ + "/run/secrets/transmissionPushover" + ]; + BindPaths = lib.mkForce [ + "/media" + "/var/lib/transmission/.config/transmission-daemon" + ]; + }; }; services.openvpn.servers.nordvpn.updateResolvConf = true; services.openvpn.servers.nordvpn.config = '' @@ -263,21 +332,23 @@ in # give containers internet access networking.nat.enable = true; networking.nat.internalInterfaces = [ "ve-torrent" ]; - networking.nat.externalInterface = "enp2s0f1"; + 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 ]; + #networking.firewall.interfaces."ve-torrent".allowedTCPPorts = + # [ 5044 12304 12305 ]; + #networking.firewall.interfaces."ve-torrent".allowedUDPPorts = + # [ 5044 12304 12305 ]; # host nginx setup + # curl transmission.robi.private < will work + # curl -H "Host: transmission.robi.private" http://144.76.13.147/ < won't work services.nginx = { enable = true; recommendedProxySettings = true; virtualHosts = { - "transmission.workhorse.private" = { - locations."/" = { proxyPass = "http://${containerAddress}:9091"; }; + "transmission.${config.networking.hostName}.private" = { + locations."/" = { proxyPass = "http://${containerAddress}:${toString uiPort}"; }; }; }; };