docs: add installation guide and deploy:install mise task

- docs/INSTALL.md covers all 6 install methods (local SCP, package install,
  SDK build, official feeds, custom feed, Image Builder/ASU)
- deploy:install mise task: one-command SCP + service restart to an OpenWrt device
  with HOST env var support (default root@192.168.15.1)
This commit is contained in:
2026-07-12 23:49:47 +05:30
parent 7d586157f3
commit 13301772ab
2 changed files with 286 additions and 0 deletions

231
docs/INSTALL.md Normal file
View File

@@ -0,0 +1,231 @@
# Installing luci-app-zt-gateway
This package provides a ZeroTier Exit Gateway Switching UI for OpenWrt.
It works on OpenWrt 24.10 (opkg) and 25.12+ (apk).
## Prerequisites
The target device must have these packages installed:
| Package | Provides |
|---|---|
| `luci-base` | LuCI framework |
| `luci-compat` | `luci.ucodebridge` (needed by modern LuCI) |
| `ucode` | Ucode runtime for rpcd backends |
| `rpcd-mod-ucode` | Ucode rpcd plugin |
| `luci-theme-bootstrap` | Default LuCI theme |
Check with:
```bash
# OpenWrt 25.12+ (apk)
apk list --installed | grep -E 'luci-base|luci-compat|ucode|rpcd-mod-ucode|luci-theme'
# OpenWrt 24.10 and older (opkg)
opkg list-installed | grep -E 'luci-base|luci-compat|ucode|rpcd-mod-ucode|luci-theme'
```
Install missing prerequisites:
```bash
# apk
apk add luci-base luci-compat ucode rpcd-mod-ucode luci-theme-bootstrap
# opkg
opkg update
opkg install luci-base luci-compat ucode rpcd-mod-ucode luci-theme-bootstrap
```
---
## Method 1: Local File Install (Development / Quick Testing)
The fastest way during development. No build step required.
```bash
HOST=root@192.168.15.1
# Upload files
scp root/usr/sbin/zt-gateway-switch $HOST:/usr/sbin/
scp root/usr/share/rpcd/ucode/zt-gateway.uc $HOST:/usr/share/rpcd/ucode/
scp root/usr/share/rpcd/ucode/system.uc $HOST:/usr/share/rpcd/ucode/
scp root/usr/share/ucode/luci/runtime.uc $HOST:/usr/share/ucode/luci/
scp root/usr/share/luci/menu.d/luci-app-zt-gateway.json $HOST:/usr/share/luci/menu.d/
scp root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json $HOST:/usr/share/rpcd/acl.d/
scp root/etc/config/zt-gateway $HOST:/etc/config/
scp htdocs/luci-static/resources/view/zt-gateway/overview.js $HOST:/www/luci-static/resources/view/zt-gateway/
# Set permissions and restart services
ssh $HOST 'chmod +x /usr/sbin/zt-gateway-switch; /etc/init.d/rpcd restart; /etc/init.d/uhttpd restart'
```
Or use the mise task (same thing, one command):
```bash
mise run deploy:install
# or with a custom target:
HOST=root@10.0.0.1 mise run deploy:install
```
Open `http://<device-ip>/cgi-bin/luci/admin/services/zt-gateway`.
**Note:** This method has no dependency tracking. The package manager won't know
about the installed files. Use for dev only.
---
## Method 2: Local Package Install via SCP
Build the `.ipk` (or `.apk` for 25.12+) with the OpenWrt SDK (see Method 5),
then transfer and install:
```bash
# Transfer
scp luci-app-zt-gateway_*.ipk root@192.168.15.1:/tmp/
# OpenWrt 24.10 and older (opkg)
ssh root@192.168.15.1 'opkg update && opkg install /tmp/luci-app-zt-gateway_*.ipk'
# OpenWrt 25.12+ (apk)
ssh root@192.168.15.1 'apk add --allow-untrusted /tmp/luci-app-zt-gateway_*.apk'
```
You can also upload via the **LuCI web UI**:
System → Software → Upload Package → select file → Install.
---
## Method 3: OpenWrt SDK Build
Build from source using the official OpenWrt SDK. Produces a proper `.ipk`/`.apk`
with dependency metadata.
```bash
# 1. Download the SDK matching your target architecture
# https://downloads.openwrt.org/ → select release → SDK
tar -xf openwrt-sdk-*.tar.xz
cd openwrt-sdk-*
# 2. Place this package in the SDK tree
ln -s /path/to/luci-app-zt-gateway package/luci-app-zt-gateway
# 3. Update feeds (resolves luci-base, ucode, etc.)
./scripts/feeds update -a
./scripts/feeds install -a
# 4. Build just this package
make package/luci-app-zt-gateway/compile V=s
# 5. Find the output
find bin/ -name "luci-app-zt-gateway*"
```
Then install via Method 2.
To speed up the build:
```bash
make package/luci-app-zt-gateway/compile -j$(nproc) V=s
```
---
## Method 4: Official Feeds Install
If the package is published to an OpenWrt feed (official or third-party):
```bash
# OpenWrt 25.12+ (apk)
apk update
apk add luci-app-zt-gateway
# OpenWrt 24.10 and older (opkg)
opkg update
opkg install luci-app-zt-gateway
```
Or via LuCI: System → Software → search "zt-gateway" → Install.
---
## Method 5: Custom Package Feed
For distributing a third-party package to multiple devices, host the built
`.ipk`/`.apk` files on an HTTP server and add a feed:
### opkg-based (24.10 and older)
```bash
# On the router:
echo 'src/gz zt-gateway https://your-server.com/packages' >> /etc/opkg/customfeeds.conf
opkg update
opkg install luci-app-zt-gateway
```
### apk-based (25.12+)
```bash
# On the router:
# Add the repo URL to /etc/apk/repositories.d/
echo 'https://your-server.com/packages' >> /etc/apk/repositories.d/custom.list
apk update
apk add --allow-untrusted luci-app-zt-gateway
```
The HTTP server must host:
- Package files (`.ipk` or `.apk`)
- An index file (`Packages.gz` for opkg, `APKINDEX.tar.gz` for apk)
The OpenWrt SDK's `make package/index` generates these indices.
---
## Method 6: Image Builder / Attended Sysupgrade
Bake the package into a firmware image so it survives factory resets.
### Via LuCI (recommended)
1. Install the attended sysupgrade tool:
```bash
# apk
apk add luci-app-attendedsysupgrade
# opkg
opkg install luci-app-attendedsysupgrade
```
2. Open **System → Attended Sysupgrade**
3. Click **Search for firmware upgrade**
4. Click **Advanced Mode** → add `luci-app-zt-gateway` to the package list
5. Click **Request firmware image** → wait for the build server to compile
6. Check **Keep settings****Install firmware image**
### Via Image Builder
```bash
# Download the Image Builder for your target
tar -xf openwrt-imagebuilder-*.tar.xz
cd openwrt-imagebuilder-*
# Build with luci-app-zt-gateway included
make image PACKAGES="luci-app-zt-gateway luci-base ucode rpcd-mod-ucode luci-compat"
```
---
## File Layout
These are the files installed by this package and their target locations:
| Source | Target | Purpose |
|---|---|---|
| `root/usr/sbin/zt-gateway-switch` | `/usr/sbin/zt-gateway-switch` | Gateway switching script |
| `root/usr/share/rpcd/ucode/zt-gateway.uc` | `/usr/share/rpcd/ucode/zt-gateway.uc` | rpcd backend |
| `root/usr/share/rpcd/ucode/system.uc` | `/usr/share/rpcd/ucode/system.uc` | system.board rpcd override |
| `root/usr/share/ucode/luci/runtime.uc` | `/usr/share/ucode/luci/runtime.uc` | LuCI ucode runtime patch |
| `root/usr/share/luci/menu.d/luci-app-zt-gateway.json` | `/usr/share/luci/menu.d/luci-app-zt-gateway.json` | LuCI menu registration |
| `root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` | `/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` | rpcd ACL rules |
| `root/etc/config/zt-gateway` | `/etc/config/zt-gateway` | UCI config |
| `htdocs/.../overview.js` | `/www/.../overview.js` | LuCI frontend view |

