321 lines
12 KiB
Nix
321 lines
12 KiB
Nix
# Partially inspired by https://krutonium.ca/posts/building-a-nixos-router/ and others.
|
|
|
|
{ pkgs, ... }:
|
|
|
|
{
|
|
imports = [
|
|
./hardware-configuration.nix
|
|
../../base.nix
|
|
../../roles/zfs.nix
|
|
../../users/root.nix
|
|
../../roles/espeakup.nix
|
|
../../roles/tailscale.nix
|
|
../../roles/nix-ld.nix
|
|
# ../../roles/caddy.nix
|
|
];
|
|
|
|
boot = {
|
|
kernelParams = [ "console=ttyS0,115200" ];
|
|
kernel.sysctl = {
|
|
"net.ipv4.conf.all.forwarding" = 1;
|
|
};
|
|
# Load kernel modules required for advanced QoS
|
|
kernelModules = [
|
|
"sch_cake" # CAKE qdisc for modern AQM and traffic shaping
|
|
"sch_fq_codel" # Fair Queue CoDel for bufferbloat mitigation
|
|
"ifb" # Intermediate Functional Block for ingress shaping
|
|
];
|
|
loader = {
|
|
efi.canTouchEfiVariables = true;
|
|
systemd-boot.enable = true;
|
|
};
|
|
supportedFilesystems = [ "zfs" ];
|
|
};
|
|
|
|
time.timeZone = "America/Detroit";
|
|
|
|
i18n.defaultLocale = "en_US.UTF-8";
|
|
console.keyMap = "us";
|
|
|
|
networking = {
|
|
hostName = "router";
|
|
hostId = "91312b0b";
|
|
firewall = {
|
|
interfaces.lan = {
|
|
allowedUDPPorts = [
|
|
53
|
|
67
|
|
];
|
|
allowedTCPPorts = [
|
|
53
|
|
67
|
|
80
|
|
443
|
|
];
|
|
};
|
|
|
|
# Install packages required for QoS management
|
|
extraPackages = [ pkgs.iproute2 ];
|
|
|
|
# QoS configuration for prioritizing gaming, streaming, and real-time traffic
|
|
extraCommands = ''
|
|
##############################################################################
|
|
# Quality of Service (QoS) Configuration
|
|
#
|
|
# Priority Tiers (DSCP Classes):
|
|
# - EF (Expedited Forwarding) : Voice chat, video calls (lowest latency)
|
|
# - CS6 (Class Selector 6) : Real-time gaming packets
|
|
# - CS5 (Class Selector 5) : Console gaming traffic
|
|
# - AF41 (Assured Forwarding 4.1) : Video streaming
|
|
# - CS3 (Class Selector 3) : Service discovery (mDNS)
|
|
# - CS1 (Class Selector 1) : Bulk downloads (lowest priority)
|
|
# - Default : Everything else
|
|
##############################################################################
|
|
|
|
|
|
# Apply CAKE (Common Applications Kept Enhanced) queue discipline
|
|
# This provides modern Active Queue Management with built-in traffic prioritization
|
|
# Settings:
|
|
# bandwidth 1gbit - Set to your LAN bandwidth
|
|
# diffserv4 - Enable 4-tier traffic classification (Bulk, Best Effort, Video, Voice)
|
|
# dual-dsthost - Per-destination fairness to prevent one device from hogging bandwidth
|
|
# nat - Handle NAT properly for accurate flow tracking
|
|
# wash - Clear incoming DSCP marks to reclassify based on our rules
|
|
# ack-filter - Filter excessive TCP ACKs from downloads
|
|
# rtt 30ms - Optimize for typical gaming latency
|
|
tc qdisc replace dev lan root cake bandwidth 1gbit diffserv4 dual-dsthost nat wash ack-filter rtt 30ms
|
|
|
|
##############################################################################
|
|
# TIER 1 - HIGHEST PRIORITY: Real-time Gaming Traffic (CS6/CS5)
|
|
##############################################################################
|
|
|
|
# PlayStation Network
|
|
# TCP ports for authentication and matchmaking
|
|
iptables -t mangle -A FORWARD -i lan -p tcp -m multiport --dports 1935,3478:3480 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "PlayStation Network TCP"
|
|
|
|
# UDP ports for gameplay and voice
|
|
iptables -t mangle -A FORWARD -i lan -p udp -m multiport --dports 3478:3479,3658 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "PlayStation Network UDP"
|
|
|
|
# PS5 high UDP port range for game traffic
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 49152:65535 -m length --length 0:500 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "PS5 game traffic (small packets)"
|
|
|
|
# Xbox Live
|
|
# Primary multiplayer and party chat port
|
|
iptables -t mangle -A FORWARD -i lan -p tcp --dport 3074 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "Xbox Live TCP"
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 3074 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "Xbox Live UDP"
|
|
|
|
# Additional Xbox ports
|
|
iptables -t mangle -A FORWARD -i lan -p udp -m multiport --dports 88,500,3544,4500 \
|
|
-j DSCP --set-dscp-class cs5 \
|
|
-m comment --comment "Xbox Live additional ports"
|
|
|
|
# Generic small gaming packets (likely real-time game data)
|
|
# Small UDP packets are typically game state updates that need lowest latency
|
|
iptables -t mangle -A FORWARD -i lan -p udp -m length --length 0:500 \
|
|
-j DSCP --set-dscp-class cs6 \
|
|
-m comment --comment "Small UDP packets (real-time gaming)"
|
|
|
|
##############################################################################
|
|
# TIER 2 - VOICE AND VIDEO CALLS: Expedited Forwarding (EF)
|
|
##############################################################################
|
|
|
|
# Console voice chat and Discord (small packets in high port range)
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 50000:65535 -m length --length 0:250 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "Voice chat (Discord, console party chat)"
|
|
|
|
# WebRTC media streams (used by Google Meet, other video conferencing)
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 19302:19309 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "WebRTC media (Google Meet, etc)"
|
|
|
|
# Zoom conferencing
|
|
iptables -t mangle -A FORWARD -i lan -p tcp -m multiport --dports 8801:8810 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "Zoom TCP"
|
|
iptables -t mangle -A FORWARD -i lan -p udp -m multiport --dports 8801:8810 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "Zoom UDP"
|
|
|
|
# General VoIP/SIP traffic
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 5060:5061 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "SIP signaling"
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 10000:20000 \
|
|
-j DSCP --set-dscp-class ef \
|
|
-m comment --comment "RTP media streams"
|
|
|
|
##############################################################################
|
|
# TIER 3 - VIDEO STREAMING: Assured Forwarding (AF41)
|
|
##############################################################################
|
|
|
|
# QUIC protocol (HTTP/3) - Used by YouTube, Netflix
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 443 \
|
|
-j DSCP --set-dscp-class af41 \
|
|
-m comment --comment "QUIC/HTTP3 video streaming"
|
|
|
|
# Chromecast/Google TV
|
|
iptables -t mangle -A FORWARD -i lan -p tcp -m multiport --dports 8008:8009,8443 \
|
|
-j DSCP --set-dscp-class af41 \
|
|
-m comment --comment "Chromecast control"
|
|
|
|
# Chromecast RTP media streams (large packets)
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 32768:61000 -m length --length 1000:1500 \
|
|
-j DSCP --set-dscp-class af41 \
|
|
-m comment --comment "Chromecast media streams"
|
|
|
|
# HTTPS video streaming (1MB-50MB connections)
|
|
# This catches most adaptive streaming video (HLS, DASH)
|
|
iptables -t mangle -A FORWARD -i lan -p tcp --dport 443 \
|
|
-m connbytes --connbytes 1000000:50000000 --connbytes-dir both --connbytes-mode bytes \
|
|
-j DSCP --set-dscp-class af41 \
|
|
-m comment --comment "HTTPS video streams (1-50MB)"
|
|
|
|
##############################################################################
|
|
# TIER 4 - SERVICE DISCOVERY: Medium Priority (CS3)
|
|
##############################################################################
|
|
|
|
# mDNS for device discovery (important for casting, AirPlay)
|
|
iptables -t mangle -A FORWARD -i lan -p udp --dport 5353 \
|
|
-j DSCP --set-dscp-class cs3 \
|
|
-m comment --comment "mDNS service discovery"
|
|
|
|
|
|
##############################################################################
|
|
# TIER 5 - BULK DOWNLOADS: Lowest Priority (CS1)
|
|
##############################################################################
|
|
|
|
# Large HTTPS downloads (over 50MB) - game updates, OS updates, etc.
|
|
iptables -t mangle -A FORWARD -i lan -p tcp --dport 443 \
|
|
-m connbytes --connbytes 50000000: --connbytes-dir both --connbytes-mode bytes \
|
|
-j DSCP --set-dscp-class cs1 \
|
|
-m comment --comment "Bulk HTTPS downloads (>50MB)"
|
|
|
|
'';
|
|
|
|
# Clean up QoS rules when firewall stops
|
|
extraStopCommands = ''
|
|
# Remove CAKE qdisc
|
|
tc qdisc del dev lan root 2>/dev/null || true
|
|
|
|
# Clear mangle table rules
|
|
iptables -t mangle -F FORWARD 2>/dev/null || true
|
|
'';
|
|
};
|
|
useNetworkd = true;
|
|
bridges = {
|
|
lan = {
|
|
interfaces = [
|
|
"lan0"
|
|
"lan1"
|
|
"lan2"
|
|
"lan3"
|
|
"lan4"
|
|
];
|
|
};
|
|
};
|
|
interfaces = {
|
|
"wan" = {
|
|
useDHCP = true;
|
|
};
|
|
"lan" = {
|
|
ipv4.addresses = [
|
|
{
|
|
address = "192.168.0.1";
|
|
prefixLength = 16;
|
|
}
|
|
];
|
|
useDHCP = false;
|
|
# macAddress = "AA:BB:CC:DD:EE:FF";
|
|
# ^ This is the MAC address of the bridge. It's important to set this
|
|
# so that the bridge has a predictable MAC address.
|
|
};
|
|
};
|
|
nat = {
|
|
enable = true;
|
|
externalInterface = "wan";
|
|
internalInterfaces = [ "lan" ];
|
|
internalIPs = [ "192.168.0.0/16" ];
|
|
};
|
|
};
|
|
|
|
services = {
|
|
resolved = {
|
|
# Disable local DNS stub listener on 127.0.0.53
|
|
extraConfig = ''
|
|
DNSStubListener=no
|
|
'';
|
|
};
|
|
adguardhome = {
|
|
enable = true;
|
|
settings = {
|
|
dhcp = {
|
|
enabled = true;
|
|
interface_name = "lan";
|
|
dhcpv4 = {
|
|
gateway_ip = "192.168.0.1";
|
|
subnet_mask = "255.255.0.0";
|
|
range_start = "192.168.1.0";
|
|
range_end = "192.168.254.254";
|
|
lease_duration = 300;
|
|
};
|
|
};
|
|
filtering = {
|
|
protection_enabled = true;
|
|
filtering_enabled = true;
|
|
};
|
|
};
|
|
};
|
|
caddy = {
|
|
enable = true;
|
|
virtualHosts."router.tailc50184.ts.net".extraConfig = ''
|
|
reverse_proxy localhost:3000
|
|
'';
|
|
};
|
|
tailscale.permitCertUid = "caddy";
|
|
udev.extraRules = ''
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:67", NAME="wan"
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:68", NAME="lan0"
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:69", NAME="lan1"
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:6a", NAME="lan2"
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:6b", NAME="lan3"
|
|
ACTION=="add", SUBSYSTEM=="net", ATTR{address}=="00:e2:69:96:fb:6c", NAME="lan4"
|
|
'';
|
|
fail2ban.enable = true;
|
|
};
|
|
|
|
# Enable the Flakes feature and the accompanying new nix command-line tool
|
|
nix.settings.experimental-features = [
|
|
"nix-command"
|
|
"flakes"
|
|
];
|
|
|
|
# This option defines the first version of NixOS you have installed on this particular machine,
|
|
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
|
#
|
|
# Most users should NEVER change this value after the initial install, for any reason,
|
|
# even if you've upgraded your system to a new NixOS release.
|
|
#
|
|
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
|
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
|
|
# to actually do that.
|
|
#
|
|
# This value being lower than the current NixOS release does NOT mean your system is
|
|
# out of date, out of support, or vulnerable.
|
|
#
|
|
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
|
# and migrated your data accordingly.
|
|
#
|
|
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
|
system.stateVersion = "25.05"; # Did you read the comment?
|
|
}
|