update main to v0.10.0 #48
@@ -0,0 +1,436 @@
|
||||
# Synology NAS Deployment Guide
|
||||
|
||||
This guide covers migrating the terra-view stack from a generic Linux host
|
||||
(currently the home server at `10.0.0.44`) to an always-on Synology NAS in
|
||||
the office, including data migration and the minimal external-access
|
||||
networking layer.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Architecture overview](#architecture-overview)
|
||||
2. [Pre-requisites](#pre-requisites)
|
||||
3. [Phase 1 — Pre-stage on the NAS (no downtime)](#phase-1--pre-stage-on-the-nas-no-downtime)
|
||||
4. [Phase 2 — Data migration (~10 min window)](#phase-2--data-migration-10-min-window)
|
||||
5. [Phase 3 — Repoint the watcher (download2-PC)](#phase-3--repoint-the-watcher-download2-pc)
|
||||
6. [Phase 4 — External access for remote operators](#phase-4--external-access-for-remote-operators)
|
||||
7. [Phase 5 — Decommission home server](#phase-5--decommission-home-server)
|
||||
8. [Verification checklist](#verification-checklist)
|
||||
9. [Rollback plan](#rollback-plan)
|
||||
10. [Gotchas](#gotchas)
|
||||
|
||||
---
|
||||
|
||||
## Architecture overview
|
||||
|
||||
The terra-view stack is three containers:
|
||||
|
||||
| Service | Port | What writes to it | Where it lives |
|
||||
|---------------|-------|-----------------------------|----------------|
|
||||
| terra-view | 8001 | Operators (UI), watchers (heartbeat) | Synology NAS |
|
||||
| SFM | 8200 | Watchers (Blastware ACH forwards) | Synology NAS |
|
||||
| SLMM | 8100 | terra-view (proxied), SLMs on LAN | Synology NAS |
|
||||
|
||||
Everything that **writes** to the stack lives inside the office LAN:
|
||||
|
||||
- **download2-PC** is the series3-watcher host. It has a static office IP and
|
||||
POSTs to terra-view's heartbeat endpoint plus SFM's Blastware import
|
||||
endpoint. Both flows are LAN-internal.
|
||||
- **Sound level meters (NL-43)** sit on the office LAN; SLMM reaches them
|
||||
via `network_mode: host`.
|
||||
|
||||
The **only** thing that needs to cross the office firewall is operator UI
|
||||
access from outside the office (laptops, phones, working from home). That
|
||||
makes the external networking layer trivial — see Phase 4.
|
||||
|
||||
---
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
On the Synology side:
|
||||
|
||||
- **DSM 7.2+** with **Container Manager** installed (Package Center).
|
||||
Older "Docker" package works too — same engine, different menu names.
|
||||
- **x86_64 model** (Plus / Value / XS series). ARM j-series will build but
|
||||
expect a slower first build.
|
||||
- **Static LAN IP** reserved for the NAS in the office router's DHCP table.
|
||||
Devices on the LAN must have a stable target.
|
||||
- **SSH enabled** — Control Panel → Terminal & SNMP → Enable SSH service.
|
||||
- **Shared folder** for the stack — e.g. `/volume1/docker/`.
|
||||
|
||||
On the home server side:
|
||||
|
||||
- Working terra-view / SFM / SLMM stack you want to migrate.
|
||||
- `rsync` available (it almost certainly is).
|
||||
|
||||
You will also need:
|
||||
|
||||
- An admin account on the Synology with sudo privileges.
|
||||
- Network access between the home server and the NAS during the migration
|
||||
window (or USB-drive shuttle if not).
|
||||
|
||||
---
|
||||
|
||||
## Phase 1 — Pre-stage on the NAS (no downtime)
|
||||
|
||||
Goal: get the NAS booting an empty stack so you can validate the build and
|
||||
networking *before* touching any production data.
|
||||
|
||||
### 1.1 Clone the repos
|
||||
|
||||
SSH to the NAS as admin:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /volume1/docker
|
||||
cd /volume1/docker
|
||||
sudo git clone <your-terra-view-remote> terra-view
|
||||
sudo git clone <your-slmm-remote> slmm
|
||||
sudo git clone <your-seismo-relay-remote> seismo-relay
|
||||
cd terra-view
|
||||
sudo git checkout main # or whichever branch you ship from
|
||||
```
|
||||
|
||||
### 1.2 Build images
|
||||
|
||||
```bash
|
||||
cd /volume1/docker/terra-view
|
||||
sudo docker compose build
|
||||
```
|
||||
|
||||
First build takes 5–15 min depending on model.
|
||||
|
||||
### 1.3 Boot the empty stack
|
||||
|
||||
```bash
|
||||
sudo docker compose up -d
|
||||
```
|
||||
|
||||
Hit `http://<nas-lan-ip>:1001` (dev profile) or `:8001` (prod profile) from
|
||||
another office machine. You should see an empty fleet roster. If that
|
||||
works, the NAS can run the stack — proven before any production data is
|
||||
at risk.
|
||||
|
||||
### 1.4 Stop the NAS stack again
|
||||
|
||||
```bash
|
||||
sudo docker compose stop
|
||||
```
|
||||
|
||||
We're ready for the data migration.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Data migration (~10 min window)
|
||||
|
||||
The terra-view stack is stateful in three places. All three must be moved
|
||||
together for consistency.
|
||||
|
||||
| Service | Data location (home server) |
|
||||
|------------|----------------------------------------------|
|
||||
| terra-view | `/home/serversdown/terra-view/data/` |
|
||||
| SLMM | `/home/serversdown/slmm/data/` |
|
||||
| SFM | `/home/serversdown/seismo-relay/data/` |
|
||||
|
||||
### 2.1 Stop writes on both sides
|
||||
|
||||
On the NAS:
|
||||
|
||||
```bash
|
||||
cd /volume1/docker/terra-view
|
||||
sudo docker compose stop
|
||||
```
|
||||
|
||||
On the home server:
|
||||
|
||||
```bash
|
||||
cd /home/serversdown/terra-view
|
||||
docker compose stop terra-view slmm sfm
|
||||
```
|
||||
|
||||
### 2.2 rsync the data dirs
|
||||
|
||||
From the home server (or anywhere with SSH access to both):
|
||||
|
||||
```bash
|
||||
rsync -avh /home/serversdown/terra-view/data/ admin@<nas-lan-ip>:/volume1/docker/terra-view/data/
|
||||
rsync -avh /home/serversdown/slmm/data/ admin@<nas-lan-ip>:/volume1/docker/slmm/data/
|
||||
rsync -avh /home/serversdown/seismo-relay/data/ admin@<nas-lan-ip>:/volume1/docker/seismo-relay/data/
|
||||
```
|
||||
|
||||
### 2.3 Fix ownership on the NAS
|
||||
|
||||
Synology admin is usually UID `1026`, GID `100`. Inside containers running
|
||||
as root, this doesn't matter — but if you've configured `user:` in any
|
||||
compose file it will. Safe default:
|
||||
|
||||
```bash
|
||||
ssh admin@<nas-lan-ip> "sudo chown -R 1026:100 \
|
||||
/volume1/docker/terra-view/data \
|
||||
/volume1/docker/slmm/data \
|
||||
/volume1/docker/seismo-relay/data"
|
||||
```
|
||||
|
||||
### 2.4 Run any pending migrations
|
||||
|
||||
Some earlier feature work added migration scripts that need to run once
|
||||
per database. After the rsync, before starting the stack, check what's
|
||||
pending:
|
||||
|
||||
```bash
|
||||
ssh admin@<nas-lan-ip>
|
||||
cd /volume1/docker/terra-view
|
||||
ls backend/migrate_*.py
|
||||
```
|
||||
|
||||
Run each one inside the container (after starting it temporarily) or apply
|
||||
them on the host with the same Python environment. Idempotent migrations
|
||||
re-run safely.
|
||||
|
||||
### 2.5 Start the NAS stack
|
||||
|
||||
```bash
|
||||
ssh admin@<nas-lan-ip> \
|
||||
"cd /volume1/docker/terra-view && sudo docker compose up -d"
|
||||
```
|
||||
|
||||
### 2.6 Spot-check
|
||||
|
||||
- Dashboard loads with real units
|
||||
- `/sfm` page lists historical events
|
||||
- A photo loads on a unit detail page
|
||||
- SFM/HB badge mix on the active table matches what you saw on the home
|
||||
server
|
||||
|
||||
If anything's off, see [Rollback plan](#rollback-plan).
|
||||
|
||||
---
|
||||
|
||||
## Phase 3 — Repoint the watcher (download2-PC)
|
||||
|
||||
The download2-PC is the one client we have to reconfigure. It currently
|
||||
POSTs to the home server. Two endpoints to change:
|
||||
|
||||
1. **terra-view heartbeat URL** —
|
||||
`http://<old-home-ip>:8001/api/series3/heartbeat`
|
||||
→ `http://<new-nas-lan-ip>:8001/api/series3/heartbeat`
|
||||
|
||||
2. **SFM Blastware import URL** —
|
||||
`http://<old-home-ip>:8200/db/import/blastware_file`
|
||||
→ `http://<new-nas-lan-ip>:8200/db/import/blastware_file`
|
||||
|
||||
Or, if you want to keep SFM container-internal and not publish 8200 on
|
||||
the LAN at all, point it through terra-view's existing SFM proxy:
|
||||
→ `http://<new-nas-lan-ip>:8001/api/sfm/db/import/blastware_file`
|
||||
|
||||
Update the config, restart the watcher service, and confirm the next
|
||||
heartbeat lands in the NAS DB (check the Recent Call-Ins card on the
|
||||
dashboard).
|
||||
|
||||
> **Tip:** keep the home server running in parallel for 1–2 days. If you
|
||||
> forget to repoint something, it'll still flow into the old DB and you
|
||||
> can resync.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4 — External access for remote operators
|
||||
|
||||
Only the terra-view UI needs to be reachable from outside the office. Two
|
||||
clean options — pick one.
|
||||
|
||||
### Option A — Tailscale (recommended for small teams)
|
||||
|
||||
Zero port forwards, zero certs, zero public DNS, zero reverse proxy.
|
||||
|
||||
1. Install Tailscale from Synology Package Center, sign in.
|
||||
2. Install Tailscale on each operator's laptop/phone, sign in to the same
|
||||
tailnet.
|
||||
3. Operators access `http://<nas-tailscale-ip>:8001` from anywhere.
|
||||
|
||||
That's the whole setup. The office network has no external exposure at
|
||||
all.
|
||||
|
||||
### Option B — Reverse proxy with Let's Encrypt
|
||||
|
||||
If you want a `https://terraview.yourdomain.com` URL that any browser can
|
||||
reach:
|
||||
|
||||
#### B.1 Port forward on the office router
|
||||
|
||||
```
|
||||
WAN 443 → <nas-lan-ip>:443
|
||||
WAN 80 → <nas-lan-ip>:80 (only needed for Let's Encrypt HTTP-01;
|
||||
skip if you use DNS-01 challenge)
|
||||
```
|
||||
|
||||
Do **not** forward 1001, 8001, 8100, or 8200.
|
||||
|
||||
#### B.2 Public DNS
|
||||
|
||||
- Free: Synology DDNS (Control Panel → External Access → DDNS) — gives
|
||||
you `something.synology.me`.
|
||||
- Better: your own domain with an A record → office WAN IP, or a CNAME →
|
||||
Synology DDNS hostname (handles dynamic IPs automatically).
|
||||
|
||||
#### B.3 Let's Encrypt certificate
|
||||
|
||||
Control Panel → Security → Certificate → Add → "Get a certificate from
|
||||
Let's Encrypt." DSM handles renewal.
|
||||
|
||||
#### B.4 Synology reverse proxy
|
||||
|
||||
Control Panel → Login Portal → Advanced → Reverse Proxy → Create:
|
||||
|
||||
```
|
||||
Source: Hostname terraview.yourdomain.com
|
||||
Protocol HTTPS
|
||||
Port 443
|
||||
Destination: Hostname localhost
|
||||
Protocol HTTP
|
||||
Port 8001
|
||||
```
|
||||
|
||||
Under "Custom Header", add:
|
||||
|
||||
| Header | Value |
|
||||
|---------------------|------------------------------------|
|
||||
| `X-Forwarded-For` | `$proxy_add_x_forwarded_for` |
|
||||
| `X-Forwarded-Proto` | `$scheme` |
|
||||
| `Host` | `$host` |
|
||||
|
||||
Tick the WebSocket support checkbox.
|
||||
|
||||
#### B.5 DSM firewall
|
||||
|
||||
Control Panel → Security → Firewall → enable:
|
||||
|
||||
- 443/TCP from `Anywhere` — allow
|
||||
- 80/TCP from `Anywhere` — allow (cert renewal only)
|
||||
- Everything else from WAN — deny
|
||||
- All from LAN — allow
|
||||
|
||||
Optional: geo-block to your country if your operators are domestic only.
|
||||
Big reduction in scanning noise.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5 — Decommission home server
|
||||
|
||||
After 1–2 weeks of stable NAS operation:
|
||||
|
||||
1. Take a final `docker compose down` on the home server.
|
||||
2. Archive `/home/serversdown/{terra-view,slmm,seismo-relay}/data/` to a
|
||||
backup volume.
|
||||
3. Free the home server hardware.
|
||||
|
||||
---
|
||||
|
||||
## Verification checklist
|
||||
|
||||
After Phase 2 (data migration):
|
||||
|
||||
- [ ] `http://<nas-lan-ip>:8001/` loads dashboard with real units
|
||||
- [ ] Recent Alerts, Call-Ins (2 cols), Fleet Summary across the top
|
||||
- [ ] SFM/HB badge mix on the active table looks sane
|
||||
- [ ] `/sfm` page lists historical events (the same count as before)
|
||||
- [ ] A unit detail page loads with photos rendering
|
||||
- [ ] `/api/recent-event-callins` returns 200 with real data
|
||||
- [ ] `/api/status-snapshot` returns 200, `sfm_reachable: true`
|
||||
|
||||
After Phase 3 (watcher cutover):
|
||||
|
||||
- [ ] Next heartbeat from download2-PC lands in NAS DB
|
||||
- [ ] A new event arrives in `/sfm` page on the NAS within the next
|
||||
Blastware ACH cycle
|
||||
- [ ] No errors in `docker logs terra-view-terra-view-1`
|
||||
|
||||
After Phase 4 (external access):
|
||||
|
||||
- [ ] (Option A) Operator laptop on tailnet can reach
|
||||
`http://<nas-tailscale-ip>:8001`
|
||||
- [ ] (Option B) `https://terraview.yourdomain.com` resolves, cert is
|
||||
valid, dashboard loads
|
||||
- [ ] (Option B) Office DSM admin (5001) is **not** reachable from outside
|
||||
|
||||
---
|
||||
|
||||
## Rollback plan
|
||||
|
||||
The home server stays alive in parallel through Phases 2–3 as a safety
|
||||
net. If anything goes wrong on the NAS:
|
||||
|
||||
1. On the home server:
|
||||
```bash
|
||||
cd /home/serversdown/terra-view
|
||||
docker compose up -d
|
||||
```
|
||||
2. Point download2-PC back at the home server IP.
|
||||
3. NAS data isn't lost — it's just sitting idle. Investigate, fix, retry.
|
||||
|
||||
The "irreversible" point is when you decommission the home server in
|
||||
Phase 5. Until then, you can always fall back.
|
||||
|
||||
---
|
||||
|
||||
## Gotchas
|
||||
|
||||
1. **Synology UID/GID quirks.** Synology admin is usually `1026:100`.
|
||||
Containers running as root inside don't care, but if your compose
|
||||
files set `user:`, mismatched UIDs cause SQLite "readonly database"
|
||||
errors. Easiest fix: omit `user:` and let containers run as root.
|
||||
|
||||
2. **`network_mode: host` for SLMM.** Required for LAN-direct comms with
|
||||
sound level meters. On Synology this binds to the NAS's interface —
|
||||
confirm nothing else on the NAS uses ports 8100 or 21 (FTP).
|
||||
|
||||
3. **Auto-start on boot.** Container Manager → Project → Settings →
|
||||
enable "Auto-restart". Otherwise a DSM update or NAS reboot drops the
|
||||
stack.
|
||||
|
||||
4. **`restart: unless-stopped` in compose.** Verify every service has it.
|
||||
DSM occasionally restarts Docker during DSM updates — this flag
|
||||
ensures everything comes back.
|
||||
|
||||
5. **Hyper Backup.** Schedule a daily snapshot of
|
||||
`/volume1/docker/terra-view/data/` to a USB drive or off-site. SQLite
|
||||
+ small photo dir = trivially small backups. The DB-Management UI's
|
||||
built-in snapshots are an additional layer but not a replacement.
|
||||
|
||||
6. **NAT loopback (Option B only).** If your office router doesn't
|
||||
support hairpinning, machines INSIDE the office can't reach the NAS
|
||||
by its public hostname — they have to use the LAN IP. Most modern
|
||||
routers handle this; some ISP-provided ones don't. Test from a laptop
|
||||
on the office Wi-Fi.
|
||||
|
||||
7. **Let's Encrypt rate limits (Option B only).** 5 issuances per domain
|
||||
per week. Don't fat-finger DNS or you'll be locked out. Test with the
|
||||
staging endpoint first if unsure.
|
||||
|
||||
8. **`host.docker.internal` resolution.** terra-view's
|
||||
`SFM_BASE_URL=http://host.docker.internal:8200` relies on Docker's
|
||||
internal DNS. Works on DSM 7.2+ in bridge mode. If you see "name not
|
||||
resolved" errors, fall back to explicit container names with a custom
|
||||
network in compose.
|
||||
|
||||
9. **SFM stale rows.** The SFM SQLite has a few rows in `monitor_log`
|
||||
and `ach_sessions` from earlier Python-ACH experiments. Harmless
|
||||
to bring over — invisible to terra-view's UI under the
|
||||
watcher-forward pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Suggested timeline
|
||||
|
||||
For a low-risk migration:
|
||||
|
||||
- **Week 1**: Phase 1. Get the NAS booting an empty stack. No production
|
||||
touch.
|
||||
- **Week 2, day 1**: Phase 2. Migrate data. 10-min window. Keep home
|
||||
server alive in parallel.
|
||||
- **Week 2, day 1**: Phase 3. Repoint download2-PC. Watch heartbeats
|
||||
land on the NAS for the rest of the day.
|
||||
- **Week 3**: Phase 4. Add Tailscale or reverse-proxy access for remote
|
||||
operators.
|
||||
- **Week 4–5**: Monitor. Confirm everything's stable. Then Phase 5
|
||||
(decommission home server).
|
||||
|
||||
Splitting "make it work on LAN" from "expose it remotely" means you
|
||||
debug one thing at a time.
|
||||
Reference in New Issue
Block a user