Consolidate scattered networking, environment, systemd keys
Fixes 3x statix W20 warnings. No functional change. - networking: Moved firewall into main block - environment: Consolidated systemPackages, localBinInPath, shellInit - systemd: Consolidated slices, services, timers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
278017efe3
commit
ad1fbf1c8c
|
|
@ -57,8 +57,42 @@ in
|
|||
boot.loader.grub.device = "/dev/vda"; # Install to MBR
|
||||
|
||||
# Network configuration
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces.ens3.useDHCP = true;
|
||||
networking = {
|
||||
useDHCP = false;
|
||||
interfaces.ens3.useDHCP = true;
|
||||
|
||||
# Firewall
|
||||
firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [ 22 80 443 ]; # SSH, HTTP, HTTPS
|
||||
allowedUDPPortRanges = [ { from = 60000; to = 60010; } ]; # mosh
|
||||
|
||||
# Egress controls for regular users
|
||||
# UID range: 1000 (first regular user) to 65534 (nobody - excluded from controls)
|
||||
# This covers all dev accounts while excluding system services
|
||||
extraCommands = ''
|
||||
# Rate limit new outbound connections (150/min sustained, burst 300)
|
||||
# High enough for npm install, low enough to prevent abuse
|
||||
# DROP instead of REJECT so apps back off naturally
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-m limit --limit 150/min --limit-burst 300 -j ACCEPT
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j LOG --log-prefix "EGRESS-LIMIT: " --log-level warning
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j DROP
|
||||
'';
|
||||
|
||||
# Clean up on stop
|
||||
extraStopCommands = ''
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-m limit --limit 150/min --limit-burst 300 -j ACCEPT 2>/dev/null || true
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j LOG --log-prefix "EGRESS-LIMIT: " --log-level warning 2>/dev/null || true
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j DROP 2>/dev/null || true
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
# Time zone
|
||||
time.timeZone = "UTC";
|
||||
|
|
@ -66,50 +100,52 @@ in
|
|||
# Internationalization
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
# System packages
|
||||
environment.systemPackages = with pkgs; [
|
||||
vim
|
||||
git
|
||||
htop
|
||||
curl
|
||||
tmux
|
||||
# Dev environment
|
||||
python3
|
||||
uv
|
||||
direnv
|
||||
zig
|
||||
# AI coding tools (via flake inputs)
|
||||
opencode # AI coding agent (opencode CLI)
|
||||
# For JS-based AI tools (gemini-cli, claude-cli): users run bun/npm install
|
||||
nodejs_22
|
||||
bun
|
||||
# Terminfo for modern terminals (ghostty, kitty, etc.)
|
||||
pkgs-unstable.ghostty.terminfo
|
||||
kitty.terminfo
|
||||
# Classic Unix social tools
|
||||
bsd-finger
|
||||
ytalk
|
||||
fortune
|
||||
# Mobile shell - resilient SSH for spotty connections
|
||||
mosh
|
||||
# Admin scripts (declarative deployment)
|
||||
dev-add
|
||||
dev-remove
|
||||
egress-status
|
||||
];
|
||||
# Environment configuration
|
||||
environment = {
|
||||
systemPackages = with pkgs; [
|
||||
vim
|
||||
git
|
||||
htop
|
||||
curl
|
||||
tmux
|
||||
# Dev environment
|
||||
python3
|
||||
uv
|
||||
direnv
|
||||
zig
|
||||
# AI coding tools (via flake inputs)
|
||||
opencode # AI coding agent (opencode CLI)
|
||||
# For JS-based AI tools (gemini-cli, claude-cli): users run bun/npm install
|
||||
nodejs_22
|
||||
bun
|
||||
# Terminfo for modern terminals (ghostty, kitty, etc.)
|
||||
pkgs-unstable.ghostty.terminfo
|
||||
kitty.terminfo
|
||||
# Classic Unix social tools
|
||||
bsd-finger
|
||||
ytalk
|
||||
fortune
|
||||
# Mobile shell - resilient SSH for spotty connections
|
||||
mosh
|
||||
# Admin scripts (declarative deployment)
|
||||
dev-add
|
||||
dev-remove
|
||||
egress-status
|
||||
];
|
||||
|
||||
# Add ~/.local/bin and /usr/local/bin to PATH for manually installed tools
|
||||
environment.localBinInPath = true;
|
||||
environment.shellInit = ''
|
||||
export PATH="/usr/local/bin:$PATH"
|
||||
# Add ~/.local/bin and /usr/local/bin to PATH for manually installed tools
|
||||
localBinInPath = true;
|
||||
shellInit = ''
|
||||
export PATH="/usr/local/bin:$PATH"
|
||||
|
||||
# Set COLORTERM for truecolor terminals (SSH doesn't forward this)
|
||||
case "$TERM" in
|
||||
xterm-ghostty|xterm-kitty|alacritty|xterm-256color)
|
||||
export COLORTERM=truecolor
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
# Set COLORTERM for truecolor terminals (SSH doesn't forward this)
|
||||
case "$TERM" in
|
||||
xterm-ghostty|xterm-kitty|alacritty|xterm-256color)
|
||||
export COLORTERM=truecolor
|
||||
;;
|
||||
esac
|
||||
'';
|
||||
};
|
||||
|
||||
# Fortune on interactive shell login
|
||||
programs.bash.interactiveShellInit = ''
|
||||
|
|
@ -138,38 +174,6 @@ in
|
|||
# Devs group for shared resources (Slack tokens, etc.)
|
||||
users.groups.devs = {};
|
||||
|
||||
# Firewall (will be configured for Matrix services)
|
||||
networking.firewall = {
|
||||
enable = true;
|
||||
allowedTCPPorts = [ 22 80 443 ]; # SSH, HTTP, HTTPS
|
||||
allowedUDPPortRanges = [ { from = 60000; to = 60010; } ]; # mosh
|
||||
|
||||
# Egress controls for regular users
|
||||
# UID range: 1000 (first regular user) to 65534 (nobody - excluded from controls)
|
||||
# This covers all dev accounts while excluding system services
|
||||
extraCommands = ''
|
||||
# Rate limit new outbound connections (150/min sustained, burst 300)
|
||||
# High enough for npm install, low enough to prevent abuse
|
||||
# DROP instead of REJECT so apps back off naturally
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-m limit --limit 150/min --limit-burst 300 -j ACCEPT
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j LOG --log-prefix "EGRESS-LIMIT: " --log-level warning
|
||||
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j DROP
|
||||
'';
|
||||
|
||||
# Clean up on stop
|
||||
extraStopCommands = ''
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-m limit --limit 150/min --limit-burst 300 -j ACCEPT 2>/dev/null || true
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j LOG --log-prefix "EGRESS-LIMIT: " --log-level warning 2>/dev/null || true
|
||||
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
||||
-j DROP 2>/dev/null || true
|
||||
'';
|
||||
};
|
||||
|
||||
# ACME for Let's Encrypt certificates
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
|
|
@ -182,11 +186,54 @@ in
|
|||
"olm-3.2.16"
|
||||
];
|
||||
|
||||
# Resource limits for user slices (prevent one user from crashing server)
|
||||
systemd.slices."user".sliceConfig = {
|
||||
MemoryMax = "80%"; # Users collectively can't exceed 80% RAM
|
||||
TasksMax = 500; # Max 500 total processes across all users
|
||||
CPUWeight = 100; # Fair sharing when contended, bursts allowed
|
||||
# Systemd configuration - resource limits and watchdogs
|
||||
systemd = {
|
||||
# Resource limits for user slices (prevent one user from crashing server)
|
||||
slices."user".sliceConfig = {
|
||||
MemoryMax = "80%"; # Users collectively can't exceed 80% RAM
|
||||
TasksMax = 500; # Max 500 total processes across all users
|
||||
CPUWeight = 100; # Fair sharing when contended, bursts allowed
|
||||
};
|
||||
|
||||
services = {
|
||||
# CPU watchdog - detects sustained abuse, kills offending user
|
||||
cpu-watchdog = {
|
||||
description = "CPU abuse watchdog";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${cpu-watchdog}/bin/cpu-watchdog";
|
||||
};
|
||||
};
|
||||
|
||||
# Egress watchdog - detects users hitting rate limits, kills after 3 strikes
|
||||
egress-watchdog = {
|
||||
description = "Egress abuse watchdog";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${egress-watchdog}/bin/egress-watchdog";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
timers = {
|
||||
cpu-watchdog = {
|
||||
description = "Run CPU watchdog every minute";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "1min";
|
||||
};
|
||||
};
|
||||
|
||||
egress-watchdog = {
|
||||
description = "Run egress watchdog every minute";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "1min";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# Per-user limits - create drop-in on activation
|
||||
|
|
@ -201,42 +248,6 @@ in
|
|||
EOF
|
||||
'';
|
||||
|
||||
# CPU watchdog - detects sustained abuse, kills offending user
|
||||
systemd.services.cpu-watchdog = {
|
||||
description = "CPU abuse watchdog";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${cpu-watchdog}/bin/cpu-watchdog";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.cpu-watchdog = {
|
||||
description = "Run CPU watchdog every minute";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "1min";
|
||||
};
|
||||
};
|
||||
|
||||
# Egress watchdog - detects users hitting rate limits, kills after 3 strikes
|
||||
systemd.services.egress-watchdog = {
|
||||
description = "Egress abuse watchdog";
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
ExecStart = "${egress-watchdog}/bin/egress-watchdog";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.timers.egress-watchdog = {
|
||||
description = "Run egress watchdog every minute";
|
||||
wantedBy = [ "timers.target" ];
|
||||
timerConfig = {
|
||||
OnBootSec = "1min";
|
||||
OnUnitActiveSec = "1min";
|
||||
};
|
||||
};
|
||||
|
||||
# This value determines the NixOS release compatibility
|
||||
system.stateVersion = "24.05";
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue