OpenVibe.Live Setup Guide

Complete deployment guide: OVH Public Cloud + Ubuntu 25.04 + Cloudflare + Let's Encrypt + Nginx — plus OVH plan sizing analysis

OVH Ubuntu 25.04 Cloudflare Let's Encrypt Nginx Node 20

1. Recommended Production Model

For a small or medium public deployment, the safest baseline is:

  • OVH Public Cloud instance in the nearest region to your users
  • Ubuntu 25.04
  • Cloudflare proxy for the main website
  • Nginx on the origin server
  • Let's Encrypt certificate on the origin
  • Cloudflare SSL/TLS mode set to Full (strict)
  • Node 20 LTS via nvm (Node Version Manager)
  • systemd for process supervision
  • ufw on the box
  • Only open the extra streaming ports you actively use
For most operators, expose only 80 and 443 first. Add RTMP, JSMPEG, or WebRTC ports later only if you really need them.

2. What OpenVibe.Live Exposes

The current server in server/index.js provides:

  • HTTP on PORT, default 3000
  • WebSocket upgrades on /ws/chat, /ws/broadcast, /ws/control, and /ws/call
  • Optional RTMP ingest
  • Optional JSMPEG relay
  • Optional WebRTC / mediasoup
  • Persistent data under data/

Typical ports

PortProtocolPurpose
3000TCPInternal Node app (behind Nginx)
80TCPHTTP redirect & Let's Encrypt validation
443TCPHTTPS to Nginx
1935TCPRTMP ingest
9710TCPJSMPEG video relay
9711TCPJSMPEG audio relay
4443TCP/UDPWebRTC entry point
10000-10100UDPmediasoup RTP range
9935TCPHTTP-FLV playback (if enabled)
Do not expose all of them by default. Only open ports for protocols you actively use.

3. OVH Instance Creation

From the OVH "Create an instance" flow:

  • Template: your chosen instance flavor, e.g. B3-16
  • Region: nearest to your users, e.g. Seattle / US-WEST-LZ-SEA-A
  • Image: Ubuntu 25.04
  • SSH key: required
OVH only accepts RSA and ECDSA SSH keys. ED25519 keys are not accepted in this flow.

So for this deployment, generate either:

  • ECDSA P-384 — recommended if OVH accepts it in your project flow
  • RSA 4096 — safest fallback for maximum compatibility

4. Generate an SSH Key for OVH

Run these commands on your local machine, not on the server.

Option A: ECDSA P-384 key

mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t ecdsa -b 384 -f ~/.ssh/ovh_openvibelive_ecdsa -C "ovh-openvibelive"

Option B: RSA 4096 key

mkdir -p ~/.ssh
chmod 700 ~/.ssh
ssh-keygen -t rsa -b 4096 -o -a 100 -f ~/.ssh/ovh_openvibelive_rsa -C "ovh-openvibelive"

Lock down the private key

# ECDSA
chmod 600 ~/.ssh/ovh_openvibelive_ecdsa
chmod 644 ~/.ssh/ovh_openvibelive_ecdsa.pub

# RSA
chmod 600 ~/.ssh/ovh_openvibelive_rsa
chmod 644 ~/.ssh/ovh_openvibelive_rsa.pub

Print the public key to paste into OVH

# ECDSA
cat ~/.ssh/ovh_openvibelive_ecdsa.pub

# RSA
cat ~/.ssh/ovh_openvibelive_rsa.pub

Copy the entire single-line public key into the OVH SSH key field.

Test the key fingerprint locally

# ECDSA
ssh-keygen -lf ~/.ssh/ovh_openvibelive_ecdsa.pub

# RSA
ssh-keygen -lf ~/.ssh/ovh_openvibelive_rsa.pub

5. Import the SSH Key into OVH

  1. Go to your Public Cloud project
  2. Open the SSH keys area, or paste the key directly during instance creation
  3. Give the key a clear name, e.g. openvibelive-seattle-prod
  4. Paste the public key line from the .pub file
  5. Create the instance with that key attached
OVH lets you store SSH keys in the control panel and reuse them across regions.

6. Connect to the New Instance

After the instance is created and shows as ready, connect over SSH. Most OVH Ubuntu images use the ubuntu user.

ECDSA example

ssh -i ~/.ssh/ovh_openvibelive_ecdsa ubuntu@YOUR_SERVER_IP

RSA example

ssh -i ~/.ssh/ovh_openvibelive_rsa ubuntu@YOUR_SERVER_IP

Optional: SSH config alias

Host openvibe.tools
    HostName YOUR_SERVER_IP
    User ubuntu
    IdentityFile ~/.ssh/ovh_openvibelive_ecdsa
    IdentitiesOnly yes

Then connect with:

ssh openvibe.tools

7. First-Login Hardening

Run these commands on the server.

Update the box

sudo apt update
sudo apt full-upgrade -y
sudo apt autoremove -y

Install baseline packages

sudo apt install -y \
  git curl wget unzip ca-certificates gnupg \
  nginx ffmpeg ufw fail2ban \
  build-essential python3 python3-pip jq

Optional: create a dedicated app user

sudo adduser --disabled-password --gecos "" openvibelive
sudo usermod -aG sudo openvibelive

Then add your public key for that user:

sudo mkdir -p /home/openvibelive/.ssh
sudo nano /home/openvibelive/.ssh/authorized_keys
sudo chown -R openvibelive:openvibelive /home/openvibelive/.ssh
sudo chmod 700 /home/openvibelive/.ssh
sudo chmod 600 /home/openvibelive/.ssh/authorized_keys

Harden SSH

sudo nano /etc/ssh/sshd_config

Recommended settings:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
ChallengeResponseAuthentication no
UsePAM yes
X11Forwarding no

Reload SSH:

sudo systemctl reload ssh
Do not disable password auth until you have confirmed key login works.

8. Install Node.js via nvm

We use nvm (Node Version Manager) instead of system packages. This avoids the recurring /usr/bin/env: 'node': No such file or directory problem where NodeSource installs node somewhere systemd can't find it.

Install nvm

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

Close and reopen your terminal (or source your profile) so nvm is available:

source ~/.bashrc
command -v nvm          # should print "nvm"

Install Node 20 LTS

nvm install 20
nvm alias default 20    # make it the default for new shells
node -v
npm -v

Verify

which node   # e.g. /home/ubuntu/.nvm/versions/node/v20.x.x/bin/node
which npm    # same nvm-managed path
nvm installs node per-user under ~/.nvm/. It is a shell function, not a binary — systemd can't see it directly. The systemd section below uses a wrapper script that sources nvm before launching the app.

9. Clone OpenVibe.Live

cd /opt
sudo git clone https://github.com/OpenVibe.Live/OpenVibe.Live.com.git openvibelive
sudo chown -R $USER:$USER /opt/openvibelive
cd /opt/openvibelive
npm install

If native modules later need rebuilding:

npm rebuild
If mediasoup fails to compile, browser-native WebRTC broadcasting won't be ready until that's fixed.

10. Configure .env

cd /opt/openvibelive
cp .env.example .env
nano .env

Recommended starting .env

ADMIN_USERNAME=admin
ADMIN_PASSWORD=change-this-now

NODE_ENV=production
HOST=0.0.0.0
PORT=3000
BASE_URL=https://your-domain.example
JWT_SECRET=replace-with-a-long-random-secret

DATABASE_URL=postgres://live_runtime:password@localhost:5432/ov_live
DATABASE_DIRECT_URL=postgres://live_owner:password@localhost:5432/ov_live

RTMP_PORT=1935
JSMPEG_VIDEO_PORT=9710
JSMPEG_AUDIO_PORT=9711
WEBRTC_PORT=4443
MEDIASOUP_LISTEN_IP=0.0.0.0
MEDIASOUP_ANNOUNCED_IP=YOUR_PUBLIC_IP
MEDIASOUP_MIN_PORT=10000
MEDIASOUP_MAX_PORT=10100

VOD_PATH=./data/vods
CLIPS_PATH=./data/clips
THUMBNAILS_PATH=./data/thumbnails
EMOTES_PATH=./data/emotes

MAX_VOD_SIZE_MB=128
MAX_EMOTE_SIZE_KB=128
MAX_EMOTES_PER_USER=10

MIN_CASHOUT=5
ESCROW_HOLD_DAYS=14

Generate a strong JWT secret

openssl rand -hex 32
Notes:
  • Set BASE_URL to your final public HTTPS hostname
  • Set MEDIASOUP_ANNOUNCED_IP to the real public OVH IP if you use WebRTC
  • Keep upload and media limits low on small servers
  • Do not expose unused protocols

11. Create Runtime Directories

The app creates them on boot, but you can pre-create them:

cd /opt/openvibelive
mkdir -p data/vods data/clips data/media data/thumbnails data/emotes data/avatars

12. Bootstrap the App

Initialize the database if needed:

cd /opt/openvibelive
npm run init-db

Or just start it once manually:

npm start

Then stop it and move on to systemd setup.

13. Cloudflare DNS Setup

Main website

Create these records in Cloudflare DNS:

  • A record for @ pointing at YOUR_OVH_PUBLIC_IP
  • CNAME for www pointing at your apex hostname

Set both to Proxied (orange cloud) after the origin is working.

Optional: direct hostnames for non-HTTP protocols

Only create these if you really need them:

RecordTypeValueProxy
rtmpAYOUR_OVH_PUBLIC_IPDNS only
webrtcAYOUR_OVH_PUBLIC_IPDNS only
jsmpegAYOUR_OVH_PUBLIC_IPDNS only
These are usually DNS only (grey cloud) because they are not standard proxied website traffic.

14. Let's Encrypt on Ubuntu 25.04

For end-to-end encryption with Cloudflare, the origin must present a valid certificate. Cloudflare's Full (strict) mode requires the origin cert to be unexpired, valid for the hostname, and issued by a publicly trusted CA.

Install Certbot

sudo apt install -y snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot
certbot --version

Temporary Nginx HTTP site

Before requesting the cert, create a plain HTTP Nginx site so your domain answers on port 80.

sudo nano /etc/nginx/sites-available/openvibelive
server {
    listen 80;
    listen [::]:80;
    server_name your-domain.example www.your-domain.example;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /ws/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600;
    }
}

Enable it:

sudo ln -sf /etc/nginx/sites-available/openvibelive /etc/nginx/sites-enabled/openvibelive
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Request the certificate

If Cloudflare proxying causes validation issues, temporarily set DNS records to DNS only until issuance succeeds, then proxy them again.
sudo certbot --nginx -d your-domain.example -d www.your-domain.example

Verify auto-renewal

sudo systemctl list-timers | grep certbot || true
sudo certbot renew --dry-run

15. Cloudflare End-to-End Encryption

Once the origin has a valid Let's Encrypt cert:

  1. Open the Cloudflare dashboard
  2. Go to SSL/TLS
  3. Set encryption mode to Full (strict)

This gives you encrypted browser-to-Cloudflare and encrypted Cloudflare-to-origin traffic, with origin certificate validation.

Recommended Cloudflare settings

  • Always Use HTTPS — enabled
  • Automatic HTTPS Rewrites — enabled
  • WAF / bot protections (if available on your plan)
  • Rate limiting for sensitive paths (if available)
For extra origin protection, add Cloudflare IP allowlists at the firewall or Nginx layer, or configure Authenticated Origin Pulls.

16. Restore the Real Visitor IP

By default, your origin sees Cloudflare edge IPs. Cloudflare provides the original visitor IP in the CF-Connecting-IP header.

Nginx real IP config

sudo nano /etc/nginx/conf.d/cloudflare-realip.conf
real_ip_header CF-Connecting-IP;

set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
real_ip_recursive on;
sudo nginx -t
sudo systemctl reload nginx

Optional: custom log format with Cloudflare info

sudo nano /etc/nginx/conf.d/log_format_cloudflare.conf
log_format cloudflare_combined '$remote_addr - $remote_user [$time_local] '
                                '"$request" $status $body_bytes_sent '
                                '"$http_referer" "$http_user_agent" '
                                'cf_ray=$http_cf_ray cf_ip=$http_cf_connecting_ip';

Apply it in your site config with:

access_log /var/log/nginx/openvibelive.access.log cloudflare_combined;
Why this matters: OpenVibe.Live uses Express with trust proxy enabled. Correct Nginx real-IP handling ensures logs, moderation, rate limiting, and security signals use the real visitor IP instead of a Cloudflare edge IP.

17. Final Nginx HTTPS Config

After Certbot runs, tighten the site config:

server {
    listen 80;
    listen [::]:80;
    server_name your-domain.example www.your-domain.example;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your-domain.example www.your-domain.example;

    ssl_certificate /etc/letsencrypt/live/your-domain.example/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.example/privkey.pem;

    access_log /var/log/nginx/openvibelive.access.log cloudflare_combined;
    error_log /var/log/nginx/openvibelive.error.log;

    client_max_body_size 128M;

    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options SAMEORIGIN always;
    add_header Referrer-Policy strict-origin-when-cross-origin always;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /ws/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600;
    }
}
sudo nginx -t
sudo systemctl reload nginx

18. Firewall (UFW)

Minimal website-only deployment

sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

If you need RTMP ingest

sudo ufw allow 1935/tcp

If you need JSMPEG

sudo ufw allow 9710/tcp
sudo ufw allow 9711/tcp

If you need WebRTC / mediasoup

sudo ufw allow 4443/tcp
sudo ufw allow 4443/udp
sudo ufw allow 10000:10100/udp
Only open what you actively use.

19. OVH Security Groups

OVH's OpenStack-based Public Cloud default security groups can allow broad traffic by default. Do not rely on OVH defaults alone.

Use at least one of these:

  • ufw on the instance
  • OVH/OpenStack security groups (if you manage networking that way)
  • Nginx allowlists for sensitive origin paths
If you build custom OVH security groups, follow the same principle: start from least privilege and only open the exact ports you need.

20. systemd service

systemd doesn't run interactive shells, so it can't see the nvm shell function or the node/npm binaries it manages. We use a tiny wrapper script that sources nvm before launching the app.

Create the wrapper script

sudo nano /opt/openvibelive/start.sh

Paste:

#!/usr/bin/env bash
set -euo pipefail

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

cd /opt/openvibelive
exec npm start

Make it executable:

sudo chmod +x /opt/openvibelive/start.sh

Create the service unit

sudo nano /etc/systemd/system/openvibelive.service

Paste the following unit file:

[Unit]
Description=OpenVibe.Live
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/opt/openvibelive
Environment=NODE_ENV=production
ExecStart=/opt/openvibelive/start.sh
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
The User= must match whoever installed nvm. If you installed nvm as ubuntu, use User=ubuntu. The script reads $HOME/.nvm from that user's home directory.
If you created a dedicated openvibelive user, install nvm under that user, change User=ubuntu to User=openvibelive, and ensure ownership of /opt/openvibelive matches.

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable openvibelive
sudo systemctl start openvibelive
sudo systemctl status openvibelive

View logs:

journalctl -u openvibelive -f

21. Close registration after bootstrap

After you create your initial admin and trusted test accounts, close public registration. This is one of the cheapest and strongest anti-abuse controls in the project.

cd /opt/openvibe.live/current
# Use the site administration settings to close registration.

22. Optional fail2ban baseline

Install:

sudo apt install -y fail2ban

Create a basic jail file:

sudo nano /etc/fail2ban/jail.local

Example:

[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h

Then:

sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
sudo fail2ban-client status
If most web traffic is behind Cloudflare, make sure your Nginx real-IP config is correct before relying on log-based web jails.

23. Protocol-specific exposure guidance

RTMP

Expose 1935/tcp only if you need OBS or FFmpeg ingest.

JSMPEG

Expose 9710/tcp and 9711/tcp only if you use the relay.

WebRTC

Expose only the exact WebRTC TCP/UDP and RTP ports you need. Make sure:

  • MEDIASOUP_ANNOUNCED_IP matches your public OVH IP
  • Your firewall allows the RTP range
  • Your Cloudflare setup is not expected to proxy raw media ports

24. Operational checks

App health

Verify:

  • http://127.0.0.1:3000/api/health on the server
  • https://your-domain.example/api/health through Nginx and Cloudflare

TLS

  • Browser sees a valid certificate
  • Cloudflare SSL/TLS mode is Full (strict)
  • No redirect loops
  • No mixed-content warnings

Visitor IP restoration

Check Nginx logs and confirm the client IP is not just a Cloudflare edge IP.

Port audit

Check that only intended ports are reachable from the internet:

sudo ss -tulpn
sudo ufw status verbose

25. Full command summary

If you want the short version, the high-level order is:

  1. Generate an OVH-compatible SSH key locally
  2. Create the OVH Ubuntu 25.04 instance with that public key
  3. SSH into the new instance
  4. Update packages and install Nginx, FFmpeg, ufw, and fail2ban
  5. Install nvm and Node 20 LTS
  6. Clone OpenVibe.Live into /opt/openvibelive
  7. Configure .env
  8. Start the app once and verify /api/health
  9. Set Cloudflare DNS to the OVH IP
  10. Configure Nginx
  11. Issue a Let's Encrypt certificate with Certbot
  12. Enable Cloudflare Full (strict)
  13. Add Cloudflare real-IP config in Nginx
  14. Enable systemd for OpenVibe.Live
  15. Close public registration after bootstrap
  16. Open only the extra media ports you actually need

26. Security reminders

  • Never use ED25519 if the OVH flow in your account rejects it
  • Keep your private SSH key only on trusted admin machines
  • Disable password SSH once key auth is confirmed
  • Keep JWT_SECRET long and random
  • Keep the website behind Cloudflare
  • Do not expose raw media ports unnecessarily
  • Keep upload limits low on small servers
  • Close registration when not actively onboarding users
  • Monitor data/ growth for VODs, clips, thumbnails, avatars, and emotes

27. References

This guide was aligned with current public guidance from:

  • OVH Public Cloud instance creation and SSH-key setup guidance
  • Cloudflare documentation for CF-Connecting-IP and restoring original visitor IPs
  • Cloudflare documentation for Full (strict) mode
  • Current Certbot installation and Nginx integration guidance

28. Setup summary

For OVH + Ubuntu 25.04, the best OpenVibe.Live deployment pattern is:

  • RSA or ECDSA SSH key uploaded to OVH
  • Ubuntu 25.04 on OVH Public Cloud
  • Node 20 LTS via nvm
  • Nginx reverse proxy on the box
  • Let's Encrypt certificate on the origin
  • Cloudflare proxy with Full (strict)
  • Cloudflare real-IP restoration in Nginx
  • systemd, ufw, fail2ban
  • Only one streaming protocol exposed at a time unless you have a real need for more

See also README.md and deploy/.

OVH Public Cloud Sizing Guide

Executive summary

Best overall pick — B3-32

  • 32 GB RAM — enough for Node, PostgreSQL, WebSockets, chat, thumbnails, clips, and moderate media workload
  • 8 vCores — sane floor for a mixed single-box deployment
  • 200 GB NVMe — much more realistic than 50–100 GB once VODs and clips start accumulating
  • 2 Gbit/s — leaves real headroom for 200 viewers at practical streaming bitrates

Best budget / staging pick

  • B3-8 — cheapest decent general-purpose box
  • C3-8 — cheaper CPU-heavier test box (only 100 GB storage)

Best safer production pick — B3-64

  • 16 vCores is much healthier for 200 viewers with WebRTC, call features, game traffic, clip creation
  • 4 Gbit/s helps if bitrate climbs or you add more streams / cameras / rooms later
The older B2 and C2 families mostly lose on price/performance against the new B3 and C3 families. C2 is the least attractive family for this workload.

What limits OpenVibe.Live on a single OVH instance

The bottleneck is not just RAM. The main constraints are:

  1. Outbound bandwidth — the first hard wall
  2. CPU — especially for WebRTC
  3. Disk space — once VODs are enabled
  4. Disk I/O
  5. Operational headroom for Node, FFmpeg, thumbnails, clips, chat, and WebSockets

Bandwidth is the first hard wall

For all three playback methods, the origin server pays outbound bandwidth per viewer:

  • JSMPEG: server relays the live stream to every viewer
  • RTMP / HTTP-FLV: server still pays outbound per viewer
  • WebRTC SFU: server forwards media to each viewer; outbound scales with audience
Cloudflare protects the website and proxied HTTP traffic, but raw media ports and direct real-time traffic are not magically offloaded just because the website uses Cloudflare.

CPU becomes more important for WebRTC

  • JSMPEG: usually more bandwidth-bound than CPU-bound
  • RTMP ingest + direct playback: also heavily bandwidth-bound
  • WebRTC / mediasoup: usually more CPU-sensitive (SFU packet forwarding, transport handling, encryption overhead, more real-time state)

Storage dominates once VODs are enabled

The service uses PostgreSQL for its database and OpenVibe.Media for VODs, clips, thumbnails, and media assets. The OS and app don't need much space — recorded video does.

Bandwidth math for 200 viewers

A useful first-order formula:

required egress Mbps ≈ viewer count × average delivered Mbps per viewer

For 200 viewers:

  • At 1.5 Mbps per viewer: ~300 Mbps raw egress
  • At 2.5 Mbps per viewer: ~500 Mbps raw egress
  • At 4.0 Mbps per viewer: ~800 Mbps raw egress

Real deployments need headroom for TLS/protocol overhead, chat/API/thumbnails, bitrate spikes, reconnections, and background jobs. Target around 70% of the listed port speed as usable sustained capacity.

Safe viewer counts at 70% utilization

NIC capSafe usable Mbps~1.5 Mbps/viewer~2.5 Mbps/viewer~4.0 Mbps/viewer
250 Mbit/s1751167043
500 Mbit/s35023314087
1,000 Mbit/s700466280175
2,000 Mbit/s1,400933560350
4,000 Mbit/s2,8001,8661,120700
8,000 Mbit/s5,6003,7332,2401,400
10,000 Mbit/s7,0004,6662,8001,750
16,000 Mbit/s11,2007,4664,4802,800

What that means for 200 viewers

  • 250 Mbit/s plans — not enough except for very low bitrates
  • 500 Mbit/s plans — can work for low-mid bitrate, but not comfortable
  • 1 Gbit/s plans — viable if you keep average delivered bitrate moderate
  • 2 Gbit/s plans — where the setup gets comfortable
  • 4 Gbit/s plans — stop thinking about bandwidth, start thinking about CPU and storage

Storage math for VODs and clips

Rule of thumb: 1 Mbps ≈ 0.44 GB/hour

  • 1.5 Mbps ≈ 0.66 GB/hour
  • 2.5 Mbps ≈ 1.10 GB/hour
  • 4.0 Mbps ≈ 1.76 GB/hour
  • 6.0 Mbps ≈ 2.64 GB/hour

Usable media space after OS/app reserve (~15–25 GB)

Raw diskUsable media space
50 GB25–35 GB
100 GB75–85 GB
200 GB175–185 GB
400 GB375–385 GB

Approximate retained recording hours (at 2.5 Mbps)

  • 30 GB usable, about 27 hours
  • 80 GB usable, about 73 hours
  • 180 GB usable, about 164 hours
  • 380 GB usable, about 345 hours

At 4.0 Mbps

  • 30 GB usable, about 17 hours
  • 80 GB usable, about 45 hours
  • 180 GB usable, about 102 hours
  • 380 GB usable, about 216 hours
Storage takeaway: 50 GB is test-only. 100 GB is okay for dev/alpha. 200 GB is the first production-usable size. 400 GB is much better but still not archival. Long-term, push older VODs to object storage.

Family-by-family analysis

B3 family — best overall fit

The new B3 family is the strongest match for OpenVibe.Live because it balances decent vCPU counts, generous RAM, NVMe storage, strong network steps, and good pricing.

PlanRAMvCPUDiskNICPrice/hour
B3-88 GB250 GB NVMe500 Mbit/s$0.0508
B3-1616 GB4100 GB NVMe1,000 Mbit/s$0.1016
B3-3232 GB8200 GB NVMe2,000 Mbit/s$0.2033
B3-6464 GB16400 GB NVMe4,000 Mbit/s$0.4065
B3-128128 GB32400 GB NVMe8,000 Mbit/s$0.8131
B3-256256 GB64400 GB NVMe16,000 Mbit/s$1.6262
  • B3-8: good dev box, too small for serious 200-viewer ambitions
  • B3-16: good small production / alpha / staging box
  • B3-32: best overall single-box production choice
  • B3-64: best safer serious production choice for 200 viewers with headroom
  • B3-128 / B3-256: overkill for early OpenVibe.Live

B2 family — older, mostly outclassed

PlanRAMvCPUDiskNICPrice
B2-77 GB250 GB SSD250 Mbit/s$29.04/mo
B2-1515 GB4100 GB SSD250 Mbit/s$55.44/mo
B2-3030 GB8200 GB SSD500 Mbit/s$112.20/mo
B2-6060 GB16400 GB SSD1,000 Mbit/s$217.80/mo
B2-120120 GB32400 GB SSD10,000 Mbit/s$429.00/mo
Compared with B3, B2 gives worse price/performance, older SSD instead of NVMe, and weaker bandwidth. Only choose B2 if B3 is unavailable in your zone.

C3 family — CPU-heavy, not best value here

PlanRAMvCPUDiskNICPrice/hour
C3-44 GB250 GB NVMe250 Mbit/s$0.0453
C3-88 GB4100 GB NVMe500 Mbit/s$0.0907
C3-1616 GB8200 GB NVMe1,000 Mbit/s$0.1813
C3-3232 GB16400 GB NVMe2,000 Mbit/s$0.3627
C3-6464 GB32400 GB NVMe4,000 Mbit/s$0.7254
C3-128128 GB64400 GB NVMe8,000 Mbit/s$1.4508

C3 gets interesting if your deployment is heavily WebRTC-centric and CPU-bound. But for OpenVibe.Live, B3 usually wins because the app wants more RAM, more bandwidth, more storage, and better economics per box.

Example: B3-32 (32 GB / 8 vCPU / 200 GB / 2 Gbit/s for $0.2033/h) vs C3-16 (16 GB / 8 vCPU / 200 GB / 1 Gbit/s for $0.1813/h) — for only a little more, B3-32 gives double the RAM and double the network.

C2 family — least attractive

PlanRAMvCPUDiskNICPrice
C2-77 GB250 GB SSD250 Mbit/s$42.24/mo
C2-1515 GB4100 GB SSD250 Mbit/s$81.83/mo
C2-3030 GB8200 GB SSD500 Mbit/s$165.00/mo
C2-6060 GB16400 GB SSD1,000 Mbit/s$323.40/mo
C2-120120 GB32400 GB SSD10,000 Mbit/s$640.20/mo

C2 is expensive, older, and has weaker bandwidth than the B3 alternative. Not recommended for OpenVibe.Live.

Streaming method plan fit

WebRTC / mediasoup

The method most likely to become CPU-sensitive first.

  • B3-32 for moderate production
  • B3-64 for safer 200-viewer production
  • C3-32 only if you are convinced CPU will matter more than RAM/bandwidth economics

If your expected audience is up to 200 and WebRTC is a real primary path, start at B3-64 — the full balance of 16 vCores + 4 Gbit/s + 400 GB NVMe is much healthier.

JSMPEG

More straightforward on the server side — becomes bandwidth-bound quickly.

  • B3-16 for smaller audiences and testing
  • B3-32 for up to 200 viewers at moderate bitrates
  • B3-64 if you want bitrate headroom or larger audience spikes

For a JSMPEG-heavy public deployment, B3-32 is the sweet spot.

RTMP ingest + direct playback

RTMP ingest itself is light. Viewer delivery is what costs you — again outbound bandwidth and storage.

  • B3-16 for low-mid audience counts
  • B3-32 for a real public rollout
  • B3-64 if you expect higher bitrate, spikes, or multiple simultaneous live loads

$200 OVH credit analysis

OVH gives $200 in public cloud credit that expires after 90 days. Two key questions: how long the credit lasts running continuously, and whether the plan can run the full 90 days within the credit window.

How long $200 lasts on each plan

PlanPrice/hour$200 lastsHours
B3-8$0.0508164 days3,937 h
B3-16$0.101682 days1,969 h
B3-32$0.203341 days984 h
B3-64$0.406520.5 days492 h
B3-128$0.813110.3 days246 h
B3-256$1.62625.1 days123 h
B2 family
B2-7$0.0813102.5 days2,460 h
B2-15$0.153954 days1,300 h
B2-30$0.312326.7 days640 h
B2-60$0.606013.8 days330 h
B2-120$1.19237 days168 h
C3 family
C3-4$0.0453184 days4,415 h
C3-8$0.090792 days2,205 h
C3-16$0.181346 days1,103 h
C3-32$0.362723 days551 h
C3-64$0.725411.5 days276 h
C2 family
C2-7$0.117670.9 days1,701 h
C2-15$0.227636.6 days879 h
C2-30$0.458618.2 days436 h
C2-60$0.89869.3 days223 h
C2-120$1.77864.7 days112 h

90-day continuous run cost (hourly plans)

Plan30-day cost90-day cost
B3-8$36.58$109.73
B3-16$73.15$219.46
B3-32$146.38$439.13
B3-64$292.68$878.04
C3-4$32.62$97.85
C3-8$65.30$195.91
C3-16$130.54$391.61
C3-32$261.14$783.43

Best credit strategies

Strategy A — longest useful beta: Run B3-8 or C3-8 during buildout, staging, and feature validation. Upgrade to B3-32 only when audience and VOD usage justify it.
Strategy B — realistic public beta: Start on B3-16. Accept that $200 covers only ~82 days. Resize to B3-32 when you need the larger envelope.
Strategy C — short burst launch: Use B3-32 for launch testing. Know that $200 gives ~41 days continuously.

Recommended picks by scenario

Scenario A — dev, staging, private alpha

Pick: B3-8 — cheapest balanced plan. Enough for app setup, testing, internal streams, chat, docs, and smoke validation. Credit lasts the full 90 days easily.

Scenario B — public beta, one main stream, realistic growth

Pick: B3-16 (budget) or B3-32 (best value). Compared with B3-16, B3-32 gives 2× RAM, 2× vCPU, 2× disk, 2× network for exactly 2× price — the operational breathing room is much better.

Scenario C — target up to 200 concurrent viewers on one box

Pick: B3-32 (minimum serious) or B3-64 (safer). For 200 viewers, the question becomes: what is your average delivered bitrate? How WebRTC-heavy is the workload? How much VOD retention locally? B3-32 is the first deliberate production choice; B3-64 is less stressful.

Scenario D — WebRTC-first, higher CPU pressure, future growth

Pick: B3-64 — only slightly more expensive than C3-32 while giving more RAM, more network, equivalent vCPU count, and better overall OpenVibe.Live balance.

Final recommendation

If you want the single OVH plan that makes the most sense for OpenVibe.Live, including storage, mixed real-time features, and streaming toward 200 viewers:

B3-32 — Best overall compromise

Price · RAM · vCPU · NVMe storage · Outbound bandwidth · Realism for local VOD/clip retention

B3-64 — Best safer no-regrets version for heavier WebRTC / more headroom
B3-8 — Best cheap build/test box while burning the free credit

Bottom line in one sentence

PlanVerdict
B3-8Best cheap build/test box
B3-16Okay starter production box
B3-32Best overall OpenVibe.Live plan
B3-64Best safer 200-viewer / WebRTC-heavy plan
B2 / C2Mostly not worth it here
C3Only if unusually CPU-biased and accept weaker overall value