transmission works but is not nice

This commit is contained in:
Ingolf Wagner 2021-12-29 19:46:20 +01:00
parent ee9ff1306d
commit 9d34f3321f
No known key found for this signature in database
GPG key ID: 76BF5F1928B9618B
6 changed files with 211 additions and 112 deletions

View file

@ -62,7 +62,7 @@
"secrets": { "secrets": {
"flake": false, "flake": false,
"locked": { "locked": {
"narHash": "sha256-nl0nvXupyQ5mIdc9pVd0quWZwDJNcudUcbusp8Im+cM=", "narHash": "sha256-OlWM45xthVFn2NnXrIYRslLFt1m+q2ytMuasN8zXfNs=",
"path": "/home/palo/dev/secrets", "path": "/home/palo/dev/secrets",
"type": "path" "type": "path"
}, },

View file

@ -6,17 +6,19 @@
./hetzner.nix ./hetzner.nix
#./nextcloud.nix # todo
./nextcloud.nix
./packages.nix ./packages.nix
./tinc.nix ./tinc.nix
./syncthing.nix ./syncthing.nix
./taskserver.nix
./transmission.nix
#../../system/server #../../system/server
#./hardware-configuration.nix #./hardware-configuration.nix
#./mail-fetcher.nix #./mail-fetcher.nix
#./transmission.nix
#./borg.nix #./borg.nix
#./finance.nix #./finance.nix
#./gogs.nix #./gogs.nix
@ -26,12 +28,18 @@
#./kibana.nix #./kibana.nix
#./mysql.nix #./mysql.nix
#./prometheus.nix #./prometheus.nix
#./taskserver.nix
#./weechat.nix #./weechat.nix
#./property.nix # flask sucks, find something else #./property.nix # flask sucks, find something else
]; ];
# Shell configuration
# -------------------
programs.custom = {
bash.enable = true;
zsh.enable = true;
};
security.acme = { security.acme = {
acceptTerms = true; acceptTerms = true;
email = "contact@ingolf-wagner.de"; email = "contact@ingolf-wagner.de";

View file

@ -1,10 +1,16 @@
{ pkgs, config, lib, ... }: { pkgs, config, lib, ... }:
let
nextcloudUid = 1000;
in
{ {
users.users.nextcloud = {
isSystemUser = true;
uid = nextcloudUid;
};
networking.firewall.allowedTCPPorts = [ 80 443 ]; #networking.firewall.allowedTCPPorts = [ 80 443 ];
networking.firewall.allowedUDPPorts = [ 80 443 ]; #networking.firewall.allowedUDPPorts = [ 80 443 ];
# host nginx setup # host nginx setup
services.nginx = { services.nginx = {
@ -13,17 +19,16 @@
recommendedOptimisation = lib.mkDefault true; recommendedOptimisation = lib.mkDefault true;
recommendedTlsSettings = lib.mkDefault true; recommendedTlsSettings = lib.mkDefault true;
recommendedProxySettings = true; recommendedProxySettings = true;
sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; #sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";
virtualHosts = { #virtualHosts = {
"nextcloud.ingolf-wagner.de" = { # "nextcloud.ingolf-wagner.de" = {
forceSSL = true; # forceSSL = true;
enableACME = true; # enableACME = true;
}; # };
}; #};
}; };
# nextcloud database # nextcloud database
# ================== # ==================
# #
@ -45,44 +50,56 @@
# ------------- # -------------
# https://docs.nextcloud.com/server/18/admin_manual/configuration_database/mysql_4byte_support.html # 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 # if you do this don't forget --default-character-set=utf8mb4 for mysqldump
services.mysql = { containers.nextcloudmysql = {
enable = true; autoStart = true;
package = pkgs.mysql; forwardPorts = [{
# https://nixos.org/manual/nixos/stable/release-notes.html#sec-release-20.09-incompatibilities containerPort = 3336;
ensureDatabases = [ "nextcloud" ]; hostPort = 3336;
ensureUsers = [{ protocol = "tcp";
name = "nextcloud";
ensurePermissions = { "nextcloud.*" = "ALL PRIVILEGES"; };
}]; }];
settings.mysqld = {
innodb_large_prefix = true; config = { config, pkgs, lib, ... }: {
innodb_file_format = "barracuda"; services.mysql = {
innodb_file_per_table = 1; 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 # in php
services.phpfpm.phpPackage = pkgs.php73; services.phpfpm.phpPackage = pkgs.php73;
# nextcloud setup # nextcloud setup
services.nextcloud = { services.nextcloud = {
enable = true; enable = false;
hostName = "nextcloud.ingolf-wagner.de"; hostName = "nextcloud.ingolf-wagner.de";
package = pkgs.nextcloud22; package = pkgs.nextcloud22;
autoUpdateApps.enable = true; autoUpdateApps.enable = true;

View file

@ -109,7 +109,7 @@
system.permown."/media/syncthing" = { system.permown."/media/syncthing" = {
owner = "syncthing"; owner = "syncthing";
group = "syncthing"; group = "syncthing";
umask = "0022"; umask = "0002";
}; };
systemd.services."permown._media_syncthing" = { systemd.services."permown._media_syncthing" = {
bindsTo = [ "media.mount" ]; bindsTo = [ "media.mount" ];

View file

@ -11,6 +11,9 @@
ciphers = "SECURE256"; 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 ];
} }

View file

@ -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 let
hostInterface = "enp3s0";
hostAddress = "192.168.100.30"; hostAddress = "192.168.100.30";
containerAddress = "192.168.100.31"; 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 in
{ {
@ -13,6 +79,7 @@ in
#}; #};
sops.secrets.nordvpn = { }; sops.secrets.nordvpn = { };
sops.secrets.transmissionPushover= { };
containers.torrent = { containers.torrent = {
@ -23,24 +90,23 @@ in
# mountPoint = "/run/secrets/transmission_password"; # mountPoint = "/run/secrets/transmission_password";
# isReadOnly = true; # isReadOnly = true;
#}; #};
transmissionPushover = {
hostPath = "/run/secrets/transmissionPushover";
mountPoint = "/run/secrets/transmissionPushover";
isReadOnly = true;
};
nordvpnPassword = { nordvpnPassword = {
hostPath = "/run/secrets/nordvpn"; hostPath = "/run/secrets/nordvpn";
mountPoint = "/run/secrets/nordvpn"; mountPoint = "/run/secrets/nordvpn";
isReadOnly = true; isReadOnly = true;
}; };
home = {
hostPath = "/home/torrent";
mountPoint = "/home/torrent";
isReadOnly = false;
};
media = { media = {
hostPath = "/media"; hostPath = "/media";
mountPoint = mountPoint = "/media"; # must be here otherwise transmission can't see the folder
"/home/torrent/downloads/media"; # must be here otherwise transmission can't see the folder
isReadOnly = false; isReadOnly = false;
}; };
lib = { lib = {
hostPath = "/home/torrent/.config"; hostPath = "/media/torrent/.config";
mountPoint = "/var/lib/transmission/.config"; mountPoint = "/var/lib/transmission/.config";
isReadOnly = false; isReadOnly = false;
}; };
@ -52,57 +118,61 @@ in
hostAddress = hostAddress; hostAddress = hostAddress;
localAddress = containerAddress; localAddress = containerAddress;
autoStart = true; autoStart = true;
# needed for openvpn # needed for openvpn
enableTun = true; enableTun = true;
config = { config, pkgs, lib, ... }: { config = { config, pkgs, lib, ... }: {
services.journalbeat = { #services.journalbeat = {
enable = true; # enable = true;
extraConfig = '' # extraConfig = ''
journalbeat.inputs: # journalbeat.inputs:
- paths: [] # - paths: []
# Position to start reading from journal. Valid values: head, tail, cursor # # Position to start reading from journal. Valid values: head, tail, cursor
seek: cursor # seek: cursor
# Fallback position if no cursor data is available. # # Fallback position if no cursor data is available.
cursor_seek_fallback: tail # cursor_seek_fallback: tail
output.logstash: # output.logstash:
# Boolean flag to enable or disable the output module. # # Boolean flag to enable or disable the output module.
enabled: true # enabled: true
# Graylog host and the beats input # # Graylog host and the beats input
hosts: ["${hostAddress}:5044"] # hosts: ["${hostAddress}:5044"]
# # If enabled only a subset of events in a batch of events is transferred per
# 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`
# transaction. The number of events to be sent increases up to `bulk_max_size` # # if no error is encountered.
# if no error is encountered. # slow_start: true
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
# The number of seconds to wait before trying to reconnect to Graylog # # tries to reconnect. If the attempt fails, the backoff timer is increased
# after a network error. After waiting backoff.init seconds, the Beat # # exponentially up to backoff.max. After a successful connection, the backoff
# tries to reconnect. If the attempt fails, the backoff timer is increased # # timer is reset. The default is 1s.
# exponentially up to backoff.max. After a successful connection, the backoff # backoff.init: 1s
# timer is reset. The default is 1s. # # The maximum number of seconds to wait before attempting to connect to
backoff.init: 1s # # Graylog after a network error. The default is 60s.
# backoff.max: 60s
# 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"; services.journald.extraConfig = "SystemMaxUse=1G";
# allow transmission to write in syncthing folders
users.groups.syncthing = {
gid = config.ids.gids.syncthing;
members = ["transmission"];
};
services.transmission = { services.transmission = {
enable = true; enable = true;
settings = { settings = {
download-dir = "/home/torrent/downloads"; download-dir = "/media/torrent/downloads";
incomplete-dir = "/home/torrent/incomplete"; incomplete-dir = "/media/torrent/incomplete";
incomplete-dir-enabled = true; incomplete-dir-enabled = true;
message-level = 1; message-level = 1;
umask = "002"; umask = "002";
rpc-whitelist-enabled = false; rpc-whitelist-enabled = false;
rpc-host-whitelist-enabled = false; rpc-host-whitelist-enabled = false;
rpc-port = 9091; rpc-port = uiPort;
rpc-enable = true; rpc-enable = true;
rpc-bind-address = "0.0.0.0"; rpc-bind-address = "0.0.0.0";
@ -110,7 +180,7 @@ in
speed-limit-down-enabled = false; speed-limit-down-enabled = false;
speed-limit-down = 800; speed-limit-down = 800;
speed-limit-up-enabled = true; speed-limit-up-enabled = true;
speed-limit-up = 50; speed-limit-up = 3000;
upload-slots-per-torrent = 8; upload-slots-per-torrent = 8;
# Queuing # Queuing
# When true, Transmission will only download # When true, Transmission will only download
@ -139,27 +209,17 @@ in
# notify me when download finished # notify me when download finished
script-torrent-done-enabled = true; script-torrent-done-enabled = true;
#script-torrent-done-filename = script-torrent-done-filename = completionScript;
# (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" \
# <url>
# '');
}; };
}; };
networking.firewall = { networking.firewall = {
allowedTCPPorts = [ 51413 ]; allowedTCPPorts = [ 51413 ];
allowedUDPPorts = [ 51413 ]; allowedUDPPorts = [ 51413 ];
# only allow access via nginx (proxy to localhost)
interfaces.eth0 = { interfaces.eth0 = {
allowedTCPPorts = [ 9091 ]; allowedTCPPorts = [ uiPort ];
allowedUDPPorts = [ 9091 ]; allowedUDPPorts = [ uiPort ];
}; };
}; };
@ -167,7 +227,16 @@ in
systemd.services.transmission = { systemd.services.transmission = {
bindsTo = [ "openvpn-nordvpn.service" ]; bindsTo = [ "openvpn-nordvpn.service" ];
after = [ "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.updateResolvConf = true;
services.openvpn.servers.nordvpn.config = '' services.openvpn.servers.nordvpn.config = ''
@ -263,21 +332,23 @@ in
# give containers internet access # give containers internet access
networking.nat.enable = true; networking.nat.enable = true;
networking.nat.internalInterfaces = [ "ve-torrent" ]; networking.nat.internalInterfaces = [ "ve-torrent" ];
networking.nat.externalInterface = "enp2s0f1"; networking.nat.externalInterface = hostInterface;
# open ports for logging # open ports for logging
networking.firewall.interfaces."ve-torrent".allowedTCPPorts = #networking.firewall.interfaces."ve-torrent".allowedTCPPorts =
[ 5044 12304 12305 ]; # [ 5044 12304 12305 ];
networking.firewall.interfaces."ve-torrent".allowedUDPPorts = #networking.firewall.interfaces."ve-torrent".allowedUDPPorts =
[ 5044 12304 12305 ]; # [ 5044 12304 12305 ];
# host nginx setup # 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 = { services.nginx = {
enable = true; enable = true;
recommendedProxySettings = true; recommendedProxySettings = true;
virtualHosts = { virtualHosts = {
"transmission.workhorse.private" = { "transmission.${config.networking.hostName}.private" = {
locations."/" = { proxyPass = "http://${containerAddress}:9091"; }; locations."/" = { proxyPass = "http://${containerAddress}:${toString uiPort}"; };
}; };
}; };
}; };