White-Label Deployment
Overview
White-label deployments are self-hosted instances of Range Day Pro for organizations (military, LE, large training companies) that need private, branded deployments. Same codebase as the SaaS product. All configuration is runtime — no custom builds.
Deployment Primitive: Docker Compose
A white-label deployment ships as a docker-compose.yml with configuration via a mounted YAML/JSON file and asset directories.
# Example docker-compose.yml
services:
server:
image: rangedaypro/server:latest
volumes:
- ./config.yaml:/etc/rangedaypro/config.yaml
- ./assets:/etc/rangedaypro/assets
- ./license.bin:/etc/rangeday/license.bin:ro # signed instance license (see runbook)
environment:
- DATABASE_URL=postgres://...
- SMTP_HOST=...
- LICENSE_FILE=/etc/rangeday/license.bin
- WEB_ORIGIN=https://<their-pwa-host> # public PWA origin; must be a licensed domain
ports:
- "443:443"
dashboard:
image: rangedaypro/dashboard:latest
volumes:
- ./config.yaml:/etc/rangedaypro/config.yaml
- ./assets:/etc/rangedaypro/assets
pwa:
image: rangedaypro/pwa:latest
volumes:
- ./config.yaml:/etc/rangedaypro/config.yaml
- ./assets:/etc/rangedaypro/assets
postgres:
image: postgres:16
volumes:
- pgdata:/var/lib/postgresql/dataThe customer runs docker compose up and has a working deployment.
Configuration
All branding and deployment configuration is runtime, loaded from a mounted config file. No rebuild required to change branding.
⚠ Not yet wired — tracked in white-label-config-branding. The server reads
config.yamlrelative to its working directory (apps/server/src/main.rs), not the/etc/rangedaypro/config.yamlmount path shown below, andServerConfighas nobrandingfields and doesn’t reject unknown keys — so thebranding:block below is currently a no-op. The signed license mount +LICENSE_FILE/WEB_ORIGINenv vars are active; config-file branding/assets are aspirational until that item lands.
# Example config.yaml
branding:
app_name: "Springfield PD Training Portal"
org_name: "Springfield Police Department"
logo: "/etc/rangedaypro/assets/logo.svg"
favicon: "/etc/rangedaypro/assets/favicon.ico"
colors:
primary: "#1a3d5c"
secondary: "#f0f4f8"
accent: "#d4a017"
email:
sender_name: "Springfield PD Training"
sender_address: "training@springfieldpd.gov"
smtp_host: "smtp.springfieldpd.gov"Capabilities are license-bound (not config)
Capability flags — public_signup, billing, drill_catalog, and the max_users
seat cap — are not set in config.yaml. They are carried in the signed instance
license (license.bin) and verified cryptographically (Ed25519). White-label
customers self-host the binary and own their database, so an unsigned YAML flag would be
trivially editable — the signature is the one thing they cannot forge, so capabilities
live only in the signed claims. (An earlier draft of this doc showed a features: YAML
block; that was removed precisely because it would be a forgeable source of truth.)
To change a customer’s capabilities or seat cap, T.REX re-issues the license
(rangeday license issue …) and the customer swaps in the new license.bin — no rebuild.
See the Instance License Onboarding runbook for the full procedure.
Custom Assets
Custom images, stylesheets, and other assets are mounted via a directory:
assets/
logo.svg
favicon.ico
custom.css # optional CSS overrides
images/
login-background.jpg
...
The platform picks up assets from the mounted directory at runtime. Changing an asset is a file replacement + container restart — no rebuild.
What Gets Deployed
White-label deployments include the server, dashboard, and PWA. The marketing site is not included — the customer doesn’t need a landing page for their own org.
| Component | Included | Notes |
|---|---|---|
| Server | Yes | Same Axum binary, pointed at customer’s Postgres |
| Dashboard | Yes | Admin web app for the customer’s instructors/admins |
| PWA | Yes | Primary client for shooters on org-owned devices |
| Marketing Site | No | Not needed — users are provisioned by admins |
| Billing Module | Disabled | Enterprise contract, not Stripe |
| Public Signup | Disabled | Admin-provisioned users only |
Primary Client: PWA on Org Devices
In white-label deployments, the PWA is often the primary client — not a degraded fallback. Military and LE shooters typically use org-owned devices (armorer’s tablet, shared range devices), not personal phones. The PWA loaded on these devices provides the scoring and drill viewing interface.
This means the PWA’s feature roadmap toward full-featured (including offline scoring) is especially important for white-label customers.
Private Network Deployment
White-label deployments may run on private networks with no public internet access. The entire stack (server, dashboard, PWA, Postgres) runs on the customer’s internal network. Org devices access the platform via internal DNS or IP.
Native Mobile Apps on White-Label
The native iOS and Android apps are not re-branded for white-label. Instead, they can be configured to point to a white-label deployment’s server URL:
- A military org deploys the white-label platform on their private network
- Org-owned devices with the native apps installed are configured to point to the internal server (e.g.,
https://training.internal.mil) - The native apps function normally — same Rust core, same UI, just talking to a different server
- No custom app store listing needed — the same Range Day Pro app, pointed at a different backend
This configuration could be:
- A settings screen in the app (“Server URL”)
- MDM-pushed configuration (for managed devices)
- A QR code scanned on first launch that sets the server URL
This is a future feature — MVP white-label uses the dashboard and PWA only.
What Differs from SaaS
| Concern | SaaS | White-Label |
|---|---|---|
| Billing | Stripe, usage-based | Disabled — enterprise contract |
| Signup | Public self-service | Admin-provisioned |
| Auth | Our auth module (future: Zitadel) | Same, or customer’s IdP via Zitadel |
| Database | Shared multi-tenant Postgres | Dedicated Postgres |
| Network | Public internet | May be private/air-gapped |
| Orgs | Many orgs | Typically one org |
| Drill visibility | Public/Published catalog | Likely all Private |
| PWA role | Degraded fallback | Often the primary client |
| Mobile apps | App store download | Configured to point to internal server (future) |
| Branding | T.REX ARMS / Range Day Pro | Customer’s brand via config.yaml |