Skip to content

Latest commit

 

History

History
336 lines (258 loc) · 11.6 KB

File metadata and controls

336 lines (258 loc) · 11.6 KB

TrailCurrent Deployment Guide

Overview

This document covers two scenarios:

  1. Updating an existing device with a new deployment package (the primary use case for this guide)
  2. Installing the CA certificate on client devices (phones, tablets, laptops)

For initial device setup (flashing a new CM5 and completing the captive-portal setup from a phone), see CM5/SETUP.md. The CM5 image includes all application code, Docker images, systemd units, and Python dependencies baked in — map data is not baked in; it's uploaded via the PWA Maps page after first boot (see DOCS/UpdatingMaps.md). No deployment package transfer is needed for a fresh device, and no SSH, keyboard, or monitor is required or supported for initial setup. The CM5 must be the WiFi variant.


Deployment Package

The deployment zip is used to update devices that already have a base image flashed and configured. It is created on your development machine:

./create-deployment-package.sh --version=1.0.0

This produces trailcurrent-deployment-1.0.0.zip containing:

  • images/*.tar — 6 pre-built ARM64 Docker images: frontend, backend, mosquitto (custom), mongodb, photon (geocoding), and valhalla (routing). Photon and Valhalla are behind the maps compose profile — they only start when a map bundle is installed.
  • docker-compose.yml — Service orchestration
  • config/ — Mosquitto configuration
  • local_code/ — Python bridges + watchers (CAN-to-MQTT, deployment watcher, map watcher)
  • firmware/wired/ — MCU firmware binaries (if available)
  • scripts/ — SSL certificate generation
  • .env.example — Environment variable template
  • deploy.sh — Deployment orchestrator
  • PI_DEPLOYMENT.md — This file

Note: build-and-save-images.sh must be run before creating a deployment package. It builds the ARM64 Docker images and saves them as tar files in images/. See README.md.


Initial Setup (Fresh Devices)

For devices flashed with the current CM5 image, no deployment package is needed. The image includes all application artifacts baked in. On first boot the device brings up a Headwaters-XXXX WiFi access point and serves a branded captive-portal setup page. The customer joins from their phone and completes setup entirely through the portal — MQTT and admin passwords, CA certificate installation, and startup of all services. See CM5/SETUP.md for the complete flashing and setup procedure.

The WiFi variant of the CM5 is required. There is no fallback setup path that uses SSH, a keyboard, a monitor, or a serial console.

If you are working with an older image that does not include baked-in artifacts, you can still deploy manually using the steps below.

Manual First-Time Deployment (Legacy Images)

For devices running older images without baked-in application artifacts:

  1. Transfer the deployment package to the Pi:

    scp trailcurrent-deployment-1.0.0.zip [email protected]:~
  2. SSH to the Pi and extract:

    ssh [email protected]
    unzip trailcurrent-deployment-1.0.0.zip
  3. Run the deployment script:

    chmod +x deploy.sh
    ./deploy.sh

    On first run, deploy.sh will:

    • Create .env from .env.example and ask you to edit it (then re-run)
    • Generate TLS certificates automatically using scripts/generate-certs.sh
    • Install the CA certificate to the system trust store (for host-side TLS verification)
    • Load all Docker images from tar files
    • Start all services
    • Set up the CAN-to-MQTT bridge
    • Set up the deployment watcher (for cloud OTA updates)
    • Deploy MCU firmware via OTA (if firmware is included)
  4. Edit .env with your credentials (first run only):

    nano .env
    # Set these values:
    #   MQTT_USERNAME / MQTT_PASSWORD
    #   ADMIN_PASSWORD
    #   TLS_CERT_HOSTNAME=headwaters.local
    #   ENCRYPTION_KEY=$(openssl rand -hex 32)

    Then re-run ./deploy.sh.

  5. Map data: No manual step here. Map bundles are uploaded via the PWA Maps page after first boot — see PLANS/Offline-Maps-Migration.md for the architecture and build/maps/README.md for how to build a region-specific bundle. The device boots into a healthy "Map Data not Loaded" state until the first upload lands.

  1. Install the CA certificate on phones/tablets (for PWA home screen icon):

    TrailCurrent uses a self-signed TLS certificate. Browsers will let you tap through the certificate warning, but iOS requires the CA to be trusted at the OS level for the PWA "Add to Home Screen" icon to work. Without this step the home screen icon will show a generic letter instead of the TrailCurrent logo.

    Copy the CA certificate from the Pi:

    scp [email protected]:~/data/keys/ca.crt ~/Desktop/TrailCurrent-CA.crt

    iOS (iPhone / iPad):

    1. Transfer TrailCurrent-CA.crt to the device (AirDrop, email, or iCloud Drive)
    2. Open the file — iOS will show "Profile Downloaded"
    3. Go to Settings > General > VPN & Device Management and install the profile
    4. Go to Settings > General > About > Certificate Trust Settings and enable full trust for TrailCurrent-CA
    5. Force close Safari (swipe up from the app switcher)
    6. Go to Settings > Apps > Safari > Clear History and Website Data to flush any cached certificate state
    7. Reopen Safari, navigate to the app, and use Share > Add to Home Screen

    If you are replacing a previously installed CA (e.g., after regenerating certificates), you must first remove the old profile before installing the new one: Settings > General > VPN & Device Management > TrailCurrent-CA > Remove Profile. Then follow steps 1-7 above.

    Android:

    1. Transfer TrailCurrent-CA.crt to the device
    2. Open the file — Android will prompt to install it as a CA certificate
    3. Follow the on-screen prompts (you may need to set a screen lock if you haven't already)

    macOS:

    1. Double-click TrailCurrent-CA.crt to add it to Keychain Access
    2. Find TrailCurrent-CA in the System keychain, double-click it
    3. Expand Trust and set to Always Trust

    Windows:

    1. Double-click TrailCurrent-CA.crt > Install Certificate
    2. Choose Local Machine > Place in: Trusted Root Certification Authorities

    This only needs to be done once per device. The CA certificate is valid for 10 years and will trust any server certificates generated by your Pi.

  2. Access the application:

    https://trailcurrent01.local
    

Subsequent Updates

When deploying a new version:

  1. Transfer new zip to Pi:

    scp trailcurrent-deployment-1.1.0.zip [email protected]:~
  2. SSH in, extract, and deploy:

    ssh [email protected]
    unzip -o trailcurrent-deployment-1.1.0.zip
    ./deploy.sh

    On updates, deploy.sh will:

    • Stop existing services
    • Update the system CA trust store if certificates were renewed
    • Load updated Docker images
    • Preserve your .env, certificates, and map tiles
    • Restart all services
    • Restart the deployment watcher service
    • Update MCU firmware if new firmware is included

What Persists Across Updates

These items are PRESERVED and never deleted by deploy.sh:

Application Configuration

  • .env — Device-specific secrets and settings
    • MQTT credentials, admin password, encryption keys, hostname

Security

  • data/keys/ — TLS certificates
    • CA certificate: 10-year validity — no need to regenerate or re-install on devices
    • Server certificate: ~2-year validity (825 days, required by Apple/iOS)
    • To renew the server cert: ./scripts/generate-certs.sh 2 (uses existing CA, no need to re-install CA on devices)

Data

  • data/maps/versions/<version>/ — Map bundles uploaded via the PWA Maps page (~130 GB per bundle for North America; one current + one previous version retained for rollback)
  • data/maps/current — Symlink to the active bundle version, updated atomically by map-watcher on successful upload
  • data/firmware/ — Peripheral module firmware payloads
  • data/deployments/ — OTA deployment package history
  • MongoDB data volume — All application state

CRITICAL: Never delete data/ directory during updates!


What Changes During Updates

  • Docker container images (loaded from new tar files)
  • Application code (backend, frontend, etc.)
  • Container configurations (config/)
  • Python local code (local_code/)
  • MCU firmware (if included in package)

Verification After Deployment

# All containers running
docker compose ps

# No errors in logs
docker compose logs --tail=20

# CAN-to-MQTT bridge running
sudo systemctl status cantomqtt.service

# Deployment watcher running (for cloud OTA updates)
sudo systemctl status deployment-watcher.service

# Map watcher running (for PWA map bundle uploads)
sudo systemctl status map-watcher.service

# API responding
curl -k https://localhost/api/health

# Web UI accessible
curl -k -o /dev/null -s -w "%{http_code}" https://localhost/

Troubleshooting

Containers fail to start

# Check logs for specific service
docker compose logs <service-name>
# Services: backend, frontend, mosquitto, mongodb

# Restart all containers
docker compose down && docker compose up -d --no-build

# Photon (search) and Valhalla (routing) are behind the `maps` profile
# and only start when a map bundle is installed. To include them:
docker compose --profile maps up -d

Map search or routing returns 503

The photon and valhalla containers are profile-gated — they only start when data/maps/current exists (a bundle has been uploaded and applied). If either service returns 503:

# Are they running?
docker ps | grep -E "photon|valhalla"

# If not, and a bundle IS installed:
docker compose --profile maps up -d photon valhalla

If no bundle is installed yet, upload one via the PWA Maps page — see DOCS/UpdatingMaps.md.

CAN-to-MQTT bridge not working

# Check service status
sudo systemctl status cantomqtt.service
sudo journalctl -u cantomqtt.service -f

# Verify CAN bus interface
ip link show can0

# Check local_code .env has correct external hostname
grep MQTT_BROKER_URL ~/local_code/.env

Deployment watcher not picking up cloud updates

# Check service status and logs
sudo systemctl status deployment-watcher.service
sudo journalctl -u deployment-watcher.service -f

# Verify cloud is configured via the PWA (Settings > Cloud Configuration)
# The watcher logs will show "Cloud not enabled" or "config incomplete" if not set up

Out of disk space

df -h
docker system prune -f  # Removes unused images, preserves data/

Network issues

nslookup trailcurrent01.local
ping trailcurrent01.local

Reference