# MeshBay — Packaging Four packages, installed under `/opt//`: | Package | RPM spec | DEB control | Description | |---|---|---|---| | `meshbay-common` | `rpm/meshbay-common.spec` | `deb/meshbay-common/` | Shared Python venv + all pip deps | | `meshbay-hub` | `rpm/meshbay-hub.spec` | `deb/meshbay-hub/` | Hub server (FastAPI + PostgreSQL) | | `meshbay-node` | `rpm/meshbay-node.spec` | `deb/meshbay-node/` | Node daemon + local UI | | `meshbay-client` | `rpm/meshbay-client.spec` | `deb/meshbay-client/` | Electron desktop app | ## Building packages ```bash # On Ubuntu 26.04: bash packaging/build/build-packages.sh deb # On Fedora 44 (local): bash packaging/build/build-packages.sh rpm # On Raspberry Pi (arm64, deferred): bash packaging/build/build-packages.sh deb --arm64 ``` Output: `meshbay-{common,hub,node,client}__{arch}.{deb,rpm}` in `/tmp/meshbay-build/out/` (override with `MESHBAY_BUILD_DIR`). The version comes from each package's `pyproject.toml`. ## Install order Always install `meshbay-common` first (owns the shared Python venv). ```bash # Ubuntu/Debian sudo dpkg -i meshbay-common_*.deb sudo dpkg -i meshbay-hub_*.deb meshbay-node_*.deb sudo dpkg -i meshbay-client_*.deb # Fedora sudo rpm -ivh meshbay-common-*.rpm sudo rpm -ivh meshbay-hub-*.rpm meshbay-node-*.rpm sudo rpm -ivh meshbay-client-*.rpm ``` ### Hardware video acceleration is a weak dependency Both the node and the client use the GPU for video where one works — the node to re-encode a browser-hostile codec (`hwaccel.py`: VA-API on Linux, Quick Sync or NVENC on Windows), the client to decode H.264 (`main.js`; only on Linux, since Chromium already decodes in hardware on Windows and macOS). Neither requires it, and both establish it by measurement rather than by assuming the packaged driver is present and functional, so a machine without a GPU installs and runs exactly as before. Only Linux needs packaged drivers — on Windows the bundled ffmpeg carries its own encoders and Chromium uses the OS's decoder. The drivers are therefore `Recommends` (`va-driver-all` on Debian/Ubuntu; `libva`, `intel-media-driver`, `mesa-va-drivers` on Fedora), which matters for how the packages are installed: **`dpkg -i` and `rpm -ivh` both ignore weak dependencies; `apt` and `dnf` install them.** On a low-power machine — an Intel mini-PC serving and watching video is the case this exists for — use the resolver, so the drivers come too: ```bash sudo apt install ./meshbay-common_*.deb ./meshbay-node_*.deb ./meshbay-client_*.deb sudo dnf install ./meshbay-common-*.rpm ./meshbay-node-*.rpm ./meshbay-client-*.rpm ``` Nothing has to be enabled afterwards and there are no flags to set by hand. The node logs which encoder it found at the first stream (`hwaccel:`), and the client records what it measured in its own `config.json` — the file that already remembers the hub address — under `videoDecodeProbe`, and `videoAcceleration: "off"` in that same file turns it back off. ## Architecture meshbay-common owns the shared Python virtual environment at `/opt/meshbay-common/venv/`. Hub and node install their code into that venv. The client is a standalone Electron app at `/opt/meshbay-client/`. No pip runs at install time — everything is pre-built. ## Post-install (hub) ```bash sudo cp /etc/meshbay/hub.toml.example /etc/meshbay/hub.toml sudo nano /etc/meshbay/hub.toml sudo systemctl enable --now meshbay-hub ``` The hub generates its own Ed25519 keypair on first start if `identity.private_key_path` does not exist yet (`app.py`, lifespan), so there is no key-generation step to run by hand. ## Post-install (node) ```bash meshbay-node init # copies default.env (with TMDB token) nano ~/.config/meshbay/node.toml systemctl --user enable --now meshbay-node ``` ## Firewall Two passive profiles: packaged, not activated. **LAN casting (client)** — the Electron client runs an HTTP relay on **TCP 19550-19553** to stream decrypted video to Chromecast / Smart TV devices on the local network. Discovery uses **mDNS (UDP 5353)**. **Peer connections (node)** — WebRTC binds an ephemeral UDP port per connection, so there is no fixed port: the node profile opens **UDP 1024-65535** and must be scoped to the LAN. A node that refuses unsolicited inbound UDP is unreachable from every browser it cannot itself call back, because browsers publish an mDNS `.local` candidate the node cannot resolve. See `docs/PACKAGING-GUIDE.md` for the reasoning. ### Fedora / RHEL (firewalld) Pre-installed service files at `/usr/lib/firewalld/services/`: ```bash sudo firewall-cmd --permanent --add-service=meshbay-cast sudo firewall-cmd --permanent --zone= --add-service=meshbay-node sudo firewall-cmd --reload ``` ### Ubuntu / Debian (ufw) Pre-installed application profile at `/etc/ufw/applications.d/meshbay`: ```bash sudo ufw allow "MeshBay Cast" sudo ufw allow from 192.168.0.0/16 app "MeshBay Node" # your LAN, not "anywhere" ``` ## Systemd units | File | Location | |---|---| | `systemd/meshbay-hub.service` | `/usr/lib/systemd/system/meshbay-hub.service` | | `systemd/meshbay-node.service` | `/usr/lib/systemd/system/meshbay-node@.service` | | `systemd/meshbay-node-user.service` | `/usr/lib/systemd/user/meshbay-node.service` | The node user service is enabled by the person themselves: ```bash systemctl --user enable --now meshbay-node loginctl enable-linger $USER # keep serving when logged out ``` ## Desktop launcher The client installs a Gnome `.desktop` file at `/usr/share/applications/meshbay.desktop` — the application appears as **"MeshBay"** in the applications menu.