Skip to content

Updating to OpenTalk Controller v0.34.0

Controller v0.34 reworks the configuration file significantly. The roomserver configuration became mandatory and now owns most of the media- and feature-related settings that previously lived in their own top-level tables.

This guide lists every breaking change when upgrading from v0.33 to v0.34 and shows how to adapt an existing deployment. Most changes affect the controller.toml settings file, but the CLI and exported metrics changed as well.

Before you start, back up your current controller.toml.

Overview of breaking changes

  • The [roomserver] section is now required.
  • The [roomserver] section gained a mandatory kind field (external or internal).
  • The roomserver url key was renamed to service_url.
  • Media and feature settings moved under [roomserver.modules.*]:
    • [livekit][roomserver.modules.livekit]
    • [etherpad][roomserver.modules.meeting_notes]
    • [spacedeck][roomserver.modules.whiteboard]
    • [subroom_audio][roomserver.modules.subroom_audio]
  • The [livekit], [etherpad], [spacedeck], [subroom_audio], [authz] and [websocket_rate_limit] top-level tables were removed.
  • service_api_keys under [http] is now required (the roomserver uses it).
  • The acl and fix-acl CLI subcommands were removed.
  • The kustos_enforce_execution_time_sec and kustos_load_policy_execution_time metrics were removed.
  • The signaling metrics are now provided by the roomserver and some of the metrics have changed.

1. Add the mandatory [roomserver] section

In v0.33 the roomserver was optional and only used when running an external roomserver service. In v0.34 it is mandatory and defines how signaling and media are handled.

Set kind to external if you run a separate roomserver service (this matches the previous behavior), or internal to run the roomserver embedded in the controller process.

Previous (v0.33)

#[roomserver]
#url = "http://localhost:11333"
#api_key = { id = "roomserver", secret = "secret" }

New (v0.34) — external roomserver only

[roomserver]
# Whether the roomserver runs embedded in the controller (internal) or as an external service.
kind = "external"

# The URL the controller uses for requests to the roomserver.
# (previously named `url`)
service_url = "http://localhost:11333"

# The roomservers API key id and secret.
api_key = { id = "roomserver", secret = "secret" }

Note the rename from url to service_url.

If you choose kind = "internal", the additional optional sections [roomserver.conference], [roomserver.defaults] and [roomserver.reports.typst] become relevant. See the example config for details.

2. Add the mandatory service_api_keys under [http]

The roomserver authenticates against the controller using these keys, so the value is now required. Uncomment (or add) it under [http]:

[http]
service_api_keys = [{ "id" = "controller", "secret" = "secret" }]

Generate a random secret with:

openssl rand -hex 32

3. Move media/feature settings into [roomserver.modules.*]

A module is enabled by adding its [roomserver.modules.<module>] table. Some modules need extra fields, others are enabled by adding their (otherwise empty) table. Omit the table to keep a module disabled.

The livekit and echo modules are required for a video conference and should not be deactivated.

LiveKit

[livekit][roomserver.modules.livekit]

Previous:

[livekit]
api_key = "your-livekit-api-key"
api_secret = "your-livekit-api-secret"
public_url = "wss://url.to.your.livekit.server"
service_url = "https://localhost:7880"

New:

[roomserver.modules.livekit]
api_key = "your-livekit-api-key"
api_secret = "your-livekit-api-secret"
public_url = "wss://url.to.your.livekit.server"
service_url = "https://localhost:7880"

Meeting notes (formerly Etherpad)

[etherpad][roomserver.modules.meeting_notes], and urlbase_url.

Previous:

[etherpad]
url = "http://localhost:9001"
api_key = "secret"

New:

[roomserver.modules.meeting_notes]
base_url = "http://localhost:9001"
api_key = "secret"

Whiteboard (formerly Spacedeck)

[spacedeck][roomserver.modules.whiteboard], and urlbase_url.

Previous:

[spacedeck]
url = "http://localhost:9666"
api_key = "secret"

New:

[roomserver.modules.whiteboard]
base_url = "http://localhost:9666"
api_key = "secret"

Subroom audio

[subroom_audio][roomserver.modules.subroom_audio]. The old enable_whisper flag no longer exists; the module is enabled simply by adding its table.

Previous:

[subroom_audio]
enable_whisper = true

New:

[roomserver.modules.subroom_audio]

Enable the mandatory echo module

[roomserver.modules.echo]

Other modules

The following modules are now configured under [roomserver.modules.*] as well. Add the table to enable a module (omit to keep it disabled):

  • [roomserver.modules.automod]
  • [roomserver.modules.chat] (with optional [roomserver.modules.chat.rate_limit])
  • [roomserver.modules.e2ee]
  • [roomserver.modules.legal_vote]
  • [roomserver.modules.meeting_report]
  • [roomserver.modules.moderation]
  • [roomserver.modules.recording]
  • [roomserver.modules.polls]
  • [roomserver.modules.reaction]
  • [roomserver.modules.shared_folder]
  • [roomserver.modules.timer]
  • [roomserver.modules.training_participation_report]
  • [roomserver.modules.transcription]
  • [roomserver.modules.raise_hands]
  • [roomserver.modules.excalidraw]

