以下是从零开始的完整操作指南,基于 ttyd + tmux,适用于 Debian (arm64)、内存 ≥ 256MiB 的设备。最终效果:

  • 浏览器打开 http://设备IP:8080 弹出认证框(用户名/密码)
  • 登录后看到上半屏实时系统监控面板,下半屏为可交互终端
  • 开机自启,无需手动干预

1. 基础环境

  • 系统:Debian 12 (Bookworm) 或 Debian 11,架构 aarch64
  • 确保网络连通,已使用 root 登录

2. 安装 ttyd(aarch64 版本)

1
2
3
4
5
6
7
8
9
10
11
# 下载 ttyd 1.7.7 aarch64 二进制文件
wget -O /usr/local/bin/ttyd https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.aarch64

# 如果下载慢,可换成国内镜像:
# wget -O /usr/local/bin/ttyd https://ghproxy.com/https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.aarch64

# 赋予执行权限
chmod +x /usr/local/bin/ttyd

# 验证版本
ttyd --version

3. 安装 tmux(如未安装)

1
apt update && apt install tmux -y

4. 创建详细的中文监控脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
cat > /root/panel_cn.sh << 'EOF'
#!/bin/bash
export LC_ALL=C
printf '\033[2J'
printf '\033[1;36m══════════════════════════════════════════════\033[0m\n'
printf '\033[1;36m 系统资源面板 (每2秒刷新)\033[0m\n'
printf '\033[1;36m══════════════════════════════════════════════\033[0m\n'

# 基础信息
hostname=$(hostname)
kernel=$(uname -r)
uptime_str=$(awk '{print int($1)}' /proc/uptime)
uptime_h=$((uptime_str/3600))
uptime_m=$(( (uptime_str%3600)/60 ))
cpu_model="骁龙 410 " # 根据实际设备修改
cores=$(nproc)
freq=$(cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq 2>/dev/null)
if [ -n "$freq" ]; then
freq=$((freq/1000))" MHz"
else
freq="未知"
fi

printf "\033[1;37m主机名:\033[0m %-10s \033[1;37m内核:\033[0m %-16s \033[1;37m运行时间:\033[0m %d小时%d分\n" "$hostname" "$kernel" $uptime_h $uptime_m
printf "\033[1;37mCPU 型号:\033[0m %-10s \033[1;37m核心数:\033[0m %d \033[1;37m频率:\033[0m %s\n" "$cpu_model" $cores "$freq"

# CPU 使用率
read cpu a b c idle rest < /proc/stat
sleep 0.3
read cpu a2 b2 c2 idle2 rest2 < /proc/stat
total1=$((a+b+c+idle))
total2=$((a2+b2+c2+idle2))
idle_diff=$((idle2-idle))
total_diff=$((total2-total1))
if [ $total_diff -gt 0 ]; then
cpu_pct=$((100*(total_diff-idle_diff)/total_diff))
usr_pct=$((100*(a2-a)/total_diff))
sys_pct=$((100*(b2-b)/total_diff))
idle_pct=$((100*idle_diff/total_diff))
else
cpu_pct=0; usr_pct=0; sys_pct=0; idle_pct=100
fi
bars=$((cpu_pct/10))
printf "\033[1;37mCPU 使用率:\033[0m ["
for i in $(seq 1 $bars); do printf "\033[1;32m█\033[0m"; done
for i in $(seq $((10-bars))); do printf "░"; done
printf "] %d%%\t用户 %d%% 系统 %d%% 空闲 %d%%\n" $cpu_pct $usr_pct $sys_pct $idle_pct

printf "\033[1;37m──────────────────────────────────────────────\033[0m\n"

