跳转至

启动速查

使用场景分类的命令速查表。每条命令都可以直接 copy-paste 用——把 X / Y 换成你自己的账号密码即可。

约定

  • X = 登录账号(手机号 / 牛牛号 / moomoo ID / 邮箱)
  • Y = 密码明文
  • Z = 短信验证码(首次登录时服务端发到手机)

1. 账号平台速选

富途有两个独立账号体系:牛牛(auth.futunn.com)和 moomoo (auth.moomoo.com)。两边都支持数字 ID / 手机号 / 邮箱三种格式 作为 --login-account。同一手机号 / 邮箱可以分别在两边注册独立账号 (不同密码)——用 --platform 显式选平台避免登到错账号。

# 牛牛账号(默认,CN / HK 归属)—— 数字 ID / 手机号 / 邮箱 任选一种
./futu-opend --login-account 12345678 --login-pwd Y
./futu-opend --login-account '+86-13900000000' --login-pwd Y
./futu-opend --login-account 'user@example.com' --login-pwd Y

# moomoo 账号(US / SG / AU / JP / CA 归属)—— 同样三种格式,加 --platform moomoo
./futu-opend --login-account 87654321 --login-pwd Y --platform moomoo
./futu-opend --login-account '+1-4155551234' --login-pwd Y --platform moomoo
./futu-opend --login-account 'user@example.com' --login-pwd Y --platform moomoo

手机号格式必须带区号 + 破折号

手机号请严格使用 +<区号>-<号码> 格式,如 +86-13900000000 / +1-4155551234,否则将导致识别失败。


2. 首次部署(推荐流程)

强烈推荐分两步:先前台 setup 一次完成 SMS,再启动生产实例。这样 systemd / Docker 场景不会在启动时卡 SMS。

# 第一步:前台跑一次 setup(会交互要求输入短信验证码)
./futu-opend --setup-only \
  --login-account X --login-pwd Y --platform moomoo

# 第二步:正常启动(自动用缓存凭据跳过 SMS)
./futu-opend --login-account X --login-pwd Y --platform moomoo \
  --rest-port 22222 --grpc-port 33333

--setup-only 完成认证后立即退出,不启动任何 server。凭据会写到 ~/.futu-opend-rs/credentials-<hash>.json,30 天内不再要 SMS。


3. 生产环境(无人值守)

systemd

/etc/systemd/system/futu-opend.service

[Unit]
Description=FutuOpenD Rust Gateway
After=network-online.target

[Service]
Type=simple
User=futu
Environment=FUTU_ACCOUNT=...
Environment=FUTU_PWD=...
ExecStart=/usr/local/bin/futu-opend \
  --login-account ${FUTU_ACCOUNT} --login-pwd ${FUTU_PWD} \
  --platform moomoo \
  --rest-port 22222 --grpc-port 33333 \
  --rest-keys-file /etc/futu-opend/keys.json \
  --grpc-keys-file /etc/futu-opend/keys.json \
  --audit-log /var/log/futu-opend/audit.jsonl
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

部署步骤

# 1. 前台跑一次 setup 写 credentials(用 futu 用户身份)
sudo -u futu /usr/local/bin/futu-opend --setup-only \
  --login-account X --login-pwd Y --platform moomoo

# 2. 启动 systemd 服务
sudo systemctl enable --now futu-opend

Docker

docker run -d --name futu-opend --restart unless-stopped \
  -p 11111:11111 -p 22222:22222 -p 33333:33333 \
  -v ~/.futu-opend-rs:/root/.futu-opend-rs \
  -v /etc/futu-opend/keys.json:/etc/futu-opend/keys.json:ro \
  ghcr.io/futuleaf/futu-opend-rs:rs-v1.4.17 \
  --login-account X --login-pwd Y --platform moomoo \
  --rest-port 22222 --grpc-port 33333 \
  --rest-keys-file /etc/futu-opend/keys.json \
  --grpc-keys-file /etc/futu-opend/keys.json

凭据目录挂载

-v ~/.futu-opend-rs:/root/.futu-opend-rs 至关重要 —— 容器重建后 device_idcredentials 需要持久化,否则每次重启都要重新 SMS 验证。


4. 多实例并行(牛牛 + moomoo 同时跑)

常见场景:一个账号在牛牛、一个在 moomoo,想同时连两个后端。端口必须错开, 否则 futucli 默认连 127.0.0.1:11111 会指向错的实例。