4. Replace the removed [websocket_rate_limit] table

The top-level [websocket_rate_limit] table was removed. Websocket rate limiting is now configured on the roomserver via [roomserver.websocket_rate_limit], and chat rate limiting via [roomserver.modules.chat.rate_limit].

Previous:

[websocket_rate_limit]
disabled = false
tokens_per_second = 10
token_bucket_size = 30

New (optional, defaults shown):

#[roomserver.websocket_rate_limit]
#disabled = false
#tokens_per_second = 10
#token_bucket_size = 30

Note that the chat rate limit defaults also changed (tokens_per_second 3 → 10, token_bucket_size 10 → 30) and a new slow_down_threshold (default 0.8) was added under [roomserver.modules.chat.rate_limit].

5. Removed [authz] table

Access control is not configurable. Earlier controller releases exposed an [authz] (later [authorization]) section with a synchronize_controllers option; this section is no longer read and can be removed.

6. Removed CLI subcommands

The following opentalk-controller subcommands used to manage the in-memory ACL and have been removed:

  • opentalk-controller acl
  • opentalk-controller fix-acl

Neither is necessary any more, because the authorization middleware derives its decisions directly from the tables that already model the authoritative state (users, rooms, events, invites and tariffs).

7. Removed metrics

The following metrics were tied to the removed ACL enforcement and no longer exist. Remove any dashboards or alerts that reference them:

  • kustos_enforce_execution_time_sec
  • kustos_load_policy_execution_time

8. Signaling metrics are provided by the roomserver

Before v0.34.0, the OpenTalk controller ran signaling in-process and exposed signaling_* metrics on its own /metrics endpoint. v0.34.0 removed the built-in signaling in favor of the RoomServer, and those metrics disappeared from the controller's endpoint. Starting with v0.34.6, the equivalent metrics are emitted by the roomserver and are observable again, but the endpoint that serves them and the set of metric names have changed.

Where to scrape

roomserver.kind Scrape target for signaling metrics
internal The controller's /metrics endpoint (unchanged host/port).
external The roomserver's /metrics endpoint (separate process, default port 11412). The roomserver's own [metrics] allowlist must include your Prometheus host; by default the endpoint refuses all connections.

Metric mapping

The otel_scope_name label on the signaling metrics changes value from ot-controller to ot-roomserver.

Old metric (pre-v0.34.0) Replacement Notes
signaling_created_rooms_count signaling_created_rooms_count Breakout rooms are now counted separately by signaling_created_breakout_rooms_count.
signaling_destroyed_rooms_count signaling_destroyed_rooms_count Breakout rooms are now counted separately by signaling_destroyed_breakout_rooms_count.
signaling_participants_count signaling_connection_count Renamed "participants" to "connections". The participation_kind label gains the values recorder, transcription, call_in, and registered_call_in.
signaling_participants_per_room signaling_connections_per_room Implemented as a set of gauges keyed by a bucket label (2, 10, 25, 50, 100, 200, 300), not a histogram. Queries using histogram_quantile no longer apply.
signaling_room_life_time signaling_room_life_time Bucket boundaries come from the roomserver; re-tune alert thresholds if you had customized them.
signaling_participant_meeting_time signaling_connection_meeting_time Renamed. Bucket boundaries come from the roomserver.
signaling_runner_startup_time_seconds removed The in-process runner no longer exists.
signaling_runner_destroy_time_seconds removed The in-process runner no longer exists.

signaling_participants_with_audio_count and signaling_participants_with_video_count were defined on the old signaling metrics but had no emitters after the Janus Media Server was removed in v0.26.0; they are gone with the rest of the old signaling metrics and have no replacement.

The following metrics are new and have no pre-v0.34.0 equivalent:

Metric Type Description
signaling_created_breakout_rooms_count counter Number of breakout rooms created. Previously folded into signaling_created_rooms_count; now tracked separately.
signaling_destroyed_breakout_rooms_count counter Number of breakout rooms destroyed. Previously folded into signaling_destroyed_rooms_count; now tracked separately.
signaling_congested_connections counter Number of connections the roomserver disconnected due to congestion. Useful as an indicator of client- or network-side backpressure.

See the metrics documentation for the full list of metrics currently exposed by the controller.

9. New optional settings (no action required)

These were added in v0.34 and are optional:

  • [roomserver] gained room_idle_timeout (seconds after which an empty room is closed, default 60).
  • The [minio] table gained force_path_style and region
    • force_path_style: Use path-style bucket URLs (host/bucket) instead of virtual-hosted style; set to true for S3-compatible servers that don't support virtual-hosted addressing
    • region: the AWS region