deploy wireguard

This commit is contained in:
Yan Lin 2026-02-18 23:04:21 +01:00
parent a47d096503
commit e097126817
7 changed files with 84 additions and 202 deletions

View file

@ -1,67 +0,0 @@
{ config, ... }:
{
# Traefik dynamic configuration for vps host
services.traefik.dynamic.files."proxy".settings = {
http = {
serversTransports = {
longTimeout = {
forwardingTimeouts = {
dialTimeout = "30s";
responseHeaderTimeout = "1200s";
idleConnTimeout = "1200s";
};
};
};
routers = {
deluge = {
rule = "Host(`deluge.home.yanlincs.com`)";
service = "deluge";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.home.yanlincs.com";
}];
};
};
photo = {
rule = "Host(`photo.home.yanlincs.com`)";
service = "photo";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.home.yanlincs.com";
}];
};
};
};
services = {
deluge = {
loadBalancer = {
servers = [{
url = "http://127.0.0.1:8112";
}];
};
};
photo = {
loadBalancer = {
serversTransport = "longTimeout";
servers = [{
url = "http://127.0.0.1:8080";
}];
};
};
};
};
};
}

View file

@ -4,11 +4,9 @@
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
./containers.nix ./containers.nix
./proxy.nix
../system-default.nix ../system-default.nix
../../../modules/vpn/tailscale.nix ../../../modules/vpn/wireguard.nix
../../../modules/podman.nix ../../../modules/podman.nix
../../../modules/traefik.nix
../../../modules/borg/client.nix ../../../modules/borg/client.nix
../../../modules/media/server.nix ../../../modules/media/server.nix
../../../modules/file-server/samba.nix ../../../modules/file-server/samba.nix
@ -132,9 +130,14 @@
}; };
}; };
services.tailscale-custom = { services.wireguard-custom = {
exitNode = true; enable = true;
subnetRoutes = [ "10.1.1.0/24" ]; mode = "client";
clientConfig = {
address = "10.2.2.10/24";
serverPublicKey = "46QHjSzAas5g9Hll1SCEu9tbR5owCxXAy6wGOUoPwUM=";
serverEndpoint = "91.98.84.215:51820";
};
}; };
# Media server services # Media server services

View file

@ -38,6 +38,17 @@
}; };
}; };
deluge = {
rule = "Host(`deluge.yanlincs.com`)";
service = "deluge";
tls = {
certResolver = "cloudflare";
domains = [{
main = "*.yanlincs.com";
}];
};
};
git = { git = {
rule = "Host(`git.yanlincs.com`)"; rule = "Host(`git.yanlincs.com`)";
service = "git"; service = "git";
@ -57,7 +68,7 @@
loadBalancer = { loadBalancer = {
serversTransport = "longTimeout"; serversTransport = "longTimeout";
servers = [{ servers = [{
url = "http://10.1.1.152:8080"; url = "http://10.2.2.10:8080";
}]; }];
}; };
}; };
@ -65,7 +76,15 @@
music = { music = {
loadBalancer = { loadBalancer = {
servers = [{ servers = [{
url = "http://10.1.1.152:4533"; url = "http://10.2.2.10:4533";
}];
};
};
deluge = {
loadBalancer = {
servers = [{
url = "http://10.2.2.10:8112";
}]; }];
}; };
}; };

View file

@ -6,7 +6,7 @@
./containers.nix ./containers.nix
./proxy.nix ./proxy.nix
../system-default.nix ../system-default.nix
../../../modules/vpn/tailscale.nix ../../../modules/vpn/wireguard.nix
../../../modules/podman.nix ../../../modules/podman.nix
../../../modules/traefik.nix ../../../modules/traefik.nix
../../../modules/borg/client.nix ../../../modules/borg/client.nix
@ -44,7 +44,6 @@
firewall = { firewall = {
enable = true; enable = true;
allowedTCPPorts = [ 22 80 443 27017 ]; allowedTCPPorts = [ 22 80 443 27017 ];
trustedInterfaces = [ "tailscale0" ];
}; };
}; };
@ -71,7 +70,17 @@
]; ];
}; };
services.tailscale-custom.exitNode = true; services.wireguard-custom = {
enable = true;
mode = "server";
serverConfig = {
address = "10.2.2.1/24";
peers = [{
publicKey = "MCuSF/aFZy7Jq3nI6VpU7jbfZOuEGuMjgpxRWazxtmY=";
allowedIPs = [ "10.2.2.10/32" ];
}];
};
};
services.git-server-custom = { services.git-server-custom = {
enable = true; enable = true;

View file

@ -49,6 +49,7 @@ in
}; };
service.DISABLE_REGISTRATION = true; service.DISABLE_REGISTRATION = true;
actions.ENABLED = true; actions.ENABLED = true;
repository.DISABLE_DOWNLOAD_SOURCE_ARCHIVES = true;
}; };
}; };

