{ pkgs, inputs, config, ... }: let # Public domain for this service — set before deploying. domain = "upload.otherwhere.app"; # Non-secret runtime configuration. port = 8390; relayUrl = "wss://relay.otherwhere.app/"; cdnUrl = "https://cdn.otherwhere.app"; bucketName = "media"; pkg = inputs.jirorian.packages.${pkgs.system}.default; # Writes an EnvironmentFile from sops-managed secret files at service start. makeEnv = pkgs.writeShellScript "jirorian-make-env" '' set -euo pipefail install -m 0600 /dev/null /run/jirorian/env { echo "R2_ACCESS_KEY_ID=$(cat ${config.sops.secrets.jirorian_r2_access_key_id.path})" echo "R2_SECRET_ACCESS_KEY=$(cat ${config.sops.secrets.jirorian_r2_secret_access_key.path})" echo "R2_ENDPOINT=$(cat ${config.sops.secrets.jirorian_r2_endpoint.path})" echo "SERVICE_NOSTR_PRIVKEY=$(cat ${config.sops.secrets.jirorian_nostr_privkey.path})" echo "JIRORIAN_APP_SECRETS=$(cat ${config.sops.secrets.jirorian_app_secrets.path})" } >> /run/jirorian/env ''; in { # Secrets — add corresponding keys to secrets/bucur.yaml via sops. sops.secrets.jirorian_r2_access_key_id = { owner = "jirorian"; }; sops.secrets.jirorian_r2_secret_access_key = { owner = "jirorian"; }; sops.secrets.jirorian_r2_endpoint = { owner = "jirorian"; }; sops.secrets.jirorian_nostr_privkey = { owner = "jirorian"; }; sops.secrets.jirorian_app_secrets = { owner = "jirorian"; }; users.users.jirorian = { isSystemUser = true; group = "jirorian"; home = "/var/lib/jirorian"; }; users.groups.jirorian = {}; systemd.services.jirorian = { description = "Jirorian — Nostr-native R2 image upload API"; after = [ "network.target" "sops-nix.service" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; User = "jirorian"; Group = "jirorian"; StateDirectory = "jirorian"; RuntimeDirectory = "jirorian"; ExecStartPre = "+${makeEnv}"; ExecStart = "${pkg}/bin/jirorian"; EnvironmentFile = "/run/jirorian/env"; Environment = [ "JIRORIAN_BASE_URL=https://${domain}" "JIRORIAN_PORT=${toString port}" "JIRORIAN_DB=/var/lib/jirorian/jirorian.db" "R2_BUCKET_NAME=${bucketName}" "R2_CDN_URL=${cdnUrl}" "SERVICE_RELAY_URL=${relayUrl}" ]; Restart = "on-failure"; RestartSec = 5; }; }; # Caddy reverse proxy fragment — picked up via the glob import in caddy.nix. environment.etc."caddy/Caddyfile.d/jirorian.caddyfile".text = '' ${domain} { reverse_proxy localhost:${toString port} } ''; }