The all-in-one folder is now Docker-AIO, so -f Docker-AIO/Dockerfile resolves without quoting. Every path that pointed at the old name follows it: the compose build stanza, the documented build commands, and the links from the two READMEs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
93 lines
3.9 KiB
Markdown
93 lines
3.9 KiB
Markdown
# DriverVault — Docker (multi-container stack)
|
|
|
|
Three containers — **PocketBase**, **API Server**, **Web App** — on one compose
|
|
network. This is the deployment to use unless you specifically want everything
|
|
in a single image; for that see [`../Docker-AIO`](../Docker-AIO).
|
|
|
|
```
|
|
Browser ─► Web App BFF (:8090) ──/api/*──► API Server (:8080) ─► PocketBase (:8070)
|
|
```
|
|
|
|
Only the Web App port is meant to be public. The API Server and the PocketBase
|
|
admin UI are published for convenience and, in the prod file, bound to
|
|
`127.0.0.1` by default.
|
|
|
|
| File | Use |
|
|
|---|---|
|
|
| `docker-compose.yml` | **builds from source** in this repo — for development and local testing |
|
|
| `docker-compose.prod.yml` | **pulls prebuilt images** from the registry — for deployment |
|
|
| `.env.example` / `.env.prod.example` | copy to `.env` for the matching compose file |
|
|
| `pocketbase/` | the PocketBase image (official release binary on alpine) |
|
|
|
|
## Run it
|
|
|
|
```bash
|
|
cd Docker
|
|
cp .env.example .env # then edit — PB_ADMIN_* have no safe defaults
|
|
docker compose up -d --build
|
|
```
|
|
|
|
Production, from the registry:
|
|
|
|
```bash
|
|
cp .env.prod.example .env # then edit
|
|
docker compose -f docker-compose.prod.yml pull
|
|
docker compose -f docker-compose.prod.yml up -d
|
|
```
|
|
|
|
Then: web app on `http://host:8090/`, the API Server's superadmin panel on
|
|
`http://host:8080/`, PocketBase admin on `http://host:8070/_/`.
|
|
|
|
## First boot
|
|
|
|
Both steps are idempotent, so restarts and upgrades are safe:
|
|
|
|
1. **PocketBase** upserts its superuser from `PB_ADMIN_EMAIL` / `PB_ADMIN_PASSWORD`.
|
|
This is the only way to create the first superuser — the REST API cannot
|
|
bootstrap it. The API Server then authenticates with the same credentials.
|
|
2. **The API Server** creates any missing collections and reconciles existing
|
|
ones, then creates the first app `superadmin` from
|
|
`DRIVERVAULT_SUPERADMIN_EMAIL` / `_PASSWORD` if no such user exists. Set
|
|
`PB_BOOTSTRAP=false` to skip once the database is established.
|
|
|
|
No manual `setup-pocketbase.mjs` step is needed here — the server runs the same
|
|
schema reconcile itself.
|
|
|
|
## Volumes
|
|
|
|
| Volume | Holds |
|
|
|---|---|
|
|
| `pb_data` | the PocketBase SQLite database and uploaded files |
|
|
| `api_data` | the API Server's `plugins.json`, and the `.env` the panel rewrites when a superadmin retargets the PocketBase connection |
|
|
|
|
Both default to Docker-managed named volumes. In the prod file, set `PB_DATA` /
|
|
`API_DATA` to absolute host paths for bind mounts instead.
|
|
|
|
> The API Server container runs as an unprivileged user, and a **named** volume
|
|
> inherits that ownership from the image. A **bind mount** does not — the host
|
|
> directory's ownership wins, so `chown` it to the container's `app` user (or
|
|
> `chmod` it writable) before setting `API_DATA` to a host path, otherwise the
|
|
> server cannot write `plugins.json`.
|
|
|
|
## Charger control (OCPP)
|
|
|
|
Chargers in own/proxy mode dial in to `/ocpp/{serial}` **on the API Server
|
|
port**, authenticating with a per-charger control token in an OCPP Basic-auth
|
|
header. A plaintext `ws://` would put that token on the wire in the clear, so
|
|
`OCPP_REQUIRE_TLS` defaults to `true` and non-TLS connections are rejected.
|
|
|
|
This stack serves plain HTTP, so to actually use charger control you need to
|
|
terminate TLS in a reverse proxy in front of it and set `OCPP_PUBLIC_URL` to the
|
|
public `wss://` base (behind a proxy, deriving it from request headers is
|
|
unreliable). `OCPP_REQUIRE_TLS=false` is for trusted networks only. You will
|
|
also need `API_BIND` set so the proxy can reach the port.
|
|
|
|
## Notes
|
|
|
|
- `docker-compose.yml` builds the API Server and Web App from `../API Server`
|
|
and `../Web App`, so run it from this directory with the repo checked out.
|
|
- The Web App's Vue bundle is built with an empty `VITE_API_BASE`, so the
|
|
browser uses same-origin `/api` and the BFF proxies it — no CORS in play.
|
|
- `CORS_ALLOW_ORIGINS` therefore only matters if a browser calls the API Server
|
|
directly. Native mobile apps are not subject to CORS at all.
|