feat: try rework
This commit is contained in:
parent
1ddbd3b8b6
commit
ecf10628c3
51 changed files with 1941 additions and 445 deletions
|
|
@ -1,57 +1,145 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
serv = import ../data/services.nix;
|
||||
net = import ../config/network.nix;
|
||||
rem = import ../intermediate/remote.nix;
|
||||
autoSshValidation = import ../validation/auto_ssh.nix;
|
||||
|
||||
autoForwards = map (port: {
|
||||
remote = port;
|
||||
localAddress = "localhost";
|
||||
localPort = port;
|
||||
}) net.usedPorts;
|
||||
fordwards = lib.unique (serv.autossh.forwards ++ autoForwards);
|
||||
devices = autoSshValidation.getDevices net;
|
||||
|
||||
forwardStrings = map (port: "-R ${toString port.remote}:${port.localAddress}:${toString port.localPort}") fordwards;
|
||||
forwardString = builtins.concatStringsSep " " forwardStrings;
|
||||
portsByRemote =
|
||||
if rem ? portsByRemote && builtins.isAttrs rem.portsByRemote then
|
||||
rem.portsByRemote
|
||||
else
|
||||
throw "intermediate/remote.nix must export portsByRemote as an attrset.";
|
||||
|
||||
sshHost = net.services.remoteProxy.ip;
|
||||
sshPort = 22;
|
||||
sshUser = "root";
|
||||
sshKeyPath = serv.autossh.key_path;
|
||||
trustedHostsFile = serv.autossh.known_hosts;
|
||||
autoSshDevices = autoSshValidation.getAutoSshDevices devices;
|
||||
|
||||
getAutoSsh = deviceName: device:
|
||||
autoSshValidation.getAutoSshConfig deviceName device;
|
||||
|
||||
validateForwards = deviceName: forwards:
|
||||
if !builtins.isList forwards then
|
||||
throw "portsByRemote.${deviceName} must be a list of forward objects."
|
||||
else if !lib.all (forward:
|
||||
builtins.isAttrs forward
|
||||
&& forward ? remote
|
||||
&& forward ? localAddress
|
||||
&& forward ? localPort
|
||||
&& builtins.isInt forward.remote
|
||||
&& builtins.isString forward.localAddress
|
||||
&& builtins.isInt forward.localPort
|
||||
) forwards then
|
||||
throw "Each forward in portsByRemote.${deviceName} must be { remote = int; localAddress = string; localPort = int; }."
|
||||
else
|
||||
forwards;
|
||||
|
||||
getForwards = deviceName:
|
||||
if portsByRemote ? ${deviceName} then
|
||||
validateForwards deviceName portsByRemote.${deviceName}
|
||||
else
|
||||
throw "Missing mapped forwards for auto_ssh device '${deviceName}' in intermediate/remote.nix portsByRemote.";
|
||||
|
||||
enabledAutoSshDevices =
|
||||
lib.filterAttrs (deviceName: device:
|
||||
let
|
||||
_ =
|
||||
if autoSshValidation.isSafeName deviceName then
|
||||
null
|
||||
else
|
||||
throw "Auto SSH device name '${deviceName}' is not safe for Linux user/systemd names. Use lowercase letters, numbers, '_' or '-' and start with a letter or '_'.";
|
||||
autoSsh = getAutoSsh deviceName device;
|
||||
in
|
||||
if !(autoSsh ? enable) then
|
||||
throw "Auto SSH device '${deviceName}' is missing required field: auto_ssh.enable."
|
||||
else if !builtins.isBool autoSsh.enable then
|
||||
throw "Auto SSH device '${deviceName}' field auto_ssh.enable must be a bool."
|
||||
else
|
||||
autoSsh.enable
|
||||
) autoSshDevices;
|
||||
|
||||
getField = deviceName: autoSsh: fieldName: typeCheck: typeName:
|
||||
if !(autoSsh ? ${fieldName}) then
|
||||
throw "Auto SSH device '${deviceName}' is missing required field: auto_ssh.${fieldName}."
|
||||
else if !typeCheck autoSsh.${fieldName} then
|
||||
throw "Auto SSH device '${deviceName}' field auto_ssh.${fieldName} must be ${typeName}."
|
||||
else
|
||||
autoSsh.${fieldName};
|
||||
|
||||
mkForwardString = forwards:
|
||||
builtins.concatStringsSep " " (map (forward:
|
||||
"-R ${toString forward.remote}:${forward.localAddress}:${toString forward.localPort}"
|
||||
) forwards);
|
||||
|
||||
mkService = deviceName: device:
|
||||
let
|
||||
autoSsh = getAutoSsh deviceName device;
|
||||
sshHost =
|
||||
if device ? ip && builtins.isString device.ip then
|
||||
device.ip
|
||||
else
|
||||
throw "Auto SSH device '${deviceName}' must define ip as string.";
|
||||
sshPort = getField deviceName autoSsh "sshPort" builtins.isInt "an int";
|
||||
sshUser = getField deviceName autoSsh "sshUser" builtins.isString "a string";
|
||||
sshKeyPath = getField deviceName autoSsh "key" (value: builtins.isString value || builtins.isPath value) "a string or path";
|
||||
trustedHostsFile = getField deviceName autoSsh "known_hosts" (value: builtins.isString value || builtins.isPath value) "a string or path";
|
||||
forwards = getForwards deviceName;
|
||||
_ = if forwards == [] then throw "Auto SSH device '${deviceName}' has no mapped forwards. Add matching endpoints or disable this remote." else null;
|
||||
forwardString = mkForwardString forwards;
|
||||
serviceName = "autossh-${deviceName}";
|
||||
in {
|
||||
name = serviceName;
|
||||
value = {
|
||||
description = "AutoSSH reverse tunnel for ${deviceName}";
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = serviceName;
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.autossh}/bin/autossh \
|
||||
-N \
|
||||
-T \
|
||||
-M 0 \
|
||||
-o ServerAliveInterval=10 \
|
||||
-o ExitOnForwardFailure=yes \
|
||||
-o UserKnownHostsFile=${trustedHostsFile} \
|
||||
${forwardString} \
|
||||
-i ${sshKeyPath} \
|
||||
-p ${toString sshPort} \
|
||||
${sshUser}@${sshHost}
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
generatedServices = builtins.listToAttrs (lib.mapAttrsToList mkService enabledAutoSshDevices);
|
||||
|
||||
generatedUsers = builtins.listToAttrs (lib.mapAttrsToList (deviceName: _: {
|
||||
name = "autossh-${deviceName}";
|
||||
value = {
|
||||
isSystemUser = true;
|
||||
group = "autossh-${deviceName}";
|
||||
extraGroups = [ "keys" ];
|
||||
description = "AutoSSH user for ${deviceName}";
|
||||
};
|
||||
}) enabledAutoSshDevices);
|
||||
|
||||
generatedGroups = builtins.listToAttrs (lib.mapAttrsToList (deviceName: _: {
|
||||
name = "autossh-${deviceName}";
|
||||
value = {};
|
||||
}) enabledAutoSshDevices);
|
||||
in
|
||||
{
|
||||
environment.systemPackages = with pkgs; [
|
||||
autossh
|
||||
moreutils
|
||||
];
|
||||
|
||||
systemd.services.autossh-tunnel = {
|
||||
description = "Autossh Reverse SSH Tunnel";
|
||||
after = [ "network.target" "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "autossh-tunnel";
|
||||
Restart = "always";
|
||||
RestartSec = 10;
|
||||
|
||||
ExecStart = ''
|
||||
${pkgs.autossh}/bin/autossh \
|
||||
-N \
|
||||
-T \
|
||||
-M 0 \
|
||||
-o ServerAliveInterval=10 \
|
||||
-o ExitOnForwardFailure=yes \
|
||||
-o UserKnownHostsFile=${trustedHostsFile} \
|
||||
${forwardString} \
|
||||
-i ${sshKeyPath} \
|
||||
-p ${toString sshPort} \
|
||||
${sshUser}@${sshHost}
|
||||
'';
|
||||
};
|
||||
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
};
|
||||
}
|
||||
users.users = generatedUsers;
|
||||
users.groups = generatedGroups;
|
||||
systemd.services = generatedServices;
|
||||
}
|
||||
|
|
@ -1,20 +1,29 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
serv = import ../data/services.nix;
|
||||
net = import ../config/network.nix;
|
||||
serv = import ../config/services.nix;
|
||||
serviceValidation = import ../validation/service/continuwuity.nix;
|
||||
|
||||
serverName =
|
||||
if net ? devices && builtins.isAttrs net.devices && net.devices ? remote_proxy && net.devices.remote_proxy ? domain && builtins.isString net.devices.remote_proxy.domain then
|
||||
net.devices.remote_proxy.domain
|
||||
else
|
||||
throw "config/network.nix must define devices.remote_proxy.domain as string for continuwuity.";
|
||||
|
||||
trustedServers = serviceValidation.getTrustedServers serv;
|
||||
in
|
||||
{
|
||||
services.matrix-continuwuity = {
|
||||
enable = true;
|
||||
settings = {
|
||||
global = {
|
||||
server_name = net.services.continuwuity.domainOverride;
|
||||
server_name = serverName;
|
||||
allow_registration = true;
|
||||
allow_encryption = true;
|
||||
allow_federation = true;
|
||||
max_request_size = 20 * 1024 * 1024; # 20 MiB
|
||||
trusted_servers = serv.matrix.trusted_servers;
|
||||
trusted_servers = trustedServers;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,20 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
net = import ../config/network.nix;
|
||||
dhcpModel = import ../intermediate/dhcp.nix;
|
||||
|
||||
routerIp =
|
||||
if net ? devices && builtins.isAttrs net.devices && net.devices ? router && net.devices.router ? ip && builtins.isString net.devices.router.ip then
|
||||
net.devices.router.ip
|
||||
else
|
||||
throw "config/network.nix must define devices.router.ip as string.";
|
||||
|
||||
dnsServerIp =
|
||||
if net ? devices && builtins.isAttrs net.devices && net.devices ? self && net.devices.self ? ip && builtins.isString net.devices.self.ip then
|
||||
net.devices.self.ip
|
||||
else
|
||||
throw "config/network.nix must define devices.self.ip as string.";
|
||||
in
|
||||
{
|
||||
services.kea.dhcp4 = {
|
||||
|
|
@ -23,11 +36,11 @@ in
|
|||
option-data = [
|
||||
{
|
||||
name = "routers";
|
||||
data = net.ips.router;
|
||||
data = routerIp;
|
||||
}
|
||||
{
|
||||
name = "domain-name-servers";
|
||||
data = builtins.concatStringsSep ", " ([net.ips.pi] ++ net.fallback_dns_servers);
|
||||
data = builtins.concatStringsSep ", " ([dnsServerIp] ++ net.fallback_dns_servers);
|
||||
}
|
||||
{
|
||||
name = "domain-name";
|
||||
|
|
@ -39,7 +52,7 @@ in
|
|||
}
|
||||
];
|
||||
|
||||
reservations = net.dhcp.reservations;
|
||||
reservations = dhcpModel.reservations;
|
||||
}];
|
||||
|
||||
valid-lifetime = net.dhcp.default_lease;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,14 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
service_data = import ../data/services.nix;
|
||||
kiwix = service_data.kiwix;
|
||||
serviceValidation = import ../validation/service/kiwix.nix;
|
||||
service_data = import ../config/services.nix;
|
||||
kiwix = serviceValidation.getKiwix service_data;
|
||||
|
||||
rootDir = kiwix.root_dir;
|
||||
|
||||
zimUrls = kiwix.urls;
|
||||
|
||||
updater = pkgs.writeShellScriptBin "kiwix-updater" ''
|
||||
set -e
|
||||
|
||||
|
|
@ -14,13 +19,13 @@ let
|
|||
download() {
|
||||
local url=''$1
|
||||
local filename=''$(basename "''$url")
|
||||
local filepath="${kiwix.root_dir}"/''$filename
|
||||
local filepath="${rootDir}"/''$filename
|
||||
|
||||
if [ -f "''$filepath" ]; then
|
||||
echo "''$filepath exists!"
|
||||
return 0
|
||||
fi
|
||||
cd ${kiwix.root_dir}
|
||||
cd ${rootDir}
|
||||
${pkgs.wget}/bin/wget --continue --quiet "''$url" -O "''$filename.tmp"
|
||||
mv ''$filename.tmp ''$filename
|
||||
}
|
||||
|
|
@ -29,7 +34,7 @@ let
|
|||
{
|
||||
echo '<?xml version="1.0" encoding="UTF-8"?>'
|
||||
echo '<library>'
|
||||
for zim in "${kiwix.root_dir}"/*.zim; do
|
||||
for zim in "${rootDir}"/*.zim; do
|
||||
if [ -f "''$zim" ]; then
|
||||
filename=''$(basename "''$zim")
|
||||
size=''$(stat -c%s "''$zim")
|
||||
|
|
@ -58,8 +63,8 @@ EOF
|
|||
fi
|
||||
done
|
||||
echo '</library>'
|
||||
} > "${kiwix.root_dir}/library.xml.tmp"
|
||||
mv "${kiwix.root_dir}/library.xml.tmp" "${kiwix.root_dir}/library.xml"
|
||||
} > "${rootDir}/library.xml.tmp"
|
||||
mv "${rootDir}/library.xml.tmp" "${rootDir}/library.xml"
|
||||
}
|
||||
|
||||
for url in "''${URLS[@]}"; do
|
||||
|
|
|
|||
|
|
@ -1,19 +1,23 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
service_data = import ../data/services.nix;
|
||||
kiwix = service_data.kiwix;
|
||||
serviceValidation = import ../validation/service/kiwix.nix;
|
||||
service_data = import ../config/services.nix;
|
||||
kiwix = serviceValidation.getKiwix service_data;
|
||||
|
||||
rootDir = kiwix.root_dir;
|
||||
|
||||
webPort = kiwix.port;
|
||||
in {
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${kiwix.root_dir} 0755 root root - -"
|
||||
"d ${kiwix.root_dir}/data 0755 root root - -"
|
||||
"d ${rootDir} 0755 root root - -"
|
||||
"d ${rootDir}/data 0755 root root - -"
|
||||
];
|
||||
|
||||
virtualisation.oci-containers.containers = {
|
||||
kiwix-serve = {
|
||||
image = "ghcr.io/kiwix/kiwix-serve:3.8.2";
|
||||
ports = ["8086:8080"];
|
||||
volumes = ["${kiwix.root_dir}/:/data:ro"];
|
||||
ports = ["${toString webPort}:8080"];
|
||||
volumes = ["${rootDir}/:/data:ro"];
|
||||
cmd = [
|
||||
"--monitorLibrary"
|
||||
"--library" "/data/library.xml"
|
||||
|
|
@ -31,6 +35,6 @@ in {
|
|||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [8086];
|
||||
allowedTCPPorts = [ webPort ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,92 +1,36 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
network = import ../data/network.nix;
|
||||
web = import ../data/web.nix;
|
||||
virtualHostFn = name: service: let
|
||||
domain = if service ? domainOverride
|
||||
then service.domainOverride
|
||||
else "${name}.${network.local_domain}";
|
||||
locationList = if service.reverse_proxy ? endpoints
|
||||
then service.reverse_proxy.endpoints
|
||||
else ["/"];
|
||||
locationsData = builtins.listToAttrs (map (endpointName: {
|
||||
name = endpointName;
|
||||
value = {
|
||||
proxyPass = "http://127.0.0.1:${builtins.toString service.reverse_proxy.port}";
|
||||
proxyWebsockets = true;
|
||||
};
|
||||
}) locationList);
|
||||
serverAlias = lib.optionalAttrs (service.reverse_proxy ? aliases) {
|
||||
serverAliases = map (alias: "${alias}.${domain}") service.reverse_proxy.aliases;
|
||||
};
|
||||
myExtraConfig = if service.reverse_proxy ? extraConfig
|
||||
then service.reverse_proxy.extraConfig
|
||||
else {};
|
||||
listenConfig = if service.reverse_proxy ? listen
|
||||
then service.reverse_proxy.listen
|
||||
else if service.reverse_proxy ? ssl && service.reverse_proxy.ssl
|
||||
then [ {port = 80;} {port = 443; ssl=true;} ]
|
||||
else [ {port = 80;} ];
|
||||
sslConfig = if service.reverse_proxy ? ssl && service.reverse_proxy.ssl
|
||||
then {
|
||||
enableACME = true;
|
||||
forceSSL = true;
|
||||
}
|
||||
else {};
|
||||
externConnections = if service.reverse_proxy ? allowExternConnections && service.reverse_proxy.allowExternConnections
|
||||
then {
|
||||
extraConfig = ''
|
||||
allow all;
|
||||
'';
|
||||
}
|
||||
else {};
|
||||
in
|
||||
{
|
||||
serverName = "${domain}";
|
||||
listen = map (obj: ({
|
||||
addr = if obj ? addr then obj.addr else "0.0.0.0";
|
||||
port = obj.port;
|
||||
} // (if obj ? ssl then {ssl = obj.ssl;} else {}))) listenConfig;
|
||||
locations = locationsData;
|
||||
extraConfig = ''
|
||||
allow ${network.network.subnet};
|
||||
deny all;
|
||||
'';
|
||||
} // serverAlias // sslConfig // externConnections // myExtraConfig;
|
||||
rproxyServices = builtins.mapAttrs (virtualHostFn) network.reverse_proxy;
|
||||
serviceNamesMessage = builtins.toString (builtins.attrNames network.reverse_proxy);
|
||||
webHosts = lib.mapAttrs' (name: description: {
|
||||
name = "${name}.web";
|
||||
value = {
|
||||
serverName = "${name}";
|
||||
listen = [ {addr = "0.0.0.0"; port = 80;} {addr = "0.0.0.0"; port = 443; ssl = true;}];
|
||||
locations = lib.mapAttrs' (endpointName: endpointValue: {
|
||||
name = endpointName;
|
||||
value = {
|
||||
extraConfig = ''
|
||||
default_type ${endpointValue.contentType};
|
||||
return ${toString endpointValue.status} "${endpointValue.content}";
|
||||
'';
|
||||
};
|
||||
}) description;
|
||||
};
|
||||
}) web;
|
||||
fallback = {
|
||||
serverName = "_";
|
||||
listen = [ {addr = "0.0.0.0"; port = 80;}];
|
||||
locations."/" = {
|
||||
return = "404";
|
||||
extraConfig = ''
|
||||
add_header Content-Type text/plain;
|
||||
'';
|
||||
};
|
||||
nginxModel = import ../intermediate/nginx.nix;
|
||||
|
||||
extraConfig = ''
|
||||
return 404 "This domain is not configured. Available services: ${serviceNamesMessage}";
|
||||
'';
|
||||
};
|
||||
virtualHosts' = builtins.attrValues (rproxyServices // webHosts // {fallback = fallback;});
|
||||
virtualHostsData = nginxModel.virtualHostsData;
|
||||
validatedEndpoints = nginxModel.validatedEndpoints;
|
||||
tlsEndpoints = lib.filter (endpoint: endpoint.force_ssl) validatedEndpoints;
|
||||
localTlsEndpoints = lib.filter (endpoint: endpoint.force_ssl && endpoint.exposure == "local") validatedEndpoints;
|
||||
localTlsDomains = lib.unique (map (endpoint: endpoint.domain) localTlsEndpoints);
|
||||
acmeEmailConfigured =
|
||||
config.security.acme ? defaults
|
||||
&& builtins.isAttrs config.security.acme.defaults
|
||||
&& config.security.acme.defaults ? email
|
||||
&& builtins.isString config.security.acme.defaults.email
|
||||
&& config.security.acme.defaults.email != "";
|
||||
|
||||
virtualHosts' = virtualHostsData;
|
||||
in {
|
||||
assertions = [
|
||||
{
|
||||
assertion = validatedEndpoints != [];
|
||||
message = "No endpoints configured. config/endpoints.nix must contain at least one endpoint.";
|
||||
}
|
||||
{
|
||||
assertion = localTlsEndpoints == [];
|
||||
message = "ACME-managed TLS is only supported for external domains. Local domains with force_ssl=true are not allowed: ${builtins.concatStringsSep ", " localTlsDomains}";
|
||||
}
|
||||
{
|
||||
assertion = tlsEndpoints == [] || acmeEmailConfigured;
|
||||
message = "TLS endpoints exist, but security.acme.defaults.email is missing or empty.";
|
||||
}
|
||||
];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
|
||||
|
|
@ -98,7 +42,7 @@ in {
|
|||
virtualHosts = virtualHosts';
|
||||
};
|
||||
|
||||
networking.firewall.allowedTCPPorts = network.usedPorts;
|
||||
networking.firewall.allowedTCPPorts = nginxModel.nginxUsedPorts;
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
#{ config, pkgs, lib, ... }:
|
||||
{ ... }:
|
||||
let
|
||||
ssh_data = import ../data/ssh.nix;
|
||||
opensshConfig = import ../config/openssh.nix;
|
||||
usersWithKeys = opensshConfig.ssh_users;
|
||||
|
||||
in {
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
settings = {
|
||||
PasswordAuthentication = true;
|
||||
PermitRootLogin = "no";
|
||||
AllowUsers = ssh_data.ssh_users;
|
||||
AllowUsers = usersWithKeys;
|
||||
};
|
||||
};
|
||||
|
||||
users.users = builtins.mapAttrs (username: value: {
|
||||
openssh.authorizedKeys.keys = ssh_data.keys.${username};
|
||||
}) ssh_data.keys;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,21 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
serviceData = import ../data/services.nix;
|
||||
qbt = serviceData.qbittorrent;
|
||||
serviceValidation = import ../validation/service/qbittorrent.nix;
|
||||
serviceData = import ../config/services.nix;
|
||||
qbt = serviceValidation.getQbittorrent serviceData;
|
||||
|
||||
webPort = qbt.port;
|
||||
|
||||
rootDir = qbt.root_dir;
|
||||
|
||||
vpnUserPath = qbt.vpn.username_file;
|
||||
vpnPasswordPath = qbt.vpn.password_file;
|
||||
in {
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${qbt.root_dir} 0755 root root - -"
|
||||
"d ${qbt.root_dir}/gluetun 0755 root root - -"
|
||||
"d ${qbt.root_dir}/downloads 0755 root root - -"
|
||||
"d ${qbt.root_dir}/config 0755 root root - -"
|
||||
"d ${rootDir} 0755 root root - -"
|
||||
"d ${rootDir}/gluetun 0755 root root - -"
|
||||
"d ${rootDir}/downloads 0755 root root - -"
|
||||
"d ${rootDir}/config 0755 root root - -"
|
||||
];
|
||||
|
||||
environment.etc."qbittorrent-compose/docker-compose.yml" = {
|
||||
|
|
@ -22,18 +29,18 @@ services:
|
|||
- NET_ADMIN
|
||||
network_mode: bridge
|
||||
ports:
|
||||
- 127.0.0.1:8085:8085 # qBittorrent
|
||||
- 127.0.0.1:${toString webPort}:${toString webPort} # qBittorrent
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun
|
||||
volumes:
|
||||
- ${qbt.root_dir}/gluetun/:/gluetun
|
||||
- ${rootDir}/gluetun/:/gluetun
|
||||
environment:
|
||||
- VPN_SERVICE_PROVIDER=protonvpn
|
||||
- SERVER_HOSTNAME=node-nl-28.protonvpn.net,node-ch-06.protonvpn.net,node-nl-13.protonvpn.net,node-ch-06.protonvpn.net,node-es-04.protonvpn.net
|
||||
- UPDATER_PERIOD=24h
|
||||
|
||||
- OPENVPN_USER=${qbt.vpn.username}
|
||||
- OPENVPN_PASSWORD=${qbt.vpn.password}
|
||||
- OPENVPN_USER=$${OPENVPN_USER:-DUMMY_NOT_USED}
|
||||
- OPENVPN_PASSWORD=$${OPENVPN_PASSWORD:-DUMMY_NOT_USED}
|
||||
|
||||
- DOT_PROVIDERS=cloudflare,google
|
||||
- BLOCK_ADS=off
|
||||
|
|
@ -50,10 +57,10 @@ services:
|
|||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=Europe/Berlin
|
||||
- WEBUI_PORT=8085
|
||||
- WEBUI_PORT=${toString webPort}
|
||||
volumes:
|
||||
- ${qbt.root_dir}/config/:/config
|
||||
- ${qbt.root_dir}/downloads/:/downloads
|
||||
- ${rootDir}/config/:/config
|
||||
- ${rootDir}/downloads/:/downloads
|
||||
'';
|
||||
};
|
||||
systemd.services.qbittorrent-stack = {
|
||||
|
|
@ -64,20 +71,27 @@ services:
|
|||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
RemainAfterExit = true;
|
||||
WorkingDirectory = qbt.root_dir;
|
||||
WorkingDirectory = rootDir;
|
||||
ExecStart = "${pkgs.writeShellScript "torrent-start" ''
|
||||
set -e
|
||||
set -eu
|
||||
export OPENVPN_USER="$(${pkgs.coreutils}/bin/cat ${vpnUserPath} | ${pkgs.coreutils}/bin/tr -d '\r\n')"
|
||||
export OPENVPN_PASSWORD="$(${pkgs.coreutils}/bin/cat ${vpnPasswordPath} | ${pkgs.coreutils}/bin/tr -d '\r\n')"
|
||||
|
||||
# Copy compose file to working directory
|
||||
cp /etc/qbittorrent-compose/docker-compose.yml ${qbt.root_dir}/
|
||||
cd ${qbt.root_dir}
|
||||
cp /etc/qbittorrent-compose/docker-compose.yml ${rootDir}/
|
||||
cd ${rootDir}
|
||||
${pkgs.docker-compose}/bin/docker-compose up -d
|
||||
''}";
|
||||
ExecStop = "${pkgs.writeShellScript "torrent-stop" ''
|
||||
cd ${qbt.root_dir}
|
||||
cd ${rootDir}
|
||||
${pkgs.docker-compose}/bin/docker-compose down
|
||||
''}";
|
||||
ExecReload = "${pkgs.writeShellScript "torrent-reload" ''
|
||||
cd ${qbt.root_dir}
|
||||
set -eu
|
||||
export OPENVPN_USER="$(${pkgs.coreutils}/bin/cat ${vpnUserPath} | ${pkgs.coreutils}/bin/tr -d '\r\n')"
|
||||
export OPENVPN_PASSWORD="$(${pkgs.coreutils}/bin/cat ${vpnPasswordPath} | ${pkgs.coreutils}/bin/tr -d '\r\n')"
|
||||
|
||||
cd ${rootDir}
|
||||
${pkgs.docker-compose}/bin/docker-compose restart
|
||||
''}";
|
||||
|
||||
|
|
@ -87,6 +101,6 @@ services:
|
|||
};
|
||||
|
||||
networking.firewall = {
|
||||
allowedTCPPorts = [8085];
|
||||
allowedTCPPorts = [ webPort ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
net = import ../data/network.nix;
|
||||
net = import ../config/network.nix;
|
||||
dnsModel = import ../intermediate/dns.nix;
|
||||
in
|
||||
{
|
||||
services.unbound = {
|
||||
|
|
@ -16,9 +17,9 @@ in
|
|||
local-zone = "\"${net.local_domain}.\" static";
|
||||
local-data =
|
||||
(map (name:
|
||||
let ip = net.dnsMappings.${name}; in
|
||||
let ip = dnsModel.dnsMappings.${name}; in
|
||||
"\"${name}. IN A ${ip}\""
|
||||
) (builtins.attrNames net.dnsMappings));
|
||||
) (builtins.attrNames dnsModel.dnsMappings));
|
||||
};
|
||||
|
||||
forward-zone = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue