Record API

The reemo-infra role can deploy Record API, the service that records container sessions (screen frames and logs) and serves them back in the Admin Area. This service is not deployed by default.

See also

Session Recordings — Replay the recorded sessions from the Admin Area.

What Record API Deploys

When Record API is enabled, the role deploys the following on the Swarm:

  • recorddb: the database of sessions, the frame index, and the logs, based on YugabyteDB (PostgreSQL-compatible).

  • recordapi: the service that receives the frames from the agent, encrypts them on disk, and serves the replay.

  • recordportal: the gateway (nginx) through which the container agents send their frames, over mutual TLS, on port 8447.

  • recordapidb: a one-shot task that creates and updates the database schema.

Only port 8447 of the gateway is exposed to the agents. recordapi and the database stay internal to the Swarm.

Activation

RECORDAPI_ENABLED: true
RECORDDB_EAR_KEY_B64: "{{ vault_recorddb_ear_key_b64 }}"
  • RECORDAPI_ENABLED: enables Record API (false by default). This single variable deploys the database, recordapi, and the gateway, opens port 8447 on Traefik, and configures the API.

  • RECORDDB_EAR_KEY_B64: encryption-at-rest key of the database, in base64 (32 bytes). The role never generates it: without it, the first deployment stops.

To generate the key:

openssl rand 32 | base64 -w0

Store it in your vault and keep a copy outside the cluster: without it, the database is unreadable.

On the first deployment, make sure PORTAL_URL is set, then pass INIT_DB=true as an extra variable, never in the inventory. This option registers the RECORD gateway in the API:

ansible-playbook -i inventory.yml playbooks/reemo-infra.yml -e INIT_DB=true

Place the Record API variables in all, or in the group that hosts the API: infra_manager (all-in-one) or api_manager (separated architecture). A variable placed under portal_manager has no effect on Record API.

Once Record API is deployed, set up the recording (video and text) in the container blueprints and the container profiles.

Warning

When Record API is enabled, recording is mandatory: if a container agent cannot reach the service (unreachable gateway, full or non-writable storage), the session is cut. Check the gateway and the storage before enabling Record API in production.

Encryption and Secrets

recordapi encrypts each frame before writing it, and the database is encrypted at rest. Keep RECORDDB_SSL_REQUIRE and RECORDDB_EAR_ENABLED set to true, their default values.

  • RECORDAPI_MASTERKEY: encryption key of the frames, in base64 (32 bytes). Provide it from your vault as soon as you go to production. If left empty, it is generated and then exists only in the Swarm: if the Swarm is lost, the frames become unreadable.

  • RECORDDB_APP_PASSWORD: application password of the database. Provide it to be able to retrieve it outside the Swarm (generated if empty).

  • SECUREGATEWAY_HMAC: HMAC secret that signs the gateway (generated if empty). Set it when several Swarms must share the same value.

Note

A Swarm secret is created only once, on the first deployment. Changing the corresponding inventory variable afterward has no effect: rotate the secrets manually.

Recording Storage

By default, the frames are written on the host, in /opt/<INSTANCE_NAME>/records (/opt/reemo/records with the default instance name). For a larger volume, use a dedicated disk or a share mounted by the role:

RECORDAPI_STORAGE_MODE: "nfs"
RECORDAPI_STORAGE_REMOTE_HOST: "nfs.example.local"
RECORDAPI_STORAGE_REMOTE_EXPORT: "/export/reemo-records"
  • RECORDAPI_STORAGE_MODE: local (default), nfs, or smb. Any other value stops the deployment.

  • RECORDAPI_STORAGE_LOCALPATH: folder on the host (mount point in external mode).

  • RECORDAPI_STORAGE_REMOTE_HOST and RECORDAPI_STORAGE_REMOTE_EXPORT: server and exported path (NFS) or share name (SMB).

  • RECORDAPI_STORAGE_SMB_USER, RECORDAPI_STORAGE_SMB_PASSWORD, and RECORDAPI_STORAGE_SMB_DOMAIN: SMB credentials. Provide the password from your vault.

The role protects the recordings. It stops the deployment if the share is not mounted, or if the service user (uid 100) cannot write to it. On the storage server, export with all_squash,anonuid=100,anongid=0 for NFS, and give the service account the modify right for SMB.

Important

