From 347f102b39d88c8a20636153142bce835f0a10df Mon Sep 17 00:00:00 2001 From: randogoth Date: Sat, 4 Jul 2026 17:39:55 +0300 Subject: [PATCH] added oberon --- flake.nix | 6 +++ modules/services/oberon.nix | 84 +++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 modules/services/oberon.nix diff --git a/flake.nix b/flake.nix index 2626b67..4f5eae6 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,11 @@ jirorian.url = "git+ssh://git@codeberg.org/randogoth/jirorian.git"; jirorian.inputs.nixpkgs.follows = "nixpkgs"; + + # oberon lives in the private xfay monorepo (server/oberon). It pins its own + # nixpkgs (nixos-unstable, for Dart 3.11) and must NOT follow ours — 25.11's + # Dart 3.9 is too old for its resolved lockfile. + oberon.url = "git+ssh://git@codeberg.org/randogoth/xfay.git?dir=server/oberon"; }; outputs = { self, nixpkgs, sops-nix, ... }@inputs: @@ -56,6 +61,7 @@ ./modules/services/static-sites ./modules/services/webhook-deploy.nix ./modules/services/jirorian.nix + ./modules/services/oberon.nix ./modules/services/nip05.nix ./modules/services/torrent-tracker.nix ./modules/services/backup.nix diff --git a/modules/services/oberon.nix b/modules/services/oberon.nix new file mode 100644 index 0000000..188568d --- /dev/null +++ b/modules/services/oberon.nix @@ -0,0 +1,84 @@ +{ pkgs, inputs, config, ... }: +let + # Public domain for the fax backend — numbers REST + Sinch inbound webhook only. + # The outbound consumer is relay-driven and has no public route. + domain = "fax.xfay.app"; + + # Non-secret runtime configuration. + port = 8391; + relayUrl = "wss://relay.xfay.app/"; + cdnUrl = "https://upload.xfay.app"; + + pkg = inputs.oberon.packages.${pkgs.system}.default; + + # Wrapper that exports sops-managed secrets, then execs oberon (same pattern as + # jirorian.nix — EnvironmentFile loads too early for sops-nix). + startScript = pkgs.writeShellScript "oberon-start" '' + set -euo pipefail + export SINCH_PROJECT_ID=$(cat ${config.sops.secrets.oberon_sinch_project_id.path}) + export SINCH_KEY_ID=$(cat ${config.sops.secrets.oberon_sinch_key_id.path}) + export SINCH_KEY_SECRET=$(cat ${config.sops.secrets.oberon_sinch_key_secret.path}) + export SINCH_FAX_SERVICE_ID=$(cat ${config.sops.secrets.oberon_sinch_service_id.path}) + export SINCH_WEBHOOK_USER=$(cat ${config.sops.secrets.oberon_sinch_webhook_user.path}) + export SINCH_WEBHOOK_PASS=$(cat ${config.sops.secrets.oberon_sinch_webhook_pass.path}) + export FAX_INBOUND_NOSTR_PRIVKEY=$(cat ${config.sops.secrets.oberon_inbound_privkey.path}) + export FAX_OUTBOUND_NOSTR_PRIVKEY=$(cat ${config.sops.secrets.oberon_outbound_privkey.path}) + export OFFICIAL_FAX_NUMBER=$(cat ${config.sops.secrets.oberon_official_number.path}) + export CDN_APP_SECRET=$(cat ${config.sops.secrets.oberon_cdn_app_secret.path}) + exec ${pkg}/bin/oberon + ''; +in +{ + # Secrets — add corresponding keys to secrets/bucur.yaml via sops. + sops.secrets.oberon_sinch_project_id = { owner = "oberon"; }; + sops.secrets.oberon_sinch_key_id = { owner = "oberon"; }; + sops.secrets.oberon_sinch_key_secret = { owner = "oberon"; }; + sops.secrets.oberon_sinch_service_id = { owner = "oberon"; }; + sops.secrets.oberon_sinch_webhook_user = { owner = "oberon"; }; + sops.secrets.oberon_sinch_webhook_pass = { owner = "oberon"; }; + sops.secrets.oberon_inbound_privkey = { owner = "oberon"; }; + sops.secrets.oberon_outbound_privkey = { owner = "oberon"; }; + sops.secrets.oberon_official_number = { owner = "oberon"; }; + sops.secrets.oberon_cdn_app_secret = { owner = "oberon"; }; + + users.users.oberon = { + isSystemUser = true; + group = "oberon"; + home = "/var/lib/oberon"; + }; + users.groups.oberon = {}; + + systemd.services.oberon = { + description = "Oberon — xfay fax backend (Sinch ⇄ Nostr bridge)"; + after = [ "network.target" "sops-nix.service" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "simple"; + User = "oberon"; + Group = "oberon"; + StateDirectory = "oberon"; + RuntimeDirectory = "oberon"; + ExecStart = startScript; + Environment = [ + "PORT=${toString port}" + "DB_PATH=/var/lib/oberon/oberon.db" + "RELAY_URLS=${relayUrl}" + "CDN_URL=${cdnUrl}" + "CDN_APP_NAME=xfay" + # Abuse controls (M4) — start conservative; empty prefix list = allow all. + "ALLOWED_DESTINATION_PREFIXES=+1" + "MAX_FAXES_PER_PUBKEY_PER_DAY=20" + "MAX_FAXES_PER_DESTINATION_PER_DAY=5" + ]; + Restart = "on-failure"; + RestartSec = 5; + }; + }; + + # Caddy reverse proxy fragment — picked up via the glob import in caddy.nix. + environment.etc."caddy/Caddyfile.d/oberon.caddyfile".text = '' + ${domain} { + reverse_proxy localhost:${toString port} + } + ''; +}