Skip to content

Deployment ​

OwlRora is one stateless-at-the-edge Rust server with embedded Console assets. Durable state lives in PostgreSQL; Redis is a required coordination dependency for every non-health-only profile in the current implementation.

Released image boundary

Use only an exact published version tag or, preferably, its immutable digest. Read the selected release notes and verify that its source contains the capabilities and migrations required by this guide. OwlRora does not publish or promote a mutable latest image tag.

Tested deployment components ​

Repository CI and image smoke tests currently exercise:

  • PostgreSQL 17;
  • Redis 7.4 and Redis 8;
  • the Debian-based linux/amd64 server image built by GitHub-hosted runners.

This is evidence of tested combinations, not a declaration that every older PostgreSQL/Redis release or every container architecture is supported. The server release workflow currently publishes one image architecture per release run, not a multi-architecture manifest.

Deployment profiles ​

ProfileHTTP surfacesWorkersRequired external state
full (default)/health, public coarse /ready, Console, Management API, Gateway ingressmanagement and gatewayPostgreSQL, Redis
management/health, public coarse /ready, Console, Management APImanagementPostgreSQL, Redis
gateway/health, /ready, Gateway ingressgatewayPostgreSQL, Redis
worker/health and /readymanagement and gatewayPostgreSQL, Redis
health-only/health onlynonenone

The official binary uses bundled software custody, so every non-health-only profile also requires OWLRORA_SECRET_ROOT. full and management additionally require the public origin and seed administrator key.

Start with full unless you have a concrete isolation or scaling reason. Split profiles use the same database, Redis endpoint, installation identity, seed-key material where management is enabled, and secret root.

Production topology ​

mermaid
graph TD
  U[Clients and operators] --> P[TLS reverse proxy / load balancer]
  P --> S1[OwlRora full or management/gateway processes]
  P --> S2[OwlRora replicas]
  S1 --> PG[(PostgreSQL 17)]
  S2 --> PG
  S1 --> R[(Redis 7.4 or 8)]
  S2 --> R
  W[Optional worker-only processes] --> PG
  W --> R

Identical HTTP-serving replicas do not require load-balancer session affinity or durable application identities. Runtime diagnostics describe the process that answered the request; fleet inventory and rollout state remain responsibilities of the deployment platform.

1. Choose an immutable image ​

For a published release:

bash
IMAGE='ghcr.io/owlfoundry/owlrora:<released-semver>'
docker pull "$IMAGE"
docker inspect --format '{{index .RepoDigests 0}}' "$IMAGE"

Use the resulting ghcr.io/owlfoundry/owlrora@sha256:... digest in production.

To evaluate current source instead:

bash
git clone https://github.com/owlfoundry/owlrora.git
cd owlrora
git checkout main

docker build --pull \
  --build-arg OWLRORA_VERSION=0.0.0-dev \
  --build-arg VCS_REF="$(git rev-parse HEAD)" \
  --tag owlrora:source .

2. Provision PostgreSQL and Redis ​

The server uses its runtime PostgreSQL connection for embedded migrations. The database role therefore needs the DDL privileges required to create and alter tables, indexes, functions, triggers, and constraints.

Redis is not an optional cache in the current source. Startup connects and sends PING; a failure prevents a non-health-only process from starting. The client accepts one redis:// or rediss:// endpoint. Redis Cluster client mode is not implemented or tested; place a managed HA service behind one stable endpoint only after validating its failover behavior.

Capacity planning starts with per-process pools:

text
potential PostgreSQL connections = processes × OWLRORA_DATABASE_MAX_CONNECTIONS
potential Redis connections      = processes × OWLRORA_REDIS_POOL_SIZE

Leave additional capacity for migrations, backups, monitoring, and administrative access.

3. Generate deployment secrets ​

Create the software-custody root and built-in seed Management API key once:

bash
umask 077
python3 > owlrora-secrets.env <<'PY'
import base64
import secrets


def b64url(value: bytes) -> str:
    return base64.urlsafe_b64encode(value).decode("ascii").rstrip("=")


print("OWLRORA_SECRET_ROOT=" + b64url(secrets.token_bytes(32)))
print(
    "OWLRORA_SEED_ADMIN_API_KEY="
    + "owlrora_mgmt_v1."
    + b64url(secrets.token_bytes(16))
    + "."
    + b64url(secrets.token_bytes(32))
)
PY
chmod 600 owlrora-secrets.env

Store both in a deployment secret manager. Never put production values in Git, image layers, Compose YAML, or PostgreSQL.

  • Losing OWLRORA_SECRET_ROOT makes existing recoverable secret envelopes unreadable.
  • Changing it is not an online rotation mechanism; the official binary has no root ring.
  • Changing the seed key changes its deterministic version identity and invalidates key-derived seed sessions across the fleet.

4. Create the runtime environment ​

Append a single-process full configuration:

bash
cat >> owlrora-secrets.env <<'EOF'
OWLRORA_PROFILE=full
OWLRORA_ADDR=0.0.0.0:8080
OWLRORA_PUBLIC_ORIGIN=https://owlrora.example.com
OWLRORA_DATABASE_URL=postgresql://owlrora:<password>@postgres.internal:5432/owlrora
OWLRORA_REDIS_URL=rediss://:<password>@redis.internal:6379/0
OWLRORA_OPERATOR_NETWORKS=127.0.0.0/8,::1/128
RUST_LOG=info
EOF
chmod 600 owlrora-secrets.env

Replace placeholders before starting. See Configuration for every setting and range.

5. Start the non-root container ​

bash
docker run --detach \
  --name owlrora \
  --restart unless-stopped \
  --env-file ./owlrora-secrets.env \
  --publish 127.0.0.1:8080:8080 \
  'ghcr.io/owlfoundry/owlrora@sha256:<pinned-digest>'

The image runs as UID/GID 10001, uses tini as PID 1, and requires no persistent application volume. If you enforce a read-only root filesystem, validate it with every configured workload/default-chain credential provider because those external SDK chains may read provider-specific files or metadata.

6. Terminate TLS at a trusted proxy ​

The server currently serves plaintext HTTP and does not implement native listener TLS. Bind it to loopback or a private network and terminate TLS at a reverse proxy that supports SSE and WebSocket upgrades.

Use separate public and operator ingress. This Caddy example blocks protected operations paths on the public host and exposes them only on a private operator host:

text
owlrora.example.com {
    @operator_operations path /api/v1/system/operations*
    respond @operator_operations 404

    reverse_proxy 127.0.0.1:8080 {
        flush_interval -1
    }
}

owlrora-ops.internal.example.com {
    bind 10.0.0.10
    reverse_proxy 127.0.0.1:8080
}

Restrict the operator hostname with private routing, firewall policy, and appropriate proxy authentication. With a same-host proxy, keep OWLRORA_OPERATOR_NETWORKS=127.0.0.0/8,::1/128; OwlRora evaluates the direct proxy peer and does not consume forwarded-client-IP headers. If the proxy connects over a container or private network, configure only that proxy CIDR instead. Set OWLRORA_PUBLIC_ORIGIN to exactly the browser-visible public HTTPS origin.

7. Check liveness and readiness ​

bash
curl -fsS http://127.0.0.1:8080/health

/health returns ok when the HTTP process is alive. It does not prove PostgreSQL, Redis, runtime publication, routes, or workers are ready.

For every profile except health-only, /ready is a public coarse load-balancer signal that returns only {"status":"ready"} or {"status":"not_ready"}:

bash
curl -fsS https://owlrora.example.com/ready

Retrieve detailed protected evidence separately:

bash
owlrora \
  --server-url https://owlrora-ops.internal.example.com \
  --key-env OWLRORA_MANAGEMENT_API_KEY \
  --output json \
  system operations readiness

Use each process's /ready for local admission and /health only for liveness. Protected operations called on a management process describe that process plus durable/shared evidence; they do not prove the local runtime or worker state of separate gateway/worker processes. Combine direct readiness probes, deployment-platform rollout checks, OTLP, and external end-to-end probes for split profiles.

Next steps ​

Released under the BSD 3-Clause License.