setup wizard: fix routing, DHCP, WiFi AP, firewall, and deploy task
Setup script fixes: - _cidr_to_mask: pad to 4 octets (/24 -> 255.255.255.0) - UCI quoting: remove embedded shell quotes from uci set calls - Bridge ports: auto-detect zt* interface instead of hardcoding ztabc0 - Bridge netmask: default to /23 (255.255.254.0) for ZT+WIBLAN - DHCP/WiFi AP: reference interface name (zt_wiblan) not device name (br_zt) - Firewall zone: add zt_wiblan to LAN zone for nftables fw4 - ZT IP persistence: ensure ZT-assigned IP stays on interface for ARP - Exit gateway routing: table 100/101 route via exit gateway, not self - New setup-wifi-ap subcommand for WIBLAN WiFi AP UBUS handler: - Add setup-wifi-ap to validation regex and error message Deploy task: - Auto-discover files from root/ and htdocs/ instead of hardcoded list - Clear LuCI cache before restarting services Documentation: - New docs/SETUP-GATEWAY.md with architecture, config, pitfalls, checklist - Updated docs/INSTALL.md with deploy task and setup wizard sections - Updated docs/PROGRESS.md with session log and learnings
This commit is contained in:
279
.omp/plans/add-setup-screen.md
Normal file
279
.omp/plans/add-setup-screen.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# Plan: One-Time Setup Screen for luci-app-zt-gateway
|
||||
|
||||
## Problem
|
||||
|
||||
When `luci-app-zt-gateway` is installed on a fresh OpenWrt router, the switch script fails with `Cannot find device "br-zt"` because the prerequisite networking (bridge, routing, hotplug, DHCP) doesn't exist yet. There's no guided setup — the user must manually configure everything via CLI.
|
||||
|
||||
## Goal
|
||||
|
||||
Add a **Setup** section to the overview UI that:
|
||||
1. Detects what's already configured vs. what's missing
|
||||
2. Lets the user run each setup step individually or all at once
|
||||
3. Shows real-time status after each step
|
||||
4. For WiFi AP, displays the UCI config to add (user confirms)
|
||||
|
||||
## Production Router State (reference)
|
||||
|
||||
The router at `root@10.11.12.254` shows the target state:
|
||||
|
||||
| Component | UCI/Config | Runtime |
|
||||
|---|---|---|
|
||||
| br-zt bridge | `config device type bridge name br-zt` | `ip link show br-zt` |
|
||||
| brzt interface | `config interface brzt proto static device br-zt ipaddr 10.11.12.254` | `ip addr show br-zt` |
|
||||
| ZT interface | `config interface zerotier proto none device ztk4jpk77j` | `ip link show ztk4jpk77j` |
|
||||
| ZT enslavement | hotplug script | `brctl show br-zt` |
|
||||
| Policy rule | `config rule src 10.11.13.0/24 lookup 100 priority 100` | `ip rule show` |
|
||||
| Table 100 default | `config route interface brzt target 0.0.0.0 gateway 10.11.12.3 table 100` | `ip route show table 100` |
|
||||
| Host route | `config route interface brzt target 10.11.12.3` | `ip route show` |
|
||||
| WIBLAN return | `config route interface brzt target 10.11.13.0 table 100` | — |
|
||||
| DHCP | `config dhcp brzt interface brzt start 257 limit 254` | — |
|
||||
| WIBLAN AP | `config wifi-iface wifinet0 device radio0 ssid WIBLAN network brzt` | — |
|
||||
| IP forwarding | sysctl | `cat /proc/sys/net/ipv4/ip_forward` → 1 |
|
||||
| Hotplug | `/etc/hotplug.d/net/99-zerotier-bridge` | — |
|
||||
| rc.local | routes in `/etc/rc.local` | — |
|
||||
|
||||
## Architecture
|
||||
|
||||
### 1. Setup Script: `root/usr/sbin/zt-gateway-setup`
|
||||
|
||||
A new POSIX shell script with subcommands. Idempotent — running any step twice is safe.
|
||||
|
||||
```
|
||||
Usage: zt-gateway-setup <command>
|
||||
|
||||
Commands:
|
||||
status Show setup status for all components
|
||||
setup-bridge Create br-zt bridge and detect ZT interface
|
||||
setup-routing Configure ip rules, table 100, ip forwarding
|
||||
setup-hotplug Write /etc/hotplug.d/net/99-zerotier-bridge
|
||||
setup-persistence Write rc.local + UCI network routes
|
||||
setup-dhcp Configure DHCP for WIBLAN subnet
|
||||
setup-all Run all setup steps in order
|
||||
```
|
||||
|
||||
**Environment variables** (same pattern as `zt-gateway-switch`):
|
||||
- `ZTG_BRIDGE` (default: `br-zt`)
|
||||
- `ZTG_WIBLAN_CIDR` (default: `10.11.13.0/24`)
|
||||
- `ZTG_TABLE_MAIN` (default: `100`)
|
||||
- `ZTG_ZT_NETWORK_ID` (default: auto-detect from `zerotier-cli listnetworks`)
|
||||
|
||||
**`status` output** (JSON, for ubus consumption):
|
||||
```json
|
||||
{
|
||||
"zt_client": true,
|
||||
"zt_network_joined": true,
|
||||
"zt_interface": "ztk4jpk77j",
|
||||
"bridge_exists": true,
|
||||
"bridge_has_zt": true,
|
||||
"bridge_has_address": true,
|
||||
"routing_ready": true,
|
||||
"ip_forwarding": true,
|
||||
"hotplug_script": true,
|
||||
"persistence": true,
|
||||
"dhcp_configured": true
|
||||
}
|
||||
```
|
||||
|
||||
**Key implementation details:**
|
||||
|
||||
#### `setup-bridge`
|
||||
1. Find ZT interface: `zerotier-cli listnetworks` → parse `<dev>` column
|
||||
2. If no ZT interface found → error "ZeroTier not joined to any network"
|
||||
3. Create UCI device: `uci set network.zt_bridge=bridge; uci set network.zt_bridge.name=$BRIDGE; uci set network.zt_bridge.bridge_empty=1`
|
||||
4. Create UCI interface: `uci set network.brzt=interface; uci set network.brzt.proto=static; uci set network.brzt.device=$BRIDGE`
|
||||
5. Set IP from UCI config (read `global` section for WIBLAN CIDR, derive gateway IP)
|
||||
6. Create UCI zerotier interface: `uci set network.zerotier=interface; uci set network.zerotier.proto=none; uci set network.zerotier.device=$ZT_IFACE`
|
||||
7. `uci commit network`
|
||||
8. Bring up: `ifup brzt; ifup zerotier`
|
||||
9. Runtime fallback: if `ifup` doesn't enslave, do it manually:
|
||||
```
|
||||
ip link add name $BRIDGE type bridge 2>/dev/null || true
|
||||
ip link set $BRIDGE up
|
||||
ip link set $ZT_IFACE master $BRIDGE
|
||||
```
|
||||
|
||||
#### `setup-routing`
|
||||
1. `echo 1 > /proc/sys/net/ipv4/ip_forward`
|
||||
2. Persist: add `net.ipv4.ip_forward=1` to `/etc/sysctl.d/99-zt-gateway.conf` + `sysctl -p`
|
||||
3. `ip rule del from $WIBLAN_CIDR table $TABLE_MAIN 2>/dev/null || true`
|
||||
4. `ip rule add from $WIBLAN_CIDR table $TABLE_MAIN priority 100`
|
||||
5. Read `active_gateway` from UCI → get IP from gateway config
|
||||
6. `ip route replace default via $GW_IP dev $BRIDGE table $TABLE_MAIN`
|
||||
7. `ip route replace $GW_IP dev $BRIDGE` (host route)
|
||||
8. `ip route replace $WIBLAN_CIDR dev $BRIDGE table 1` (MWAN return)
|
||||
|
||||
#### `setup-hotplug`
|
||||
Write `/etc/hotplug.d/net/99-zerotier-bridge`:
|
||||
```sh
|
||||
#!/bin/sh
|
||||
# Auto-generated by zt-gateway-setup — do not edit manually.
|
||||
# Re-enslaves ZT interface to br-zt and restores routes on reconnect.
|
||||
[ "$INTERFACE" = "$ZT_IFACE" ] && [ "$ACTION" = "add" ] && {
|
||||
ip link set $ZT_IFACE master $BRIDGE 2>/dev/null || brctl addif $BRIDGE $ZT_IFACE 2>/dev/null
|
||||
ip route del $ZT_SUBNET dev $ZT_IFACE 2>/dev/null
|
||||
ip route replace $WIBLAN_CIDR dev $BRIDGE table 1 2>/dev/null
|
||||
ip route replace $GW_IP dev $BRIDGE 2>/dev/null
|
||||
ip route replace default via $GW_IP dev $BRIDGE table $TABLE_MAIN 2>/dev/null
|
||||
}
|
||||
```
|
||||
The IPs are hardcoded (matching how `persist_all` uses `sed` to update them on switch).
|
||||
|
||||
#### `setup-persistence`
|
||||
Write rc.local entries and UCI network routes (already handled by `persist_all` in the switch script, but `setup-persistence` creates the initial entries).
|
||||
|
||||
#### `setup-dhcp`
|
||||
Write to `/etc/config/dhcp` (NOT `/etc/config/network`):
|
||||
```sh
|
||||
uci set dhcp.brzt=dhcp
|
||||
uci set dhcp.brzt.interface='brzt'
|
||||
uci set dhcp.brzt.start=257
|
||||
uci set dhcp.brzt.limit=254
|
||||
uci set dhcp.brzt.leasetime='12h'
|
||||
uci add_list dhcp.brzt.dhcp_option='3,$WIBLAN_GW' # gateway
|
||||
uci add_list dhcp.brzt.dhcp_option='6,8.8.8.8,1.1.1.1' # DNS
|
||||
uci commit dhcp
|
||||
```
|
||||
The gateway IP is the router's own IP on br-zt (read from UCI `network.brzt.ipaddr` after bridge setup).
|
||||
|
||||
### 2. Backend: `root/usr/share/rpcd/ucode/zt-gateway.uc`
|
||||
|
||||
Add a new `setup` ubus method:
|
||||
|
||||
```js
|
||||
setup: {
|
||||
args: {
|
||||
action: 'string' // 'status' | 'setup-bridge' | 'setup-routing' | ...
|
||||
},
|
||||
call: function(req) {
|
||||
const action = req.args?.action || 'status';
|
||||
const result = system_output(`/usr/sbin/zt-gateway-setup ${shell_quote(action)}`);
|
||||
// Parse JSON output, return structured result
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Also update the ACL in `root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` to allow the `setup` method.
|
||||
|
||||
### 3. UI: `htdocs/luci-static/resources/view/zt-gateway/overview.js`
|
||||
|
||||
Add a **Setup** section to the overview page. When setup is incomplete, show it prominently at the top. When complete, collapse it or hide it.
|
||||
|
||||
#### Setup Panel Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Setup [Status] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ☑ ZeroTier client installed │
|
||||
│ ☑ Network "whiteblossom" joined (ztk4jpk77j) │
|
||||
│ │
|
||||
│ ☐ Bridge (br-zt) [Setup] │
|
||||
│ Creates br-zt and enslaves ZT interface │
|
||||
│ │
|
||||
│ ☐ Routing (ip rules + table 100) [Setup] │
|
||||
│ Configures policy routing for WIBLAN traffic │
|
||||
│ │
|
||||
│ ☐ Hotplug script [Setup] │
|
||||
│ Restores routes when ZT reconnects │
|
||||
│ │
|
||||
│ ☐ Boot persistence [Setup] │
|
||||
│ Routes survive reboot │
|
||||
│ │
|
||||
│ ☐ DHCP for WIBLAN [Setup] │
|
||||
│ Assigns IPs to WiFi clients (10.11.13.0/24) │
|
||||
│ │
|
||||
│ ───────────────────────────────────────────────────── │
|
||||
│ WiFi AP (WIBLAN) [Guide] │
|
||||
│ Add to /etc/config/wireless: │
|
||||
│ ┌─────────────────────────────────────────────┐ │
|
||||
│ │ config wifi-iface 'wifinetN' │ │
|
||||
│ │ option device 'radio0' │ │
|
||||
│ │ option mode 'ap' │ │
|
||||
│ │ option ssid 'WIBLAN' │ │
|
||||
│ │ option encryption 'psk2' │ │
|
||||
│ │ option key '<your-password>' │ │
|
||||
│ │ option network 'brzt' │ │
|
||||
│ └─────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [Run All Setup Steps] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### UI Behavior
|
||||
|
||||
1. **On page load**: Call `zt-gateway.setup { action: 'status' }` to get current state
|
||||
2. **Render checklist**: Each step shows ✓ (green) or ✗ (gray) with a [Setup] button
|
||||
3. **[Setup] button**: Calls `zt-gateway.setup { action: 'setup-bridge' }` (etc.), then refreshes status
|
||||
4. **[Run All]**: Calls `zt-gateway.setup { action: 'setup-all' }`, then refreshes status
|
||||
5. **WiFi Guide**: Shows the UCI config snippet to add (read-only, with copy button)
|
||||
6. **After all steps complete**: Collapse the setup section, show normal overview
|
||||
|
||||
#### Status Detection Logic (in `zt-gateway-setup status`)
|
||||
|
||||
| Check | How |
|
||||
|---|---|
|
||||
| ZT client installed | `command -v zerotier-cli` |
|
||||
| ZT network joined | `zerotier-cli listnetworks 2>/dev/null \| grep -q OK` |
|
||||
| ZT interface name | Parse `zerotier-cli listnetworks` → `<dev>` column |
|
||||
| Bridge exists | `ip link show $BRIDGE 2>/dev/null` |
|
||||
| Bridge has ZT | `brctl show $BRIDGE 2>/dev/null \| grep -q $ZT_IFACE` |
|
||||
| Bridge has address | `ip -o -4 addr show dev $BRIDGE 2>/dev/null` |
|
||||
| IP forwarding | `cat /proc/sys/net/ipv4/ip_forward` |
|
||||
| Policy rule | `ip rule show \| grep "from $WIBLAN_CIDR.*lookup $TABLE_MAIN"` |
|
||||
| Table 100 default | `ip route show table $TABLE_MAIN \| grep -q "default via"` |
|
||||
| Hotplug script | `[ -x /etc/hotplug.d/net/99-zerotier-bridge ]` |
|
||||
| Persistence | Check rc.local has routes |
|
||||
| DHCP | `uci get dhcp.brzt.interface 2>/dev/null` |
|
||||
### 4. Files to Create/Modify
|
||||
|
||||
| File | Action | Purpose |
|
||||
|---|---|---|
|
||||
| `root/usr/sbin/zt-gateway-setup` | **Create** | Setup script with subcommands |
|
||||
| `root/usr/share/rpcd/ucode/zt-gateway.uc` | **Modify** | Add `setup` ubus method |
|
||||
| `root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` | **Modify** | Add `setup` to ubus read/write ACL |
|
||||
| `htdocs/luci-static/resources/view/zt-gateway/overview.js` | **Modify** | Add setup panel section |
|
||||
| `root/etc/config/zt-gateway` | **Modify** | Add `wiblan_subnet` and `zt_network_id` options to global |
|
||||
| `docs/INSTALL.md` | **Modify** | Document setup screen in installation guide |
|
||||
|
||||
### 5. UCI Config Additions
|
||||
|
||||
Add to `config global` in `root/etc/config/zt-gateway`:
|
||||
```
|
||||
option wiblan_subnet '10.11.13.0/24'
|
||||
option wiblan_gateway '10.11.12.254'
|
||||
option wiblan_dhcp_start '257'
|
||||
option wiblan_dhcp_limit '254'
|
||||
option zt_network_id ''
|
||||
```
|
||||
|
||||
These allow the setup script and UI to derive all IP addresses from config rather than hardcoding.
|
||||
|
||||
### 6. Verification
|
||||
|
||||
1. **Deploy to router**: `HOST=root@10.11.12.254 mise run deploy:install`
|
||||
2. **Open UI**: Navigate to Services > ZeroTier Gateway
|
||||
3. **Setup panel**: Should show checklist with current state (most items ✓ since router is pre-configured)
|
||||
4. **Fresh test**: Deploy to a clean OpenWrt container (`docker compose up openwrt-luci`), verify setup panel shows all ✗
|
||||
5. **Run setup**: Click [Run All], verify all items turn ✓
|
||||
6. **Switch test**: After setup, select a gateway and switch — should succeed
|
||||
7. **Reboot test**: After setup, reboot — verify routes survive
|
||||
|
||||
### 7. Implementation Order
|
||||
|
||||
1. Create `zt-gateway-setup` script with `status` command only
|
||||
2. Add `setup` ubus method to backend
|
||||
3. Add ACL for `setup` method
|
||||
4. Add setup panel to UI (read-only status display)
|
||||
5. Implement `setup-bridge` in script
|
||||
6. Implement `setup-routing` in script
|
||||
7. Implement `setup-hotplug` in script
|
||||
8. Implement `setup-persistence` in script
|
||||
9. Implement `setup-dhcp` in script
|
||||
10. Implement `setup-all` in script
|
||||
11. Wire [Setup] buttons in UI to call backend
|
||||
12. Add WiFi AP guide section
|
||||
13. Update UCI config with new options
|
||||
14. Update deploy task and docs
|
||||
15. Test end-to-end
|
||||
66
.omp/plans/allow-reactivate-current-gateway.md
Normal file
66
.omp/plans/allow-reactivate-current-gateway.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Plan: Allow re-activating the current gateway from the UI
|
||||
|
||||
## Problem
|
||||
|
||||
The UI shows "active" on a gateway based solely on the UCI `active_gateway` config value, but the switch script (`zt-gateway-switch`) may never have been run — meaning no routing tables, no masquerade, no actual traffic forwarding. The user sees "active" and assumes it works.
|
||||
|
||||
Two blocking issues prevent fixing this from the UI:
|
||||
|
||||
1. **Backend** (`zt-gateway.uc` line 184-187): `switch` method short-circuits with "Already on X" when UCI `active_gateway` matches the requested region — never runs the script
|
||||
2. **UI** (`overview.js` line 81): radio button for the active gateway is `disabled`, so the user can't even select it to click "Switch to selected"
|
||||
|
||||
## Fix
|
||||
|
||||
Two files, one change each.
|
||||
|
||||
### 1. Backend: `root/usr/share/rpcd/ucode/zt-gateway.uc`
|
||||
|
||||
**Remove the "Already on X" early return** (lines 184-187):
|
||||
|
||||
```js
|
||||
// DELETE these lines:
|
||||
const current_region = read_active_region();
|
||||
if (current_region === region && !drain_active()) {
|
||||
return { success: true, message: `Already on ${region}.` };
|
||||
}
|
||||
```
|
||||
|
||||
**Why this is safe:**
|
||||
- `do_force()` in the switch script is idempotent: `ip route replace` is a no-op when the route already matches, conntrack flush is harmless, `persist_all` writes the same values
|
||||
- The backend still updates UCI after the script runs (line 198-199) — setting the same value is harmless
|
||||
- If the gateway is unreachable, `preflight_ping` fails with exit 2 and the backend returns the error — same as switching to any other unreachable gateway
|
||||
|
||||
### 2. UI: `htdocs/luci-static/resources/view/zt-gateway/overview.js`
|
||||
|
||||
**Remove the `disabled` attribute from the active gateway's radio** (line 81):
|
||||
|
||||
Change:
|
||||
```js
|
||||
disabled: isActive || null
|
||||
```
|
||||
To:
|
||||
```js
|
||||
// Remove this line entirely (or keep disabled only during an active drain)
|
||||
```
|
||||
|
||||
**Why this is safe:**
|
||||
- The user can now select the active gateway and click "Switch to selected"
|
||||
- The backend runs the switch script which sets up routing
|
||||
- If routing is already correct, the script is a harmless idempotent no-op
|
||||
- The "Switch to selected" button text still makes sense — it re-applies the gateway config
|
||||
|
||||
### Files to modify
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `root/usr/share/rpcd/ucode/zt-gateway.uc` | Remove lines 184-187 (early return) |
|
||||
| `htdocs/luci-static/resources/view/zt-gateway/overview.js` | Remove `disabled` on line 81 |
|
||||
|
||||
### Verification
|
||||
|
||||
1. Deploy to device: `mise run deploy:install`
|
||||
2. Open UI → amsterdam shows "active" → radio is now enabled
|
||||
3. Select amsterdam → click "Switch to selected" → should succeed and set up routing
|
||||
4. Verify routing: `ip route show table 100` should show `default via 10.11.12.3 dev ztk4jpk77j`
|
||||
5. Verify NAT: `iptables -t mangle -L -n` should show WIBLAN mangle rules (for graceful mode)
|
||||
6. Test from LAN client: `ping -I br-lan 10.11.12.3` should now work
|
||||
75
.omp/plans/install-docs-and-deploy-task.md
Normal file
75
.omp/plans/install-docs-and-deploy-task.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Plan: Document installation guide + add deploy mise task
|
||||
|
||||
## What
|
||||
|
||||
1. Create `docs/INSTALL.md` — installation guide for luci-app-zt-gateway covering all methods
|
||||
2. Add `deploy:install` task to `mise.toml` — one-command SCP + install to a real OpenWrt device
|
||||
|
||||
## 1. `docs/INSTALL.md`
|
||||
|
||||
New file covering all 6 installation methods, researched from official OpenWrt docs:
|
||||
|
||||
| Method | When to use |
|
||||
|---|---|
|
||||
| **LuCI web UI** | End users, official feeds |
|
||||
| **CLI** (`apk add` / `opkg install`) | Headless / SSH users |
|
||||
| **Custom feed** | Distributing third-party packages via HTTP |
|
||||
| **Local file SCP** | Dev/testing, quick iteration |
|
||||
| **OpenWrt SDK** | Building proper .ipk/.apk with dependency metadata |
|
||||
| **Image Builder / ASU** | Production firmware, survives factory reset |
|
||||
|
||||
Key details to document:
|
||||
- OpenWrt 25.12+ uses `apk` (not `opkg`); older uses `opkg`
|
||||
- `apk add --allow-untrusted` required for unsigned local packages
|
||||
- `opkg install /tmp/pkg.ipk` for opkg-based systems
|
||||
- SDK build: `make package/luci-app-zt-gateway/compile V=s`
|
||||
- ASU: `luci-app-attendedsysupgrade` → Advanced Mode → add package
|
||||
- Prerequisites: `luci-base`, `ucode`, `rpcd-mod-ucode`, `luci-compat`
|
||||
- Custom feed: `src/gz` in `/etc/opkg/customfeeds.conf` or apk equivalent
|
||||
|
||||
## 2. `mise.toml` — add `deploy:install` task
|
||||
|
||||
Following snowbud patterns: env var params, usage validation, step-by-step echo output.
|
||||
|
||||
### Task design
|
||||
|
||||
```toml
|
||||
[tasks."deploy:install"]
|
||||
description = "SCP app files to an OpenWrt device and install"
|
||||
```
|
||||
|
||||
**Parameters** (via env vars):
|
||||
- `HOST` — SSH target, default `root@192.168.15.1`
|
||||
|
||||
**What it does:**
|
||||
1. Validate `ssh` connectivity to `$HOST`
|
||||
2. SCP each file from `root/` to its corresponding remote path (stripping the leading `root` prefix)
|
||||
3. SCP `htdocs/luci-static/resources/view/zt-gateway/overview.js` → `/www/luci-static/resources/view/zt-gateway/overview.js`
|
||||
4. `chmod +x` the `zt-gateway-switch` script on the remote
|
||||
5. Restart `rpcd` and `uhttpd` so LuCI picks up changes
|
||||
6. Echo the URL to open
|
||||
|
||||
### File mapping (local → remote)
|
||||
|
||||
| Local | Remote |
|
||||
|---|---|
|
||||
| `root/usr/sbin/zt-gateway-switch` | `/usr/sbin/zt-gateway-switch` |
|
||||
| `root/usr/share/rpcd/ucode/zt-gateway.uc` | `/usr/share/rpcd/ucode/zt-gateway.uc` |
|
||||
| `root/usr/share/rpcd/ucode/system.uc` | `/usr/share/rpcd/ucode/system.uc` |
|
||||
| `root/usr/share/ucode/luci/runtime.uc` | `/usr/share/ucode/luci/runtime.uc` |
|
||||
| `root/usr/share/luci/menu.d/luci-app-zt-gateway.json` | `/usr/share/luci/menu.d/luci-app-zt-gateway.json` |
|
||||
| `root/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` | `/usr/share/rpcd/acl.d/luci-app-zt-gateway.json` |
|
||||
| `root/etc/config/zt-gateway` | `/etc/config/zt-gateway` |
|
||||
| `htdocs/.../overview.js` | `/www/.../overview.js` |
|
||||
|
||||
## Files to modify
|
||||
|
||||
| File | Action |
|
||||
|---|---|
|
||||
| `docs/INSTALL.md` | **Create** |
|
||||
| `mise.toml` | **Edit** — append `deploy:install` task |
|
||||
|
||||
## Verification
|
||||
|
||||
1. `mise tasks` should list the new `deploy:install` task
|
||||
2. `docs/INSTALL.md` should be readable and cover all 6 methods
|
||||
Reference in New Issue
Block a user