TNAS Docker 部署 Kaneo · SSH 认证与组网排障实录
本文为部署实录,已做脱敏:IP、用户名、密码、密钥、主机名、密钥指纹等关键信息均以占位符或掩码呈现,仅保留可复用的方法论与技术细节。
一、结果
| 项 | 值 |
|---|---|
| 目标 | TerraMaster NAS(TOS 3.x, x86_64, 主机名 TNAS-xxxx)上部署 Kaneo |
| 方案 | docker-compose:postgres:16-alpine + ghcr.io/usekaneo/kaneo:latest |
| 部署路径 | /Volume1/Docker/kaneo/(compose + .env) |
| 对外端口 | 5173(数据库 5432 仅容器网内,不发布主机) |
| 验证 | 容器双 healthy;/api/health 返回 {"status":"ok"};外部 HTTP 200 |
二、最坑的一段:SSH 密码正确却全线被拒
现象
笔记记录的凭据(用户名 + 密码 + SSH 端口)通过三种客户端反复尝试——OpenSSH ssh、PuTTY plink、Python paramiko——全部 Authentication failed,而人工登录却能成功。
期间排除掉的假设:
-
密码错 → 三种客户端发送链路逐一验证(askpass 脚本直读输出确认字节无误),排除;
-
keyboard-interactive 特殊提示 → paramiko 抓取到服务器仅问一句
Password:,排除; -
换了不同的服务器 → 见下文”主机密钥指纹比对”,确认同一台,排除;
-
本机密钥未注册 → 人工加公钥后仍被拒,说明问题不在密钥。
根因:记录的用户名就是错的
突破口来自用户回传的会话提示符:
[<用户名>@TNAS-xxxx ~]#
人工登录后 whoami 实测返回的用户名与笔记记录不一致。用实测用户名重试,密码与公钥同时立即通过。
方法论沉淀:
-
认证排障的终点是
whoami,不是猜密码。所有凭据变体被拒时,优先让人工登录后回传whoami/ 提示符原文; -
笔记中的凭据可能长期未核验,以实测为准;
-
一次排障覆盖 5 个用户名 × 2 密码仍全灭,说明”组合穷举”不如”一次实测”。
验证”是否同一台机器”:主机密钥指纹比对
人工会话与自动化会话各执行:
ssh-keygen
将输出的 SHA256:**** 指纹与本机连接时握手拿到的指纹(ssh -vv 或 known_hosts)比对——一致即同一 sshd。这一步排除了”同 IP 不同机 / 隧道指向别的设备”的假设,把排查收敛回认证本身。
三、顺带的发现:本机到 NAS 的流量并不走局域网
排障中注意到反常信号:
-
192.168.1.x在 WLAN 网卡上的 ARP 始终 Incomplete(00-00-00-00-00-00); -
ping 延迟 23ms——同网段局域网应 <5ms;
-
Find-NetRoute -RemoteIPAddress <NAS_IP>返回出口为 EasyTier 虚拟网卡(et_*),而非 WLAN。
原因是双路由并存:
| 目的网段 | 出口 | 接口 metric | 路由 metric |
|---|---|---|---|
| 192.168.1.0/24 | WLAN | 35 | 256 |
| 192.168.1.0/24 | EasyTier 虚拟网卡 | 5 | 9000 |
Windows 用接口 metric + 路由 metric 综合选路,EasyTier 接口的低接口 metric 压过了 WLAN,实际流量全部经隧道到达异地 NAS。
排障信号优先级:ARP Incomplete + 异常延迟 + Find-NetRoute,三者组合基本可断定”你以为的局域网 IP 其实走着 VPN”。这对理解”为何本机连不上、别的设备连得上”类问题很关键。
四、Windows → TOS 远程自动化的踩坑集
| 坑 | 现象 | 解法 |
|---|---|---|
| plink 主机密钥 | -batch 下拒绝确认密钥,-hostkey 各种格式均报 invalid | -hostkey SHA256:<指纹>(冒号格式);或注册表预写无效,指纹格式才可靠 |
| sshpass 不存在 | Windows 无 sshpass、pip 装不到 | SSH_ASKPASS_REQUIRE=force + SSH_ASKPASS 指向输出密码的 .cmd 脚本 |
| paramiko keyboard-interactive | 回调返回 [(答案, echo)] 元组报 bytes-like required | 回调应返回纯字符串列表 ['密码'] |
| PowerShell 引号地狱 | 内联 python/ssh 命令含 ` | && —format` 被 PS 解析截断 |
| scp 被服务端禁用 | Connection closed | base64-over-ssh:`echo |
| ssh 后台任务挂起 | nohup ... & 仍挂住 ssh 会话 | 三重重定向 >/log 2>&1 </dev/null & + 客户端加 -n |
| 长拉取超时 | 前台 docker pull 超时杀进程,NAS 上仍继续 | 后台 nohup 拉取写日志,本地轮询 grep PULL_DONE |
| 输出编码 | docker 日志含 emoji,GBK 控制台 UnicodeEncodeError | sys.stdout.reconfigure(encoding='utf-8', errors='replace') |
五、TOS 环境特有的点
-
docker 不在非登录 shell PATH:裸
ssh host docker ...报 command not found,必须bash -lc 'docker ...'; -
无 compose 插件:
docker compose不可用,独立二进制在/Volume1/@apps/DockerEngine/dockerd/bin/docker-compose(v2.x),登录 shell 下可直接docker-compose; -
无 curl/wget:TOS 提供
ter_前缀替代品,健康检查尽量在容器内做(kaneo 自带 wget healthcheck); -
存储惯例:项目落
/Volume1/Docker/<项目名>/,数据盘 3.x TB 独立于系统盘; -
镜像源:Docker Hub 与 ghcr.io 均直连可达,但 ghcr 层重试频繁(Retrying in N seconds),务必后台拉取 + 轮询;
-
端口冲突排查:
docker ps --format "{{.Names}}\t{{.Ports}}"先看存量容器(本机已有 penpot 9001、gitlab 8929 等),再定新服务端口。
六、Kaneo 部署要点
# 核心结构:postgres 等 healthy 后才起 kaneo
services
postgres
image
healthcheck
kaneo
image
ports
depends_on
postgres
-
.env最少三项:KANEO_CLIENT_URL、POSTGRES_PASSWORD、AUTH_SECRET(openssl rand -hex 32,必须持久固定,变动会使全部会话失效); -
数据库端口不要发布到主机,容器网内互通即可;
-
首次访问
http://<NAS内网IP>:5173注册首账户,注册完可设ALLOW_REGISTRATION: false关闭注册; -
升级:
docker-compose pull && docker-compose up -d。
七、可复用的排障顺序
-
先确认连的是谁:banner(
SSH-2.0-OpenSSH_x.x)+ 主机密钥指纹比对; -
再确认凭据:人工
whoami实测,胜过一切组合穷举; -
再确认路径:
Find-NetRoute/ ARP / 延迟,判断是否走 VPN; -
最后才是服务本身:容器状态、healthcheck、日志。