@@ -4,6 +4,7 @@
|
||||
|
||||
Added:
|
||||
- Plex service
|
||||
- Autobrr service
|
||||
- Sandboxed Jellyseerr module and added expose option
|
||||
|
||||
Updated:
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
with lib; let
|
||||
cfg = config.nixarr.autobrr;
|
||||
nixarr = config.nixarr;
|
||||
# Externalize username and group
|
||||
user = "autobrr";
|
||||
group = "autobrr";
|
||||
|
||||
# Define config format and template
|
||||
configFormat = pkgs.formats.toml {};
|
||||
configTemplate = configFormat.generate "autobrr.toml" cfg.settings;
|
||||
in {
|
||||
options.nixarr.autobrr = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
Whether or not to enable the Autobrr service.
|
||||
|
||||
**Required options:** [`nixarr.enable`](#nixarr.enable)
|
||||
'';
|
||||
};
|
||||
|
||||
package = mkPackageOption pkgs "autobrr" {};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = types.bool;
|
||||
defaultText = literalExpression ''!nixarr.autobrr.vpn.enable'';
|
||||
default = !cfg.vpn.enable;
|
||||
example = true;
|
||||
description = "Open firewall for the Autobrr port.";
|
||||
};
|
||||
|
||||
vpn.enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
example = true;
|
||||
description = ''
|
||||
**Required options:** [`nixarr.vpn.enable`](#nixarr.vpn.enable)
|
||||
|
||||
Route Autobrr traffic through the VPN.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = lib.mkOption {
|
||||
type = lib.types.submodule {freeformType = configFormat.type;};
|
||||
default = {
|
||||
host = "0.0.0.0";
|
||||
port = 7474;
|
||||
checkForUpdates = false;
|
||||
};
|
||||
example = {
|
||||
logLevel = "DEBUG";
|
||||
};
|
||||
description = ''
|
||||
Autobrr configuration options.
|
||||
|
||||
See https://autobrr.com/configuration/autobrr for more information.
|
||||
|
||||
`sessionSecret` is automatically generated upon first installation and will be overridden.
|
||||
This is done to ensure that the secret is not hard-coded in the configuration file.
|
||||
The actual secret file is generated in the systemd service at `${cfg.stateDir}/session-secret`.
|
||||
'';
|
||||
};
|
||||
|
||||
stateDir = mkOption {
|
||||
type = types.path;
|
||||
default = "${nixarr.stateDir}/autobrr";
|
||||
defaultText = literalExpression ''"''${nixarr.stateDir}/autobrr"'';
|
||||
example = "/nixarr/.state/autobrr";
|
||||
description = "The location of the state directory for the Autobrr service.";
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.vpn.enable -> nixarr.vpn.enable;
|
||||
message = ''
|
||||
The nixarr.autobrr.vpn.enable option requires the
|
||||
nixarr.vpn.enable option to be set, but it was not.
|
||||
'';
|
||||
}
|
||||
{
|
||||
assertion = cfg.enable -> nixarr.enable;
|
||||
message = ''
|
||||
The nixarr.autobrr.enable option requires the nixarr.enable
|
||||
option to be set, but it was not.
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
users = {
|
||||
groups.${group} = {};
|
||||
users.${user} = {
|
||||
isSystemUser = true;
|
||||
group = group;
|
||||
};
|
||||
};
|
||||
|
||||
# Create state directory with proper permissions
|
||||
systemd.tmpfiles.rules = [
|
||||
"d '${cfg.stateDir}' 0700 ${user} ${group} - -"
|
||||
];
|
||||
|
||||
# Configure the autobrr service
|
||||
services.autobrr = {
|
||||
enable = true;
|
||||
package = cfg.package;
|
||||
# We need to provide a secretFile even though we're handling it ourselves
|
||||
# The actual secret file is generated in the systemd service at ${cfg.stateDir}/session-secret
|
||||
secretFile = "/dev/null"; # This is a placeholder that won't be used
|
||||
settings = mkMerge [
|
||||
# User settings
|
||||
cfg.settings
|
||||
# Override host if VPN is enabled
|
||||
(mkIf cfg.vpn.enable {host = "192.168.15.1";})
|
||||
];
|
||||
};
|
||||
|
||||
# Override the autobrr service to use our state directory and session secret handling
|
||||
systemd.services.autobrr = {
|
||||
description = "Autobrr";
|
||||
after = ["syslog.target" "network-online.target"];
|
||||
wants = ["network-online.target"];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [pkgs.openssl pkgs.dasel];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = user;
|
||||
Group = "root";
|
||||
UMask = 066;
|
||||
DynamicUser = lib.mkForce false;
|
||||
# disable SecretFilec
|
||||
LoadCredential = lib.mkForce null;
|
||||
# disable state directory
|
||||
StateDirectory = lib.mkForce null;
|
||||
ExecStartPre = lib.mkForce (pkgs.writeShellScript "autobrr-config-prep" ''
|
||||
# Generate session secret if it doesn't exist
|
||||
SESSION_SECRET_FILE="${cfg.stateDir}/session-secret"
|
||||
if [ ! -f "$SESSION_SECRET_FILE" ]; then
|
||||
openssl rand -base64 32 > "$SESSION_SECRET_FILE"
|
||||
chmod 600 "$SESSION_SECRET_FILE"
|
||||
fi
|
||||
|
||||
# Create config with session secret
|
||||
SESSION_SECRET=$(cat "$SESSION_SECRET_FILE")
|
||||
cp '${configTemplate}' "${cfg.stateDir}/config.toml"
|
||||
chmod 600 "${cfg.stateDir}/config.toml"
|
||||
${pkgs.dasel}/bin/dasel put -f "${cfg.stateDir}/config.toml" -v "$SESSION_SECRET" -o "${cfg.stateDir}/config.toml" "sessionSecret"
|
||||
'');
|
||||
ExecStart = lib.mkForce "${lib.getExe cfg.package} --config ${cfg.stateDir}";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
|
||||
# Enable and specify VPN namespace to confine service in
|
||||
vpnConfinement = mkIf cfg.vpn.enable {
|
||||
enable = true;
|
||||
vpnNamespace = "wg";
|
||||
};
|
||||
};
|
||||
|
||||
# Port mappings for VPN
|
||||
vpnNamespaces.wg = mkIf cfg.vpn.enable {
|
||||
portMappings = [
|
||||
{
|
||||
from = cfg.settings.port;
|
||||
to = cfg.settings.port;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
# Nginx proxy for VPN-confined service
|
||||
services.nginx = mkIf cfg.vpn.enable {
|
||||
enable = true;
|
||||
recommendedTlsSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedGzipSettings = true;
|
||||
|
||||
virtualHosts."127.0.0.1:${builtins.toString cfg.settings.port}" = {
|
||||
listen = [
|
||||
{
|
||||
addr = "0.0.0.0";
|
||||
port = cfg.settings.port;
|
||||
}
|
||||
];
|
||||
locations."/" = {
|
||||
recommendedProxySettings = true;
|
||||
proxyWebsockets = true;
|
||||
proxyPass = "http://192.168.15.1:${builtins.toString cfg.settings.port}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Open firewall ports if needed
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [cfg.settings.port];
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -81,6 +81,10 @@ with lib; let
|
||||
chown -R jellyseerr:root "${cfg.jellyseerr.stateDir}"
|
||||
find "${cfg.jellyseerr.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \)
|
||||
''
|
||||
+ strings.optionalString cfg.autobrr.enable ''
|
||||
chown -R autobrr:root "${cfg.autobrr.stateDir}"
|
||||
find "${cfg.autobrr.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \)
|
||||
''
|
||||
+ strings.optionalString cfg.recyclarr.enable ''
|
||||
chown -R recyclarr:root "${cfg.recyclarr.stateDir}"
|
||||
find "${cfg.recyclarr.stateDir}" \( -type d -exec chmod 0700 {} + -true \) -o \( -exec chmod 0600 {} + \)
|
||||
@@ -88,6 +92,7 @@ with lib; let
|
||||
};
|
||||
in {
|
||||
imports = [
|
||||
./autobrr
|
||||
./jellyfin
|
||||
./jellyseerr
|
||||
./plex
|
||||
@@ -141,6 +146,7 @@ in {
|
||||
- [Sonarr](#nixarr.sonarr.enable)
|
||||
- [Transmission](#nixarr.transmission.enable)
|
||||
- [SABnzbd](#nixarr.sabnzbd.enable)
|
||||
- [Autobrr](#nixarr.autobrr.enable)
|
||||
|
||||
Remember to read the options.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user