Skip to content

Commit 131f1e0

Browse files
committed
Initial commit
This is a somewhat working prototype at this point.
0 parents  commit 131f1e0

27 files changed

Lines changed: 4835 additions & 0 deletions

.dockerignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Python-generated files
2+
__pycache__/
3+
*.py[oc]
4+
build/
5+
dist/
6+
wheels/
7+
*.egg-info
8+
.*cache
9+
10+
# Virtual environments
11+
.venv
12+
13+
# Test data directories
14+
testhook.py
15+
testdata
16+
.var
17+
18+
# Other unimportant directories
19+
examples
20+
docs
21+
.github

.github/workflows/docker.yaml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: docker
2+
3+
on:
4+
push:
5+
branches: ['main']
6+
tags: ['v*']
7+
8+
env:
9+
REGISTRY: ghcr.io
10+
IMAGE_NAME: ${{ github.repository }}
11+
12+
jobs:
13+
build-and-push-main:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
packages: write
18+
attestations: write
19+
id-token: write
20+
steps:
21+
- name: Check out the repo
22+
uses: actions/checkout@v5
23+
- name: Docker meta
24+
id: meta
25+
uses: docker/metadata-action@v5
26+
with:
27+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
28+
tags: |
29+
type=ref,event=branch
30+
type=semver,pattern={{version}}
31+
type=semver,pattern={{major}}.{{minor}}
32+
type=semver,pattern={{major}}
33+
- name: Login to Image Registry
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ${{ env.REGISTRY }}
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
- name: Build and push
40+
uses: docker/build-push-action@v6
41+
with:
42+
context: .
43+
file: docker/Dockerfile
44+
push: true
45+
tags: ${{ steps.meta.outputs.tags }}
46+
labels: ${{ steps.meta.outputs.labels }}

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Python-generated files
2+
__pycache__/
3+
*.py[oc]
4+
build/
5+
dist/
6+
wheels/
7+
*.egg-info
8+
.*cache
9+
10+
# Virtual environments
11+
.venv
12+
13+
# Test data directories
14+
testhook.py
15+
testdata
16+
.var
17+
examples/compose/data

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.13

LICENSE-AGPL-3.0.md

