feat: nas add cyberghost
This commit is contained in:
@@ -13,7 +13,7 @@ in {
|
|||||||
./utils/modules/victoriametrics
|
./utils/modules/victoriametrics
|
||||||
./utils/modules/promtail
|
./utils/modules/promtail
|
||||||
|
|
||||||
# ./modules/cyberghost.nix
|
./modules/cyberghost.nix
|
||||||
./modules/pyload.nix
|
./modules/pyload.nix
|
||||||
./modules/jellyfin.nix
|
./modules/jellyfin.nix
|
||||||
./modules/power-management.nix
|
./modules/power-management.nix
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
let
|
let
|
||||||
localNetwork = "10.42.96.0/20";
|
localNetwork = "10.42.96.0/20";
|
||||||
|
vpnServer = "87-1-hu.cg-dialup.net";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# SOPS secrets for CyberGhost credentials
|
# SOPS secrets for CyberGhost credentials
|
||||||
@@ -23,10 +24,16 @@ in
|
|||||||
|
|
||||||
environment.systemPackages = [ pkgs.openvpn ];
|
environment.systemPackages = [ pkgs.openvpn ];
|
||||||
|
|
||||||
# OpenVPN client service
|
# Enable iproute2 for routing tables
|
||||||
|
networking.iproute2.enable = true;
|
||||||
|
networking.iproute2.rttablesExtraConfig = ''
|
||||||
|
100 vpn
|
||||||
|
'';
|
||||||
|
|
||||||
|
# OpenVPN client service - only establishes tunnel, no routing
|
||||||
services.openvpn.servers.cyberghost = {
|
services.openvpn.servers.cyberghost = {
|
||||||
autoStart = true;
|
autoStart = true;
|
||||||
updateResolvConf = true;
|
updateResolvConf = false;
|
||||||
config = ''
|
config = ''
|
||||||
client
|
client
|
||||||
dev tun
|
dev tun
|
||||||
@@ -53,51 +60,62 @@ in
|
|||||||
# Connection
|
# Connection
|
||||||
ping 5
|
ping 5
|
||||||
explicit-exit-notify 2
|
explicit-exit-notify 2
|
||||||
route-delay 5
|
|
||||||
|
|
||||||
# Split tunnel: Don't pull routes from server, we'll set our own
|
# Don't pull any routes - we manage routing ourselves
|
||||||
route-nopull
|
route-nopull
|
||||||
|
|
||||||
# Route all traffic through VPN except local network
|
|
||||||
route 0.0.0.0 128.0.0.0 vpn_gateway
|
|
||||||
route 128.0.0.0 128.0.0.0 vpn_gateway
|
|
||||||
|
|
||||||
# Keep local network route direct
|
|
||||||
route ${localNetwork} net_gateway
|
|
||||||
|
|
||||||
verb 4
|
verb 4
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Kill switch: Block outgoing traffic if VPN is down
|
# Systemd service to set up VPN routing after tunnel is up
|
||||||
networking.firewall = {
|
systemd.services.cyberghost-routing = {
|
||||||
extraCommands = ''
|
description = "CyberGhost VPN routing rules";
|
||||||
# Allow traffic to local network
|
after = [ "openvpn-cyberghost.service" ];
|
||||||
iptables -A OUTPUT -d ${localNetwork} -j ACCEPT
|
requires = [ "openvpn-cyberghost.service" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
# Allow traffic through VPN tunnel
|
serviceConfig = {
|
||||||
iptables -A OUTPUT -o tun+ -j ACCEPT
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = pkgs.writeShellScript "vpn-routing-up" ''
|
||||||
|
# Wait for tun0 to be available
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if ${pkgs.iproute2}/bin/ip link show tun0 &>/dev/null; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
# Allow loopback
|
# Add default route via VPN tunnel to table vpn
|
||||||
iptables -A OUTPUT -o lo -j ACCEPT
|
${pkgs.iproute2}/bin/ip route add default dev tun0 table vpn 2>/dev/null || true
|
||||||
|
|
||||||
# Allow established connections (for responses)
|
# Policy rules (lower number = higher priority)
|
||||||
iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
|
# VPN server traffic must use main table to avoid routing loop
|
||||||
|
# Resolve all IPs (hostname has multiple A records for load balancing)
|
||||||
|
for VPN_SERVER_IP in $(${pkgs.dig}/bin/dig +short ${vpnServer} A); do
|
||||||
|
${pkgs.iproute2}/bin/ip rule add to $VPN_SERVER_IP table main priority 50 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
# Allow OpenVPN to establish connection (UDP 443)
|
# Local network always uses main routing table
|
||||||
iptables -A OUTPUT -p udp --dport 443 -j ACCEPT
|
${pkgs.iproute2}/bin/ip rule add to ${localNetwork} table main priority 100 2>/dev/null || true
|
||||||
|
${pkgs.iproute2}/bin/ip rule add from ${localNetwork} table main priority 100 2>/dev/null || true
|
||||||
|
|
||||||
# Drop all other outgoing internet traffic (kill switch)
|
# Everything else goes through VPN
|
||||||
iptables -A OUTPUT ! -d ${localNetwork} -j DROP
|
${pkgs.iproute2}/bin/ip rule add table vpn priority 200 2>/dev/null || true
|
||||||
'';
|
'';
|
||||||
|
ExecStop = pkgs.writeShellScript "vpn-routing-down" ''
|
||||||
|
${pkgs.iproute2}/bin/ip rule del table vpn priority 200 2>/dev/null || true
|
||||||
|
${pkgs.iproute2}/bin/ip rule del from ${localNetwork} table main priority 100 2>/dev/null || true
|
||||||
|
${pkgs.iproute2}/bin/ip rule del to ${localNetwork} table main priority 100 2>/dev/null || true
|
||||||
|
|
||||||
extraStopCommands = ''
|
# Clean up all VPN server IP rules
|
||||||
iptables -D OUTPUT -d ${localNetwork} -j ACCEPT 2>/dev/null || true
|
for VPN_SERVER_IP in $(${pkgs.dig}/bin/dig +short ${vpnServer} A); do
|
||||||
iptables -D OUTPUT -o tun+ -j ACCEPT 2>/dev/null || true
|
${pkgs.iproute2}/bin/ip rule del to $VPN_SERVER_IP table main priority 50 2>/dev/null || true
|
||||||
iptables -D OUTPUT -o lo -j ACCEPT 2>/dev/null || true
|
done
|
||||||
iptables -D OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT 2>/dev/null || true
|
|
||||||
iptables -D OUTPUT -p udp --dport 443 -j ACCEPT 2>/dev/null || true
|
${pkgs.iproute2}/bin/ip route del default table vpn 2>/dev/null || true
|
||||||
iptables -D OUTPUT ! -d ${localNetwork} -j DROP 2>/dev/null || true
|
'';
|
||||||
'';
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user