Files
gpt_from_scratch/kylin_remote_setup.md
2026-06-12 17:19:26 +08:00

476 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Kylin Remote Control & Monitoring Setup
Complete reference for controlling and monitoring a Kylin Linux machine from a
Windows 11 PC over a local phone-hotspot network. No VPN is used for the SSH
connection itself — only the local Wi-Fi/hotspot.
---
## 0. Bootstrap — START HERE in a new session
**The connection is already fully set up** (SSH key login + passwordless sudo).
A new session does **NOT** need to repeat the setup in §2–§3 — those sections are
records of what was already done. Just connect and go.
**Verify everything with one command** (run from the Windows machine, e.g. Claude Code's Bash tool):
```bash
ssh -o BatchMode=yes -o ConnectTimeout=10 kylin 'echo SSH_OK; whoami; hostname; sudo -n true && echo SUDO_OK'
```
Expected: `SSH_OK` / `caichl` / `caichl-HUAWEIQINGYUNL420` / `SUDO_OK`.
-**`SSH_OK` + `SUDO_OK`** → full control. Run anything (incl. `sudo`) via
`ssh -o BatchMode=yes kylin "<command>"`. No password needed.
-**asks for password / times out** → most likely the **hotspot IP changed**
(`192.168.43.248` is DHCP-assigned and can change between sessions). Ask the user
to re-check the Kylin IP (`hostname -I` on that machine), update
`C:\Users\adusu\.ssh\config`, then re-verify. If it asks for a password, the key
may have been removed — see §2.3 / §2.4 to re-establish.
- ️ SSH prints a harmless **post-quantum warning** to stderr — ignore it (the
examples in this doc filter it out).
**Connect manually:** `ssh kylin` (alias in `C:\Users\adusu\.ssh\config``caichl@192.168.43.248`,
with the pinned cipher/MAC already configured — see §2).
> A fresh Claude Code session also auto-loads memory pointers (`MEMORY.md` →
> `kylin-remote-machine`, `kylin-command-logging`, `kylin-mihomo-vpn`) that link
> back here. This file is the authoritative, self-contained reference.
---
## 1. The two machines
| Role | Details |
|------|---------|
| **Controller** | Windows 11 (`C:\Users\adusu`), where Claude Code + VPN run |
| **Target** | Kylin V10 SP1, Huawei QINGYUN L420, **ARM64 / aarch64** |
| **Network** | Shared phone hotspot, subnet `192.168.43.x` |
| **Target IP** | `192.168.43.248` |
| **Target user** | `caichl` |
> **Key idea:** Claude Code needs the VPN to reach Anthropic's servers, but the
> SSH hop from Windows → Kylin is **local LAN traffic** and needs no VPN. The two
> connections are independent.
---
## 2. SSH connection
### 2.1 Required cipher/MAC (important)
The default cipher fails over this hotspot link with
`Corrupted MAC on input`. The connection must pin a specific cipher and MAC:
```
-c aes256-ctr -m hmac-sha2-256
```
### 2.2 Windows SSH config
File: `C:\Users\adusu\.ssh\config`
```sshconfig
Host kylin kyln
HostName 192.168.43.248
User caichl
Ciphers aes256-ctr
MACs hmac-sha2-256
```
With this in place, simply run:
```powershell
ssh kylin # or: ssh kyln (both aliases work)
```
The equivalent explicit command (no config) is:
```powershell
ssh -m hmac-sha2-256 -c aes256-ctr caichl@192.168.43.248
```
### 2.3 Passwordless login (SSH key)
The Windows key `~/.ssh/id_ed25519.pub` was copied to the Kylin machine:
```powershell
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | `
ssh kylin "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
```
Result: `ssh kylin` logs in with **no password**.
### 2.4 Passwordless sudo
So admin commands can run non-interactively from Windows:
```bash
# Run once on the Kylin machine (asks for password the one time)
sudo bash -c 'echo "caichl ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/caichl-nopasswd; \
chmod 440 /etc/sudoers.d/caichl-nopasswd; \
visudo -cf /etc/sudoers.d/caichl-nopasswd'
```
> **Security note:** This makes `caichl` a passwordless-sudo account — acceptable
> for a disposable machine only. To revert: `sudo rm /etc/sudoers.d/caichl-nopasswd`.
After this, from Windows you can run, e.g.:
```powershell
ssh -o BatchMode=yes kylin "sudo systemctl status ssh"
```
### 2.5 Account credentials (recovery only)
> ⚠️ **Plaintext password below — keep this file private; do NOT commit or share it.**
| Item | Value |
|------|-------|
| User | `caichl` |
| Password | `Caicai@2026` |
**Normally not needed** — SSH login uses the key (§2.3) and sudo is passwordless
(§2.4). Use this only to **recover** if the key auth or sudoers drop-in is ever lost
(e.g. to log in interactively and re-copy the key, or to re-create
`/etc/sudoers.d/caichl-nopasswd`). To change it: run `passwd` on the Kylin machine.
---
## 3. Initial SSH server setup (done on the Kylin machine)
```bash
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
hostname -I # find the IP (192.168.43.248)
whoami # confirm the username (caichl)
```
---
## 4. Monitoring
### 4.1 SSH logins & sessions (works out of the box)
```bash
who # who is logged in + source
w # sessions + current command
last # login history with IPs
lastb # FAILED login attempts (sudo)
sudo grep "Accepted" /var/log/auth.log # successful SSH logins
sudo grep "Failed" /var/log/auth.log # failed/suspicious attempts
sudo tail -f /var/log/auth.log # live SSH activity
```
### 4.2 Command logging — no reboot (WORKING)
Logs every command typed in an interactive shell, with user, tty, source IP,
and the command text.
**`/etc/profile.d/cmdlog.sh`**
```bash
# Log interactive shell commands to syslog (facility local6) -> /var/log/cmdlog.log
if [ -n "$BASH" ] && [ -n "$PS1" ]; then
export PROMPT_COMMAND='logger -p local6.notice -t cmdlog "user=$USER tty=$(tty 2>/dev/null) from=$(who am i 2>/dev/null | sed -n "s/.*(\(.*\)).*/\1/p") cmd=$(history 1 | sed "s/^ *[0-9]* *//")"'
fi
```
**`/etc/rsyslog.d/30-cmdlog.conf`**
```
local6.* /var/log/cmdlog.log
```
**Setup commands**
```bash
sudo touch /var/log/cmdlog.log
sudo chown syslog:adm /var/log/cmdlog.log # MUST be syslog-owned (rsyslog drops privs)
sudo chmod 640 /var/log/cmdlog.log
sudo systemctl restart rsyslog
```
**View the logs**
```bash
sudo cat /var/log/cmdlog.log # all logged commands
sudo tail -f /var/log/cmdlog.log # live
```
Example line:
```
Jun 11 10:54:22 caichl-HUAWEIQINGYUNL420 cmdlog: user=caichl tty=/dev/pts/5 from=192.168.43.180 cmd=echo hello
```
> **Gotcha:** rsyslog runs as the `syslog` user. If `/var/log/cmdlog.log` is owned
> by `root:root`, nothing is written. It must be `chown syslog:adm`.
### 4.3 System-wide auditing — auditd (QUEUED, UNVERIFIED)
`auditd` is installed and enabled, with a rule logging all `execve` for real
users:
**`/etc/audit/rules.d/cmdlog.rules`**
```
-a exit,always -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k cmdlog
```
It cannot run yet because the kernel booted with `audit=0`. This was changed to
`audit=1`:
```bash
sudo sed -i 's/audit=0/audit=1/' /etc/default/grub
# /boot is read-only on this device — remount to rebuild grub
sudo mount -o remount,rw /boot
sudo update-grub
sudo mount -o remount,ro /boot
```
> **Caveat:** This device appears to boot via **Huawei firmware, not standard
> GRUB** (running kernel `-27` is not the one in `grub.cfg` which lists `-11`, and
> the kernel cmdline has Huawei-specific params). So the `audit=1` change **may
> not take effect** on reboot. The no-reboot logging in §4.2 already covers
> interactive command logging, so auditd is a bonus.
**Verify after any reboot**
```bash
cat /proc/sys/kernel/audit_enabled # want: 1
sudo systemctl is-active auditd # want: active
sudo ausearch -k cmdlog -i | tail -40 # human-readable command audit
sudo aureport -x --summary # summary of executables run
```
---
## 5. Device-specific quirks (Huawei Kylin ARM64)
- **Architecture is ARM64 (aarch64).** Software must have an ARM64 build; x86-only
proprietary apps will not install/run.
- **`/boot` is a separate ext4 partition mounted read-only.** Remount rw to change
GRUB, then back to ro (see §4.3).
- **Boot likely controlled by Huawei firmware**, limiting effectiveness of GRUB
cmdline edits.
- **Hotspot link needs `aes256-ctr` / `hmac-sha2-256`** or SSH fails with
"Corrupted MAC on input".
---
## 6. Quick reference
```powershell
# Connect
ssh kylin
# Run a one-off command from Windows
ssh kylin "uptime"
# Run an admin command from Windows
ssh kylin "sudo systemctl status ssh"
# See logged commands
ssh kylin "sudo tail -50 /var/log/cmdlog.log"
# Watch live
ssh kylin "sudo tail -f /var/log/cmdlog.log"
# SSH login history
ssh kylin "last"
```
---
## 7. Troubleshooting
| Symptom | Cause / Fix |
|---------|-------------|
| `Corrupted MAC on input` | Use `-c aes256-ctr -m hmac-sha2-256` (already in config) |
| `Connection timed out` | Both devices not on same hotspot, or AP/client isolation on the phone — disable isolation |
| `ssh kyln` "could not resolve" | Alias spelling — config now accepts both `kylin` and `kyln` |
| Still asks for password | SSH key not copied (§2.3) |
| `sudo` asks for password | sudoers drop-in empty/missing (§2.4) |
| `audit support not in kernel` | Kernel booted `audit=0`; needs reboot with `audit=1` (§4.3) |
| `cmdlog.log` empty | File not owned by `syslog:adm`; `sudo chown syslog:adm /var/log/cmdlog.log` then restart rsyslog |
| `grub.cfg: Read-only file system` | `/boot` is read-only; `sudo mount -o remount,rw /boot` first |
| VPN GUI app won't run (`GLIBC_2.34 not found`) | Kylin has glibc 2.31; modern Flutter/Electron clients need 2.34+. Use the Go-based mihomo core instead (see §8) |
---
## 8. VPN / proxy: mihomo + web dashboard
**Why not FlClash / GUI clients:** Kylin V10 SP1 has **glibc 2.31**, but FlClash 0.8.93
and similar modern GUI clients require **glibc 2.34+** and fail to run. Upgrading
glibc would risk breaking the OS. mihomo is a **statically-linked Go binary** with
no glibc dependency, so it runs fine — controlled via a browser dashboard.
### Current state
> **VPN is currently OFF.** The `mihomo` service is **stopped** and **disabled**
> (auto-start removed), so it stays off across reboots until re-enabled. Ports
> `7890`/`9090` are closed. The full configuration below is intact and ready to
> resume.
### Turn the VPN on / off (run on Kylin, or via `ssh kylin`)
```bash
# TURN ON (and restore auto-start on boot)
sudo systemctl enable --now mihomo
# TURN OFF for this session only (comes back on next reboot)
sudo systemctl stop mihomo
# TURN OFF and keep it off across reboots <-- current state
sudo systemctl stop mihomo && sudo systemctl disable mihomo
# Check state
systemctl is-active mihomo # active / inactive
systemctl is-enabled mihomo # enabled / disabled
```
> Reminder: if you had set the Kylin **system proxy** to `127.0.0.1:7890`, switch
> it back to "None" while the VPN is off, or apps will fail to reach the network.
### Desktop access
A launcher **"Mihomo VPN Dashboard"** was added to the app menu (Network category)
at `/usr/share/applications/mihomo-dashboard.desktop`; it opens
`http://127.0.0.1:9090/ui/`. (Only works while the service is running.)
### Installed components
| Item | Location / value |
|------|------------------|
| mihomo core | `/usr/local/bin/mihomo` (Clash.Meta v1.19.27, arm64) |
| Config | `/etc/mihomo/config.yaml` |
| Web dashboard (zashboard) | `/etc/mihomo/ui/` |
| systemd service | `/etc/systemd/system/mihomo.service` (auto-starts on boot) |
| Proxy port (HTTP+SOCKS) | `7890` |
| Dashboard API | `0.0.0.0:9090` |
| Dashboard secret | `428968aebf7c301565c6b6d3a11826c4` |
### Install steps (done; for reference / rebuild)
```bash
# binary (downloaded on Windows through VPN, scp'd over to dodge chicken-and-egg)
gunzip mihomo-linux-arm64-vX.gz
sudo install -m 755 mihomo-linux-arm64 /usr/local/bin/mihomo
# dashboard
sudo mkdir -p /etc/mihomo/ui && sudo unzip zashboard-dist.zip -d /etc/mihomo/ui
# config.yaml: mixed-port 7890, external-controller 0.0.0.0:9090, secret, external-ui: ui,
# proxy-providers (subscription URL), PROXY (select) + AUTO (url-test) groups
sudo systemctl enable --now mihomo
```
> The subscription URL lives in `/etc/mihomo/config.yaml` under `proxy-providers:`.
> `external-ui-name` must NOT be set (it makes mihomo look in a `ui/<name>` subdir
> and auto-download); serve `/etc/mihomo/ui` directly.
### Open the dashboard
- **From Windows browser:** `http://192.168.43.248:9090/ui/`
- backend/API: `http://192.168.43.248:9090` • secret: `428968aebf7c301565c6b6d3a11826c4`
- **From Kylin desktop browser:** `http://127.0.0.1:9090/ui/`
### Use the proxy
Point apps at `127.0.0.1:7890` (HTTP/SOCKS), or set the Kylin system proxy
(Settings → Network → Proxy → Manual → `127.0.0.1:7890`). For transparent
whole-system routing, enable mihomo **TUN mode** (`/dev/net/tun` is present).
### Manage via API (examples)
```bash
S=428968aebf7c301565c6b6d3a11826c4
# switch PROXY group to a node / AUTO
curl -X PUT -H "Authorization: Bearer $S" http://127.0.0.1:9090/proxies/PROXY -d '{"name":"AUTO"}'
# verify exit IP goes through the proxy
curl -x http://127.0.0.1:7890 -s https://api.ip.sb/geoip
# update subscription / reload
sudo systemctl restart mihomo
```
**Verified working:** exit IP resolved to Singapore and `google.com/generate_204`
returned HTTP 204 through the proxy.
---
## 9. Browsers
| Browser | App-menu name | Type / location | Notes |
|---------|---------------|-----------------|-------|
| **Chromium** | "Chromium" | snap `chromium` v149 (`/snap/bin/chromium`) | Installed as the Chrome/Edge equivalent — same engine, Chrome Web Store extensions work. **Set as the default browser.** |
- **Chrome & Edge cannot be installed** — neither has an official ARM64 Linux build
(same architecture wall as the VPN GUI clients). Chromium is the substitute.
- Installing the chromium snap first required **updating snapd** (Kylin shipped 2.54,
too old → error `assumes unsupported features: snapd2.55`). Fix:
`sudo snap install snapd` (brought it to 2.75.2), then `sudo snap install chromium`.
- Default browser is recorded in `~/.config/mimeapps.list`
(`text/html`, `x-scheme-handler/http(s)``chromium_chromium.desktop`). If a
double-click opens the wrong app, right-click the file → **Open with → Chromium →
Set as default**.
### Desktop instruction files (for the user at the machine)
- `~/桌面/VPN_Guide.html` + `~/桌面/VPN_Guide.md` (copies also in `~/Desktop/`):
a user-facing "how to turn the VPN on/off" guide. Double-click the **`.html`** to
read it rendered in a browser; the **`.md`** opens in **VS Code** (`code`, installed)
with `Ctrl+Shift+V` preview.
- App-menu launcher **"Mihomo VPN Dashboard"** → opens `http://127.0.0.1:9090/ui/`
(only works while the mihomo service is running).
---
## 10. Inventory — everything set up on the Kylin machine
| Area | What | State |
|------|------|-------|
| Access | SSH alias `kylin`/`kyln`, key login, passwordless sudo | ✅ active |
| Monitoring | SSH login logs (`auth.log`); command logging → `/var/log/cmdlog.log` | ✅ active |
| Monitoring | auditd execve rule | ⏳ queued (needs reboot + `audit=1`; may not take on Huawei firmware) |
| VPN | mihomo core + zashboard dashboard, subscription configured | ⛔ installed, **OFF** (stopped + disabled) |
| Browser | Chromium v149 (default), 360/CNOOC browser | ✅ installed |
| Editors | VS Code (`code`), pluma, WPS Office | ✅ pre-installed |
| IDE | Cursor 3.7.27 (`/opt/cursor`) via `env -i` wrapper | ✅ installed (see §11) |
| Desktop docs | `VPN_Guide.html` / `.md`, dashboard launcher | ✅ on desktop |
---
## 11. Cursor IDE (Electron) — install + crash fixes
Cursor (AI code editor, Electron-based) installed as an **extracted AppImage** at
`/opt/cursor` (currently **v3.7.27**, ARM64). It will NOT run with a normal launcher
on this Huawei/Kylin box — it needs a special wrapper.
### Why the special launcher (three Kylin/Huawei ARM64 problems)
1. **EFAULT machine-ID probe crash** — Cursor runs a command to generate a unique
machine ID; the Kylin kernel blocks that memory `write` as suspicious →
`Error: EFAULT: bad address in system call argument, write` → instant crash.
**Fix:** `env -i` strips the environment (especially D-Bus) so Cursor skips the probe.
2. **Mali GPU crash (段错误 / segfault)** — hardware rendering conflicts with Huawei's
Mali GPU driver (`dmesg`: `mali gpu: kctx ... create/destroyed` at crash time).
**Fix:** `--disable-gpu` (software rendering).
3. **Blocked sandbox**`--no-sandbox`.
Also installed `xdg-desktop-portal` + `xdg-desktop-portal-gtk` (1.6.0) for the
Wayland file picker (necessary but not sufficient alone).
### The launcher (already installed)
- **Wrapper:** `/usr/local/bin/cursor-launch`
- **Start-menu entry:** `/usr/share/applications/cursor.desktop``Exec=/usr/local/bin/cursor-launch %F`
```sh
#!/bin/sh
exec env -i \
HOME="$HOME" DISPLAY="${DISPLAY:-:0}" PATH="$PATH" \
/opt/cursor/usr/share/cursor/cursor --no-sandbox --disable-gpu "$@"
```
### Updating Cursor to a newer version
1. Get the latest ARM64 AppImage URL (downloads on Windows through the VPN):
```bash
curl -sL -A "Mozilla/5.0" -H "Accept: application/json" \
"https://www.cursor.com/api/download?platform=linux-arm64&releaseTrack=stable"
# -> JSON with "downloadUrl" (…/Cursor-X.Y.Z-aarch64.AppImage) and "version"
curl -L -C - -o Cursor-new.AppImage "<downloadUrl>"
```
2. `scp` it to Kylin, then:
```bash
chmod +x Cursor-new.AppImage
cd /tmp && ./Cursor-new.AppImage --appimage-extract # -> /tmp/squashfs-root
sudo rm -rf /opt/cursor && sudo cp -r /tmp/squashfs-root /opt/cursor
sudo chown -R root:root /opt/cursor && rm -rf /tmp/squashfs-root
```
3. **No change needed** to the wrapper or menu entry — paths stay the same.
Verify glibc first (must need ≤ 2.31): `objdump -T /opt/cursor/usr/share/cursor/cursor | grep -oE 'GLIBC_[0-9.]+' | sort -V | tail`.
### Cleanup note
Old AppImages in `~/software/` (`Cursor-3.2.11`, `Cursor-3.7.27`) and the user's
manual extract `~/software/squashfs-root` (3.2.11) are redundant now that `/opt/cursor`
is the install — safe to delete to reclaim space.