Lines changed: 660 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# BBBLB: Yet another Load Balancer for BigBlueButton
2+
3+
BBBLB (BigBlueButton Load Balancer) is yet another load balancer for BigBlueButton. It aims to provide secure, scalable and robust solution large BigBlueButton installations and allow organizations to host their own BigBlueButton cluster or offer such services to others.
4+
5+
## Current Status
6+
7+
BBBLB is currently in a **pre-alpha state**. It is a working prototype and **not ready for production environments** at this time. You have been warned.
8+
9+
## Features
10+
11+
* **Multi-Tenancy**: Allow multiple front-end applications or customers to share the same BigBlueButton cluster while keeping their meetings and recordings strictly separated.
12+
* **Advanced Loadbalancing**: New meetings are created on the BBB servers with the lowest *load*, which is updated in realtime and calculated based un multiple tuneable factors. The algorithm expscially tries to avoid the 'trampling herd' problem when multiple meetings with unknown size are created at the same time.
13+
* **Recording Management**: Recordings are transferred from the BBB servers to central storage via a simple and robust `post_publish` script that does not need any configuration, `ssh` connectivity or shared network file system to work.
14+
* **Callback Relay**: Callbacks registered for a meeting are properly relayed between the back-end BBB server and the front-end application with a robust retry-mechanism.
15+
* **Control API**: BBBLB offers its own API and command line tool to fetch health information, manage tenants or backend servers, or perform maintenance tasks.
16+
* **Scaleable**: Most existing BigBlueButton Load Balancer implementations claim to be scalable. Until I have time to actually benchmark those claims, I'll also just claim that BBBLB scales to hundreds of backend servers and thousands of meetings without any issues. The bottleneck will always be your BBB cluster, not BBBLB. Trust me bro.
17+
* **Easy to deploy**: That's a lie. But it's easier to deploy than most other BigBlueButton Load Balancer implementations.
18+
19+
## Planned features
20+
21+
* [ ] A `bbblb-agent` command line tool that can:
22+
* Auto-register and enable back-end BBB servers when they start up and disable them when they shut down.
23+
* Report additional health and load information from back-end BBB servers to bbblb for better load balancing.
24+
* [ ] A `bbblb` admin command line tool that can:
25+
* Manage tenants, servers, running meetings or recordings.
26+
* Display and export statistics or metrics.
27+
* [ ] Rate limiting and DoS protection that is fair to unaffected tenants.
28+
29+
## Totally not a biased feature comparison againwithst Scalelite
30+
31+
ScalScaleliteeite is the reference implementation of a BigBlueButton Load Balancer, developed by the creators of BigBlueButton themselves.
32+
33+
| Feature | BBBLB | Scalelite |
34+
| ------- | ----- | --------- |
35+
| Zero config post_publish script | Yes | No |
36+
| Recording upload via HTTPS | Yes | No 1) |
37+
| Graceful handling of unstable back-end servers | Yes | No 2) |
38+
| Deployed as a single app/container | Yes 3) | No 4) |
39+
| Scales to many concurrent users | Yes | No 5) |
40+
41+
1) You need ssh/rsync or a shared file system for recording transfer.
42+
2) Scalelite immediately breaks all meetings on an unresponsive server, even if it's only a short temporary issue.
43+
3) BBBLB greatly benefits from a fast static-file HTTP server (e.g. nginx or caddy) in front of it, but can also run on its own.
44+
4) Scalelite needs a recording importer and a poller in addition to its main server process. Both cannot be scaled to multiple instances or stuff will break.
45+
5) Scalelite uses ruby on rails and synchronous handlers, which means that it can only serve a limited number of requests at the same time.
46+
47+
## API Usage
48+
49+
See (API Docs)[./docs/API.md] (TODO)
50+
51+
## Deploment
52+
53+
TODO
54+
55+
# License
56+
57+
BBBLB - BigBlueButton Load Balancer
58+
Copyright (C) 2025 Marcel Hellkamp
59+
60+
This program is free software: you can redistribute it and/or modify
61+
it under the terms of the GNU Affero General Public License as
62+
published by the Free Software Foundation, either version 3 of the
63+
License, or (at your option) any later version.
64+
65+
This program is distributed in the hope that it will be useful,
66+
but WITHOUT ANY WARRANTY; without even the implied warranty of
67+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
68+
GNU Affero General Public License for more details.
69+
70+
You should have received a copy of the GNU Affero General Public License
71+
along with this program. If not, see <https://www.gnu.org/licenses/>.

bbblb/__init__.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import logging
2+
from .settings import config
3+
4+
__version__ = "0.0.1"
5+
VERSION = __version__.split(".", 2)
6+
VERSION[-1], _, BUILD = VERSION[-1].partition("-")
7+
8+
ROOT_LOGGER = logging.getLogger(__name__)
9+
ROOT_LOGGER.setLevel(logging.INFO)
10+
ROOT_LOGGER.propagate = False
11+
ch = logging.StreamHandler()
12+
ch.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s"))
13+
ROOT_LOGGER.addHandler(ch)
14+
15+
16+
@config.watch
17+
def watch_debug_level(name, old, new):
18+
if name == "DEBUG":
19+
level = logging.DEBUG if new else logging.INFO
20+
if level != ROOT_LOGGER.level:
21+
ROOT_LOGGER.setLevel(logging.DEBUG if new else logging.INFO)

bbblb/__main__.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import secrets
2+
import sys
3+
import time
4+
import jwt
5+
6+
from bbblb.settings import config
7+
8+
config.populate()
9+
10+
11+
def cmd_maketoken(subject, maxage, *scopes):
12+
payload = {
13+
"sub": subject,
14+
"exp": int(time.time() + int(maxage)),
15+
"scope": " ".join(scopes),
16+
"jti": secrets.token_hex(8),
17+
}
18+
print(payload, file=sys.stderr)
19+
print(jwt.encode(payload, config.SECRET))
20+
21+
22+
cmd = sys.argv[1]
23+
locals()[f"cmd_{cmd}"](*sys.argv[2:])

bbblb/api/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)