HydraIssues

Citymesh: enroll cloud-seven + rupelmonde as partner WG peers; hydraneck reads MikroTik over the mesh
done feature Project: Reporter: 11 May 2026 09:21

Description

Pre-event work to unblock partner read access to Citymesh-managed MikroTik routers at cloud-seven and rupelmonde, so hydraneck can correlate venue network state during the 2026-05-22 → 2026-05-25 event.

Updated architectural framing (2026-05-11)

First pass of this issue framed it as a public-internet API call with an IP whitelist (46.225.8.28). That's off-design. The documented Partner Network Design (last touched 2026-04-09) specifies that partner-managed routers join our hydraguard mesh as venue peers — the partner installs a WG peer profile we provide, no public-internet API surface required.

Corrected procedure (now documented in hydraguard/docs/runbooks/citymesh-venue.md and hydraneck/docs/runbooks/mesh-participation.md):

1. Generate venue peer profiles on the hub

ssh ubuntu@141.227.136.199
hydraguard venue add cloud-seven --location bxl1 --guard citymesh
hydraguard venue add rupelmonde  --location bxl1 --guard citymesh
hydraguard apply
hydraguard venue config cloud-seven > /tmp/cloud-seven.partner.conf
hydraguard venue config rupelmonde  > /tmp/rupelmonde.partner.conf

2. Hand off to Citymesh

Per the partner design's 'What HYDRA Provides' bundle:

  • The two .partner.conf files (peer profiles to install on the MikroTiks)
  • Endpoint: hydraguard.experiencenet.com:51820/udp (their MikroTiks need outbound UDP/51820)
  • Confirmed CIDR allocations
  • Request: allow Head VLAN → Body VLAN locally on the MikroTik so local heads streaming from local bodies don't round-trip the hub
  • Request: enable a read-only API user on the MikroTik (REST on :443 preferred, legacy binary on :8729 acceptable fallback)

3. Enroll hydraneck as an air peer (one-time)

hydraguard air add hydraneck
hydraguard apply
hydraguard air config hydraneck > /tmp/hydraneck.wg.conf

Install the resulting config on hydraneck.experiencenet.com:

ssh root@46.225.8.28
apt-get install -y wireguard
install -m 600 /path/to/hydraneck.wg.conf /etc/wireguard/wg0.conf
systemctl enable --now wg-quick@wg0

4. Wire per-venue config

Once Citymesh confirms the peer is up and provides API creds, edit /root/.hydraneck/config.yaml:

venues:
  cloud-seven:
    mikrotik:
      host: 10.10.X.1   # WG tunnel address — NOT public WAN
      user: <readonly>
      pass: <password>
      transport: rest
  rupelmonde:
    mikrotik:
      host: 10.10.Y.1
      user: <readonly>
      pass: <password>
      transport: rest

The exact WG addresses are assigned by hydraguard apply — confirm via hydraguard status.