View file

@ -2,6 +2,8 @@
{ {
config = { config = {
boot.kernel.sysctl."net.ipv4.conf.all.forwarding" = true;
virtualisation = { virtualisation = {
podman = { podman = {
enable = true; enable = true;

View file

@ -1,5 +1,4 @@
# NOTE: Private key file at: `/etc/wireguard/private.key` with mode 600 # NOTE: After deploy, get public key with: `sudo sh -c 'wg pubkey < /etc/wireguard/private.key'`
# Generate with: `wg genkey > /etc/wireguard/private.key`
{ config, pkgs, lib, ... }: { config, pkgs, lib, ... }:
@ -12,192 +11,108 @@ in
{ {
options.services.wireguard-custom = { options.services.wireguard-custom = {
enable = mkEnableOption "WireGuard VPN"; enable = mkEnableOption "WireGuard VPN";
mode = mkOption { mode = mkOption {
type = types.enum [ "server" "client" ]; type = types.enum [ "server" "client" ];
description = "Whether to run as server (hub) or client (spoke)";
};
interface = mkOption {
type = types.str;
default = "wg0";
description = "WireGuard interface name";
};
listenPort = mkOption {
type = types.port;
default = 51820;
description = "UDP port to listen on (server mode only)";
}; };
privateKeyFile = mkOption {
type = types.str;
default = "/etc/wireguard/private.key";
description = "Path to private key file";
};
serverConfig = mkOption { serverConfig = mkOption {
type = types.submodule { type = types.submodule {
options = { options = {
address = mkOption { address = mkOption {
type = types.str; type = types.str;
example = "10.2.2.1/24"; example = "10.2.2.1/24";
description = "Server IP address with CIDR";
}; };
peers = mkOption { peers = mkOption {
type = types.listOf (types.submodule { type = types.listOf (types.submodule {
options = { options = {
name = mkOption { publicKey = mkOption { type = types.str; };
type = types.str; allowedIPs = mkOption { type = types.listOf types.str; };
description = "Peer name for identification";
};
publicKey = mkOption {
type = types.str;
description = "Peer's public key";
};
allowedIPs = mkOption {
type = types.listOf types.str;
description = "IP addresses this peer is allowed to use";
};
}; };
}); });
default = []; default = [];
description = "List of client peers";
}; };
}; };
}; };
description = "Server-specific configuration";
}; };
clientConfig = mkOption { clientConfig = mkOption {
type = types.submodule { type = types.submodule {
options = { options = {
address = mkOption { address = mkOption {
type = types.str; type = types.str;
example = "10.2.2.20/24"; example = "10.2.2.2/24";
description = "Client IP address with CIDR";
}; };
serverPublicKey = mkOption { serverPublicKey = mkOption { type = types.str; };
type = types.str;
description = "Server's public key";
};
serverEndpoint = mkOption { serverEndpoint = mkOption {
type = types.str; type = types.str;
example = "vpn.example.com:51820"; example = "vpn.example.com:51820";
description = "Server endpoint (host:port)";
}; };
allowedIPs = mkOption { allowedIPs = mkOption {
type = types.listOf types.str; type = types.listOf types.str;
default = [ "10.2.2.0/24" ]; default = [ "10.2.2.0/24" ];
description = "IP ranges to route through the tunnel";
}; };
}; };
}; };
description = "Client-specific configuration";
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
# Install WireGuard tools environment.systemPackages = [ pkgs.wireguard-tools ];
environment.systemPackages = with pkgs; [ wireguard-tools ];
# Create private key file if it doesn't exist
systemd.tmpfiles.rules = [ systemd.tmpfiles.rules = [
"d /etc/wireguard 0700 root root - -" "d /etc/wireguard 0700 root root - -"
"f ${cfg.privateKeyFile} 0600 root root - -" "f /etc/wireguard/private.key 0600 root root - -"
]; ];
# Generate private key on first run
systemd.services.wireguard-keygen = { systemd.services.wireguard-keygen = {
description = "Generate WireGuard private key"; description = "Generate WireGuard private key";
before = [ "wg-quick-${cfg.interface}.service" ]; before = [ "wg-quick-wg0.service" ];
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
serviceConfig = { serviceConfig = {
Type = "oneshot"; Type = "oneshot";
RemainAfterExit = true; RemainAfterExit = true;
}; };
script = '' script = ''
if [ ! -s ${cfg.privateKeyFile} ]; then if [ ! -s /etc/wireguard/private.key ]; then
echo "Generating WireGuard private key..." ${pkgs.wireguard-tools}/bin/wg genkey > /etc/wireguard/private.key
${pkgs.wireguard-tools}/bin/wg genkey > ${cfg.privateKeyFile} chmod 600 /etc/wireguard/private.key
chmod 600 ${cfg.privateKeyFile} echo "Public key: $(${pkgs.wireguard-tools}/bin/wg pubkey < /etc/wireguard/private.key)"
echo "Private key generated. Public key:"
${pkgs.wireguard-tools}/bin/wg pubkey < ${cfg.privateKeyFile}
echo "Please add this public key to your peer configurations."
fi fi
''; '';
}; };
# WireGuard interface configuration (combined server and client) networking.wg-quick.interfaces.wg0 = mkMerge [
networking.wg-quick.interfaces = { { privateKeyFile = "/etc/wireguard/private.key"; }
${cfg.interface} = mkMerge [
# Common configuration
{
privateKeyFile = cfg.privateKeyFile;
}
# Server-specific configuration
(mkIf (cfg.mode == "server") {
address = [ cfg.serverConfig.address ];
listenPort = cfg.listenPort;
# Enable IP forwarding and NAT for server
preUp = ''
${pkgs.iptables}/bin/iptables -A FORWARD -i ${cfg.interface} -j ACCEPT
${pkgs.iptables}/bin/iptables -A FORWARD -o ${cfg.interface} -j ACCEPT
${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.2.2.0/24 -o eth0 -j MASQUERADE
'';
postDown = ''
${pkgs.iptables}/bin/iptables -D FORWARD -i ${cfg.interface} -j ACCEPT
${pkgs.iptables}/bin/iptables -D FORWARD -o ${cfg.interface} -j ACCEPT
${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.2.2.0/24 -o eth0 -j MASQUERADE
'';
peers = map (peer: {
publicKey = peer.publicKey;
allowedIPs = peer.allowedIPs;
}) cfg.serverConfig.peers;
})
# Client-specific configuration
(mkIf (cfg.mode == "client") {
address = [ cfg.clientConfig.address ];
peers = [{
publicKey = cfg.clientConfig.serverPublicKey;
allowedIPs = cfg.clientConfig.allowedIPs;
endpoint = cfg.clientConfig.serverEndpoint;
persistentKeepalive = 25;
}];
})
];
};
# Firewall configuration
networking.firewall = mkMerge [
# Server firewall rules
(mkIf (cfg.mode == "server") { (mkIf (cfg.mode == "server") {
allowedUDPPorts = [ cfg.listenPort ]; address = [ cfg.serverConfig.address ];
trustedInterfaces = [ cfg.interface ]; listenPort = 51820;
peers = map (peer: {
inherit (peer) publicKey allowedIPs;
}) cfg.serverConfig.peers;
}) })
# Client firewall rules
(mkIf (cfg.mode == "client") { (mkIf (cfg.mode == "client") {
trustedInterfaces = [ cfg.interface ]; address = [ cfg.clientConfig.address ];
peers = [{
publicKey = cfg.clientConfig.serverPublicKey;
allowedIPs = cfg.clientConfig.allowedIPs;
endpoint = cfg.clientConfig.serverEndpoint;
persistentKeepalive = 25;
}];
}) })
]; ];
# Enable IP forwarding for server networking.firewall = mkMerge [
boot.kernel.sysctl = mkIf (cfg.mode == "server") { (mkIf (cfg.mode == "server") {
"net.ipv4.ip_forward" = 1; allowedUDPPorts = [ 51820 ];
"net.ipv6.conf.all.forwarding" = 1; })
}; { trustedInterfaces = [ "wg0" ]; }
];
}; };
} }