Services
VPS agent
Agent AutoIt chạy trên mỗi VPS MT5: gửi heartbeat (CPU / RAM / Disk / Net, danh sách login MT5) về fxconsole, nhận lệnh deploy / gỡ / nâng cấp tài khoản và tự nâng cấp chính nó. Trang này hướng dẫn cài đặt, cấu hình, luồng heartbeat và lệnh, gói deploy và xử lý sự cố. The AutoIt agent on every MT5 VPS: it pushes heartbeats (CPU / RAM / Disk / Net, MT5 login list) to fxconsole, receives deploy / remove / upgrade commands for accounts, and upgrades itself. This page covers install, configuration, the heartbeat and command flows, deploy packages and troubleshooting.
Tổng quan nhanhAt a glance
| Thành phầnComponent | Phiên bảnVersion | Vai tròRole |
|---|---|---|
HeartbeatAgent.exe | 1.3.4-phase11 | Tiến trình vỏ sống lâu: stream tới broker qua stunnel, HTTPS dự phòng, IPC server 127.0.0.1:9606, giám sát CmdAgentLong-lived shell: broker stream via stunnel, HTTPS fallback, IPC server 127.0.0.1:9606, supervises CmdAgent |
CmdAgent.exe | 1.3.4-phase11 | Worker: thực thi add_account / remove_account / upgrade_account / upgrade_agent / rename_host, relaunch MT5 lúc bootWorker: runs add_account / remove_account / upgrade_account / upgrade_agent / rename_host, relaunches MT5 at boot |
stunnel.exe | 5.78 | Nghe 127.0.0.1:9605, bọc TLS tới VpsStreamBrokerListens on 127.0.0.1:9605, wraps TLS to VpsStreamBroker |
| TightVNC (service)(service) | 2.8.81 | Cổng 5900, cho Guacamole / VNC client xem desktop mà không khoá sessionPort 5900, lets Guacamole / a VNC client view the desktop without locking the session |
prepare-vm.ps1 | 2026-06-05.06 | Script cài đặt một lần, idempotent, kèm zero-touch initOne-shot, idempotent installer, including zero-touch init |
bootstrap-fresh-vm.ps1 | — | Chạy một lần cho mỗi image Windows mớiRuns once per fresh Windows image |
upgrade.ps1 | 2026-06-06.01 | Tự nâng cấp agent khi có lệnh upgrade_agentAgent self-upgrade on an upgrade_agent command |
Khi nâng cấp vpsagent hoặc deploy gói, nếu MT5 hiện "Welcome to LiveUpdate" thì phải trả lời Later. Nút mặc định là Restart, bấm vào sẽ tắt terminal, giết các EA đang chạy và mất trạng thái rổ lệnh trong bộ nhớ. Từ 1.3.2-phase9 CmdAgent tự quét và bấm Later ở mọi bước chờ GUI (deploy, relaunch, WebRequest) và không bao giờ gửi ENTER mù khi hộp thoại có thể đang mở. Khi bạn thao tác tay qua VNC, cũng chọn Later. Việc cập nhật terminal là thao tác riêng, có lên lịch.
When upgrading vpsagent or deploying packages, if MT5 shows "Welcome to LiveUpdate" the answer must be Later. The default button is Restart, which kills the terminal, its running EAs and any in-memory basket state. Since 1.3.2-phase9 CmdAgent sweeps for the prompt and clicks Later during every GUI wait (deploy, relaunch, WebRequest) and never sends a blind ENTER while it may be up. When you work by hand over VNC, choose Later too. Terminal updates are a separately scheduled operator action.
Kiến trúcArchitecture
flowchart LR
subgraph VPS["Windows VPS (AutoLogon session)"]
HB["HeartbeatAgent.exe"]
CA["CmdAgent.exe"]
ST["stunnel.exe 127.0.0.1:9605"]
VNC["TightVNC :5900"]
MT["MT5 terminals in C:\fxconsole-mt5 (one folder per login)"]
end
subgraph HOST["Docker host"]
VB["VpsStreamBroker :9605"]
APP["fxconsole app (HTTPS)"]
RED[("Redis")]
MY[("MySQL vpses / vps_commands")]
GD["guacd"]
end
HB -- "spawn + supervise" --> CA
HB -- "IPC NDJSON 127.0.0.1:9606" --- CA
HB -- "plain TCP" --> ST
ST -- "TLS" --> VB
HB -. "HTTPS fallback /api/vps/heartbeat" .-> APP
CA -- "HTTPS payload + package download" --> APP
CA -- "launch / GUI automation" --> MT
VB --> RED
VB --> MY
APP --> MY
GD -- "VNC" --> VNC- Chỉ đẩy ra, không cổng vào. VPS không mở cổng nào cho Internet; TLS + secret riêng từng VPS là toàn bộ xác thực. (TightVNC 5900 chỉ dành cho guacd / VPN.)
- Hai tiến trình. Bản
VpsAgent.exenguyên khối cũ được tách để một lần cài MT5 60+ giây không chặn heartbeat. Hợp đồng dây với server không đổi. - Chạy tương tác, không phải Windows Service. CmdAgent phải cùng desktop session với MT5 để điều khiển GUI; service chạy ở Session 0 không làm được.
- Phát hiện "lost" ở trình duyệt. DB chỉ lưu 3 trạng thái admin đặt được (
pending | running | disabled);lostđược tính phía client mỗi 5 s theo cùng quy tắc của dashboard tài khoản MT5.
- Push-only. The VPS exposes no port to the internet; TLS + a per-VPS secret are the whole authentication. (TightVNC 5900 is for guacd / VPN only.)
- Two processes. The old monolithic
VpsAgent.exewas split so a 60+ second MT5 install can never block heartbeats. The wire contract with the server is unchanged. - Interactive, not a Windows Service. CmdAgent must share the desktop session with MT5 to drive its GUI; a service in Session 0 cannot.
- "Lost" is computed in the browser. The DB stores only the three admin-settable states (
pending | running | disabled);lostis derived client-side every 5 s with the same rule as the MT5 accounts dashboard.
Luồng heartbeatHeartbeat flow
sequenceDiagram
participant HB as HeartbeatAgent
participant ST as stunnel (local 9605)
participant VB as VpsStreamBroker
participant DB as Redis + MySQL
participant UI as Trình duyệt admin
participant WEB as fxconsole HTTPS
HB->>ST: TCP loopback
ST->>VB: TLS (verify=2, CAfile broker-ca.cert)
HB->>VB: hello (secret_key, agent_v)
VB->>DB: tìm vps_id theo secret_key
VB-->>HB: hello_ok (vps_id)
UI->>VB: admin mở /vps (WebSocket live)
VB-->>HB: stream_on
loop mỗi heartbeat_interval
HB->>VB: hb (cpu, ram, disk, net, accts, logins)
VB->>DB: cập nhật trạng thái + account_logins
VB-->>HB: hb_ok (interval chuẩn)
end
VB-->>HB: stream_off (tab admin cuối đóng)
Note over HB: chỉ gửi hb_min, bỏ qua WMI
VB-->>HB: ping mỗi 30 s
HB->>VB: pong
alt broker không khoẻ (HELLO lỗi hoặc 60 s không có frame)
HB->>WEB: POST /api/vps/heartbeat + X-Vps-Secret (full + command_acks)
WEB-->>HB: 200 (status, heartbeat_interval, commands)
endsequenceDiagram
participant HB as HeartbeatAgent
participant ST as stunnel (local 9605)
participant VB as VpsStreamBroker
participant DB as Redis + MySQL
participant UI as Admin browser
participant WEB as fxconsole HTTPS
HB->>ST: TCP loopback
ST->>VB: TLS (verify=2, CAfile broker-ca.cert)
HB->>VB: hello (secret_key, agent_v)
VB->>DB: resolve vps_id from secret_key
VB-->>HB: hello_ok (vps_id)
UI->>VB: admin opens /vps (live WebSocket)
VB-->>HB: stream_on
loop every heartbeat_interval
HB->>VB: hb (cpu, ram, disk, net, accts, logins)
VB->>DB: update state + account_logins
VB-->>HB: hb_ok (canonical interval)
end
VB-->>HB: stream_off (last admin tab closed)
Note over HB: sends hb_min only, skips WMI
VB-->>HB: ping every 30 s
HB->>VB: pong
alt broker unhealthy (HELLO failed or no frame for 60 s)
HB->>WEB: POST /api/vps/heartbeat + X-Vps-Secret (full + command_acks)
WEB-->>HB: 200 (status, heartbeat_interval, commands)
end- Hai đường heartbeat. Khi stream khoẻ (đã HELLO + có frame bất kỳ trong 60 s), agent gửi frame
hbvà bỏ hẳn HTTPS POST. Khi broker sập hoặc HELLO lỗi, agent quay về HTTPS với cùng chu kỳ; chuyển đổi âm thầm trong khoảng 60 s. Kết nối lại broker theo backoff tối đa 30 s. - Stream theo nhu cầu (phase5). Khi không admin nào xem
/vps, frame chỉ là keepalive{"t":"hb","ts":N}, không chạy WMI. Admin mở dashboard → broker gửistream_on→ agent gửi đủ payload. Đường HTTPS dự phòng luôn gửi đủ. - Hot-reload chu kỳ (phase8). Admin sửa interval ở dialog Edit của
/vps→ observerVps::updatedghi Redisvps:agent:{id}:interval→ broker đưaintervalvàohb_ok(hoặc HTTPS response cóheartbeat_interval) →ApplyServerIntervalkẹp về[1, 600], đổi trong bộ nhớ và ghi lại dòngheartbeat_intervaltrongvps-agent.ini. Không cần restart. - Agent gửi một heartbeat ngay khi khởi động để server thấy
runningtrong vài giây.
- Two heartbeat paths. When the stream is healthy (HELLO acked + any frame in the last 60 s) the agent sends
hbframes and skips the HTTPS POST entirely. When the broker is down or HELLO failed it falls back to HTTPS at the same cadence; the switch happens silently within about 60 s. Broker reconnects back off up to 30 s. - On-demand stream (phase5). While no admin is viewing
/vps, the frame is a tiny{"t":"hb","ts":N}keepalive with no WMI poll. An admin opens the dashboard → the broker sendsstream_on→ the agent ships the full payload. The HTTPS fallback always carries full telemetry. - Interval hot-reload (phase8). Admin edits the interval in the
/vpsEdit dialog → theVps::updatedobserver sets Redisvps:agent:{id}:interval→ the broker includesintervalinhb_ok(or the HTTPS response carriesheartbeat_interval) →ApplyServerIntervalclamps to[1, 600], updates memory and rewrites theheartbeat_intervalline invps-agent.ini. No restart. - The agent fires one heartbeat immediately at startup so the server shows
runningwithin seconds.
Mô hình trạng tháiStatus model
| Trạng tháiState | NguồnSource | Ý nghĩaMeaning |
|---|---|---|
| pending | Server (DB) | Admin vừa tạo, chưa nhận heartbeat nàoCreated by admin, no heartbeat received yet |
| running | Server (DB) | Đã nhận ít nhất một heartbeat, lần gần nhất còn mớiAt least one heartbeat received, the last one is recent |
| lost | Client (suy ra)Client (derived) | Heartbeat cuối cũ hơn interval × staleness_multiplierLast heartbeat older than interval × staleness_multiplier |
| disabled | Server (DB) | Admin tắt tay. Heartbeat vẫn cập nhật số liệu nhưng giữ disabled và không bao giờ hiện lostAdmin disabled it. Heartbeats still update stats, but the state stays disabled and lost is suppressed |
lost ⇔ now − last_heartbeat_at > heartbeat_interval × staleness_multiplier
staleness_multiplier mặc định 2, dùng chung qua app_setting('staleness_multiplier'). VpsApiController::heartbeat xử lý chuyển trạng thái: pending → running ở heartbeat thành công đầu tiên; running → running ở mỗi lần sau (làm mới số liệu); disabled → disabled giữ nguyên.
staleness_multiplier defaults to 2, shared via app_setting('staleness_multiplier'). VpsApiController::heartbeat handles transitions: pending → running on the first successful heartbeat; running → running on every later one (stats refreshed); disabled → disabled unchanged.
Phát hiện và liên kết tài khoảnAccount discovery & linkage
Mỗi heartbeat mang mảng login MT5 đang thấy trên máy (account_logins qua HTTPS, logins qua stream). Trang /vps/{id} nối các login đó với kho trạng thái tài khoản trong Redis (do EA AccountStatusUpdater ghi) để hiện balance / equity / profit.
Không có bảng pivot VPS ↔ tài khoản. Login MT5 là duy nhất và đã là account_id ở ba nơi: payload HELLO của EA, key Redis, và kết quả quét tiêu đề cửa sổ của agent. Agent báo "thấy login 12345678" + Redis có account_status:12345678 là toàn bộ liên kết.
Every heartbeat carries the MT5 logins visible on the box (account_logins over HTTPS, logins over the stream). /vps/{id} joins them against the Redis account-status store (written by the AccountStatusUpdater EA) to show balance / equity / profit.
There is no pivot table between VPSes and accounts. An MT5 login is globally unique and already serves as account_id in three places: the EA's HELLO payload, the Redis key, and the agent's window-title scan. "Agent sees login 12345678" + Redis holding account_status:12345678 is the entire linkage.
Pipeline mỗi heartbeatPer-heartbeat pipeline
- WMI:
SELECT ProcessId, CommandLine FROM Win32_Process WHERE Name='terminal64.exe', giữ các PID có/portabletrong CommandLine.WMI:SELECT ProcessId, CommandLine FROM Win32_Process WHERE Name='terminal64.exe', keep PIDs whose CommandLine contains/portable. WinList()lấy mọi cửa sổ top-level; với mỗi cửa sổ, hWnd → PID bằngWinGetProcess; nếu PID thuộc tập portable thì lấy dãy chữ số đầu tiêu đề (login MT5).WinList()lists every top-level window; for each, hWnd → PID viaWinGetProcess; if the PID is in the portable set, take the leading digit run of the title (the MT5 login).- Khử trùng lặp rồi gửi trong heartbeat.Dedupe, then send in the heartbeat.
- Server kiểm tra (mảng, ≤1000 phần tử, mỗi phần tử ≤32 ký tự) và ghi đè (không merge) cột JSON
vpses.account_logins: ảnh chụp của đúng heartbeat này.The server validates (array, ≤1000 entries, each ≤32 chars) and overwrites (not merges) the JSON columnvpses.account_logins: a snapshot of this heartbeat only. - Khi mở
/vps/{id},VpsController::showtra từng login: admin dùngAccountStatusStore::findAny($login), người thường dùng::findForSecretKey($userSecret, $login), rồi hiển thị account_id, name, server, balance, equity, profit, badge.On/vps/{id},VpsController::showlooks up each login: admins viaAccountStatusStore::findAny($login), others via::findForSecretKey($userSecret, $login), then renders account_id, name, server, balance, equity, profit and the status badge.
| Dữ liệuField | Nơi lưuWhere | Vòng đờiLifetime |
|---|---|---|
account_logins | MySQL vpses | Thay mới mỗi heartbeat (từ phase8 broker cũng cập nhật qua stream)Replaced every heartbeat (since phase8 the broker also updates it from the stream) |
account_status:{login} | Redis | TTL 48 giờ, EA làm mới48 h TTL, refreshed by the EA |
| Balance / equity / profitBalance / equity / profit | Chỉ RedisRedis only | TTL 48 giờ48 h TTL |
Restart server không mất liên kết vì vpses.account_logins nằm trong MySQL. Restart Redis xoá dữ liệu tài khoản nhưng danh sách login vẫn còn; EA sẽ ghi lại Redis ngay khi stream lại.
Restarting the server doesn't lose the linkage because vpses.account_logins is in MySQL. Restarting Redis erases the account data but the login list remains; the EA repopulates Redis as soon as it streams again.
Quy tắc đọc tiêu đề cửa sổWindow-title parsing rules
Tiêu đề cửa sổ chính của MT5 là "{login} - {type} {broker} - MetaTrader 5" (ví dụ "12345678 - Real - Vantage Intl - MetaTrader 5"). Agent lấy dãy chữ số đầu và dừng ở ký tự không phải số, nên cũng đúng với dạng có dấu hai chấm ("12345678: Real ..."). Tiêu đề không bắt đầu bằng số ("MetaTrader 5 — not logged in", cửa sổ con) bị bỏ qua.
MT5's main window title is "{login} - {type} {broker} - MetaTrader 5" (e.g. "12345678 - Real - Vantage Intl - MetaTrader 5"). The agent takes the leading digit run and stops at the first non-digit, so the colon variant ("12345678: Real ...") works too. Titles that don't start with digits ("MetaTrader 5 — not logged in", sub-windows) are skipped.
Ai thấy gì trên /vps/{id}Visibility on /vps/{id}
| Người xemViewer | ThấySees |
|---|---|
| Admin | Mọi login agent báo. Login chưa có dòng Redis hiện "no data yet".Every login the agent reported. Logins with no Redis row show a "no data yet" placeholder. |
| Người thườngNon-admin | Chỉ login khớp mt5_secret_key của mình. Tài khoản người khác bị ẩn hẳn, không phải che bớt.Only logins matching their own mt5_secret_key. Other users' accounts are hidden, not redacted: they don't appear as rows at all. |
Trường hợp biênEdge cases
| Tình huốngSituation | Hành viBehaviour |
|---|---|
| MT5 vừa mở, chưa đăng nhậpMT5 just started, not logged in | Tiêu đề không bắt đầu bằng số → không báoTitle doesn't start with digits → not reported |
| MT5 đang khởi động lạiMT5 restarting | Mất khỏi mảng 1–2 heartbeat rồi quay lạiDrops out for 1–2 heartbeats, then returns |
| WMI bị tắt / image Windows rút gọnWMI disabled / stripped Windows image | Agent trả []; UI hiện 0 tài khoảnAgent returns []; UI shows 0 accounts |
| Agent báo login nhưng EA chưa streamLogin reported, EA hasn't streamed yet | Admin thấy placeholder; người thường không thấy gìAdmin sees a placeholder; non-admin sees nothing |
| Nhiều cửa sổ MT5 cùng loginSeveral MT5 windows for one login | Khử trùng, đếm một lầnDeduplicated, counted once |
| Tiến trình MT5 còn nhưng phiên đăng nhập hỏngMT5 process alive but login session crashed | Vẫn được đếm (tiến trình /portable còn)Still counted (the /portable process exists) |
| Cùng login chạy trên hai VPSSame login active on two VPSes | Cả hai VPS đều báo; UI trỏ về cùng trang /dashboard/accounts/{login}Both report it; the UI links to the same /dashboard/accounts/{login} page |
Agent không báo: tên tài khoản, broker, balance (lấy từ Redis qua EA); chủ sở hữu (server suy ra từ secret_key của dòng Redis); tài khoản đã đăng nhập hay đang ở hộp thoại login (cả hai đều là tiến trình terminal64.exe /portable, nhưng hộp thoại login không có số trong tiêu đề nên bị bỏ).
The agent does not report: account name, broker, balance (from Redis via the EA); the owner (derived server-side from the Redis row's secret_key); whether the account is logged in or sitting at the login dialog (both are terminal64.exe /portable processes, but the dialog has no digits in its title so it's skipped).
Quy trình admin trên webAdmin workflow (web)
- Đăng nhập fxconsole bằng tài khoản admin; sidebar → VPS (biểu tượng Server).Log in to fxconsole as an admin; sidebar → VPS (the Server icon).
- Bấm Add VPS, đặt tên (ví dụ
vps-tokyo-01), tuỳ chọn Max accounts (0= không giới hạn). Với zero-touch, nhập thêm MAC address và heartbeat interval.Click Add VPS, give it a name (e.g.vps-tokyo-01), optionally set Max accounts (0= unlimited). For zero-touch, also enter the MAC address and heartbeat interval. - Dòng mới có trạng thái pending. Bấm biểu tượng mắt để hiện secret 64 ký tự tự sinh và copy.The row appears as pending. Click the eye icon to reveal the auto-generated 64-char secret and copy it.
- Dán secret vào
vps-agent.initrên VPS (xem phần cài đặt).Paste the secret into the VPS'svps-agent.ini(see install). - Ở heartbeat đầu tiên dòng chuyển sang running, các cột có số liệu, cột Last heartbeat đếm giây.On the first heartbeat the row flips to running, columns fill with live numbers, and Last heartbeat shows seconds.
- Edit: đổi tên,
max_accounts, heartbeat interval (hot-reload), cổng / mật khẩu VNC, ép trạng tháipending / running / disabled. - Eye: mở lại và copy secret.
- Trash: xoá. Agent trên VPS đó nhận
401 Unknown VPS secretở heartbeat kế tiếp, ghi log và vẫn tiếp tục vòng lặp.
Người thường thấy cùng danh sách nhưng không có cột thao tác và không có secret. Mọi thao tác thay đổi được chặn phía server bằng middleware admin, không chỉ ở giao diện.
- Edit: rename, change
max_accounts, heartbeat interval (hot-reloaded), VNC port / password, force status topending / running / disabled. - Eye: reopen and copy the secret again.
- Trash: remove. The agent on that VPS gets
401 Unknown VPS secreton its next heartbeat, logs it, and the loop continues.
Non-admins see the same list with no action column and no secret. Mutations are gated server-side by the admin middleware, not just in the UI.
Cài agent (từng VPS)Agent install (per VPS)
Yêu cầuRequirements
- Windows 7+ (khuyến nghị 64-bit), đã bật AutoLogon (xem VM headless).
- AutoIt v3.3.16+ trên máy build (chỉ để compile; VPS chỉ cần file
.exe). - URL fxconsole truy cập được qua TLS (agent gọi
<server_url>/api/vps/heartbeat), và cổng TCP 9605 của broker mở từ VPS.
- Windows 7+ (64-bit recommended) with AutoLogon enabled (see headless VM).
- AutoIt v3.3.16+ on the build machine (compile only; the VPS just needs the
.exefiles). - A TLS-reachable fxconsole URL (the agent calls
<server_url>/api/vps/heartbeat) and the broker's TCP port 9605 reachable from the VPS.
File cần có trong C:\VpsAgent\Files in C:\VpsAgent\
| FileFile | Ghi chúNotes |
|---|---|
HeartbeatAgent.exe, CmdAgent.exe | Compile từ .au3 hoặc lấy trong vps-agent-setup-1.3.2-phase9.zipCompiled from the .au3 files or taken from vps-agent-setup-1.3.2-phase9.zip |
vps-agent.ini | Điền từ /vps → biểu tượng mắt → Copy; hoặc vps-agent.ini.init-template (có init_token) cho zero-touchFilled from /vps → eye icon → Copy; or vps-agent.ini.init-template (with init_token) for zero-touch |
bootstrap-fresh-vm.ps1 | Chạy MỘT lần trên image Windows mớiRuns ONCE on a fresh Windows image |
prepare-vm.ps1 | Script cài chínhMain installer |
upgrade.ps1 | Bắt buộc cho tự nâng cấp; không nằm trong zip upgrade (script không tự ghi đè được khi đang chạy)Required for self-upgrade; deliberately not in the upgrade zip (a running script can't overwrite itself) |
Các bướcSteps
- Compile
HeartbeatAgent.au3+CmdAgent.au3ở chế độ GUI (xem Compile), hoặc dùng gói setup.CompileHeartbeatAgent.au3+CmdAgent.au3in GUI mode (see Compiling), or use the setup package. - Copy các file trên vào
C:\VpsAgent\.Copy the files above intoC:\VpsAgent\. -
Chỉ với Windows cài mới, lần đầu cho mỗi image, chạy bằng Administrator rồi snapshot VM (mọi bản clone thừa hưởng chỉnh registry và bỏ qua bước này):Fresh Windows only, first time per OS image, run as Administrator, then snapshot the VM (every clone inherits the registry tweaks and skips this step):
cd C:\VpsAgent powershell -ExecutionPolicy Bypass -File .\bootstrap-fresh-vm.ps1 -
Chạy script cài chính bằng Administrator (sau bước 3 không cần cờ
-ExecutionPolicy):Run the main installer as Administrator (no-ExecutionPolicyflag needed after step 3):
Script lo chuẩn bị AutoLogon, gỡ MOTW, shortcut Startup cho HeartbeatAgent, cài stunnel cho broker stream và cài TightVNC service.It handles AutoLogon prep, MOTW stripping, the HeartbeatAgent Startup shortcut, the stunnel install for the broker stream and the TightVNC service install.cd C:\VpsAgent .\prepare-vm.ps1 - Reboot. Sau AutoLogon, HeartbeatAgent tự chạy trong session tương tác và spawn CmdAgent. Mở
heartbeat-agent.logđể kiểm tra.Reboot. After AutoLogon, HeartbeatAgent starts in the interactive session and spawns CmdAgent. Openheartbeat-agent.logto verify.
[2026-06-04 14:22:01] Starting HeartbeatAgent 1.3.2-phase9 -- interval=5s host=WIN-VPS-01
[2026-06-04 14:22:01] IPC listening on 127.0.0.1:9606
[2026-06-04 14:22:02] BROKER: HELLO ok — stream healthy
[2026-06-04 14:22:02] HB via broker stream cpu=8.4 ram=42.1 disk=33.7 net=0.6 acc=0
host= chỉ là @ComputerName để đọc log, không gửi lên server; tên hiển thị là name admin đặt trên web. Mật khẩu VNC do server sinh, prepare-vm.ps1 lấy qua /api/agent/broker-config; admin xem trên /vps/{id} khi cần dùng VNC client native thay vì Guacamole. (README gốc in log mẫu với 1.3.0-phase4d; bản hiện tại in 1.3.2-phase9.)
host= is just @ComputerName for log context and is not sent to the server; the display label is the name set in the web UI. The VNC password is generated server-side and fetched by prepare-vm.ps1 via /api/agent/broker-config; admins reveal it on /vps/{id} for a native VNC client instead of Guacamole. (The original README shows sample logs with 1.3.0-phase4d; the current build prints 1.3.2-phase9.)
Compile binaryCompiling the binaries
Aut2Exe.exe /in HeartbeatAgent.au3 /out HeartbeatAgent.exe /gui /icon icon.ico
Aut2Exe.exe /in CmdAgent.au3 /out CmdAgent.exe /gui /icon icon.ico
- Compile ở GUI mode để không có cửa sổ console mỗi lần khởi động.
lib/ipc.au3vàJson.au3được#includetừ cả hai file; thư mụclib/phải nằm cạnh source lúc compile (AutoIt tìm include theo vị trí source). - Từ phase7/8 có hằng
$DEBUG_CONSOLE(hiện đangTruetrong source): exe GUI vẫn mở cửa sổ console hiển thị log trực tiếp (AllocConsole+ ghi vàoCONOUT$). ĐặtFalsevà compile lại cho bản production im lặng; đổi cho cả hai agent cùng lúc.
- Compile in GUI mode so no console window appears at every boot.
lib/ipc.au3andJson.au3are#included by both files; thelib/folder must sit next to the sources at compile time (AutoIt resolves includes relative to the source). - Since phase7/8 there is a
$DEBUG_CONSOLEconstant (currentlyTruein source): the GUI exe still opens a console window with the live log (AllocConsole+ writes toCONOUT$). Set it toFalseand recompile for silent production builds; flip both agents together.
VM headless (AutoLogon)Headless VM setup (AutoLogon)
Bước cấu hình WebRequest URL dùng GUI automation của AutoIt (Send, WinActivate, ControlClick) trên hộp thoại Tools → Options của MT5. Các lệnh này cần một desktop Windows tương tác. Trên VM Proxmox / Hyper-V / VMware không mở console và không có RDP, Windows không có desktop sống, lệnh GUI thoát sớm và log deploy hiện:
The WebRequest URL step uses AutoIt GUI automation (Send, WinActivate, ControlClick) against MT5's Tools → Options dialog. Those calls need an interactive Windows desktop session. On a Proxmox / Hyper-V / VMware VM with no console open and no RDP attached there is no live desktop, GUI calls return early, and the deploy log shows:
WARN: WebRequest GUI automation didn't complete -- configure manually:
https://your-url-1
https://your-url-2
Cách sửa: bật Windows AutoLogon để VM luôn đăng nhập Administrator vào desktop thật, qua cả reboot, không cần người. Làm theo thứ tự dưới đây.
Fix: enable Windows AutoLogon so the VM always has Administrator logged in to a real desktop, surviving reboots, with no human needed. Follow the steps below in order.
Cài Sysinternals AutoLogonInstall Sysinternals AutoLogon
- Tải
AutoLogon.ziptừhttps://learn.microsoft.com/en-us/sysinternals/downloads/autologon(bản copy có sẵn trongmonitor/vps-agent/AutoLogon.zipvà trong gói setup), giải nén, lấyAutologon64.exeđặt vào ví dụC:\Tools\.DownloadAutoLogon.zipfromhttps://learn.microsoft.com/en-us/sysinternals/downloads/autologon(a copy ships inmonitor/vps-agent/AutoLogon.zipand in the setup package), extract, and putAutologon64.exein e.g.C:\Tools\. - Kiểm tra mật khẩu trước:
runas /user:Administrator cmd. Mở được cửa sổcmdmới = đúng. Lỗi1326: The username or password is incorrect→ đặt lại mật khẩu rồi quay lại.Test the password first:runas /user:Administrator cmd. A newcmdwindow = correct. Error1326: The username or password is incorrect→ reset the password, then come back. - Chuột phải
Autologon64.exe→ Run as administrator; lần đầu tick Agree ở EULA.Right-clickAutologon64.exe→ Run as administrator; on first run tick Agree on the EULA. - Điền Username =
Administrator, Domain = trống hoặc tên máy (ví dụfxbot001), Password = mật khẩu thật của Administrator.Fill Username =Administrator, Domain = blank or the computer name (e.g.fxbot001), Password = the Administrator account's real password. - Bấm Enable. Thành công → popup
Autologon successfully configured; sai mật khẩu → báo lỗi ngay.Click Enable. Success → popupAutologon successfully configured; a wrong password errors immediately.
Vì sao dùng Sysinternals thay vì registry: AutoLogon lưu mật khẩu mã hoá trong LSA Secrets thay vì dạng rõ ở HKLM:\…\Winlogon\DefaultPassword; ai dump registry cũng không đọc được.
Why Sysinternals over the registry method: AutoLogon stores the password encrypted in LSA Secrets instead of plaintext in HKLM:\…\Winlogon\DefaultPassword, so a registry dump can't read it.
bootstrap-fresh-vm.ps1 (Windows mới, một lần mỗi image)bootstrap-fresh-vm.ps1 (fresh Windows, once per image)
Windows mới có hai trở ngại trước khi prepare-vm.ps1 chạy được: ExecutionPolicy = Restricted (mỗi lần phải thêm -ExecutionPolicy Bypass) và Attachment Manager (Mark-of-the-Web) (hộp thoại "Open File — Security Warning" mỗi lần double-click vì OneDrive / SMB / trình duyệt gắn ADS Zone.Identifier). Script tắt vĩnh viễn cả hai:
ExecutionPolicy = Bypassở cả scope LocalMachine và CurrentUser.- Thêm
.ps1 .cmd .bat .exe .au3 .msi .zipvào allowlistLowRiskFileTypes. - Đặt
SaveZoneInformation = 1ở HKLM + HKCU để Windows không gắn MOTW cho file tải mới. - Gỡ MOTW khỏi mọi thứ đang có trong
C:\VpsAgent\.
A brand-new Windows install has two friction points before prepare-vm.ps1 can start: ExecutionPolicy = Restricted (every run needs -ExecutionPolicy Bypass) and Attachment Manager (Mark-of-the-Web) (an "Open File — Security Warning" dialog on every double-click, because OneDrive / SMB / browsers tag files with a Zone.Identifier ADS). The script turns both off permanently:
ExecutionPolicy = Bypassat both LocalMachine and CurrentUser scope.- Adds
.ps1 .cmd .bat .exe .au3 .msi .zipto theLowRiskFileTypesallowlist. - Sets
SaveZoneInformation = 1at HKLM + HKCU so Windows stops tagging new downloads. - Strips MOTW from anything already under
C:\VpsAgent\.
cd C:\VpsAgent
# ONE-TIME bypass needed -- the script itself sets bypass permanent for next runs
powershell -ExecutionPolicy Bypass -File .\bootstrap-fresh-vm.ps1
Script tắt các cảnh báo trước khi chạy script chưa ký. Chỉ dùng cho VPS trong mạng nội bộ an toàn, không chạy trình duyệt hay mở file đính kèm email, dành riêng cho MT5 automation dưới fxconsole. Không chạy trên máy trạm, máy dev hay máy tải file tuỳ ý từ Internet.
This disables prompts that normally warn before running unsigned scripts. Use it ONLY on internal-network VPSes in a safe zone that don't run a browser or open email attachments and are dedicated to MT5 automation under fxconsole. Do not run it on a workstation, dev box, or any machine handling arbitrary downloads.
prepare-vm.ps1 làm gìWhat prepare-vm.ps1 does
- Dọn trạng thái cũ: dừng
VpsAgent/HeartbeatAgent/CmdAgent/ stunnel để thay được file exe; xoá shortcut Startup cũ (kể cảVpsAgent.lnk); gỡ im lặng stunnel và TightVNC cũ để lần cài sau luôn sạch.Clean previous state: stopVpsAgent/HeartbeatAgent/CmdAgent/ stunnel so the exe files can be replaced; drop stale Startup shortcuts (includingVpsAgent.lnk); silently uninstall any old stunnel and TightVNC so every run reinstalls cleanly. - Chuẩn bị cho AutoLogon:
DisableCADtắt Ctrl+Alt+Del (cần cho Windows Server, vô hại trên 10/11);powercfgkhông bao giờ sleep / tắt màn hình / hibernate;NoLockScreen+ tắt screensaver (session bị khoá không còn là session tương tác choSend).AutoLogon-friendly prep:DisableCADremoves the Ctrl+Alt+Del prompt (required on Windows Server, harmless on 10/11);powercfgnever sleeps / blanks / hibernates;NoLockScreen+ screensaver off (a locked session is NOT interactive forSend). Unblock-Filegỡ MOTW khỏi hai binary agent để SmartScreen không hỏi mỗi lần chạy.Unblock-Filestrips MOTW off both agent binaries so SmartScreen doesn't prompt on each launch.- Tạo
HeartbeatAgent.lnktrong thư mục Startup. CmdAgent không nằm trong Startup: HeartbeatAgent spawn nó.CreatesHeartbeatAgent.lnkin the Startup folder. CmdAgent is NOT in Startup: HeartbeatAgent spawns it. - Broker stream: cài stunnel, gọi
GET /api/agent/broker-config, ghistunnel.conf+ CA, tạo shortcut Startup cho stunnel và chạy nó (chi tiết ở Broker stream).Broker stream: installs stunnel, callsGET /api/agent/broker-config, writesstunnel.conf+ CA, adds a Startup shortcut for stunnel and launches it (details in Broker stream). - TightVNC: cài làm Windows Service với mật khẩu riêng của VPS lấy từ response bootstrap, nghe cổng 5900.TightVNC: installs it as a Windows Service with the per-VPS password from the bootstrap response, listening on 5900.
- Smoke test
Test-NetConnection 127.0.0.1cổng 9605 và 5900, ghiinit = provisioned, rồi reboot sau đếm ngược 10 s có thể huỷ.Smoke-testsTest-NetConnection 127.0.0.1on ports 9605 and 5900, writesinit = provisioned, then reboots after a cancellable 10 s countdown.
| Tham sốParameter | Công dụngPurpose |
|---|---|
-AgentDir <path> | Thư mục cài (mặc định C:\VpsAgent)Install root (default C:\VpsAgent) |
-SkipBroker | Bỏ cài stunnel + lấy cert (khi chưa muốn tích hợp broker)Skip the stunnel install + cert fetch (when you don't want broker integration yet) |
-StunnelInstallerUrl | Mặc định https://www.stunnel.org/downloads/stunnel-5.78-win64-installer.exeDefault https://www.stunnel.org/downloads/stunnel-5.78-win64-installer.exe |
-StunnelInstallerLocalPath C:\path\to\stunnel-installer.exe | Installer đặt sẵn cho VPS không ra được stunnel.orgPre-staged installer for VPSes that can't reach stunnel.org |
-TightVncInstallerUrl / -TightVncInstallerLocalPath | MSI TightVNC (mặc định bản 2.8.81 64-bit) hoặc bản đặt sẵnTightVNC MSI (default 2.8.81 64-bit) or a pre-staged copy |
-Force | Cài lại toàn bộ + reboot dù ini đã init = provisionedFull reinstall + reboot even when the ini says init = provisioned |
Chạy lại sau khi: thay HeartbeatAgent.exe / CmdAgent.exe bằng bản mới (SmartScreen cache danh tiếng theo hash nên binary mới lại bị cảnh báo); xoay cert broker; đổi vps_broker_host / vps_broker_port trên /admin/settings. Script idempotent. Lưu ý: khi ini đã init = provisioned, script thoát ngay trừ khi truyền -Force hoặc đổi thành init = installing / xoá dòng init.
Re-run after: replacing HeartbeatAgent.exe / CmdAgent.exe with a new build (SmartScreen caches reputation per file hash, so a new binary brings the warning back); broker cert rotation; a vps_broker_host / vps_broker_port change on /admin/settings. The script is idempotent. Note: once the ini says init = provisioned the script exits immediately unless you pass -Force or change it to init = installing / delete the init line.
Gỡ Windows Service VpsAgent cũ (chỉ máy nâng cấp)Remove the legacy VpsAgent Windows Service (upgraded hosts only)
Bản cài cũ có thể chạy VpsAgent.exe như service (NSSM…). Service chạy ở Session 0, tách khỏi desktop; agent mới bắt buộc chạy tương tác. Kiểm tra bằng sc.exe query VpsAgent: thấy STATE: 4 RUNNING thì gỡ; thấy service does not exist thì bỏ qua.
Old installs may run VpsAgent.exe as a service (NSSM or similar). A service runs in Session 0, isolated from the desktop; the new agents must run interactively. Check with sc.exe query VpsAgent: STATE: 4 RUNNING means remove it; service does not exist means skip.
sc.exe query VpsAgent
Stop-Service VpsAgent -ErrorAction SilentlyContinue
sc.exe delete VpsAgent
Chạy HeartbeatAgent khi đăng nhậpRun HeartbeatAgent at logon
Bỏ qua nếu đã chạy prepare-vm.ps1 (Option A đã được làm sẵn). Option A — Startup folder: Win+R → shell:startup → New → Shortcut → C:\VpsAgent\HeartbeatAgent.exe. Option B — Task Scheduler (có restart khi lỗi):
Skip if you ran prepare-vm.ps1 (Option A is already done). Option A — Startup folder: Win+R → shell:startup → New → Shortcut → C:\VpsAgent\HeartbeatAgent.exe. Option B — Task Scheduler (with restart-on-fail):
$action = New-ScheduledTaskAction -Execute "C:\VpsAgent\HeartbeatAgent.exe"
$trigger = New-ScheduledTaskTrigger -AtLogOn -User "Administrator"
# CRITICAL: LogonType Interactive — task runs in the user's session,
# not Session 0.
$principal = New-ScheduledTaskPrincipal `
-UserId "Administrator" `
-RunLevel Highest `
-LogonType Interactive
$settings = New-ScheduledTaskSettingsSet `
-AllowStartIfOnBatteries -DontStopIfGoingOnBatteries `
-StartWhenAvailable `
-RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName "fxconsole-HeartbeatAgent" `
-Action $action -Trigger $trigger `
-Principal $principal -Settings $settings
Kiểm tra ngay: double-click shortcut hoặc Start-ScheduledTask -TaskName "fxconsole-HeartbeatAgent". Task Manager → Details → cột User name phải là Administrator, KHÔNG phải SYSTEM (thấy SYSTEM nghĩa là chưa gỡ service cũ). End task bản thử; lần boot sau nó tự chạy và spawn CmdAgent.
Verify immediately: double-click the shortcut or run Start-ScheduledTask -TaskName "fxconsole-HeartbeatAgent". Task Manager → Details → User name must be Administrator, NOT SYSTEM (SYSTEM means the legacy service step was missed). End the test process; it starts again on next boot and spawns CmdAgent.
Reboot và kiểm traReboot and verify
Restart-Computer, rồi mở console Proxmox (noVNC / SPICE), KHÔNG dùng RDP, để thử AutoLogon riêng.Restart-Computer, then open the Proxmox console (noVNC / SPICE), NOT RDP, to test AutoLogon in isolation.- Phải thấy desktop đã đăng nhập Administrator, không có màn Ctrl+Alt+Del hay login.You should see the desktop already logged in as Administrator, with no Ctrl+Alt+Del or login screen.
- Task Manager → Details:
HeartbeatAgent.exe,CmdAgent.exe,stunnel.exeđều chạy với userAdministrator.Task Manager → Details:HeartbeatAgent.exe,CmdAgent.exeandstunnel.exeall run asAdministrator. - Từ máy khác, deploy thử một tài khoản; sau 1–2 phút
/deploymentsphải chuyển sangrunning.From another machine, trigger one deploy; after 1–2 minutes/deploymentsshould showrunning. - Mở
/admin/vps/{id}/logs(admin) và tìmWebReq: starting for …,WebReq: main hwnd=…,WebRequest URLs configured via GUI (N). Dòng cuối nghĩa là GUI automation đã chạy thật.Open/admin/vps/{id}/logs(admin) and look forWebReq: starting for …,WebReq: main hwnd=…,WebRequest URLs configured via GUI (N). The last line means the GUI automation really ran.
Khi WebRequest vẫn lỗiWhen WebRequest still fails
Lấy khối log agent từ CMD #N add_account tới WARN: WebRequest… hoặc done in … ms:
Grab the agent log block between CMD #N add_account and either WARN: WebRequest… or done in … ms:
| Dòng logLog line | Nguyên nhânCause | Cách sửaFix |
|---|---|---|
WebReq: main window not found within 90s | CmdAgent kẹt ở Session 0 (service cũ còn), hoặc MT5 chưa khởi động xongCmdAgent stuck in Session 0 (legacy service lingering), or MT5 hasn't finished booting | Xác nhận CmdAgent + HeartbeatAgent chạy dưới Administrator; MT5 chậm ở lần đầu thì chờ thêm.Confirm CmdAgent + HeartbeatAgent run as Administrator; allow more time if MT5 is slow on first run. |
WebReq: couldn't activate main window | Có popup đè lên cướp focus (UAC, EULA, Defender, LiveUpdate)A popup is stealing focus (UAC, EULA, Defender, LiveUpdate) | Mở console và đóng popup (LiveUpdate: chọn Later). Deploy sau sẽ chạy.Open the console and dismiss it (LiveUpdate: choose Later). The next deploy should work. |
WebReq: Options dialog didn't appear | Phím bị mất do focus bị cướp (agent thử Alt+T,O rồi Ctrl+O)Keystroke lost to focus-steal (the agent tries Alt+T,O, then Ctrl+O) | Đảm bảo không có gì nhấp nháy focus trong lúc deploy.Make sure nothing flickers focus during the deploy. |
Log dừng giữa chừng, không có doneLog stops mid-flow, no done line | CmdAgent bị kill / crash; HeartbeatAgent spawn lại trong ~5 s nhưng ACK của lệnh đang chạy bị mất, reaper 5 phút phía server xử lýCmdAgent killed or crashed; HeartbeatAgent respawns it within ~5 s but the in-flight ACK is lost; the server's 5-min reaper picks it up | Event Viewer → Windows Logs → Application; tìm Supervisor: spawned CmdAgent pid=… trong heartbeat-agent.log.Event Viewer → Windows Logs → Application; look for Supervisor: spawned CmdAgent pid=… in heartbeat-agent.log. |
Vì sao VNC mà không RDPWhy VNC and not RDP
GUI automation của agent cần desktop tương tác luôn mở khoá. RDP gắn vào console session sẽ khoá desktop khi ngắt (mặc định bảo mật của Windows); mọi Send() / WinActivate trong ConfigureWebRequestUrls khi đó rơi vào secure desktop Winlogon thay vì MT5 và deploy lỗi âm thầm. VNC chỉ phản chiếu framebuffer của phiên AutoLogon đang có; kết nối / ngắt qua Guacamole hay VNC client không đổi trạng thái session. Vì vậy prepare-vm.ps1 cài TightVNC service và nút "Connect" của fxconsole cấp token VNC. Xem Guacamole.
The agent's GUI automation needs an interactive desktop that stays unlocked. RDP attached to the console session locks the desktop on disconnect (Windows security default); every Send() / WinActivate in ConfigureWebRequestUrls then targets the Winlogon secure desktop instead of MT5 and the deploy fails silently. VNC just mirrors the framebuffer of the existing AutoLogon session; connecting or disconnecting via Guacamole or a VNC client doesn't change the session. That's why prepare-vm.ps1 installs the TightVNC service and fxconsole's "Connect" button hands out VNC tokens. See Guacamole.
Mẹo Proxmox và đánh đổi bảo mậtProxmox tips and security trade-offs
- Driver VirtIO Balloon + Display: SPICE / std vga hiển thị ổn định trong noVNC; adapter "cirrus" mặc định có thể làm hỏng GUI MT5.
- Bật Start at boot (Proxmox → VM → Options) để VM tự lên sau khi host reboot. Có UPS thì cài
qemu-guest-agentđể Proxmox biết khi nào guest thật sự sẵn sàng. - Mật khẩu trong LSA Secrets được mã hoá khi lưu nhưng ai có quyền Administrator vẫn giải mã được (ngang RDP lưu mật khẩu).
- Ai có quyền console Proxmox sẽ vào thẳng desktop đã đăng nhập; chấp nhận được nếu Proxmox sau VPN / LAN tin cậy.
- Snapshot backup Proxmox chụp cả trạng thái desktop; nếu snapshot rời máy, mã hoá storage.
- Chặt hơn: dùng user không phải admin (ví dụ
mt5runner) chỉ đủ quyền chạy MT5 + AutoIt (ngoài phạm vi hướng dẫn). - AutoLogon chỉ hết bắt buộc nếu agent chuyển sang ghi WebRequest URL thẳng vào
<target>\config\common.inithay vì qua GUI; tới lúc đó mới quay lại chạy dạng service được.
- VirtIO Balloon driver + Display: SPICE / std vga render reliably in noVNC; the default "cirrus" adapter can corrupt MT5's GUI.
- Enable Start at boot (Proxmox → VM → Options) so the VM comes back after host reboots. With UPS power, install
qemu-guest-agentso Proxmox knows when the guest is truly ready. - The LSA Secrets password is encrypted at rest but decryptable by anyone with Administrator rights (same trust level as RDP with a saved password).
- Anyone with Proxmox console access lands on a logged-in desktop; acceptable if Proxmox sits behind VPN / a trusted LAN.
- Proxmox backup snapshots capture the desktop state; if snapshots leave the box, encrypt the storage.
- Tighter: a non-admin runner user (e.g.
mt5runner) with just enough rights for MT5 + AutoIt (out of scope here). - AutoLogon stops being required only if the agent switches to writing WebRequest URLs directly into
<target>\config\common.iniinstead of the GUI; only then could the agents go back to running as services.
Zero-touch provisioningZero-touch provisioning
Từ agent v1.3.0-phase4k. Image Windows "vàng" mang sẵn vps-agent.ini tối giản (server_url + init_token + init = pending); khi bản clone boot lần đầu, prepare-vm.ps1 (trong Startup của user AutoLogon) tự nhận danh tính.
Since agent v1.3.0-phase4k. The "golden" Windows image carries a minimal vps-agent.ini (server_url + init_token + init = pending); when a clone first boots, prepare-vm.ps1 (in the AutoLogon user's Startup folder) claims its identity.
flowchart TD A["init = pending (clone mới)"] --> B["Lấy MAC các NIC đang chạy"] B --> C["POST /api/agent/init-config (Bearer init_token, macs, server_url)"] C -- "401 / 404 / không tới được" --> X["Dừng, in lỗi"] C -- "200: secret_key, name, interval, mt5_root, computer_name" --> D["Ghi lại ini (bỏ init_token), init = installing"] D --> E["Rename-Computer, reboot sau 5 s"] E --> F["Cài đặt thường: stunnel, TightVNC, Startup"] F --> G["init = provisioned, reboot"] G --> H["Các lần chạy sau: thoát ngay (trừ -Force)"]
flowchart TD A["init = pending (fresh clone)"] --> B["Collect active NIC MACs"] B --> C["POST /api/agent/init-config (Bearer init_token, macs, server_url)"] C -- "401 / 404 / unreachable" --> X["Abort with error"] C -- "200: secret_key, name, interval, mt5_root, computer_name" --> D["Rewrite ini (init_token removed), init = installing"] D --> E["Rename-Computer, reboot in 5 s"] E --> F["Normal install: stunnel, TightVNC, Startup"] F --> G["init = provisioned, reboot"] G --> H["Later runs: exit immediately (unless -Force)"]
- Admin, trên web:
/vps→ Add VPS, điền Name (cũng là tên máy Windows, cắt còn 15 ký tự), MAC address (MAC NIC của VM, cố định trong hypervisor TRƯỚC khi clone hoặc đặt lúc clone), Heartbeat interval, Max accounts. - Clone template → gắn MAC đã đăng ký → bật máy.
- Chờ khoảng 30 s cho lần reboot tự động + agent khởi động. Xong.
Vì sao cần bootstrap token: không có nó, ai tới được /api/agent/init-config có thể dò MAC và cướp danh tính của VM vừa clone trước khi nó boot xong. Server so token bằng hash_equals trước khi tra MAC. Giá trị kỳ vọng lấy theo thứ tự: VPS_INIT_BOOTSTRAP_TOKEN trong .env của fxconsole, bị ghi đè bởi vps_init_bootstrap_token trên /admin/settings. Env trống = endpoint trả 503 (không có fallback dễ dãi). Script từ chối gọi nếu ini còn giá trị placeholder mẫu.
Xoay token khi image rời tay tin cậy, người vận hành có quyền image nghỉ việc, hoặc nghi bị lộ: đổi trên /admin/settings (hoặc env + restart) rồi nướng lại giá trị mới vào template. VM đã init xong không bị ảnh hưởng vì chúng dùng secret_key riêng. Nếu không muốn zero-touch, bỏ qua template và dùng luồng thủ công (Reveal Secret → dán vào ini → chạy prepare-vm.ps1).
- Admin, in the web UI:
/vps→ Add VPS with Name (also becomes the Windows computer name, truncated to 15 chars), MAC address (the VM NIC MAC, fixed in the hypervisor BEFORE cloning or set at clone time), Heartbeat interval, Max accounts. - Clone the template → attach the pre-registered MAC → power on.
- Wait about 30 s for the auto-reboot + agent boot. Done.
Why a bootstrap token: without one, anybody who can reach /api/agent/init-config could brute-force MACs and steal a fresh clone's identity before it finishes booting. The server checks the token with hash_equals before the MAC lookup. The expected value resolves as: VPS_INIT_BOOTSTRAP_TOKEN in fxconsole's .env, overridden by vps_init_bootstrap_token on /admin/settings. An empty value makes the endpoint return 503 (no permissive fallback). The script refuses to call it while the ini still holds the template placeholder.
Rotate the token when the golden image leaves trusted hands, an operator with image access departs, or compromise is suspected: change it on /admin/settings (or env + restart), then re-bake the new value into the template. Already-initialised VMs are unaffected because they use their own secret_key. If you don't want zero-touch, ignore the template and use the manual flow (Reveal Secret → paste into the ini → run prepare-vm.ps1).
Tham chiếu cấu hình vps-agent.inivps-agent.ini reference
Mọi key nằm trong section [agent]. Dòng hostname = ... của config cũ vẫn được chấp nhận nhưng bị bỏ qua (tên hiển thị và VNC do server quản lý). Agent không trim khoảng trắng trong secret: copy cẩn thận.
All keys live under [agent]. Legacy hostname = ... lines are accepted but ignored (display name and VNC are server-managed). The agent does not trim whitespace around the secret: copy carefully.
[agent]
server_url = https://fxconsole.gamelau.uk
secret_key = <secret>
heartbeat_interval = 5
mt5_root = C:\fxconsole-mt5
auto_relaunch_on_boot = true
init = provisioned
| Key | Bắt buộcRequired | Mặc địnhDefault | Ghi chúNotes |
|---|---|---|---|
server_url | cóyes | — | URL gốc fxconsole (không phải broker), không kèm /api/...; phải bắt đầu bằng http:// hoặc https:// (dùng https).fxconsole base URL (not the broker), no /api/...; must start with http:// or https:// (use https). |
secret_key | cóyes | — | Token riêng VPS từ admin UI, gửi trong header X-Vps-Secret.Per-VPS token from the admin UI, sent in the X-Vps-Secret header. |
heartbeat_interval | khôngno | 15 | Giây giữa hai heartbeat, kẹp [1, 600] (README cũ ghi [5, 600]; phase8 hạ sàn xuống 1 s). Server có thể ghi đè và agent ghi lại vào file.Seconds between heartbeats, clamped to [1, 600] (the old README says [5, 600]; phase8 lowered the floor to 1 s). The server can override it and the agent rewrites the file. |
mt5_root | khôngno | C:\fxconsole-mt5 | Thư mục gốc chứa MT5 portable của từng tài khoản; server nối thêm \<login>\ khi deploy (lưu ở vpses.mt5_root để dựng target_dir). Tạo sẵn với quyền ghi cho user chạy agent.Root holding each account's MT5 portable; the server appends \<login>\ per deploy (stored on vpses.mt5_root to build target_dir). Pre-create it with write permission for the agent user. |
auto_relaunch_on_boot | khôngno | true | Khi CmdAgent khởi động, quét mt5_root và chạy lại mọi thư mục có terminal64.exe chưa chạy (tìm file ini có [Common] + Login= làm /config), rồi thêm lại WebRequest URL từ .fxconsole-weburls.txt. Idempotent. false / 0 / no / off để tự điều khiển.On CmdAgent start, scan mt5_root and relaunch every folder with a non-running terminal64.exe (using an ini with [Common] + Login= as /config), then re-add WebRequest URLs from .fxconsole-weburls.txt. Idempotent. false / 0 / no / off for manual control. |
init | khôngno | (không có)(absent) | Máy trạng thái của prepare-vm.ps1: pending → installing → provisioned. Không có = ini thủ công, coi như cần cài.prepare-vm.ps1 state machine: pending → installing → provisioned. Absent = manual ini, treated as install pending. |
init_token | chỉ templatetemplate only | — | Bootstrap token dùng một lần; bị xoá khỏi file sau init.One-shot bootstrap token; removed from the file after init. |
Broker stream qua stunnelBroker stream via stunnel
HeartbeatAgent luôn nói TCP thuần tới 127.0.0.1:9605 (hard-code); stunnel trên VPS bọc TLS và chuyển tới VpsStreamBroker. Phía server xem Các broker realtime.
HeartbeatAgent always speaks plain TCP to 127.0.0.1:9605 (hard-coded); stunnel on the VPS wraps TLS and forwards to VpsStreamBroker. For the server side see Realtime brokers.
Agent tìm broker thế nào (một nguồn sự thật)How the agent discovers the broker (single source of truth)
vps-agent.ini chỉ chứa hai giá trị lấy từ bên ngoài: URL web fxconsole và secret của VPS. Host, cổng và CA của broker được lấy lúc cài qua một lệnh HTTPS có xác thực:
vps-agent.ini holds only two values from the outside world: the fxconsole web URL and the per-VPS secret. Broker host, port and CA are discovered at install time through one authenticated HTTPS call:
vps-agent.ini
server_url = https://fxconsole.gamelau.uk ← fxconsole web URL, NOT the broker
secret_key = <secret> ← per-VPS opaque token
│ prepare-vm.ps1 reads these
▼
GET ${server_url}/api/agent/broker-config
X-Vps-Secret: <secret>
│ Laravel reads app_setting('vps_broker_host'), app_setting('vps_broker_port')
│ (live from /admin/settings) + the broker CA cert (+ per-VPS VNC password)
▼
{ "broker_host":"fxconsole.gamelau.uk", "broker_port":9605,
"broker_ca":"-----BEGIN CERTIFICATE-----\n..." }
▼
prepare-vm.ps1 renders stunnel\config\stunnel.conf + broker-ca.cert
▼
stunnel listens on 127.0.0.1:9605 → ${broker_host}:${broker_port}
▼
HeartbeatAgent.au3 (hard-coded) connects to 127.0.0.1:9605
Khi broker chuyển sang địa chỉ khác (ví dụ abc.com:9999):
- Admin sửa
/admin/settings→ "VpsStreamBroker hostname" / "port". - Trên host broker: đổi
CERT_HOSTtrongmonitor/VpsStreamBroker/.env,rm -rf certs/,docker compose up -dđể sinh cert mới. - Trên từng VPS: chạy lại
prepare-vm.ps1để lấy host / port / CA mới và ghi lạistunnel.conf+broker-ca.cert. - Không sửa
vps-agent.initrên VPS nào.
Cố ý như vậy: để host/port broker trong ini sẽ tạo hai nguồn sự thật (DB + ini từng VPS) trôi lệch nhau.
When the broker moves (e.g. to abc.com:9999):
- The admin edits
/admin/settings→ "VpsStreamBroker hostname" / "port". - On the broker host: change
CERT_HOSTinmonitor/VpsStreamBroker/.env,rm -rf certs/,docker compose up -dto mint a new cert. - On each VPS: re-run
prepare-vm.ps1to fetch the new host / port / CA and rewritestunnel.conf+broker-ca.cert. - No edit to
vps-agent.inion any VPS.
This is intentional: broker host/port in the ini would create two sources of truth (DB + per-VPS ini) that drift apart.
Cert của broker trên Docker hostBroker cert on the Docker host
Hiện docker-compose.yml của fxconsole mount ../VpsStreamBroker/certs:/broker-certs:ro vào container app, nên cert tự sinh của broker được phục vụ qua /api/agent/broker-config ngay sau docker compose up -d. Bước import thủ công trong README cũ nay là dự phòng (chạy lại sau khi xoay cert nếu không dùng mount; hạn cert mặc định 10 năm):
monitor/fxconsole/docker-compose.yml now mounts ../VpsStreamBroker/certs:/broker-certs:ro into the app container, so the broker's self-signed cert is served by /api/agent/broker-config right after docker compose up -d. The manual import from the old README is now a fallback (re-run after a cert rotation if you don't use the mount; default cert validity is 10 years):
docker cp fxconsole-vps-stream-broker:/app/certs/server.cert /tmp/broker-ca.cert
docker cp /tmp/broker-ca.cert fxconsole-app:/tmp/broker-ca.cert
docker exec fxconsole-app php artisan vps-stream-broker:cert-import /tmp/broker-ca.cert
stunnel trên từng VPSstunnel on each VPS
- Đọc
server_url+secret_keytừvps-agent.ini.Readserver_url+secret_keyfromvps-agent.ini. - Tải installer stunnel (mặc định 5.78 win64; đổi bằng
-StunnelInstallerUrlhoặc dùng-StunnelInstallerLocalPath).Download the stunnel installer (default 5.78 win64; override with-StunnelInstallerUrlor use-StunnelInstallerLocalPath). - Cài NSIS im lặng (
/S /D=...) vào thư mục stunnel dướiC:\VpsAgent\.Silent NSIS install (/S /D=...) into a stunnel folder underC:\VpsAgent\. GET /api/agent/broker-configvới headerX-Vps-Secret→{broker_host, broker_port, broker_ca}.GET /api/agent/broker-configwith theX-Vps-Secretheader →{broker_host, broker_port, broker_ca}.- Ghi
stunnel\config\broker-ca.cert(PEM) vàstunnel\config\stunnel.confở chế độ client:accept 127.0.0.1:9605,connect ${broker_host}:${broker_port},verify = 2,checkHost,CAfile.Writestunnel\config\broker-ca.cert(PEM) andstunnel\config\stunnel.confin client mode:accept 127.0.0.1:9605,connect ${broker_host}:${broker_port},verify = 2,checkHost,CAfile. - Tạo shortcut Startup
fxconsole-stunnel.lnk(cửa sổ thu nhỏ) để stunnel chạy cùng session với agent và MT5.Create the Startup shortcutfxconsole-stunnel.lnk(minimised) so stunnel runs in the same session as the agents and MT5. - Chạy stunnel ngay và smoke test
Test-NetConnection 127.0.0.1 -Port 9605.Launch stunnel immediately and smoke-testTest-NetConnection 127.0.0.1 -Port 9605.
# From a fresh PowerShell window on the VPS:
Test-NetConnection 127.0.0.1 -Port 9605
# TcpTestSucceeded : True ← stunnel is listening locally
Test-NetConnection fxconsole.gamelau.uk -Port 9605
# TcpTestSucceeded : True ← TLS path to the remote broker is open
Get-Content C:\VpsAgent\stunnel\stunnel.log -Tail 20
# "Service [vps-broker] accepted connection from 127.0.0.1"
# then "Service [vps-broker] connected remote server"
| Triệu chứngSymptom | Nguyên nhân thường gặpLikely cause |
|---|---|
broker-config fetch failed | Server chưa có CA của broker (mount cert hoặc chạy import ở trên).The server has no broker CA yet (cert mount or the import above). |
stunnel download failed | VPS không ra được stunnel.org: đặt sẵn installer và chạy lại với -StunnelInstallerLocalPath.No outbound to stunnel.org: pre-stage the installer and re-run with -StunnelInstallerLocalPath. |
stunnel did NOT bind 127.0.0.1:9605 | Xem C:\VpsAgent\stunnel\stunnel.log: tiến trình khác giữ cổng (hiếm) hoặc config lỗi cú pháp.Check C:\VpsAgent\stunnel\stunnel.log: another process holds the port (rare) or the rendered config has a syntax error. |
| Cổng local mở nhưng 9605 phía xa bị từ chốiLocal port opens but remote 9605 refused | Firewall phía host broker (OVH Network Firewall / IPFire): mở TCP 9605 vào từ IP public của VPS.Firewall on the broker host (OVH Network Firewall / IPFire): open inbound TCP 9605 from the VPS public IP. |
| 9605 mở nhưng bắt tay TLS lỗiRemote 9605 opens but the TLS handshake fails | Lệch CN cert: CERT_HOST trong VpsStreamBroker/.env phải khớp vps_broker_host trên /admin/settings.Cert CN mismatch: CERT_HOST in VpsStreamBroker/.env must match vps_broker_host on /admin/settings. |
BROKER: HELLO rejected reason=bad_secret | vpses.secret_key không khớp secret_key trong ini: copy lại khối ini từ /vps/{id} → Reveal Secret.vpses.secret_key doesn't match the ini's secret_key: re-copy the ini block from /vps/{id} → Reveal Secret. |
| Đã đổi host/port broker nhưng VPS cũ vẫn gọi địa chỉ cũBroker host/port changed but old VPSes still hit the old address | Chạy lại prepare-vm.ps1 trên từng VPS.Re-run prepare-vm.ps1 on each VPS. |
Trang /vps và /deployments hiển thị heartbeat và thay đổi trạng thái realtime qua WebSocket của trình duyệt (phase7), không đổi gì phía agent; chi tiết trong monitor/VpsStreamBroker/README.md.
/vps and /deployments render heartbeats and status changes live over a browser WebSocket (phase7), with nothing changed on the agent side; details in monitor/VpsStreamBroker/README.md.
Lệnh và luồng deployCommands and deploy flow
| LệnhVerb | CmdAgent làm gìWhat CmdAgent does |
|---|---|
add_account | Tải ZIP, kiểm SHA-256, giải nén vào target_dir, inject .set, ghi file profile ini, chạy MT5, bấm Later cho LiveUpdate, quét journal, cấu hình WebRequest URL. Lỗi ở bất kỳ bước nào → rollback (kill terminal, xoá thư mục).Download the ZIP, verify SHA-256, unzip into target_dir, inject .set values, write the profile ini, launch MT5, answer Later to LiveUpdate, scan the journal, configure WebRequest URLs. Any failure → rollback (kill the terminal, delete the folder). |
remove_account | Tìm mọi terminal64.exe dưới target_dir, ProcessClose, chờ 10 s rồi taskkill /F, xoá thư mục (thử lại một lần). Thư mục không tồn tại = thành công (no-op).Find every terminal64.exe under target_dir, ProcessClose, wait 10 s then taskkill /F, delete the folder (one retry). A missing folder = success (no-op). |
upgrade_account | remove_account nội bộ (cmd_id = −1, ACK bị bỏ) rồi add_account.Internal remove_account (cmd_id = −1, ACK dropped) followed by add_account. |
upgrade_agent | ACK thành công trước, chờ 2 s, chạy upgrade.ps1 rồi thoát (xem Tự nâng cấp).ACKs success first, waits 2 s, spawns upgrade.ps1, then exits (see Self-upgrade). |
rename_host | Từ 1.3.4-phase11. Đổi tên máy Windows thành computer_name (WMI Win32_ComputerSystem.Rename, tối đa 15 ký tự). Với reboot = true: ACK thành công trước, rồi shutdown /r /t reboot_delay_sec (fxconsole đặt = 3 × heartbeat interval, 30–600 s) để ACK kịp về server. Sau khi boot, AutoLogon chạy lại agent và agent mở lại mọi terminal MT5. Được gửi khi admin tick "Đổi tên máy Windows… khởi động lại VM ngay" trong dialog Edit ở /vps.Since 1.3.4-phase11. Renames the Windows machine to computer_name (WMI Win32_ComputerSystem.Rename, max 15 chars). With reboot = true: ACKs success first, then shutdown /r /t reboot_delay_sec (fxconsole sets 3 × heartbeat interval, 30–600 s) so the ACK reaches the server. After boot, AutoLogon restarts the agent and it relaunches every MT5 terminal. Sent when an admin ticks "Rename the Windows machine… restart the VM now" in the /vps Edit dialog. |
sequenceDiagram
participant U as Người dùng / admin
participant APP as fxconsole app
participant DB as MySQL
participant VB as VpsStreamBroker
participant HB as HeartbeatAgent
participant CA as CmdAgent
participant MT as MT5 terminal
U->>APP: Deploy (package, VPS, login)
APP->>DB: INSERT vps_commands status=queued
APP->>VB: Redis PUBLISH vps:cmd (vps_id, cmd_id, kind)
VB->>HB: cmd (cmd_id, kind), không kèm payload
HB->>CA: IPC do_cmd_pull (cmd_id, kind)
CA->>APP: GET /api/vps/cmd/ID/payload + X-Vps-Secret
APP-->>CA: id, type, payload
CA->>CA: tải ZIP, kiểm SHA-256, giải nén, inject .set, ghi profile ini
CA->>MT: terminal64.exe /portable /config:profile
CA->>MT: bấm Later cho LiveUpdate, quét journal, thêm WebRequest URL
CA-->>HB: IPC ack (cmd_id, success, log, error)
alt broker khoẻ
HB->>VB: event (cmd_id, finished, status)
VB->>DB: UPDATE vps_commands
else broker sập
HB->>APP: command_acks trong heartbeat HTTPS kế tiếp
APP->>DB: UPDATE vps_commands
endsequenceDiagram
participant U as User / admin
participant APP as fxconsole app
participant DB as MySQL
participant VB as VpsStreamBroker
participant HB as HeartbeatAgent
participant CA as CmdAgent
participant MT as MT5 terminal
U->>APP: Deploy (package, VPS, login)
APP->>DB: INSERT vps_commands status=queued
APP->>VB: Redis PUBLISH vps:cmd (vps_id, cmd_id, kind)
VB->>HB: cmd (cmd_id, kind), no payload
HB->>CA: IPC do_cmd_pull (cmd_id, kind)
CA->>APP: GET /api/vps/cmd/ID/payload + X-Vps-Secret
APP-->>CA: id, type, payload
CA->>CA: download ZIP, check SHA-256, unzip, inject .set, write profile ini
CA->>MT: terminal64.exe /portable /config:profile
CA->>MT: answer Later to LiveUpdate, scan journal, add WebRequest URLs
CA-->>HB: IPC ack (cmd_id, success, log, error)
alt broker healthy
HB->>VB: event (cmd_id, finished, status)
VB->>DB: UPDATE vps_commands
else broker down
HB->>APP: command_acks in the next HTTPS heartbeat
APP->>DB: UPDATE vps_commands
end- Hai đường nhận lệnh. Broker push (dưới 1 giây) là chính: chỉ
cmd_id+kindđi qua broker, payload nhạy cảm được CmdAgent kéo qua HTTPS. HTTPS heartbeat response là dự phòng (do_cmdkèm nguyên response). Vòng dedup 256cmd_idtrong HeartbeatAgent bỏ lệnh tới hai lần. - Hai đường ACK. Frame
eventkhi stream khoẻ; khi không, ACK xếp trong mảng của HeartbeatAgent và gửi kèm heartbeat HTTPS kế tiếp. Hai đường cùng dẫn tớiUPDATE vps_commands SET status=…. - Tuần tự. CmdAgent xử lý một lệnh một lúc; lệnh tới dồn dập xếp hàng trong socket IPC. Heartbeat vẫn chạy trong lúc cài MT5, VPS vẫn "running".
- Crash. Supervisor kiểm
ProcessExistsmỗi tick và spawn lại CmdAgent trong ~5 s; ACK của lệnh đang chạy mất, reaper 5 phút phía server xử lý. HeartbeatAgent crash thì chỉ lên lại ở lần logon kế (chưa có watchdog). - Payload thiếu trường,
target_dirchứa..hoặc không chứa login, SHA-256 lệch, giải nén 3 phút không raterminal64.exe, 30 s không thấy tiến trình MT5, journal cóauthorization on … failed/Invalid account/account disabled|suspended|locked→ ACK thất bại (có rollback khi đã tạo thư mục).
- Two command-arrival paths. Broker push (sub-second) is primary: only
cmd_id+kindcross the broker, and CmdAgent pulls the sensitive payload over HTTPS. The HTTPS heartbeat response is the fallback (do_cmdcarrying the raw response). A 256-entry dedup ring in HeartbeatAgent drops a command that arrives twice. - Two ACK paths. An
eventframe when the stream is healthy; otherwise the ACK is queued in HeartbeatAgent and shipped in the next HTTPS heartbeat. Both converge onUPDATE vps_commands SET status=…. - Serial. CmdAgent runs one command at a time; bursts queue in the IPC socket. Heartbeats keep flowing during an MT5 install, so the VPS stays "running".
- Crashes. The supervisor checks
ProcessExistsevery tick and respawns CmdAgent within ~5 s; the in-flight ACK is lost and the server's 5-minute reaper picks it up. If HeartbeatAgent itself crashes, it only returns at the next logon (no watchdog yet). - Missing payload fields, a
target_dircontaining..or not containing the login, SHA-256 mismatch, noterminal64.exeafter a 3-minute unzip, no MT5 process within 30 s, or a journal lineauthorization on … failed/Invalid account/account disabled|suspended|locked→ failure ACK (with rollback once the folder exists).
Chi tiết add_accountadd_account in detail
Trường payload: login, password_b64, server, target_dir, package_url, package_sha256, profile (mặc định Default, tự thêm .ini), injections[] (file, key, value), web_request_urls[]. File profile được ghi vào target_dir:
Payload fields: login, password_b64, server, target_dir, package_url, package_sha256, profile (default Default, .ini appended), injections[] (file, key, value), web_request_urls[]. The profile file written into target_dir:
[Common]
Login=<login>
Password=<secret>
Server=<server>
EnableLiveUpdate=0
KeepPrivate=1
[Experts]
AllowLiveTrading=1
AllowDllImport=1
Enabled=1
Account=0
Profile=0
- MT5 được chạy bằng
"<target>terminal64.exe" /portable /config:<profile>.ini(ẩn cửa sổ). File profile được giữ lại trên đĩa (chế độ debug) và cũng là thứ relaunch lúc boot dùng lại. - Danh sách WebRequest URL được lưu vào
<target>.fxconsole-weburls.txtđể thêm lại khi relaunch. GUI automation: Tools → Options → tab Expert Advisors → tick cho phép WebRequest → gõ từng URL → OK, rồi thu nhỏ MT5. Không có URL thì chỉ thu nhỏ cửa sổ. EnableLiveUpdate=0không đủ để chặn hộp thoại LiveUpdate nếu bản cập nhật đã được tải trước đó; vì vậy CmdAgent quét hộp thoại ở mọi bước chờ và bấm Later (thử nút caption "Later", rồi[TEXT:Later], cuối cùngWinClose, không bao giờ ENTER). Log ACK ghideferred N MT5 LiveUpdate prompt(s) -- chose Later, terminal not restarted.
- MT5 is launched with
"<target>terminal64.exe" /portable /config:<profile>.ini(hidden). The profile file stays on disk (debug mode) and is what boot-time relaunch reuses. - The WebRequest URL list is saved to
<target>.fxconsole-weburls.txtfor re-adding on relaunch. GUI automation: Tools → Options → Expert Advisors tab → tick allow WebRequest → type each URL → OK, then minimise MT5. With no URLs it just minimises the window. EnableLiveUpdate=0is not enough to stop the LiveUpdate prompt when an update was downloaded earlier; so CmdAgent sweeps for the dialog during every wait and clicks Later (the button captioned "Later", then[TEXT:Later], finallyWinClose, never ENTER). The ACK log recordsdeferred N MT5 LiveUpdate prompt(s) -- chose Later, terminal not restarted.
Khung dữ liệu IPC và brokerIPC and broker frames
Cả hai kênh đều là NDJSON. IPC chạy TCP loopback thuần 127.0.0.1:9606, không TLS (ai tới được loopback thì đã có quyền đọc file agent). Kênh broker đi qua stunnel.
Both channels are NDJSON. IPC is plain TCP loopback on 127.0.0.1:9606 with no TLS (anything reaching loopback already has filesystem access to the agent). The broker channel goes through stunnel.
HeartbeatAgent → CmdAgent:
{"t":"do_cmd", "cmd_index":N, "hb_resp":"<raw heartbeat JSON>"} ← HTTPS fallback path
{"t":"do_cmd_pull", "cmd_id":N, "kind":"add_account"} ← broker push path
CmdAgent → HeartbeatAgent:
{"t":"ready", "cmd_v":"…", "ts":…} ← on every IPC connect
{"t":"ack", "cmd_id":N, "success":bool, "log":"…", "error":"…"} ← terminal result
{"t":"log", "msg":"…"} ← optional
HeartbeatAgent → broker:
{"t":"hello", "v":1, "secret":"<secret_key>", "agent_v":"1.3.2-phase9", "ts":…}
{"t":"hb", "cpu":12.4, "ram":34.0, "disk":78.2, "net":5.1, "accts":3, "logins":[…], "ts":…}
{"t":"hb", "ts":…} ← hb_min while stream_off
{"t":"event", "cmd_id":N, "phase":"finished", "status":"success", "log":"…", "error":"", "ts":…}
{"t":"pong", "ts":…}
Broker → HeartbeatAgent:
{"t":"hello_ok", "vps_id":42, "server_t":…}
{"t":"hello_err", "reason":"bad_secret"|"timeout"|"unknown_vps"}
{"t":"hb_ok", "ts":…, "interval":N}
{"t":"cmd", "cmd_id":N, "kind":"add_account", "ts":…}
{"t":"stream_on"} / {"t":"stream_off"}
{"t":"ping", "ts":…} ← every PING_INTERVAL (broker .env)
{"t":"bye", "reason":"shutdown"}
Dấu vết log một lần deploy qua brokerEnd-to-end log trace (deploy via broker)
fxconsole-app INSERT vps_commands … status=queued
VpsCommand::booted PUBLISH laravel-database-vps:cmd {vps_id:42,cmd_id:1234,kind:add_account}
fxconsole-vps-stream-broker cmd push → vps=42 cmd_id=1234 kind=add_account
heartbeat-agent.log BROKER: cmd push cmd_id=1234 kind=add_account — forwarding to CmdAgent
cmd-agent.log CMD #1234 pulling payload via HTTPS (kind=add_account)
CMD recv #1234 type=add_account
CMD #1234 downloading...
… (install, unzip, inject, launch MT5, journal scan) …
CMD #1234 add_account ok login=12345678
heartbeat-agent.log ACK via broker stream cmd_id=1234 success=true
fxconsole-vps-stream-broker [vps=42] event cmd_id=1234 → success
fxconsole MySQL vps_commands.id=1234 status=success completed_at=now
Nếu stream sập ở bất kỳ bước nào, HeartbeatAgent âm thầm chuyển bước đang dở (heartbeat và/hoặc ACK) sang HTTPS; người dùng không thấy khác biệt.
If the stream drops at any point, HeartbeatAgent silently moves whichever step was in flight (heartbeats and/or ACKs) to HTTPS; users see no difference.
Gói deploy tài khoảnAccount deploy packages
Một package là file ZIP chứa MT5 portable + EA + profile, host ở URL HTTPS do admin kiểm soát. fxconsole chỉ lưu URL + version + SHA-256 + metadata (allowlist URL, value injection, broker), không lưu file ZIP. Mỗi package gắn với một broker; người dùng chỉ deploy được lên VPS cùng broker. Đăng ký ở /admin/packages; người dùng chọn ở /deployments/new.
A package is a ZIP of an MT5 portable + EA + profile, hosted at an HTTPS URL the admin controls. fxconsole stores only the URL + version + SHA-256 + metadata (URL allowlist, value injections, broker), never the ZIP itself. Each package is tied to one broker; users can only deploy it onto a VPS of the same broker. Register on /admin/packages; users pick on /deployments/new.
Gói hiện có trong monitor/vps-agentPackages currently in monitor/vps-agent
Gói deploy GoldenRobber production là GoldenRobber-Pass58_v1-42-b3-Vantage-build-6182.zip (17/09/2026): chart01.chr trỏ tới Experts\GoldenRobber-1.42.ex5 — đúng EA production 1.42 b3 — và đã đặt sẵn InpCloudMyApiDomain=https://fxconsole.gamelau.uk/easupported/goldenrobber. Gói của bản cũ 1.41.4 là GoldenRobber-Pass58_v1_41_4-Vantage-build-6182.zip. Lưu ý (18/09/2026): thư mục monitor/vps-agent/ không có file …v1_41_4… — chỉ có gói b3 ở trên (tạo 17/09/2026); gói b2 đã bị thay. Trước khi deploy, kiểm tra trên /admin/packages URL + SHA-256 của package người dùng sẽ chọn, và mở MQL5/Profiles/Charts/Default/chart01.chr trong ZIP để xác nhận EA.
The production GoldenRobber deploy package is GoldenRobber-Pass58_v1-42-b3-Vantage-build-6182.zip (17/09/2026): its chart01.chr points to Experts\GoldenRobber-1.42.ex5 — the production EA 1.42 b3 — and it already sets InpCloudMyApiDomain=https://fxconsole.gamelau.uk/easupported/goldenrobber. The previous 1.41.4 package is GoldenRobber-Pass58_v1_41_4-Vantage-build-6182.zip. Note (18/09/2026): monitor/vps-agent/ does not contain a …v1_41_4… file — only the b3 package above (created 17/09/2026); the b2 package has been replaced. Before deploying, check on /admin/packages the URL + SHA-256 of the package users will pick, and open MQL5/Profiles/Charts/Default/chart01.chr inside the ZIP to confirm the EA.
| File | Chart EA (chart01 / chart02)Chart EAs (chart01 / chart02) | NgàyDate |
|---|---|---|
GoldenRobber-Pass58_v1-42-b3-Vantage-build-6182.zip | GoldenRobber-1.42.ex5 / AccountStatusUpdater-1.14.ex5 PRODUCTION | 17/09/2026 |
GoldenRobber-Pass58-Vantage-build-6140.zip | GoldenRobber-1.41.1.ex5 / AccountStatusUpdater-1.14.ex5 | 22/08/2026 |
GoldenRobber-Pass58-Vantage.zip | GoldenRobber-1.41.1.ex5 / AccountStatusUpdater-1.14.ex5 | 04/08/2026 |
GoldenRobber-1.46-H4origin-mult1.5-TrueScale1.5.zip | GoldenRobber-1.46.ex5 / AccountStatusUpdater-1.14.ex5 | 14/07/2026 |
GoldenRobberMaxLot-0.3_Vantage_v1.14062026.zip | GoldenRobber-1.39.ex5 / AccountStatusUpdater-1.14.ex5 | 30/06/2026 |
CloseAllOrders-build-6182.zip, CloseAllOrders.zip | CloseAll.ex5 / AccountStatusUpdater-1.14.ex5 | 07/09, 14/06/2026 |
MonitoringBot-build-6182.zip, MonitoringBot.zip | AccountStatusUpdater-1.14.ex5 | 07/09, 01/07/2026 |
Mọi gói trên đều kèm preset MQL5/Presets/AccountStatusUpdater-1.09.set và MQL5/Presets/GoldenRobber-1.39.set. Hậu tố build-6140 / build-6182 nhiều khả năng là build MT5 terminal trong gói (suy luận từ tên).
Every package above also ships the presets MQL5/Presets/AccountStatusUpdater-1.09.set and MQL5/Presets/GoldenRobber-1.39.set. The build-6140 / build-6182 suffix is most likely the bundled MT5 terminal build (inferred from the name).
Chuẩn bị ZIPPreparing the ZIP
my-package.zip
├── terminal64.exe ← MT5 main binary
├── metaeditor64.exe ← optional
├── MQL5/
│ ├── Experts/ ← your EAs (.ex5)
│ ├── Presets/ ← .set files for value injection
│ └── Profiles/Charts/Default/ ← chart01.chr, chart02.chr … attach the EAs
├── config/ ← MT5 writes here at first launch (keep empty)
└── …other MT5 standard folders
- ZIP phải giải nén thẳng ra thư mục MT5 portable dùng được: agent giải nén vào
C:\fxconsole-mt5\<login>\và chạyterminal64.exeở gốc.The ZIP must unzip directly into a usable MT5 portable folder: the agent extracts intoC:\fxconsole-mt5\<login>\and runsterminal64.exefrom the root. - Không để lại
config/origin.inihay tài khoản đã lưu từ máy chuẩn bị: chúng mã hoá bằng DPAPI của máy đó và không giải mã được ở máy khác. Xoá nội dungconfig/(giữ thư mục) nếu từng đăng nhập bằng bản copy đó.Do not includeconfig/origin.inior saved accounts from the prep machine: they are DPAPI-encrypted to that machine and won't decrypt elsewhere. Emptyconfig/(keep the folder) if you ever logged in from that copy. - Chạy bản portable, mở chart, gắn EA, cấu hình input, lưu profile (File → Profiles → Save As…); tên profile nhập vào trường Profile của package.Run the portable, open a chart, attach the EA, configure inputs, save the profile (File → Profiles → Save As…); put that name in the package's Profile field.
- Input nào cần khác nhau theo người dùng thì đặt trong file
.setdướiMQL5/Presets/với giá trị placeholder (ví dụREPLACE_ME), rồi trong MT5 bấm Load chọn file.setđó và lưu lại template chart.Inputs that differ per user go into a.setfile underMQL5/Presets/with a placeholder value (e.g.REPLACE_ME); in MT5 click Load, pick that.set, and save the chart template again. - Nén toàn bộ thư mục, upload lên URL HTTPS (máy chủ riêng, S3, Cloudflare R2, GitHub release, link tải trực tiếp Dropbox / Google Drive). Không dùng HTTP thường.Zip the whole folder and upload it to an HTTPS URL (own server, S3, Cloudflare R2, a GitHub release, a Dropbox / Google Drive direct-download link). Never plain HTTP.
- Tính SHA-256 (64 ký tự hex) và nhập vào package. Agent tính lại sau khi tải; lệch là huỷ deploy.Compute the SHA-256 (64 hex chars) and enter it on the package. The agent recomputes after download; a mismatch aborts the deploy.
certutil -hashfile package.zip SHA256 # Windows
shasum -a 256 package.zip # Linux / macOS
openssl dgst -sha256 package.zip
Trường của packagePackage fields
| TrườngField | Nhập gìWhat to enter |
|---|---|
| Label / Description | Tên ngắn người dùng chọn và mô tả một dòngShort name users pick and a one-line description |
| Broker | Chọn từ /admin/brokers; raw name phải khớp đúng ACCOUNT_COMPANY MT5 báoFrom /admin/brokers; the raw name must exactly match MT5's ACCOUNT_COMPANY |
| ZIP URL / Version | URL HTTPS agent tải và chuỗi version tuỳ ýHTTPS URL the agent downloads and any version string |
| Profile | Tên profile MT5 trong ZIP, truyền vào /config:MT5 profile name inside the ZIP, passed to /config: |
| MT5 build | Tuỳ chọn; từ chối deploy nếu build thực tế khác. Trống = không kiểm.Optional; refuses deploys when the actual build differs. Empty = no check. |
| SHA-256 | 64 ký tự hex của ZIP64 hex chars of the ZIP |
| WebRequest URLs | Mỗi dòng một URL EA cần gọi (ví dụ https://fxconsole.example.com cho AccountStatusUpdater); agent tự thêm vào MT5One URL per row that the EA calls (e.g. https://fxconsole.example.com for AccountStatusUpdater); the agent adds them to MT5 |
| Value injections | file (đường dẫn .set tương đối trong ZIP), key (tên input), source: user.mt5_secret_key, user.email, mt5_account.login, mt5_account.serverfile (.set path relative to the ZIP root), key (input name), source: user.mt5_secret_key, user.email, mt5_account.login, mt5_account.server |
Server phân giải source thành giá trị thật trước khi gửi; agent chỉ nhận literal. InjectKeyValue của CmdAgent dùng regex ^key=.*$ để thay dòng đã tồn tại trong file .set (giữ nguyên encoding UTF-16 / UTF-8 BOM). Key không có trong file sẽ không được thêm: log ghi inject FAILED: <file> :: <key> nhưng deploy vẫn tiếp tục. File không tồn tại → inject SKIP (missing); đường dẫn tuyệt đối, có .. hoặc : → inject SKIP (bad path). Vì vậy mọi key cần inject phải có sẵn (với placeholder) trong .set của ZIP; nếu không, mọi người dùng sẽ chạy với secret nướng sẵn trong gói. Kiểm tra log deploy sau mỗi gói mới.
The server resolves source to the real value before sending; the agent only sees literals. CmdAgent's InjectKeyValue uses the regex ^key=.*$ to replace an existing line in the .set file (keeping its UTF-16 / UTF-8 BOM encoding). A key missing from the file is not added: the log says inject FAILED: <file> :: <key> and the deploy carries on. A missing file → inject SKIP (missing); an absolute path, .. or : → inject SKIP (bad path). So every injected key must already exist (with a placeholder) in the ZIP's .set; otherwise every user runs with whatever secret is baked into the package. Check the deploy log after each new package.
Trạng thái deploymentDeployment statuses
| Trạng tháiStatus | Ý nghĩaMeaning | Thường chuyển sangNext likely state |
|---|---|---|
pending | Lệnh đã xếp hàng, agent chưa nhậnCommand queued; agent hasn't started | deploying |
deploying | Agent đang tải / giải nén / chạy MT5Agent downloading / unzipping / launching | running / failed |
running | MT5 chạy, EA đang báo vềMT5 up; EA reporting back | removing / upgrading |
removing | Đang dừng MT5 và xoá fileStopping MT5 and cleaning files | removed |
migrating | Đang chuyển sang VPS khácMove to another VPS in progress | running / failed |
upgrading | Thay package mới tại chỗNew package version replacing MT5 in place | running / failed |
failed | Thao tác cuối lỗi, xem last_error; tài khoản KHÔNG chạyLast operation errored, see last_error; account NOT running | removed |
removed | Đã gỡ mềm; login được deploy lạiSoft-removed; login free to redeploy | — |
- Một login chỉ có một deployment đang hoạt động trên toàn hệ thống (hai MT5 cùng login sẽ bị broker đá một bên). Muốn chuyển VPS thì dùng migrate.
- Quota mặc định 5 tài khoản / người, chỉnh ở
/admin/users(0= chặn deploy). - Mật khẩu MT5 mã hoá bằng
Crypt::encryptStringkhi lưu; nằm dạng rõ tạm trongvps_commands.payloadkhi thực thi và được dọn sau khi deploy thành công (quét 24 giờ); tới agent qua HTTPS; trên VPS MT5 tự lưu mã hoá DPAPI. - Có sẵn đổi package hàng loạt (
/deployments/bulk-change-package), migrate và migrate hàng loạt.DEPLOYMENT_GUIDE.htmlcòn ghi agent "chưa thực thi lệnh" và các tính năng này "phase sau": phần đó đã cũ.
- A login can have only one active deployment system-wide (two MT5s on one login get one kicked by the broker). Use migrate to move VPS.
- Default quota is 5 accounts per user, set on
/admin/users(0blocks deploys). - MT5 passwords are encrypted at rest with
Crypt::encryptString; they sit in plaintext briefly invps_commands.payloadduring execution and are GC'd after a successful deploy (24 h sweep); they reach the agent over HTTPS; on the VPS MT5 stores them DPAPI-encrypted. - Bulk package change (
/deployments/bulk-change-package), migrate and bulk migrate exist.DEPLOYMENT_GUIDE.htmlstill says the agent "doesn't execute commands yet" and calls these features "later phases": that part is stale.
Tự nâng cấp agentAgent self-upgrade
| Gói agentAgent package | Nội dungContents | Dùng choUsed for |
|---|---|---|
vps-agent-setup-1.3.4-phase11.zip | HeartbeatAgent.exe, CmdAgent.exe, prepare-vm.ps1, bootstrap-fresh-vm.ps1, upgrade.ps1, vps-agent.ini.init-template, AutoLogon.zip | Cài mới / image vàngFresh install / golden image |
vps-agent-upgrade-1.3.4-phase11.zip | HeartbeatAgent.exe, CmdAgent.exe | Upload ở /admin/agent-releases cho upgrade_agentUpload on /admin/agent-releases for upgrade_agent |
…-1.3.3-phase10.zip, …-1.3.2-phase9.zip | như trênsame as above | Bản trước, để rollbackPrevious release, for rollback |
- Admin upload zip nâng cấp ở
/admin/agent-releases, rồi bấm nâng cấp một VPS (POST /admin/vps/{id}/upgrade-agent) hoặc nhiều VPS (POST /admin/vps/upgrade-agent-bulk).The admin uploads the upgrade zip on/admin/agent-releases, then upgrades one VPS (POST /admin/vps/{id}/upgrade-agent) or many (POST /admin/vps/upgrade-agent-bulk). - CmdAgent nhận payload
{release_id, download_url, expected_hash, label, version, size_bytes}, đọc lạisecret_keytừ ini, ACK thành công trước (script sắp kill nó), chờ 2 s, chạyupgrade.ps1 -DownloadUrl … -ExpectedHash … -SecretKey <secret> -AgentDir …(hiện cửa sổ) rồi thoát.CmdAgent receives{release_id, download_url, expected_hash, label, version, size_bytes}, re-readssecret_keyfrom the ini, ACKs success first (the script is about to kill it), waits 2 s, runsupgrade.ps1 -DownloadUrl … -ExpectedHash … -SecretKey <secret> -AgentDir …(visible window), then exits. upgrade.ps1tải zip từ/api/agent/release/{id}/download(headerX-Vps-Secret), kiểm SHA-256, kill các tiến trình agent, chờ-KillSettleSeconds(3 s), giải nén (làm phẳng nếu zip có một thư mục gốc), robocopy đè lênAgentDir,Unblock-File, rồi reboot sau-RebootCountdownSeconds(10 s, Ctrl+C để huỷ). Log ởupgrade.log.upgrade.ps1downloads the zip from/api/agent/release/{id}/download(X-Vps-Secretheader), verifies SHA-256, kills the agent processes, waits-KillSettleSeconds(3 s), extracts (flattening a single-folder zip), robocopies overAgentDir, runsUnblock-File, then reboots after-RebootCountdownSeconds(10 s, Ctrl+C aborts). It logs toupgrade.log.- Sau reboot, AutoLogon → Startup chạy binary mới;
agent_vmới hiện trên thẻ/vps.After the reboot, AutoLogon → Startup runs the new binaries; the newagent_vshows on the/vpscard.
Nâng cấp agent reboot VPS: mọi MT5 trên máy tắt rồi được relaunch khi boot. Lên lịch ngoài giờ giao dịch căng. Khi terminal chạy lại, nếu hiện "Welcome to LiveUpdate" thì chọn Later (CmdAgent phase9 tự làm việc này; nếu đang nâng cấp từ bản cũ hơn phase9 hoặc bạn thao tác tay qua VNC, phải tự bấm Later). Nếu script lỗi âm thầm sau khi đã ACK, lệnh vẫn hiện thành công; kiểm tra agent_v và upgrade.log.
An agent upgrade reboots the VPS: every MT5 on the box stops and is relaunched at boot. Schedule it outside busy trading hours. When terminals come back, if "Welcome to LiveUpdate" appears, choose Later (CmdAgent phase9 does this itself; when upgrading from a pre-phase9 build or working by hand over VNC, click Later yourself). If the script fails silently after the ACK, the command still shows success; check agent_v and upgrade.log.
upgrade.ps1 không nằm trong zip nâng cấp; muốn cập nhật chính script này thì chạy lại prepare-vm.ps1 với file mới (nếu thiếu, lệnh upgrade_agent báo upgrade.ps1 not found … re-run prepare-vm.ps1 to drop it).
upgrade.ps1 is not in the upgrade zip; to update the script itself, re-run prepare-vm.ps1 with the new file (if it's missing, upgrade_agent fails with upgrade.ps1 not found … re-run prepare-vm.ps1 to drop it).
Tham chiếu APIAPI reference
| Method | Path | Auth | Công dụngPurpose |
|---|---|---|---|
| POST | /api/vps/heartbeat | X-Vps-Secret | Heartbeat HTTPS (dự phòng), trả lệnh chờHTTPS heartbeat (fallback), returns pending commands |
| GET | /api/vps/cmd/{id}/payload | X-Vps-Secret | Payload đầy đủ của lệnh được broker pushFull payload for a broker-pushed command |
| GET | /api/agent/broker-config | X-Vps-Secret | Host / port / CA broker + mật khẩu VNCBroker host / port / CA + VNC password |
| POST | /api/agent/init-config | Authorization: Bearer (bootstrap token)(bootstrap token) | Zero-touch: MAC → config riêng VPSZero-touch: MACs → per-VPS config |
| GET | /api/agent/release/{id}/download | X-Vps-Secret | Tải zip nâng cấp agentDownload the agent upgrade zip |
| GET | /vps, /vps/{id} | Cookie phiênSession cookie | Trang Inertia; admin nhận isAdmin: true và secretInertia pages; admins get isAdmin: true and secrets |
| POST / DELETE | /admin/vps, /admin/vps/{id} | Phiên + middleware admin (403)Session + admin middleware (403) | CRUD VPSVPS CRUD |
POST /api/vps/heartbeat
{
"agent_version": "1.3.2-phase9",
"heartbeat_interval": 15,
"mt5_root": "C:\\fxconsole-mt5",
"lan_ip": "192.168.1.10",
"cpu_name": "…",
"cpu_pct": 12.40,
"ram_pct": 42.18,
"disk_pct": 33.70,
"net_pct": 0.60,
"account_count": 1,
"account_logins": ["12345678"],
"command_acks": []
}
Mọi trường đều tuỳ chọn trừ header. Server kiểm phạm vi (0–100 cho phần trăm, 0–1000 cho account_count); lan_ip là IPv4 lấy từ @IPAddress1. Server chỉ gán vpses.rdp_info bằng giá trị này ở heartbeat đầu tiên khi field còn trống; admin đã nhập thì không ghi đè. (lan_ip cũng là địa chỉ Guacamole quay VNC.) Agent coi mọi mã ngoài 200–299 là lỗi mềm: ghi log và thử lại lần sau.
All fields are optional except the header. Ranges are validated (0–100 for percentages, 0–1000 for account_count); lan_ip is IPv4 from @IPAddress1. The server seeds vpses.rdp_info with it only on the first heartbeat where the field is still empty; once an admin types a value it is left alone. (lan_ip is also the address Guacamole dials over VNC.) The agent treats anything outside 200–299 as a soft failure: it logs and retries next interval.
| Status | Body | Khi nàoWhen |
|---|---|---|
| 200 | {"ok":true,"status":"running","heartbeat_interval":15, "commands":[…]} | thành côngsuccess |
| 401 | {"message":"Missing X-Vps-Secret"} / "Unknown VPS secret" | thiếu / sai keymissing / bad key |
| 422 | {"message":"Validation failed","errors":{…}} | payload saibad payload |
Mô hình bảo mậtSecurity model
| Rủi roConcern | Giảm thiểuMitigation |
|---|---|
Secret bị lấy từ .iniSecret stolen from the .ini | Chưa có nút xoay secret: xoá rồi tạo lại VPS. Chấp nhận vì file nằm trên máy vốn đã tin cậy.No rotate button yet: delete and re-create the VPS. Accepted because the file sits on a machine you already trust. |
| Replay / MitMReplay / MitM | TLS qua https://server_url và stunnel verify = 2. Không chạy agent với http thường.TLS via https://server_url and stunnel verify = 2. Never run the agent against plain http. |
| VPS bị chiếm gửi số liệu giảCompromised VPS sends fake stats | Tệ nhất là dòng hiện sai CPU/RAM; endpoint không tạo user, không sửa VPS khác, không đọc dữ liệu về.Worst case the row shows wrong CPU/RAM; the endpoint can't create users, mutate other VPSes or read data back. |
| Người thường gọi endpoint adminAdmin endpoints from a regular user | EnsureAdmin trả 403 cho mọi POST /admin/vps*; ẩn trên UI chỉ để tiện.EnsureAdmin returns 403 on every POST /admin/vps*; UI gating is convenience only. |
| Dò secretBrute-forcing the secret | VPS- + Str::random(60) viết hoa, rất khó đoán; chưa có rate limit (có thể thêm throttle:60,1 nếu bị flood heartbeat).VPS- + upper-cased Str::random(60), practically unguessable; no rate limit yet (add throttle:60,1 if heartbeat flooding becomes real). |
| Cướp danh tính VM mới cloneHijacking a fresh clone's identity | Bootstrap token so bằng hash_equals trước khi tra MAC; token bị xoá khỏi ini sau init.Bootstrap token checked with hash_equals before the MAC lookup; removed from the ini after init. |
Xử lý sự cốTroubleshooting
| Triệu chứngSymptom | Nguyên nhân / cách xử lýCause / fix |
|---|---|
Chạy HeartbeatAgent.exe mà không thấy gìRan HeartbeatAgent.exe and nothing happened | Bản GUI không có console (trừ khi $DEBUG_CONSOLE bật). Kiểm Task Manager → Details có cả HeartbeatAgent.exe và CmdAgent.exe dưới Administrator; đọc heartbeat-agent.log cạnh exe; refresh /vps.A GUI build has no console (unless $DEBUG_CONSOLE is on). Check Task Manager → Details for both HeartbeatAgent.exe and CmdAgent.exe under Administrator; read heartbeat-agent.log next to the exe; refresh /vps. |
HB http=401 resp={"message":"Unknown VPS secret"} | Secret không khớp dòng nào: copy nhầm, admin đã xoá VPS, hoặc có khoảng trắng quanh key (agent không trim).The secret matches no row: wrong string copied, the admin deleted the VPS, or whitespace around the key (the agent doesn't trim). |
COM error: hresult=0x80072EE7 (hoặc lỗi WinHttp khác)(or other WinHttp errors) | Lỗi mạng: VPS mất Internet, DNS của server_url lỗi, cert server không hợp lệ với WinHTTP. Agent tự thử lại.Network: VPS offline, DNS for server_url failed, or the server cert isn't trusted by WinHTTP. The agent retries. |
Dòng kẹt pending dù agent báo chạyRow stuck on pending though the agent runs | Xác nhận server_url đúng server, secret khớp (nếu nghi thì xoá + tạo lại); xem log có HB ok (HTTPS) hoặc HB via broker stream.Confirm server_url points at the right server and the secret matches (delete + re-create if unsure); look for HB ok (HTTPS) or HB via broker stream in the log. |
cpu_pct luôn 0cpu_pct always 0 | Máy quá rảnh; kiểm tay: wmic path Win32_PerfFormattedData_PerfOS_Processor WHERE Name="_Total" get PercentProcessorTime. Khi stream_off, agent cố ý không đo WMI.Extremely idle box; check by hand: wmic path Win32_PerfFormattedData_PerfOS_Processor WHERE Name="_Total" get PercentProcessorTime. While stream_off the agent deliberately skips WMI. |
net_pct luôn 0net_pct always 0 | Win32_PerfFormattedData_Tcpip_NetworkInterface cần perf counter: bật lại service WmiPerfClass và winmgmt trên image rút gọn.Win32_PerfFormattedData_Tcpip_NetworkInterface needs perf counters: re-enable WmiPerfClass and winmgmt on stripped images. |
| Agent chết âm thầm khi chạy dạng serviceAgent dies silently as a service | Không hỗ trợ: agent phải chạy trong session tương tác (Startup hoặc Task Scheduler LogonType Interactive).Unsupported: the agents must run in the interactive session (Startup or Task Scheduler LogonType Interactive). |
FATAL: cannot bind IPC listener on 127.0.0.1:9606 | Đã có một HeartbeatAgent khác đang chạy.Another HeartbeatAgent instance is already running. |
Deploy lỗi SHA-256 mismatchDeploy fails with SHA-256 mismatch | ZIP ở URL đã bị thay mà chưa cập nhật hash trên package.The ZIP at the URL changed but the package hash wasn't updated. |
Deploy lỗi MT5 build mismatchDeploy fails with MT5 build mismatch | MT5 tự cập nhật lên build khác: sửa build kỳ vọng, đóng gói lại bằng MT5 mới, hoặc để trống trường build.MT5 auto-updated to another build: update the expected build, repackage with a fresh MT5, or clear the build field. |
| Đã deploy nhưng balance / equity hiện "—"Deployed but balance / equity shows "—" | Chờ 10–30 s. Sau đó qua VNC kiểm EA đã gắn chart, tab Experts không lỗi, WebRequest có URL fxconsole, và secret của AccountStatusUpdater không còn REPLACE_ME (nếu còn: injection chưa cấu hình hoặc key không có trong .set).Wait 10–30 s. Then over VNC check the EA is on the chart, the Experts tab shows no errors, WebRequest lists fxconsole's URL, and the AccountStatusUpdater secret isn't still REPLACE_ME (if it is: no injection configured, or the key is missing from the .set). |
| Tài khoản "unmanaged" ma vẫn hiện runningGhost "unmanaged" accounts still shown running | Agent trước phase8 không gửi logins[] qua stream nên account_logins đứng im; nâng cấp agent.Pre-phase8 agents don't send logins[] over the stream, so account_logins froze; upgrade the agent. |
Ghi chú vận hànhOperational notes
- Hai file log cạnh exe:
heartbeat-agent.log(heartbeat, broker stream, IPC, supervisor) vàcmd-agent.log(lệnh, tải payload, relaunch, LiveUpdate). Mỗi file xoay khi vượt 5 MB thành.log.1(giữ một bản), tổng khoảng 20 MB cho hai agent. Thêmupgrade.logvàstunnel\stunnel.log. - Kiểm tra nhanh sau reboot:
- Two log files next to the exes:
heartbeat-agent.log(heartbeats, broker stream, IPC, supervisor) andcmd-agent.log(commands, payload fetches, relaunch, LiveUpdate). Each rotates past 5 MB to.log.1(one backup), about 20 MB total for both agents. Plusupgrade.logandstunnel\stunnel.log. - Quick check after a reboot:
tasklist | findstr /I "HeartbeatAgent CmdAgent stunnel"
Get-Content C:\VpsAgent\heartbeat-agent.log -Tail 20
# Supervisor: spawned CmdAgent pid=…
# BROKER: TCP connected (TLS via stunnel) — sending HELLO
# IPC: CmdAgent READY cmd_v=1.3.2-phase9
# BROKER: HELLO ok — stream healthy
# HB via broker stream cpu=… logins=…
Get-Content C:\VpsAgent\cmd-agent.log -Tail 10
# Starting CmdAgent 1.3.2-phase9 -- mt5_root=C:\fxconsole-mt5
# RelaunchExistingDeploys: done -- N candidate(s), N launched, …
docker logs fxconsole-vps-stream-broker # on the broker host: [vps=N] HELLO ok (agent_v=…)
Lộ trình (chưa làm)Roadmap (not implemented)
Theo README.html gốc (ngày 04/06/2026, một số mục có thể đã cũ):
- Đếm tài khoản bằng cách map tham số
/portable /config:<file>với danh sách MT5 đã biết (README gọiaccount_countlà stub 0; agent hiện đếm theo quét tiêu đề cửa sổ). - WebSocket theo từng user để người thường thấy
/deploymentscập nhật realtime. - Nút xoay secret không cần xoá + tạo lại.
- Rate limit
throttle:cho route heartbeat. - Endpoint log từng VPS (agent gửi N dòng log cuối) để khỏi phải vào VNC. (Trang
/admin/vps/{id}/logsđã được README nhắc; mức độ hoàn thiện chưa xác minh.) - Watchdog cho HeartbeatAgent (hiện chỉ lên lại ở lần logon).
From the original README.html (dated 04/06/2026; some items may be stale):
- Account counting by mapping
/portable /config:<file>arguments to known MT5 instances (the README callsaccount_counta 0 stub; the agent now counts via the window-title scan). - Per-user WebSocket subscriptions so non-admins see
/deploymentsupdate live. - Secret rotation without delete + re-create.
- Rate limiting with
throttle:on the heartbeat route. - Per-VPS log endpoint (the agent ships its last N log lines) so troubleshooting doesn't need VNC. (The README already mentions
/admin/vps/{id}/logs; how complete it is is unverified.) - Watchdog for HeartbeatAgent (today it only returns at the next logon).
Bản đồ fileFile map
| Path | Vai tròPurpose |
|---|---|
monitor/vps-agent/HeartbeatAgent.au3 | Vỏ sống lâu: broker stream, HTTPS dự phòng, IPC server, giám sát CmdAgentLong-lived shell: broker stream, HTTPS fallback, IPC server, CmdAgent supervisor |
monitor/vps-agent/CmdAgent.au3 | Worker: IPC client, các lệnh, kéo payload HTTPS, LiveUpdate, WebRequestWorker: IPC client, verbs, HTTPS payload pull, LiveUpdate, WebRequest |
monitor/vps-agent/lib/ipc.au3, Json.au3 | Helper NDJSON-over-TCP và JSON dùng chungShared NDJSON-over-TCP and JSON helpers |
monitor/vps-agent/bootstrap-fresh-vm.ps1 | Chuẩn bị Windows mới một lầnOne-time prep for a fresh Windows install |
monitor/vps-agent/prepare-vm.ps1 | Cài đặt (AutoLogon prep, stunnel, TightVNC, Startup) + zero-touch initInstaller (AutoLogon prep, stunnel, TightVNC, Startup) + zero-touch init |
monitor/vps-agent/upgrade.ps1 | Tự nâng cấpSelf-upgrade |
monitor/vps-agent/vps-agent.ini.init-template | Template zero-touch cho image vàng (README nhắc thêm vps-agent.ini.example cho luồng thủ công; file này không có trong thư mục hiện tại)Zero-touch template for the golden image (the README also mentions vps-agent.ini.example for the manual flow; that file isn't in the folder now) |
monitor/vps-agent/HEADLESS_VM_SETUP.md, DEPLOY_FEATURE_PLAN.md, DEPLOYMENT_GUIDE.html | Tài liệu gốc: VM headless (tiếng Việt, thời VpsAgent.exe), thiết kế và hướng dẫn deployOriginal docs: headless VM (Vietnamese, VpsAgent.exe era), deploy design and guide |
monitor/vps-agent/vantage_sample/ | Thư mục MT5 portable mẫu dùng làm nền đóng gói (có thể chứa dữ liệu tài khoản: không chia sẻ)Sample MT5 portable used as a packaging base (may contain account data: don't share) |
monitor/fxconsole/app/Http/Controllers/Api/VpsApiController.php | POST /api/vps/heartbeat, GET /api/vps/cmd/{id}/payload |
monitor/fxconsole/app/Http/Controllers/Api/AgentInitController.php | POST /api/agent/init-config |
monitor/fxconsole/app/Http/Controllers/VpsController.php | Trang Inertia, CRUD admin, upgrade-agent, remote-sessionsInertia pages, admin CRUD, upgrade-agent, remote-sessions |
monitor/fxconsole/app/Models/Vps.php | Model (observer hot-reload interval)Model (interval hot-reload observer) |
monitor/fxconsole/routes/api.php, routes/web.php | Route API agent; /vps, /admin/vps*, /admin/agent-releases, /deploymentsAgent API routes; /vps, /admin/vps*, /admin/agent-releases, /deployments |
monitor/fxconsole/resources/js/Pages/Vps/Index.tsx, Show.tsx | Giao diện danh sách và chi tiết VPSVPS list and detail UI |
monitor/VpsStreamBroker/ | Broker TLS phía server (xem Các broker realtime)Server-side TLS broker (see Realtime brokers) |
DEPLOY/README.txt ở gốc repo không liên quan tới agent: nó mô tả các file .set H4-origin (mult 1.5, Scale1.5x, TrueScale1.5x, tháng 7/2026) cho EA, là config lịch sử. Config ổn định hiện tại là pass58: xem Config ổn định.
DEPLOY/README.txt at the repo root is not about the agent: it describes the H4-origin EA .set files (mult 1.5, Scale1.5x, TrueScale1.5x, July 2026), which are historical configs. The current stable config is pass58: see Stable config.