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

18 KiB
Raw Blame History

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):

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\configcaichl@192.168.43.248, with the pinned cipher/MAC already configured — see §2).

A fresh Claude Code session also auto-loads memory pointers (MEMORY.mdkylin-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

Host kylin kyln
    HostName 192.168.43.248
    User caichl
    Ciphers aes256-ctr
    MACs hmac-sha2-256

With this in place, simply run:

ssh kylin       # or: ssh kyln  (both aliases work)

The equivalent explicit command (no config) is:

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:

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:

# 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.:

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)

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)

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

# 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

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

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:

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

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

# 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)

# 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)

# 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)

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.desktopExec=/usr/local/bin/cursor-launch %F
#!/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):
    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:
    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.