Compare commits
2
Commits
1121835678
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6173bf3ac2 | ||
|
|
cd1ee3631d |
@@ -10,6 +10,11 @@ Ansible playbooks for deploying MeshCore monitoring nodes (Raspberry Pi Zero W /
|
|||||||
| dm-ashwell | Pi Zero 2 W (armv7) | zero2_w |
|
| dm-ashwell | Pi Zero 2 W (armv7) | zero2_w |
|
||||||
| dm-edworth | Pi Zero 2 W (armv7) | zero2_w |
|
| dm-edworth | Pi Zero 2 W (armv7) | zero2_w |
|
||||||
|
|
||||||
|
There's also a fourth capture node, **dotminipc** (device name `dm-stotfold`) —
|
||||||
|
not managed by this repo (it's a Docker container on the shared dotnetwork
|
||||||
|
host, not a dedicated Pi), but documented below since it's the same upstream
|
||||||
|
software and shares config with the Pi fleet. See "dotminipc" below.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
**Local machine:**
|
**Local machine:**
|
||||||
@@ -72,7 +77,7 @@ You'll be prompted for a Tailscale auth key — leave blank if the node is alrea
|
|||||||
1. **wifi** — configures NetworkManager connections for `dotnetwork` (home), `dotmobile` (phone hotspot, field troubleshooting fallback), and the host's deployed-location network
|
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)
|
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
|
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
|
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 config (TOML `config.d/99-user.toml` on current "system"-layout nodes, legacy `.env.local` on the two nodes still on the old layout — see `meshcore_capture_layout` in `group_vars/all/vars.yml`), enables the capture service, deploys update/log helper scripts
|
||||||
5. **scripts** — deploys `voltage.sh` and `bandwidth.sh`
|
5. **scripts** — deploys `voltage.sh` and `bandwidth.sh`
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
@@ -91,3 +96,43 @@ ansible-vault edit --vault-password-file ../.vault_pass host_vars/dm-edworth/vau
|
|||||||
`*/vault.yml.example` shows the expected keys.
|
`*/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.
|
`group_vars/meshcore.yml` (MQTT credentials) is still plaintext — consider moving it into the vault too if this repo is shared further.
|
||||||
|
|
||||||
|
## dotminipc (Docker node, not managed by this repo)
|
||||||
|
|
||||||
|
A fourth capture point, device name `dm-stotfold`, runs as a Docker container
|
||||||
|
(`ghcr.io/agessaman/meshcore-packet-capture:latest`) on **dotminipc**
|
||||||
|
(172.16.31.92), the shared Docker/HA host documented in the sibling
|
||||||
|
`dotnetwork` repo. It isn't part of this repo's inventory — no Ansible role
|
||||||
|
here touches it — but it's the same upstream software as the Pi fleet, so
|
||||||
|
config drift between the two is worth knowing about.
|
||||||
|
|
||||||
|
- Compose file: `dotnetwork/docker/dotminipc/meshcore-packet-capture/docker-compose.yml`
|
||||||
|
- Config: `dotnetwork/docker/dotminipc/meshcore-packet-capture/config.d/99-user.toml`
|
||||||
|
— host-only, gitignored (contains MQTT credentials), same TOML shape as
|
||||||
|
this repo's `meshcore_capture` role template
|
||||||
|
(`ansible/roles/meshcore_capture/templates/99-user.toml.j2`); keep the
|
||||||
|
broker list in sync between the two if either changes. The committed
|
||||||
|
`config.d/99-user.toml.example` in the dotnetwork repo is the sanitized
|
||||||
|
reference copy.
|
||||||
|
- Deploy/restart: `ssh [email protected]`, then from `/opt/docker`:
|
||||||
|
`docker compose up -d meshcore-capture --force-recreate`. Logs:
|
||||||
|
`docker logs -f meshcore-packet-capture`.
|
||||||
|
|
||||||
|
**2026-07-27 outage, for reference**: the `:latest` image was rebuilt
|
||||||
|
2026-07-25 and switched its config format from `.env.local` to TOML
|
||||||
|
(`/etc/meshcore-packet-capture/config.toml` + `config.d/*.toml` —
|
||||||
|
the same "system" layout `meshcore_capture_layout` already models for the Pi
|
||||||
|
fleet). It silently stopped reading `.env.local` at all — despite upstream's
|
||||||
|
own README still describing that as a supported "legacy" path, in practice it
|
||||||
|
was just ignored — so the container fell back to the image's baked-in
|
||||||
|
defaults (`connection_type = "ble"`, `serial.ports = ["/dev/ttyUSB0"]`, no
|
||||||
|
owner key, only 2 of 5 brokers) and crash-looped on
|
||||||
|
`could not open port /dev/ttyUSB0`. Fix was to mount a full TOML override at
|
||||||
|
`config.d/99-user.toml` instead (see above) — same pattern as the Pi
|
||||||
|
`meshcore_capture` role already uses for `system`-layout nodes. Also found in
|
||||||
|
the process: the old `.env.local` had `PACKETCAPTURE_MQTT5_SERVER` set to
|
||||||
|
`mqtt.meshmapper.cc`, which fails TLS handshake — the correct domain is
|
||||||
|
`mqtt.meshmapper.net` (confirmed via `openssl s_client`; `.net` presents a
|
||||||
|
valid Let's Encrypt cert, `.cc` returns a TLS alert). If the Pi fleet's
|
||||||
|
`99-user.toml.j2` broker list is ever regenerated from a stale copy of this
|
||||||
|
node's old config, watch out for that typo resurfacing.
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
remote_user: david
|
remote_user: david
|
||||||
ansible_user: "{{ remote_user }}"
|
ansible_user: "{{ remote_user }}"
|
||||||
ansible_become: true
|
# become is set at the play level in site.yml, NOT here — ansible_become as a
|
||||||
|
# connection variable takes precedence over a task's own `become: false`
|
||||||
|
# keyword, which silently broke every become:false task in this repo (they
|
||||||
|
# all ran as root regardless). Play-level `become:` correctly loses to a
|
||||||
|
# task-level override.
|
||||||
|
|
||||||
meshcore_description: "meshcore management"
|
meshcore_description: "meshcore management"
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,3 @@ serial_port: /dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_1C:DB:D4
|
|||||||
# Deployed-location wifi
|
# Deployed-location wifi
|
||||||
wifi_ssid_location: "awesome"
|
wifi_ssid_location: "awesome"
|
||||||
wifi_password_location: "{{ vault_wifi_location }}"
|
wifi_password_location: "{{ vault_wifi_location }}"
|
||||||
|
|
||||||
# Predates the current upstream installer's system-service layout
|
|
||||||
meshcore_capture_layout: "legacy"
|
|
||||||
|
|||||||
@@ -17,6 +17,15 @@
|
|||||||
state: present
|
state: present
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
|
- name: Install libffi headers (armv6 has no prebuilt cffi wheel, needs to compile it)
|
||||||
|
apt:
|
||||||
|
name:
|
||||||
|
- libffi-dev
|
||||||
|
- pkg-config
|
||||||
|
state: present
|
||||||
|
become: true
|
||||||
|
when: ansible_architecture == "armv6l"
|
||||||
|
|
||||||
- name: Set MOTD
|
- name: Set MOTD
|
||||||
template:
|
template:
|
||||||
src: motd.j2
|
src: motd.j2
|
||||||
|
|||||||
@@ -29,7 +29,9 @@
|
|||||||
- name: Write .env.local config (legacy layout)
|
- name: Write .env.local config (legacy layout)
|
||||||
template:
|
template:
|
||||||
src: env.local.j2
|
src: env.local.j2
|
||||||
dest: "{{ ansible_env.HOME }}/.meshcore-packet-capture/.env.local"
|
dest: "/home/{{ remote_user }}/.meshcore-packet-capture/.env.local"
|
||||||
|
owner: "{{ remote_user }}"
|
||||||
|
group: "{{ remote_user }}"
|
||||||
mode: "0640"
|
mode: "0640"
|
||||||
become: false
|
become: false
|
||||||
when: meshcore_capture_layout == 'legacy'
|
when: meshcore_capture_layout == 'legacy'
|
||||||
@@ -56,11 +58,12 @@
|
|||||||
|
|
||||||
- name: Deploy meshcore-capture-update script
|
- name: Deploy meshcore-capture-update script
|
||||||
copy:
|
copy:
|
||||||
content: >-
|
content: |
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
bash <(curl -fsSL https://raw.githubusercontent.com/agessaman/meshcore-packet-capture/main/install.sh){{ ' --update' if meshcore_capture_layout != 'legacy' else '' }}
|
bash <(curl -fsSL https://raw.githubusercontent.com/agessaman/meshcore-packet-capture/main/install.sh){{ ' --update' if meshcore_capture_layout != 'legacy' else '' }}
|
||||||
dest: "{{ ansible_env.HOME }}/meshcore-capture-update.sh"
|
dest: "/home/{{ remote_user }}/meshcore-capture-update.sh"
|
||||||
|
owner: "{{ remote_user }}"
|
||||||
|
group: "{{ remote_user }}"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
become: false
|
become: false
|
||||||
|
|
||||||
@@ -69,6 +72,8 @@
|
|||||||
content: |
|
content: |
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
sudo journalctl -u {{ 'meshcore-capture' if meshcore_capture_layout == 'legacy' else 'meshcore-packet-capture' }} -f
|
sudo journalctl -u {{ 'meshcore-capture' if meshcore_capture_layout == 'legacy' else 'meshcore-packet-capture' }} -f
|
||||||
dest: "{{ ansible_env.HOME }}/meshcore-capture-logs.sh"
|
dest: "/home/{{ remote_user }}/meshcore-capture-logs.sh"
|
||||||
|
owner: "{{ remote_user }}"
|
||||||
|
group: "{{ remote_user }}"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
become: false
|
become: false
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# MeshCore Packet Capture - user overrides
|
# MeshCore Packet Capture - user overrides
|
||||||
# Managed by Ansible - local changes will be overwritten on next playbook run
|
# Managed by Ansible - local changes will be overwritten on next playbook run
|
||||||
#
|
#
|
||||||
# [[broker]] tables merge by name across config.d/*.toml, so the letsmesh-us
|
# Defines every broker fully (not relying on config.d/10-letsmesh.toml being
|
||||||
# and letsmesh-eu entries below only add owner identity to the connection
|
# auto-installed) — whether that preset exists depends on which path the
|
||||||
# details already installed as config.d/10-letsmesh.toml.
|
# installer took (fresh install vs migrate), so a partial override here would
|
||||||
|
# silently no-op on nodes where it wasn't created.
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
iata = "{{ packetcapture_iata }}"
|
iata = "{{ packetcapture_iata }}"
|
||||||
@@ -22,17 +23,45 @@ advert_interval_hours = {{ packetcapture_advert_interval_hours }}
|
|||||||
owner_public_key = "{{ packetcapture_owner_public_key }}"
|
owner_public_key = "{{ packetcapture_owner_public_key }}"
|
||||||
owner_email = "{{ packetcapture_owner_email }}"
|
owner_email = "{{ packetcapture_owner_email }}"
|
||||||
|
|
||||||
|
# LetsMesh.net Packet Analyzer (US)
|
||||||
[[broker]]
|
[[broker]]
|
||||||
name = "letsmesh-us"
|
name = "letsmesh-us"
|
||||||
|
enabled = true
|
||||||
|
server = "mqtt-us-v1.letsmesh.net"
|
||||||
|
port = 443
|
||||||
|
transport = "websockets"
|
||||||
|
keepalive = 120
|
||||||
|
qos = 0
|
||||||
|
retain = true
|
||||||
|
|
||||||
|
[broker.tls]
|
||||||
|
enabled = true
|
||||||
|
verify = true
|
||||||
|
|
||||||
[broker.auth]
|
[broker.auth]
|
||||||
|
method = "token"
|
||||||
|
audience = "mqtt-us-v1.letsmesh.net"
|
||||||
owner = "{{ packetcapture_owner_public_key }}"
|
owner = "{{ packetcapture_owner_public_key }}"
|
||||||
email = "{{ packetcapture_owner_email }}"
|
email = "{{ packetcapture_owner_email }}"
|
||||||
|
|
||||||
|
# LetsMesh.net Packet Analyzer (EU)
|
||||||
[[broker]]
|
[[broker]]
|
||||||
name = "letsmesh-eu"
|
name = "letsmesh-eu"
|
||||||
|
enabled = true
|
||||||
|
server = "mqtt-eu-v1.letsmesh.net"
|
||||||
|
port = 443
|
||||||
|
transport = "websockets"
|
||||||
|
keepalive = 120
|
||||||
|
qos = 0
|
||||||
|
retain = true
|
||||||
|
|
||||||
|
[broker.tls]
|
||||||
|
enabled = true
|
||||||
|
verify = true
|
||||||
|
|
||||||
[broker.auth]
|
[broker.auth]
|
||||||
|
method = "token"
|
||||||
|
audience = "mqtt-eu-v1.letsmesh.net"
|
||||||
owner = "{{ packetcapture_owner_public_key }}"
|
owner = "{{ packetcapture_owner_public_key }}"
|
||||||
email = "{{ packetcapture_owner_email }}"
|
email = "{{ packetcapture_owner_email }}"
|
||||||
|
|
||||||
|
|||||||
@@ -11,5 +11,5 @@
|
|||||||
shell: pipx install meshcore-cli
|
shell: pipx install meshcore-cli
|
||||||
args:
|
args:
|
||||||
executable: /bin/bash
|
executable: /bin/bash
|
||||||
creates: "{{ ansible_env.HOME }}/.local/bin/meshcore-cli"
|
creates: "/home/{{ remote_user }}/.local/bin/meshcore-cli"
|
||||||
become: false
|
become: false
|
||||||
|
|||||||
@@ -2,13 +2,17 @@
|
|||||||
- name: Deploy voltage.sh
|
- name: Deploy voltage.sh
|
||||||
copy:
|
copy:
|
||||||
src: voltage.sh
|
src: voltage.sh
|
||||||
dest: "{{ ansible_env.HOME }}/voltage.sh"
|
dest: "/home/{{ remote_user }}/voltage.sh"
|
||||||
|
owner: "{{ remote_user }}"
|
||||||
|
group: "{{ remote_user }}"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
become: false
|
become: false
|
||||||
|
|
||||||
- name: Deploy bandwidth.sh
|
- name: Deploy bandwidth.sh
|
||||||
copy:
|
copy:
|
||||||
src: bandwidth.sh
|
src: bandwidth.sh
|
||||||
dest: "{{ ansible_env.HOME }}/bandwidth.sh"
|
dest: "/home/{{ remote_user }}/bandwidth.sh"
|
||||||
|
owner: "{{ remote_user }}"
|
||||||
|
group: "{{ remote_user }}"
|
||||||
mode: "0755"
|
mode: "0755"
|
||||||
become: false
|
become: false
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
- name: Deploy MeshCore monitoring nodes
|
- name: Deploy MeshCore monitoring nodes
|
||||||
hosts: meshcore
|
hosts: meshcore
|
||||||
|
become: true
|
||||||
vars_prompt:
|
vars_prompt:
|
||||||
- name: tailscale_auth_key
|
- name: tailscale_auth_key
|
||||||
prompt: "Tailscale auth key (leave blank to skip)"
|
prompt: "Tailscale auth key (leave blank to skip)"
|
||||||
|
|||||||
Reference in New Issue
Block a user