Network Hardening
All network-level hardening is applied via boot.kernel.sysctl in server/modules/kernel.nix and firewall rules in server/modules/network.nix.
BPF Hardening
"net.core.bpf_jit_harden" = 2;
"net.core.bpf_jit_kallsyms" = 0;| Sysctl | Value | Effect |
|---|---|---|
bpf_jit_harden | 2 | Applies JIT hardening to all BPF programs (not just unprivileged), constant blinding prevents JIT spray attacks |
bpf_jit_kallsyms | 0 | Hides JIT-compiled BPF program addresses from /proc/kallsyms |
Combined with kernel.unprivileged_bpf_disabled = 1 from Kernel Hardening, this eliminates eBPF as an attack vector for unprivileged users and hardens it for privileged use.
Core Network Security
"net.core.fb_tunnels_only_for_init_net" = 1;
"net.core.xfrm_larval_drop" = 1;| Sysctl | Value | Effect |
|---|---|---|
fb_tunnels_only_for_init_net | 1 | Restricts fallback tunnel devices to the initial network namespace only |
xfrm_larval_drop | 1 | Drops packets requiring IPsec SA resolution instead of queueing them |
IPv4 Interface Hardening
Applied to both all and default interfaces to ensure coverage for dynamically created interfaces (e.g., container veth pairs):
# Applied to both conf.all and conf.default
"net.ipv4.conf.*.accept_redirects" = 0;
"net.ipv4.conf.*.accept_source_route" = 0;
"net.ipv4.conf.*.bootp_relay" = 0;
"net.ipv4.conf.*.forwarding" = 0;
"net.ipv4.conf.*.log_martians" = 1;
"net.ipv4.conf.*.mc_forwarding" = 0;
"net.ipv4.conf.*.proxy_arp" = 0;
"net.ipv4.conf.*.rp_filter" = 1;
"net.ipv4.conf.*.send_redirects" = 0;| Setting | Value | Rationale |
|---|---|---|
accept_redirects | 0 | Prevents ICMP redirect poisoning (MitM attacks) |
accept_source_route | 0 | Blocks source-routed packets (used to bypass firewalls) |
bootp_relay | 0 | Disables BOOTP relay (not needed) |
forwarding | 0 | Disables IP forwarding at the sysctl level (NAT is handled by nftables) |
log_martians | 1 | Logs packets with impossible source addresses for forensic analysis |
mc_forwarding | 0 | Disables multicast forwarding |
proxy_arp | 0 | Prevents this host from answering ARP requests for other hosts |
rp_filter | 1 | Strict reverse path filtering; drops packets with spoofed source addresses |
send_redirects | 0 | Prevents sending ICMP redirects (host is not a router) |
Why Both all and default?
conf.all applies to existing interfaces. conf.default applies to interfaces created after boot. Both must be set because container veth interfaces are created dynamically.
ICMP Hardening
"net.ipv4.icmp_echo_ignore_all" = 1;
"net.ipv4.icmp_echo_ignore_broadcasts" = 1;
"net.ipv4.icmp_errors_use_inbound_ifaddr" = 0;
"net.ipv4.icmp_ignore_bogus_error_responses" = 1;
"net.ipv4.icmp_msgs_burst" = 10;
"net.ipv4.icmp_msgs_per_sec" = 10;
"net.ipv4.icmp_ratelimit" = 100;
"net.ipv4.icmp_ratemask" = 6168;| Setting | Value | Effect |
|---|---|---|
icmp_echo_ignore_all | 1 | Host does not respond to ping; makes port scanning harder |
icmp_echo_ignore_broadcasts | 1 | Ignores broadcast pings (Smurf attack mitigation) |
icmp_errors_use_inbound_ifaddr | 0 | ICMP errors use primary address, not the interface the error arrived on |
icmp_ignore_bogus_error_responses | 1 | Silently drops malformed ICMP error messages |
icmp_msgs_burst / icmp_msgs_per_sec | 10 | Rate limits ICMP message generation to 10/sec with burst of 10 |
icmp_ratelimit | 100 | Rate limit in milliseconds between ICMP packets |
icmp_ratemask | 6168 | Bitmask selecting which ICMP types are rate-limited |
TCP Hardening
"net.ipv4.tcp_sack" = 0;
"net.ipv4.tcp_dsack" = 0;
"net.ipv4.tcp_fack" = 0;
"net.ipv4.tcp_syncookies" = 1;
"net.ipv4.tcp_rfc1337" = 1;
"net.ipv4.tcp_timestamps" = 0;| Setting | Value | Rationale |
|---|---|---|
tcp_sack | 0 | Disables Selective ACK; SACK has had critical CVEs (e.g., SACK Panic CVE-2019-11477) |
tcp_dsack | 0 | Disables Duplicate SACK (depends on SACK) |
tcp_fack | 0 | Disables Forward ACK (depends on SACK) |
tcp_syncookies | 1 | Enables SYN cookies to protect against SYN flood DoS |
tcp_rfc1337 | 1 | Drops RST packets for TIME-WAIT sockets (TIME-WAIT assassination protection) |
tcp_timestamps | 0 | Disables TCP timestamps; prevents uptime fingerprinting and side-channel leaks |
Performance Trade-off
Disabling SACK reduces TCP performance on lossy or high-latency links. For a homelab on a local LAN with a Cloudflare Tunnel, this trade-off is acceptable. If you add WAN-facing services without Cloudflare, reconsider tcp_sack.
TCP Optimisation
"net.ipv4.tcp_fastopen" = 3;
"net.ipv4.tcp_congestion_control" = "bbr";
"net.core.default_qdisc" = "cake";| Setting | Value | Effect |
|---|---|---|
tcp_fastopen | 3 | Enables TCP Fast Open for both client and server connections (reduces latency) |
tcp_congestion_control | bbr | Google BBR congestion control; better throughput and lower latency than Cubic |
default_qdisc | cake | CAKE queueing discipline; mitigates bufferbloat |
Buffer Tuning
"net.core.rmem_default" = 524288; # 512 KB
"net.core.wmem_default" = 524288; # 512 KB
"net.core.rmem_max" = 8388608; # 8 MB
"net.core.wmem_max" = 8388608; # 8 MB
"net.core.optmem_max" = 262144; # 256 KB
"net.core.netdev_max_backlog" = 4096;These are 4-8x the kernel defaults. Larger buffers help with bursty workloads (e.g., Immich photo uploads, Restic backup transfers) without requiring per-socket tuning.
Firewall
Defined in server/modules/network.nix:
firewall = {
enable = true;
allowPing = false;
allowedUDPPorts = [ 53 ];
allowedTCPPorts = [ 53 80 443 ];
};Only three services are reachable from the LAN:
| Port | Service | Protocol |
|---|---|---|
| 53 | AdGuard Home (DNS) | TCP + UDP |
| 80 | Traefik (HTTP, redirects to 443) | TCP |
| 443 | Traefik (HTTPS) | TCP |
SSH (port 22) is also open via services.openssh.ports but is not listed in the firewall rules because NixOS automatically opens ports for enabled openssh service.
See also Networking & Firewall for the full network architecture.