The role does not move existing data. Switching from local mode to a share hides the sessions already recorded: copy them to the new storage before switching.

Retention and Purge

  • RECORDAPI_RETENTION_DAYS: how long recordings are kept, in days (90 by default, 0 to keep them indefinitely).

The recordapicron service, deployed with Record API, purges expired sessions:

  • RECORDAPICRON_ENABLED: deploys the purge service. By default, it follows RECORDAPI_ENABLED: there is nothing to set. Set it to false to disable the purge.

  • RECORDAPICRON_STORAGE_WARNING_THRESHOLD: storage usage level, as a percentage, at which a warning is raised (80 by default).

On an already deployed installation, setting RECORDAPICRON_ENABLED to false does not remove the service. To stop the purge, scale the service down to zero replicas:

docker service scale reemo_recordapicron=0

Important

If you disable recordapicron, no session is purged: the storage grows without limit. Monitor the available space in the Storage & status tab (see Storage & Status).

Restrict Access to the Gateway

RECORD_PORTAL_RESTRICT_IP:
  - name: provisions
    ip: "10.0.30.0/24"
  • RECORD_PORTAL_RESTRICT_IP: list of addresses allowed to reach the gateway. Each entry has a name and an ip. Limit the list to the provision nodes.

  • RECORD_PORTAL_PORT: public port of the gateway (8447 by default). Open it in your firewall. On an existing installation, also update the gateway port in the Secure Gateways whenever you change it.

Separated Architecture

In a separated architecture, Record API and its gateway run on the API Swarm (api_manager group). The signaling service stays on the portal Swarm. Set PROVISION_SIGNAL_IP to the address of the portal, even though the API side reads this variable:

all:
    vars:
        RECORDAPI_ENABLED: true
        PROVISION_SIGNAL_IP:
            - ip: "10.0.10.25"

If you set the API address instead, containers fail with “Connection refused” errors when they connect to the signaling service.

Commands in the Player

The commands and URLs shown in the player logs come from the session logs of the agent. They require the signaling service in version 2.14.0 or later (DOCKER_VERSION_SIGNAL) and the Text recording setting set to Portal or Portal and standard output, in the container blueprint or the container profile (Session Recording step). With Standard output alone, the lines stay in the container logs and do not reach the player. Otherwise, the Commands counters and the player logs stay empty.

Inventory Examples

All-in-one, with NFS storage and restricted access:

infra_manager:
    vars:
        PORTAL_URL: "url.domain.tld"
        RECORDAPI_ENABLED: true
        RECORDDB_EAR_KEY_B64: "{{ vault_recorddb_ear_key_b64 }}"
        RECORDAPI_MASTERKEY: "{{ vault_recordapi_masterkey }}"
        RECORDAPI_STORAGE_MODE: "nfs"
        RECORDAPI_STORAGE_REMOTE_HOST: "nfs.example.local"
        RECORDAPI_STORAGE_REMOTE_EXPORT: "/export/reemo-records"
        RECORDAPI_RETENTION_DAYS: "90"
        RECORD_PORTAL_RESTRICT_IP:
          - name: provisions
            ip: "10.0.30.0/24"

Separated architecture:

all:
    vars:
        RECORDAPI_ENABLED: true
        PROVISION_SIGNAL_IP:
            - ip: "10.0.10.25"
api_manager:
    vars:
        RECORDDB_EAR_KEY_B64: "{{ vault_recorddb_ear_key_b64 }}"
        RECORDAPI_MASTERKEY: "{{ vault_recordapi_masterkey }}"

Check the Deployment

On the node that hosts the API, list the Record services:

docker service ls | grep -E 'recordapi|recorddb|recordportal'

The reemo_recordapi, reemo_recorddb, and reemo_recordportal services must show 1/1. reemo_recordapidb shows 0/1 (task completed), which is expected.

Then open the Storage & status tab of the Session Recordings: the Recording service must be Reachable and the Mount must be Present.

Points to Watch

  • Deploy recordapi and recordapidb at the same version.

  • Never expose the internal port of recordapi: leave RECORDAPI_TRAEFIK_ENABLED set to false.

  • To change the version of an image, edit DOCKER_VERSION_RECORD*, not *_DOCKER_IMAGE, which the role recalculates.

  • Pass INIT_DB as an extra variable, on the first deployment only.