From ab5aebb161e9e40a45935659807036d20b1c4929 Mon Sep 17 00:00:00 2001 From: Dan Date: Mon, 13 Oct 2025 14:51:14 -0700 Subject: [PATCH] Phase 3: Extract and sanitize Matrix platform modules from ops-base Extracted modules: - Matrix homeserver (matrix-continuwuity.nix) - mautrix bridges (slack, whatsapp, gmessages) - Security modules (fail2ban, ssh-hardening) - Development services module - Matrix secrets module All modules sanitized to remove personal information: - Domains: example.com, matrix.example.org - IPs: 10.0.0.x, 203.0.113.10 - Paths: /home/user, /path/to/ops-base - Emails: admin@example.com Configuration: - Updated flake.nix with sops-nix and nixpkgs-unstable - Updated hosts/ops-jrz1.nix to import all extracted modules - Added example files (secrets, minimal config) - Generated flake.lock Generated with Claude Code - https://claude.com/claude-code --- .gitignore | 1 + configurations/dev-vps.nix | 131 ++++++ configurations/vultr-dev.nix | 184 ++++++++ docs/examples/minimal-matrix.nix | 79 ++++ flake.lock | 65 +++ flake.nix | 22 +- hosts/ops-jrz1.nix | 45 +- modules/dev-services.nix | 308 +++++++++++++ modules/matrix-continuwuity.nix | 119 +++++ modules/matrix-secrets/README.md | 23 + modules/matrix-secrets/default.nix | 62 +++ modules/mautrix-gmessages.nix | 712 +++++++++++++++++++++++++++++ modules/mautrix-slack.nix | 392 ++++++++++++++++ modules/mautrix-whatsapp.nix | 571 +++++++++++++++++++++++ modules/security/fail2ban.nix | 61 +++ modules/security/ssh-hardening.nix | 130 ++++++ secrets/.sops.yaml.example | 16 + secrets/secrets.yaml.example | 31 ++ 18 files changed, 2929 insertions(+), 23 deletions(-) create mode 100644 configurations/dev-vps.nix create mode 100644 configurations/vultr-dev.nix create mode 100644 docs/examples/minimal-matrix.nix create mode 100644 flake.lock create mode 100644 modules/dev-services.nix create mode 100644 modules/matrix-continuwuity.nix create mode 100644 modules/matrix-secrets/README.md create mode 100644 modules/matrix-secrets/default.nix create mode 100644 modules/mautrix-gmessages.nix create mode 100644 modules/mautrix-slack.nix create mode 100644 modules/mautrix-whatsapp.nix create mode 100644 modules/security/fail2ban.nix create mode 100644 modules/security/ssh-hardening.nix create mode 100644 secrets/.sops.yaml.example create mode 100644 secrets/secrets.yaml.example diff --git a/.gitignore b/.gitignore index 1bf77a8..49e8b59 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ result-* # Staging directories (temporary extraction workspace) staging/ +staging-sanitized/ # Secrets (never commit real secrets) secrets/*.yaml diff --git a/configurations/dev-vps.nix b/configurations/dev-vps.nix new file mode 100644 index 0000000..ec9b6ae --- /dev/null +++ b/configurations/dev-vps.nix @@ -0,0 +1,131 @@ +# NixOS configuration for development VPS +# Simple setup for Matrix + Forgejo + Slack bridge testing +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../modules/dev-services.nix + ]; + + # Basic boot configuration for VPS + boot = { + loader = { + grub = { + enable = true; + device = "/dev/vda"; # Common for cloud VPS + useOSProber = false; + }; + }; + # Cloud VPS typically uses virtio + initrd.availableKernelModules = [ + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_scsi" + ]; + }; + + # Network configuration + networking = { + hostName = "dev-matrix-vps"; + + # Most VPS providers use DHCP + useDHCP = false; + interfaces.ens3 = { # Common interface name, adjust as needed + useDHCP = true; + }; + + enableIPv6 = true; + + # Firewall - only expose what's needed + firewall = { + enable = true; + allowedTCPPorts = [ + 22 # SSH + 80 # HTTP + 443 # HTTPS + 3000 # Forgejo (for testing, remove in production) + 8008 # Matrix (for testing, remove in production) + ]; + allowPing = true; + }; + }; + + # SSH configuration + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "prohibit-password"; + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + }; + }; + + # Admin user + users.users.admin = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = [ + # Add your SSH public key here + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + ]; + }; + + # Enable sudo without password for admin (dev environment) + security.sudo.wheelNeedsPassword = false; + + # Enable dev services stack + services.dev-platform = { + enable = true; + domain = "localhost"; # Change to your domain or IP + + matrix = { + enable = true; + serverName = "dev.matrix"; + }; + + forgejo = { + enable = true; + subdomain = "git"; + }; + + slackBridge = { + enable = true; + workspace = ""; # Will be configured via secrets + }; + }; + + # Basic monitoring + services.netdata = { + enable = true; + config = { + global = { + "bind to" = "127.0.0.1"; + }; + }; + }; + + # Automatic garbage collection + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; + + # Enable flakes and optimize for deployment + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + + # Optimize for builds and downloads + max-jobs = "auto"; + cores = 0; # Use all cores + substituters = [ + "https://cache.nixos.org" + ]; + trusted-public-keys = [ + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + ]; + }; + + system.stateVersion = "24.11"; +} \ No newline at end of file diff --git a/configurations/vultr-dev.nix b/configurations/vultr-dev.nix new file mode 100644 index 0000000..89bd6d2 --- /dev/null +++ b/configurations/vultr-dev.nix @@ -0,0 +1,184 @@ +# NixOS configuration for Vultr development VPS +# Optimized for Matrix + Forgejo deployment without federation +{ config, pkgs, lib, ... }: + +{ + imports = [ + ../modules/dev-services.nix + ./vultr-hardware.nix + ]; + + # sops-nix secrets management + sops = { + defaultSopsFile = ../secrets/secrets.yaml; + age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ]; + + # Secret declarations + secrets."matrix-registration-token" = { + mode = "0400"; + }; + + secrets."acme-email" = { + mode = "0400"; + # Using direct email value, no secret needed + }; + }; + + # Boot configuration for Vultr VPS (Legacy BIOS mode) + boot = { + loader = { + grub = { + enable = true; + device = "/dev/vda"; # Legacy BIOS - install to MBR + efiSupport = false; + useOSProber = false; + }; + }; + # Vultr uses virtio drivers + initrd.availableKernelModules = [ + "virtio_pci" + "virtio_blk" + "virtio_net" + "virtio_scsi" + ]; + }; + + # Filesystem configuration managed by vultr-hardware.nix + # Boot partition, root partition, and swap declared via generated hardware config + + # Network configuration for Vultr + networking = { + hostName = "matrix"; + + # Vultr-specific network interface + useDHCP = false; + interfaces.ens3 = { # Vultr uses ens3 + useDHCP = true; + }; + + enableIPv6 = true; + + # Firewall - only expose reverse proxy ports + firewall = { + enable = true; + allowedTCPPorts = [ + 22 # SSH + 80 # HTTP (ACME challenges, redirects) + 443 # HTTPS + ]; + allowPing = true; + logRefusedConnections = false; # Reduce log noise on public VPS + }; + }; + + # SSH configuration - secure but accessible for development + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "prohibit-password"; # More secure than "yes" + PasswordAuthentication = false; + KbdInteractiveAuthentication = false; + X11Forwarding = false; + }; + # Basic security settings + extraConfig = '' + MaxAuthTries 3 + MaxSessions 10 + ClientAliveInterval 300 + ClientAliveCountMax 2 + ''; + }; + + # SSH key for root and admin users + users.users.root.openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOqHsgAuD/8LL6HN3fo7X1ywryQG393pyQ19a154bO+h delpad-2025" + ]; + + users.users.admin = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOqHsgAuD/8LL6HN3fo7X1ywryQG393pyQ19a154bO+h delpad-2025" + ]; + }; + + # Enable sudo without password for development convenience + security.sudo.wheelNeedsPassword = false; + + # Enable fail2ban for brute force protection + security.fail2ban-enhanced = { + enable = true; + bantime = "1h"; + maxretry = 3; + }; + + # Enable ACME for TLS certificates + security.acme = { + acceptTerms = true; + defaults.email = "admin@example.com"; # Using direct email as ACME doesn't support emailFile + }; + + # Dev services stack - simplified without federation + services.dev-platform = { + enable = true; + domain = "example.com"; + + matrix = { + enable = true; + port = 8008; + }; + + forgejo = { + enable = true; + subdomain = "git"; + port = 3000; + }; + + slackBridge = { + enable = true; + }; + }; + + # Basic monitoring for development + services.netdata = { + enable = true; + config = { + global = { + "bind to" = "127.0.0.1"; # Localhost only for security + }; + }; + }; + + # Automatic garbage collection to manage disk space + nix.gc = { + automatic = true; + dates = "weekly"; + options = "--delete-older-than 7d"; + }; + + # Allow insecure packages needed for Matrix bridges + nixpkgs.config.permittedInsecurePackages = [ + "olm-3.2.16" + ]; + + # NixOS configuration optimized for VPS + nix.settings = { + experimental-features = [ "nix-command" "flakes" ]; + + # Optimize for VPS builds and downloads + max-jobs = "auto"; + cores = 0; # Use all available cores + substituters = [ + "https://cache.nixos.org" + ]; + trusted-public-keys = [ + "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" + ]; + }; + + # Timezone and locale for VPS + time.timeZone = "UTC"; + i18n.defaultLocale = "en_US.UTF-8"; + + system.stateVersion = "24.11"; +} \ No newline at end of file diff --git a/docs/examples/minimal-matrix.nix b/docs/examples/minimal-matrix.nix new file mode 100644 index 0000000..ddef820 --- /dev/null +++ b/docs/examples/minimal-matrix.nix @@ -0,0 +1,79 @@ +# Minimal ops-jrz1 configuration example +# Demonstrates Matrix homeserver + single bridge deployment +{ config, pkgs, ... }: + +{ + imports = [ + ../../modules/matrix-continuwuity.nix + ../../modules/mautrix-slack.nix + ../../modules/security/ssh-hardening.nix + ../../modules/security/fail2ban.nix + ]; + + # Basic networking + networking = { + hostName = "matrix"; + firewall = { + enable = true; + allowedTCPPorts = [ 22 80 443 8008 ]; + }; + }; + + # Matrix homeserver configuration + services.matrix-homeserver = { + enable = true; + domain = "matrix.example.org"; + port = 8008; + enableRegistration = true; + enableFederation = false; + }; + + # Slack bridge configuration + services.mautrix-slack = { + enable = true; + matrix = { + homeserverUrl = "http://127.0.0.1:8008"; + serverName = "matrix.example.org"; + }; + bridge = { + permissions = { + "matrix.example.org" = "user"; + "@admin:matrix.example.org" = "admin"; + }; + }; + }; + + # Security hardening + security = { + fail2ban-enhanced = { + enable = true; + bantime = "1h"; + maxretry = 3; + }; + acme = { + acceptTerms = true; + defaults.email = "admin@example.com"; + }; + }; + + # SSH hardening + services.openssh = { + enable = true; + settings = { + PermitRootLogin = "prohibit-password"; + PasswordAuthentication = false; + }; + }; + + # PostgreSQL for bridge database + services.postgresql = { + enable = true; + ensureDatabases = [ "mautrix_slack" ]; + ensureUsers = [{ + name = "mautrix_slack"; + ensureDBOwnership = true; + }]; + }; + + system.stateVersion = "24.05"; +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..78e72c5 --- /dev/null +++ b/flake.lock @@ -0,0 +1,65 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1760284886, + "narHash": "sha256-TK9Kr0BYBQ/1P5kAsnNQhmWWKgmZXwUQr4ZMjCzWf2c=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "cf3f5c4def3c7b5f1fc012b3d839575dbe552d43", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "nixpkgs-unstable": "nixpkgs-unstable", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1760240450, + "narHash": "sha256-sa9bS9jSyc4vH0jSWrUsPGdqtMvDwmkLg971ntWOo2U=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "41fd1f7570c89f645ee0ada0be4e2d3c4b169549", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 6e0528a..cef7560 100644 --- a/flake.nix +++ b/flake.nix @@ -3,24 +3,28 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05"; + nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable"; - # sops-nix for secrets management (will be configured after extraction) - # sops-nix = { - # url = "github:Mic92/sops-nix"; - # inputs.nixpkgs.follows = "nixpkgs"; - # }; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { self, nixpkgs, ... }@inputs: { + outputs = { self, nixpkgs, nixpkgs-unstable, sops-nix, ... }@inputs: { nixosConfigurations = { ops-jrz1 = nixpkgs.lib.nixosSystem { system = "x86_64-linux"; + specialArgs = { + pkgs-unstable = import nixpkgs-unstable { + system = "x86_64-linux"; + config.allowUnfree = true; + }; + }; modules = [ ./configuration.nix ./hosts/ops-jrz1.nix - - # sops-nix will be added after extraction - # inputs.sops-nix.nixosModules.sops + sops-nix.nixosModules.sops ]; }; }; diff --git a/hosts/ops-jrz1.nix b/hosts/ops-jrz1.nix index ca9cb15..e7c3bc9 100644 --- a/hosts/ops-jrz1.nix +++ b/hosts/ops-jrz1.nix @@ -1,34 +1,51 @@ -{ config, pkgs, ... }: +{ config, pkgs, pkgs-unstable, ... }: { # ops-jrz1 dev/test server configuration - # This file will be populated with Matrix platform modules and server-specific settings + # Imports extracted Matrix modules from ops-base imports = [ # Hardware configuration will be added based on server specs # ./hardware-configuration.nix - # Matrix platform modules (to be imported after extraction) - # ../modules/matrix-continuwuity.nix - # ../modules/mautrix-slack.nix - # ../modules/mautrix-whatsapp.nix - # ../modules/mautrix-gmessages.nix - # ../modules/security/fail2ban.nix - # ../modules/security/ssh-hardening.nix + # Matrix platform modules + ../modules/matrix-continuwuity.nix + ../modules/mautrix-slack.nix + ../modules/mautrix-whatsapp.nix + ../modules/mautrix-gmessages.nix + ../modules/dev-services.nix + ../modules/security/fail2ban.nix + ../modules/security/ssh-hardening.nix + ../modules/matrix-secrets ]; # System configuration networking.hostName = "ops-jrz1"; - # Placeholder for Matrix homeserver configuration - # services.matrix-continuwuity = { + # Example Matrix homeserver configuration (disabled by default) + # Uncomment and configure for actual deployment: + # services.matrix-homeserver = { # enable = true; - # domain = "REPLACE_ME"; # ops-jrz1 domain + # domain = "matrix.example.org"; # port = 8008; + # enableRegistration = true; + # enableFederation = false; # }; - # Placeholder for bridge configurations - # Bridges will be configured after modules are extracted + # Example mautrix-slack bridge configuration (disabled by default) + # services.mautrix-slack = { + # enable = true; + # matrix = { + # homeserverUrl = "http://127.0.0.1:8008"; + # serverName = "matrix.example.org"; + # }; + # bridge = { + # permissions = { + # "matrix.example.org" = "user"; + # "@admin:matrix.example.org" = "admin"; + # }; + # }; + # }; system.stateVersion = "24.05"; } diff --git a/modules/dev-services.nix b/modules/dev-services.nix new file mode 100644 index 0000000..d66394d --- /dev/null +++ b/modules/dev-services.nix @@ -0,0 +1,308 @@ +# Development services module - Matrix, Forgejo, and Slack bridge +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.dev-platform; +in +{ + options.services.dev-platform = { + enable = mkEnableOption "development platform with Matrix and Forgejo"; + + domain = mkOption { + type = types.str; + default = "localhost"; + description = "Base domain for services"; + }; + + matrix = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable Matrix server"; + }; + + serverName = mkOption { + type = types.str; + default = cfg.domain; + description = "Matrix server name"; + }; + + port = mkOption { + type = types.port; + default = 8008; + description = "Matrix server port"; + }; + }; + + forgejo = { + enable = mkOption { + type = types.bool; + default = true; + description = "Enable Forgejo git service"; + }; + + subdomain = mkOption { + type = types.str; + default = "git"; + description = "Subdomain for Forgejo"; + }; + + port = mkOption { + type = types.port; + default = 3000; + description = "Forgejo port"; + }; + }; + + slackBridge = { + enable = mkOption { + type = types.bool; + default = false; + description = "Enable Slack bridge"; + }; + + workspace = mkOption { + type = types.str; + default = ""; + description = "Slack workspace name"; + }; + + port = mkOption { + type = types.port; + default = 29319; + description = "Slack bridge port"; + }; + }; + }; + + config = mkIf cfg.enable { + # PostgreSQL for Forgejo and bridge services (Matrix uses RocksDB) + services.postgresql = { + enable = true; + ensureDatabases = [ + "forgejo" + ] ++ optional cfg.slackBridge.enable "mautrix_slack"; + + ensureUsers = [ + { + name = "forgejo"; + ensureDBOwnership = true; + } + ] ++ optional cfg.slackBridge.enable { + name = "mautrix_slack"; + ensureDBOwnership = true; + }; + }; + + # Matrix Continuwuity server + systemd.services.matrix-continuwuity = mkIf cfg.matrix.enable { + description = "Continuwuity Matrix homeserver"; + after = [ "network.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + preStart = '' + # Generate config file at runtime with secret injection from systemd credentials + cat > /var/lib/matrix-continuwuity/continuwuity.toml <