129 lines
5.5 KiB
Markdown
129 lines
5.5 KiB
Markdown
# Unraid deployment
|
|
|
|
MobilityOps is deployed from a committed source archive; the server does not need Gitea
|
|
credentials. The portable `compose.yaml` is combined with `compose.unraid.yaml`; of the
|
|
MobilityOps-owned services, only the web application is reachable from the LAN. The host's
|
|
existing shared n8n remains available on its established port 5678.
|
|
|
|
## Server layout
|
|
|
|
- Directory: `/mnt/user/appdata/mobilityops`
|
|
- Compose project: `mobilityops`
|
|
- Public web: `https://fleetops.itworx.tech` (TLS reverse proxy to host port `1236`)
|
|
- API and PostgreSQL: Compose network only
|
|
- Shared n8n: `http://192.168.10.150:5678` (outside the MobilityOps Compose project)
|
|
|
|
## Deploy
|
|
|
|
Create `.env` from `.env.example`, replace every placeholder secret, set
|
|
`MOBILITYOPS_ENV=production`, set both public URLs to
|
|
`https://fleetops.itworx.tech`, set `SESSION_COOKIE_SECURE=true`, and configure
|
|
`KNOWLEDGE_PROVIDER=ragcore` only after the RAGcore health and source inventory checks pass.
|
|
The internal `1236` listener is
|
|
an upstream for the TLS proxy, not a user-facing URL.
|
|
|
|
When RAGcore runs as a separate Compose project on the same host, keep its HTTP listener
|
|
private and configure Fleet Ops through the existing shared Docker network, for example:
|
|
|
|
```dotenv
|
|
RAGCORE_BASE_URL=http://ragcore-app:8080
|
|
RAGCORE_DOCKER_NETWORK=ragcore-proxy
|
|
```
|
|
|
|
The release deployer validates the network, attaches only the API replicas and takes the
|
|
non-secret RAGcore URL from the server `.env` on every promotion. Tokens and the remaining
|
|
resolved API environment continue to be inherited without being printed.
|
|
|
|
```bash
|
|
cd /mnt/user/appdata/mobilityops
|
|
./deploy/unraid/configure-env.sh \
|
|
https://fleetops.itworx.tech \
|
|
https://n8n.itworx.tech/webhook/mobilityops-return
|
|
git archive --format=tar.gz -o /tmp/mobilityops-source.tar.gz HEAD
|
|
sha256sum /tmp/mobilityops-source.tar.gz
|
|
# Copy the archive and run deploy-release.sh with its SHA-256 and full Git SHA.
|
|
```
|
|
|
|
`deploy-release.sh` stages a clean, commit-named release, builds OCI-labelled immutable
|
|
API/web images, starts two candidate replicas per stateless service behind a stable gateway,
|
|
and removes the previous replicas only after public readiness passes. It promotes without a
|
|
seed/reset and leaves the database, backups and monitoring untouched during routine app
|
|
releases. Run `python -m app.cli seed --reset` only for initial setup or
|
|
an explicit synthetic-demo reset; it is never part of a routine deployment.
|
|
|
|
Refresh the pinned stateful and monitoring containers explicitly after reviewing their
|
|
version/configuration changes:
|
|
|
|
```bash
|
|
./deploy/unraid/refresh-infrastructure.sh
|
|
```
|
|
|
|
Migrations run automatically in the API entrypoint. Import and publish the MobilityOps
|
|
workflow into the existing n8n container:
|
|
|
|
```bash
|
|
./deploy/unraid/setup-existing-n8n.sh \
|
|
n8n \
|
|
https://fleetops.itworx.tech/api/v1/integrations/n8n/return-callback
|
|
```
|
|
|
|
The callback token remains server-side and is never written to the repository. The
|
|
bundled n8n service is retained only as a standalone fallback behind the explicit
|
|
`bundled-n8n` Compose profile; it is not started in this deployment.
|
|
|
|
## Operate
|
|
|
|
```bash
|
|
cd /mnt/user/appdata/mobilityops
|
|
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml ps
|
|
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml logs --tail=200
|
|
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec api alembic current
|
|
docker logs --tail=200 n8n
|
|
```
|
|
|
|
## Backup and restore
|
|
|
|
The `backup` service creates a backup immediately and then every 24 hours. Every dump is
|
|
checked by SHA-256 and `pg_restore --list`; at least weekly the newest dump is also restored
|
|
into a disposable database and its migration revision and core table counts are verified.
|
|
Backups are retained for 30 days with at least seven copies protected from pruning. Its
|
|
healthcheck becomes unhealthy when the daily backup or eight-day restore-drill SLA is missed.
|
|
|
|
For this synthetic demo, OneDrive is the supported real off-site target. The optional worker
|
|
uploads the newest locally verified dump and checksum, downloads both again, verifies the
|
|
round trip, and performs a weekly restore into a disposable database. Its OAuth token remains
|
|
in the untracked mode-0600 rclone configuration directory. Configure it once from an
|
|
interactive server terminal (Microsoft browser authorization is required):
|
|
|
|
```bash
|
|
./deploy/unraid/configure-onedrive-backup.sh onedrive
|
|
docker inspect --format '{{.State.Health.Status}}' mobilityops-offsite-backup-1
|
|
```
|
|
|
|
Set `RCLONE_ONEDRIVE_PATH` to change the default `FleetOps/backups` folder. Do not set
|
|
`BACKUP_SECONDARY_DESTINATION` to another path on the same server and call that off-site;
|
|
that legacy mount remains available only for an independently mounted filesystem.
|
|
|
|
Create an additional on-demand backup, verify the newest backup, or execute the isolated
|
|
restore drill:
|
|
|
|
```bash
|
|
./deploy/unraid/backup-postgres.sh
|
|
./deploy/unraid/verify-postgres-backups.sh
|
|
docker compose -p mobilityops -f compose.yaml -f compose.unraid.yaml exec -T backup \
|
|
/opt/mobilityops/restore-drill-postgres.sh /backups/<backup>.dump
|
|
```
|
|
|
|
A restore is deliberately guarded and creates an additional safety backup before
|
|
replacing the database:
|
|
|
|
```bash
|
|
./deploy/unraid/restore-postgres.sh \
|
|
backups/postgres/mobilityops-YYYYMMDDTHHMMSSZ.dump \
|
|
RESTORE-MOBILITYOPS
|
|
```
|
|
|
|
The restore stops the API, recreates only the configured MobilityOps database, restarts
|
|
API/web and verifies the active Alembic revision. Test restores in a disposable environment
|
|
before using a production backup for incident recovery.
|