Skip to content

Analytics Callback URL Fails in HA Deployments Behind Proxy #1229

@jfedericobn

Description

@jfedericobn

Describe the bug

Analytics callback URL construction fails in High Availability (HA) deployments behind a proxy or load balancer. The callback URL is built using URL_HOST which is set to an internal hostname for DNS rebinding protection, but BigBlueButton servers cannot reach the internal hostname when sending analytics callbacks. This results in failed analytics tracking and connection errors.

To Reproduce

Deployment:

  1. Deployment: Docker Compose HA deployment behind a proxy/load balancer (or any HA setup where URL_HOST is internal)
  2. Versions: Scalelite v1.7+, BigBlueButton 2.4+, Docker Compose v2+
  3. Tools used for reproducing the issue: BigBlueButton API, curl, Docker Compose

Steps to reproduce the behavior:

  1. Deploy Scalelite using docker-compose.yml with URL_HOST set to internal hostname (e.g., scalelite-api or 0.0.0.0)
  2. Set DOMAIN_NAME to public domain (e.g., sl.example.com)
  3. Register a BigBlueButton server with the Scalelite load balancer
  4. Create a meeting via Scalelite API:
curl -X POST "https://sl.example.com/bigbluebutton/api/create" \
  -d "meetingID=test-123" \
  -d "name=Test Meeting" \
  -d "checksum=..." \
  -d "meta_analytics-callback-url=https://sl.example.com/analytics"
  1. Wait for the meeting to end and recordings to process
  2. Check BigBlueButton server logs: Connection errors to unreachable analytics callback URL
  3. See error: Connection refused to https://0.0.0.0/bigbluebutton/api/analytics_callback or similar internal hostname

Expected behavior

The analytics callback URL should be constructed using the public-facing hostname (reachable from BigBlueButton servers), while URL_HOST continues to protect against DNS rebinding attacks. BigBlueButton servers should successfully send analytics callbacks to the Scalelite endpoint.

Actual behavior

Analytics callback URL is constructed as: https://0.0.0.0/bigbluebutton/api/analytics_callback or https://scalelite-api/bigbluebutton/api/analytics_callback

BigBlueButton servers attempt to POST analytics but fail because:

  • The internal hostname is not resolvable from BigBlueButton servers
  • Even if resolvable, the internal IP/hostname is not routable

Root Cause

File: app/handlers/analytics_callback_event_handler.rb (line 14)

host_name = Rails.configuration.x.url_host

URL_HOST serves conflicting purposes:

  • Primary use: DNS rebinding protection in config/environments/production.rb
  • Conflicting use: Analytics callback URL construction (should use public hostname)

Solution

Introduce new environment variable ANALYTICS_CALLBACK_URL_HOST with fallback to URL_HOST for backward compatibility:

File: config/application.rb

config.x.analytics_callback_url_host = ENV.fetch('ANALYTICS_CALLBACK_URL_HOST', nil)

File: app/handlers/analytics_callback_event_handler.rb

def handle
  return if analytics_callback_url.nil?

  # Use ANALYTICS_CALLBACK_URL_HOST if set (for HA/proxy deployments)
  # Otherwise fall back to URL_HOST (for direct deployments)
  host_name = Rails.configuration.x.analytics_callback_url_host || Rails.configuration.x.url_host

  params['meta_analytics-callback-url'] = if tenant.present?
    "https://#{tenant.name}.#{host_name}/bigbluebutton/api/analytics_callback"
  else
    "https://#{host_name}/bigbluebutton/api/analytics_callback"
  end

  callback_attributes = { analytics_callback_url: analytics_callback_url }
  callback_data = CallbackData.find_or_create_by!(meeting_id: meeting_id)
  callback_data.update!(callback_attributes: callback_attributes)
end

Screenshots

N/A - This is a configuration/networking issue

Additional context

Impact:

  • 🔴 Critical for HA deployments behind proxy/load balancer
  • ⚠️ No impact on single-instance direct deployments
  • ✅ Fully backward compatible when ANALYTICS_CALLBACK_URL_HOST not set

Affected deployment scenarios:

  • AWS ALB/NLB + Scalelite cluster
  • Kubernetes ingress + Scalelite pod
  • Any external load balancer + Scalelite cluster
  • Any deployment where URL_HOST ≠ public hostname

Configuration examples:

Direct deployment (current, works):

URL_HOST=sl.example.com

HA behind proxy (currently broken, would be fixed with this change):

URL_HOST=scalelite-api                        # Internal for DNS rebinding
ANALYTICS_CALLBACK_URL_HOST=sl.example.com   # Public for analytics callbacks

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions