mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-08-04 18:00:30 +00:00
Closes #1561. Follow-up to #1551. ## Why #1551 added `Cache-Control: no-store` to all `/api/*` responses. That's sufficient for CDNs that honour origin headers (Varnish, nginx). It is **not** sufficient for Cloudflare zones where Cache Rules / Page Rules override origin Cache-Control. Field evidence from the meshat.se diagnosis (2026-06-04): observers behind Cloudflare were returning `cf-cache-status: HIT` with `age` up to ~6 hours despite the origin emitting `no-store`. The CDN was caching per zone policy and ignoring the upstream directive — exactly the failure mode #1551 cannot reach. The application has no way to inject CDN rules; the only durable fix is operator-side. This PR makes that operator step discoverable and verifiable. ## What ### Server-side detection (log-only) `cmd/server/cdn_detection.go` adds a middleware wired into the `/api/*` chain after `noStoreAPIMiddleware`. On the **first** request bearing any CDN-typical header (`CF-Connecting-IP`, `CF-Ray`, `X-Forwarded-For`, `X-Real-IP`, `Fastly-Client-IP`, `True-Client-IP`) it logs: ``` [security] WARNING: detected request via CDN (CF-Ray header present). Ensure /api/* is bypassed in your CDN config — see docs/deployment-behind-cdn.md. Cached API responses cause observer-flap and incorrect dashboards. ``` `sync.Once` guarantees the warning fires at most once per process boot. The middleware never blocks, never modifies the response, never adds headers. Detection is observational only — operators who run behind a CDN without bypass have a real bug; the warning is appropriate. ### Operator documentation `docs/deployment.md` gains a new **"Behind a CDN (Cloudflare, Fastly)"** section covering: 1. Curl verification command + healthy vs unhealthy output examples 2. Cloudflare Cache Rule creation (URI Path starts-with `/api/` → Bypass cache) 3. Legacy Page Rules equivalent 4. Fastly note 5. Re-verification 6. Meaning of the startup log warning 7. Why we can't fix this server-side `docs/deployment-behind-cdn.md` is the canonical path the log message references — it's a short TL;DR that links back to the full section. ### Healthcheck script `scripts/check-cdn-bypass.sh` — POSIX sh, no dependencies beyond curl + grep + awk. Operators run: ```sh scripts/check-cdn-bypass.sh https://your-domain.example.com ``` Exits `0` with `OK: no CDN caching detected ...` or `1` with a precise diagnostic naming the offending header (`cf-cache-status: HIT` or stale `age`). ## TDD - **Red commit `e90ccaba`** (`test(security): RED ...`) — `cmd/server/cdn_detection_test.go` (4 Go tests + 6 subtests for each header) and `scripts/test-check-cdn-bypass.sh` (3 shell harness cases). Middleware stub returns `next` unchanged so tests compile and fail on assertions, not build errors. - **Green commit `5e6a60b5`** (`feat(security): GREEN ...`) — real middleware, wiring in `routes.go`, healthcheck script, doc. ## Deliverables | File | Status | Purpose | |------|--------|---------| | `cmd/server/cdn_detection.go` | new | middleware + sync.Once warning | | `cmd/server/cdn_detection_test.go` | new | 4 Go tests (1 stand-alone + 1 silence + 1 once + 1 table-driven over 6 headers) | | `cmd/server/routes.go` | modified | `r.Use(cdnDetectionMiddleware)` after no-store | | `docs/deployment.md` | modified | TOC entry + "Behind a CDN" section | | `docs/deployment-behind-cdn.md` | new | canonical path referenced by log message + script output | | `scripts/check-cdn-bypass.sh` | new | operator-runnable healthcheck | | `scripts/test-check-cdn-bypass.sh` | new | shell harness with fake curl | ## What this PR explicitly does NOT do - Does not block requests based on CDN detection (log-only). - Does not enforce CDN bypass (impossible — operator-controlled). - Does not spoof, strip or modify CDN headers. - Does not add CSP / HSTS / other security headers (out of scope). - Warning is not configurable — operators behind a CDN without bypass have a real bug, surfacing it is correct. ## Verification - `go test ./...` in `cmd/server/` — full suite green. - `sh scripts/test-check-cdn-bypass.sh` — 3/3 pass. - Preflight checklist — all 11 gates clean (PII, branch scope, red commit, CSS vars, CSS self-fallback, LIKE-on-JSON, sync migration, async-migration annotation, XSS sinks, img/SVG ratio, themed-img/SVG, fixture coverage). --------- Co-authored-by: openclaw-bot <bot@openclaw.local> Co-authored-by: clawbot <bot@clawbot.invalid>
601 lines
16 KiB
Markdown
601 lines
16 KiB
Markdown
# CoreScope Deployment Guide
|
|
|
|
Comprehensive guide to deploying and operating CoreScope. For a quick start, see [DEPLOY.md](../DEPLOY.md).
|
|
|
|
## Table of Contents
|
|
|
|
- [System Requirements](#system-requirements)
|
|
- [Docker Deployment](#docker-deployment)
|
|
- [Configuration Reference](#configuration-reference)
|
|
- [MQTT Setup](#mqtt-setup)
|
|
- [TLS / HTTPS](#tls--https)
|
|
- [Behind a CDN (Cloudflare, Fastly)](#behind-a-cdn-cloudflare-fastly)
|
|
- [Monitoring & Health Checks](#monitoring--health-checks)
|
|
- [Backup & Restore](#backup--restore)
|
|
- [Troubleshooting](#troubleshooting)
|
|
|
|
---
|
|
|
|
## System Requirements
|
|
|
|
| Resource | Minimum | Recommended |
|
|
|----------|---------|-------------|
|
|
| RAM | 256 MB | 512 MB+ |
|
|
| Disk | 500 MB (image + DB) | 2 GB+ for long-term data |
|
|
| CPU | 1 core | 2+ cores |
|
|
| Architecture | `linux/amd64`, `linux/arm64` | — |
|
|
| Docker | 20.10+ | Latest stable |
|
|
|
|
CoreScope runs well on Raspberry Pi 4/5 (ARM64). The Go server uses ~300 MB RAM for 56K+ packets.
|
|
|
|
---
|
|
|
|
## Docker Deployment
|
|
|
|
### Quick Start (one command)
|
|
|
|
```bash
|
|
docker run -d --name corescope \
|
|
-p 80:80 \
|
|
-v corescope-data:/app/data \
|
|
ghcr.io/kpa-clawbot/corescope:latest
|
|
```
|
|
|
|
Open `http://localhost` — you'll see an empty dashboard ready to receive packets.
|
|
|
|
No `config.json` is required. The server starts with sensible defaults:
|
|
- HTTP on port 3000 (Caddy proxies port 80 → 3000 internally)
|
|
- Internal Mosquitto MQTT broker on port 1883
|
|
- Ingestor connects to `mqtt://localhost:1883` automatically
|
|
- SQLite database at `/app/data/meshcore.db`
|
|
|
|
### Full `docker run` Reference (recommended)
|
|
|
|
The bare `docker run` command is the primary deployment method. One image, documented parameters — run it however you want.
|
|
|
|
```bash
|
|
docker run -d --name corescope \
|
|
--restart=unless-stopped \
|
|
-p 80:80 -p 443:443 -p 1883:1883 \
|
|
-e DISABLE_MOSQUITTO=false \
|
|
-e DISABLE_CADDY=false \
|
|
-v /your/data:/app/data \
|
|
-v /your/Caddyfile:/etc/caddy/Caddyfile:ro \
|
|
-v /your/caddy-data:/data/caddy \
|
|
ghcr.io/kpa-clawbot/corescope:latest
|
|
```
|
|
|
|
#### Parameters
|
|
|
|
| Parameter | Required | Description |
|
|
|-----------|----------|-------------|
|
|
| `-p 80:80` | Yes | HTTP web UI |
|
|
| `-p 443:443` | No | HTTPS (only if using built-in Caddy with a domain) |
|
|
| `-p 1883:1883` | No | MQTT broker (expose if external gateways connect directly) |
|
|
| `-v /your/data:/app/data` | Yes | Persistent data: SQLite DB, config.json, theme.json |
|
|
| `-v /your/Caddyfile:/etc/caddy/Caddyfile:ro` | No | Custom Caddyfile for HTTPS |
|
|
| `-v /your/caddy-data:/data/caddy` | No | Caddy TLS certificate storage |
|
|
| `-e DISABLE_MOSQUITTO=true` | No | Skip the internal Mosquitto broker (use your own) |
|
|
| `-e DISABLE_CADDY=true` | No | Skip the built-in Caddy reverse proxy |
|
|
| `-e MQTT_BROKER=mqtt://host:1883` | No | Override MQTT broker URL |
|
|
|
|
#### `/app/data/.env` convenience file
|
|
|
|
Instead of passing `-e` flags, you can drop a `.env` file in your data volume:
|
|
|
|
```bash
|
|
# /your/data/.env
|
|
DISABLE_MOSQUITTO=true
|
|
DISABLE_CADDY=true
|
|
MQTT_BROKER=mqtt://my-broker:1883
|
|
```
|
|
|
|
The entrypoint sources this file before starting services. This works with any launch method (`docker run`, compose, or manage.sh).
|
|
|
|
### Docker Compose (legacy alternative)
|
|
|
|
Docker Compose files are maintained for backward compatibility but are no longer the recommended approach.
|
|
|
|
```bash
|
|
curl -sL https://raw.githubusercontent.com/Kpa-clawbot/CoreScope/master/docker-compose.example.yml \
|
|
-o docker-compose.yml
|
|
docker compose up -d
|
|
```
|
|
|
|
#### Compose environment variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `HTTP_PORT` | `80` | Host port for the web UI |
|
|
| `DATA_DIR` | `./data` | Host path for persistent data |
|
|
| `DISABLE_MOSQUITTO` | `false` | Set `true` to use an external MQTT broker |
|
|
| `DISABLE_CADDY` | `false` | Set `true` to skip the built-in Caddy proxy |
|
|
|
|
### manage.sh (legacy alternative)
|
|
|
|
The `manage.sh` wrapper script provides a setup wizard and convenience commands. It uses Docker Compose internally. See [DEPLOY.md](../DEPLOY.md) for usage. New deployments should prefer bare `docker run`.
|
|
|
|
### Image tags
|
|
|
|
| Tag | Use case |
|
|
|-----|----------|
|
|
| `v3.4.1` | Pinned release — recommended for production |
|
|
| `v3.4` | Latest patch in the v3.4.x series |
|
|
| `v3` | Latest minor+patch in v3.x |
|
|
| `latest` | Latest release tag |
|
|
| `edge` | Built from master on every push — unstable |
|
|
|
|
### Updating
|
|
|
|
```bash
|
|
docker compose pull
|
|
docker compose up -d
|
|
```
|
|
|
|
For `docker run` users:
|
|
|
|
```bash
|
|
docker pull ghcr.io/kpa-clawbot/corescope:latest
|
|
docker stop corescope && docker rm corescope
|
|
docker run -d --name corescope ... # same flags as before
|
|
```
|
|
|
|
Data is preserved in the volume — updates are non-destructive.
|
|
|
|
---
|
|
|
|
## Configuration Reference
|
|
|
|
CoreScope uses a layered configuration system (highest priority wins):
|
|
|
|
1. **Environment variables** — `MQTT_BROKER`, `DB_PATH`, etc.
|
|
2. **`/app/data/config.json`** — full config file (volume-mounted)
|
|
3. **Built-in defaults** — work out of the box with no config
|
|
|
|
### Environment variable overrides
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `MQTT_BROKER` | `mqtt://localhost:1883` | MQTT broker URL (overrides config file) |
|
|
| `MQTT_TOPIC` | `meshcore/#` | MQTT topic subscription pattern |
|
|
| `DB_PATH` | `data/meshcore.db` | SQLite database path |
|
|
| `DISABLE_MOSQUITTO` | `false` | Skip the internal Mosquitto broker |
|
|
| `DISABLE_CADDY` | `false` | Skip the built-in Caddy reverse proxy |
|
|
|
|
### config.json
|
|
|
|
For advanced configuration, create a `config.json` and mount it at `/app/data/config.json`:
|
|
|
|
```bash
|
|
docker run -d --name corescope \
|
|
-p 80:80 \
|
|
-v corescope-data:/app/data \
|
|
-v ./config.json:/app/data/config.json:ro \
|
|
ghcr.io/kpa-clawbot/corescope:latest
|
|
```
|
|
|
|
See `config.example.json` in the repository for all available options including:
|
|
- MQTT sources (multiple brokers)
|
|
- Channel encryption keys
|
|
- Branding and theming
|
|
- Health thresholds
|
|
- Region filters
|
|
- Retention policies
|
|
- Geo-filtering
|
|
|
|
---
|
|
|
|
## MQTT Setup
|
|
|
|
CoreScope receives MeshCore packets via MQTT. The container ships with an internal Mosquitto broker — no setup needed for basic use.
|
|
|
|
### Internal broker (default)
|
|
|
|
The built-in Mosquitto broker listens on port 1883 inside the container. Point your MeshCore gateways at it:
|
|
|
|
```bash
|
|
# Expose MQTT port for external gateways
|
|
docker run -d --name corescope \
|
|
-p 80:80 -p 1883:1883 \
|
|
-v corescope-data:/app/data \
|
|
ghcr.io/kpa-clawbot/corescope:latest
|
|
```
|
|
|
|
### External broker
|
|
|
|
To use your own MQTT broker (Mosquitto, EMQX, HiveMQ, etc.):
|
|
|
|
1. Disable the internal broker:
|
|
```bash
|
|
-e DISABLE_MOSQUITTO=true
|
|
```
|
|
|
|
2. Point the ingestor at your broker:
|
|
```bash
|
|
-e MQTT_BROKER=mqtt://your-broker:1883
|
|
```
|
|
|
|
Or via `config.json`:
|
|
```json
|
|
{
|
|
"mqttSources": [
|
|
{
|
|
"name": "my-broker",
|
|
"broker": "mqtt://your-broker:1883",
|
|
"username": "user",
|
|
"password": "pass",
|
|
"topics": ["meshcore/#"]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Multiple brokers
|
|
|
|
CoreScope can connect to multiple MQTT brokers simultaneously:
|
|
|
|
```json
|
|
{
|
|
"mqttSources": [
|
|
{
|
|
"name": "local",
|
|
"broker": "mqtt://localhost:1883",
|
|
"topics": ["meshcore/#"]
|
|
},
|
|
{
|
|
"name": "remote",
|
|
"broker": "mqtts://remote-broker:8883",
|
|
"username": "reader",
|
|
"password": "secret",
|
|
"topics": ["meshcore/+/+/packets"]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### MQTT topic format
|
|
|
|
MeshCore gateways typically publish to `meshcore/<gateway>/<region>/packets`. The default subscription `meshcore/#` catches all of them.
|
|
|
|
---
|
|
|
|
## TLS / HTTPS
|
|
|
|
### Option 1: External reverse proxy (recommended)
|
|
|
|
Run CoreScope behind nginx, Traefik, or Cloudflare Tunnel for TLS termination:
|
|
|
|
```nginx
|
|
# nginx example
|
|
server {
|
|
listen 443 ssl;
|
|
server_name corescope.example.com;
|
|
|
|
ssl_certificate /etc/ssl/certs/corescope.pem;
|
|
ssl_certificate_key /etc/ssl/private/corescope.key;
|
|
|
|
location / {
|
|
proxy_pass http://localhost:80;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_set_header Host $host;
|
|
}
|
|
}
|
|
```
|
|
|
|
The `Upgrade` and `Connection` headers are required for WebSocket support.
|
|
|
|
### Option 2: Built-in Caddy (auto-TLS)
|
|
|
|
The container includes Caddy for automatic Let's Encrypt certificates:
|
|
|
|
1. Create a Caddyfile:
|
|
```
|
|
corescope.example.com {
|
|
reverse_proxy localhost:3000
|
|
}
|
|
```
|
|
|
|
2. Mount it and expose TLS ports:
|
|
```bash
|
|
docker run -d --name corescope \
|
|
-p 80:80 -p 443:443 \
|
|
-v corescope-data:/app/data \
|
|
-v caddy-certs:/data/caddy \
|
|
-v ./Caddyfile:/etc/caddy/Caddyfile:ro \
|
|
ghcr.io/kpa-clawbot/corescope:latest
|
|
```
|
|
|
|
Caddy handles certificate issuance and renewal automatically.
|
|
|
|
---
|
|
|
|
## API Documentation
|
|
|
|
CoreScope auto-generates an OpenAPI 3.0 specification from its route definitions. The spec is always in sync with the running server — no manual maintenance required.
|
|
|
|
### Endpoints
|
|
|
|
| URL | Description |
|
|
|-----|-------------|
|
|
| `/api/spec` | OpenAPI 3.0 JSON schema — machine-readable API definition |
|
|
| `/api/docs` | Interactive Swagger UI — browse and test all 40+ endpoints |
|
|
|
|
### Usage
|
|
|
|
**Browse the API interactively:**
|
|
```
|
|
http://your-instance/api/docs
|
|
```
|
|
|
|
**Fetch the spec programmatically:**
|
|
```bash
|
|
curl http://your-instance/api/spec | jq .
|
|
```
|
|
|
|
**For bot/integration developers:** The spec includes all request parameters, response schemas, and example values. Import it into Postman, Insomnia, or any OpenAPI-compatible tool.
|
|
|
|
### Public instance
|
|
The live instance at [analyzer.00id.net](https://analyzer.00id.net) has all API endpoints publicly accessible:
|
|
- Spec: [analyzer.00id.net/api/spec](https://analyzer.00id.net/api/spec)
|
|
- Docs: [analyzer.00id.net/api/docs](https://analyzer.00id.net/api/docs)
|
|
|
|
---
|
|
|
|
## Behind a CDN (Cloudflare, Fastly)
|
|
|
|
If you front CoreScope with a CDN — Cloudflare, Fastly, Akamai, or
|
|
similar — you **must** configure the CDN to bypass cache for `/api/*`.
|
|
The server emits `Cache-Control: no-store` on every API response
|
|
(see #1551), but Cloudflare's zone-level Cache Rules and legacy Page
|
|
Rules can override origin headers. When that happens, observers, packets,
|
|
stats and other API responses get cached at the edge for minutes to hours,
|
|
producing observer-flap, stale dashboards and inconsistent state across
|
|
viewers.
|
|
|
|
### 1. Verify whether your CDN is caching `/api/*`
|
|
|
|
From **outside** the CDN (a different network than your origin), run:
|
|
|
|
```sh
|
|
curl -sI 'https://<your-domain>/api/observers' | grep -iE 'cf-cache|age|cache-control'
|
|
```
|
|
|
|
Healthy output (cache is bypassed):
|
|
|
|
```
|
|
cache-control: no-store
|
|
cf-cache-status: BYPASS
|
|
age: 0
|
|
```
|
|
|
|
Unhealthy output (CDN is caching despite `no-store`):
|
|
|
|
```
|
|
cache-control: no-store
|
|
cf-cache-status: HIT
|
|
age: 4732
|
|
```
|
|
|
|
`HIT` or `age > 0` means an intermediary is serving cached JSON. Fix it
|
|
before relying on the dashboard.
|
|
|
|
You can also run the bundled helper, which exits non-zero with a precise
|
|
diagnostic when caching is detected:
|
|
|
|
```sh
|
|
scripts/check-cdn-bypass.sh https://<your-domain>
|
|
```
|
|
|
|
### 2. Cloudflare: add a Cache Rule (recommended)
|
|
|
|
Cloudflare Dashboard → your zone → **Caching → Cache Rules → Create rule**:
|
|
|
|
- **When incoming requests match:** Field = `URI Path`, Operator = `starts with`, Value = `/api/`
|
|
- **Then:** Cache eligibility → **Bypass cache**
|
|
|
|
Save and deploy. Re-run the curl above; you should now see
|
|
`cf-cache-status: BYPASS`.
|
|
|
|
Legacy Page Rules equivalent (if your zone has no Cache Rules):
|
|
|
|
- URL pattern: `*your-domain*/api/*`
|
|
- Setting: **Cache Level → Bypass**
|
|
|
|
### 3. Fastly / other CDNs
|
|
|
|
Apply the equivalent bypass-cache rule for the `/api/` path prefix.
|
|
The key invariant is: any response from `/api/*` must reach the
|
|
browser uncached (no shared-cache HIT, no positive `Age` header).
|
|
|
|
### 4. Re-verify
|
|
|
|
After applying the rule, run step 1's curl from outside the CDN again
|
|
and confirm `cf-cache-status: BYPASS` (or absence of HIT) and `age: 0`.
|
|
|
|
### 5. Watch the server log
|
|
|
|
The server logs a one-shot warning at the first request bearing a
|
|
CDN-specific header (`CF-Connecting-IP`, `CF-Ray`, `Fastly-Client-IP`,
|
|
or `True-Client-IP`):
|
|
|
|
Generic reverse-proxy headers (`X-Forwarded-For`, `X-Real-IP`) are
|
|
deliberately NOT used as the signal — every nginx/Caddy/Traefik/k8s
|
|
deploy sets them, so they'd produce false positives on every
|
|
reverse-proxied install.
|
|
|
|
```
|
|
[security] WARNING: detected request via CDN (CF-Ray header present).
|
|
Ensure /api/* is bypassed in your CDN config — see docs/deployment-behind-cdn.md.
|
|
Cached API responses cause observer-flap and incorrect dashboards.
|
|
```
|
|
|
|
This is informational — the request is not blocked. Treat it as a
|
|
prompt to run the verification curl above. The warning logs at most
|
|
once per process boot, regardless of how many CDN-fronted requests
|
|
arrive.
|
|
|
|
### Why this can't be fixed server-side
|
|
|
|
CDN cache policy is operator-controlled. The application emits the
|
|
most conservative cache header it can (`Cache-Control: no-store`),
|
|
but Cloudflare Cache Rules / Page Rules have higher precedence than
|
|
origin headers in many zone configurations. The only durable fix is
|
|
the operator-side bypass rule.
|
|
|
|
---
|
|
|
|
## Monitoring & Health Checks
|
|
|
|
### Docker health check
|
|
|
|
The container includes a built-in health check that hits `/api/stats`:
|
|
|
|
```bash
|
|
docker inspect --format='{{.State.Health.Status}}' corescope
|
|
```
|
|
|
|
Docker reports `healthy` or `unhealthy` automatically. The check runs every 30 seconds.
|
|
|
|
### Manual health check
|
|
|
|
```bash
|
|
curl -f http://localhost/api/stats
|
|
```
|
|
|
|
Returns JSON with packet counts, node counts, and version info:
|
|
|
|
```json
|
|
{
|
|
"totalPackets": 56234,
|
|
"totalNodes": 142,
|
|
"totalObservers": 12,
|
|
"packetsLastHour": 830,
|
|
"packetsLast24h": 19644,
|
|
"engine": "go",
|
|
"version": "v3.4.1"
|
|
}
|
|
```
|
|
|
|
### Log monitoring
|
|
|
|
```bash
|
|
# All logs
|
|
docker compose logs -f
|
|
|
|
# Server only
|
|
docker compose logs -f | grep '\[server\]'
|
|
|
|
# Ingestor only
|
|
docker compose logs -f | grep '\[ingestor\]'
|
|
```
|
|
|
|
### Resource monitoring
|
|
|
|
```bash
|
|
docker stats corescope
|
|
```
|
|
|
|
---
|
|
|
|
## Backup & Restore
|
|
|
|
### Backup
|
|
|
|
All persistent data lives in `/app/data`. The critical file is the SQLite database:
|
|
|
|
```bash
|
|
# Copy from the Docker volume
|
|
docker cp corescope:/app/data/meshcore.db ./backup-$(date +%Y%m%d).db
|
|
|
|
# Or if using a bind mount
|
|
cp ./data/meshcore.db ./backup-$(date +%Y%m%d).db
|
|
```
|
|
|
|
Optional files to back up:
|
|
- `config.json` — custom configuration
|
|
- `theme.json` — custom theme/branding
|
|
|
|
### Restore
|
|
|
|
```bash
|
|
# Stop the container
|
|
docker stop corescope
|
|
|
|
# Replace the database
|
|
docker cp ./backup.db corescope:/app/data/meshcore.db
|
|
|
|
# Restart
|
|
docker start corescope
|
|
```
|
|
|
|
### Automated backups
|
|
|
|
```bash
|
|
# cron: daily backup at 3 AM, keep 7 days
|
|
0 3 * * * docker cp corescope:/app/data/meshcore.db /backups/corescope-$(date +\%Y\%m\%d).db && find /backups -name "corescope-*.db" -mtime +7 -delete
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Container starts but dashboard is empty
|
|
|
|
This is normal on first start with no MQTT sources configured. The dashboard shows data once packets arrive via MQTT. Either:
|
|
- Point a MeshCore gateway at the container's MQTT broker (port 1883)
|
|
- Configure an external MQTT source in `config.json`
|
|
|
|
### "no MQTT connections established" in logs
|
|
|
|
The ingestor couldn't connect to any MQTT broker. Check:
|
|
1. Is the internal Mosquitto running? (`DISABLE_MOSQUITTO` should be `false`)
|
|
2. Is the external broker reachable? Test with `mosquitto_sub -h broker -t meshcore/#`
|
|
3. Are credentials correct in `config.json`?
|
|
|
|
### WebSocket disconnects / real-time updates stop
|
|
|
|
If behind a reverse proxy, ensure WebSocket upgrade headers are forwarded:
|
|
```nginx
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
```
|
|
|
|
Also check proxy timeouts — set them to at least 300s for long-lived WebSocket connections.
|
|
|
|
### High memory usage
|
|
|
|
The in-memory packet store grows with retained packets. Configure retention limits in `config.json`:
|
|
|
|
```json
|
|
{
|
|
"packetStore": {
|
|
"retentionHours": 24,
|
|
"maxMemoryMB": 512
|
|
},
|
|
"retention": {
|
|
"nodeDays": 7,
|
|
"packetDays": 30
|
|
}
|
|
}
|
|
```
|
|
|
|
### Database locked errors
|
|
|
|
SQLite doesn't support concurrent writers well. Ensure only one CoreScope instance accesses the database file. If running multiple containers, each needs its own database.
|
|
|
|
### Container unhealthy
|
|
|
|
Check logs: `docker compose logs --tail 50`. Common causes:
|
|
- Port 3000 already in use inside the container
|
|
- Database file permissions (must be writable by the container user)
|
|
- Corrupted database — restore from backup
|
|
|
|
### ARM / Raspberry Pi issues
|
|
|
|
- Use `linux/arm64` images (Pi 4 and 5). Pi 3 (armv7) is not supported.
|
|
- First pull may be slow — the multi-arch manifest selects the right image automatically.
|
|
- If memory is tight, set `packetStore.maxMemoryMB` to limit RAM usage.
|