# 实例 A:牛牛账号(默认端口)
./futu-opend --login-account 12345678 --login-pwd Y1 \
  --rest-port 22222 --grpc-port 33333 &

# 实例 B:moomoo 账号(端口 +1)
./futu-opend --login-account '+86-13900000000' --login-pwd Y2 --platform moomoo \
  --port 11112 --rest-port 22223 --grpc-port 33334 &

v1.4.16 起启动时会检测端口占用,冲突会打 WARN 日志提醒你。

客户端访问:

curl http://localhost:22222/api/accounts   # 牛牛
curl http://localhost:22223/api/accounts   # moomoo

5. 调试与开发

# 详细日志(看协议帧 + HTTP 请求响应)
./futu-opend --login-account X --login-pwd Y --log-level trace

# 只看鉴权流程(POST raw response / salt / tgtgt 关键行)
./futu-opend --login-account X --login-pwd Y --log-level debug 2>&1 \
  | grep -E "POST.*raw|salt|tgtgt|error_code"

# JSON 结构化日志(给 logging pipeline / Loki / ELK)
./futu-opend --login-account X --login-pwd Y --json-log

# 单独写审计日志(只记 auth / 交易事件,常规日志不变)
./futu-opend --login-account X --login-pwd Y \
  --audit-log /var/log/futu-opend/audit.jsonl

6. 故障恢复

