Compare commits
15 Commits
Author | SHA1 | Date |
---|---|---|
Simon Bruder | 79fd82d0cd | |
Simon Bruder | 0048c6d523 | |
Simon Bruder | 79e4438d5a | |
Simon Bruder | 0ea90e3ee5 | |
Simon Bruder | b709aa6179 | |
Simon Bruder | 89612d38d3 | |
Simon Bruder | 1e5642ce81 | |
Simon Bruder | ca1fb06560 | |
Simon Bruder | 362243f7f6 | |
Simon Bruder | 3658865ad2 | |
Simon Bruder | ab035b2c44 | |
Simon Bruder | 2a425638e6 | |
Simon Bruder | 560fc237b7 | |
Simon Bruder | d733c5a802 | |
Simon Bruder | 133bb85357 |
91
flake.lock
91
flake.lock
|
@ -44,11 +44,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1692799911,
|
||||
"narHash": "sha256-3eihraek4qL744EvQXsK1Ha6C3CR7nnT8X2qWap4RNk=",
|
||||
"lastModified": 1694529238,
|
||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "f9e7cf818399d17d347f847525c5a5a8032e4e44",
|
||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -85,11 +85,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694465129,
|
||||
"narHash": "sha256-8BQiuobMrCfCbGM7w6Snx+OBYdtTIm0+cGVaKwQ5BFg=",
|
||||
"lastModified": 1695108154,
|
||||
"narHash": "sha256-gSg7UTVtls2yO9lKtP0yb66XBHT1Fx5qZSZbGMpSn2c=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "9787dffff5d315c9593d3f9fb0f9bf2097e1b57b",
|
||||
"rev": "07682fff75d41f18327a871088d20af2710d4744",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -106,11 +106,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694469544,
|
||||
"narHash": "sha256-eqZng5dZnAUyb7xXyFk5z871GY/++KVv3Gyld5mVh20=",
|
||||
"lastModified": 1695984718,
|
||||
"narHash": "sha256-LQwKgaaaFOkIcxarf0xQXeDJFwZ5BZWcgmPeo3xp2CM=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "5171f5ef654425e09d9c2100f856d887da595437",
|
||||
"rev": "4f02e35f9d150573e1a710afa338846c2f6d850c",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -180,6 +180,28 @@
|
|||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs-overlay",
|
||||
"poetry2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688870561,
|
||||
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
|
@ -193,11 +215,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694364351,
|
||||
"narHash": "sha256-oadhSCqopYXxURwIA6/Anpe5IAG11q2LhvTJNP5zE6o=",
|
||||
"lastModified": 1695576016,
|
||||
"narHash": "sha256-71KxwRhTfVuh7kNrg3/edNjYVg9DCyKZl2QIKbhRggg=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "4f883a76282bc28eb952570afc3d8a1bf6f481d7",
|
||||
"rev": "cb770e93516a1609652fa8e945a0f310e98f10c0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -209,11 +231,11 @@
|
|||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1694432324,
|
||||
"narHash": "sha256-bo3Gv6Cp40vAXDBPi2XiDejzp/kyz65wZg4AnEWxAcY=",
|
||||
"lastModified": 1695887975,
|
||||
"narHash": "sha256-u3+5FR12dI305jCMb0fJNQx2qwoQ54lv1tPoEWp0hmg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "ca41b8a227dd235b1b308217f116c7e6e84ad779",
|
||||
"rev": "adcfd6aa860d1d129055039696bc457af7d50d0e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -225,11 +247,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1694426803,
|
||||
"narHash": "sha256-osusXQo0zkEqs502SNMffsKp1O9evpDM54A37MuyT2Q=",
|
||||
"lastModified": 1695825837,
|
||||
"narHash": "sha256-4Ne11kNRnQsmSJCRSSNkFRSnHC4Y5gPDBIQGjjPfJiU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9a74ffb2ca1fc91c6ccc48bd3f8cbc1501bf7b8a",
|
||||
"rev": "5cfafa12d57374f48bcc36fda3274ada276cf69e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -253,11 +275,11 @@
|
|||
"poetry2nix": "poetry2nix"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1691841402,
|
||||
"narHash": "sha256-9WYGqa6hAxoTuqjSGsNivkHECIWsA/ksDETbFBzfSxM=",
|
||||
"lastModified": 1696421393,
|
||||
"narHash": "sha256-GarjKZ00NVXDgQZocnWvyhTWRm1LYZuZuJ4gEva+GGs=",
|
||||
"ref": "refs/heads/master",
|
||||
"rev": "3b8f90ed3a3828784f91800c32f1f83910ce966b",
|
||||
"revCount": 55,
|
||||
"rev": "c8a17806a75733dec2ecdd8f0021c70d1f9dfc43",
|
||||
"revCount": 62,
|
||||
"type": "git",
|
||||
"url": "https://git.sbruder.de/simon/nixpkgs-overlay"
|
||||
},
|
||||
|
@ -284,11 +306,11 @@
|
|||
},
|
||||
"nixpkgs-stable_2": {
|
||||
"locked": {
|
||||
"lastModified": 1693675694,
|
||||
"narHash": "sha256-2pIOyQwGyy2FtFAUIb8YeKVmOCcPOTVphbAvmshudLE=",
|
||||
"lastModified": 1694908564,
|
||||
"narHash": "sha256-ducA98AuWWJu5oUElIzN24Q22WlO8bOfixGzBgzYdVc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "5601118d39ca9105f8e7b39d4c221d3388c0419d",
|
||||
"rev": "596611941a74be176b98aeba9328aa9d01b8b322",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -300,11 +322,11 @@
|
|||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1694422566,
|
||||
"narHash": "sha256-lHJ+A9esOz9vln/3CJG23FV6Wd2OoOFbDeEs4cMGMqc=",
|
||||
"lastModified": 1695830400,
|
||||
"narHash": "sha256-gToZXQVr0G/1WriO83olnqrLSHF2Jb8BPcmCt497ro0=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3a2786eea085f040a66ecde1bc3ddc7099f6dbeb",
|
||||
"rev": "8a86b98f0ba1c405358f1b71ff8b5e1d317f5db2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -359,17 +381,18 @@
|
|||
"nixpkgs-overlay",
|
||||
"flake-utils"
|
||||
],
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"nixpkgs-overlay",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1682132397,
|
||||
"narHash": "sha256-NbIdSrx3Y1NioEEvoaOTETNTpq6m6bfoxmEt/C8GLAQ=",
|
||||
"lastModified": 1695386222,
|
||||
"narHash": "sha256-5lgnhCCGW0NH5+m5iTED8u6NSSM/dbH9LBPvX0x0XXg=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "e2d2c7a31485aeb801fa85da2d0fa103dd5112ef",
|
||||
"rev": "093383b3d7fdd36846a7d84e128ca11865800538",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -428,11 +451,11 @@
|
|||
"nixpkgs-stable": "nixpkgs-stable_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1694495315,
|
||||
"narHash": "sha256-sZEYXs9T1NVHZSSbMqBEtEm2PGa7dEDcx0ttQkArORc=",
|
||||
"lastModified": 1695284550,
|
||||
"narHash": "sha256-z9fz/wz9qo9XePEvdduf+sBNeoI9QG8NJKl5ssA8Xl4=",
|
||||
"owner": "Mic92",
|
||||
"repo": "sops-nix",
|
||||
"rev": "ea208e55f8742fdcc0986b256bdfa8986f5e4415",
|
||||
"rev": "2f375ed8702b0d8ee2430885059d5e7975e38f78",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -62,4 +62,9 @@ in
|
|||
|
||||
targetHost = "shinobu.home.sbruder.de";
|
||||
};
|
||||
nazuna = {
|
||||
system = "x86_64-linux";
|
||||
|
||||
targetHost = "nazuna.sbruder.de";
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# renge
|
||||
|
||||
## Hardware
|
||||
|
||||
[Hetzner Cloud](https://hetzner.com/cloud) CPX21 (3 AMD EPYC vCPU, 4 GB RAM, 80 GB SSD).
|
||||
|
||||
## Purpose
|
||||
|
||||
It will host most services that do not require large storage and benefit from high availability.
|
||||
|
||||
## Name
|
||||
|
||||
Renge Miyauchi is a character from *Non Non Biyori*
|
|
@ -0,0 +1,12 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
../../modules
|
||||
];
|
||||
|
||||
networking.hostName = "nazuna";
|
||||
|
||||
system.stateVersion = "23.05";
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
{ lib, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports = [
|
||||
(modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
|
||||
boot = {
|
||||
kernelParams = [ "ip=86.106.183.111/26::86.106.183.65::nazuna" ];
|
||||
initrd = {
|
||||
availableKernelModules = [ "ata_piix" "uhci_hcd" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
|
||||
kernelModules = [ "dm-snapshot" ];
|
||||
network.enable = true; # remote unlocking
|
||||
luks.devices."root".device = "/dev/disk/by-uuid/b20be409-adb6-47fc-ba9b-c07e61503070";
|
||||
};
|
||||
loader.grub.device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_drive-scsi0";
|
||||
};
|
||||
|
||||
fileSystems = {
|
||||
"/" = {
|
||||
device = "/dev/disk/by-uuid/05b0918e-3c24-45bf-950e-4af9d89d3be2";
|
||||
fsType = "btrfs";
|
||||
options = [ "compress=zstd" ];
|
||||
};
|
||||
"/boot" = {
|
||||
device = "/dev/disk/by-uuid/7e93d8ba-516b-424e-a8e5-149c1654212a";
|
||||
fsType = "ext2";
|
||||
};
|
||||
};
|
||||
|
||||
swapDevices = [
|
||||
{
|
||||
device = "/dev/disk/by-partuuid/08140a4b-38d7-4af3-b302-ccc952b085eb";
|
||||
randomEncryption.enable = true;
|
||||
}
|
||||
];
|
||||
|
||||
networking = {
|
||||
useDHCP = false;
|
||||
usePredictableInterfaceNames = false;
|
||||
};
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
networks = {
|
||||
eth0 = {
|
||||
name = "eth0";
|
||||
DHCP = "yes";
|
||||
domains = [ "sbruder.de" ];
|
||||
address = [ "86.106.183.111/26" "2a0d:f302:123:8d61::1/64" ];
|
||||
gateway = [ "86.106.183.65" "2a0d:f302:123::1" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# no smart on qemu disk
|
||||
services.smartd.enable = false;
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
../../modules
|
||||
|
||||
./services/co2_exporter.nix
|
||||
./services/router.nix
|
||||
./services/router
|
||||
];
|
||||
|
||||
sbruder = {
|
||||
|
|
|
@ -1,439 +0,0 @@
|
|||
# Home network configuration
|
||||
# (2.5GbE clients)
|
||||
# | |
|
||||
# +----------+ +----------+
|
||||
# | | | | | | (1GbE clients)
|
||||
# | | | | | +|-|-|-|-|+
|
||||
# +---+----+ +-+-+-+-+-+ |5 4 3 2 1|
|
||||
# |upstream| | 1 2 3 4 | |TL-SG105 |
|
||||
# +--------+ | shinobu | +---------+
|
||||
# +---------+
|
||||
#
|
||||
# It consists of shinobu as a router (this configuration),
|
||||
# connected to a TP-LINK TL-SG105E “smart managed” (i.e., it can do VLANs) 5-port switch.
|
||||
# The upstream comes (for now) from a PŸUR “WLAN-Kabelbox” (Compal CH7467CE).
|
||||
# Sadly, I could not enable bridge mode on it, so the packets now go through (at least) four layers of NAT:
|
||||
# device → NAT on shinobu (→ NAT on plastic router → PŸUR CGNAT) → NAT on VPN
|
||||
#
|
||||
# Because the switch only supports GbE,
|
||||
# the two clients I currently have with support for 2.5GbE are connected
|
||||
# directly to the two remaining network interfaces on shinobu.
|
||||
# Once I have more devices with support for 2.5GbE
|
||||
# or I find a good deal on a matching switch,
|
||||
# I will change this.
|
||||
#
|
||||
# Wireless is configured by providing the whole hostapd configuration file as a secret.
|
||||
# Once nixpkgs PR 222536 is merged, I will migrate to using the NixOS module.
|
||||
# Thanks to Intel’s wisdom, it’s not possible to use 5GHz in AP mode.
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
domain = "home.sbruder.de";
|
||||
|
||||
vpnBypassFwMark = 10000;
|
||||
in
|
||||
{
|
||||
sops.secrets.wg-upstream-private-key = {
|
||||
owner = config.users.users.systemd-network.name;
|
||||
sopsFile = ../secrets.yaml;
|
||||
};
|
||||
sops.secrets.hostapd-config = {
|
||||
sopsFile = ../secrets.yaml;
|
||||
};
|
||||
|
||||
boot.kernel.sysctl = {
|
||||
"net.ipv4.conf.all.forwarding" = true;
|
||||
"net.ipv6.conf.all.forwarding" = true;
|
||||
};
|
||||
|
||||
networking = {
|
||||
# networkd handles this
|
||||
useDHCP = false;
|
||||
|
||||
nftables = {
|
||||
enable = true;
|
||||
ruleset = ''
|
||||
define NAT_LAN_IFACES = { "br-lan" }
|
||||
define NAT_WAN_IFACES = { "wg-upstream" }
|
||||
define PHYSICAL_WAN = "enp1s0"
|
||||
define MASQUERADE_IFACES = { $NAT_WAN_IFACES, $PHYSICAL_WAN }
|
||||
define VUEKO_V4 = 168.119.176.53
|
||||
define VUEKO_V6 = 2a01:4f8:c012:2f4::1
|
||||
define VUEKO_PORT = 51820
|
||||
define WG_UPSTREAM_ENDPOINT = ${lib.elemAt (lib.splitString ":" (lib.elemAt config.systemd.network.netdevs.wg-upstream.wireguardPeers 0).wireguardPeerConfig.Endpoint) 0}
|
||||
define PLASTIC_ROUTER_V4 = 192.168.0.1
|
||||
define VPN_BYPASS_MARK = ${toString vpnBypassFwMark}
|
||||
|
||||
table inet filter {
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop
|
||||
|
||||
# Use MSS clamping
|
||||
# to avoid too large packets from client on the lan
|
||||
# not going through the tunnel.
|
||||
iifname wg-upstream tcp flags syn / syn,rst tcp option maxseg size set rt mtu
|
||||
oifname wg-upstream tcp flags syn / syn,rst tcp option maxseg size set rt mtu
|
||||
|
||||
# allow traffic between lan and wan
|
||||
iifname $NAT_LAN_IFACES oifname $NAT_WAN_IFACES counter accept
|
||||
iifname $NAT_WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept
|
||||
|
||||
# accept responses on physical wan
|
||||
iifname $PHYSICAL_WAN oifname $NAT_LAN_IFACES ct state established,related counter accept
|
||||
|
||||
# allow selected destinations via physical wan
|
||||
|
||||
# plastic router
|
||||
iifname $NAT_LAN_IFACES oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 counter accept
|
||||
|
||||
# all destinations configured via policy based routing
|
||||
oifname $PHYSICAL_WAN mark $VPN_BYPASS_MARK counter accept
|
||||
}
|
||||
}
|
||||
|
||||
table inet nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority filter; policy accept
|
||||
oifname $MASQUERADE_IFACES masquerade
|
||||
}
|
||||
}
|
||||
|
||||
# Bypass VPN by setting mark.
|
||||
# This acts in two places that are handled separatly by nftables:
|
||||
# Packets from the local host (output hook) and forwared packets (prerouting hook).
|
||||
# To simplify the handling,
|
||||
# there is a single chain that handles both,
|
||||
# which is jumped to from the specific chains.
|
||||
table inet vpn-bypass {
|
||||
# This must be of type route, otherwise no route lookup will be performed
|
||||
chain output {
|
||||
type route hook output priority mangle
|
||||
jump common
|
||||
}
|
||||
|
||||
# This does not need to be of type route
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority mangle
|
||||
jump common
|
||||
}
|
||||
|
||||
chain common {
|
||||
ip daddr $VUEKO_V4 udp dport $VUEKO_PORT mark set $VPN_BYPASS_MARK counter
|
||||
ip6 daddr $VUEKO_V6 udp dport $VUEKO_PORT mark set $VPN_BYPASS_MARK counter
|
||||
}
|
||||
}
|
||||
|
||||
# Only allow select connections from and to (physical) wan,
|
||||
# overriding NixOS firewall in some cases.
|
||||
table inet restrict-wan {
|
||||
# Priorities must be higher than filter (0),
|
||||
# which the NixOS firewall uses.
|
||||
chain input {
|
||||
type filter hook input priority -50; policy accept
|
||||
|
||||
# accept responses
|
||||
iifname $PHYSICAL_WAN ct state established,related counter accept
|
||||
|
||||
# accept icmpv6
|
||||
iifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
|
||||
|
||||
# drop everything else
|
||||
iifname $PHYSICAL_WAN counter drop
|
||||
}
|
||||
|
||||
# This handles all packets (local and forwarded)
|
||||
chain postrouting {
|
||||
type filter hook postrouting priority 0; policy accept
|
||||
|
||||
# accept connections to plastic router
|
||||
oifname $PHYSICAL_WAN ip daddr $PLASTIC_ROUTER_V4 counter accept
|
||||
|
||||
# accept icmpv6
|
||||
oifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
|
||||
|
||||
# accept connections to selected endpoints
|
||||
# VPN (wg-upstream)
|
||||
oifname $PHYSICAL_WAN ip daddr $WG_UPSTREAM_ENDPOINT counter accept # only this is used
|
||||
# destinations configured in VPN bypass
|
||||
oifname $PHYSICAL_WAN mark $VPN_BYPASS_MARK counter accept
|
||||
|
||||
# drop all other packets
|
||||
oifname $PHYSICAL_WAN counter drop
|
||||
}
|
||||
}
|
||||
|
||||
# Tracing infrastructure, can be used for debugging (nft monitor trace)
|
||||
table inet trace {
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority raw - 1
|
||||
jump common
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority raw - 1
|
||||
jump common
|
||||
}
|
||||
|
||||
chain common {
|
||||
# Add tracing rule here
|
||||
# … meta nftrace set 1
|
||||
# DO NOT COMMIT ANY TRACING RULES
|
||||
}
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
# not all interfaces need to be up
|
||||
wait-online.extraArgs = [ "--any" ];
|
||||
netdevs = {
|
||||
br-lan = {
|
||||
netdevConfig = {
|
||||
Name = "br-lan";
|
||||
Kind = "bridge";
|
||||
};
|
||||
};
|
||||
wg-upstream = {
|
||||
netdevConfig = {
|
||||
Kind = "wireguard";
|
||||
Name = "wg-upstream";
|
||||
};
|
||||
wireguardConfig = {
|
||||
PrivateKeyFile = config.sops.secrets.wg-upstream-private-key.path;
|
||||
FirewallMark = 51820;
|
||||
};
|
||||
wireguardPeers = lib.singleton {
|
||||
wireguardPeerConfig = {
|
||||
Endpoint = "193.32.248.71:51820";
|
||||
PublicKey = "eprzkkkSbXCANngQDo305DIAvkKAnZaN71IpTNaOoTk=";
|
||||
AllowedIPs = [ "0.0.0.0/0" "::0/0" ];
|
||||
PersistentKeepalive = 25;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
networks = {
|
||||
wan = {
|
||||
name = "enp1s0";
|
||||
DHCP = "ipv4";
|
||||
networkConfig = {
|
||||
IPv6AcceptRA = "yes";
|
||||
};
|
||||
dhcpV4Config = {
|
||||
UseDNS = "no";
|
||||
};
|
||||
ipv6AcceptRAConfig = {
|
||||
# Only use RA
|
||||
DHCPv6Client = false;
|
||||
UseDNS = "no";
|
||||
};
|
||||
};
|
||||
lan1 = {
|
||||
name = "enp2s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
lan2 = {
|
||||
name = "enp3s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
lan3 = {
|
||||
name = "enp4s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
br-lan = {
|
||||
name = "br-lan";
|
||||
domains = [ domain ];
|
||||
address = [ "10.80.1.1/24" "fd00:80:1::1/64" ];
|
||||
};
|
||||
wg-upstream = {
|
||||
name = "wg-upstream";
|
||||
address = [ "10.66.208.88/32" "fc00:bbbb:bbbb:bb01::3:d057/128" ];
|
||||
routingPolicyRules = [
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
Family = "both"; # default is only ipv4
|
||||
FirewallMark = 51820;
|
||||
InvertRule = "yes";
|
||||
Table = 51820;
|
||||
Priority = 10;
|
||||
#SuppressPrefixLength = 0; # can’t be used here (forwarding does not work with it)
|
||||
};
|
||||
}
|
||||
# FIXME: those two shouldn’t be necessary
|
||||
# It should automatically detect those routes existing and prioritise them
|
||||
# LAN (v4)
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
To = "10.80.1.0/24";
|
||||
Priority = 9;
|
||||
};
|
||||
}
|
||||
# LAN (v6)
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
To = "fd00:80:1::/64";
|
||||
Priority = 9;
|
||||
};
|
||||
}
|
||||
# wg-home
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
To = "10.80.0.0/24";
|
||||
Priority = 9;
|
||||
};
|
||||
}
|
||||
# VPN bypass
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
Family = "both"; # welcome in the year 2023, where ipv4 is the default
|
||||
FirewallMark = vpnBypassFwMark;
|
||||
Priority = 9;
|
||||
};
|
||||
}
|
||||
# plastic router
|
||||
{
|
||||
routingPolicyRuleConfig = {
|
||||
To = "192.168.0.0/24";
|
||||
Priority = 9;
|
||||
};
|
||||
}
|
||||
];
|
||||
routes = [
|
||||
{
|
||||
routeConfig = {
|
||||
Gateway = "0.0.0.0"; # point-to-point connection
|
||||
Table = 51820;
|
||||
};
|
||||
}
|
||||
{
|
||||
routeConfig = {
|
||||
Gateway = "::";
|
||||
Table = 51820;
|
||||
};
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
services.resolved.enable = false;
|
||||
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
bogus-priv = true; # do not forward revese lookups of internal addresses
|
||||
domain-needed = true; # do not forward names without domain
|
||||
interface = "br-lan"; # only respond to queries from lan
|
||||
no-hosts = true; # do not resolve hosts from /etc/hosts
|
||||
no-resolv = true; # only use explicitly configured resolvers
|
||||
|
||||
cache-size = 10000;
|
||||
|
||||
inherit domain;
|
||||
|
||||
# Allow resolving the router
|
||||
interface-name = [
|
||||
"${config.networking.hostName}.${domain},br-lan"
|
||||
"${config.networking.hostName},br-lan"
|
||||
];
|
||||
|
||||
# DHCPv4
|
||||
dhcp-range = [
|
||||
"10.80.1.20,10.80.1.150,12h" # DHCPv4
|
||||
"fd00:80:1::,ra-stateless,ra-names" # SLAAC (for addresses) / DHCPv6 (for DNS)
|
||||
];
|
||||
dhcp-option = [
|
||||
"option:router,10.80.1.1"
|
||||
"option6:dns-server,fd00:80:1::1"
|
||||
];
|
||||
|
||||
# Despite its name, the switch does not have a “smart” configuration,
|
||||
# that would allow me to tell it not to get DHCP from wan,
|
||||
# but from lan instead.
|
||||
# So it has to use static configuration.
|
||||
host-record = "switchviech,switchviech.${domain},10.80.1.19";
|
||||
server = [
|
||||
"127.0.0.1#5053"
|
||||
];
|
||||
};
|
||||
};
|
||||
systemd.services.dnsmasq.after = [ "systemd-networkd.service" ];
|
||||
|
||||
services.prometheus.exporters.dnsmasq = {
|
||||
enable = true;
|
||||
listenAddress = config.sbruder.wireguard.home.address;
|
||||
leasesPath = "/var/lib/dnsmasq/dnsmasq.leases";
|
||||
};
|
||||
|
||||
networking.firewall.allowedUDPPorts = [ 53 67 ];
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
|
||||
# Wireless
|
||||
boot.kernelModules = [ "nl80211" ];
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
ethtool
|
||||
iw
|
||||
wirelesstools
|
||||
];
|
||||
|
||||
# The service is mostly taken from nixpkgs pr 222536.
|
||||
systemd.services.hostapd = {
|
||||
path = with pkgs; [ hostapd ];
|
||||
after = [ "sys-subsystem-net-devices-wlp5s0.device" ];
|
||||
bindsTo = [ "sys-subsystem-net-devices-wlp5s0.device" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.hostapd}/bin/hostapd ${config.sops.secrets.hostapd-config.path}";
|
||||
Restart = "always";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||
RuntimeDirectory = "hostapd";
|
||||
|
||||
# Hardening
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
DevicePolicy = "closed";
|
||||
DeviceAllow = "/dev/rfkill rw";
|
||||
NoNewPrivileges = true;
|
||||
PrivateUsers = false; # hostapd requires true root access.
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
|
||||
services.https-dns-proxy = {
|
||||
enable = true;
|
||||
provider = {
|
||||
kind = "custom";
|
||||
ips = [ "9.9.9.9" "149.112.112.112" ];
|
||||
url = "https://dns.quad9.net/dns-query";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
domain = "home.sbruder.de";
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
# Home network configuration
|
||||
# (2.5GbE clients)
|
||||
# | |
|
||||
# +----------+ +----------+
|
||||
# | | | | | | (1GbE clients)
|
||||
# | | | | | +|-|-|-|-|+
|
||||
# +---+----+ +-+-+-+-+-+ |5 4 3 2 1|
|
||||
# |upstream| | 1 2 3 4 | |TL-SG105 |
|
||||
# +--------+ | shinobu | +---------+
|
||||
# +---------+
|
||||
#
|
||||
# It consists of shinobu as a router (this configuration),
|
||||
# connected to a TP-LINK TL-SG105E “smart managed” (i.e., it can do VLANs) 5-port switch.
|
||||
# The upstream comes (for now) from a PŸUR “WLAN-Kabelbox” (Compal CH7467CE).
|
||||
# Sadly, I could not enable bridge mode on it, so the packets now go through (at least) three layers of NAT:
|
||||
# device → NAT on shinobu → NAT on plastic router → PŸUR CGNAT
|
||||
#
|
||||
# Because the switch only supports GbE,
|
||||
# the two clients I currently have with support for 2.5GbE are connected
|
||||
# directly to the two remaining network interfaces on shinobu.
|
||||
# Once I have more devices with support for 2.5GbE
|
||||
# or I find a good deal on a matching switch,
|
||||
# I will change this.
|
||||
#
|
||||
# Wireless is configured by providing the whole hostapd configuration file as a secret.
|
||||
# Once nixpkgs PR 222536 is merged, I will migrate to using the NixOS module.
|
||||
# Thanks to Intel’s wisdom, it’s not possible to use 5GHz in AP mode.
|
||||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
cfg = import ./common.nix;
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
./dnsmasq.nix
|
||||
./nft.nix
|
||||
./wlan.nix
|
||||
];
|
||||
|
||||
boot.kernel.sysctl = {
|
||||
"net.ipv4.conf.all.forwarding" = true;
|
||||
"net.ipv6.conf.all.forwarding" = true;
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
ethtool
|
||||
];
|
||||
|
||||
networking.useDHCP = false;
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
# not all interfaces need to be up
|
||||
wait-online.extraArgs = [ "--any" ];
|
||||
netdevs = {
|
||||
br-lan = {
|
||||
netdevConfig = {
|
||||
Name = "br-lan";
|
||||
Kind = "bridge";
|
||||
};
|
||||
};
|
||||
};
|
||||
networks = {
|
||||
wan = {
|
||||
name = "enp1s0";
|
||||
DHCP = "ipv4";
|
||||
networkConfig = {
|
||||
IPv6AcceptRA = "yes";
|
||||
};
|
||||
dhcpV4Config = {
|
||||
UseDNS = "no";
|
||||
};
|
||||
ipv6AcceptRAConfig = {
|
||||
# Only use RA
|
||||
DHCPv6Client = false;
|
||||
UseDNS = "no";
|
||||
};
|
||||
};
|
||||
lan1 = {
|
||||
name = "enp2s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
lan2 = {
|
||||
name = "enp3s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
lan3 = {
|
||||
name = "enp4s0";
|
||||
bridge = [ "br-lan" ];
|
||||
};
|
||||
br-lan = {
|
||||
name = "br-lan";
|
||||
domains = [ cfg.domain ];
|
||||
address = [ "10.80.1.1/24" "fd00:80:1::1/64" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
services.resolved.enable = false;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
{ config, ... }:
|
||||
let
|
||||
cfg = import ./common.nix;
|
||||
in
|
||||
{
|
||||
services.dnsmasq = {
|
||||
enable = true;
|
||||
|
||||
settings = {
|
||||
bogus-priv = true; # do not forward revese lookups of internal addresses
|
||||
domain-needed = true; # do not forward names without domain
|
||||
interface = "br-lan"; # only respond to queries from lan
|
||||
no-hosts = true; # do not resolve hosts from /etc/hosts
|
||||
no-resolv = true; # only use explicitly configured resolvers
|
||||
|
||||
cache-size = 10000;
|
||||
|
||||
inherit (cfg) domain;
|
||||
|
||||
# Allow resolving the router
|
||||
interface-name = [
|
||||
"${config.networking.hostName}.${cfg.domain},br-lan"
|
||||
"${config.networking.hostName},br-lan"
|
||||
];
|
||||
|
||||
# DHCPv4
|
||||
dhcp-range = [
|
||||
"10.80.1.20,10.80.1.150,12h" # DHCPv4
|
||||
"fd00:80:1::,ra-stateless,ra-names" # SLAAC (for addresses) / DHCPv6 (for DNS)
|
||||
];
|
||||
dhcp-option = [
|
||||
"option:router,10.80.1.1"
|
||||
"option6:dns-server,fd00:80:1::1"
|
||||
];
|
||||
|
||||
# Despite its name, the switch does not have a “smart” configuration,
|
||||
# that would allow me to tell it not to get DHCP from wan,
|
||||
# but from lan instead.
|
||||
# So it has to use static configuration.
|
||||
host-record = "switchviech,switchviech.${cfg.domain},10.80.1.19";
|
||||
server = [
|
||||
"127.0.0.1#5053"
|
||||
];
|
||||
};
|
||||
};
|
||||
systemd.services.dnsmasq.after = [ "systemd-networkd.service" ];
|
||||
|
||||
networking.firewall.allowedUDPPorts = [ 53 67 ];
|
||||
networking.firewall.allowedTCPPorts = [ 53 ];
|
||||
|
||||
services.prometheus.exporters.dnsmasq = {
|
||||
enable = true;
|
||||
listenAddress = config.sbruder.wireguard.home.address;
|
||||
leasesPath = "/var/lib/dnsmasq/dnsmasq.leases";
|
||||
};
|
||||
|
||||
services.https-dns-proxy = {
|
||||
enable = true;
|
||||
provider = {
|
||||
kind = "custom";
|
||||
ips = [ "9.9.9.9" "149.112.112.112" ];
|
||||
url = "https://dns.quad9.net/dns-query";
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{ config, lib, ... }:
|
||||
let
|
||||
cfg = import ./common.nix;
|
||||
|
||||
mkKeyValue = lib.generators.mkKeyValueDefault
|
||||
rec {
|
||||
mkValueString = v:
|
||||
if lib.isString v then ''"${v}"''
|
||||
else if lib.isList v then ''{ ${lib.concatMapStringsSep ", " mkValueString v} }''
|
||||
else lib.generators.mkValueStringDefault { } v;
|
||||
} " = ";
|
||||
|
||||
passthru = { };
|
||||
|
||||
defines = lib.concatStringsSep
|
||||
"\n"
|
||||
(lib.mapAttrsToList
|
||||
(key: value: "define " + (mkKeyValue key value))
|
||||
passthru);
|
||||
in
|
||||
{
|
||||
networking.nftables = {
|
||||
enable = true;
|
||||
ruleset = ''
|
||||
${defines}
|
||||
|
||||
include "${./rules.nft}"
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
define NAT_LAN_IFACES = { "br-lan" }
|
||||
define PHYSICAL_WAN = "enp1s0"
|
||||
define NAT_WAN_IFACES = { $PHYSICAL_WAN }
|
||||
|
||||
table inet filter {
|
||||
chain forward {
|
||||
type filter hook forward priority filter; policy drop
|
||||
|
||||
# allow traffic between lan and wan
|
||||
iifname $NAT_LAN_IFACES oifname $NAT_WAN_IFACES counter accept
|
||||
iifname $NAT_WAN_IFACES oifname $NAT_LAN_IFACES ct state established,related counter accept
|
||||
}
|
||||
}
|
||||
|
||||
table inet nat {
|
||||
chain postrouting {
|
||||
type nat hook postrouting priority filter; policy accept
|
||||
oifname $NAT_WAN_IFACES masquerade
|
||||
}
|
||||
}
|
||||
|
||||
# Only allow select connections from and to (physical) wan,
|
||||
# overriding NixOS firewall in some cases.
|
||||
table inet restrict-wan {
|
||||
# Priorities must be higher than filter (0),
|
||||
# which the NixOS firewall uses.
|
||||
chain input {
|
||||
type filter hook input priority -50; policy accept
|
||||
|
||||
# accept responses
|
||||
iifname $PHYSICAL_WAN ct state established,related counter accept
|
||||
|
||||
# accept icmpv6
|
||||
iifname $PHYSICAL_WAN icmpv6 type { nd-neighbor-solicit, nd-router-advert, nd-neighbor-advert } accept
|
||||
|
||||
# drop everything else
|
||||
iifname $PHYSICAL_WAN counter drop
|
||||
}
|
||||
|
||||
# This handles all packets (local and forwarded)
|
||||
chain postrouting {
|
||||
type filter hook postrouting priority 0; policy accept
|
||||
|
||||
# accept connections over physical wan
|
||||
oifname $PHYSICAL_WAN counter accept
|
||||
}
|
||||
}
|
||||
|
||||
# Tracing infrastructure, can be used for debugging (nft monitor trace)
|
||||
table inet trace {
|
||||
chain prerouting {
|
||||
type filter hook prerouting priority raw - 1
|
||||
jump common
|
||||
}
|
||||
|
||||
chain output {
|
||||
type filter hook output priority raw - 1
|
||||
jump common
|
||||
}
|
||||
|
||||
chain common {
|
||||
# Add tracing rule here
|
||||
# … meta nftrace set 1
|
||||
# DO NOT COMMIT ANY TRACING RULES
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
{ config, pkgs, ... }:
|
||||
{
|
||||
sops.secrets.hostapd-config = {
|
||||
sopsFile = ../../secrets.yaml;
|
||||
};
|
||||
|
||||
# The service is mostly taken from nixpkgs pr 222536.
|
||||
systemd.services.hostapd = {
|
||||
path = with pkgs; [ hostapd ];
|
||||
after = [ "sys-subsystem-net-devices-wlp5s0.device" ];
|
||||
bindsTo = [ "sys-subsystem-net-devices-wlp5s0.device" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = "${pkgs.hostapd}/bin/hostapd ${config.sops.secrets.hostapd-config.path}";
|
||||
Restart = "always";
|
||||
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
|
||||
RuntimeDirectory = "hostapd";
|
||||
|
||||
# Hardening
|
||||
LockPersonality = true;
|
||||
MemoryDenyWriteExecute = true;
|
||||
DevicePolicy = "closed";
|
||||
DeviceAllow = "/dev/rfkill rw";
|
||||
NoNewPrivileges = true;
|
||||
PrivateUsers = false; # hostapd requires true root access.
|
||||
PrivateTmp = true;
|
||||
ProtectClock = true;
|
||||
ProtectControlGroups = true;
|
||||
ProtectHome = true;
|
||||
ProtectHostname = true;
|
||||
ProtectKernelLogs = true;
|
||||
ProtectKernelModules = true;
|
||||
ProtectKernelTunables = true;
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
ProtectSystem = "strict";
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
"AF_NETLINK"
|
||||
"AF_UNIX"
|
||||
];
|
||||
RestrictNamespaces = true;
|
||||
RestrictRealtime = true;
|
||||
RestrictSUIDSGID = true;
|
||||
SystemCallArchitectures = "native";
|
||||
SystemCallFilter = [
|
||||
"@system-service"
|
||||
"~@privileged"
|
||||
"@chown"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
};
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
iw
|
||||
wirelesstools
|
||||
];
|
||||
|
||||
|
||||
# Wireless
|
||||
boot.kernelModules = [ "nl80211" ];
|
||||
}
|
Binary file not shown.
|
@ -67,5 +67,9 @@
|
|||
hostNames = [ "shinobu" "shinobu.home.sbruder.de" "shinobu.vpn.sbruder.de" ];
|
||||
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJJNZPT2Mmys2nw/ovX6Z1Cb4WDAaWBWanycNwF9IEjl";
|
||||
};
|
||||
nazuna-initrd = {
|
||||
hostNames = [ "[nazuna.sbruder.de]:2222" ];
|
||||
publicKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN/VDiagTEI5BIjTrPRkGWAH3YurcMEV8i6Q8PSnxlg3 nazuna";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ lib.mkIf nixosConfig.sbruder.gui.enable {
|
|||
};
|
||||
|
||||
home.packages = with pkgs; [
|
||||
listenbrainz-content-resolver
|
||||
mpc_cli
|
||||
];
|
||||
|
||||
|
|
|
@ -198,7 +198,6 @@ lib.mkIf nixosConfig.sbruder.gui.enable
|
|||
|
||||
# Privacy
|
||||
content.cookies.accept = "no-3rdparty";
|
||||
content.headers.user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0";
|
||||
content.headers.accept_language = "en-US,en;q=0.5";
|
||||
|
||||
# Filtering (many don’t get used yet due to lack of cosmetic filtering)
|
||||
|
|
Loading…
Reference in New Issue