diff --git a/docs/deploy-and-configure/orb-lan-tester.md b/docs/deploy-and-configure/orb-lan-tester.md
new file mode 100644
index 0000000..3f5fbd4
--- /dev/null
+++ b/docs/deploy-and-configure/orb-lan-tester.md
@@ -0,0 +1,250 @@
+---
+title: Orb LAN Tester
+shortTitle: Orb LAN Tester
+metaDescription: Configure a single Wi-Fi+Ethernet device to measure LAN performance to router and back.
+section: Deploy & Configure
+---
+
+
+# Orb LAN Tester
+
+:::danger
+This guide uses features from [Endpoints & Engines](/docs/deploy-and-configure/endpoints) that are experimental, and not yet intended for production environments. We appreciate your testing and feedback. Please use our [Help & Support](https://orb.net/support) page or [Discord](https://discord.gg/orbforge) to report issues and ask questions.
+:::
+
+
+This guide walks you through setting up an **Orb LAN Tester**: a dual-interface device that measures the real-world performance of your Wi-Fi network by routing Orb measurement traffic from a Wi-Fi interface, through your router, and back to an Ethernet-connected Orb measurement server β all from a single device.
+
+This setup gives you a clean way to isolate and analyze Wi-Fi network performance. You'll receive realistic and full-fidelity Orb measurements of the network path from a Wi-Fi client to your router, and back to an Ethernet client.
+
+We'll be setting up 2 Orbs on your device:
+1. An Orb Docker container, with self-contained DHCP client, bound to the Ethernet interface (using `macvlan` driver as detailed in the [multi-interface setup guide](/docs/setup-sensor/docker-multiple-interfaces)).
+2. An Orb bound to the Wi-Fi interface, testing to the resolved private IP of the Ethernet Orb container on the network (technically it's bound to the default interface, but we'll make sure Wi-Fi interface is the default).
+
+Even though both Orbs run on the same device, traffic actually traverses your network while measuring from the Wi-Fi Orb to the Ethernet Orb (container), giving you a measurement of the LAN loop.
+
+
+
+
+---
+
+## π§° Requirements
+
+- A Debian-based system (e.g. Raspberry Pi OS, Ubuntu)
+- Both **Wi-Fi (`wlan0`) and Ethernet (`eth0`) connected**
+- An Orb Cloud account
+
+> In this guide we use a **Raspberry Pi 4 Model B**, but any Debian host with both interfaces works.
+
+---
+
+## βοΈ Step 1: Create Two Orb Configurations
+
+In [Orb Cloud Orchestration tab](https://cloud.orb.net/orchestration), create two sensor configurations, and copy the Deployment Token for each.
+
+### 1. Config for the Wi-Fi Orb
+
+Give this configuration a reconizable name like `Orb Lan Tester (Wi-Fi)` (recommended, name whatever you like).
+
+This configuration will be used by the Wi-Fi interface Orb running on the host. This will be the Orb measuring the "LAN Loop".
+
+- Uses `orb-lan-tester-ethernet.local` as the measurement endpoint for both Speed and Responsiveness testing. This will be mapped to the resolved IP of the Orb Ethernet container at run time.
+- Collects Wi-Fi metrics (RSSI, link quality, etc.)
+- Sends analytics data to Orb Cloud Analytics (alternatively, you can configure [Orb Local Analytics](/docs/deploy-and-configure/local-analytics))
+
+
+
+#### Advanced Config
+```json
+{
+ "datasets.cloud_push": [
+ "scores_1m",
+ "speed_results",
+ "responsiveness_1s",
+ "web_responsiveness_results",
+ "wifi_link_1s"
+ ],
+ "datasets.identifiable": [
+ "true"
+ ],
+ "orb.identifiable_level": [
+ "full"
+ ],
+ "collectors.response.lag_endpoints": [
+ "h3://orb-lan-tester-ethernet.local:7443"
+ ],
+ "collectors.bandwidth.speed_servers": [
+ "orb://orb-lan-tester-ethernet.local:7443"
+ ],
+ "collectors.bandwidth.content_interval": [
+ "1h"
+ ]
+}
+```
+
+
+### 2. Config for the Ethernet Orb (Container)
+Give this configuration a reconizable name like `Orb Lan Tester (Ethernet)` (recommended, name whatever you like).
+
+This configuration will be used by the Wi-Fi interface Orb running on the host. This will be the Orb acting as a measurement server for the LAN Loop.
+In addition to acting as a server, this Orb will also measure the WAN connectivity (default behavior).
+Since we are focusing on the LAN performance measurement in this guide, we will disable Speed test measurement for this Orb to keep it's WAN measurements very lightweight.
+
+- Disables Speed measurement
+- Sends analytics data to Orb Cloud Analytics (alternatively, you can configure [Orb Local Analytics](/docs/deploy-and-configure/local-analytics))
+
+
+
+---
+
+## βοΈ Step 2: Run the Setup Script
+
+Export your tokens:
+
+```bash
+export ORB_DEPLOYMENT_TOKEN_WIFI="your-wifi-deployment-token"
+export ORB_DEPLOYMENT_TOKEN_ETHERNET="your-ethernet-deployment-token"
+```
+
+Optionally, override the Orb names:
+
+```bash
+export HOST_ORB_NAME="custom-name-for-wifi-orb"
+export ETH_ORB_NAME="custom-name-for-ethernet-orb"
+```
+
+Then run the setup:
+
+```bash
+curl -fsSL https://orb.net/docs/scripts/orb-lan-tester/setup.sh | sudo -E sh
+```
+
+This script will:
+
+- Install Docker
+- Configure Wi-Fi as the preferred interface
+- Enable ARP filtering to avoid multi-interface routing issues
+- Install Orb directly on the host (Wi-Fi)
+- Start a Docker Orb bound to Ethernet using macvlan
+- Install a scheduled helper to resolve the Orb Ethernet containerβs real DHCP IP and update `/etc/hosts` to ensure `orb-lan-tester-ethernet.local` resolves to it
+- Ensure everything self-heals across reboots and interface changes
+
+After completion, the device will reboot.
+
+---
+
+## π Step 3: Verify the Setup
+
+Once the device comes back online:
+
+```bash
+getent hosts orb-lan-tester-ethernet.local
+```
+
+You should see something like:
+
+```
+192.168.1.42 orb-lan-tester-ethernet.local
+```
+
+This IP is dynamically tracked and updated automatically.
+
+**NOTE:** it may take up to 30 seconds for the hosts file to be updated on changes. It is expected for Orb measurements to time out briefly on startup while things are being initialized.
+
+---
+
+## π§ Step 4: Understand How the Loop Works
+
+Your system is now running:
+
+| Component | Interface | Role |
+|------------------|----------|------|
+| Host Orb | Wi-Fi | Test source (captures Wi-Fi metrics in addition to Responsiveness, Reliability, and Speed measurements) |
+| Docker Orb | Ethernet | Test target (also measures WAN connectivity) |
+
+When the Wi-Fi Orb runs tests against:
+
+```
+orb-lan-tester-ethernet.local
+```
+
+Traffic flows:
+
+```
+WiFi β Router/AP β Ethernet β Docker Orb
+```
+
+This ensures:
+
+- No kernel shortcutting
+- Real RF + LAN traversal
+- Accurate Wi-Fi performance measurement
+
+---
+
+## π Step 4: View Results in Orb Cloud
+
+In Orb Cloud, use Analytics and/or Live View for the **Wi-Fi Orb** to visualize the LAN performance of your Wi-Fi network.
+
+## π§ Why This Works
+
+Your system is now running:
+
+| Component | Interface | Role |
+|------------------|----------|------|
+| Host Orb | Wi-Fi | Test source (captures Wi-Fi metrics in addition to Responsiveness, Reliability, and Speed measurements) |
+| Docker Orb | Ethernet | Test target (also measures WAN connectivity) |
+
+When the Wi-Fi Orb runs tests against:
+
+```
+orb-lan-tester-ethernet.local
+```
+
+Traffic flows:
+
+```
+WiFi β Router/AP β Ethernet β Docker Orb
+```
+
+This ensures:
+
+- No kernel shortcutting
+- Real RF + LAN traversal
+- Accurate Wi-Fi performance measurement
+
+Normally, testing from a device to itself never leaves the kernel.
+
+This setup avoids that by:
+
+- Using a Docker container with its own MAC/IP (via macvlan)
+- Resolving its real DHCP address dynamically
+- Forcing traffic to traverse your network
+
+The result is a **true loop through your LAN**, not a local shortcut.
+
+---
+
+## π Reliability & Self-Healing
+
+This setup is designed to recover automatically:
+
+- If Ethernet or Wi-Fi disconnects β it recovers when restored
+- If DHCP IP changes β `/etc/hosts` updates automatically
+- On reboot β everything comes back up cleanly
+
+Once both interfaces are active, the system should always return to a good state.
+It is expected that Orb measurements may time out or be invalid for up to 30 seconds after both interfaces are up and in a good state, while the host overrides are adjusted.
+
+---
+
+## β
Summary
+
+You now have:
+
+- A dual-interface Orb setup on a single device
+- Real Wi-Fi β LAN β Ethernet testing
+- Continuous, self-healing operation
+- Full visibility into Wi-Fi performance from Orb Cloud
+
+This is one of the most effective ways to measure **real Wi-Fi experience** without needing multiple physical devices and without including WAN connectivity in your measurements.
diff --git a/images/deploy-and-configure/orb-lan-tester-eth-config.png b/images/deploy-and-configure/orb-lan-tester-eth-config.png
new file mode 100644
index 0000000..85ca662
Binary files /dev/null and b/images/deploy-and-configure/orb-lan-tester-eth-config.png differ
diff --git a/images/deploy-and-configure/orb-lan-tester-live-view.png b/images/deploy-and-configure/orb-lan-tester-live-view.png
new file mode 100644
index 0000000..892773a
Binary files /dev/null and b/images/deploy-and-configure/orb-lan-tester-live-view.png differ
diff --git a/images/deploy-and-configure/orb-lan-tester-wifi-config.png b/images/deploy-and-configure/orb-lan-tester-wifi-config.png
new file mode 100644
index 0000000..2138921
Binary files /dev/null and b/images/deploy-and-configure/orb-lan-tester-wifi-config.png differ
diff --git a/navigation.md b/navigation.md
index f3bf73c..4cbcc6c 100644
--- a/navigation.md
+++ b/navigation.md
@@ -71,6 +71,7 @@
- [MDM](/docs/deploy-and-configure/mdm)
- [Guest Orbs](/docs/deploy-and-configure/guest-orbs)
- [Endpoints & Engines](/docs/deploy-and-configure/endpoints)
+- [Orb LAN Tester](/docs/deploy-and-configure/orb-lan-tester)
## [Integrations](/docs/integrations)
diff --git a/scripts/orb-lan-tester/setup.sh b/scripts/orb-lan-tester/setup.sh
new file mode 100644
index 0000000..f27df38
--- /dev/null
+++ b/scripts/orb-lan-tester/setup.sh
@@ -0,0 +1,353 @@
+#!/bin/sh
+set -eu
+
+SUCCESS=0
+
+cleanup() {
+ if [ "$SUCCESS" -eq 1 ]; then
+ echo
+ echo "Setup completed successfully."
+ echo "Rebooting in 10 seconds..."
+ sleep 10
+ reboot
+ else
+ echo
+ echo "Setup failed β not rebooting."
+ echo "Fix the issue and re-run the script."
+ fi
+}
+trap cleanup EXIT
+
+HOST_ORB_NAME="${HOST_ORB_NAME:-orb-lan-tester-wifi}"
+ETH_ORB_NAME="${ETH_ORB_NAME:-orb-lan-tester-ethernet}"
+ETH_HOSTS_ALIAS="${ETH_HOSTS_ALIAS:-orb-lan-tester-ethernet.local}"
+STACK_DIR="/opt/orb-ethernet"
+ENV_FILE="$STACK_DIR/.env"
+ORB_DEFAULTS="/etc/default/orb"
+
+log() {
+ printf '\n==> %s\n' "$*"
+}
+
+require_root() {
+ if [ "$(id -u)" -ne 0 ]; then
+ echo "Run as root: curl ... | sudo -E sh"
+ exit 1
+ fi
+}
+
+require_env() {
+ var_name="$1"
+ eval "var_value=\${$var_name:-}"
+ if [ -z "$var_value" ]; then
+ echo "$var_name is required"
+ exit 1
+ fi
+}
+
+set_kv_file() {
+ file="$1"
+ key="$2"
+ value="$3"
+ tmp="$(mktemp)"
+ if [ -f "$file" ]; then
+ grep -v "^${key}=" "$file" > "$tmp" || true
+ fi
+ printf '%s=%s\n' "$key" "$value" >> "$tmp"
+ install -m 0644 "$tmp" "$file"
+ rm -f "$tmp"
+}
+
+detect_wifi_conn() {
+ nmcli -t -f GENERAL.CONNECTION device show wlan0 2>/dev/null | sed -n 's/^GENERAL.CONNECTION://p' | head -n1
+}
+
+detect_eth_conn() {
+ nmcli -t -f GENERAL.CONNECTION device show eth0 2>/dev/null | sed -n 's/^GENERAL.CONNECTION://p' | head -n1
+}
+
+ensure_apt_keyring_dir() {
+ install -m 0755 -d /etc/apt/keyrings
+}
+
+ensure_docker_repo() {
+ ensure_apt_keyring_dir
+
+ if [ ! -f /etc/apt/keyrings/docker.asc ]; then
+ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
+ chmod a+r /etc/apt/keyrings/docker.asc
+ fi
+
+ CODENAME="$(. /etc/os-release && printf '%s' "$VERSION_CODENAME")"
+ ARCH="$(dpkg --print-architecture)"
+
+ cat > /etc/apt/sources.list.d/docker.list </dev/null 2>&1; then
+ printf 'eth0'
+ return 0
+ fi
+
+ nmcli connection add type ethernet ifname eth0 con-name eth0 ipv4.method auto ipv6.method auto connection.autoconnect yes >/dev/null
+ printf 'eth0'
+}
+
+write_udhcpc_script() {
+ cat > "$STACK_DIR/udhcpc-script.sh" <<'EOF'
+#!/bin/sh
+case "$1" in
+ bound|renew)
+ ip addr flush dev "$interface" 2>/dev/null || true
+ ip addr add "$ip"/"$mask" dev "$interface"
+ ip route del default 2>/dev/null || true
+ ip route add default via "$router" dev "$interface"
+ : > /etc/resolv.conf
+ for ns in $dns; do
+ echo "nameserver $ns" >> /etc/resolv.conf
+ done
+ ;;
+esac
+EOF
+ chmod 0755 "$STACK_DIR/udhcpc-script.sh"
+}
+
+write_orb_entrypoint() {
+ cat > "$STACK_DIR/orb-entrypoint.sh" <<'EOF'
+#!/bin/sh
+set -e
+udhcpc -i eth0 -s /udhcpc-script.sh -R
+exec /app/orb sensor
+EOF
+ chmod 0755 "$STACK_DIR/orb-entrypoint.sh"
+}
+
+write_compose_env() {
+ cat > "$ENV_FILE" < "$STACK_DIR/docker-compose.yml" <<'EOF'
+services:
+ orb-ethernet:
+ image: orbforge/orb:latest
+ container_name: orb-ethernet
+ entrypoint: ["/orb-entrypoint.sh"]
+ volumes:
+ - orb-ethernet-data:/root/.config/orb
+ - ./orb-entrypoint.sh:/orb-entrypoint.sh:ro
+ - ./udhcpc-script.sh:/udhcpc-script.sh:ro
+ cap_add:
+ - NET_ADMIN
+ restart: unless-stopped
+ networks:
+ - ethnet
+ environment:
+ ORB_DEVICE_NAME_OVERRIDE: ${ETH_ORB_NAME}
+ ORB_DEPLOYMENT_TOKEN: ${ORB_DEPLOYMENT_TOKEN_ETHERNET}
+ ORB_MEASURE_SERVER_ENABLED: 1
+ ORB_EPHEMERAL_MODE: 1
+ labels:
+ - "wud.watch=true"
+ - "wud.trigger.include=docker.orbeth"
+
+ wud:
+ image: ghcr.io/getwud/wud
+ container_name: wud
+ restart: unless-stopped
+ ports:
+ - "127.0.0.1:3000:3000"
+ volumes:
+ - /var/run/docker.sock:/var/run/docker.sock
+ environment:
+ WUD_WATCHER_LOCAL_WATCHBYDEFAULT: "false"
+ WUD_TRIGGER_DOCKER_ORBETH_AUTO: "true"
+ WUD_TRIGGER_DOCKER_ORBETH_PRUNE: "true"
+
+networks:
+ ethnet:
+ driver: macvlan
+ driver_opts:
+ parent: eth0
+ ipam:
+ config:
+ - subnet: 192.0.2.0/24
+ gateway: 192.0.2.1
+
+volumes:
+ orb-ethernet-data:
+EOF
+}
+
+enable_arp_filter() {
+ log "Enabling ARP filtering"
+ sysctl -w net.ipv4.conf.all.arp_filter=1
+ cat > /etc/sysctl.d/99-orb-network.conf <<'EOF'
+net.ipv4.conf.all.arp_filter=1
+EOF
+}
+
+write_hosts_updater_script() {
+ cat > /usr/local/bin/update-orb-ethernet-hosts </dev/null || true)"
+
+awk '
+{
+ keep=1
+ for (i=2; i<=NF; i++) {
+ if (\$i == "'"${ETH_HOSTS_ALIAS}"'") {
+ keep=0
+ }
+ }
+ if (keep) print
+}
+' "\$HOSTS_FILE" > "\$TMP_FILE"
+
+if [ -n "\$CONTAINER_IP" ]; then
+ printf '%s %s\n' "\$CONTAINER_IP" "\$ALIAS_NAME" >> "\$TMP_FILE"
+fi
+
+install -m 0644 "\$TMP_FILE" "\$HOSTS_FILE"
+rm -f "\$TMP_FILE"
+EOF
+
+ chmod 0755 /usr/local/bin/update-orb-ethernet-hosts
+}
+
+write_hosts_timer_service() {
+ cat > /etc/systemd/system/orb-ethernet-hosts.service <<'EOF'
+[Unit]
+Description=Update /etc/hosts with orb-ethernet container DHCP IP
+After=docker.service
+Wants=docker.service
+
+[Service]
+Type=oneshot
+ExecStart=/usr/local/bin/update-orb-ethernet-hosts
+EOF
+
+ cat > /etc/systemd/system/orb-ethernet-hosts.timer <<'EOF'
+[Unit]
+Description=Refresh orb-ethernet hosts entry every 30 seconds
+
+[Timer]
+OnBootSec=20s
+OnUnitActiveSec=30s
+AccuracySec=5s
+Unit=orb-ethernet-hosts.service
+
+[Install]
+WantedBy=timers.target
+EOF
+}
+
+require_root
+require_env ORB_DEPLOYMENT_TOKEN_WIFI
+require_env ORB_DEPLOYMENT_TOKEN_ETHERNET
+
+log "Installing prerequisites"
+export DEBIAN_FRONTEND=noninteractive
+apt-get update
+apt-get install -y ca-certificates curl gnupg lsb-release network-manager iproute2
+
+log "Installing Docker"
+ensure_docker_repo
+apt-get update
+apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
+systemctl enable docker
+systemctl start docker
+
+log "Configuring NetworkManager"
+systemctl enable NetworkManager || true
+systemctl start NetworkManager || true
+systemctl enable NetworkManager-dispatcher.service || true
+systemctl start NetworkManager-dispatcher.service || true
+
+WIFI_CONN="$(detect_wifi_conn || true)"
+if [ -z "$WIFI_CONN" ] || [ "$WIFI_CONN" = "--" ]; then
+ echo "No active WiFi connection found on wlan0"
+ exit 1
+fi
+
+ETH_CONN="$(ensure_eth_connection)"
+
+log "Setting WiFi preferred without bouncing live connections"
+nmcli connection modify "$WIFI_CONN" connection.autoconnect yes ipv4.route-metric 100 ipv6.route-metric 100
+nmcli connection modify "$ETH_CONN" connection.autoconnect yes ipv4.route-metric 200 ipv6.route-metric 200
+
+enable_arp_filter
+
+log "Installing Orb on host"
+ensure_orb_repo
+apt-get update
+apt-get install -y orb
+systemctl enable orb-update.timer
+systemctl start orb-update.timer
+
+touch "$ORB_DEFAULTS"
+set_kv_file "$ORB_DEFAULTS" ORB_DEVICE_NAME_OVERRIDE "$HOST_ORB_NAME"
+set_kv_file "$ORB_DEFAULTS" ORB_DEPLOYMENT_TOKEN "$ORB_DEPLOYMENT_TOKEN_WIFI"
+set_kv_file "$ORB_DEFAULTS" ORB_EPHEMERAL_MODE "1"
+
+systemctl enable orb
+systemctl restart orb
+
+log "Setting up Docker Orb and WUD"
+install -d -m 0755 "$STACK_DIR"
+write_udhcpc_script
+write_orb_entrypoint
+write_compose_env
+write_compose_file
+
+cd "$STACK_DIR"
+docker compose up -d
+
+log "Installing periodic /etc/hosts updater"
+write_hosts_updater_script
+write_hosts_timer_service
+systemctl daemon-reload
+systemctl enable orb-ethernet-hosts.timer
+systemctl start orb-ethernet-hosts.timer
+systemctl start orb-ethernet-hosts.service || true
+
+log "Bootstrap complete"
+echo
+echo "Host Orb name: $HOST_ORB_NAME"
+echo "Ethernet Orb name: $ETH_ORB_NAME"
+echo "WiFi profile: $WIFI_CONN"
+echo "Ethernet profile: $ETH_CONN"
+echo "Compose stack: $STACK_DIR"
+echo "Ethernet alias: $ETH_HOSTS_ALIAS"
+
+SUCCESS=1
+exit 0
\ No newline at end of file