Why this is strictly better than the IP whitelist approach

  • No public-internet API exposure on the MikroTik (Citymesh doesn't whitelist anything; peer-key auth only)
  • Same trust model as AD6 — already battle-tested in production
  • Side-benefit: hydraneck gains routed access to every venue LAN (10.0.X.0/24), unlocking future LAN-side observability without re-asking Citymesh
  • No fragility around hydraneck VPS migration changing the egress IP — peer keys are stable

Out of scope (covered elsewhere)

  • Tizen sdb / sideload tooling for Samsung TVs → issue #141 (post-event)
  • Per-district hydraneck topology — single Brussels district today; multi-district notes captured in mesh-participation.md
  • partner vs citymesh doc/code terminology drift — doc says partner, code requires citymesh. Use citymesh in CLI for now; rename tracked separately.

Verification

  1. Citymesh confirms peer profile installed on cloud-seven and rupelmonde MikroTiks.
  2. From the hub: hydraguard status shows handshake for both venues; ping <venue-LAN-gateway> succeeds.
  3. From hydraneck (post air-peer enrollment): wg show shows hub handshake; ping 10.10.0.1 succeeds; curl -sk https://<venue-mikrotik-WG-IP>/rest/system/resource returns JSON.
  4. hydraneck scan cloud-seven and hydraneck scan rupelmonde populate clients + bandwidth.
  5. Web UI correlation table green for both venues.

Plan files

  • Original plan: ~/.claude/plans/meandering-trotting-mongoose.md
  • Documentation plan: ~/.claude/plans/breezy-gliding-narwhal.md

2026-05-14 — Citymesh ping failure: not our side

Citymesh reported cloud-seven (10.10.2.1) and rupelmonde (10.10.3.1) cannot ping hydraneck (10.10.100.14), while mobile-kit (10.10.4.1) works.

Our side is not blocking. Full investigation:

  • Hub iptables FORWARD: ACCEPT for all wg0→wg0 traffic — no rules blocking inter-peer traffic
  • Hydraneck INPUT: policy ACCEPT, zero blocking rules
  • Hydraneck AllowedIPs: 10.10.0.0/16, 10.0.0.0/8 — covers all venue WG addresses
  • Hydraneck can ping all three venues: cloud-seven (10.10.2.1) 20ms ✓, rupelmonde (10.10.3.1) 32ms ✓, mobile-kit (10.10.4.1) 48ms ✓
  • Hub shows active handshakes for both cloud-seven and rupelmonde (recent, not stale)

The mesh is bidirectional and routed correctly. If hydraneck's pings reach cloud-seven/rupelmonde and their ICMP replies traverse hub → hydraneck successfully, the path from venues to hydraneck is open end-to-end.

Root cause is on the MikroTik side at cloud-seven and rupelmonde. Likely:

  1. MikroTik firewall blocks new ICMP originating from the router's own WG interface (stateful rule allows replies to established sessions only, but drops new outgoing ICMP)
  2. Missing explicit route for 10.10.0.0/16 via wg-interface — MikroTik does not auto-derive routes from AllowedIPs the way Linux does; the route must be added manually in /ip route

Recommended check for Citymesh: compare MikroTik routing table and firewall on cloud-seven/rupelmonde vs mobile-kit:

  • /ip route print — is there a route for 10.10.0.0/16 (or 10.10.100.0/24) via the WG interface on cloud-seven and rupelmonde?
  • /ip firewall filter print — any rule dropping outgoing ICMP from 10.10.2.1 or 10.10.3.1?
  • Test: try /ping 10.10.100.14 src-address=10.10.2.1 from cloud-seven MikroTik terminal to confirm source routing

2026-05-14 — Mesh routing confirmed working; next: MikroTik API keys

All three venues now have WG handshakes and bidirectional routing confirmed:

Venue WG IP Ping from hydraneck Route status
cloud-seven 10.10.2.1 20ms route confirmed by Citymesh
rupelmonde 10.10.3.1 32ms route confirmed by Citymesh
mobile-kit 10.10.4.1 48ms route confirmed by Citymesh

Root cause of initial ping failure was a missing explicit MikroTik route — MikroTik does not auto-derive routes from WireGuard AllowedIPs unlike Linux. Citymesh added 10.10.0.0/16 → WG interface on each device. Route for mobile-kit appeared to work earlier only because it was temporarily behind our own router (false positive).

Known constraint: Citymesh datacenter uses 10.10.8.0/23. Do not assign HYDRA WG addresses or source from that range — their management VPN more-specific route handles it on their side, but our side would lose replies.

Runbooks updated and pushed:

  • hydraguard/docs/runbooks/citymesh-venue.md — MikroTik routing requirement, 10.10.8.0/23 overlap, mobile-kit in reference table, asymmetric ping diagnostic
  • hydraneck/docs/runbooks/mesh-participation.md — MikroTik routing note in enrollment steps
  • hydraneck/docs/runbooks/address-ranges.md — 10.10.8.0/23 overlap warning

Next step: receive read-only MikroTik API credentials from Citymesh (cloud-seven + rupelmonde already sent; mobile-kit in mailbox per Citymesh message) and wire into /root/.hydraneck/config.yaml.

2026-05-14 — Mobile-kit API creds wired; TCP ports blocked (needs Citymesh action)

Credentials received and wired into hydraneck:

  • Venue registered in HydraVenues as mobile-kit (bxl1, visit-flanders)
  • hydraneck config updated: 10.10.4.1:8729, user hydra, protocol api (API-SSL)
  • Password stored in /root/.hydraneck/secrets.yaml under mobile-kit/mikrotik-mobile-kit

Connectivity status:

  • Ping to 10.10.4.1 from hydraneck: ✓ (ICMP works, WG tunnel confirmed)
  • TCP port 8729 (API-SSL): ✗ timeout
  • TCP port 8728 (API): ✗ timeout
  • TCP port 443 (WEB API): ✗ timeout

Root cause: On MikroTik, two layers must both allow the connection:

  1. /ip firewall filter INPUT chain — the rule Citymesh added (from 10.10.100.14)
  2. /ip service settings — the API/API-SSL service must not restrict the allowed-from address in a way that blocks the WG interface

ICMP passing but all TCP failing is the classic symptom of the firewall filter rule allowing ICMP only (or a missing TCP rule), OR the service being bound to specific interfaces that exclude the WG interface.

Ask for Citymesh:

  • /ip service print — is API (port 8728) or API-SSL (port 8729) enabled and what is available-from?
  • /ip firewall filter print chain=input — is there a rule allowing TCP from 10.10.100.14 to port 8728 or 8729?
  • Alternatively: /tool telnet 10.10.100.14 from the MikroTik terminal to verify the WG route back to us works from their side

2026-05-15 — Email sent to Citymesh; two open items

Email sent re: two blockers

1. Mobile-kit API — TCP ports blocked (Citymesh action needed)

WG tunnel up, ping 10.10.4.1 works. TCP 8729/8728/443 all timeout. MikroTik requires both layers: /ip firewall filter INPUT chain rule AND /ip service available-from settings. Asked Citymesh to verify both with /ip service print and /ip firewall filter print chain=input.

2. Cloud-seven + rupelmonde credentials — link expired

The secure link Citymesh sent with read-only API credentials has expired. Resend requested.

Open state

  • All three WG handshakes up (cloud-seven 10.10.2.1, rupelmonde 10.10.3.1, mobile-kit 10.10.4.1)
  • hydraneck config: mobile-kit wired (10.10.4.1:8729, user hydra, protocol api)
  • new-venue.md Step 7 updated with correct procedure + MikroTik two-layer gotcha
  • Citymesh fixes mobile-kit /ip service to allow TCP from 10.10.100.14
  • Citymesh resends cloud-seven + rupelmonde read-only API creds
  • cloud-seven + rupelmonde wired in hydraneck config
  • First successful hydraneck scan (all three venues)

2026-05-15 — Email verstuurd naar Citymesh

Email verstuurd naar Yentel met twee punten:

  1. Mobile-kit API poorten (8729/8728/443) timeout ondanks actieve WG tunnel — gevraagd om /ip service en /ip firewall filter chain=input te controleren op de mobile-kit MikroTik
  2. Cloud-seven + rupelmonde credentials — link verlopen, resend gevraagd

Wachten op reactie Citymesh.

2026-05-18 — cloud-seven + rupelmonde live; mobile-kit waiting on new password

Root cause of username failure: config had hydra-read (dash) but actual MikroTik user is hydra_read (underscore). Fixed.

Config changes applied to hydraneck:

  • cloud-seven: added address: 10.10.2.1:8728, protocol: api, fixed username: hydra_read
  • rupelmonde: added address: 10.10.3.1:8728, protocol: api, fixed username: hydra_read
  • Passwords stored in secrets store for both

Scan results:

  • cloud-seven: live, RouterOS 7.21.3 (stable), 70 clients, nodes: turbo-pancake-76 + cosmic-pretzel-98
  • rupelmonde: live, RouterOS 7.20.8 (long-term), 10 clients, nodes: boom-pickle-38 + peppy-dumpling-32

mobile-kit still blocked: stored password does not match hydra user. Error code 6 from RouterOS (invalid user name or password). New password requested from Citymesh.

When Citymesh provides the new mobile-kit password, run:

curl -sk -X PUT https://hydraneck.experiencenet.com/admin/api/secrets/mobile-kit/mikrotik-mobile-kit \
  -H "Authorization: Bearer <hydraneck-admin-token>" \
  -H "Content-Type: application/json" \
  -d '{"password":"<new-pw>"}'
hydraneck scan mobile-kit

(admin token is in /root/.hydraneck/config.yaml on hydraneck.experiencenet.com)

Open items:

  • cloud-seven scan green
  • rupelmonde scan green
  • Citymesh resets hydra user password on mobile-kit
  • hydraneck scan mobile-kit green

Custom Fields

affected_venues
cloud-seven, rupelmonde, mobile-kit
blocked_on
Citymesh installs WG peer configs + provides read-only API creds
handover_method
email with .partner.conf attachments
handover_sent
2026-05-11
hub_peer_state
added, offline (awaiting install)
hydraneck_state
air-hydraneck @ 10.10.100.14, handshaking
related_issues
141 (Samsung TV, post-event), 147+148+149 (bug fixes done today), 151 (local-machine handoff)

Comments (10)

api 11 May 2026 11:43

Documentation for the operating mode has landed:

  • hydraguard — new runbook docs/runbooks/citymesh-venue.md (commit cd71790). Full procedure: hydraguard venue add --guard citymesh, peer profile export, handover bundle to Citymesh, verification, troubleshooting. Linked from the runbook.md guard-types table.
  • hydraneck — new runbook docs/runbooks/mesh-participation.md (commit 491a7e5). One-time enrollment of hydraneck as a HydraGuard air peer, per-venue config pointing at WG addresses, graceful degradation, multi-district notes. Wired into the public docs nav under Operations.
  • partner-network-design updated with an operator-procedures callout pointing to both new docs, and a footnote noting the partner vs citymesh terminology drift (doc says partner, code requires citymesh today).

The operational ask to Citymesh changes from 'whitelist 46.225.8.28' to: 'install WG peer profiles on the MikroTik at cloud-seven and rupelmonde'. Procedure to generate those profiles is in the new citymesh-venue.md.

api 11 May 2026 18:38

2026-05-11 — handover complete from our side

Hub-side enrollment done. Both venues added as citymesh-guard peers in the Brussels hub mesh:

Venue WG addr LAN CIDR Status
cloud-seven 10.10.2.1/32 10.0.2.0/24 added, awaiting Citymesh install
rupelmonde 10.10.3.1/32 10.0.3.0/24 added, awaiting Citymesh install

Reference table in hydraguard/docs/runbooks/citymesh-venue.md committed (7944a96).

hydraneck enrolled as air peer in the same mesh — air-hydraneck at 10.10.100.14. Handshake confirmed (~14ms RTT to hub over WG). Ready to scan the venues over the tunnel once Citymesh installs their side.

Email + both .partner.conf attachments sent to Citymesh today.

Open state

  • Hub peer profiles generated
  • hydraneck enrolled as air peer in mesh
  • Handover email + configs sent to Citymesh (2026-05-11)
  • Citymesh installs cloud-seven peer → handshake on hub
  • Citymesh installs rupelmonde peer → handshake on hub
  • Citymesh provides read-only MikroTik API user creds
  • hydraneck /root/.hydraneck/config.yaml updated with WG-side hosts
  • First successful hydraneck scan cloud-seven
  • First successful hydraneck scan rupelmonde

Bugs found and fixed along the way (today)

  • #147 (hydrarelease updater .backup filename chain) — done, shipped in hydrarelease v1.17.3
  • #148 (hydraguard wrong systemd unit name) — done, shipped in hydraguard v1.10.9
  • #149 (add subcommands corrupted pipeable config) — done, shipped in hydraguard v1.10.10

Related

  • Companion (post-event) issue: #141 Samsung Tizen TV head client
  • Local-machine handoff issue (transient, secret-bearing): #151 — should be redacted + closed by the local Claude after the user confirms files landed
  • Memory: project_citymesh_rollout.md mirrors this state for cross-session continuity
api 12 May 2026 07:25

2026-05-12 — Citymesh firewall question + answer

Citymesh asked: Which IP should they allowlist in the MikroTik firewall rules to allow REST and binary API connections from hydraneck? They suspected it would be the WireGuard gateway IP but wanted confirmation, and asked whether there is a LAN range between the WG server and hydraneck.

Answer: allow 10.10.100.14/32 — hydraneck's WireGuard address.

Verified on the Brussels hub (141.227.136.199): no NAT in the POSTROUTING chain, pure routing between WG peers. This means the MikroTik sees hydraneck's own WG IP as the source — not the hub IP.

Ports to open inbound from 10.10.100.14:

  • TCP 443 — MikroTik REST API (preferred)
  • TCP 8729 — legacy binary API (optional fallback)

No public internet IP needs to be whitelisted. There is no LAN range between the WG hub and hydraneck — hydraneck is an air peer directly in the mesh at 10.10.100.14; packets travel 10.10.100.14 → hub → 10.10.2.1 / 10.10.3.1 with source IP preserved.

Citymesh confirmed they will implement this week, expected Wednesday 2026-05-14 (venue IT staff are on an install tomorrow).

api 13 May 2026 14:12

2026-05-13 — mobile-kit added to mesh

The mobile Hydra kit is also Citymesh-managed, so it follows the same enrollment path as cloud-seven and rupelmonde.

Hub-side enrollment done.

Venue WG addr LAN CIDR Guard Status
cloud-seven 10.10.2.1/32 10.0.2.0/24 citymesh awaiting Citymesh install
rupelmonde 10.10.3.1/32 10.0.3.0/24 citymesh awaiting Citymesh install
mobile-kit 10.10.4.1/32 10.0.4.0/24 citymesh added today — awaiting Citymesh install

Partner config saved to /tmp/mobile-kit.partner.conf on the Brussels hub (141.227.136.199). Needs to be included in the next handover email to Citymesh alongside the cloud-seven and rupelmonde configs (or as a follow-up if those are already sent).

Updated open state

  • Hub peer profiles generated (cloud-seven, rupelmonde, mobile-kit)
  • hydraneck enrolled as air peer in mesh
  • Handover email + cloud-seven/rupelmonde configs sent to Citymesh (2026-05-11)
  • Send mobile-kit.partner.conf to Citymesh
  • Citymesh installs cloud-seven peer → handshake on hub
  • Citymesh installs rupelmonde peer → handshake on hub
  • Citymesh installs mobile-kit peer → handshake on hub
  • Citymesh provides read-only MikroTik API user creds (all three venues)
  • hydraneck /root/.hydraneck/config.yaml updated with WG-side hosts
  • First successful hydraneck scan cloud-seven
  • First successful hydraneck scan rupelmonde
  • First successful hydraneck scan mobile-kit
api 13 May 2026 14:43

mobile-kit.partner.conf sent to Citymesh on 2026-05-13 (see #167). Awaiting acknowledgement.

admin 14 May 2026 13:22

Feedback citymesh: Rupelmonde VPN, firewall rules actief gezet (met user die je reeds had gekregen) maar daar kan ik niet pingen naar 10.10.100.14 desondanks dat de wireguard een allowed address 10.10.0.0/16 heeft staan, kan het zijn dat jouw kant nog iets blocked komende van 10.10.3.1 (rupelmonde) die wel werkt op mobilekit (10.10.4.1)?

Zelfde probleem voor cloud7 vanaf 10.10.2.1, daarmee kan ik niet naar 10.10.100.14

admin 14 May 2026 14:45

[14/5, 16:27] Yentel Hollebeke: De reden dat mobilekit werkte is omdat die achter jullie router zat
hij kon dus naar de hub via wan over jullie router, maar dat is niet de juiste weg als hij ergens anders zou staan.

Met wat finetuning van de routes (want wireguard routes worden niet automatisch toegevoegd aan de routing table) en te zeggen dat 10.10.100.14 over de wireguard moet gestuurd worden zou het moeten lukken
[14/5, 16:27] Yentel Hollebeke: Die zitten in je mailbox voor de dev kit (de andere 2 had je al) normaalgezien.
[14/5, 16:28] Yentel Hollebeke: Ik heb voorlopig wel enkel een route staan voor de 10.10.100.14 over wireguard, niet voor de volledige 10.10.0.0/16 range, maar kan dat op zich wel zo aanpassen.
Opgepast, die route overlapt met ons datacenter op 10.10.8.0/23 dus zolang daar niets in zit die belangrijk is langs jullie kant zou dat geen problemen mogen geven.
[14/5, 16:33] C: Miss best Dan een andere route zodat we niet botsen met jullie datacenter?
[14/5, 16:34] Yentel Hollebeke: Ik kan op zich perfect de 10.10.0.0/16 richting wireguard sturen

10.10.8.0/23 is kleiner & specifieker dus die gaat dan gewoon over onze eigen management vpn gaan.

Thing is gewoon dat als jij ooit iets zou sturen met source 10.10.8.123 dat hij daar nooit iets van terug zal krijgen. Dus zolang jij dat stuk ontwijkt is dit voor ons goed genoeg

admin 15 May 2026 11:00

[15/5, 12:46] Yentel Hollebeke: API, API-SSL en WWW-SSL poorten staan normaalgezien allemaal open, uit het hoofd 8728, 8729 en 443, allemaal tcp
[15/5, 12:46] Yentel Hollebeke: dit voor packets vanaf source 10.10.100.14, maar ik kijk straks nog even na
[15/5, 12:47] Yentel Hollebeke: zal ook nieuwe passwords genereren voor rupel & cloud7
Note dat de users daar hydra-read zijn en de mobilekit hydra is (in opzicht om daar later write op te zetten)

api 15 May 2026 11:41

2026-05-15 — Scan test + config fix

WG tunnel confirmed (hydraneck side):

  • ICMP to all three venues: ✓ (cloud-seven 20ms, rupelmonde 32ms, mobile-kit 42ms)
  • ip route get 10.10.4.1 on hydraneck: routes via wg0 with source 10.10.100.14 — correct source IP matching the firewall rule Citymesh applied

hydraneck scan mobile-kit test run:

=== Scanning mobile-kit ===
Routers:
  mikrotik-mobile-kit  mikrotik  unreachable  (0 clients)
    error: mikrotik dial 10.10.4.1:8729: i/o timeout

Our side is correct — scan targets 10.10.4.1:8729 out wg0 from 10.10.100.14. TCP still timing out, meaning Citymesh firewall rules on mobile-kit are not yet applied (Yentel said he would verify shortly).

Config fix — username mismatch:

Yentel confirmed cloud-seven and rupelmonde use user hydra-read. Config had hydraneck — corrected to hydra-read on both venues.

Remaining open items before first successful scan:

  • Citymesh applies firewall rules on mobile-kit (TCP 8729/8728/443 from 10.10.100.14)
  • Citymesh resends cloud-seven + rupelmonde credentials (link expired)
  • Wire cloud-seven address (10.10.2.1:PORT) + protocol into hydraneck config
  • Wire rupelmonde address (10.10.3.1:PORT) + protocol into hydraneck config
  • Add cloud-seven + rupelmonde credentials to secrets store on hydraneck
  • hydraneck scan cloud-seven green
  • hydraneck scan rupelmonde green
  • hydraneck scan mobile-kit green
api 17 May 2026 08:27

Citymesh confirmed install on all three venues — WireGuard handshakes live as of 2026-05-15:

  • mobile-kit (10.10.4.1): handshake ~4s
  • cloud-seven (10.10.2.1): handshake ~25s
  • rupelmonde (10.10.3.1): handshake ~90s

Bidirectional tunnels are up. Next step: receive read-only MikroTik API creds from Citymesh and update /root/.hydraneck/config.yaml with WG-side hosts to enable first scan.