85 lines
3.4 KiB
Nix
85 lines
3.4 KiB
Nix
|
|
{ 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}
|
||
|
|
}
|
||
|
|
'';
|
||
|
|
}
|