Compare commits
23 commits
331dceba7f
...
29ae755d41
| Author | SHA1 | Date | |
|---|---|---|---|
| 29ae755d41 | |||
| ecd65c5e86 | |||
| 7c52c6a6d4 | |||
| 19ba9e9442 | |||
| ea5d240d83 | |||
| 135cef2536 | |||
| ee1139713c | |||
| 058096079e | |||
| c40090d176 | |||
| 1b6a48d6c2 | |||
| e4bc0444bf | |||
| c69aaa7adb | |||
| 26ee59ef6e | |||
| 6f5ac4e55f | |||
| 67936af4c7 | |||
| e82ae4a219 | |||
| a0473a5c6c | |||
| a28295da27 | |||
| bd55ecc016 | |||
| 1dd1dbb917 | |||
| 439a6bc930 | |||
| e5bf5a3ba1 | |||
| a1cab7f606 |
16 changed files with 177 additions and 42 deletions
6
flake.lock
generated
6
flake.lock
generated
|
|
@ -175,11 +175,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1743689281,
|
"lastModified": 1744777043,
|
||||||
"narHash": "sha256-y7Hg5lwWhEOgflEHRfzSH96BOt26LaYfrYWzZ+VoVdg=",
|
"narHash": "sha256-O6jgTxz9BKUiaJl03JsVHvSjtCOC8gHfDvC2UCfcLMc=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "2bfc080955153be0be56724be6fa5477b4eefabb",
|
"rev": "7a6f7f4c1c69eee05641beaa40e7f85da8e69fb0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@ let
|
||||||
defaultModules = [
|
defaultModules = [
|
||||||
# Include generic settings
|
# Include generic settings
|
||||||
"${self}/modules/home"
|
"${self}/modules/home"
|
||||||
|
{
|
||||||
|
nixpkgs.overlays = (lib.attrValues self.overlays) ++ [
|
||||||
|
inputs.nur.overlays.default
|
||||||
|
];
|
||||||
|
}
|
||||||
{
|
{
|
||||||
# Basic user information defaults
|
# Basic user information defaults
|
||||||
home.username = lib.mkDefault "ambroisie";
|
home.username = lib.mkDefault "ambroisie";
|
||||||
|
|
@ -21,18 +26,15 @@ let
|
||||||
# * not letting me set `lib` as an extraSpecialArgs
|
# * not letting me set `lib` as an extraSpecialArgs
|
||||||
# * not respecting `nixpkgs.overlays` [1]
|
# * not respecting `nixpkgs.overlays` [1]
|
||||||
# [1]: https://github.com/nix-community/home-manager/issues/2954
|
# [1]: https://github.com/nix-community/home-manager/issues/2954
|
||||||
pkgs = import inputs.nixpkgs {
|
pkgs = inputs.nixpkgs.legacyPackages.${system};
|
||||||
inherit system;
|
|
||||||
|
|
||||||
overlays = (lib.attrValues self.overlays) ++ [
|
|
||||||
inputs.nur.overlays.default
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
modules = defaultModules ++ [
|
modules = defaultModules ++ [
|
||||||
"${self}/hosts/homes/${name}"
|
"${self}/hosts/homes/${name}"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Use my extended lib in NixOS configuration
|
||||||
|
inherit (self) lib;
|
||||||
|
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
# Inject inputs to use them in global registry
|
# Inject inputs to use them in global registry
|
||||||
inherit inputs;
|
inherit inputs;
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@
|
||||||
enablePassthrough = true;
|
enablePassthrough = true;
|
||||||
|
|
||||||
terminalFeatures = {
|
terminalFeatures = {
|
||||||
# HTerm uses `xterm-256color` as its `$TERM`, so use that here
|
# HTerm configured to use a more accurate terminfo entry than `xterm-256color`
|
||||||
xterm-256color = { };
|
hterm-256color = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@
|
||||||
enableResurrect = true;
|
enableResurrect = true;
|
||||||
|
|
||||||
terminalFeatures = {
|
terminalFeatures = {
|
||||||
# HTerm uses `xterm-256color` as its `$TERM`, so use that here
|
# HTerm configured to use a more accurate terminfo entry than `xterm-256color`
|
||||||
xterm-256color = { };
|
hterm-256color = { };
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ in
|
||||||
"pyload/credentials.age".publicKeys = all;
|
"pyload/credentials.age".publicKeys = all;
|
||||||
|
|
||||||
"servarr/autobrr/session-secret.age".publicKeys = all;
|
"servarr/autobrr/session-secret.age".publicKeys = all;
|
||||||
|
"servarr/cross-seed/configuration.json.age".publicKeys = all;
|
||||||
|
|
||||||
"sso/auth-key.age" = {
|
"sso/auth-key.age" = {
|
||||||
owner = "nginx-sso";
|
owner = "nginx-sso";
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -51,6 +51,10 @@ in
|
||||||
passwordFile = secrets."forgejo/mail-password".path;
|
passwordFile = secrets."forgejo/mail-password".path;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
# Home inventory
|
||||||
|
homebox = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
# Jellyfin media server
|
# Jellyfin media server
|
||||||
jellyfin.enable = true;
|
jellyfin.enable = true;
|
||||||
# Gitea mirrorig service
|
# Gitea mirrorig service
|
||||||
|
|
@ -144,6 +148,9 @@ in
|
||||||
autobrr = {
|
autobrr = {
|
||||||
sessionSecretFile = secrets."servarr/autobrr/session-secret".path;
|
sessionSecretFile = secrets."servarr/autobrr/session-secret".path;
|
||||||
};
|
};
|
||||||
|
cross-seed = {
|
||||||
|
secretSettingsFile = secrets."servarr/cross-seed/configuration.json".path;
|
||||||
|
};
|
||||||
# ... But not Lidarr because I don't care for music that much
|
# ... But not Lidarr because I don't care for music that much
|
||||||
lidarr = {
|
lidarr = {
|
||||||
enable = false;
|
enable = false;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ in
|
||||||
|
|
||||||
# I want the full experience by default
|
# I want the full experience by default
|
||||||
package = mkPackageOption pkgs "atuin" { };
|
package = mkPackageOption pkgs "atuin" { };
|
||||||
|
|
||||||
|
daemon = {
|
||||||
|
enable = my.mkDisableOption "atuin daemon";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
@ -15,12 +19,18 @@ in
|
||||||
enable = true;
|
enable = true;
|
||||||
inherit (cfg) package;
|
inherit (cfg) package;
|
||||||
|
|
||||||
|
daemon = lib.mkIf cfg.daemon.enable {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
flags = [
|
flags = [
|
||||||
# I *despise* this hijacking of the up key, even though I use Ctrl-p
|
# I *despise* this hijacking of the up key, even though I use Ctrl-p
|
||||||
"--disable-up-arrow"
|
"--disable-up-arrow"
|
||||||
];
|
];
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
|
# Reasonable date format
|
||||||
|
dialect = "uk";
|
||||||
# The package is managed by Nix
|
# The package is managed by Nix
|
||||||
update_check = false;
|
update_check = false;
|
||||||
# I don't care for the fancy display
|
# I don't care for the fancy display
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,16 @@ let
|
||||||
(config.my.home.wm.windowManager != null)
|
(config.my.home.wm.windowManager != null)
|
||||||
];
|
];
|
||||||
|
|
||||||
mkTerminalFlags = opt: flag:
|
mkTerminalFlags = tmuxVar: opt: flag:
|
||||||
let
|
let
|
||||||
mkFlag = term: ''set -as terminal-features ",${term}:${flag}"'';
|
mkFlag = term: ''set -as ${tmuxVar} ",${term}:${flag}"'';
|
||||||
enabledTerminals = lib.filterAttrs (_: v: v.${opt}) cfg.terminalFeatures;
|
enabledTerminals = lib.filterAttrs (_: v: v.${opt}) cfg.terminalFeatures;
|
||||||
terminals = lib.attrNames enabledTerminals;
|
terminals = lib.attrNames enabledTerminals;
|
||||||
in
|
in
|
||||||
lib.concatMapStringsSep "\n" mkFlag terminals;
|
lib.concatMapStringsSep "\n" mkFlag terminals;
|
||||||
|
|
||||||
|
mkTerminalFeatures = mkTerminalFlags "terminal-features";
|
||||||
|
mkTerminalOverrides = mkTerminalFlags "terminal-overrides";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.my.home.tmux = with lib; {
|
options.my.home.tmux = with lib; {
|
||||||
|
|
@ -28,6 +31,8 @@ in
|
||||||
hyperlinks = my.mkDisableOption "hyperlinks through OSC8";
|
hyperlinks = my.mkDisableOption "hyperlinks through OSC8";
|
||||||
|
|
||||||
trueColor = my.mkDisableOption "24-bit (RGB) color support";
|
trueColor = my.mkDisableOption "24-bit (RGB) color support";
|
||||||
|
|
||||||
|
underscoreStyle = my.mkDisableOption "underscore style/color support";
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -54,6 +59,20 @@ in
|
||||||
terminal = "tmux-256color"; # I want accurate termcap info
|
terminal = "tmux-256color"; # I want accurate termcap info
|
||||||
aggressiveResize = true; # Automatic resize when switching client size
|
aggressiveResize = true; # Automatic resize when switching client size
|
||||||
|
|
||||||
|
# FIXME
|
||||||
|
# * Sixel support
|
||||||
|
# * OSC 133 prompt integration
|
||||||
|
# FIXME: when sensible-on-top is disabled: check if any of those are unset
|
||||||
|
# * tmux bind-key $prefix_without_ctrl last-window
|
||||||
|
# *
|
||||||
|
# * tmux bind-key C-b send-prefix: included
|
||||||
|
# * aggressive resize? done
|
||||||
|
# * tmux bind-key C-p previous-window: done
|
||||||
|
# * tmux bind-key C-n next-window: done
|
||||||
|
# * C-r to refresh my config: done
|
||||||
|
# * tmux set-option -g focus-events on: done
|
||||||
|
|
||||||
|
# FIXME: make PRs for `bind-key` description
|
||||||
plugins = with pkgs.tmuxPlugins; builtins.filter (attr: attr != { }) [
|
plugins = with pkgs.tmuxPlugins; builtins.filter (attr: attr != { }) [
|
||||||
# Open high-lighted files in copy mode
|
# Open high-lighted files in copy mode
|
||||||
open
|
open
|
||||||
|
|
@ -123,9 +142,14 @@ in
|
||||||
}
|
}
|
||||||
|
|
||||||
# Force OSC8 hyperlinks for each relevant $TERM
|
# Force OSC8 hyperlinks for each relevant $TERM
|
||||||
${mkTerminalFlags "hyperlinks" "hyperlinks"}
|
${mkTerminalFeatures "hyperlinks" "hyperlinks"}
|
||||||
# Force 24-bit color for each relevant $TERM
|
# Force 24-bit color for each relevant $TERM
|
||||||
${mkTerminalFlags "trueColor" "RGB"}
|
${mkTerminalFeatures "trueColor" "RGB"}
|
||||||
|
# Force underscore style/color for each relevant $TERM
|
||||||
|
${mkTerminalFeatures "underscoreStyle" "usstyle"}
|
||||||
|
# FIXME: see https://github.com/folke/tokyonight.nvim#fix-undercurls-in-tmux for additional overrides
|
||||||
|
# ${mkTerminalOverrides "underscoreStyle" "Smulx=\\E[4::%p1%dm"}
|
||||||
|
# ${mkTerminalOverrides "underscoreStyle" "Setulc=\\E[58::2::::%p1%{65536}%/%d::%p1%{256}%/%{255}%&%d::%p1%{255}%&%d%;m"}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,3 @@ vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "InsertEnter", "WinLeave"
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
-- Never show the sign column in a terminal buffer
|
|
||||||
vim.api.nvim_create_autocmd({ "TermOpen" }, {
|
|
||||||
pattern = "*",
|
|
||||||
group = numbertoggle,
|
|
||||||
callback = function()
|
|
||||||
vim.opt.number = false
|
|
||||||
vim.opt.relativenumber = false
|
|
||||||
end,
|
|
||||||
})
|
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,21 @@
|
||||||
local signtoggle = vim.api.nvim_create_augroup("signtoggle", { clear = true })
|
local signtoggle = vim.api.nvim_create_augroup("signtoggle", { clear = true })
|
||||||
|
|
||||||
-- Only show sign column for the currently focused buffer
|
-- Only show sign column for the currently focused buffer, if it has a number column
|
||||||
vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "WinEnter" }, {
|
vim.api.nvim_create_autocmd({ "BufEnter", "FocusGained", "WinEnter" }, {
|
||||||
pattern = "*",
|
pattern = "*",
|
||||||
group = signtoggle,
|
group = signtoggle,
|
||||||
callback = function()
|
callback = function()
|
||||||
vim.opt.signcolumn = "yes"
|
if vim.opt.number:get() then
|
||||||
|
vim.opt.signcolumn = "yes"
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "WinLeave" }, {
|
vim.api.nvim_create_autocmd({ "BufLeave", "FocusLost", "WinLeave" }, {
|
||||||
pattern = "*",
|
pattern = "*",
|
||||||
group = signtoggle,
|
group = signtoggle,
|
||||||
callback = function()
|
callback = function()
|
||||||
vim.opt.signcolumn = "no"
|
if vim.opt.number:get() then
|
||||||
end,
|
vim.opt.signcolumn = "no"
|
||||||
})
|
end
|
||||||
|
|
||||||
-- Never show the sign column in a terminal buffer
|
|
||||||
vim.api.nvim_create_autocmd({ "TermOpen" }, {
|
|
||||||
pattern = "*",
|
|
||||||
group = signtoggle,
|
|
||||||
callback = function()
|
|
||||||
vim.opt.signcolumn = "no"
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,11 @@ in
|
||||||
services.homebox = {
|
services.homebox = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
|
# Automatic PostgreSQL provisioning
|
||||||
|
database = {
|
||||||
|
createLocally = true;
|
||||||
|
};
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
# FIXME: mailer?
|
# FIXME: mailer?
|
||||||
HBOX_WEB_PORT = toString cfg.port;
|
HBOX_WEB_PORT = toString cfg.port;
|
||||||
|
|
@ -28,6 +33,7 @@ in
|
||||||
my.services.nginx.virtualHosts = {
|
my.services.nginx.virtualHosts = {
|
||||||
homebox = {
|
homebox = {
|
||||||
inherit (cfg) port;
|
inherit (cfg) port;
|
||||||
|
websocketsLocations = [ "/api" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# IRC-based
|
# IRC-based indexer
|
||||||
{ config, lib, ... }:
|
{ config, lib, ... }:
|
||||||
let
|
let
|
||||||
cfg = config.my.services.servarr.autobrr;
|
cfg = config.my.services.servarr.autobrr;
|
||||||
|
|
@ -40,6 +40,7 @@ in
|
||||||
my.services.nginx.virtualHosts = {
|
my.services.nginx.virtualHosts = {
|
||||||
autobrr = {
|
autobrr = {
|
||||||
inherit (cfg) port;
|
inherit (cfg) port;
|
||||||
|
websocketsLocations = [ "/api" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -54,7 +55,7 @@ in
|
||||||
environment.etc = {
|
environment.etc = {
|
||||||
"fail2ban/filter.d/autobrr.conf".text = ''
|
"fail2ban/filter.d/autobrr.conf".text = ''
|
||||||
[Definition]
|
[Definition]
|
||||||
failregex = ^.*Auth: invalid login \[.*\] from: <HOST>$
|
failregex = "message":"Auth: Failed login attempt username: \[.*\] ip: <HOST>"
|
||||||
journalmatch = _SYSTEMD_UNIT=autobrr.service
|
journalmatch = _SYSTEMD_UNIT=autobrr.service
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
|
||||||
96
modules/nixos/services/servarr/cross-seed.nix
Normal file
96
modules/nixos/services/servarr/cross-seed.nix
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
# Automatic cross-seeding for video media
|
||||||
|
{ config, lib, ... }:
|
||||||
|
let
|
||||||
|
cfg = config.my.services.servarr.cross-seed;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.my.services.servarr.cross-seed = with lib; {
|
||||||
|
enable = mkEnableOption "cross-seed daemon" // {
|
||||||
|
default = config.my.services.servarr.enableAll;
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 2468;
|
||||||
|
example = 8080;
|
||||||
|
description = "Internal port for daemon";
|
||||||
|
};
|
||||||
|
|
||||||
|
linkDirectory = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "/data/downloads/complete/links";
|
||||||
|
example = "/var/lib/cross-seed/links";
|
||||||
|
description = "Link directory";
|
||||||
|
};
|
||||||
|
|
||||||
|
secretSettingsFile = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
example = "/run/secrets/cross-seed-secrets.json";
|
||||||
|
description = ''
|
||||||
|
File containing secret settings.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
services.cross-seed = {
|
||||||
|
enable = true;
|
||||||
|
group = "media";
|
||||||
|
|
||||||
|
# Rely on recommended defaults for tracker snatches etc...
|
||||||
|
useGenConfigDefaults = true;
|
||||||
|
|
||||||
|
settings = {
|
||||||
|
inherit (cfg) port;
|
||||||
|
host = "127.0.0.1";
|
||||||
|
|
||||||
|
# Inject torrents to client directly
|
||||||
|
action = "inject";
|
||||||
|
# Query the client for torrents to match
|
||||||
|
useClientTorrents = true;
|
||||||
|
# Use hardlinks
|
||||||
|
linkType = "hardlink";
|
||||||
|
# Use configured link directory
|
||||||
|
linkDirs = [ cfg.linkDirectory ];
|
||||||
|
# Match as many torrents as possible
|
||||||
|
matchMode = "partial";
|
||||||
|
# Cross-seed full season if at least 50% of episodes are already downloaded
|
||||||
|
seasonFromEpisodes = 0.5;
|
||||||
|
};
|
||||||
|
|
||||||
|
settingsFile = cfg.secretSettingsFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.cross-seed = {
|
||||||
|
serviceConfig = {
|
||||||
|
# Loose umask to make cross-seed links readable by `media`
|
||||||
|
UMask = "0002";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Set-up media group
|
||||||
|
users.groups.media = { };
|
||||||
|
|
||||||
|
my.services.nginx.virtualHosts = {
|
||||||
|
cross-seed = {
|
||||||
|
inherit (cfg) port;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.fail2ban.jails = {
|
||||||
|
cross-seed = ''
|
||||||
|
enabled = true
|
||||||
|
filter = cross-seed
|
||||||
|
action = iptables-allports
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
environment.etc = {
|
||||||
|
"fail2ban/filter.d/cross-seed.conf".text = ''
|
||||||
|
[Definition]
|
||||||
|
failregex = ^.*Unauthorized API access attempt to .* from <HOST>$
|
||||||
|
journalmatch = _SYSTEMD_UNIT=cross-seed.service
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
imports = [
|
imports = [
|
||||||
./autobrr.nix
|
./autobrr.nix
|
||||||
./bazarr.nix
|
./bazarr.nix
|
||||||
|
./cross-seed.nix
|
||||||
./jackett.nix
|
./jackett.nix
|
||||||
./nzbhydra.nix
|
./nzbhydra.nix
|
||||||
./prowlarr.nix
|
./prowlarr.nix
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ in
|
||||||
# Proxied behind Nginx.
|
# Proxied behind Nginx.
|
||||||
rpc-whitelist-enabled = true;
|
rpc-whitelist-enabled = true;
|
||||||
rpc-whitelist = "127.0.0.1";
|
rpc-whitelist = "127.0.0.1";
|
||||||
|
|
||||||
|
umask = "002"; # To go with `downloadDirPermissions`
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue