Install — Dokploy
Single-node alternative for evaluation. Authored from the K8s mapping; not yet validated on a real Dokploy host.
Dokploy is a self-hosted PaaS for Docker. It is a much simpler target than Kubernetes — a single VPS with Docker, Traefik, and a small control plane — and is the right answer when you want to evaluate R2-D2 without standing up a real cluster. It is not the production path; for that, use the Kubernetes install.
The mapping from the K8s install to a Dokploy install is mostly mechanical:
| K8s concept | Dokploy concept |
|---|---|
| Deployment + Service + Ingress | A single Docker "service" with a domain attached |
| Helm chart | A compose.yaml or per-service config |
| ConfigMap | Mounted file or env block |
| Secret | Dokploy "Environment" block (encrypted at rest) |
| kube-vip LB IP | Not needed — Traefik routes by hostname |
| nginx-ingress | Replaced by Traefik (Dokploy's default) |
| Caddy edge | Optional — Traefik can terminate TLS itself via Let's Encrypt |
Prerequisites
- A single Linux VPS (4 vCPU / 8 GB RAM minimum if you want all four backing services on the same host; more if you intend to run more than a handful of camera feeds).
- A domain you control, with DNS pointed at the VPS. Subdomains for each public
endpoint (
r2d2.example.com,restreamer.example.com,trailbase.example.com,holonet.example.com, etc.). - Dokploy installed per their docs — typically a one-liner install script.
Layout we'll build
VPS (one box)
├── Dokploy control plane
├── r2d2-fleet (this dashboard) ← r2d2.example.com
├── trailbase ← trailbase.example.com
├── restreamer (datarhei/core) ← restreamer.example.com
├── tbmq + redis (MQTT) ← tbmq internal-only
├── yugabytedb (optional) ← yb internal-only
└── one Node-RED instance for testing ← nr.example.comYou can drop YugabyteDB if you only care about the Fleet + Restreaming planes — TrailBase covers everything the dashboard itself needs.
1. Prepare environment
Create a Dokploy Project called r2d2. Inside it, create one Service per row
above.
For each backing service, the basic shape is:
| Service | Image | Internal port | Public hostname | Volumes |
|---|---|---|---|---|
| trailbase | trailbase/trailbase:latest | 4000 | trailbase.example.com | /data |
| restreamer | datarhei/core:latest | 8080 | restreamer.example.com | /core/config, /core/data |
| tbmq | thingsboard/tbmq:latest | 1883 (mqtt), 8083 (admin) | tbmq.example.com (admin only) | broker data |
| redis (for tbmq) | redis:7-alpine | 6379 | internal-only | redis data |
| yugabyte (optional) | yugabytedb/yugabyte:latest | 5433 (YSQL) | internal-only | yb data |
| r2d2-fleet | your-registry/r2d2-fleet:<tag> | 3000 | r2d2.example.com | — |
| node-red (test) | nodered/node-red:latest | 1880 | nr.example.com | flows |
2. Wire the network
Dokploy services on the same project see each other on a shared docker network using
the service name as DNS. So inside the r2d2-fleet service, the env vars look like:
AUTH_ENABLED=true
TRAILBASE_URL=http://trailbase:4000
RESTREAMER_API_URL=http://restreamer:8080
HOLONET_URL=https://tbmq.example.com
HOLOCHRON_URL= # external, configure later
COP_URL= # external, configure later
PROBE_URL= # external, configure later
RIFT_GATES_URL= # external, configure later
NODE_RED_ADMIN_TOKEN=<generate one>HOLONET_URL for Dokploy installs is typically the public TBMQ admin URL — there's no
in-cluster MQTT Explorer in this layout, so you embed the TBMQ admin UI itself.
3. Bootstrap content
R2-D2 expects the same config files as on K8s. The simplest path is to commit them into a fork of this repo and have Dokploy clone from that fork at deploy time:
instances/registry.yaml— start with one entry for the test Node-RED servicerepublic-config.yaml,videos-config.yaml,holocron-config.yaml,archives-config.yaml— start empty; fill in via the Settings pages
Dokploy supports per-service "preDeploy" hooks; that's where you'd run any config-generation script.
4. TLS
Easiest: let Traefik (Dokploy's bundled reverse proxy) terminate TLS via Let's Encrypt. Each service in Dokploy has a "Domains" tab — add the public hostname, tick the "Enable HTTPS" checkbox, point your DNS at the VPS, and it Just Works.
There is no equivalent of the K8s "Caddy → nginx-ingress LB IPs" pattern here. Traefik talks directly to the container by hostname. Simpler in every way.
5. First login
- Open
https://trailbase.example.com, create the initial admin account. - Open
https://r2d2.example.com, log in with that account. - Walk through the seven planes' Settings pages to fill in the YAML configs.
Known unknowns
Because this guide has not yet been validated end-to-end, the gaps you might hit:
- Persistence-volume sizing. TrailBase's data volume grows with the size of the Republic/Holoprojector state and the snapshot ingest cadence. The K8s install uses PVC sizes the K8s side has dialed in — Dokploy will need analogous host-volume sizes. The TBMQ redis volume in particular is sensitive to retention settings.
- MQTT Explorer (HoloNet). On K8s we run a separate in-cluster MQTT Explorer service and embed it in the Force iframe. On Dokploy you can either run one yourself or use the TBMQ admin UI as the embed target. The latter is what the env block above assumes.
- YugabyteDB single-node. Single-node YB works for evaluation but is unsupported for production loads. If you're using R2-D2 just for the Fleet + Restreaming planes, drop YB from the stack entirely.
- Backup/restore. Dokploy has its own backup story; we haven't validated that it produces a consistent snapshot across all four backing services. Worth testing before you trust this layout with non-throwaway data.
When you do validate this guide on a real Dokploy host, please update this page with the deltas you found.