- Log all new outbound connections from users (EGRESS: prefix) - Rate limit: 30/min sustained, burst 60 - Over-limit connections logged (EGRESS-LIMIT:) and rejected - Closes ops-jrz1-p2d, ops-jrz1-cmv 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
136 lines
4.3 KiB
Nix
136 lines
4.3 KiB
Nix
{ config, pkgs, beads, opencode, ... }:
|
|
|
|
{
|
|
# Main NixOS configuration for ops-jrz1 server
|
|
# Imports host-specific configuration from hosts/ops-jrz1.nix
|
|
|
|
# Boot loader configuration (Legacy BIOS for Vultr VPS)
|
|
boot.loader.grub.enable = true;
|
|
boot.loader.grub.device = "/dev/vda"; # Install to MBR
|
|
|
|
# Network configuration
|
|
networking.useDHCP = false;
|
|
networking.interfaces.ens3.useDHCP = true;
|
|
|
|
# Time zone
|
|
time.timeZone = "UTC";
|
|
|
|
# Internationalization
|
|
i18n.defaultLocale = "en_US.UTF-8";
|
|
|
|
# System packages
|
|
environment.systemPackages = with pkgs; [
|
|
vim
|
|
git
|
|
htop
|
|
curl
|
|
tmux
|
|
# Dev environment
|
|
python3
|
|
uv
|
|
direnv
|
|
# AI coding tools (via flake inputs)
|
|
beads # Issue tracker (bd CLI)
|
|
opencode # AI coding agent (opencode CLI)
|
|
# For npm-based AI tools (gemini-cli, codex): users run npm install
|
|
nodejs_22
|
|
];
|
|
|
|
# Add ~/.local/bin and /usr/local/bin to PATH for manually installed tools
|
|
environment.localBinInPath = true;
|
|
environment.shellInit = ''
|
|
export PATH="/usr/local/bin:$PATH"
|
|
'';
|
|
|
|
# Enable Nix flakes
|
|
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
|
|
|
# SSH configuration
|
|
services.openssh = {
|
|
enable = true;
|
|
settings = {
|
|
PermitRootLogin = "prohibit-password";
|
|
PasswordAuthentication = false;
|
|
};
|
|
};
|
|
|
|
# SSH authorized keys for root
|
|
users.users.root.openssh.authorizedKeys.keys = [
|
|
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOqHsgAuD/8LL6HN3fo7X1ywryQG393pyQ19a154bO+h delpad-2025"
|
|
];
|
|
|
|
# Firewall (will be configured for Matrix services)
|
|
networking.firewall = {
|
|
enable = true;
|
|
allowedTCPPorts = [ 22 80 443 ]; # SSH, HTTP, HTTPS
|
|
|
|
# Egress controls for regular users (uid 1000+)
|
|
extraCommands = ''
|
|
# Log all new outbound connections from regular users
|
|
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
|
-j LOG --log-prefix "EGRESS: " --log-level info
|
|
|
|
# Rate limit new outbound connections (30/min sustained, burst 60)
|
|
iptables -A OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
|
-m limit --limit 30/min --limit-burst 60 -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 REJECT
|
|
'';
|
|
|
|
# Clean up on stop
|
|
extraStopCommands = ''
|
|
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
|
-j LOG --log-prefix "EGRESS: " --log-level info 2>/dev/null || true
|
|
iptables -D OUTPUT -m state --state NEW -m owner --uid-owner 1000:65534 \
|
|
-m limit --limit 30/min --limit-burst 60 -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 REJECT 2>/dev/null || true
|
|
'';
|
|
};
|
|
|
|
# ACME for Let's Encrypt certificates
|
|
security.acme = {
|
|
acceptTerms = true;
|
|
defaults.email = "dlei@duck.com";
|
|
};
|
|
|
|
# Allow deprecated olm library for Matrix bridges
|
|
# Note: olm is deprecated with known CVEs but required by mautrix bridges
|
|
# This is necessary for Matrix bridge functionality until alternatives are available
|
|
nixpkgs.config.permittedInsecurePackages = [
|
|
"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 processes per user (prevents fork bombs)
|
|
CPUWeight = 100; # Fair sharing when contended, bursts allowed
|
|
};
|
|
|
|
# CPU watchdog - detects sustained abuse, kills offending user
|
|
systemd.services.cpu-watchdog = {
|
|
description = "CPU abuse watchdog";
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
ExecStart = "/usr/local/bin/cpu-watchdog";
|
|
};
|
|
};
|
|
|
|
systemd.timers.cpu-watchdog = {
|
|
description = "Run CPU watchdog every minute";
|
|
wantedBy = [ "timers.target" ];
|
|
timerConfig = {
|
|
OnBootSec = "1min";
|
|
OnUnitActiveSec = "1min";
|
|
};
|
|
};
|
|
|
|
# This value determines the NixOS release compatibility
|
|
system.stateVersion = "24.05";
|
|
}
|