device_id 被锁(ret_type=15ret_type=21

# 方法 A:清空文件 + 重新 setup(推荐,最彻底)
./futu-opend --reset-device --setup-only \
  --login-account X --login-pwd Y --platform moomoo

# 方法 B:换一个特定 device_id(不触发新 SMS 的情况,比如迁移机器时)
./futu-opend --device-id abcdef0123456789 \
  --login-account X --login-pwd Y

# 方法 C:手动清所有状态(怀疑所有缓存都坏了)
rm -rf ~/.futu-opend-rs/

v1.4.17 起,SMS 验证码输错(error_code=21自动轮换 device_id 重试 2 次, 一般不用手动处理。

密码对了但 error_code=2 账号密码不匹配

几乎一定是平台选错了(moomoo 账号发到 futunn 了,或反之):

# 加 --platform 显式指定
./futu-opend --login-account X --login-pwd Y --platform moomoo

连接卡住(Connection timed out

v1.4.10 加了 10s 超时,v1.4.11 按地区选 IP 池,v1.4.12 并发 3 IP 竞速。 新版一般不会卡。如仍挂:

# 看具体卡在哪
./futu-opend --login-account X --login-pwd Y --log-level debug

# 如果是海外账号但所在区域 IP 全不通(ISP 屏蔽),只能走 VPN

客户端侧常见症状

症状 原因 处理
connect refused :11111 网关根本没起来 / 被别的进程占端口 futu-opend 控制台日志;v1.4.16+ 启动时会 WARN 端口占用
account/password mismatch 登录凭证错 --login-account / --login-pwd,或加 --platform moomoo 选对平台
device not authorized 新设备需短信验证 前台跑一次 --setup-only 输入验证码
no subscription 先 subscribe 再 quote POST /api/subscribePOST /api/quote
gRPC UNAUTHENTICATED 没带 Bearer Token 或 key 错 看下一节配 --grpc-keys-file

7. 登录密码安全存储(v1.4.18+)

避免明文密码出现在 ps aux / ~/.bash_history / 配置文件 backup 里。 opend 按 7 层优先级查密码,推荐用 OS keychain

# 一次性存到 keychain(macOS Keychain / Linux Secret Service / Windows Credential Manager)
futucli set-login-pwd --account 12345678
# 交互式输入密码,不回显不进 history

# 之后启动 opend 不带 --login-pwd,自动从 keychain 读
./futu-opend --login-account 12345678 --platform moomoo --rest-port 22222

7 层优先级(高到低)

优先级 方式 适用场景 安全
1 --login-pwd-file <path> Docker secrets / systemd LoadCredential ⭐⭐⭐⭐⭐
2 --login-pwd <plain> 老脚本兼容(会打 WARN) ⭐ 暴露在 argv
3 --login-pwd-md5 <hex> 同上,md5 等同明文 ⭐ 暴露在 argv
4 FUTU_PWD env var CI / cron / bash export ⭐⭐⭐ 无 argv 泄露
5 OS keychain 长期本地 / 服务器(推荐默认) ⭐⭐⭐⭐
6 交互式 prompt(stdin 是 tty) 本地开发随手跑 ⭐⭐⭐⭐ 不回显不进 history
7 以上都没有 报错退出

部署场景选择指南

# A. 本地长期使用(最推荐)
futucli set-login-pwd --account 12345678          # 一次性
./futu-opend --login-account 12345678 ...         # 每次启动自动读 keychain

# B. Docker(用 secret 挂载到文件)
docker run -v pwd-file:/run/secrets/futu-pwd:ro \
  ghcr.io/futuleaf/futu-opend-rs \
  --login-account X --login-pwd-file /run/secrets/futu-pwd ...

# C. systemd(LoadCredential 从 EncryptedDir / TPM 读)
# /etc/systemd/system/futu-opend.service
[Service]
LoadCredential=login-pwd:/etc/futu/pwd
ExecStart=/usr/local/bin/futu-opend \
  --login-account X \
  --login-pwd-file ${CREDENTIALS_DIRECTORY}/login-pwd ...

# D. CI / cron(FUTU_PWD env)
FUTU_PWD='...' ./futu-opend --login-account X ...

# E. 本地随手跑(啥都不配,会弹 prompt)
./futu-opend --login-account 12345678 ...
# → "Login password for account 12345678: "

清除密码

futucli clear-login-pwd --account 12345678

8. REST / gRPC / 核心 WebSocket 鉴权

生产环境强烈建议加 Bearer Token 鉴权,否则 /api/* 端口对所有客户端 开放。

# 1. 生成 API key(限定 scope + 过期时间)
futucli gen-key \
  --keys-file ~/.futu-opend-rs/keys.json \
  --scopes quote,trade:read \
  --expires 30d

# 2. 启动 opend 带 keys-file
./futu-opend --login-account X --login-pwd Y \
  --rest-keys-file ~/.futu-opend-rs/keys.json \
  --grpc-keys-file ~/.futu-opend-rs/keys.json \
  --ws-keys-file   ~/.futu-opend-rs/keys.json \
  --rest-port 22222 --grpc-port 33333 --websocket-port 44444

# 3. 客户端带 Bearer token 访问
curl -H "Authorization: Bearer <key_plaintext>" \
  http://localhost:22222/api/qot/get_global_state

详细的 scope 表和 key 管理见 API Key 授权配置


9. 网络受限场景(进阶)

走 HTTPS 代理(调试 / 抓包)

# --auth-server 显式指定时,不会被 attribution 自动切换覆盖(v1.4.15+)
./futu-opend --login-account X --login-pwd Y \
  --auth-server http://127.0.0.1:19998

用自写的 HTTP 代理(比如 mitmproxy)可以抓到完整的 /authority/saltPOST /authority/ 请求体,用于调试账号识别问题。

海外账号 IP 不通

富途的海外 IP 偶尔被 ISP 屏蔽。现象:所有 HK/US 地区的 IP 全 connect timeout(10s 后失败),gateway 进 offline mode。

# 先确认是不是网络问题
for ip in 101.32.217.163 43.135.111.64; do
  nc -vz $ip 9595   # 或 `timeout 5 bash -c "</dev/tcp/$ip/9595"`
done
  • 全 FAIL,CN IP 能通 → ISP 屏蔽了海外段 → 走 VPN
  • 全 FAIL,443 能通但 9595 不通 → 防火墙挡 9595 → IT 开端口
  • 部分通 → 等 v1.4.12 的并发竞速自动选通的 IP

10. 凭据文件位置

v1.4.17 起所有持久化文件统一在 ~/.futu-opend-rs/

~/.futu-opend-rs/
├── device-<hash>.dat              # 16-hex device_id(每 account 一份)
├── credentials-<hash>.json        # device_sig + tgtgt + rand_key + uid
└── keys.json                      # (可选)API key 文件

<hash> = md5(normalized_account)[..16],所以 +86-1390000000013900000000 共享同一份文件(归一化会把区号拆出去)。

什么时候删这些文件

情况 删哪个
device_id 被服务端锁定 device-<hash>.dat + credentials-<hash>.json(或用 --reset-device
换了密码 credentials-<hash>.json 保留,让重新 SMS 验证
切换平台(futunn ↔ moomoo) 无需删,两个平台有独立缓存
彻底清理 rm -rf ~/.futu-opend-rs/

索引