A growing specialty-coffee and bakery chain across Crete: eight shops from Heraklion to Chania, a central roastery that doubles as HQ, tills and card terminals that cannot stop, guest Wi-Fi people actually work from, and a new shop opening every few months. One network, built once as a template and stamped out per site — the do-it-yourself mechanics behind what SD-WAN products automate.
Full network · all steps built
highlighted = lines added in the selected step · earlier steps shown plain · later steps hidden
Download the full config: MikroTik .rsc · Cisco IOS .txt — illustrative, review before use
This is the Build series' first multi-site design. The earlier eight were one building each; a chain is a different problem — not a bigger network but the same network, eight times, plus a head office that ties them together and a tenth shop that has to come online next month without a van full of engineers.
It leans on three ideas that none of the single-site builds needed: write the shop once as a template and stamp it out per site, join the sites with an overlay so every shop talks to HQ and no shop talks to another, and steer the traffic that matters — the tills and the card terminals — onto the reliable link by application, not just by a backup route. That last trio is what the SD-WAN products sell; here we build the mechanics by hand so you can see what they automate.
01
A fictional but very typical Cretan chain: eight shops, a roastery that is also the office, and an owner who wants the ninth open by spring.
Each shop is small and the same: two tills with card terminals, a kitchen-display and a menu screen, three or four cameras, a back-office PC, and guest Wi-Fi that people treat like an office. The roastery / HQ holds the central POS and ERP, the loyalty and online-ordering backend, the accounts office, and a small NOC that is supposed to notice a dead shop before the shop phones in. Shops run on whatever the street offers — fibre where it exists, VDSL or 4G where it doesn't — and the card terminals must keep working through a flaky line. A new shop opens every few months, and nobody wants to send an engineer with a laptop each time.
| Requirement | Where it comes from, and what it forces |
|---|---|
| R1 Eight shops, one design | Each shop must be identical bar a site number, so a fix or a new VLAN rolls out everywhere the same way. A template, not eight hand-built routers. |
| R2 Shops reach HQ, not each other | Central POS, loyalty, CCTV viewing and config all live at HQ. A compromised shop must not be a path to a sister shop. Hub-spoke, not mesh. |
| R3 The tills cannot stop | Card payments and the HQ sync ride the reliable link and fail over on their own; guest traffic is never allowed to crowd them out. |
| R4 Two uplinks, used by purpose | Every shop has a primary and a backup WAN. The money traffic is pinned to the good one by application; bulk uses whatever is spare. |
| R5 Open a shop in a day | Ship a pre-keyed router, plug it in, it configures itself from HQ and joins the overlay. Zero-touch, no on-site engineer. |
| R6 See the whole fleet | One NOC view of all shops; a down link or a dead till pages someone before a customer notices. |
| R7 Card data stays clean | The payment path is its own segment end to end, logged, and never shares a VLAN with guests or the office (PCI hygiene). |
02
Each is a choice about building a fleet rather than a single site.
Every shop runs the same file; the only thing that changes is a site number. Addresses are 10.<site>.<vlan>.0/24, so site 3's guest network is 10.3.50.0/24 and site 7's is 10.7.50.0/24 — the config computes them from one variable. A new VLAN, a firewall fix, a DNS change: edit the template, re-render, push to all eight. Eight hand-maintained routers drift; one template doesn't.
A café in Chania never needs to reach a café in Heraklion — only HQ. So the overlay is a hub and spokes: every shop dials one WireGuard tunnel to HQ, and each shop's tunnel is scoped to HQ's addresses only. There is no route from one shop to another, which means a till compromised in one shop is a dead end, not a doorway to the chain.
Plain failover moves everything to the backup when the primary drops. That's not enough here: on a congested fibre line the card terminals can stall long before the line is "down". So the money traffic — tills to the acquirer, and the HQ tunnel — is marked and pinned to the primary with its own tracked route, while guest and bulk traffic are steered separately. This is the one idea that makes "SD-WAN" more than "dual-WAN", and RouterOS does it with mangle marks and routing tables.
Growth is the point of a chain, so provisioning can't be a bottleneck. A new router ships with a one-line bootstrap: get online, fetch sites/<serial>.rsc from HQ, import it. HQ renders that file from the same template, so the ninth shop is configured identically to the first — no laptop, no SSH session, no chance to fat-finger a VLAN at 7am before opening.
03
One octet is the site; the rest is identical everywhere. That is what makes a template possible.
| Block | Who lives here |
|---|---|
| 10.0.0.0/16 — HQ | Servers (POS/ERP .30.10, loyalty .30.11, NVR .30.20), office 10.0.20.0/24, NOC 10.0.99.0/24. |
| 10.<s>.0.0/16 — shop s | Each shop's whole network. Site 3 = 10.3.0.0/16, site 7 = 10.7.0.0/16, and so on (s = 1–8). |
| · 10.<s>.10.0/24 POS | Tills + card terminals (reserved by MAC). |
| · 10.<s>.20/30/40/50 | Office, IoT (KDS/music/menu), CCTV, Guest. |
| · 10.<s>.99.0/24 MGMT | The shop's router, switch and AP. |
| 10.255.0.0/24 — overlay | WireGuard: HQ hub .1, shop s = .<s+1>. The only subnet every device shares. |
Because a shop's whole estate is one /16, HQ needs exactly one route per shop (10.<s>.0.0/16 down its tunnel), and a shop needs exactly one route to the centre (10.0.0.0/16 up its tunnel). The plan is the routing table.
04
Who may start a connection to whom, across the whole chain.
| From ↓ / To → | May reach |
|---|---|
| Shop POS (tills) | The card acquirer (443) and the HQ POS/ERP over the tunnel. Nothing else, not even the shop's own office. |
| Shop office | HQ (files, mail) over the tunnel, and the internet. |
| Shop IoT / cameras | IoT: its vendor cloud only. Cameras: the HQ NVR over the tunnel only. |
| Shop guest | The internet only — never HQ, never the tills, never another shop. |
| HQ → shop | The NOC (management) and the central apps' return traffic. HQ is the only thing that may start a connection into a shop. |
| Shop → shop | Nothing. There is no route; the hub is the only meeting point. |
05
Every requirement from the brief, and the step that satisfies it.
| Req | Satisfied by |
|---|---|
| R1 One design, eight shops | Step 2 — the templated shop config (one variable, $SITE) |
| R2 Shops reach HQ, not each other | Step 3 — hub-spoke overlay with per-tunnel scoping |
| R3 The tills cannot stop | Steps 4 + 6 — app-aware steering + tills-first QoS |
| R4 Two uplinks by purpose | Step 4 — dual-WAN, money traffic pinned by routing mark |
| R5 Open a shop in a day | Step 7 — zero-touch provisioning from HQ |
| R6 See the whole fleet | Step 8 — centralised monitoring + alerting (the NOC) |
| R7 Card data stays clean | Steps 5 + 9 — payment segment, logging, PCI hygiene |
06 · Step 1 of 9
The head office is the centre of the star: the central servers, the NOC, and the one WireGuard endpoint every shop dials.
▲ Show step 1 in the interactive topology · select HQ-R1 for its config
! HQ-R1 — C8300: the DMVPN hub + server VLAN + NOC. One mGRE tunnel; every shop is a spoke. hostname HQ-R1 ip routing vlan 20,30,99 interface GigabitEthernet0/0/1 switchport mode trunk switchport trunk allowed vlan 20,30,99 interface Vlan20 ip address 10.0.20.1 255.255.255.0 interface Vlan30 ip address 10.0.30.1 255.255.255.0 interface Vlan99 ip address 10.0.99.1 255.255.255.0 ! the overlay hub: one multipoint GRE tunnel, IPsec-protected; shops register via NHRP interface Tunnel0 ip address 10.255.0.1 255.255.255.0 ip nhrp network-id 1 ip nhrp map multicast dynamic tunnel source GigabitEthernet0/0/0 tunnel mode gre multipoint tunnel protection ipsec profile DMVPN ! phase-1 DMVPN (no spoke-to-spoke): the hub routes everything, so shops never reach each other router eigrp 1 network 10.255.0.0 0.0.0.255 network 10.0.0.0 0.0.255.255
# HQ-R1 — CCR2004: the hub. Server VLAN, the NOC, and the WireGuard head-end every shop dials. /system identity set name=HQ-R1 /interface bridge add name=bridge vlan-filtering=yes /interface bridge port add bridge=bridge interface=ether2 frame-types=admit-only-vlan-tagged comment="HQ switch" /interface bridge vlan add bridge=bridge vlan-ids=20,30,99 tagged=bridge,ether2 /interface vlan add name=v20-office interface=bridge vlan-id=20 add name=v30-srv interface=bridge vlan-id=30 add name=v99-noc interface=bridge vlan-id=99 /ip address add address=10.0.20.1/24 interface=v20-office add address=10.0.30.1/24 interface=v30-srv add address=10.0.99.1/24 interface=v99-noc # the overlay head-end: one WireGuard interface, one peer per shop /interface wireguard add name=wg-hub listen-port=51820 /ip address add address=10.255.0.1/24 interface=wg-hub # each shop is a peer: its overlay /32 + its whole 10.<id>.0.0/16 behind it /interface wireguard peers add interface=wg-hub public-key="<shop-03 pubkey>" \ allowed-address=10.255.0.4/32,10.3.0.0/16 comment="shop-03 Rethymno" # HQ routes each shop's block back down its tunnel /ip route add dst-address=10.3.0.0/16 gateway=10.255.0.4
HQ is deliberately simple: a server VLAN for the central POS/ERP, loyalty and the NVR; a management VLAN for the NOC; and a single WireGuard interface that is the hub of the star. Every shop is one peer, scoped with allowed-address to its own overlay address plus its /16 — so HQ knows exactly which block sits behind each tunnel, and a shop can't claim another shop's addresses.
/interface wireguard peers print shows a recent handshake.07 · Step 2 of 9
One config, stamped out per site. The only thing that changes is a number.
▲ Show step 2 in the interactive topology · select SHOP-R1 or SHOP-SW
! SHOP-R1 — C1121X: the templated shop. PnP / a template renders the per-site values (site 3 here). hostname SHOP-3 ip routing vlan 10,20,30,40,50,99 interface GigabitEthernet0/0/1 switchport mode trunk switchport trunk allowed vlan 10,20,30,40,50,99 interface Vlan10 ip address 10.3.10.1 255.255.255.0 interface Vlan20 ip address 10.3.20.1 255.255.255.0 interface Vlan30 ip address 10.3.30.1 255.255.255.0 interface Vlan40 ip address 10.3.40.1 255.255.255.0 interface Vlan50 ip address 10.3.50.1 255.255.255.0 interface Vlan99 ip address 10.3.99.1 255.255.255.0 ! the fleet plan: every address is 10.<site>.<vlan>.1 — the template substitutes the site octet ip dhcp excluded-address 10.3.50.1 10.3.50.9 ip dhcp pool GUEST network 10.3.50.0 255.255.255.0 default-router 10.3.50.1 dns-server 9.9.9.9 1.1.1.1 lease 0 2 ! tills + card terminals are reserved by MAC (no dynamic pool on VLAN 10) ip name-server 9.9.9.9 1.1.1.1
# SHOP-R1 — hAP ax: the shop template. The ONLY thing that changes per shop is $SITE.
:global SITE 3
/system identity set name=("SHOP-" . $SITE)
/interface bridge add name=bridge vlan-filtering=yes
/interface bridge port add bridge=bridge interface=ether2 frame-types=admit-only-vlan-tagged comment="SHOP switch"
/interface bridge vlan add bridge=bridge vlan-ids=10,20,30,40,50,99 tagged=bridge,ether2
/interface vlan
add name=v10-pos interface=bridge vlan-id=10
add name=v20-office interface=bridge vlan-id=20
add name=v30-iot interface=bridge vlan-id=30
add name=v40-cctv interface=bridge vlan-id=40
add name=v50-guest interface=bridge vlan-id=50
add name=v99-mgmt interface=bridge vlan-id=99
# the fleet plan: 10.<SITE>.<vlan>.1/24 — identical everywhere but the SITE octet
/ip address add address=("10." . $SITE . ".10.1/24") interface=v10-pos
# … .20 / .30 / .40 / .50 / .99 the same way
/ip dhcp-server add name=d-guest interface=v50-guest address-pool=p-guest lease-time=2h
/ip dhcp-server add name=d-pos interface=v10-pos address-pool=static-only lease-time=1d
# … office + iot pools; the tills and card terminals are reserved by MAC
/ip dns set allow-remote-requests=yes servers=9.9.9.9,1.1.1.1! SHOP-SW — Catalyst 1000-8P: tills, KDS, camera, AP trunk, uplink. Identical in every shop. vtp mode transparent vlan 10,20,30,40,50,99 interface range GigabitEthernet1/0/1 - 2 description tills / card terminal switchport mode access switchport access vlan 10 spanning-tree portfast interface GigabitEthernet1/0/3 description KDS / menu screen switchport access vlan 30 interface GigabitEthernet1/0/4 description camera switchport access vlan 40 interface GigabitEthernet1/0/8 description cAP AP (trunk) switchport mode trunk switchport trunk native vlan 99 switchport trunk allowed vlan 20,50,99 interface GigabitEthernet1/0/10 description uplink SHOP-R1 switchport mode trunk switchport trunk allowed vlan 10,20,30,40,50,99
# SHOP-SW — CRS112-8P-4S: tills, KDS, cameras, an AP trunk, uplink to the router. Identical in every shop.
/system identity set name=("SHOP-" . $SITE . "-SW")
/interface bridge add name=bridge vlan-filtering=yes
/interface bridge port
add bridge=bridge interface=ether1 frame-types=admit-only-vlan-tagged comment="uplink SHOP-R1"
add bridge=bridge interface=ether2 pvid=10 comment="till 1"
add bridge=bridge interface=ether3 pvid=10 comment="till 2 / card terminal"
add bridge=bridge interface=ether4 pvid=30 comment="KDS / menu screen"
add bridge=bridge interface=ether5 pvid=40 comment="camera"
add bridge=bridge interface=ether8 pvid=99 comment="cAP ax (trunk)"
/interface bridge vlan
add bridge=bridge vlan-ids=10,30,40 tagged=ether1
add bridge=bridge vlan-ids=20,50,99 tagged=ether1,ether8
add bridge=bridge vlan-ids=99 tagged=bridgeThe shop is the coffee-shop build in miniature, but written so a machine can produce it: every address is derived from $SITE. In production you don't type $SITE by hand — HQ substitutes it when it renders the file (step 7). The switch is the same in every shop, so there is nothing site-specific on it at all.
$SITE to 7 and re-run on a lab router: every address becomes 10.7.x with no other edit./interface bridge vlan print: the POS VLAN is tagged only toward the router, never on the AP trunk.08 · Step 3 of 9
One tunnel per shop, up to the hub. Shops reach HQ and central services — and, by design, nothing of each other.
▲ Show step 3 in the interactive topology · select SHOP-R1
! SHOP-R1 — a DMVPN spoke to the HQ hub. Spokes register with the hub, never each other. interface Tunnel0 ip address 10.255.0.4 255.255.255.0 ip nhrp network-id 1 ip nhrp nhs 10.255.0.1 nbma hq.cafe.example multicast tunnel source GigabitEthernet0/0/0 tunnel mode gre multipoint tunnel protection ipsec profile DMVPN router eigrp 1 network 10.255.0.0 0.0.0.255 network 10.3.0.0 0.0.255.255 ! no NHRP shortcut here on purpose — phase-1 hub-spoke, so a shop reaches HQ and central ! services but has no route to a sister shop; the hub is the only meeting point
# SHOP-R1 — one tunnel up to HQ. A shop reaches HQ and central services, never another shop.
/interface wireguard add name=wg-hq listen-port=51820
/interface wireguard peers add interface=wg-hq public-key="<HQ hub pubkey>" \
endpoint-address=hq.cafe.example endpoint-port=51820 \
allowed-address=10.0.0.0/16,10.255.0.0/24 persistent-keepalive=25s
/ip address add address=("10.255.0." . ($SITE + 1) . "/24") interface=wg-hq
# central services (POS/ERP/loyalty at HQ) are reached over the tunnel; the default stays local (step 4)
/ip route add dst-address=10.0.0.0/16 gateway=10.255.0.1
# allowed-address scopes the tunnel to HQ's blocks only — there is no route to 10.<other-shop>,
# so a compromised shop cannot reach a sister shop; the hub is the only meeting pointThis is the heart of hub-spoke. A shop's tunnel is allowed to carry only HQ's 10.0.0.0/16 and the overlay subnet — not 10.<other>.0.0/16. So even though all eight shops terminate on the same hub, no shop has a route to any other. HQ, holding every peer, could route shop-to-shop, but doesn't: the policy matrix (and step 5's firewall) keep the hub a destination, not a transit.
Hub-spoke isolation lives at the hub. Because HQ terminates every tunnel, a misconfigured HQ firewall (or a compromised HQ) can bridge shops. HQ's own forward rules must permit shop↔HQ only, never shop↔shop, and the hub gets the hardening of the whole chain's crown jewels — it is the one box that, if lost, loses everyone.
/ping 10.255.0.1 (the hub) succeeds; the handshake is recent at both ends.09 · Step 4 of 9
Two uplinks, but the card terminals don't just "fail over" — they ride the good link by name, and move only when they have to.
▲ Show step 4 in the interactive topology · select SHOP-R1
! SHOP-R1 — two WANs; PBR pins the card path to WAN1 with a tracked fallback to WAN2. interface GigabitEthernet0/0/0 description WAN1 fibre ip address dhcp ip nat outside interface Cellular0/1/0 description WAN2 4G ip nat outside ip sla 1 icmp-echo 1.1.1.1 source-interface GigabitEthernet0/0/0 frequency 5 ip sla schedule 1 life forever start-time now track 1 ip sla 1 reachability ! the money path: tills -> acquirer, pinned to WAN1, falling to 4G if the track drops ip access-list extended MONEY permit tcp 10.3.10.0 0.0.0.255 host <acquirer> eq 443 route-map PBR-MONEY permit 10 match ip address MONEY set ip next-hop verify-availability <wan1-gw> 1 track 1 set ip next-hop <wan2-gw> interface Vlan10 ip policy route-map PBR-MONEY ! everything else: WAN1 primary, WAN2 floating backup ip route 0.0.0.0 0.0.0.0 dhcp 1 track 1 ip route 0.0.0.0 0.0.0.0 Cellular0/1/0 2 ip nat inside source list NAT-ALL interface GigabitEthernet0/0/0 overload
# SHOP-R1 — two WANs; the money traffic is steered by APPLICATION, not just a backup route. /interface list add name=WAN /interface list member add list=WAN interface=ether1 add list=WAN interface=lte1 /ip dhcp-client add interface=ether1 use-peer-dns=no comment="WAN1 fibre/VDSL" /ip dhcp-client add interface=lte1 use-peer-dns=no add-default-route=no comment="WAN2 4G" /ip firewall nat add chain=srcnat action=masquerade out-interface-list=WAN # mark what MUST take the reliable path: tills, card terminals, and the HQ tunnel /ip firewall mangle add chain=prerouting src-address-list=POS dst-address-list=ACQUIRER action=mark-routing new-routing-mark=money passthrough=no add chain=prerouting out-interface=wg-hq action=mark-routing new-routing-mark=money passthrough=no # the money mark prefers WAN1, fails to WAN2; the default (guest + bulk) does the same, separately /ip route add dst-address=0.0.0.0/0 gateway=ether1 routing-mark=money check-gateway=ping distance=1 /ip route add dst-address=0.0.0.0/0 gateway=lte1 routing-mark=money check-gateway=ping distance=2 /ip route add dst-address=0.0.0.0/0 gateway=ether1 check-gateway=ping distance=1 /ip route add dst-address=0.0.0.0/0 gateway=lte1 check-gateway=ping distance=2
Two routing tables, one per purpose. Traffic tagged money (tills to the acquirer, and the HQ tunnel) has its own default route that prefers WAN1 and falls to WAN2 on a failed check-gateway ping. Everything else uses the main table, which is steered the same way but independently — so you can, for example, hold guests on WAN1 while pushing the card path to WAN2 during a partial outage, or cap the 4G so a failover doesn't produce a surprise bill. That selectivity — moving an application, not the whole site — is the difference between dual-WAN and SD-WAN.
When WAN1 drops, the money traffic belongs on 4G — but a shop full of guests streaming does not. Keep the guest/bulk default's failover conservative (or shape it hard on WAN2), or a ten-minute fibre blip becomes a data-cap overage. The point of steering by application is precisely to send the €2 of card traffic over 4G and leave the €200 of video behind.
/ip route print where routing-mark=money shows the active gateway following the healthy WAN.10 · Step 5 of 9
The payment path reaches two things and no more; guests reach the internet and nothing of ours.
▲ Show step 5 in the interactive topology · select SHOP-R1
! SHOP-R1 — Zone-Based Firewall. The payment zone reaches the acquirer + HQ only. zone security POS zone security OFFICE zone security IOT zone security CCTV zone security GUEST zone security HQ zone security WAN interface Vlan10 zone-member security POS interface Vlan20 zone-member security OFFICE interface Vlan30 zone-member security IOT interface Vlan40 zone-member security CCTV interface Vlan50 zone-member security GUEST interface Tunnel0 zone-member security HQ interface GigabitEthernet0/0/0 zone-member security WAN class-map type inspect match-any CM-GEN match protocol tcp match protocol udp match protocol icmp policy-map type inspect PM-OUT class type inspect CM-GEN inspect class class-default drop ! tills -> the acquirer (443) and the HQ POS server, nothing else ip access-list extended ACL-POS permit tcp 10.3.10.0 0.0.0.255 host <acquirer> eq 443 permit ip 10.3.10.0 0.0.0.255 10.0.30.0 0.0.0.255 class-map type inspect match-all CM-POS match access-group name ACL-POS policy-map type inspect PM-POS class type inspect CM-POS inspect class class-default drop zone-pair security ZP-POS-WAN source POS destination WAN service-policy type inspect PM-POS zone-pair security ZP-POS-HQ source POS destination HQ service-policy type inspect PM-POS ! guest -> internet only; cameras -> HQ NVR; office -> HQ + internet zone-pair security ZP-GUEST-WAN source GUEST destination WAN service-policy type inspect PM-OUT zone-pair security ZP-CCTV-HQ source CCTV destination HQ service-policy type inspect PM-OUT zone-pair security ZP-OFFICE-WAN source OFFICE destination WAN service-policy type inspect PM-OUT zone-pair security ZP-OFFICE-HQ source OFFICE destination HQ service-policy type inspect PM-OUT
# SHOP-R1 — the tills reach the card acquirer and HQ only; guests get the internet and nothing of ours. /ip firewall address-list add list=ACQUIRER address=pay.acquirer.example add list=POS address=10.3.10.0/24 /ip firewall filter add chain=forward connection-state=established,related,untracked action=accept add chain=forward connection-state=invalid action=drop # tills: the acquirer (card, 443) + the HQ POS/ERP over the tunnel, nothing else add chain=forward in-interface=v10-pos dst-address-list=ACQUIRER protocol=tcp dst-port=443 action=accept add chain=forward in-interface=v10-pos out-interface=wg-hq dst-address=10.0.30.0/24 action=accept comment="POS -> HQ ERP/loyalty" add chain=forward in-interface=v10-pos action=drop log=yes log-prefix=POS-DROP # cameras record to the HQ NVR over the tunnel; office reaches HQ + internet; guest internet only add chain=forward in-interface=v40-cctv out-interface=wg-hq dst-address=10.0.30.20 action=accept comment="cameras -> HQ NVR" add chain=forward in-interface=v50-guest out-interface-list=WAN action=accept comment="guest -> internet only" add chain=forward in-interface=v20-office action=accept add chain=forward in-interface=v30-iot out-interface-list=WAN protocol=tcp dst-port=443 action=accept comment="music/KDS cloud" add chain=forward action=drop log=yes log-prefix=FWD-DROP
The payment VLAN is the tightest thing in the shop: it may reach the acquirer on 443 and the HQ POS server over the tunnel, and that is the whole list — not the office PC two metres away, not the internet at large. Guests are the opposite extreme: the internet and nothing else, enforced by sending them straight out the WAN and dropping anything aimed inward. Cameras don't keep footage locally; they stream to the HQ NVR over the tunnel, which also means a shop break-in can't erase the recording.
POS-DROP).11 · Step 6 of 9
People treat café Wi-Fi like an office. Let them — but never at the cost of a card going through.
▲ Show step 6 in the interactive topology · select SHOP-R1
! SHOP-R1 — MQC gives the tills priority and shares the rest to guests; guest portal is CWA on the EWC. class-map match-all CM-TILLS match access-group name ACL-POS class-map match-all CM-GUEST match vlan 50 policy-map SHOP-WAN class CM-TILLS priority percent 10 class CM-GUEST bandwidth remaining percent 80 fair-queue class class-default fair-queue interface GigabitEthernet0/0/0 service-policy output SHOP-WAN ! the guest Wi-Fi itself is a Catalyst 9800 EWC WLAN with web-consent (as in the coffee-shop build)
# SHOP-R1 — captive-portal guest Wi-Fi, fair per device, and a guarantee the tills always transmit. /ip hotspot setup # (guest on v50, a click-through 'trial' profile; per-device pcq limits, as in the coffee-shop build) # mark the money traffic so the queue can protect it /ip firewall mangle add chain=forward src-address-list=POS action=mark-packet new-packet-mark=pos passthrough=no /ip firewall mangle add chain=forward in-interface=v50-guest action=mark-packet new-packet-mark=guest passthrough=no /queue type add name=guest-pcq kind=pcq pcq-rate=5M pcq-classifier=dst-address /queue tree add name=up parent=global max-limit=50M add name=pos-up parent=up packet-mark=pos limit-at=5M max-limit=50M priority=1 add name=guest-up parent=up packet-mark=guest max-limit=40M queue=guest-pcq priority=8 # priority 1 vs 8: under contention the tills get served first, guests share what is left
Guest Wi-Fi is a feature customers choose the café for, so it gets real bandwidth — but it sits under a queue that hands the tills a guaranteed slice and the highest priority. On a busy Saturday with forty phones streaming, a card transaction is a tiny, high-priority flow that jumps the queue; the guests simply share whatever is left, fairly, per device. The captive portal (a click-through "trial" page) keeps the shop out of arguments about who was on the Wi-Fi when.
/queue tree print stats: drops land on the guest queue, not the POS queue.12 · Step 7 of 9
Opening the ninth shop should be: ship a router, plug it in, pour the coffee. No engineer, no laptop.
▲ Show step 7 in the interactive topology · select SHOP-R1
! Cisco's zero-touch is Network Plug-and-Play (PnP): a factory-fresh router finds the PnP server ! (DHCP option 43, DNS, or the cloud redirect) and pulls its config + image with no console session. pnp profile ztp transport https ipv4 pnp.cafe.example port 443 ! the per-site config is a template in Cisco DNA Center (or a lightweight PnP server) with the site ! variables — exactly like the rendered .rsc on the MikroTik side. For eight cafés a small PnP server ! is plenty; DNA Center is the product you reach for at hundreds of sites.
# Opening a shop: plug the router in, it fetches its own config from HQ. No truck roll with a laptop. # the factory/default config carries only a bootstrap WAN DHCP + the provisioning key, then runs ztp: /system script add name=ztp source={ :global SITE [/system routerboard get serial-number] /tool fetch url=("https://provision.cafe.example/sites/" . $SITE . ".rsc") dst-path=site.rsc /import file-name=site.rsc } /system scheduler add name=firstboot start-time=startup interval=0 on-event=ztp # HQ renders sites/<serial>.rsc from the ONE template + that site's variables (SITE id, keys, WAN type) # opening shop #9 is: ship a pre-keyed router, staff plug it in, it joins the overlay in minutes
Zero-touch turns a site opening from an engineering visit into a logistics task. The router ships with a one-screen default: come up on WAN DHCP, reach the provisioning server, pull sites/<serial>.rsc, import it, reboot into the real config. HQ generates that file from the same template every other shop uses — so the ninth shop is, byte for byte, configured like the first. The serial number (or a QR sticker scanned at HQ when the box is keyed) is the only thing that ties a physical router to a site.
The dangerous moment is first boot, before the tunnel exists: the router fetches config over the open internet. Serve the provisioning file over HTTPS with a pinned CA, key each router at HQ (so a stolen serial can't pull a config), and make the provisioning server refuse a serial that's already claimed. Get this wrong and "zero-touch" becomes "anyone-touch".
.rsc, and comes up fully configured with its tunnel to HQ.13 · Step 8 of 9
The NOC should know a shop is down before the shop knows. One view of eight sites, and a page when one goes dark.
▲ Show step 8 in the interactive topology · select HQ-R1
! HQ + shops — SNMP/syslog to the NOC over the overlay. The monitoring stack is vendor-neutral: ! argus (VictoriaMetrics + Grafana + Alertmanager) scrapes SNMP the same whatever the routers are. snmp-server community <ro> RO 99 snmp-server host 10.0.99.20 version 2c <ro> logging host 10.0.99.20 logging trap warnings ! on IOS-XE you can push model-driven telemetry (gNMI/gRPC) instead of polling ! an ACL (step 9) keeps SNMP/SSH reachable only from the overlay + the NOC
# HQ — the NOC watches the fleet. A shop that goes dark pages before a barista calls. # argus stack (VictoriaMetrics + Grafana + vmalert + Alertmanager) scrapes each shop over the overlay /snmp set enabled=yes contact=noc@cafe.example /snmp community set [find default=yes] addresses=10.255.0.0/24 comment="poll only over the tunnel" /system logging action add name=noc target=remote remote=10.0.99.20 /system logging add topics=warning,error action=noc # a per-site Grafana dashboard + one fleet overview; Alertmanager -> the on-call bot # (every shop pushes the same metric names, so one dashboard template fits all 8)
Because every shop is identical, monitoring is too: the same SNMP metrics and log topics from all eight, scraped over the overlay (never the public internet), into one time-series store. A single Grafana dashboard template renders per-site, and a fleet overview shows all eight at a glance. The alert that matters most is the simplest — a shop whose tunnel or WAN has been down for two minutes pages the on-call before the morning queue notices the card machine is dead.
14 · Step 9 of 9
Managed from one place, backed up to one place, and the card path kept clean end to end.
▲ Show step 9 in the interactive topology · select SHOP-R1
! SHOP-R1 — SSH from the NOC/overlay only; config archived to HQ nightly; card path kept PCI-clean. no ip http server no ip http secure-server ip ssh version 2 username netadmin privilege 15 secret 0 ******** no username admin ip access-list standard MGMT-IN permit 10.0.99.0 0.0.0.255 permit 10.255.0.0 0.0.0.255 line vty 0 4 transport input ssh access-class MGMT-IN in login local archive path scp://backup@10.0.99.20/cafe-shop kron occurrence NIGHTLY at 3:30 recurring policy-list SAVE kron policy-list SAVE cli show running-config | redirect scp://backup@10.0.99.20/shop-latest.cfg ! PCI: the card path stays on VLAN 10 end to end, logged, never shared with guest or office
# SHOP-R1 — managed from the NOC over the tunnel; config backed up to HQ nightly; the card path kept clean. /ip service disable telnet,ftp,www,api,api-ssl /ip service set ssh address=10.0.99.0/24,10.255.0.0/24 /ip service set winbox address=10.0.99.0/24,10.255.0.0/24 /user set admin disabled=yes /user add name=netadmin group=full password=******** # nightly export up to HQ over the tunnel; rollback = re-render from the template + re-push /system scheduler add name=nightly start-time=03:30:00 interval=1d on-event={ /export file=latest ; /tool fetch upload=yes url="sftp://10.0.99.20/backups/" src-path=latest.rsc user=backup } # PCI: the card path (tills -> acquirer) sits on its own VLAN, is logged, and never shares with guest or office
Management only happens from the NOC, over the tunnel — the shops expose nothing to the street. Every shop exports its config to HQ nightly, which gives both a backup and an audit trail of drift; because the real source of truth is the template, "rollback" is just re-rendering and re-pushing. The card path keeps the discipline PCI expects: its own VLAN from till to acquirer, logged at the drop, and never co-mingled with guest or office traffic — the segmentation isn't a nicety, it's what keeps the chain's card handling in scope-control.
15
A chain fails one shop at a time, quietly. Test the failures, and test that a change rolls out the same everywhere.
| Test | Pass looks like |
|---|---|
| Template parity | Re-render the template for two different sites; the configs differ only in the site octet and keys. |
| Spoke isolation | From shop 3, every address in shop 7 is unreachable; only HQ answers. |
| App-aware failover | Kill WAN1: a card sale completes on 4G in seconds; guests are throttled, not the tills. |
| Zero-touch | A factory-reset router joins the overlay from the provisioning server with no console session. |
| Fleet alerting | A dark shop pages the on-call within two minutes, naming the site. |
| Backup + rollback | Restore a shop from HQ's nightly export (or re-render) and it comes back identical. |
16
What the network can't do on its own, and what covers each gap.
17
I test networks like this for a living. On a chain the prize is the card data and the hub — here's what I'd try, and why each stays bounded.
18
Almost all of this runs in a lab — a fleet is exactly the kind of thing you want to test before it's eight real shops.
| Runs in a lab | Doesn't — needs the real thing |
|---|---|
| One CHR as HQ and three as shops: the overlay, spoke isolation, routing and firewall all behave exactly as on metal. | The 4G link's real behaviour (latency, caps) — a lab gives you failover logic, not a true cellular path. |
| Zero-touch: a provisioning web server + a factory-default CHR that fetches and imports — the whole flow, end to end. | The physical "ship a box, staff plug it in" step — but the config side is fully testable. |
| App-aware steering: give the shop CHR two upstream CHRs as WAN1/WAN2 and pull one; watch the money mark follow. | Captive-portal UX and per-device Wi-Fi fairness — a bench AP proves the config, not the café. |
19
Indicative EU street prices, late 2026, excluding VAT. Per shop plus the one-off HQ.
| Item | Indicative (EUR, ex VAT) |
|---|---|
| Per shop · router (hAP ax³ or RB5009) + 4G | 180 – 320, plus a data SIM |
| Per shop · switch (CRS112-8P) + cAP ax | 180 – 260 |
| Per shop total | ≈ 360 – 580 + cabling |
| HQ · hub router (CCR2004) + switch | 700 – 1,000 |
| HQ · provisioning + monitoring (one small server/VM for argus + the ZTP web server) | reuse existing, or ≈ 400 – 800 |
| Eight shops + HQ | ≈ 4,000 – 6,000, plus per-shop WAN and SIM running costs |
Appendix
Most of this maps to IOS; one word of honesty about "SD-WAN".
The shop and HQ routers become ISRs (a C1121X per shop, a C8300 at HQ); VLANs and SVIs, DHCP, the Zone-Based Firewall and the QoS (MQC with a priority class for the tills) all have direct equivalents. The overlay is DMVPN (a hub-spoke design by nature) or FlexVPN, and app-aware steering is PBR with tracked next-hops — the same mechanics by different names.
Real Cisco SD-WAN is Catalyst SD-WAN (Viptela) with vManage — a controller that automates exactly what we built by hand: the overlay, the per-application policy, and zero-touch onboarding through PnP. For eight cafés the DIY DMVPN + PBR approach is the right size and cost; vManage (or Meraki, or a Fortinet/VeloCloud fabric) earns its licensing when the fleet is hundreds of sites and the policy changes weekly. This build teaches the mechanics those products package; knowing them is how you tell whether you need the product.
Takeaways
Part of the Build series. A single node of this chain is the coffee shop; the operator-hub idea also appears in the villa and the farm.
I build and manage multi-site networks for chains and franchises: one templated design across every branch, an encrypted overlay to head office, payments kept clean, and a new site online in a day — all watched from one place so a dead shop pages me before it costs you a morning's sales.
Talk about your sites →