split up hopper lab configuration into multiple files
This commit is contained in:
parent
f077fbe3fd
commit
b69fbbcde9
14 changed files with 435 additions and 404 deletions
15
sys/machines/hopper/lab/acme.nix
Normal file
15
sys/machines/hopper/lab/acme.nix
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{config, ...}: {
|
||||||
|
security.acme = {
|
||||||
|
acceptTerms = true;
|
||||||
|
defaults.email = "xunuwu@gmail.com";
|
||||||
|
certs = {
|
||||||
|
"xunuwu.xyz" = {
|
||||||
|
domain = "*.xunuwu.xyz";
|
||||||
|
dnsProvider = "cloudflare";
|
||||||
|
reloadServices = ["caddy.service"];
|
||||||
|
credentialFiles.CF_DNS_API_TOKEN_FILE = config.sops.secrets.cloudflare.path;
|
||||||
|
extraDomainNames = ["xunuwu.xyz"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
39
sys/machines/hopper/lab/adguard.nix
Normal file
39
sys/machines/hopper/lab/adguard.nix
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
{
|
||||||
|
services.adguardhome = {
|
||||||
|
enable = true;
|
||||||
|
mutableSettings = false;
|
||||||
|
port = 23489;
|
||||||
|
settings = {
|
||||||
|
dhcp.enabled = false;
|
||||||
|
dns = {
|
||||||
|
upstream_dns = [
|
||||||
|
"quic://dns.nextdns.io"
|
||||||
|
"https://cloudflare-dns.com/dns-query"
|
||||||
|
"tls://unfiltered.adguard-dns.com"
|
||||||
|
"https://dns10.quad9.net/dns-query"
|
||||||
|
];
|
||||||
|
bind_hosts = ["100.115.105.144"];
|
||||||
|
bootstrap_dns = ["1.1.1.1" "8.8.8.8"];
|
||||||
|
};
|
||||||
|
filtering = {
|
||||||
|
rewrites = [
|
||||||
|
{
|
||||||
|
domain = "*.hopper.xun.host";
|
||||||
|
answer = "100.115.105.144";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
domain = "hopper.xun.host";
|
||||||
|
answer = "100.115.105.144";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
filters = [
|
||||||
|
{
|
||||||
|
name = "OISD (Big)";
|
||||||
|
url = "https://big.oisd.nl";
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
77
sys/machines/hopper/lab/caddy.nix
Normal file
77
sys/machines/hopper/lab/caddy.nix
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{config, ...}: let
|
||||||
|
domain = "xunuwu.xyz";
|
||||||
|
caddyPort = 8336;
|
||||||
|
in {
|
||||||
|
systemd.services.caddy.vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.caddy = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = {
|
||||||
|
jellyfin = {
|
||||||
|
useACMEHost = domain;
|
||||||
|
hostName = "jellyfin.${domain}:${toString caddyPort}";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy {
|
||||||
|
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
|
||||||
|
to localhost:8096
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
navidrome = {
|
||||||
|
useACMEHost = domain;
|
||||||
|
hostName = "navidrome.${domain}:${toString caddyPort}";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy unix//var/lib/navidrome/navidrome.sock
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
slskd = {
|
||||||
|
hostName = "slskd.hopper.xun.host:80";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy localhost:${toString config.services.slskd.settings.web.port}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
transmission = {
|
||||||
|
hostName = "transmission.hopper.xun.host:80";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy localhost:${toString config.services.transmission.settings.rpc-port}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
dash = {
|
||||||
|
hostName = "dash.hopper.xun.host:80";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy localhost:${toString config.services.homepage-dashboard.listenPort}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
vw = {
|
||||||
|
useACMEHost = domain;
|
||||||
|
hostName = "vw.${domain}:${toString caddyPort}";
|
||||||
|
extraConfig = ''
|
||||||
|
reverse_proxy {
|
||||||
|
header_up X-Real-Ip {http.request.header.CF-Connecting-IP}
|
||||||
|
to localhost:${toString config.services.vaultwarden.config.ROCKET_PORT}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
other = {
|
||||||
|
useACMEHost = domain;
|
||||||
|
hostName = ":${toString caddyPort}";
|
||||||
|
extraConfig = ''
|
||||||
|
respond 404 {
|
||||||
|
body "uhh that doesnt exist, i hope this isnt my fault.."
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
otherPriv = {
|
||||||
|
hostName = ":80";
|
||||||
|
extraConfig = ''
|
||||||
|
respond 404 {
|
||||||
|
body "uhh that doesnt exist, i hope this isnt my fault.."
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,21 +1,20 @@
|
||||||
## TODO look into sops-nix placeholders
|
## TODO look into sops-nix placeholders
|
||||||
## reference: https://github.com/javigomezo/nixos/blob/b3ebe8d570ea9b37aea8bb3a343f6e16e054e322/services/network/authelia/user_database.nix
|
## reference: https://github.com/javigomezo/nixos/blob/b3ebe8d570ea9b37aea8bb3a343f6e16e054e322/services/network/authelia/user_database.nix
|
||||||
{
|
{
|
||||||
pkgs,
|
|
||||||
inputs,
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
l = lib // builtins;
|
|
||||||
domain = "xunuwu.xyz";
|
|
||||||
caddyPort = 8336;
|
|
||||||
slskdUiPort = 23488;
|
|
||||||
adguardWebPort = 23489;
|
|
||||||
in {
|
|
||||||
imports = [
|
imports = [
|
||||||
|
./acme.nix
|
||||||
|
./adguard.nix
|
||||||
|
./caddy.nix
|
||||||
|
./homepage.nix
|
||||||
|
./jellyfin.nix
|
||||||
|
./navidrome.nix
|
||||||
|
./prometheus.nix
|
||||||
|
./restic.nix
|
||||||
./samba.nix
|
./samba.nix
|
||||||
inputs.authentik-nix.nixosModules.default
|
./slskd.nix
|
||||||
|
./transmission.nix
|
||||||
|
./vaultwarden.nix
|
||||||
|
./vpn-namespace.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
users.groups.media = {};
|
users.groups.media = {};
|
||||||
|
@ -24,65 +23,6 @@ in {
|
||||||
group = "media";
|
group = "media";
|
||||||
};
|
};
|
||||||
|
|
||||||
security.acme = {
|
|
||||||
acceptTerms = true;
|
|
||||||
defaults.email = "xunuwu@gmail.com";
|
|
||||||
certs = {
|
|
||||||
${domain} = {
|
|
||||||
domain = "*.${domain}";
|
|
||||||
dnsProvider = "cloudflare";
|
|
||||||
reloadServices = ["caddy.service"];
|
|
||||||
credentialFiles.CF_DNS_API_TOKEN_FILE = config.sops.secrets.cloudflare.path;
|
|
||||||
extraDomainNames = [domain];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
vpnNamespaces."wg" = {
|
|
||||||
enable = true;
|
|
||||||
wireguardConfigFile = config.sops.secrets.wireguard.path;
|
|
||||||
accessibleFrom = [
|
|
||||||
"192.168.0.0/24"
|
|
||||||
# "127.0.0.1"
|
|
||||||
];
|
|
||||||
|
|
||||||
# Forwarded to my vpn, for making things accessible from outside
|
|
||||||
openVPNPorts = [
|
|
||||||
{
|
|
||||||
port = caddyPort;
|
|
||||||
protocol = "tcp";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
port = config.services.slskd.settings.soulseek.listen_port;
|
|
||||||
protocol = "both";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
port = config.services.slskd.settings.soulseek.listen_port + 1;
|
|
||||||
protocol = "both";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
port = config.services.transmission.settings.peer-port;
|
|
||||||
protocol = "both";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
# From inside of the vpn namespace to outside of it, for making things inside accessible to LAN
|
|
||||||
portMappings = let
|
|
||||||
passthrough = [
|
|
||||||
caddyPort
|
|
||||||
slskdUiPort
|
|
||||||
80 # caddy
|
|
||||||
443 # caddy
|
|
||||||
1900 # jellyfin discovery
|
|
||||||
7359 # jellyfin discovery
|
|
||||||
];
|
|
||||||
in (l.map (x: {
|
|
||||||
from = x;
|
|
||||||
to = x;
|
|
||||||
})
|
|
||||||
passthrough);
|
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall = {
|
networking.firewall = {
|
||||||
allowedUDPPorts = [1900 7359]; # Jellyfin auto-discovery
|
allowedUDPPorts = [1900 7359]; # Jellyfin auto-discovery
|
||||||
allowedTCPPorts = [
|
allowedTCPPorts = [
|
||||||
|
@ -93,337 +33,5 @@ in {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.services.caddy.vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.caddy = {
|
|
||||||
enable = true;
|
|
||||||
virtualHosts = {
|
|
||||||
jellyfin = {
|
|
||||||
useACMEHost = domain;
|
|
||||||
hostName = "jellyfin.${domain}:${toString caddyPort}";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy {
|
|
||||||
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
|
|
||||||
to localhost:8096
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
navidrome = {
|
|
||||||
useACMEHost = domain;
|
|
||||||
hostName = "navidrome.${domain}:${toString caddyPort}";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy unix//var/lib/navidrome/navidrome.sock
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
slskd = {
|
|
||||||
hostName = "slskd.hopper.xun.host:80";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:${toString config.services.slskd.settings.web.port}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
transmission = {
|
|
||||||
hostName = "transmission.hopper.xun.host:80";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:${toString config.services.transmission.settings.rpc-port}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
dash = {
|
|
||||||
hostName = "dash.hopper.xun.host:80";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy localhost:${toString config.services.homepage-dashboard.listenPort}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
vw = {
|
|
||||||
useACMEHost = domain;
|
|
||||||
hostName = "vw.${domain}:${toString caddyPort}";
|
|
||||||
extraConfig = ''
|
|
||||||
reverse_proxy {
|
|
||||||
header_up X-Real-Ip {http.request.header.CF-Connecting-IP}
|
|
||||||
to localhost:${toString config.services.vaultwarden.config.ROCKET_PORT}
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
other = {
|
|
||||||
useACMEHost = domain;
|
|
||||||
hostName = ":${toString caddyPort}";
|
|
||||||
extraConfig = ''
|
|
||||||
respond 404 {
|
|
||||||
body "uhh that doesnt exist, i hope this isnt my fault.."
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
otherPriv = {
|
|
||||||
hostName = ":80";
|
|
||||||
extraConfig = ''
|
|
||||||
respond 404 {
|
|
||||||
body "uhh that doesnt exist, i hope this isnt my fault.."
|
|
||||||
}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.homepage-dashboard.vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.homepage-dashboard = {
|
|
||||||
enable = true;
|
|
||||||
widgets = [
|
|
||||||
{
|
|
||||||
resources = {
|
|
||||||
cpu = true;
|
|
||||||
disk = "/";
|
|
||||||
uptime = "";
|
|
||||||
units = "metric";
|
|
||||||
cputemp = true;
|
|
||||||
memory = true;
|
|
||||||
network = true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
services = [
|
|
||||||
{
|
|
||||||
"Downloading" = [
|
|
||||||
{
|
|
||||||
"transmission" = {
|
|
||||||
href = "http://transmission.hopper.xun.host";
|
|
||||||
icon = "transmission";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"slskd" = {
|
|
||||||
href = "http://slskd.hopper.xun.host";
|
|
||||||
icon = "slskd";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"Services" = [
|
|
||||||
{
|
|
||||||
"jellyfin" = {
|
|
||||||
href = "https://jellyfin.${domain}";
|
|
||||||
icon = "jellyfin";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"navidrome" = {
|
|
||||||
href = "https://navidrome.${domain}";
|
|
||||||
icon = "navidrome";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"adguard home" = {
|
|
||||||
href = "http://${config.networking.hostName}:${toString config.services.adguardhome.port}";
|
|
||||||
icon = "adguard-home";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"prometheus" = {
|
|
||||||
href = "http://${config.networking.hostName}:${toString config.services.prometheus.port}";
|
|
||||||
icon = "prometheus";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
"vaultwarden" = {
|
|
||||||
href = "https://vw.${domain}";
|
|
||||||
icon = "vaultwarden";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.jellyfin.vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.jellyfin.enable = true;
|
|
||||||
|
|
||||||
services.prometheus = {
|
|
||||||
enable = true;
|
|
||||||
port = 9001;
|
|
||||||
extraFlags = ["--storage.tsdb.retention.time=30d"];
|
|
||||||
scrapeConfigs = [
|
|
||||||
{
|
|
||||||
job_name = "node";
|
|
||||||
static_configs = lib.singleton {
|
|
||||||
targets = ["127.0.0.1:${toString config.services.prometheus.exporters.node.port}"];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
{
|
|
||||||
job_name = "tailscale_client";
|
|
||||||
static_configs = lib.singleton {
|
|
||||||
targets = ["100.100.100.100"];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
services.prometheus.exporters = {
|
|
||||||
node = {
|
|
||||||
enable = true;
|
|
||||||
enabledCollectors = ["systemd"];
|
|
||||||
};
|
|
||||||
systemd.enable = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.slskd.vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.slskd = {
|
|
||||||
enable = true;
|
|
||||||
environmentFile = config.sops.secrets.slskd.path;
|
|
||||||
domain = null; # why isnt this the default?
|
|
||||||
settings = {
|
|
||||||
metrics = {
|
|
||||||
enabled = true;
|
|
||||||
authentication.disabled = true;
|
|
||||||
};
|
|
||||||
remote_file_management = true;
|
|
||||||
shares.directories = ["/media/library/music"];
|
|
||||||
soulseek = {
|
|
||||||
listen_port = 26449;
|
|
||||||
description = "";
|
|
||||||
};
|
|
||||||
global = {
|
|
||||||
upload = {
|
|
||||||
slots = 50;
|
|
||||||
speed_limit = 10000;
|
|
||||||
};
|
|
||||||
download.speed_limit = 10000;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services.transmission.vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
|
|
||||||
services.transmission = {
|
|
||||||
enable = true;
|
|
||||||
package = pkgs.transmission_4;
|
|
||||||
performanceNetParameters = true;
|
|
||||||
settings = let
|
|
||||||
mbit = 125;
|
|
||||||
in {
|
|
||||||
speed-limit-up-enabled = true;
|
|
||||||
speed-limit-up = 100 * mbit;
|
|
||||||
speed-limit-down-enabled = true;
|
|
||||||
speed-limit-down = 150 * mbit;
|
|
||||||
rpc-authentication-required = true;
|
|
||||||
peer-port = 11936;
|
|
||||||
rpc-bind-address = "0.0.0.0";
|
|
||||||
rpc-whitelist = "127.0.0.1,192.168.\*.\*";
|
|
||||||
};
|
|
||||||
credentialsFile = config.sops.secrets.transmission.path;
|
|
||||||
};
|
|
||||||
|
|
||||||
boot.kernel.sysctl."fs.inotify.max_user_watches" = 99999999;
|
boot.kernel.sysctl."fs.inotify.max_user_watches" = 99999999;
|
||||||
|
|
||||||
services.adguardhome = {
|
|
||||||
enable = true;
|
|
||||||
mutableSettings = false;
|
|
||||||
port = adguardWebPort;
|
|
||||||
settings = {
|
|
||||||
dhcp.enabled = false;
|
|
||||||
dns = {
|
|
||||||
upstream_dns = [
|
|
||||||
"quic://dns.nextdns.io"
|
|
||||||
"https://cloudflare-dns.com/dns-query"
|
|
||||||
"tls://unfiltered.adguard-dns.com"
|
|
||||||
"https://dns10.quad9.net/dns-query"
|
|
||||||
];
|
|
||||||
bind_hosts = ["100.115.105.144"];
|
|
||||||
bootstrap_dns = ["1.1.1.1" "8.8.8.8"];
|
|
||||||
};
|
|
||||||
filtering = {
|
|
||||||
rewrites = [
|
|
||||||
{
|
|
||||||
domain = "*.hopper.xun.host";
|
|
||||||
answer = "100.115.105.144";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
domain = "hopper.xun.host";
|
|
||||||
answer = "100.115.105.144";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
filters = [
|
|
||||||
{
|
|
||||||
name = "OISD (Big)";
|
|
||||||
url = "https://big.oisd.nl";
|
|
||||||
enabled = true;
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.${config.services.navidrome.group}.members = ["caddy"]; # for caddy to access socket file
|
|
||||||
services.navidrome = {
|
|
||||||
enable = true;
|
|
||||||
settings = {
|
|
||||||
MusicFolder = "/media/library/music";
|
|
||||||
Address = "unix:/var/lib/navidrome/navidrome.sock";
|
|
||||||
EnableSharing = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
systemd.services.navidrome.serviceConfig.EnvironmentFile = config.sops.secrets.navidrome.path;
|
|
||||||
|
|
||||||
systemd.services.vaultwarden = {
|
|
||||||
serviceConfig.EnvironmentFile = config.sops.secrets.vaultwarden-env.path;
|
|
||||||
vpnConfinement = {
|
|
||||||
enable = true;
|
|
||||||
vpnNamespace = "wg";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
# NOTE send doesnt work, probably due to my cloudflare port rewriting rules
|
|
||||||
services.vaultwarden = {
|
|
||||||
enable = true;
|
|
||||||
config = {
|
|
||||||
DOMAIN = "https://${domain}:${toString caddyPort}";
|
|
||||||
ROCKET_ADDRESS = "127.0.0.1";
|
|
||||||
ROCKET_PORT = 35381;
|
|
||||||
ROCKET_LOG = "critical";
|
|
||||||
SIGNUPS_ALLOWED = false;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.restic.backups.hopper = {
|
|
||||||
initialize = true;
|
|
||||||
inhibitsSleep = true;
|
|
||||||
repository = "rest:http://nixdesk:8000/hopper";
|
|
||||||
passwordFile = config.sops.secrets.restic-password.path;
|
|
||||||
timerConfig = {
|
|
||||||
OnCalendar = "18:00";
|
|
||||||
Persistent = true;
|
|
||||||
RandomizedDelaySec = "1h";
|
|
||||||
};
|
|
||||||
pruneOpts = [
|
|
||||||
"--keep-daily 7"
|
|
||||||
"--keep-weekly 5"
|
|
||||||
"--keep-monthly 12"
|
|
||||||
"--keep-yearly 2"
|
|
||||||
];
|
|
||||||
paths = [
|
|
||||||
"/var/lib/navidrome"
|
|
||||||
"/var/lib/jellyfin/data"
|
|
||||||
"/var/lib/jellyfin/config"
|
|
||||||
"/var/lib/bitwarden_rs"
|
|
||||||
"/media/library/music"
|
|
||||||
];
|
|
||||||
exclude = [
|
|
||||||
"/var/lib/navidrome/cache"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
75
sys/machines/hopper/lab/homepage.nix
Normal file
75
sys/machines/hopper/lab/homepage.nix
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
{config, ...}: {
|
||||||
|
systemd.services.homepage-dashboard.vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.homepage-dashboard = {
|
||||||
|
enable = true;
|
||||||
|
widgets = [
|
||||||
|
{
|
||||||
|
resources = {
|
||||||
|
cpu = true;
|
||||||
|
disk = "/";
|
||||||
|
uptime = "";
|
||||||
|
units = "metric";
|
||||||
|
cputemp = true;
|
||||||
|
memory = true;
|
||||||
|
network = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
services = [
|
||||||
|
{
|
||||||
|
"Downloading" = [
|
||||||
|
{
|
||||||
|
"transmission" = {
|
||||||
|
href = "http://transmission.hopper.xun.host";
|
||||||
|
icon = "transmission";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"slskd" = {
|
||||||
|
href = "http://slskd.hopper.xun.host";
|
||||||
|
icon = "slskd";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"Services" = [
|
||||||
|
{
|
||||||
|
"jellyfin" = {
|
||||||
|
href = "https://jellyfin.xunuwu.xyz";
|
||||||
|
icon = "jellyfin";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"navidrome" = {
|
||||||
|
href = "https://navidrome.xunuwu.xyz";
|
||||||
|
icon = "navidrome";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"adguard home" = {
|
||||||
|
href = "http://${config.networking.hostName}:${toString config.services.adguardhome.port}";
|
||||||
|
icon = "adguard-home";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"prometheus" = {
|
||||||
|
href = "http://${config.networking.hostName}:${toString config.services.prometheus.port}";
|
||||||
|
icon = "prometheus";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
"vaultwarden" = {
|
||||||
|
href = "https://vw.xunuwu.xyz";
|
||||||
|
icon = "vaultwarden";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
12
sys/machines/hopper/lab/jellyfin.nix
Normal file
12
sys/machines/hopper/lab/jellyfin.nix
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
systemd.services.jellyfin.vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
services.jellyfin.enable = true;
|
||||||
|
|
||||||
|
services.restic.backups.hopper.paths = [
|
||||||
|
"/var/lib/jellyfin/data"
|
||||||
|
"/var/lib/jellyfin/config"
|
||||||
|
];
|
||||||
|
}
|
17
sys/machines/hopper/lab/navidrome.nix
Normal file
17
sys/machines/hopper/lab/navidrome.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{config, ...}: {
|
||||||
|
users.groups.${config.services.navidrome.group}.members = ["caddy"]; # for caddy to access socket file
|
||||||
|
services.navidrome = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
MusicFolder = "/media/library/music";
|
||||||
|
Address = "unix:/var/lib/navidrome/navidrome.sock";
|
||||||
|
EnableSharing = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.services.navidrome.serviceConfig.EnvironmentFile = config.sops.secrets.navidrome.path;
|
||||||
|
|
||||||
|
services.restic.backups.hopper = {
|
||||||
|
paths = ["/var/lib/navidrome"];
|
||||||
|
exclude = ["/var/lib/navidrome/cache"];
|
||||||
|
};
|
||||||
|
}
|
33
sys/machines/hopper/lab/prometheus.nix
Normal file
33
sys/machines/hopper/lab/prometheus.nix
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
services.prometheus = {
|
||||||
|
enable = true;
|
||||||
|
port = 9001;
|
||||||
|
extraFlags = ["--storage.tsdb.retention.time=30d"];
|
||||||
|
scrapeConfigs = [
|
||||||
|
{
|
||||||
|
job_name = "node";
|
||||||
|
static_configs = lib.singleton {
|
||||||
|
targets = ["127.0.0.1:${toString config.services.prometheus.exporters.node.port}"];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
job_name = "tailscale_client";
|
||||||
|
static_configs = lib.singleton {
|
||||||
|
targets = ["100.100.100.100"];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.prometheus.exporters = {
|
||||||
|
node = {
|
||||||
|
enable = true;
|
||||||
|
enabledCollectors = ["systemd"];
|
||||||
|
};
|
||||||
|
systemd.enable = true;
|
||||||
|
};
|
||||||
|
}
|
22
sys/machines/hopper/lab/restic.nix
Normal file
22
sys/machines/hopper/lab/restic.nix
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{config, ...}: {
|
||||||
|
services.restic.backups.hopper = {
|
||||||
|
initialize = true;
|
||||||
|
inhibitsSleep = true;
|
||||||
|
repository = "rest:http://nixdesk:8000/hopper";
|
||||||
|
passwordFile = config.sops.secrets.restic-password.path;
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "18:00";
|
||||||
|
Persistent = true;
|
||||||
|
RandomizedDelaySec = "1h";
|
||||||
|
};
|
||||||
|
pruneOpts = [
|
||||||
|
"--keep-daily 7"
|
||||||
|
"--keep-weekly 5"
|
||||||
|
"--keep-monthly 12"
|
||||||
|
"--keep-yearly 2"
|
||||||
|
];
|
||||||
|
paths = [
|
||||||
|
"/media/library/music"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
}
|
|
@ -62,4 +62,6 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.restic.backups.hopper.paths = ["/srv/vault"];
|
||||||
}
|
}
|
||||||
|
|
31
sys/machines/hopper/lab/slskd.nix
Normal file
31
sys/machines/hopper/lab/slskd.nix
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{config, ...}: {
|
||||||
|
systemd.services.slskd.vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.slskd = {
|
||||||
|
enable = true;
|
||||||
|
environmentFile = config.sops.secrets.slskd.path;
|
||||||
|
domain = null; # why isnt this the default?
|
||||||
|
settings = {
|
||||||
|
metrics = {
|
||||||
|
enabled = true;
|
||||||
|
authentication.disabled = true;
|
||||||
|
};
|
||||||
|
remote_file_management = true;
|
||||||
|
shares.directories = ["/media/library/music"];
|
||||||
|
soulseek = {
|
||||||
|
listen_port = 26449;
|
||||||
|
description = "";
|
||||||
|
};
|
||||||
|
global = {
|
||||||
|
upload = {
|
||||||
|
slots = 50;
|
||||||
|
speed_limit = 10000;
|
||||||
|
};
|
||||||
|
download.speed_limit = 10000;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
29
sys/machines/hopper/lab/transmission.nix
Normal file
29
sys/machines/hopper/lab/transmission.nix
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
systemd.services.transmission.vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
|
||||||
|
services.transmission = {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.transmission_4;
|
||||||
|
performanceNetParameters = true;
|
||||||
|
settings = let
|
||||||
|
mbit = 125;
|
||||||
|
in {
|
||||||
|
speed-limit-up-enabled = true;
|
||||||
|
speed-limit-up = 100 * mbit;
|
||||||
|
speed-limit-down-enabled = true;
|
||||||
|
speed-limit-down = 150 * mbit;
|
||||||
|
rpc-authentication-required = true;
|
||||||
|
peer-port = 11936;
|
||||||
|
rpc-bind-address = "0.0.0.0";
|
||||||
|
rpc-whitelist = "127.0.0.1,192.168.\*.\*";
|
||||||
|
};
|
||||||
|
credentialsFile = config.sops.secrets.transmission.path;
|
||||||
|
};
|
||||||
|
}
|
22
sys/machines/hopper/lab/vaultwarden.nix
Normal file
22
sys/machines/hopper/lab/vaultwarden.nix
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
{config, ...}: {
|
||||||
|
systemd.services.vaultwarden = {
|
||||||
|
serviceConfig.EnvironmentFile = config.sops.secrets.vaultwarden-env.path;
|
||||||
|
vpnConfinement = {
|
||||||
|
enable = true;
|
||||||
|
vpnNamespace = "wg";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
# NOTE send doesnt work, probably due to my cloudflare port rewriting rules
|
||||||
|
services.vaultwarden = {
|
||||||
|
enable = true;
|
||||||
|
config = {
|
||||||
|
DOMAIN = "https://${config.services.caddy.virtualHosts.vw.hostName}";
|
||||||
|
ROCKET_ADDRESS = "127.0.0.1";
|
||||||
|
ROCKET_PORT = 35381;
|
||||||
|
ROCKET_LOG = "critical";
|
||||||
|
SIGNUPS_ALLOWED = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.restic.backups.hopper.paths = ["/var/lib/bitwarden_rs"];
|
||||||
|
}
|
49
sys/machines/hopper/lab/vpn-namespace.nix
Normal file
49
sys/machines/hopper/lab/vpn-namespace.nix
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}: {
|
||||||
|
vpnNamespaces."wg" = {
|
||||||
|
enable = true;
|
||||||
|
wireguardConfigFile = config.sops.secrets.wireguard.path;
|
||||||
|
accessibleFrom = [
|
||||||
|
"192.168.0.0/24"
|
||||||
|
# "127.0.0.1"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Forwarded to my vpn, for making things accessible from outside
|
||||||
|
openVPNPorts = [
|
||||||
|
{
|
||||||
|
port = 8336;
|
||||||
|
protocol = "tcp";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
port = config.services.slskd.settings.soulseek.listen_port;
|
||||||
|
protocol = "both";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
port = config.services.slskd.settings.soulseek.listen_port + 1;
|
||||||
|
protocol = "both";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
port = config.services.transmission.settings.peer-port;
|
||||||
|
protocol = "both";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# From inside of the vpn namespace to outside of it, for making things inside accessible to LAN
|
||||||
|
portMappings = let
|
||||||
|
passthrough = [
|
||||||
|
8336 # caddy
|
||||||
|
80 # caddy
|
||||||
|
443 # caddy
|
||||||
|
1900 # jellyfin discovery
|
||||||
|
7359 # jellyfin discovery
|
||||||
|
];
|
||||||
|
in (lib.map (x: {
|
||||||
|
from = x;
|
||||||
|
to = x;
|
||||||
|
})
|
||||||
|
passthrough);
|
||||||
|
};
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue