WBO Collaborative Whiteboard on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and configuration of WBO (Whitebophir) 2.17.0 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images. WBO is a self-hosted, zero-config online collaborative whiteboard: you and your collaborators open the same board by its URL and draw together in real time over websockets, with a pen, straight lines, rectangles, ellipses, text and images on a shared, infinite canvas. It is a lean, privacy-respecting alternative to hosted whiteboard services — your boards stay on infrastructure you control.
The image installs WBO 2.17.0 from the upstream project pinned by commit into /opt/wbo, running as a dedicated non-root service under systemd on the Node.js 22 runtime, and ships the AGPL-3.0 licence text alongside it. Each board is stored as files on the VM's own disk under /var/lib/wbo/server-data, so there is no external database, no object store and no database port to secure.
Security model. WBO has no authentication of its own, so this image is hardened never to be left open to the internet. WBO binds to 127.0.0.1:5001 only and is fronted by nginx on port 443 (TLS). The entire whiteboard is protected by per-VM HTTP Basic Auth (a password minted uniquely on first boot) served over a per-VM self-signed TLS certificate (also minted on first boot). The websocket upgrade that real-time collaboration depends on is proxied correctly. The only unauthenticated endpoint is /healthz, a static health check that leaks nothing. The only ports exposed are SSH (22) and the web UI (443, with 80 redirecting to HTTPS).
What is included:
-
WBO (Whitebophir) 2.17.0 under
/opt/wbo, run as the non-rootwboservice account on Node.js 22 -
wbo.servicesystemd unit running the server bound to127.0.0.1:5001 -
nginxreverse proxy on port 443 (TLS): the whole whiteboard behind per-VM HTTP Basic Auth, websocket upgrade proxied -
wbo-firstboot.servicesystemd oneshot that mints the per-VM Basic Auth password and per-VM self-signed TLS certificate on first boot -
Boards stored as files under
/var/lib/wbo/server-data(no database) -
A credential + draw self-test at
/usr/local/sbin/wbo-credcheck.sh -
The AGPL-3.0 licence text at
/usr/local/share/wbo/LICENSE -
Ubuntu 24.04 LTS base with latest security patches applied at build time
-
24/7 cloudimg support with guaranteed 24 hour response SLA
Prerequisites
-
An active Azure subscription
-
A subscription to the WBO on Ubuntu 24.04 listing on Azure Marketplace
-
An SSH public key for VM authentication
-
A virtual network and subnet in the target region
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM). WBO is lightweight; scale up only for very large boards or many concurrent collaborators.
Step 1: Deploy from the Azure Portal
Navigate to Marketplace in the Azure Portal, search for WBO (or Whitebophir), select the cloudimg publisher entry, and click Create.
On the Networking tab attach a network security group that allows inbound TCP 22 from your management IP range and TCP 443 from the networks whose users will open the whiteboard. Port 80 only redirects to HTTPS. The whiteboard is protected by a per-VM Basic Auth password, but you should still restrict the source ranges that can reach it.
Click Review + create, wait for validation, then Create. Deployment takes around two minutes.
Step 2: Deploy from the Azure CLI
RG="wbo-prod"
LOCATION="eastus"
az group create --name "$RG" --location "$LOCATION"
az vm create \
--resource-group "$RG" \
--name wbo-01 \
--image <publisher>:<offer>:<sku>:latest \
--size Standard_B2s \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_rsa.pub \
--public-ip-sku Standard
# open the ports the whiteboard uses (SSH from your management range, HTTPS from your users)
az vm open-port --resource-group "$RG" --name wbo-01 --port 443 --priority 900
Step 3: Connect via SSH
Connect as azureuser (the login user for this image):
ssh azureuser@<vm-ip>
Step 4: Verify the services
WBO runs on the Node.js 22 runtime, bound to loopback, behind nginx TLS. Confirm the runtime, the version, that both services are active, that WBO listens only on 127.0.0.1:5001, and that the AGPL-3.0 licence ships with the image:
node --version
jq -r '"WBO "+.version' /opt/wbo/package.json
systemctl is-active wbo nginx
sudo ss -ltn | grep -E ':443 |:5001 '
head -2 /usr/local/share/wbo/LICENSE
Expected output:
v22.23.2
WBO 2.17.0
active
active
LISTEN 0 511 127.0.0.1:5001 0.0.0.0:*
LISTEN 0 511 0.0.0.0:443 0.0.0.0:*
LISTEN 0 511 [::]:443 [::]:*
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007

Step 5: Retrieve the per-VM credentials
On first boot the image generated a Basic Auth password and a self-signed TLS certificate that are unique to this VM, and wrote the password to a root-only file. Read it:
sudo cat /root/wbo-credentials.txt
The file contains the whiteboard URL, the Basic Auth user (admin) and the generated password. The structure is shown below (values are unique to your instance):
wbo.url=https://<vm-public-ip>/
wbo.basicauth.user=admin
wbo.basicauth.pass=<generated-per-vm>
You can confirm the per-VM credential and the end-to-end draw path with the shipped self-test, which prints OK:
sudo bash /usr/local/sbin/wbo-credcheck.sh

Step 6: The authentication gate
The only unauthenticated endpoint is /healthz. The whole whiteboard returns 401 without the per-VM Basic Auth password, and passes through with it. The commands below read the generated password from the root-only file and prove all three cases over TLS (the -k flag accepts the per-VM self-signed certificate):
BP=$(sudo grep '^wbo.basicauth.pass=' /root/wbo-credentials.txt | cut -d= -f2-)
curl -ks -o /dev/null -w 'GET /healthz (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/healthz
curl -ks -o /dev/null -w 'GET / (no auth) -> HTTP %{http_code}\n' https://127.0.0.1/
curl -ks -o /dev/null -w 'GET / (wrong pw) -> HTTP %{http_code}\n' -u admin:wrong https://127.0.0.1/
curl -ks -o /dev/null -w 'GET /boards/demo (ok) -> HTTP %{http_code}\n' -u admin:"$BP" https://127.0.0.1/boards/demo
Expected output:
GET /healthz (no auth) -> HTTP 200
GET / (no auth) -> HTTP 401
GET / (wrong pw) -> HTTP 401
GET /boards/demo (ok) -> HTTP 200

Step 7: Open the whiteboard
In your browser, go to https://<vm-public-ip>/. Because the certificate is self-signed (per-VM), your browser will warn you the first time — accept the warning to continue (Step 9 covers installing a certificate for a custom domain). Enter the Basic Auth credential when prompted: user admin and the password from Step 5.
You will land on a fresh board with the drawing toolbar on the left — pen, straight line, rectangle, ellipse, text, eraser, hand (pan), grid, download, zoom and a colour picker.

Select the pen and draw — everything you sketch appears instantly. Add shapes, text and freehand strokes:

To collaborate, open a board at a memorable URL — for example https://<vm-public-ip>/boards/team-planning — and share that URL (and the Basic Auth password) with your collaborators. Everyone who opens the same board draws on the same canvas in real time. Because each board is persisted to disk, reopening the board later brings back exactly what was drawn:

Step 8: Confirm a drawing persisted
WBO saves each board to disk shortly after it changes and serves the current state of any board as an SVG at /boards/<name>.svg. After you have drawn on a board (for example demo in the browser), you can fetch its SVG and see the shapes that were saved:
BP=$(sudo grep '^wbo.basicauth.pass=' /root/wbo-credentials.txt | cut -d= -f2-)
curl -ks -u admin:"$BP" https://127.0.0.1/boards/demo.svg | head -c 400; echo
A board that has been drawn on contains the stored shapes (lines, paths, rectangles and ellipses). A stroke drawn over the real websocket path is persisted and rendered back — which is exactly what makes real-time collaboration work:

Step 9: Add a custom domain and a real TLS certificate
The image ships a per-VM self-signed certificate. For a public deployment, point a DNS name at the VM and install a CA-issued certificate (for example with Let's Encrypt). Replace the self-signed certificate that nginx serves — after issuing a certificate for <your-domain>, copy the files into place and reload nginx:
# after issuing a certificate for <your-domain>, install it:
sudo cp /path/to/fullchain.pem /etc/nginx/wbo/wbo.crt
sudo cp /path/to/privkey.pem /etc/nginx/wbo/wbo.key
sudo nginx -t && sudo systemctl reload nginx
Or issue one automatically for <your-domain> with certbot:
sudo certbot --nginx -d <your-domain>
Step 10: Change the Basic Auth password
Set your own whiteboard password at any time (admin is the user). Run sudo htpasswd /etc/nginx/.wbo.htpasswd admin for an interactive prompt, or set it non-interactively to a value you choose:
sudo htpasswd -b /etc/nginx/.wbo.htpasswd admin '<new-password>'
sudo systemctl reload nginx
Step 11: Back up your boards
Every board is a file under /var/lib/wbo/server-data. Back the directory up with tar:
sudo tar czf ~/wbo-boards-backup.tgz -C /var/lib/wbo server-data
ls -lh ~/wbo-boards-backup.tgz
Restore by extracting the archive back into /var/lib/wbo and restarting WBO:
sudo systemctl restart wbo
Troubleshooting
The browser cannot connect / certificate warning. The per-VM certificate is self-signed, so a warning on first visit is expected — accept it, or install a CA-issued certificate (Step 9). Confirm nginx is serving on 443 with sudo ss -ltn | grep ':443 '.
The whiteboard returns 401. That is the Basic Auth gate working. Use user admin and the password from sudo cat /root/wbo-credentials.txt, or set your own (Step 10).
Real-time updates are not appearing. Real-time collaboration uses websockets. If you front WBO with an additional proxy or load balancer, ensure it forwards the Upgrade and Connection headers so the websocket upgrade reaches nginx.
Check the service logs:
sudo journalctl -u wbo.service --no-pager -n 50
sudo systemctl status nginx --no-pager
Support
cloudimg provides 24/7 technical support for this WBO product by email (support@cloudimg.co.uk) and live chat, with a guaranteed 24 hour response SLA and a one hour average response time for critical issues. We help with deployment and initial configuration, retrieving and changing the Basic Auth password, sharing boards with collaborators, installing a CA-issued certificate for a custom domain, backing up and restoring boards, upgrades and patch management, and troubleshooting.