davidandClaude Sonnet 5 1121835678 Finish dm-edworth bootstrap: fix Tailscale install, add system-layout meshcore_capture support
- base: Tailscale's per-codename .nosetup.sh install scripts are gone
  (404); switch to the universal tailscale.com/install.sh, and split
  install/enable (always) from auth (only when a key is given) so a
  node without an authkey still gets Tailscale installed, just not
  authenticated.
- meshcore_capture: the current upstream installer (v2.0.0+, what a
  fresh install now produces) uses a completely different layout than
  dm-baldock/dm-ashwell's older flat ~/.meshcore-packet-capture setup —
  dedicated system user, /opt + /etc/meshcore-packet-capture,
  config.d/*.toml, meshcore-packet-capture.service. Added
  meshcore_capture_layout (system/legacy) so the role targets the right
  paths/service name per host without touching the two working legacy
  nodes. New 99-user.toml.j2 replicates the old MQTT broker coverage
  (letsmesh us/eu, meshrank, ukmesh, meshmapper) in the new config.d
  override format.
- dm-edworth: fill in serial_port now that the MeshCore device is
  connected; confirmed running and publishing to all 5 brokers.
- README: fix broken list formatting, document the installer's
  required manual step and why.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-07-06 22:39:08 +01:00

dotmesh-monitor

Ansible playbooks for deploying MeshCore monitoring nodes (Raspberry Pi Zero W / Zero 2 W).

Hosts

Host Hardware Group
dm-baldock Pi Zero W (armv6) zero_w
dm-ashwell Pi Zero 2 W (armv7) zero2_w
dm-edworth Pi Zero 2 W (armv7) zero2_w

Prerequisites

Local machine:

pip install ansible
# or: sudo apt install ansible

New Pi node checklist:

  1. Flash Raspberry Pi OS Lite (Trixie) with Raspberry Pi Imager, using "Edit Settings" (OS customisation) to set hostname, the david user + password, and the dotnetwork wifi (SSID/password only — the imager only supports one network at flash time; the deployed-location and dotmobile networks get added later by the wifi role, see below).
  2. Before ejecting the card, verify the customisation actually got written — mount the boot partition and check network-config/user-data aren't just the commented-out stock template (see "Imager gotcha" below). Only cmdline.txt's regdomain getting a fresh timestamp while the rest stay at the image's build date is the tell that it silently failed.
  3. Boot the Pi, find its LAN IP (e.g. from the router's DHCP leases), confirm SSH access with the password you set — no key is seeded at flash time.
  4. Run ssh-copy-id david@<ip> from an interactive terminal (not through a non-interactive shell/script — it needs a real TTY to prompt for the password) so ansible can connect with a key.
  5. Connect the MeshCore device via USB, then find its serial ID: ls /dev/serial/by-id/.
  6. Add serial_port (and wifi_ssid_location) to ansible/host_vars/<hostname>/vars.yml, and the location wifi password to ansible/host_vars/<hostname>/vault.yml (see "Vault" below).
  7. Run site.yml against just that host, overriding the host's address since Tailscale/DNS won't resolve it yet: ansible-playbook site.yml --limit <hostname> -e "ansible_host=<ip>". This authorizes your SSH keys, joins the deployed-location + dotmobile wifi networks, installs (but does not authenticate) Tailscale, and deploys everything else in one pass.
  8. Tailscale needs one manual step: SSH in and run sudo tailscale up, then open the printed URL in a browser to approve the device on your tailnet. (You can pass -e tailscale_auth_key=tskey-... — from the admin console — to authenticate non-interactively instead, but there's no stored key anywhere for this repo, so the interactive route is simplest for a one-off node.)
  9. The meshcore-packet-capture installer also needs one manual step (see "meshcore-packet-capture install is interactive" below): SSH in and run sudo bash -c "$(curl -fsSL https://raw.githubusercontent.com/agessaman/meshcore-packet-capture/main/install.sh)", answering its ~3 prompts (service account, install method — pick 1, IATA/broker config — defaults are fine, site.yml overwrites .env.local afterward anyway).
  10. Once Tailscale is up, re-run site.yml without the ansible_host override — it'll resolve via the Tailscale hostname from here on, and will now just write .env.local + enable the service since the installer step is already satisfied.

meshcore-packet-capture install is interactive

The install.sh bootstrap has no real non-interactive path for a fresh install — its --update flag only changes behavior when an installation already exists. It also refuses to run at all with piped stdin (curl | sudo bash errors out asking you to download the script first) and its Python layer explicitly opens /dev/tty for prompts, which just hangs forever over plain SSH/ansible (no human there to answer). We tried feeding it scripted answers via script/a pty and it's not worth the fragility — just run it manually once per node (step 9 above); ansible/roles/meshcore_capture/tasks/main.yml's creates: guard means ansible never touches it again afterward.

Imager gotcha (2026-07)

The Raspberry Pi Imager available via Flathub (org.raspberrypi.rpi-imager) is stuck on 1.9.6 and there's no newer .deb/Flatpak in the Ubuntu or Flathub repos either — Flathub hasn't published the 2.0.x rewrite. 1.9.6 silently fails to apply OS customisation (hostname, user, SSH, wifi) on newer Raspberry Pi OS Trixie images: it only writes the kernel cfg80211.ieee80211_regdom= cmdline parameter and leaves user-data/network-config as the stock commented-out template, with no error. The result looks exactly like a wifi problem (Pi never appears on the network) but is actually "the card has no credentials on it at all."

Fix: grab the real .deb from the GitHub releases page (e.g. rpi-imager_2.0.10_amd64.deb) and sudo dpkg -i it — that version writes the customisation correctly.

Usage

Deploy to a single host (recommended for first run / testing):

cd ansible
ansible-playbook -i inventory.yml site.yml --limit dm-edworth

Deploy to all nodes:

ansible-playbook -i inventory.yml site.yml

Dry run:

ansible-playbook -i inventory.yml site.yml --limit dm-edworth --check

If sudo requires a password, add --ask-become-pass.

You'll be prompted for a Tailscale auth key — leave blank if the node is already authenticated.

What it does

  1. wifi — configures NetworkManager connections for dotnetwork (home), dotmobile (phone hotspot, field troubleshooting fallback), and the host's deployed-location network
  2. base — apt upgrade, installs screen/pipx/vnstat/git, sets MOTD, authorizes SSH keys for both laptop partitions, installs Tailscale (always) and authenticates it (only if tailscale_auth_key is set — otherwise run sudo tailscale up manually once, see checklist above)
  3. meshcore_cli — installs meshcore-cli via pipx
  4. meshcore_capture — runs the agessaman/meshcore-packet-capture install script (skipped once already installed — see "meshcore-packet-capture install is interactive" above, this needs a manual first run), writes .env.local config, enables meshcore-capture.service, deploys update/log helper scripts
  5. scripts — deploys voltage.sh and bandwidth.sh

Config

Shared MQTT config lives in group_vars/meshcore.yml. Per-host serial port and wifi SSID are in host_vars/<hostname>/vars.yml.

Running the playbook again re-applies .env.local and restarts the service if it changed — safe to run on already-deployed nodes.

Vault

group_vars/all/vault.yml (shared wifi/SSH secrets) and host_vars/<hostname>/vault.yml (per-host deployed-location wifi password) are encrypted with Ansible Vault. ansible.cfg points at ../.vault_pass (gitignored, not committed) for the password — ask David for a copy, or generate a fresh one and re-encrypt if starting over:

ansible-vault view --vault-password-file ../.vault_pass group_vars/all/vault.yml
ansible-vault edit --vault-password-file ../.vault_pass host_vars/dm-edworth/vault.yml

*/vault.yml.example shows the expected keys.

group_vars/meshcore.yml (MQTT credentials) is still plaintext — consider moving it into the vault too if this repo is shared further.

S
Description
No description provided
Readme
65 KiB
Languages
Jinja 86.6%
Shell 13.4%