diff --git a/flake.lock b/flake.lock index 3ba6cfd..781fc09 100644 --- a/flake.lock +++ b/flake.lock @@ -188,11 +188,11 @@ ] }, "locked": { - "lastModified": 1778009629, - "narHash": "sha256-nUoQtf4Zq7DRYJrfv904hjrxjAlWVP6a1pNNFKx3FCg=", + "lastModified": 1778144356, + "narHash": "sha256-dGM+QCstz/DyLB68+JK5GWyMx4QSqmOJEVgZmy63d/g=", "owner": "nix-community", "repo": "home-manager", - "rev": "00ed86e58bb6979a7921859fd1615d19382eac5c", + "rev": "e4419d3123b780d5f4c0bceeace450424387638c", "type": "github" }, "original": { @@ -301,11 +301,11 @@ "xdph": "xdph" }, "locked": { - "lastModified": 1777995176, - "narHash": "sha256-iq9W7sFoKFNFt0UAxRnnLVkbvNT+nJWsZQFNcWh/fCU=", + "lastModified": 1778199997, + "narHash": "sha256-vmCYnK7/iRQGWj+s0l3+cf/IVoUcCTrlFtgUCTwRdjU=", "owner": "hyprwm", "repo": "Hyprland", - "rev": "a531c2ed6bb4cd4eb2c6cb51838cb07a37226377", + "rev": "de9f8dc9831d921cd1ee30d5d14f45f0e345a8ca", "type": "github" }, "original": { @@ -561,11 +561,11 @@ ] }, "locked": { - "lastModified": 1777492286, - "narHash": "sha256-PwuoEJQcjSKJNP5T55qhfDwIP0tw5zxEhfu8GDfKfeg=", + "lastModified": 1778179779, + "narHash": "sha256-Ri6rVf54CRD3aISHLhSY6H4tBScVjm9ebkv7rF2lcZM=", "owner": "hyprwm", "repo": "hyprutils", - "rev": "ec5c0c709706bad5b82f667fd8758eae442577ce", + "rev": "3e170e5ad010602671f5f25b327e8bdb8fdd532c", "type": "github" }, "original": { @@ -656,11 +656,11 @@ "nixpkgs-nixcord": "nixpkgs-nixcord" }, "locked": { - "lastModified": 1778058822, - "narHash": "sha256-iWK6mx+b9UeIrLCRC3tQMluI9TU093Q/q78/8LW7IHk=", + "lastModified": 1778202527, + "narHash": "sha256-Yn0A4iYFtVNYIf1IXfT1R7gYNbJ5UEqvExii2aK4VAY=", "owner": "kaylorben", "repo": "nixcord", - "rev": "a88a9e39026c8456c9cbb130a794a37c358ef07d", + "rev": "471c6da493cb642bbc941a4bc5c10c22595ed013", "type": "github" }, "original": { diff --git a/home/desktop/hyprland/default.nix b/home/desktop/hyprland/default.nix index 7cb3c8c..74e8f87 100644 --- a/home/desktop/hyprland/default.nix +++ b/home/desktop/hyprland/default.nix @@ -66,6 +66,11 @@ in "XCURSOR_SIZE,24" ]; + debug = { + disable_logs = false; + enable_stdout_logs = false; + }; + monitor = [ "DP-1, 1920x1080@60, 1920x0, 1" "HDMI-A-2, 1920x1080@60, 0x0, 1" @@ -113,7 +118,6 @@ in enabled = false; range = 16; render_power = 4; - ignore_window = true; color = "$green"; color_inactive = "$red"; }; @@ -146,7 +150,6 @@ in # ]; dwindle = { - pseudotile = "yes"; preserve_split = "yes"; }; diff --git a/home/neovim/catppuccin.nix b/home/neovim/catppuccin.nix index 98ba46c..c463b47 100644 --- a/home/neovim/catppuccin.nix +++ b/home/neovim/catppuccin.nix @@ -1,5 +1,4 @@ -{ pkgs, ... }: -{ +_: { # Catppuccin: Soothing pastel theme for Neovim # Provides consistent theming across plugins with transparency support. programs.nixvim = { @@ -20,6 +19,7 @@ mini = { enabled = true; }; + lualine = true; }; }; }; diff --git a/home/neovim/lualine.nix b/home/neovim/lualine.nix index 4f85435..9157117 100644 --- a/home/neovim/lualine.nix +++ b/home/neovim/lualine.nix @@ -1,5 +1,4 @@ -{ pkgs, ... }: -{ +_: { # Lualine: Fast and customizable statusline for Neovim # Displays file info, git status, diagnostics, and mode at the bottom of the editor. programs.nixvim.plugins.lualine = { @@ -7,7 +6,6 @@ settings = { options = { - theme = "catppuccin"; component_separators = { left = "|"; right = "|"; diff --git a/hosts/cyper-controller/configuration.nix b/hosts/cyper-controller/configuration.nix index 1e9d6a4..ee2be17 100644 --- a/hosts/cyper-controller/configuration.nix +++ b/hosts/cyper-controller/configuration.nix @@ -42,6 +42,5 @@ }; efi.canTouchEfiVariables = true; }; - system.stateVersion = "26.05"; } diff --git a/hosts/cyper-desktop/configuration.nix b/hosts/cyper-desktop/configuration.nix index 0bfe984..9f68e4a 100644 --- a/hosts/cyper-desktop/configuration.nix +++ b/hosts/cyper-desktop/configuration.nix @@ -1,3 +1,4 @@ +{ ... }: { imports = [ ./hardware-configuration.nix ]; @@ -32,5 +33,16 @@ efi.canTouchEfiVariables = true; }; + services.desktopManager.plasma6.enable = false; + services.displayManager.sddm = { + enable = false; + wayland.enable = true; + }; + + environment.pathsToLink = [ + "/share/applications" + "/share/xdg-desktop-portal" + ]; + system.stateVersion = "26.05"; } diff --git a/nixos/default.nix b/nixos/default.nix index d3fa149..a3d6c6f 100644 --- a/nixos/default.nix +++ b/nixos/default.nix @@ -18,7 +18,7 @@ ./regreet.nix ./plymouth.nix ./audio.nix - ./webcam.nix + # ./webcam.nix ./virt.nix ./catppuccin.nix ]; @@ -95,7 +95,7 @@ // lib.optionalAttrs (!isServer) { dconf.enable = true; hyprland = { - enable = true; + enable = false; package = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland; }; steam.enable = true; @@ -159,6 +159,7 @@ "video" "audio" "libvirtd" + "input" ]; }; } diff --git a/nixos/regreet.nix b/nixos/regreet.nix index d24a3a3..4fe0a85 100644 --- a/nixos/regreet.nix +++ b/nixos/regreet.nix @@ -1,5 +1,6 @@ { lib, + pkgs, ... }: { @@ -13,7 +14,7 @@ }; programs.regreet = { - enable = true; + enable = false; cageArgs = [ "-s" @@ -63,4 +64,18 @@ }; }; }; + + services.greetd = { + enable = true; + settings = { + default_session = { + command = "${pkgs.tuigreet}/bin/tuigreet --cmd start-hyprland"; + user = "greeter"; + }; + initial_session = { + command = "Hyprland"; + user = "phil"; + }; + }; + }; } diff --git a/nixos/roles/matrix/default.nix b/nixos/roles/matrix/default.nix index 8d3f947..de1e2c8 100644 --- a/nixos/roles/matrix/default.nix +++ b/nixos/roles/matrix/default.nix @@ -8,6 +8,7 @@ ./clients.nix ./mjolnir.nix ./coturn.nix + ./maubot.nix ./discord-bridge.nix ./whatsapp-bridge.nix ]; diff --git a/nixos/roles/matrix/discord-bridge.nix b/nixos/roles/matrix/discord-bridge.nix index 9bcf190..217188b 100644 --- a/nixos/roles/matrix/discord-bridge.nix +++ b/nixos/roles/matrix/discord-bridge.nix @@ -1,4 +1,4 @@ -{ config, pkgs, ... }: +{ config, lib, ... }: { nixpkgs.config.permittedInsecurePackages = [ "olm-3.2.16" ]; @@ -61,4 +61,5 @@ }; }; }; + systemd.services.mautrix-discord-registration.serviceConfig.UMask = lib.mkForce "0022"; } diff --git a/nixos/roles/matrix/maubot.nix b/nixos/roles/matrix/maubot.nix new file mode 100644 index 0000000..d1066ef --- /dev/null +++ b/nixos/roles/matrix/maubot.nix @@ -0,0 +1,46 @@ +{ config, ... }: +{ + services = { + maubot = { + enable = true; + plugins = [ config.services.maubot.package.plugins.weather ]; + settings = { + database = "postgresql:///maubot?host=/run/postgresql"; + homeservers = { + "cyperpunk.de" = { + url = "https://matrix.cyperpunk.de"; + }; + }; + admins = { + root = ""; + dergrumpf = "$2b$12$62kYoqsSloK3hco/N/EZUupD/JOjTMMVhUf064cqveBJYXGJJF8Hi"; + }; + plugin_directories = { + upload = "/var/lib/maubot/plugins"; + load = [ "/var/lib/maubot/plugins" ]; + trash = "/var/lib/maubot/trash"; + }; + }; + }; + + postgresql = { + ensureUsers = [ + { + name = "maubot"; + ensureDBOwnership = true; + } + ]; + ensureDatabases = [ "maubot" ]; + }; + + nginx.virtualHosts."cyperpunk.de".locations."/_matrix/maubot/" = { + proxyPass = "http://127.0.0.1:29316"; + proxyWebsockets = true; + }; + }; + + systemd.tmpfiles.rules = [ + "d /var/lib/maubot/plugins 0750 maubot maubot -" + "d /var/lib/maubot/trash 0750 maubot maubot -" + ]; +} diff --git a/nixos/roles/matrix/postgres-backup.nix b/nixos/roles/matrix/postgres-backup.nix new file mode 100644 index 0000000..752acd2 --- /dev/null +++ b/nixos/roles/matrix/postgres-backup.nix @@ -0,0 +1,102 @@ +{ + config, + pkgs, + lib, + ... +}: +{ + sops.secrets = { + pg_replication_password = { + owner = "postgres"; + group = "postgres"; + }; + }; + + services.postgresql = { + enable = true; + package = pkgs.postgresql_15; # must match cyper-proxy's PG version exactly + + settings = { + hot_standby = true; + hot_standby_feedback = true; + max_standby_streaming_delay = "30s"; + listen_addresses = "127.0.0.1"; # only local, no external exposure + wal_receiver_timeout = "60s"; + recovery_min_apply_delay = "0"; # set e.g. "1h" for a delayed safety replica + }; + }; + + # Writes standby.signal and primary_conninfo before PostgreSQL starts. + systemd.services.postgresql = { + preStart = lib.mkAfter '' + DATADIR="${config.services.postgresql.dataDir}" + PG_PASS=$(cat ${config.sops.secrets.pg_replication_password.path}) + + # Tell Postgres to start as a hot standby + if [ ! -f "$DATADIR/standby.signal" ]; then + touch "$DATADIR/standby.signal" + chown postgres:postgres "$DATADIR/standby.signal" + fi + + # primary_conninfo via Tailscale — no public IP involved + CONNINFO="host=100.109.10.91 port=5432 user=replicator password=$PG_PASS application_name=cyper-controller sslmode=require" + + grep -v "^primary_conninfo" "$DATADIR/postgresql.auto.conf" 2>/dev/null > /tmp/auto.conf.tmp || true + echo "primary_conninfo = '$CONNINFO'" >> /tmp/auto.conf.tmp + mv /tmp/auto.conf.tmp "$DATADIR/postgresql.auto.conf" + chown postgres:postgres "$DATADIR/postgresql.auto.conf" + ''; + }; + + # Run once manually to seed the standby: systemctl start postgresql-basebackup + # Do NOT add it to wantedBy — it would wipe the data dir on every reboot. + systemd.services.postgresql-basebackup = { + description = "Bootstrap PostgreSQL standby via pg_basebackup from cyper-proxy"; + requires = [ + "network-online.target" + "tailscaled.service" + ]; + after = [ + "network-online.target" + "tailscaled.service" + ]; + + serviceConfig = { + Type = "oneshot"; + User = "postgres"; + RemainAfterExit = false; + }; + + script = '' + DATADIR="${config.services.postgresql.dataDir}" + PG_PASS=$(cat ${config.sops.secrets.pg_replication_password.path}) + + if [ -d "$DATADIR/global" ]; then + echo "Data directory already exists — skipping." + echo "Remove $DATADIR manually to force a re-initialise." + exit 0 + fi + + echo "Running pg_basebackup from cyper-proxy via Tailscale..." + PGPASSWORD="$PG_PASS" ${config.services.postgresql.package}/bin/pg_basebackup \ + --host=100.109.10.91 \ + --port=5432 \ + --username=replicator \ + --pgdata="$DATADIR" \ + --wal-method=stream \ + --write-recovery-conf \ + --checkpoint=fast \ + --progress \ + --verbose + + chown -R postgres:postgres "$DATADIR" + chmod 0700 "$DATADIR" + echo "Done. Start postgresql.service to begin streaming replication." + ''; + }; + + # Block any external access to postgres on the public interface + networking.firewall = { + interfaces."tailscale0".allowedTCPPorts = [ ]; # replication is outbound only + }; +} diff --git a/nixos/roles/matrix/synapse.nix b/nixos/roles/matrix/synapse.nix index 1715766..47318fd 100644 --- a/nixos/roles/matrix/synapse.nix +++ b/nixos/roles/matrix/synapse.nix @@ -1,6 +1,7 @@ { config, pkgs, + lib, ... }: let @@ -33,6 +34,7 @@ in owner = "matrix-synapse"; group = "matrix-synapse"; }; + pg_replication_password = { }; }; services = { @@ -144,11 +146,34 @@ in enable = true; initialScript = pkgs.writeText "synapse-init.sql" '' CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD 'synapse'; + CREATE ROLE replicator WITH REPLICATION LOGIN; CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse" TEMPLATE template0 LC_COLLATE = "C" LC_CTYPE = "C"; ''; + + settings = { + wal_level = "replica"; + max_wal_senders = 3; + wal_keep_size = "512MB"; + }; + + authentication = lib.mkAfter '' + host replication replicator 100.0.0.0/8 scram-sha-256 + ''; }; }; + + systemd.services = { + matrix-synapse.serviceConfig.ReadOnlyPaths = [ + "/var/lib/mautrix-discord" + "/var/lib/mautrix-whatsapp" + ]; + postgresql.postStart = lib.mkAfter '' + PG_PASS=$(cat ${config.sops.secrets.pg_replication_password.path}) + ${config.services.postgresql.package}/bin/psql -U postgres -c \ + "ALTER ROLE replicator WITH PASSWORD '$PG_PASS';" + ''; + }; } diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index ca56938..895789d 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -13,6 +13,7 @@ mjolnir_access_token: ENC[AES256_GCM,data:vvrAY9CAkEIGEzah+TQiwa6PahGuXVvU7wzBpT coturn_static_auth_secret: ENC[AES256_GCM,data:7AI0E8Hu4WxI5q4j1GqBMSQ+evE006uPMtwIfGn4eFz+XB2JA6fhhiGMPPxSkqOyK+3eZJ5ahiG05JpmBmmAbw==,iv:hQJQQDVo43U7lvV754PC1THeFCpZZEyag+BslXyoDos=,tag:Vkm+IXr1h8ZNpah6UYaKng==,type:str] discord_bot_token: ENC[AES256_GCM,data:j37Qo3FCyRwNFqWSWpnQKCs+AxH5HlQ8U5If7ylHilQoORp8Pb3TtNETTJSjZyvUXllldevAbHrbAEEKnNfoUJx1U8/wl6H0,iv:WQqxFXTE+0LIB2lSvVcnr4LNXPE7uzNc0Kk8NU6Z/aE=,tag:fNeQLhoThEgfa4sSGKLZCw==,type:str] discord_client_id: ENC[AES256_GCM,data:U/iUKXT6Nsl6LRN9lPh1xaIaqw==,iv:k7kQ8rJBrMs3YwD9aDfZ6qhd7H3aVsSPTOwEIxVTw2Y=,tag:2wKhxGbf+P+h3BYeWUSczA==,type:str] +pg_replication_password: ENC[AES256_GCM,data:w2h07D+j3LNkcbvoKQ2Qp3HSvC2Wf5HRAPAo/HNhmUkHBOaDyILNxo7IDjqajv0jytpG7q4joCJQhS7tEUlA9Q==,iv:26ZurAq61IDqGdAl0yPpoTJElo93hJJIEUlza4DGDNc=,tag:a46FOKgeqEEZE+rC+H9NbQ==,type:str] gitea: dbPassword: ENC[AES256_GCM,data:S6VvRgkdYk1AzXljyQEEq68UJ9zrFy6+INBMIAspXNcqcM6o+es19o0mcXA=,iv:/pHYpkZZq+9Md+75uSCb2YXfSvaDzUh6mMfH53wb7eg=,tag:ZnbyCQwrK2JnbO5HFqgJYw==,type:str] internalToken: ENC[AES256_GCM,data:7N8TkPNb1YdCk2uAcCvVd2pKRVOf85//DYxAvz0UCg1E8ccEI5630xVyKafDFiSTM4ER7xiYelartzXL0jLWSf3QNOjSHUP8TIAz4bJRAZUJPxO917bURSLGGe7WEOfONzqy3Ts5QhrJ,iv:DiIs1ytlwLvqD/Ejep6m2fmpSqdFZkxBcgLNt6+29jY=,tag:8jsEcOkH0p+1mP9cnVjiDQ==,type:str] @@ -31,7 +32,7 @@ sops: N3I5dzUwc3JtYzczMUhyT04vSHlZamMKT+FzYcDLmlEFYxm/XoBpJb8XaZzBH1v9 6fuez+zApathZfl14w41kAUojPWBznnxDqYtNvzVVLXwnpp3BMx+7w== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-05-07T07:00:06Z" - mac: ENC[AES256_GCM,data:KSkcRm/aTGAZBfj2ZZ03x8EB2Sh0lFKUSDKLedgtYYk/QnUKTZOO8oaT36xIdrPN0pjK1CnElDQMkAHG6JCklif2UkcodKcerVWaVcNwZ4mk6wSvZz7OIqneMR0W/U+Ly3NMgwIKrlP9f7axiYMq9JyK6pVeepKrmw4RvOPzxqU=,iv:vlcFxxV5EofNAPnDf7eGJZ8FUM83uGUnkZtU57Epb3Y=,tag:yfYpa/F7PTwvZY11SZyRaw==,type:str] + lastmodified: "2026-05-09T09:12:42Z" + mac: ENC[AES256_GCM,data:sTVJcBb8cBzixOBQNlx44/m8W3smfwP5fhmnm9hlr5iwMuPJ7JeKTUqqlQaeL4RX/MpEuLc+Rm4thromJ11M/aA5yiqgWOY7vn8xYPoScGzx6HfV1cRJTofmrWmpxrDICQULwOaO+c8vwFBPy7fVqF/AacRtejx5sEOxsMzrYR8=,iv:/Fc5//8coI/rdQIyGcxCTgXPzOS9xNd0ChDHNs4yffw=,tag:8w6bbZcWMBZQWkujhXQY0w==,type:str] unencrypted_suffix: _unencrypted version: 3.12.2