feat: add internal proxy to high-volume applications at home

This commit is contained in:
oddlama 2024-05-20 02:30:17 +02:00
parent b01c521830
commit 20a5e1e66a
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
32 changed files with 301 additions and 21 deletions

View file

@ -5,6 +5,7 @@
...
}: let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
in {
meta.promtail = {
enable = true;
@ -12,7 +13,12 @@ in {
};
# Connect safely via wireguard to skip http authentication
networking.hosts.${sentinelCfg.wireguard.proxy-sentinel.ipv4} = [sentinelCfg.networking.providedDomains.influxdb];
networking.hosts.${
if config.wireguard ? proxy-home
then wardWebProxyCfg.wireguard.proxy-home.ipv4
else sentinelCfg.wireguard.proxy-sentinel.ipv4
} = [sentinelCfg.networking.providedDomains.influxdb];
meta.telegraf = lib.mkIf (!config.boot.isContainer) {
enable = true;
scrapeSensors = false;

View file

@ -4,6 +4,7 @@
...
}: let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
grafanaDomain = "grafana.${config.repo.secrets.global.domains.me}";
in {
wireguard.proxy-sentinel = {
@ -116,6 +117,11 @@ in {
}
];
networking.hosts.${wardWebProxyCfg.wireguard.proxy-home.ipv4} = [
sentinelCfg.networking.providedDomains.influxdb # technically a duplicate (see ./common.nix)...
sentinelCfg.networking.providedDomains.loki
];
services.grafana = {
enable = true;
settings = {

View file

@ -5,6 +5,7 @@
...
}: let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
immichDomain = "immich.${config.repo.secrets.global.domains.me}";
ipImmichMachineLearning = "10.89.0.10";
@ -169,10 +170,15 @@ in {
client.via = "sentinel";
firewallRuleForNode.sentinel.allowedTCPPorts = [2283];
};
wireguard.proxy-home = {
client.via = "ward";
firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [2283];
};
networking.nftables.chains.forward.into-immich-container = {
after = ["conntrack"];
rules = [
"iifname proxy-sentinel ip saddr ${sentinelCfg.wireguard.proxy-sentinel.ipv4} tcp dport 3001 accept"
"iifname proxy-home ip saddr ${wardWebProxyCfg.wireguard.proxy-home.ipv4} tcp dport 3001 accept"
"iifname podman1 oifname lan accept"
];
};
@ -202,6 +208,31 @@ in {
};
};
nodes.ward-web-proxy = {
services.nginx = {
upstreams.immich = {
servers."${config.wireguard.proxy-home.ipv4}:2283" = {};
extraConfig = ''
zone immich 64k;
keepalive 2;
'';
};
virtualHosts.${immichDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://immich";
proxyWebsockets = true;
};
extraConfig = ''
client_max_body_size 10G;
allow 192.168.1.0/24;
deny all;
'';
};
};
};
systemd.tmpfiles.settings = {
"10-immich" = {
${upload_folder}.d = {

View file

@ -6,6 +6,7 @@
...
}: let
sentinelCfg = nodes.sentinel.config;
wardCfg = nodes.ward.config;
influxdbDomain = "influxdb.${config.repo.secrets.global.domains.me}";
influxdbPort = 8086;
in {
@ -14,6 +15,11 @@ in {
firewallRuleForNode.sentinel.allowedTCPPorts = [influxdbPort];
};
wireguard.proxy-home = {
client.via = "ward";
firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [influxdbPort];
};
nodes.sentinel = {
networking.providedDomains.influxdb = influxdbDomain;
@ -50,6 +56,40 @@ in {
};
};
nodes.ward-web-proxy = {
services.nginx = {
upstreams.influxdb = {
servers."${config.wireguard.proxy-home.ipv4}:${toString influxdbPort}" = {};
extraConfig = ''
zone influxdb 64k;
keepalive 2;
'';
};
virtualHosts.${influxdbDomain} = let
accessRules = ''
${lib.concatMapStrings (ip: "allow ${ip};\n") wardCfg.wireguard.proxy-home.server.reservedAddresses}
deny all;
'';
in {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://influxdb";
proxyWebsockets = true;
extraConfig = accessRules;
};
locations."/api/v2/write" = {
proxyPass = "http://influxdb/api/v2/write";
proxyWebsockets = true;
extraConfig = ''
${accessRules}
access_log off;
'';
};
};
};
};
age.secrets.influxdb-admin-password = {
generator.script = "alnum";
mode = "440";

View file

@ -1,9 +1,12 @@
{
config,
lib,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
wardCfg = nodes.ward.config;
lokiDomain = "loki.${config.repo.secrets.global.domains.me}";
in {
wireguard.proxy-sentinel = {
@ -11,6 +14,11 @@ in {
firewallRuleForNode.sentinel.allowedTCPPorts = [config.services.loki.configuration.server.http_listen_port];
};
wireguard.proxy-home = {
client.via = "ward";
firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [config.services.loki.configuration.server.http_listen_port];
};
nodes.sentinel = {
networking.providedDomains.loki = lokiDomain;
@ -28,6 +36,51 @@ in {
keepalive 2;
'';
};
virtualHosts.${lokiDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations."/" = {
proxyPass = "http://loki";
proxyWebsockets = true;
extraConfig = ''
auth_basic "Authentication required";
auth_basic_user_file ${wardWebProxyCfg.age.secrets.loki-basic-auth-hashes.path};
proxy_read_timeout 1800s;
proxy_connect_timeout 1600s;
${lib.concatMapStrings (ip: "allow ${ip};\n") wardCfg.wireguard.proxy-home.server.reservedAddresses}
deny all;
access_log off;
'';
};
locations."= /ready" = {
proxyPass = "http://loki";
extraConfig = ''
auth_basic off;
access_log off;
'';
};
};
};
};
nodes.ward-web-proxy = {
age.secrets.loki-basic-auth-hashes = {
inherit (nodes.sentinel.config.age.secrets.loki-basic-auth-hashes) rekeyFile;
mode = "440";
group = "nginx";
};
services.nginx = {
upstreams.loki = {
servers."${config.wireguard.proxy-home.ipv4}:${toString config.services.loki.configuration.server.http_listen_port}" = {};
extraConfig = ''
zone loki 64k;
keepalive 2;
'';
};
virtualHosts.${lokiDomain} = {
forceSSL = true;
useACMEWildcardHost = true;

View file

@ -6,12 +6,23 @@
...
}: let
sentinelCfg = nodes.sentinel.config;
wardWebProxyCfg = nodes.ward-web-proxy.config;
paperlessDomain = "paperless.${config.repo.secrets.global.domains.me}";
paperlessBackupDir = "/var/cache/paperless-backup";
in {
microvm.mem = 1024 * 9;
microvm.vcpu = 8;
wireguard.proxy-sentinel = {
client.via = "sentinel";
firewallRuleForNode.sentinel.allowedTCPPorts = [config.services.paperless.port];
};
wireguard.proxy-home = {
client.via = "ward";
firewallRuleForNode.ward-web-proxy.allowedTCPPorts = [config.services.paperless.port];
};
nodes.sentinel = {
networking.providedDomains.paperless = paperlessDomain;
@ -38,9 +49,30 @@ in {
};
};
wireguard.proxy-sentinel = {
client.via = "sentinel";
firewallRuleForNode.sentinel.allowedTCPPorts = [config.services.paperless.port];
nodes.ward-web-proxy = {
services.nginx = {
upstreams.paperless = {
servers."${config.wireguard.proxy-home.ipv4}:${toString config.services.paperless.port}" = {};
extraConfig = ''
zone paperless 64k;
keepalive 2;
'';
};
virtualHosts.${paperlessDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
extraConfig = ''
client_max_body_size 512M;
allow 192.168.1.0/24;
deny all;
'';
locations."/" = {
proxyPass = "http://paperless";
proxyWebsockets = true;
X-Frame-Options = "SAMEORIGIN";
};
};
};
};
age.secrets.paperless-admin-password = {
@ -75,7 +107,10 @@ in {
PAPERLESS_URL = "https://${paperlessDomain}";
PAPERLESS_ALLOWED_HOSTS = paperlessDomain;
PAPERLESS_CORS_ALLOWED_HOSTS = "https://${paperlessDomain}";
PAPERLESS_TRUSTED_PROXIES = sentinelCfg.wireguard.proxy-sentinel.ipv4;
PAPERLESS_TRUSTED_PROXIES = lib.concatStringSep "," [
sentinelCfg.wireguard.proxy-sentinel.ipv4
wardWebProxyCfg.wireguard.proxy-home.ipv4
];
# Authentication via kanidm
PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect";

View file

@ -74,23 +74,26 @@ in {
];
dhcp.enabled = false;
};
filtering.rewrites = [
# Undo the /etc/hosts entry so we don't answer with the internal
# wireguard address for influxdb
{
domain = nodes.sentinel.config.networking.providedDomains.influxdb;
answer = config.repo.secrets.global.domains.me;
}
filtering.rewrites =
[
# Undo the /etc/hosts entry so we don't answer with the internal
# wireguard address for influxdb
{
domain = nodes.sentinel.config.networking.providedDomains.influxdb;
answer = config.repo.secrets.global.domains.me;
}
]
# Use the local mirror-proxy for some services (not necessary, just for speed)
{
domain = nodes.sentinel.config.networking.providedDomains.grafana;
answer = "192.168.1.4"; # web-proxy
}
{
domain = nodes.sentinel.config.networking.providedDomains.immich;
answer = "192.168.1.4"; # web-proxy
}
];
++ map (domain: {
inherit domain;
answer = "192.168.1.4";
}) [
nodes.sentinel.config.networking.providedDomains.grafana
nodes.sentinel.config.networking.providedDomains.immich
nodes.sentinel.config.networking.providedDomains.influxdb
nodes.sentinel.config.networking.providedDomains.loki
nodes.sentinel.config.networking.providedDomains.paperless
];
filters = [
{
name = "AdGuard DNS filter";