View File

@@ -64,3 +64,58 @@ docker exec openwrt-luci sh -c "uci set zt-gateway.global.active_gateway=amsterd
description = "Full CI: build stack + install browsers + run E2E"
depends = ["docker:up", "setup"]
run = "npx playwright test"
# ===============================
# Deployment
# ===============================
[tasks."deploy:install"]
description = "SCP app files to an OpenWrt device and restart services"
run = '''
set -e
HOST="${HOST:-root@192.168.15.1}"
echo "==> Checking connectivity to ${HOST}..."
if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "$HOST" true 2>/dev/null; then
echo "ERROR: Cannot reach ${HOST}. Check SSH access."
echo " ssh-copy-id ${HOST} # if needed"
exit 1
fi
echo " ${HOST} is reachable."
echo "==> Uploading files..."
# root/ files → strip leading root/, map to / on device
scp -q root/usr/sbin/zt-gateway-switch "$HOST:/usr/sbin/"
echo " zt-gateway-switch"
scp -q root/usr/share/rpcd/ucode/zt-gateway.uc "$HOST:/usr/share/rpcd/ucode/"
echo " rpcd/ucode/zt-gateway.uc"
scp -q root/usr/share/rpcd/ucode/system.uc "$HOST:/usr/share/rpcd/ucode/"
echo " rpcd/ucode/system.uc"
scp -q root/usr/share/ucode/luci/runtime.uc "$HOST:/usr/share/ucode/luci/"
echo " ucode/luci/runtime.uc"
scp -q root/usr/share/luci/menu.d/luci-app-zt-gateway.json "$HOST:/usr/share/luci/menu.d/"
echo " menu.d/luci-app-zt-gateway.json"
scp -q root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json "$HOST:/usr/share/rpcd/acl.d/"
echo " acl.d/luci-app-zt-gateway.json"
scp -q root/etc/config/zt-gateway "$HOST:/etc/config/"
echo " config/zt-gateway"
# Frontend view
ssh -q "$HOST" mkdir -p /www/luci-static/resources/view/zt-gateway
scp -q htdocs/luci-static/resources/view/zt-gateway/overview.js "$HOST:/www/luci-static/resources/view/zt-gateway/"
echo " overview.js"
echo "==> Setting permissions..."
ssh -q "$HOST" chmod +x /usr/sbin/zt-gateway-switch
echo "==> Restarting rpcd and uhttpd..."
ssh -q "$HOST" /etc/init.d/rpcd restart
ssh -q "$HOST" /etc/init.d/uhttpd restart
DEVICE_IP=$(echo "$HOST" | sed 's/.*@//')
echo ""
echo "==> Done! Open: http://${DEVICE_IP}/cgi-bin/luci/admin/services/zt-gateway"
'''