# 内存
mem_line=$(free | awk '/^Mem|^内存/{print $2,$3,$4,$5,$6,$7}')
[ -z "$mem_line" ] && mem_line=$(free | awk '/^Mem:/{print $2,$3,$4,$5,$6,$7}')
total_kb=$(echo $mem_line | awk '{print $1}')
used_kb=$(echo $mem_line | awk '{print $2}')
free_kb=$(echo $mem_line | awk '{print $3}')
shared_kb=$(echo $mem_line | awk '{print $4}')
cache_kb=$(echo $mem_line | awk '{print $5}')
avail_kb=$(echo $mem_line | awk '{print $6}')
conv() {
kb=$1
if [ $kb -ge 1048576 ]; then
printf "%.1fGi" $(echo "scale=1; $kb/1048576" | bc 2>/dev/null || echo "0")
elif [ $kb -ge 1024 ]; then
printf "%.0fMi" $(echo "scale=0; $kb/1024" | bc 2>/dev/null || echo "0")
else
printf "%.0fKi" $kb
fi
}
printf "\033[1;33m▶ 内存\033[0m\n"
printf " %-6s %-6s %-6s %-6s %-10s %-6s\n" "总计" "已用" "空闲" "共享" "缓冲/缓存" "可用"
printf " %-6s %-6s %-6s %-6s %-10s %-6s\n" "$(conv $total_kb)" "$(conv $used_kb)" "$(conv $free_kb)" "$(conv $shared_kb)" "$(conv $cache_kb)" "$(conv $avail_kb)"

swap_line=$(free | awk '/^Swap|^交换/{print $2,$3}')
if [ -n "$swap_line" ]; then
swap_total_kb=$(echo $swap_line | awk '{print $1}')
swap_used_kb=$(echo $swap_line | awk '{print $2}')
[ $swap_total_kb -gt 0 ] && swap_pct=$((100*swap_used_kb/swap_total_kb)) || swap_pct=0
printf "交换: %s / %s (%d%%)\n" "$(conv $swap_used_kb)" "$(conv $swap_total_kb)" $swap_pct
fi

printf "\033[1;37m──────────────────────────────────────────────\033[0m\n"

# 磁盘
disk_line=$(df -h / | tail -1)
printf "\033[1;33m▶ 根目录磁盘 /\033[0m 总:%s 已用:%s 可用:%s (%s)\n" $(echo $disk_line | awk '{print $2,$3,$4,$5}')

printf "\033[1;37m──────────────────────────────────────────────\033[0m\n"

# 网络
iface=$(ip route show default 2>/dev/null | awk '{print $5}' | head -1)
[ -z "$iface" ] && iface=$(ls /sys/class/net/ | grep -v lo | head -1)
if [ -n "$iface" ]; then
ip_addr=$(ip -4 addr show $iface | grep inet | awk '{print $2}' | head -1)
rx1=$(cat /sys/class/net/$iface/statistics/rx_bytes 2>/dev/null || echo 0)
tx1=$(cat /sys/class/net/$iface/statistics/tx_bytes 2>/dev/null || echo 0)
sleep 0.3
rx2=$(cat /sys/class/net/$iface/statistics/rx_bytes 2>/dev/null || echo 0)
tx2=$(cat /sys/class/net/$iface/statistics/tx_bytes 2>/dev/null || echo 0)
rx_speed=$(( (rx2-rx1)*10/3 ))
tx_speed=$(( (tx2-tx1)*10/3 ))
format_speed() {
speed=$1
if [ $speed -gt 1048576 ]; then
printf "%.1f MB/s" $(echo "scale=1; $speed/1048576" | bc 2>/dev/null || echo "0")
elif [ $speed -gt 1024 ]; then
printf "%.1f KB/s" $(echo "scale=1; $speed/1024" | bc 2>/dev/null || echo "0")
else
printf "%d B/s" $speed
fi
}
printf "\033[1;33m▶ 网络 (%s)\033[0m IP: %s\n" "$iface" "$ip_addr"
printf " 接收: %s 发送: %s\n" "$(format_speed $rx_speed)" "$(format_speed $tx_speed)"
else
printf "\033[1;33m▶ 网络\033[0m 无活动接口\n"
fi

printf "\033[1;37m──────────────────────────────────────────────\033[0m\n"

# 负载
load=$(cat /proc/loadavg | awk '{print $1,$2,$3}')
printf "\033[1;33m▶ 负载 (1/5/15min):\033[0m %s\n" "$load"

