Compare commits
2 Commits
c1030c1dfe
...
f4a4edf478
| Author | SHA1 | Date | |
|---|---|---|---|
| f4a4edf478 | |||
| 1ac3f05e3e |
@@ -153,6 +153,13 @@ in
|
|||||||
description = "Prefix length derived from subnet CIDR";
|
description = "Prefix length derived from subnet CIDR";
|
||||||
readOnly = true;
|
readOnly = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Shared host entries for all containers (host + VPN + service containers)
|
||||||
|
containerHosts = mkOption {
|
||||||
|
type = types.attrsOf (types.listOf types.str);
|
||||||
|
internal = true;
|
||||||
|
readOnly = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = mkIf cfg.enable {
|
config = mkIf cfg.enable {
|
||||||
@@ -252,10 +259,12 @@ in
|
|||||||
# Host entries for container hostnames — NixOS only auto-creates these for
|
# Host entries for container hostnames — NixOS only auto-creates these for
|
||||||
# hostAddress/localAddress containers, not hostBridge. Use the standard
|
# hostAddress/localAddress containers, not hostBridge. Use the standard
|
||||||
# {name}.containers convention.
|
# {name}.containers convention.
|
||||||
networking.hosts =
|
pia-vpn.containerHosts =
|
||||||
{ ${cfg.vpnAddress} = [ "pia-vpn.containers" ]; }
|
{ ${cfg.vpnAddress} = [ "pia-vpn.containers" ]; }
|
||||||
// mapAttrs' (name: ctr: nameValuePair ctr.ip [ "${name}.containers" ]) cfg.containers;
|
// mapAttrs' (name: ctr: nameValuePair ctr.ip [ "${name}.containers" ]) cfg.containers;
|
||||||
|
|
||||||
|
networking.hosts = cfg.containerHosts;
|
||||||
|
|
||||||
# PIA login secret
|
# PIA login secret
|
||||||
age.secrets."pia-login.conf".file = ../../../secrets/pia-login.age;
|
age.secrets."pia-login.conf".file = ../../../secrets/pia-login.age;
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,29 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
networking.hosts = cfg.containerHosts;
|
||||||
|
|
||||||
# DNS through VPN container (queries go through WG tunnel = no DNS leak)
|
# DNS through VPN container (queries go through WG tunnel = no DNS leak)
|
||||||
networking.nameservers = [ cfg.vpnAddress ];
|
networking.nameservers = [ cfg.vpnAddress ];
|
||||||
|
|
||||||
|
# Wait for actual VPN connectivity before network-online.target.
|
||||||
|
# Without this, services start before the VPN tunnel is ready and failures
|
||||||
|
# can't be reported to ntfy (no outbound connectivity yet).
|
||||||
|
systemd.services.wait-for-vpn = {
|
||||||
|
description = "Wait for VPN connectivity";
|
||||||
|
before = [ "network-online.target" ];
|
||||||
|
wantedBy = [ "network-online.target" ];
|
||||||
|
after = [ "systemd-networkd-wait-online.service" ];
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
path = [ pkgs.iputils ];
|
||||||
|
script = ''
|
||||||
|
until ping -c1 -W2 1.1.1.1 >/dev/null 2>&1; do
|
||||||
|
echo "Waiting for VPN connectivity..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
# Trust the bridge interface (host reaches us directly for nginx)
|
# Trust the bridge interface (host reaches us directly for nginx)
|
||||||
networking.firewall.trustedInterfaces = [ "eth0" ];
|
networking.firewall.trustedInterfaces = [ "eth0" ];
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ in
|
|||||||
{
|
{
|
||||||
imports = allModules;
|
imports = allModules;
|
||||||
|
|
||||||
|
networking.hosts = cfg.containerHosts;
|
||||||
|
|
||||||
# Static IP on bridge — no gateway (VPN container routes via WG only)
|
# Static IP on bridge — no gateway (VPN container routes via WG only)
|
||||||
networking.useNetworkd = true;
|
networking.useNetworkd = true;
|
||||||
systemd.network.enable = true;
|
systemd.network.enable = true;
|
||||||
@@ -89,6 +91,9 @@ in
|
|||||||
# Ignore WG interface for wait-online (it's configured manually, not by networkd)
|
# Ignore WG interface for wait-online (it's configured manually, not by networkd)
|
||||||
systemd.network.wait-online.ignoredInterfaces = [ cfg.interfaceName ];
|
systemd.network.wait-online.ignoredInterfaces = [ cfg.interfaceName ];
|
||||||
|
|
||||||
|
# Route ntfy alerts through the host proxy (VPN container has no gateway on eth0)
|
||||||
|
ntfy-alerts.curlExtraArgs = "--proxy http://${cfg.hostAddress}:${toString cfg.proxyPort}";
|
||||||
|
|
||||||
# Enable forwarding so bridge traffic can go through WG
|
# Enable forwarding so bridge traffic can go through WG
|
||||||
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
boot.kernel.sysctl."net.ipv4.ip_forward" = 1;
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ in
|
|||||||
default = "service-failures";
|
default = "service-failures";
|
||||||
description = "ntfy topic to publish alerts to.";
|
description = "ntfy topic to publish alerts to.";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
curlExtraArgs = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
description = "Extra arguments to pass to curl (e.g. --proxy http://host:port).";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf config.thisMachine.hasRole."ntfy" {
|
config = lib.mkIf config.thisMachine.hasRole."ntfy" {
|
||||||
@@ -33,6 +39,7 @@ in
|
|||||||
${lib.getExe pkgs.curl} \
|
${lib.getExe pkgs.curl} \
|
||||||
--fail --silent --show-error \
|
--fail --silent --show-error \
|
||||||
--max-time 30 --retry 3 \
|
--max-time 30 --retry 3 \
|
||||||
|
${cfg.curlExtraArgs} \
|
||||||
-H "Authorization: Bearer $NTFY_TOKEN" \
|
-H "Authorization: Bearer $NTFY_TOKEN" \
|
||||||
-H "Title: Service failure on ${config.networking.hostName}" \
|
-H "Title: Service failure on ${config.networking.hostName}" \
|
||||||
-H "Priority: high" \
|
-H "Priority: high" \
|
||||||
|
|||||||
Reference in New Issue
Block a user