# 温度
temp=$(cat /sys/class/thermal/thermal_zone0/temp 2>/dev/null)
if [ -n "$temp" ]; then
printf "\033[1;33m▶ CPU 温度:\033[0m %d°C\n" $((temp/1000))
else
printf "\033[1;33m▶ CPU 温度:\033[0m 无传感器\n"
fi

printf "\033[1;37m──────────────────────────────────────────────\033[0m\n"

# 进程排名(过滤自身)
printf "\033[1;33m▶ 最耗 CPU 的 3 个进程\033[0m\n"
ps aux --sort=-%cpu | grep -vE "watch|ttyd|panel_cn|grep|ps" | awk 'NR>1{printf " %-10s %5.1f%%\n", $11, $3}' | head -3
printf "\033[1;33m▶ 最耗内存的 3 个进程\033[0m\n"
ps aux --sort=-%mem | grep -vE "watch|ttyd|panel_cn|grep|ps" | awk 'NR>1{printf " %-10s %6s\n", $11, $6}' | head -3
EOF

chmod +x /root/panel_cn.sh

如果设备不是骁龙410,请修改脚本中 cpu_model 变量为实际型号,或使用 lscpu 动态获取。

5. 创建 tmux 分屏启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
cat > /root/start_tmux_panel.sh << 'EOF'
#!/bin/bash
tmux kill-session -t panel 2>/dev/null
sleep 0.2
tmux new-session -d -s panel -n main
tmux send-keys -t panel "watch -n 2 -c /root/panel_cn.sh" Enter
tmux split-window -v -t panel
tmux send-keys -t panel "clear; echo '终端已就绪,可输入命令'" Enter
tmux select-pane -t 1
EOF

chmod +x /root/start_tmux_panel.sh

6. 设置密码(环境变量文件)

1
2
echo 'TTYD_CREDENTIALS="admin:123456"' > /etc/ttyd_env
chmod 600 /etc/ttyd_env

请立即修改 123456 为强密码,用户名也可自定义。

7. 创建 systemd 服务(带密码保护 + 开机自启)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
cat > /etc/systemd/system/ttyd-panel.service << 'EOF'
[Unit]
Description=ttyd web terminal with tmux panel
After=network.target

[Service]
Type=simple
User=root
EnvironmentFile=/etc/ttyd_env
ExecStartPre=-/usr/bin/tmux kill-session -t panel 2>/dev/null || true
ExecStartPre=/bin/sleep 0.5
ExecStartPre=/root/start_tmux_panel.sh
ExecStart=/usr/local/bin/ttyd -p 8080 -W -c ${TTYD_CREDENTIALS} tmux attach-session -t panel
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

8. 启动服务并设置开机自启

1
2
systemctl daemon-reload
systemctl enable --now ttyd-panel.service

9. 检查服务状态

1
systemctl status ttyd-panel.service

应看到 active (running),且无报错。

10. 访问面板

在局域网内任意设备浏览器打开 http://设备IP:8080

  • 弹出登录框,输入用户名 admin,密码 123456(你设置的密码)
  • 登陆后,上半部分为每2秒刷新的彩色系统监控面板
  • 下半部分为可交互的 Linux 终端(光标默认在下半部分)

11. 日常管理命令

1
2
3
4
5
6
7
8
9
10
# 修改密码
nano /etc/ttyd_env
systemctl restart ttyd-panel.service

# 停止 / 重启面板
systemctl stop ttyd-panel.service
systemctl restart ttyd-panel.service

# 查看服务日志
journalctl -u ttyd-panel.service -f

12. 公网访问安全建议(内网穿透时)

  • 使用 SSH 隧道(最安全):ssh -L 8080:localhost:8080 user@你的服务器IP
  • 或配置 Nginx 反向代理 + HTTPS,并添加 HTTP 基本认证,双重加密
  • 避免将 8080 端口直接暴露在公网且仅使用 HTTP 明文传输
  • cloudflare内网穿透

以上步骤完成后,你的 Debian 设备就拥有了一套轻量、安全、开机即用的远程监控与管理系统。