Bắt đầuStart here

Hướng dẫn deployDeployment guide

Dựng mới và cập nhật toàn bộ hệ thống: stack fxconsole, bốn broker, cổng firewall, chứng chỉ, terminal MT5, vps-agent, cùng cách kiểm tra, rollback và xử lý sự cố. Setting up and updating the whole system: the fxconsole stack, the four brokers, firewall ports, certificates, MT5 terminals and vps-agent, plus how to verify, roll back and troubleshoot.

  • Cập nhậtUpdated 28/09/2026
  • NguồnSource deploy.sh
  • monitor/*/docker-compose.yml
  • monitor/*/.env.example
  • monitor/EaLinkBroker/README.md
  • monitor/VpsStreamBroker/README.md
  • monitor/claude-cli/README.md
  • monitor/vps-agent/README.html
Không bao giờNever
  • Chạy docker compose down -v ở monitor/fxconsole: xoá volume timescale_data (mất toàn bộ lịch sử OHLC) và claude_creds / claude_config (mất đăng nhập subscription).
  • Đổi APP_KEY của fxconsole đã chạy: mọi cột mã hoá (vpses.vnc_password, mt5_accounts.password_encrypted, cookie phiên…) không giải mã được nữa.
  • Dán secret vào tài liệu, commit .env hay .set có token. Trang này chỉ ghi tên biến.
  • Run docker compose down -v in monitor/fxconsole: it deletes the timescale_data volume (all OHLC history) and claude_creds / claude_config (the subscription login).
  • Change the APP_KEY of a running fxconsole: every encrypted column (vpses.vnc_password, mt5_accounts.password_encrypted, session cookies…) becomes undecryptable.
  • Paste secrets into docs, or commit a .env or a .set containing a token. This page names variables only.

Cần deploy những gìWhat gets deployed

Thành phầnComponent Ở đâuWhere Cách deployHow Phiên bản hiện tạiCurrent version
fxconsole (web, app, scheduler, redis, timescale, claude-cli, guacamole)(web, app, scheduler, redis, timescale, claude-cli, guacamole)Docker host · monitor/fxconsoledeploy.shapp_version 2026.09.22.1
AccountStatusBroker, TickBroker, VpsStreamBroker, EaLinkBrokerDocker host · monitor/<Broker>deploy.shtheo commit trên mainwhatever main holds
GoldenRobber EATerminal MT5MT5 terminalCopy .ex5, gỡ rồi gắn lại EA, hoặc gói deploy của vps-agentCopy .ex5, remove and re-attach the EA, or a vps-agent deploy packageProduction 1.42 b7 · bản cũ 1.41.4 b21 · hotfix b21.1 (không deploy)Production 1.42 b7 · previous 1.41.4 b21 · hotfix b21.1 (never deployed)
Config ổn địnhStable configTerminal MT5MT5 terminalNạp .set, điền token trên terminalLoad the .set, type the token on the terminalv1.42.b7-pass58.set
AccountStatusUpdater, TickStreamerPubTerminal MT5MT5 terminalCopy .ex5 + inputCopy .ex5 + inputs1.14 · 1.04
vps-agentVPS Windowsprepare-vm.ps1 · lệnh Upgrade từ webUpgrade command from the web1.3.2-phase9
cloudflare-tmap-workerCloudflarenpm run deploy (tuỳ chọn)(optional)không dùng ở productionnot used in production

Kiến trúc, cổng và luồng dữ liệu: Kiến trúc hệ thống.

Architecture, ports and data flows: System architecture.

Điều kiện tiên quyếtPrerequisites

  • Docker host Linux có Docker Engine + plugin docker compose. Tuning Postgres trong compose giả định 8 core / 16 GB RAM / NVMe.
  • Repo clone tại ~/goldenrobber/GoldenRobber (đường dẫn mặc định của deploy.sh, đổi được bằng biến REPO), theo nhánh main. fxconsole, các broker, TickStreamer, vps-agent đều là thư mục con của repo này.
  • Mạng Docker fxconsole_default: được tạo khi stack fxconsole chạy lần đầu. Mọi broker join mạng này dạng external, nên luôn bật fxconsole trước.
  • MySQL từ xa trên host aaPanel (database trade_copier) truy cập được từ Docker host; user DB của fxconsole cũng được broker dùng.
  • DNS + reverse proxy: fxconsole.gamelau.uk trỏ về biên; openresty (aaPanel, Let's Encrypt) proxy HTTPS về fxconsole-web cổng 8080 và chuyển header X-Forwarded-Proto, X-Forwarded-Host.
  • Firewall: OVH Network Firewall + IPFire, xem checklist cổng.
  • Docker host: Linux with Docker Engine + the docker compose plugin. The Postgres tuning in the compose file assumes 8 cores / 16 GB RAM / NVMe.
  • Repo cloned at ~/goldenrobber/GoldenRobber (the deploy.sh default, overridable with the REPO variable), tracking main. fxconsole, the brokers, TickStreamer and vps-agent are all subfolders of this one repo.
  • Docker network fxconsole_default: created the first time the fxconsole stack starts. Every broker joins it as external, so always start fxconsole first.
  • Remote MySQL on the aaPanel host (database trade_copier) reachable from the Docker host; the brokers reuse fxconsole's DB user.
  • DNS + reverse proxy: fxconsole.gamelau.uk points at the edge; openresty (aaPanel, Let's Encrypt) proxies HTTPS to fxconsole-web on port 8080 and forwards X-Forwarded-Proto, X-Forwarded-Host.
  • Firewall: OVH Network Firewall + IPFire, see the port checklist.
mkdir -p ~/goldenrobber && cd ~/goldenrobber
git clone <repo-url> GoldenRobber
cd GoldenRobber && git checkout main

Cài đặt lần đầuFirst-time setup

Làm theo đúng thứ tự: fxconsole → cấu hình /admin/settings → các broker → firewall → terminal. Sau lần đầu, mọi cập nhật chỉ cần deploy.sh.

Follow this order: fxconsole → /admin/settings → brokers → firewall → terminals. After the first time, every update is just deploy.sh.

fxconsolefxconsole

  1. Tạo file .env từ mẫu và khoá quyền:Create .env from the example and lock its permissions:
    cd ~/goldenrobber/GoldenRobber/monitor/fxconsole
    cp .env.example .env
    chmod 600 .env
  2. Điền các biến trong bảng dưới (chỉ tên; giá trị lấy từ nơi ghi ở cột phải).Fill the variables in the table below (names only; take values from where the right-hand column says).
  3. Khởi động stack (tạo luôn mạng fxconsole_default):Start the stack (this also creates the fxconsole_default network):
    docker compose up -d --build
    docker compose logs -f app
    Container app tự: tạo thư mục storage + chmod, composer install/update và npm ci/install khi manifest mới hơn, npm run build, php artisan key:generate --force chỉ khi .env chưa có APP_KEY=base64:, php artisan migrate --force, php artisan view:clear, rồi php-fpm -F. scheduler chờ vendor/autoload.php, chạy schedule:clear-cache rồi schedule:work. The app container: creates storage dirs + chmod, runs composer install/update and npm ci/install when manifests are newer, npm run build, php artisan key:generate --force only if .env has no APP_KEY=base64:, php artisan migrate --force, php artisan view:clear, then php-fpm -F. scheduler waits for vendor/autoload.php, runs schedule:clear-cache, then schedule:work.
  4. Sao lưu .env (đã có APP_KEY) ra nơi an toàn.Back up .env (now holding APP_KEY) somewhere safe.
  5. Đăng nhập admin, mở /admin/settings: kiểm tra app_version, điền EALinkBroker Secret Key (settings.broker_internal_secret), secret admin firehose (broker_admin_secret), VpsStreamBroker hostname / port, nhịp hb_interval_secs / stream_cadence_ms, Guacamole, token khởi tạo VPS. Giá trị trong DB thắng giá trị .env.Log in as admin, open /admin/settings: check app_version, fill EALinkBroker Secret Key (settings.broker_internal_secret), the admin firehose secret (broker_admin_secret), VpsStreamBroker hostname / port, the hb_interval_secs / stream_cadence_ms cadences, Guacamole, the VPS bootstrap token. DB values win over .env.
  6. Đăng ký EA product: /admin/easupported → Thêm EA → slug (vd goldenrobber) → secret token tự sinh. URL https://fxconsole.gamelau.uk/easupported/goldenrobber đi vào InpCloudMyApiDomain, token đi vào InpCloudBearerToken (gõ trên terminal, không commit).Register the EA product: /admin/easupported → Add EA → slug (e.g. goldenrobber) → the secret token is generated. The URL https://fxconsole.gamelau.uk/easupported/goldenrobber goes into InpCloudMyApiDomain, the token into InpCloudBearerToken (typed on the terminal, never committed).
Biến trong monitor/fxconsole/.envVariable in monitor/fxconsole/.env Dùng cho / lấy giá trị ở đâuUsed for / where the value comes from
APP_NAME, APP_ENV, APP_DEBUGProduction: tắt debug. Lưu ý: nếu không đặt REDIS_PREFIX, tiền tố Redis = slug(APP_NAME)-database-; mọi broker mặc định laravel-database-, nên đổi APP_NAME thì phải sửa REDIS_PREFIX ở broker.Production: debug off. Note: without REDIS_PREFIX, the Redis prefix = slug(APP_NAME)-database-; every broker defaults to laravel-database-, so renaming APP_NAME means updating REDIS_PREFIX on the brokers.
APP_KEYĐể trống lần đầu, container tự tạo. Không bao giờ đổi sau đó.Leave empty the first time; the container generates it. Never change it afterwards.
APP_URL, TRUSTED_PROXIESURL https công khai; TRUSTED_PROXIES = IP proxy hoặc * để Laravel tin X-Forwarded-Proto.Public https URL; TRUSTED_PROXIES = proxy IPs or * so Laravel trusts X-Forwarded-Proto.
APP_TIMEZONE, APP_DATETIME_FORMAT, APP_LOCALEHiển thị. Container dùng TZ=Asia/Ho_Chi_Minh.Display. Containers run with TZ=Asia/Ho_Chi_Minh.
DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORDMySQL từ xa trên aaPanel (trade_copier). deploy.sh copy sang .env của broker.Remote MySQL on aaPanel (trade_copier). deploy.sh copies them into the brokers' .env.
TIMESCALE_HOST, TIMESCALE_PORT, TIMESCALE_DATABASE, TIMESCALE_USERNAME, TIMESCALE_PASSWORDService timescale đọc cùng file (mặc định DB fxconsole_ts, user fxconsole). Mật khẩu phải khớp lúc volume được khởi tạo.The timescale service reads the same file (default DB fxconsole_ts, user fxconsole). The password must match what the volume was initialised with.
REDIS_CLIENT, REDIS_HOST, REDIS_PORT, REDIS_PASSWORDREDIS_HOST=redis (service trong compose, không đặt mật khẩu).REDIS_HOST=redis (compose service, no password configured).
SESSION_*, CACHE_STORE, QUEUE_CONNECTION, FILESYSTEM_DISK, BROADCAST_CONNECTIONGiữ như mẫu trừ khi có lý do.Keep the example values unless there is a reason.
MAIL_*SMTP Mailjet: MAIL_USERNAME = API key, MAIL_PASSWORD = secret key của Mailjet.Mailjet SMTP: MAIL_USERNAME = API key, MAIL_PASSWORD = Mailjet secret key.
AWS_*Chỉ cần khi dùng disk S3.Only needed for an S3 disk.
EA_API_BEARERBearer của /api/account-status và backfill OHLC; = InpApiBearer (AccountStatusUpdater) và InpFxconsoleBearer (TickStreamerPub). Setting DB ea_api_bearer ghi đè.Bearer for /api/account-status and OHLC backfill; = InpApiBearer (AccountStatusUpdater) and InpFxconsoleBearer (TickStreamerPub). The DB setting ea_api_bearer overrides it.
TMAP_SECRET_KEYBearer của URL TMap kiểu cũ /api/tmap/* và secret của Cloudflare worker. URL per-EA /easupported/{slug} dùng easupported.secret_token thay thế.Bearer for the legacy /api/tmap/* TMap URL and the Cloudflare worker secret. The per-EA /easupported/{slug} URL uses easupported.secret_token instead.
BROKER_STREAM_SECRET= BROKER_SECRET trong monitor/AccountStatusBroker/.env = InpBrokerSecret của EA. Hiện read-only trên Settings để copy.= BROKER_SECRET in monitor/AccountStatusBroker/.env = the EA's InpBrokerSecret. Shown read-only on Settings for copying.
HB_INTERVAL_SECS_DEFAULT, STREAM_CADENCE_MS_DEFAULTGiá trị khởi động nguội; nguồn chân lý là /admin/settings.Cold-start defaults; /admin/settings is the source of truth.
GUAC_JSON_SECRET_KEYKhoá AES 32 hex (openssl rand -hex 16). Service guacamole đọc cùng giá trị làm JSON_SECRET_KEY.32-hex AES key (openssl rand -hex 16). The guacamole service reads the same value as JSON_SECRET_KEY.
GUAC_PUBLIC_URLURL https công khai của Guacamole, không có / cuối. Rỗng = nút Connect tắt. DB ghi đè.Public https URL of Guacamole, no trailing /. Empty = Connect buttons disabled. DB overrides.
VPS_INIT_BOOTSTRAP_TOKENopenssl rand -hex 32; bake vào vps-agent.ini.init-template. Rỗng = /api/agent/init-config trả 503.openssl rand -hex 32; baked into vps-agent.ini.init-template. Empty = /api/agent/init-config returns 503.
VPS_BROKER_HOST, VPS_BROKER_PORT, VPS_BROKER_URLGiá trị gieo cho "VpsStreamBroker hostname / port" trên Settings. Host phải khớp CERT_HOST của VpsStreamBroker. VPS_BROKER_URL rỗng = tự suy ra tls://host:port.Seed for "VpsStreamBroker hostname / port" on Settings. The host must match VpsStreamBroker's CERT_HOST. Empty VPS_BROKER_URL = derived as tls://host:port.
BROKER_ADMIN_SECRETDự phòng khởi động cho token firehose admin; giá trị sống ở settings.broker_admin_secret.Bootstrap fallback for the admin firehose token; the live value is settings.broker_admin_secret.
BROKER_INTERNAL_SECRETDự phòng khởi động cho header X-Broker-Secret; giá trị sống là "EALinkBroker Secret Key" (settings.broker_internal_secret).Bootstrap fallback for the X-Broker-Secret header; the live value is "EALinkBroker Secret Key" (settings.broker_internal_secret).
DEFAULT_HEARTBEAT_INTERVAL, STALENESS_MULTIPLIERHeartbeat mặc định cho VPS mới; hệ số phát hiện "lost" trên dashboard.Default heartbeat for new VPS rows; the dashboard "lost" detection multiplier.
EA_DOWNLOAD_URL, FAVICON_URLTuỳ chọn.Optional.

Các brokerBrokers

deploy.sh lo phần lớn: trước khi docker compose up mỗi broker, hàm ensure_env

  1. chưa có .env → tạo từ .env.example, mọi giá trị giữ chỗ change_me… bị để trống (broker không bao giờ chạy với secret đoán được), chmod 600, và in tên các biến cần điền;
  2. nếu .env.example có DB_HOST (AccountStatusBroker, VpsStreamBroker, EaLinkBroker) → điền DB_* từ monitor/fxconsole/.env (DB_DATABASE → DB_NAME, DB_USERNAME → DB_USER). File mới: ghi đè giá trị mẫu. File đã có: chỉ điền ô trống hoặc thiếu, không bao giờ ghi đè.

Sau đó mở từng file được báo, điền ô còn trống, rồi cd monitor/<Broker> && docker compose up -d. Muốn làm tay: cp .env.example .env && chmod 600 .env, rồi sửa.

deploy.sh does most of it: before each broker's docker compose up, ensure_env

  1. no .env yet → creates it from .env.example, leaving every change_me… placeholder empty (a broker never boots with a guessable secret), chmod 600, and prints the names still to fill;
  2. if .env.example has DB_HOST (AccountStatusBroker, VpsStreamBroker, EaLinkBroker) → fills DB_* from monitor/fxconsole/.env (DB_DATABASE → DB_NAME, DB_USERNAME → DB_USER). New file: replaces the example values. Existing file: fills only empty or missing keys, never overwrites.

Then open each reported file, fill the blanks, and run cd monitor/<Broker> && docker compose up -d. By hand: cp .env.example .env && chmod 600 .env, then edit.

Broker Biến cần cóVariables to set Giá trị lấy từValue comes from
TickBrokerTICK_BROKER_SECRET REQUIRED, REDIS_URL, CERT_HOSTSecret = InpSharedSecret của TickStreamerPub (rỗng → FATAL). REDIS_URL mặc định redis://fxconsole-redis:6379. CERT_HOST = InpBrokerHost của EA (mặc định compose fxconsole.gamelau.uk). Không có DB_*.Secret = TickStreamerPub's InpSharedSecret (empty → FATAL). REDIS_URL defaults to redis://fxconsole-redis:6379. CERT_HOST = the EA's InpBrokerHost (compose default fxconsole.gamelau.uk). No DB_*.
AccountStatusBrokerBROKER_SECRET REQUIRED, BROKER_ADMIN_SECRET, DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD, REDIS_URL, REDIS_PREFIX, CERT_HOST, HB_INTERVAL_SECS, STREAM_CADENCE_MSBROKER_SECRET = BROKER_STREAM_SECRET của fxconsole = InpBrokerSecret (rỗng → FATAL). BROKER_ADMIN_SECRET chỉ là dự phòng cuối. DB_* tuỳ chọn nhưng nên có (deploy.sh điền) để đọc broker_admin_secret, hb_interval_secs, stream_cadence_ms từ bảng settings. HB_INTERVAL_SECS 15 / STREAM_CADENCE_MS 900 là mặc định.BROKER_SECRET = fxconsole's BROKER_STREAM_SECRET = InpBrokerSecret (empty → FATAL). BROKER_ADMIN_SECRET is only the last fallback. DB_* optional but recommended (deploy.sh fills it) to read broker_admin_secret, hb_interval_secs, stream_cadence_ms from the settings table. HB_INTERVAL_SECS 15 / STREAM_CADENCE_MS 900 are the defaults.
VpsStreamBrokerDB_* REQUIRED, CERT_HOST, BROKER_INTERNAL_URL, BROKER_INTERNAL_SECRET, BROKER_INTERNAL_TIMEOUT_MS, BROKER_ADMIN_SECRET, REDIS_URL, REDIS_PREFIX, PING_INTERVAL, PING_TIMEOUT, HEARTBEAT_TTL, BROKER_DEBUGDB_* bắt buộc (đọc vpses.secret_key, ghi vps_commands, vpses.account_logins). CERT_HOST phải khớp hostname stunnel kiểm tra (= "VpsStreamBroker hostname" trên Settings). BROKER_INTERNAL_URL = http://fxconsole-web (nginx cổng 80 nội bộ, không phải 8080, không phải fxconsole-app). Secret: DB → Redis → env. PING_INTERVAL 30 / PING_TIMEOUT 10 / HEARTBEAT_TTL 15 mặc định.DB_* required (reads vpses.secret_key, writes vps_commands, vpses.account_logins). CERT_HOST must match the hostname stunnel checks (= "VpsStreamBroker hostname" on Settings). BROKER_INTERNAL_URL = http://fxconsole-web (nginx internal port 80, not 8080, not fxconsole-app). Secrets: DB → Redis → env. Defaults PING_INTERVAL 30 / PING_TIMEOUT 10 / HEARTBEAT_TTL 15.
EaLinkBrokerDB_* NEEDED, BROKER_INTERNAL_URL, BROKER_INTERNAL_SECRET, BROKER_INTERNAL_TIMEOUT_MS, REDIS_URL, REDIS_PREFIX, CERT_HOST, HB_TIMEOUT_SEC, HELLO_GRACE_MS, KEY_CACHE_SEC, BROKER_DEBUG, TZDB_* để đọc settings.broker_internal_secret thẳng từ MySQL; thiếu thì sau deploy hoặc restart Redis mọi EA dính auth_unavailable. BROKER_INTERNAL_SECRET là dự phòng cuối, giá trị phải bằng "EALinkBroker Secret Key" trên /admin/settings. CERT_HOST chỉ mang tính thông tin (MQL5 không verify). Mặc định HB_TIMEOUT_SEC 60 / HELLO_GRACE_MS 5000 / KEY_CACHE_SEC 60 / timeout 3000 ms.DB_* to read settings.broker_internal_secret straight from MySQL; without it, every EA hits auth_unavailable after a deploy or Redis restart. BROKER_INTERNAL_SECRET is the last fallback and must equal "EALinkBroker Secret Key" on /admin/settings. CERT_HOST is informational only (MQL5 does not verify). Defaults HB_TIMEOUT_SEC 60 / HELLO_GRACE_MS 5000 / KEY_CACHE_SEC 60 / timeout 3000 ms.
Thứ tự đọc secret của broker (commit cb272d5)Broker secret read order (commit cb272d5)

Bảng settings MySQL → Redis laravel-database-app_config:<key> → biến .env, cache 30 s; DB lỗi hoặc chậm quá 2 s thì rơi xuống Redis/env. Lý do: Redis của fxconsole không persistence và mirror chỉ được ghi khi admin mở trang, nên trước đây EaLinkBroker báo auth_unavailable sau mỗi lần deploy.

MySQL settings table → Redis laravel-database-app_config:<key> → the .env variable, 30 s cache; if the DB errors or takes over 2 s, it falls back to Redis/env. Why: fxconsole's Redis has no persistence and the mirror is only written when an admin opens a page, so EaLinkBroker used to report auth_unavailable after every deploy.

Chứng chỉ VpsStreamBroker cho fxconsoleVpsStreamBroker certificate for fxconsole

stunnel trên VPS verify broker (verify = 2, checkHost, CAfile), nên fxconsole phải trao CA của broker qua GET /api/agent/broker-config. Compose của fxconsole mount ../VpsStreamBroker/certs:/broker-certs:ro vào fxconsole-app, nên chỉ cần bật VpsStreamBroker một lần (sinh cert) là tự nối. Cách cũ vẫn dùng được khi cần import tay:

stunnel on the VPS verifies the broker (verify = 2, checkHost, CAfile), so fxconsole must hand out the broker's CA via GET /api/agent/broker-config. fxconsole's compose mounts ../VpsStreamBroker/certs:/broker-certs:ro into fxconsole-app, so starting VpsStreamBroker once (which generates the cert) wires it up. The older manual import still works:

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

claude-cli (một lần)claude-cli (one time)

Sidecar được build tự động cùng fxconsole. Lần chạy đầu (hoặc khi refresh token hết hạn sau vài tuần/tháng) phải đăng nhập subscription tương tác, không script được:

The sidecar builds automatically with fxconsole. The first run (or when the refresh token expires after weeks/months) needs an interactive subscription login that cannot be scripted:

cd ~/goldenrobber/GoldenRobber/monitor/fxconsole
docker compose exec -it claude-cli claude login
# open the printed URL, approve, paste the code back

# back up the OAuth creds (treat the file as a secret)
docker compose exec claude-cli sh -c 'tar czf - -C /home/node .claude .config' > claude-creds-backup.tgz

Về sau có thể đăng nhập lại ngay trên /admin/analysis (banner đỏ "CLI cần đăng nhập lại" → Re-login). Muốn khoá phiên bản CLI: docker compose build --build-arg CLAUDE_CODE_VERSION=<x.y.z> claude-cli. Lưu ý vùng xám ToS khi chạy subscription từ backend 24/7: giữ lưu lượng thấp. Chi tiết: claude-cli.

Later re-logins can be done from /admin/analysis (red "CLI cần đăng nhập lại" banner → Re-login). To pin the CLI version: docker compose build --build-arg CLAUDE_CODE_VERSION=<x.y.z> claude-cli. Mind the ToS grey area of driving a subscription from a 24/7 backend: keep volume low. Details: claude-cli.

Cloudflare TMap worker (tuỳ chọn)Cloudflare TMap worker (optional)

Config ổn định để InpCloudCfDomain trống nên production không cần bước này. Nếu muốn backup TMap thứ hai:

The stable config leaves InpCloudCfDomain empty, so production does not need this. For a second TMap backup:

cd cloudflare-tmap-worker
npm install
wrangler login
npm run db:create      # copy database_id into wrangler.toml
npm run db:migrate
npm run secret:set     # enter TMAP_SECRET_KEY
npm run deploy         # → https://gr-tmap.<account>.workers.dev → InpCloudCfDomain

Thêm domain worker vào Allow WebRequest của terminal. Chi tiết: Cloudflare TMap worker.

Add the worker domain to the terminal's Allow WebRequest list. Details: Cloudflare TMap worker.

Deploy thường ngày với deploy.shRoutine deploy with deploy.sh

cd ~/goldenrobber/GoldenRobber
bash deploy.sh
Dòng trong deploy.shLine in deploy.sh Làm gìWhat it does
set -eMột lệnh lỗi (vd git pull xung đột) là dừng cả script.Any failing command (e.g. a git pull conflict) stops the whole script.
REPO="${REPO:-$HOME/goldenrobber/GoldenRobber}"Đường dẫn repo; test có thể source file với REPO khác.Repo path; tests can source the file with another REPO.
git restore .Bỏ các thay đổi trên file đã track mà container chạm vào mỗi lần boot (composer.lock, .gitkeep, .gitignore) để git pull không báo "local changes would be overwritten". Không đụng file chưa track (thư mục upload public/theme-bg, broker-logos, packages, dữ liệu storage) và mọi .env. Vì vậy không sửa tay file đã track trên server: sẽ mất ở lần deploy sau.Discards changes to tracked files that containers touch on every boot (composer.lock, .gitkeep, .gitignore) so git pull never fails with "local changes would be overwritten". Untracked files (upload dirs public/theme-bg, broker-logos, packages, storage data) and every .env are left alone. So never hand-edit tracked files on the server: the next deploy wipes them.
git checkout main · git pull origin mainProduction luôn theo main.Production always tracks main.
cd monitor/fxconsole/; docker compose down; docker compose up -d --buildDựng lại fxconsole, gồm cả sidecar claude-cli (build context ../claude-cli). Migration tự chạy khi app khởi động. down thường giữ mọi named volume.Rebuilds fxconsole, including the claude-cli sidecar (build context ../claude-cli). Migrations run when app boots. A plain down keeps every named volume.
compose_up AccountStatusBroker · TickBroker · VpsStreamBroker · EaLinkBrokerMỗi broker: ensure_env (tạo .env / điền DB_*) → docker compose down → docker compose up -d --build.Each broker: ensure_env (create .env / fill DB_*) → docker compose down → docker compose up -d --build.
#docker system prune -afĐang comment, không chạy.Commented out, never runs.
echo "== Deploy done =="In ghi chú .env của broker (nếu có) và nhắc lệnh claude login.Prints broker .env notes (if any) and the claude login reminder.
flowchart TD
  A["git restore ."] --> B["git checkout main"]
  B --> C["git pull origin main"]
  C --> D["fxconsole: down, up -d --build"]
  D --> E["AccountStatusBroker: ensure_env, down, up -d --build"]
  E --> F["TickBroker: ensure_env, down, up -d --build"]
  F --> G["VpsStreamBroker: ensure_env, down, up -d --build"]
  G --> H["EaLinkBroker: ensure_env, down, up -d --build"]
  H --> I["== Deploy done == + .env notes + claude login reminder"]

fxconsole luôn đi trước để mạng fxconsole_default và fxconsole-redis tồn tại khi broker khởi động. fxconsole always goes first so fxconsole_default and fxconsole-redis exist when the brokers start.

Các dòng ghi chú .env có thể xuất hiện (chuỗi in ra bằng tiếng Việt):

The .env note lines you may see (the script prints them in Vietnamese):

== .env của broker ==
  TẠO MỚI  monitor/<Broker>/.env  — cần điền: <KEY1> <KEY2>
  ĐIỀN DB  monitor/<Broker>/.env: DB_HOST DB_PORT DB_NAME DB_USER DB_PASSWORD  (lấy từ monitor/fxconsole/.env)
  THIẾU DB monitor/<Broker>/.env: DB_PASSWORD trống và fxconsole/.env không có giá trị
  → Mở các file trên, điền ô còn trống (vd secret), rồi áp dụng lại cho service đó:
      cd ~/goldenrobber/GoldenRobber/monitor/<Broker> && docker compose up -d
Lần đầu chạy một deploy.sh mớiFirst run of a new deploy.sh

Toàn bộ script được bọc trong main() để bash đọc hết file trước khi git pull ghi đè deploy.sh; bản mới chỉ có hiệu lực ở lần chạy sau. Khi một commit vừa đổi deploy.sh (vd commit 15b70c3 thêm tự tạo .env broker), hãy chạy git pull trước rồi mới bash deploy.sh, để logic mới chạy ngay lần này.

The whole script is wrapped in main() so bash has parsed it fully before git pull rewrites deploy.sh; a new version only takes effect on the next run. When a commit has just changed deploy.sh (e.g. commit 15b70c3 added auto-created broker .env), run git pull first, then bash deploy.sh, so the new logic runs this time.

cd ~/goldenrobber/GoldenRobber
git pull origin main
bash deploy.sh
  • Gián đoạn: mỗi stack bị down rồi up, nên có vài giây đến vài phút (npm build của fxconsole) không phục vụ. EA vẫn giao dịch (mất server không đổi hành vi EA); EA Link, AccountStatusUpdater, TickStreamerPub và agent tự kết nối lại với backoff; trong lúc đó EA Link rơi về heartbeat HTTP.
  • Chỉ cập nhật một broker: cd ~/goldenrobber/GoldenRobber/monitor/<Broker> && docker compose up -d --build. Chỉ đổi .env: docker compose up -d (compose tạo lại container với env mới).
  • Xác nhận bản đã lên: /admin/settings hiện app_version (hiện tại 2026.09.22.1); git log -1 --oneline trên server.
  • Downtime: each stack goes down then up, so expect seconds to minutes (fxconsole's npm build) without service. EAs keep trading (losing the server does not change EA behaviour); EA Link, AccountStatusUpdater, TickStreamerPub and the agents reconnect with backoff; meanwhile EA Link falls back to the HTTP heartbeat.
  • Update one broker only: cd ~/goldenrobber/GoldenRobber/monitor/<Broker> && docker compose up -d --build. Only .env changed: docker compose up -d (compose recreates the container with the new env).
  • Confirm what went live: /admin/settings shows app_version (currently 2026.09.22.1); git log -1 --oneline on the server.

Checklist firewall và port-forwardFirewall and port-forward checklist

CổngPort Service OVH Network Firewall IPFire Ai kết nốiWho connects
443/tcpopenresty (aaPanel)ACCEPTtheo thiết lập biên hiện tạiper the current edge setupTrình duyệt, mọi EA (WebRequest), agent, TickStreamerPubBrowsers, every EA (WebRequest), agents, TickStreamerPub
9600/tcpTickBroker TLSACCEPTWAN:9600 → <docker-host-LAN-IP>:9600TickStreamerPub
9602/tcpAccountStatusBroker TLSACCEPTWAN:9602 → <docker-host-LAN-IP>:9602AccountStatusUpdater (TCP / HYBRID)AccountStatusUpdater (TCP / HYBRID)
9605/tcpVpsStreamBroker TLSACCEPTWAN:9605 → <docker-host-LAN-IP>:9605stunnel trên mọi VPSstunnel on every VPS
9607/tcpEaLinkBroker TLSACCEPTWAN:9607 → <docker-host-LAN-IP>:9607GoldenRobber 1.42+
9601, 9603WS của Tick / AccountStatusTick / AccountStatus WSNONOCompose publish trên host, nhưng trình duyệt đi qua /ws, /status-ws; không cần forward.Published on the host by compose, but browsers use /ws, /status-ws; no forward needed.
9606WS của VpsStreamVpsStream WSNONOChỉ expose trong mạng Docker, qua /vps-ws.Only exposed on the Docker network, via /vps-ws.
8080, 8282fxconsole-web, guacamoleNONOChỉ reverse proxy truy cập.Reverse proxy only.
5432TimescaleDBBLOCKNEVERPublish mọi interface cho LAN; host có IP public thì phải chặn.Published on all interfaces for LAN use; block it if the host has a public IP.
6379, 8788, 4822, 9000redis, claude-cli, guacd, php-fpmNONOChỉ nội bộ Docker.Docker-internal only.
51820/udpwg-easy (CT 107)ALLOWtheo thiết lập VPNper the VPN setupClient WireGuard (cổng mặc định của wg-easy)WireGuard clients (wg-easy default port)

Kiểm tra từ bên ngoài sau khi mở cổng. "connection refused / reset / timeout" nghĩa là cổng chưa tới được broker, sửa firewall trước khi đi tiếp.

Test from outside after opening a port. "connection refused / reset / timeout" means the port does not reach the broker yet; fix the firewall before going further.

# Linux / Git Bash
openssl s_client -connect fxconsole.gamelau.uk:9600 -servername fxconsole.gamelau.uk
openssl s_client -connect fxconsole.gamelau.uk:9602 -servername fxconsole.gamelau.uk
openssl s_client -connect fxconsole.gamelau.uk:9605 -servername fxconsole.gamelau.uk
openssl s_client -connect fxconsole.gamelau.uk:9607 -quiet
# Windows VPS
Test-NetConnection fxconsole.gamelau.uk -Port 9605

Phía MT5: SocketConnect() chỉ chạy với host có trong Tools → Options → Expert Advisors → Allow WebRequest for listed URL, cùng danh sách mà WebRequest dùng.

MT5 side: SocketConnect() only works for hosts listed in Tools → Options → Expert Advisors → Allow WebRequest for listed URL, the same list WebRequest uses.

Chứng chỉ TLSTLS certificates

  • Phía trình duyệt và WebRequest: chứng chỉ Let's Encrypt của openresty. WebRequest của EA bắt buộc HTTPS có chứng chỉ hợp lệ; chứng chỉ tự ký báo lỗi GetLastError = 4014.
  • Broker: Dockerfile chạy node gen-cert.js "${CERT_HOST:-localhost}" && node broker.js. gen-cert.js dùng openssl tạo certs/server.key + certs/server.cert tự ký, hạn 10 năm, CN=CERT_HOST; đã có cả hai file thì bỏ qua. Thư mục monitor/<Broker>/certs được bind mount nên cert sống qua mọi lần rebuild. Compose đặt mặc định CERT_HOST=fxconsole.gamelau.uk.
  • Nội bộ: nginx của fxconsole proxy tới cổng WS của broker với proxy_ssl_verify off.
  • Browser and WebRequest side: openresty's Let's Encrypt certificate. The EA's WebRequest requires HTTPS with a valid certificate; a self-signed one fails with GetLastError = 4014.
  • Brokers: the Dockerfile runs node gen-cert.js "${CERT_HOST:-localhost}" && node broker.js. gen-cert.js uses openssl to create a self-signed certs/server.key + certs/server.cert, valid 10 years, CN=CERT_HOST; if both files exist it skips. monitor/<Broker>/certs is bind-mounted, so the cert survives every rebuild. Compose defaults CERT_HOST=fxconsole.gamelau.uk.
  • Internal: fxconsole's nginx proxies to the brokers' WS ports with proxy_ssl_verify off.
Broker Ai kiểm tra certWho checks the cert CERT_HOST phải bằngCERT_HOST must equal
TickBrokerMT5 gửi SNI; ghi chú trong compose/.env.example nói handshake bị từ chối nếu CN khácMT5 sends SNI; the compose/.env.example comments say the handshake is rejected if the CN differsInpBrokerHost (TickStreamerPub)
AccountStatusBrokerNhư TickBrokerSame as TickBrokerInpBrokerHost (AccountStatusUpdater)
VpsStreamBrokerstunnel verify = 2, checkHost, CAfile (chặt nhất)stunnel verify = 2, checkHost, CAfile (strictest)"VpsStreamBroker hostname" trên /admin/settings (VPS_BROKER_HOST)"VpsStreamBroker hostname" on /admin/settings (VPS_BROKER_HOST)
EaLinkBrokerKhông ai (MQL5 SocketTlsHandshake không verify)Nobody (MQL5 SocketTlsHandshake does not verify)Chỉ để thông tin; vẫn nên đặt đúng hostnameInformational; still set the real hostname

Tạo lại cert (đổi CN, xoay khoá). Sao lưu thư mục cũ trước:

Regenerate a certificate (CN change, key rotation). Back up the old folder first:

cd ~/goldenrobber/GoldenRobber/monitor/<Broker>
docker compose down
cp -a certs "certs.bak-$(date +%F)"
rm -rf certs/
docker compose up -d      # regenerates with the current CERT_HOST

Riêng VpsStreamBroker, sau khi xoay cert: fxconsole tự thấy cert mới qua mount /broker-certs (hoặc chạy lại vps-stream-broker:cert-import), rồi chạy lại prepare-vm.ps1 trên mọi VPS để lấy CA mới và ghi lại stunnel.conf. Nếu CERT_HOST đổi thì sửa luôn VPS_BROKER_HOST, "VpsStreamBroker hostname" trên /admin/settings và bản ghi DNS.

For VpsStreamBroker, after rotating: fxconsole sees the new cert through the /broker-certs mount (or re-run vps-stream-broker:cert-import), then re-run prepare-vm.ps1 on every VPS to fetch the new CA and rewrite stunnel.conf. If CERT_HOST changed, also update VPS_BROKER_HOST, "VpsStreamBroker hostname" on /admin/settings, and the DNS record.

Kiểm tra sau deployVerify after deploy

fxconsole

cd ~/goldenrobber/GoldenRobber/monitor/fxconsole
docker compose ps                         # app, web, scheduler, redis, timescale, claude-cli, guacd, guacamole: Up
docker compose logs --tail=100 app        # migrate --force ran, php-fpm started
docker compose logs --tail=50 scheduler   # schedule:work running
curl -I http://127.0.0.1:8080             # nginx answers
docker exec -it fxconsole-redis redis-cli PING   # PONG

Mở /admin/settings và xác nhận app_version (2026.09.22.1). /admin/analysis không có banner đỏ = claude-cli đã đăng nhập. timescale có healthcheck pg_isready nên docker compose ps hiện healthy.

Open /admin/settings and confirm app_version (2026.09.22.1). No red banner on /admin/analysis = claude-cli is logged in. timescale has a pg_isready healthcheck, so docker compose ps shows healthy.

Tỷ giá, hệ số chia, EA của tôi (fxconsole ≥ 2026.09.14.2)Exchange rate, money divisor, My EAs (fxconsole ≥ 2026.09.14.2)

cd ~/goldenrobber/GoldenRobber/monitor/fxconsole
docker compose exec app php artisan migrate:status | grep 2026_09_1      # 09_13 000001..000004, 09_14 000001, 09_16 000001: Ran
docker compose exec app php artisan schedule:list | grep fx:sync         # every minute
docker compose exec app php artisan fx:sync-usdt-vnd --force             # USDT/VND = … (median of 10 SELL ads)
docker compose exec app sh -c 'grep fx.usdt_vnd storage/logs/laravel.log | tail -n 5'
  1. Migration: container app tự migrate khi boot. Bốn migration ngày 2026-09-13 tạo fx_rates, thêm users.currency, mt5_accounts.is_cent (sau đó cho phép rỗng bằng ->change()) và broker_profiles.cent_servers; migration 2026_09_14_000001 chuyển hai cột này thành mt5_accounts.money_divisor và broker_profiles.server_divisors (Cent → /100, Standard → /1) rồi xoá cột cũ. Migration lỗi thì xem log app.Migrations: the app container migrates on boot. The four 2026-09-13 migrations create fx_rates and add users.currency, mt5_accounts.is_cent (then made nullable with ->change()) and broker_profiles.cent_servers; migration 2026_09_14_000001 turns those two into mt5_accounts.money_divisor and broker_profiles.server_divisors (Cent → /100, Standard → /1) and drops the old columns. If one fails, read the app log.
  2. Tỷ giá: lệnh --force in ra giá. failed — HTTP 403 / 429 = Binance chặn IP server. Trên web, nút $ cạnh nút ngôn ngữ phải có mục VND bấm được và dòng "1 USDT = … ₫".Rate: the --force run prints the rate. failed — HTTP 403 / 429 = Binance is blocking the server IP. On the web, the $ button next to the language button must offer a clickable VND option and a "1 USDT = … ₫" line.
  3. Hệ số chia: /admin/brokers → sửa broker → chọn /100 cạnh các server cent (/10 nếu broker báo ×10). Trên /deployments, cột Hệ số của account trên server đó hiện "/100 tự động". Ngoại lệ: chọn dòng → menu Hệ số chia.Money divisor: /admin/brokers → edit the broker → pick /100 next to the cent servers (/10 if the broker reports ×10). On /deployments, the Divisor column of accounts on that server shows "/100 auto". Exceptions: select the rows → Money divisor menu.
  4. EA của tôi: đăng nhập bằng user có account đang chạy GoldenRobber → /easupported hiện thẻ EA với đủ account. Trống thì mở /admin/easupported/{slug} bằng admin: account không có ở đó = EA chưa heartbeat tới URL này (sửa InpCloudMyApiDomain / token).My EAs: log in as a user with accounts running GoldenRobber → /easupported shows the EA card with every account. If empty, open /admin/easupported/{slug} as admin: an account missing there = the EA is not heartbeating to that URL (fix InpCloudMyApiDomain / token).

Các broker: log khởi động cần thấyBrokers: startup log lines to expect

docker logs --tail=50 fxconsole-tick-broker
docker logs --tail=50 fxconsole-account-status-broker
docker logs --tail=50 fxconsole-vps-stream-broker
docker logs --tail=50 fxconsole-ea-link-broker
Broker Dòng log mong đợiExpected log lines
Mọi broker (boot đầu / các lần sau)Every broker (first boot / later)Generating self-signed cert for "fxconsole.gamelau.uk" (10y validity)…
Certs already exist at /app/certs — skipping generation.
TickBrokerTickBroker pub TCP listening on 0.0.0.0:9600 (TLS)
TickBroker WS listening on 0.0.0.0:9601 (wss://)
AccountStatusBrokersettings DB: on (<DB_HOST>:<DB_PORT>/<DB_NAME>)
AccountStatusBroker pub TCP listening on 0.0.0.0:9602 (TLS)
AccountStatusBroker WS listening on 0.0.0.0:9603 (wss://)
Subscribed to Redis channel: report:request
VpsStreamBrokerVpsStreamBroker listening on 0.0.0.0:9605 (TLS)
VpsStreamBroker WS listening on 0.0.0.0:9606 (wss://)
Subscribed to laravel-database-vps:cmd (channels=1)
khi agent nối:when an agent connects: [vps=42] HELLO ok (agent_v=…)
EaLinkBrokersettings DB: on (<DB_HOST>:<DB_PORT>/<DB_NAME>) — broker_internal_secret read from settings table
EaLinkBroker listening on 0.0.0.0:9607 (TLS) hb_timeout=60s prefix="laravel-database-"
PSubscribed to *ea:link:cfg (subscriptions=1)
khi EA nối:when an EA connects: [ea=goldenrobber/vantage::…/21478308] connected inst=… ea=GoldenRobber ver=… ea_id=…
Dấu hiệu saiRed flags

settings DB: off (DB_HOST empty) ở EaLinkBroker nghĩa là thiếu DB_*: auth EA Link sẽ gãy sau lần restart Redis kế. FATAL: … is empty nghĩa là thiếu secret bắt buộc. Redis main error: getaddrinfo ENOTFOUND fxconsole-redis nghĩa là fxconsole chưa chạy.

settings DB: off (DB_HOST empty) on EaLinkBroker means DB_* is missing: EA Link auth will break on the next Redis restart. FATAL: … is empty means a required secret is missing. Redis main error: getaddrinfo ENOTFOUND fxconsole-redis means fxconsole is not running.

# 1. TLS + challenge from outside
openssl s_client -connect fxconsole.gamelau.uk:9607 -quiet
# → {"t":"challenge","v":1,"nonce":"…","server_t":…}
# after 5 s → {"t":"hello_err","reason":"timeout"} and the connection closes

# 2. Full auth + heartbeat with the bundled client (or inside the container:
#    docker compose exec ea-link-broker node test-client.js …)
node test-client.js --host fxconsole.gamelau.uk --port 9607 \
  --slug goldenrobber --token '<secret>' \
  --composite vantage::vantagemarkets-live-3::25938032 --magic 21478308 \
  --node ops-test --inst 1
# → hello_ok, then hb_ok every 20 s   (--key <64hex> passes sha256(token) directly)

# 3. Fire a signal from another shell
docker exec -it fxconsole-redis redis-cli PUBLISH laravel-database-ea:link:cfg \
  '{"slug":"goldenrobber","targets":[{"composite_id":"vantage::vantagemarkets-live-3::25938032","magic":"21478308"}],"rev":1}'
# client prints {"t":"cfg","rev":1} and answers cfg_ack
# broker logs: cfg rev=1 slug=goldenrobber targets=1 delivered=1

# 4. Presence
docker exec -it fxconsole-redis redis-cli HGETALL \
  'laravel-database-ea_link:presence:goldenrobber:vantage::vantagemarkets-live-3::25938032:21478308'

VpsStreamBrokerVpsStreamBroker

# heartbeat keys of connected agents (refresh every heartbeat, expire 15 s)
docker exec -it fxconsole-redis redis-cli --scan --pattern 'laravel-database-vps:agent:*'
docker exec -it fxconsole-redis redis-cli GET laravel-database-vps:agent:42:heartbeat

# fake command push (agent 42 connected → "cmd push → vps=42 cmd_id=99999 kind=test")
docker exec -it fxconsole-redis redis-cli \
  PUBLISH laravel-database-vps:cmd '{"vps_id":42,"cmd_id":99999,"kind":"test"}'

# live UI path: open /vps as admin in two tabs, Disable a VPS in one,
# the badge must flip in the other within ~100 ms
docker exec -it fxconsole-redis redis-cli SUBSCRIBE laravel-database-vps:state

Phía terminal MT5MT5 terminal side

  1. Allow WebRequest: Tools → Options → Expert Advisors → Allow WebRequest for listed URL, thêm https://fxconsole.gamelau.uk (chỉ cần origin; một dòng phủ heartbeat, TMap, /api/account-status, /api/sync-*). Socket tới broker dùng chung danh sách này, nên host của InpLinkHost / InpBrokerHost cũng phải có. Dùng Cloudflare worker thì thêm domain worker. Thiếu → WebRequest trả -1.Allow WebRequest: Tools → Options → Expert Advisors → Allow WebRequest for listed URL, add https://fxconsole.gamelau.uk (origin only; one line covers the heartbeat, TMap, /api/account-status, /api/sync-*). Broker sockets use the same list, so the InpLinkHost / InpBrokerHost hosts must be there too. Using the Cloudflare worker? Add its domain. Missing → WebRequest returns -1.
  2. Copy file .ex5 vào MQL5\Experts của terminal (đúng đường dẫn mà chart/profile tham chiếu).Copy the .ex5 into the terminal's MQL5\Experts (the path the chart/profile references).
  3. Gỡ EA khỏi chart rồi gắn lại. F7 (mở hộp thoại input) khi EA đang gắn không nạp binary mới.Remove the EA from the chart, then attach it again. F7 (the inputs dialog) on an attached EA does not load the new binary.
  4. Nếu MT5 hiện hộp thoại "Welcome to LiveUpdate": chọn Later. Restart sẽ tắt mọi EA đang chạy.If MT5 shows the "Welcome to LiveUpdate" dialog: choose Later. Restart kills every running EA.
  5. Nạp .set (bản chia sẻ trong README/configs/ có token trống), gõ InpCloudBearerToken ngay trên terminal, kiểm tra lại tab Inputs sau khi nạp (input thiếu trong .set cũ giữ giá trị cũ).Load the .set (the shareable copy in README/configs/ has a blank token), type InpCloudBearerToken on the terminal itself, and re-check the Inputs tab afterwards (inputs missing from an older .set keep stale values).
  6. Kiểm tra panel: tiêu đề có build (vd GoldenRobber v1.42 (b3), tên file không cho biết build), Server: CONNECTED (Ns ago), Link: UP fxconsole.gamelau.uk:9607 (Ns) (1.42+), dòng Node: … | LEADER.Check the panel: the title shows the build (e.g. GoldenRobber v1.42 (b3); the filename does not tell you the build), Server: CONNECTED (Ns ago), Link: UP fxconsole.gamelau.uk:9607 (Ns) (1.42+), the Node: … | LEADER line.
EA Input liên quan hạ tầngInfrastructure inputs
GoldenRobber 1.42 b3InpCloudSyncEnable=true, InpCloudMyApiDomain=https://fxconsole.gamelau.uk/easupported/goldenrobber, InpCloudBearerToken (gõ taytyped by hand), InpCloudSyncIntervalSec=10, InpCloudNodePriority=100, InpCloudHeartbeatTimeoutSec=90, InpCloudCfDomain= (trốngempty), InpLinkMode=1, InpLinkHost=fxconsole.gamelau.uk, InpLinkPort=9607
AccountStatusUpdater 1.16InpApiUrl (mặc định trong code là http://127.0.0.1:8080/api/account-status, production dùng URL https công khaicode default is http://127.0.0.1:8080/api/account-status; production uses the public https URL), InpApiBearer, InpAccountSecretKey, InpTransport, InpBrokerHost, InpBrokerPort=9602, InpBrokerSecret, InpHybridHttpIntervalSec=30
TickStreamerPub 1.04InpBrokerHost, InpBrokerPort=9600, InpSharedSecret, InpFxconsoleUrl, InpFxconsoleBearer, InpCalendarIntervalMinutes=15

Checklist rollout GoldenRobber 1.42GoldenRobber 1.42 rollout checklist

Trạng tháiStatus

Checklist viết cho lần rollout 1.42 b3 (EA Link, commit ff0e30e). Production hiện là 1.42 b7 (commit 663082f, từ 29/09/2026); các bước vẫn dùng khi nâng build 1.42, với config v1.42.b7-pass58.set. Chi tiết thay đổi: Release note 1.42 b7 · Build & release.

Written for the 1.42 b3 rollout (EA Link, commit ff0e30e). Production is now 1.42 b7 (commit 663082f, since 29/09/2026); the steps still apply when upgrading a 1.42 build, with the v1.42.b7-pass58.set config. Change details: Release note 1.42 b7 · Builds & releases.

ServerServer

  1. bash deploy.sh (fxconsole ≥ 2026.09.12.3: endpoint /api/internal/ea-link/key, notify sau Apply/Clear, badge Link, broker đọc secret từ DB).bash deploy.sh (fxconsole ≥ 2026.09.12.3: the /api/internal/ea-link/key endpoint, notify after Apply/Clear, Link badge, brokers read secrets from the DB).
  2. monitor/EaLinkBroker/.env có DB_*; log có settings DB: on và PSubscribed to *ea:link:cfg.monitor/EaLinkBroker/.env has DB_*; the log shows settings DB: on and PSubscribed to *ea:link:cfg.
  3. /admin/settings → EALinkBroker Secret Key đã có giá trị./admin/settings → EALinkBroker Secret Key is set.
  4. Cổng 9607 mở trên OVH + IPFire; openssl s_client -connect fxconsole.gamelau.uk:9607 -quiet trả challenge.Port 9607 open on OVH + IPFire; openssl s_client -connect fxconsole.gamelau.uk:9607 -quiet returns a challenge.

Terminal demoDemo terminal

  1. Copy GoldenRobber-1.42.ex5; Allow WebRequest có https://fxconsole.gamelau.uk.Copy GoldenRobber-1.42.ex5; Allow WebRequest contains https://fxconsole.gamelau.uk.
  2. Nạp v1.42.b7-pass58.set, gõ token, gỡ EA rồi gắn lại, LiveUpdate → Later.Load v1.42.b7-pass58.set, type the token, remove and re-attach the EA, LiveUpdate → Later.
  3. Panel: GoldenRobber v1.42 (b7), Server: CONNECTED, Link: UP …. Trên /admin/easupported/goldenrobber: account Online, badge Link.Panel: GoldenRobber v1.42 (b7), Server: CONNECTED, Link: UP …. On /admin/easupported/goldenrobber: account Online, Link badge.
  4. Apply một hot config vô hại cho account demo → log Experts có [EaLink] cfg rev=… đã áp trong N ms, broker log cfg rev=… delivered=1, dòng Hot Reload trên panel đổi trong ≈ 1 s. Rồi Clear config và kiểm tra EA về giá trị input.Apply a harmless hot config to the demo account → the Experts log shows [EaLink] cfg rev=… đã áp trong N ms, the broker logs cfg rev=… delivered=1, the panel's Hot Reload line changes within ≈ 1 s. Then Clear config and check the EA reverts to its inputs.
  5. Thử mất Link: docker compose stop ea-link-broker → panel Link: DOWN, retry Ns, EA vẫn nhận config qua heartbeat; docker compose start ea-link-broker → Link UP lại.Test losing the link: docker compose stop ea-link-broker → panel Link: DOWN, retry Ns, the EA still gets config via heartbeat; docker compose start ea-link-broker → Link UP again.
Manual Init = Close all (5)Manual Init = Close all (5)

Đóng mọi position của EA trên chart (symbol + magic, gồm lệnh Hedge), không hoàn tác được, chỉ node LEADER thực hiện, sau đó EA đứng yên như Pause tới khi đổi về OFF. Build khác cùng slug (b21, b21.1, b28) không hiểu giá trị 5 và giữ giá trị cũ. Khi nhiều build cùng chạy slug goldenrobber, schema trên web đổi qua lại theo account gửi heartbeat gần nhất. Không thử Close all trên tài khoản thật.

Closes every EA position on the chart (symbol + magic, Hedge orders included), cannot be undone, runs only on the LEADER node, then the EA stays idle like Pause until switched back to OFF. Other builds on the same slug (b21, b21.1, b28) do not understand value 5 and keep their previous value. With several builds on slug goldenrobber, the web schema flips according to whichever account sent the latest heartbeat. Do not test Close all on a live account.

vps-agent và gói MT5vps-agent and MT5 packages

Tóm tắt; từng bước chi tiết ở VPS agent.

Summary; step-by-step detail on VPS agent.

VPS mớiNew VPS

  1. Server sẵn sàng: VpsStreamBroker chạy, cổng 9605 mở, CA sẵn cho /api/agent/broker-config, "VpsStreamBroker hostname / port" đã điền, VPS_INIT_BOOTSTRAP_TOKEN đã đặt (nếu provisioning tự động).Server ready: VpsStreamBroker running, port 9605 open, CA available to /api/agent/broker-config, "VpsStreamBroker hostname / port" filled, VPS_INIT_BOOTSTRAP_TOKEN set (for zero-touch provisioning).
  2. Compile HeartbeatAgent.au3, CmdAgent.au3 (AutoIt 3.3.16+, chế độ GUI, thư mục lib/ cạnh source), copy vào C:\VpsAgent\ cùng vps-agent.ini (copy từ /vps) hoặc vps-agent.ini.init-template, bootstrap-fresh-vm.ps1, prepare-vm.ps1. Hoặc dùng gói vps-agent-setup-1.3.2-phase9.zip.Compile HeartbeatAgent.au3, CmdAgent.au3 (AutoIt 3.3.16+, GUI mode, lib/ next to the sources), copy into C:\VpsAgent\ with vps-agent.ini (copied from /vps) or vps-agent.ini.init-template, bootstrap-fresh-vm.ps1, prepare-vm.ps1. Or use the vps-agent-setup-1.3.2-phase9.zip package.
  3. Màn hình VM: độ phân giải 1600×900, scale 100% (mặc định của Windows), đặt ở Settings › System › Display trước khi snapshot để mọi VM clone ra giống nhau. Không đổi scale: CmdAgent điền danh sách WebRequest trong Options của MT5 bằng cách click theo toạ độ pixel cố định (mỗi dòng 18 px, tính ở scale 100%).VM display: 1600×900 resolution, 100% scale (the Windows default), set in Settings › System › Display before the snapshot so every cloned VM matches. Do not change the scale: CmdAgent fills the WebRequest list in MT5's Options by clicking fixed pixel offsets (18 px rows, measured at 100% scale).
  4. Windows mới cài, một lần mỗi OS image: powershell -ExecutionPolicy Bypass -File .\bootstrap-fresh-vm.ps1 (Administrator), rồi snapshot VM.Fresh Windows, once per OS image: powershell -ExecutionPolicy Bypass -File .\bootstrap-fresh-vm.ps1 (Administrator), then snapshot the VM.
  5. .\prepare-vm.ps1 (Administrator): chuẩn bị AutoLogon, gỡ MOTW, shortcut Startup cho HeartbeatAgent, cài stunnel + cấu hình từ /api/agent/broker-config, cài dịch vụ TightVNC. Với init = pending: gửi MAC tới /api/agent/init-config, ghi lại ini, đổi tên máy, reboot..\prepare-vm.ps1 (Administrator): AutoLogon prep, MOTW strip, Startup shortcut for HeartbeatAgent, stunnel install + config from /api/agent/broker-config, TightVNC service install. With init = pending: posts the MAC to /api/agent/init-config, rewrites the ini, renames the computer, reboots.
  6. Reboot, rồi kiểm tra: tasklist | findstr /I "HeartbeatAgent CmdAgent stunnel"; heartbeat-agent.log có BROKER: HELLO ok — stream healthy và HB via broker stream …; broker log [vps=N] HELLO ok.Reboot, then check: tasklist | findstr /I "HeartbeatAgent CmdAgent stunnel"; heartbeat-agent.log shows BROKER: HELLO ok — stream healthy and HB via broker stream …; the broker logs [vps=N] HELLO ok.

Nâng cấp agentAgent upgrade

Upload zip release trên /admin/agent-releases (vd vps-agent-upgrade-1.3.2-phase9.zip) → gửi lệnh Upgrade tới VPS → CmdAgent chạy upgrade.ps1: tải /api/agent/release/{id}/download với X-Vps-Secret, so SHA-256, dừng agent, giải nén đè C:\VpsAgent, reboot để AutoLogon khởi động bản mới. upgrade.ps1 không nằm trong zip (không tự ghi đè được); muốn cập nhật chính nó thì chạy lại prepare-vm.ps1.

Upload the release zip on /admin/agent-releases (e.g. vps-agent-upgrade-1.3.2-phase9.zip) → send an Upgrade command to the VPS → CmdAgent runs upgrade.ps1: downloads /api/agent/release/{id}/download with X-Vps-Secret, checks SHA-256, stops the agents, extracts over C:\VpsAgent, reboots so AutoLogon starts the new binaries. upgrade.ps1 is not inside the zip (it cannot overwrite itself); to update it, re-run prepare-vm.ps1.

Gói tài khoản MT5MT5 account packages

  1. /admin/brokers: raw name phải khớp đúng ACCOUNT_COMPANY; gói và VPS đều gắn một broker, chỉ ghép được khi cùng broker./admin/brokers: the raw name must match ACCOUNT_COMPANY exactly; packages and VPSes are each tied to a broker and can only be paired when they match.
  2. Chuẩn bị ZIP: thư mục MT5 portable có EA + profile chart; input khác nhau theo user để trong .set dưới MQL5/Presets/ với giá trị giữ chỗ. Tính SHA-256 (certutil -hashfile package.zip SHA256). Tên gói trong repo có dạng GoldenRobber-Pass58_v1-42-b3-Vantage-build-6182.zip.Prepare the ZIP: a portable MT5 folder with the EA + chart profile; per-user inputs go in a .set under MQL5/Presets/ with a placeholder value. Compute SHA-256 (certutil -hashfile package.zip SHA256). Package names in the repo look like GoldenRobber-Pass58_v1-42-b3-Vantage-build-6182.zip.
  3. /admin/packages: URL ZIP (hoặc upload qua /admin/packages/upload, nginx cho phép tới 1024 MB, 600 s), version, profile, MT5 build (tuỳ chọn), SHA-256, danh sách URL Allow WebRequest, value injection (vd MQL5/Presets/AccountStatusUpdater.set · InpAccountSecretKey · user.mt5_secret_key)./admin/packages: ZIP URL (or upload via /admin/packages/upload, nginx allows up to 1024 MB, 600 s), version, profile, MT5 build (optional), SHA-256, Allow WebRequest URL list, value injections (e.g. MQL5/Presets/AccountStatusUpdater.set · InpAccountSecretKey · user.mt5_secret_key).
  4. User deploy ở /deployments/new; theo dõi ở /vps/{id} và /deployments. Account đã deploy không tự nâng cấp khi gói đổi; có route bulk-upgrade theo gói.Users deploy on /deployments/new; watch /vps/{id} and /deployments. Deployed accounts do not auto-upgrade when a package changes; there is a per-package bulk-upgrade route.
Đóng gói hotfix b21.1Packaging hotfix b21.1

chart01.chr trong gói hiện có trỏ tới Experts\GoldenRobber-1.41.4.ex5. Đổi tên GoldenRobber-1.41.4-b21.1.ex5 thành GoldenRobber-1.41.4.ex5 khi cho vào zip (hoặc sửa name=/path= trong .chr), rồi kiểm tra panel có (b21.1).

The existing package's chart01.chr points at Experts\GoldenRobber-1.41.4.ex5. Rename GoldenRobber-1.41.4-b21.1.ex5 to GoldenRobber-1.41.4.ex5 inside the zip (or edit name=/path= in the .chr), then check the panel shows (b21.1).

MySQL trên aaPanelMySQL on aaPanel

  • Database trade_copier nằm trên host aaPanel từ xa, được dùng bởi fxconsole-app, fxconsole-scheduler và ba broker (AccountStatusBroker, VpsStreamBroker, EaLinkBroker; deploy.sh copy cùng user DB của fxconsole). User này cần đọc settings, vpses và ghi vps_commands, vpses.
  • Sự cố binlog đầy disk: EA đẩy lại toàn bộ ticket map mỗi 5–10 s và controller cũ xoá-hết rồi insert-hết, tạo ~10 lượt ghi/giây (~873k/ngày) và ~3 GB binlog/ngày trên một DB chỉ 179 MB, cuối cùng làm đầy disk MySQL. Hai biện pháp: binlog_expire_logs_seconds đã được hạ xuống, và fxconsole 2026.09.04.1 (commit 020339f) bỏ ghi lại tmap_entries khi map không đổi (dấu vân tay sha1 trong Redis, kỳ vọng giảm 95–99% lượt ghi; EA không cần đổi).
  • Theo dõi định kỳ dung lượng binlog và disk của host aaPanel. Đổi cấu hình MySQL qua aaPanel (my.cnf) để giữ sau restart.
  • The trade_copier database lives on the remote aaPanel host and is used by fxconsole-app, fxconsole-scheduler and three brokers (AccountStatusBroker, VpsStreamBroker, EaLinkBroker; deploy.sh copies fxconsole's DB user). That user needs to read settings, vpses and write vps_commands, vpses.
  • Binlog filled the disk: the EA re-pushed the whole ticket map every 5–10 s and the old controller deleted everything and re-inserted it, producing ~10 writes/s (~873k/day) and ~3 GB of binlog/day on a database of only 179 MB, which eventually filled the MySQL disk. Two remedies: binlog_expire_logs_seconds was lowered, and fxconsole 2026.09.04.1 (commit 020339f) stopped rewriting tmap_entries when the map is unchanged (sha1 fingerprint in Redis, expected 95–99% fewer writes; no EA change needed).
  • Watch binlog size and disk usage on the aaPanel host regularly. Change MySQL config through aaPanel (my.cnf) so it survives restarts.
-- current retention and binlog files
SHOW VARIABLES LIKE 'binlog_expire_logs_seconds';
SHOW BINARY LOGS;
-- emergency cleanup (check replicas first if any)
PURGE BINARY LOGS BEFORE NOW() - INTERVAL 1 DAY;

VPN WireGuard (CT 107)WireGuard VPN (CT 107)

wg-easy chạy bằng Docker trong container Proxmox CT 107, 3 NIC (vmbr101 / vmbr102 / vmbr103), MASQUERADE cho dải client 10.8.2.0/24.

wg-easy runs in Docker inside Proxmox container CT 107, with 3 NICs (vmbr101 / vmbr102 / vmbr103) and MASQUERADE for the client range 10.8.2.0/24.

Sau mỗi lần tạo hoặc xoá clientAfter every client create or delete

Restart Docker trong CT 107 (docker restart wg-easy hoặc docker compose restart ở thư mục của wg-easy). Nếu không, peer mới không được nạp vào wg0 và client không bao giờ handshake dù cấu hình đúng. Client mới không kết nối được: kiểm tra việc này trước khi soi firewall/NAT.

Restart Docker inside CT 107 (docker restart wg-easy or docker compose restart in wg-easy's folder). Otherwise the new peer is never loaded into wg0 and the client never handshakes even with a correct config. New client cannot connect: check this before digging into firewall/NAT.

Rollback theo thành phầnRollback per component

Thành phầnComponent Cách rollbackHow to roll back Lưu ýNotes
fxconsoleRevert commit lỗi trên main (git revert <commit> ở máy dev, push), rồi bash deploy.sh. Không checkout commit cũ trên server: deploy.sh luôn quay về main.Revert the bad commit on main (git revert <commit> on a dev machine, push), then bash deploy.sh. Do not check out an old commit on the server: deploy.sh always returns to main.Migration đã chạy không tự lùi; chỉ php artisan migrate:rollback khi chắc chắn. Không đụng APP_KEY, không down -v.Migrations already applied do not roll back by themselves; only run php artisan migrate:rollback when sure. Never touch APP_KEY, never down -v.
EaLinkBrokerRevert + deploy, hoặc tạm docker compose downRevert + deploy, or temporarily docker compose downEA hiện Link: DOWN và vẫn nhận config qua heartbeat HTTP. Không mất gì.EAs show Link: DOWN and still get config over the HTTP heartbeat. Nothing is lost.
VpsStreamBrokerRevert + deploy, hoặc docker compose downRevert + deploy, or docker compose downAgent rơi về HTTPS polling (heartbeat, lệnh, ACK); lệnh trong vps_commands không bị ảnh hưởng.Agents fall back to HTTPS polling (heartbeats, commands, ACKs); commands in vps_commands are unaffected.
AccountStatusBrokerRevert + deployRevert + deployEA ở HTTP / HYBRID vẫn đẩy qua HTTP; EA chỉ TCP mất dữ liệu sống; dashboard chuyển sang polling.EAs in HTTP / HYBRID keep posting over HTTP; TCP-only EAs lose live data; the dashboard falls back to polling.
TickBrokerRevert + deployRevert + deployCharts mất tick sống; nến lịch sử trong TimescaleDB vẫn còn.Charts lose live ticks; historical bars in TimescaleDB remain.
Cert brokerBroker certDừng broker, chép lại certs.bak-<ngày> thành certs, bật lạiStop the broker, copy certs.bak-<date> back to certs, start againVpsStreamBroker: chạy lại prepare-vm.ps1 trên VPS nếu CA đã được phát.VpsStreamBroker: re-run prepare-vm.ps1 on VPSes if the new CA was already distributed.
GoldenRobber EALấy lại bản cũ b21 (Git Bash hoặc cmd, không dùng > của PowerShell vì hỏng file nhị phân):Recover the previous build b21 (Git Bash or cmd, not PowerShell's >, which corrupts binaries):
git cat-file -p 71dac5f:GoldenRobber-1.41.4.ex5 > GoldenRobber-1.41.4-b21.ex5
Gỡ EA rồi gắn lại, kiểm tra tiêu đề (b21). Clear override không hiểu được (vd manual_init = 5) trên web. Nạp lại .set của b21 (v1.41.4-pass58-easupported-goldenrobber-29082026.set).Remove and re-attach the EA, check the title shows (b21). Clear overrides it cannot understand (e.g. manual_init = 5) on the web. Reload the b21 .set (v1.41.4-pass58-easupported-goldenrobber-29082026.set).
vps-agentUpload lại zip bản trước (vd vps-agent-upgrade-1.3.1-phase8.zip) trên /admin/agent-releases và gửi Upgrade, hoặc chép binary cũ rồi chạy lại prepare-vm.ps1Re-upload the previous zip (e.g. vps-agent-upgrade-1.3.1-phase8.zip) on /admin/agent-releases and send Upgrade, or copy the old binaries and re-run prepare-vm.ps1Tính năng Phase 8 cần agent ≥ 1.3.0-phase4k.Phase 8 features need agent ≥ 1.3.0-phase4k.
claude-clidocker compose build --build-arg CLAUDE_CODE_VERSION=<x.y.z> claude-cliKhôi phục credential từ bản sao lưu nếu volume mất: docker compose exec -T claude-cli sh -c 'tar xzf - -C /home/node' < claude-creds-backup.tgzRestore credentials from the backup if the volume is lost: docker compose exec -T claude-cli sh -c 'tar xzf - -C /home/node' < claude-creds-backup.tgz

Xử lý sự cốTroubleshooting

Triệu chứngSymptom Nguyên nhânCause Cách sửaFix
EaLinkBroker logEaLinkBroker log no broker internal secret (DB settings + Redis mirror + env all empty) / [ealink] key lookup slug=… failedKhông tìm được broker_internal_secret: thiếu hoặc sai DB_*, mirror Redis trống (Redis vừa restart), env trốngNo broker_internal_secret found: DB_* missing or wrong, Redis mirror empty (Redis just restarted), env emptyĐiền DB_* trong monitor/EaLinkBroker/.env (deploy.sh tự điền), kiểm tra log settings DB: on, đặt "EALinkBroker Secret Key" trên /admin/settings, docker compose up -dFill DB_* in monitor/EaLinkBroker/.env (deploy.sh fills it), check the settings DB: on log line, set "EALinkBroker Secret Key" on /admin/settings, docker compose up -d
Mọi EA nhậnAll EAs get hello_err auth_unavailableLaravel không tới được / trả mã khác 200-404 / thiếu secret; BROKER_INTERNAL_URL sai; fxconsole-web chếtLaravel unreachable / non-200/404 / no secret; wrong BROKER_INTERNAL_URL; fxconsole-web downBROKER_INTERNAL_URL=http://fxconsole-web; sửa secret như dòng trên. EA tự thử lại với backoff.BROKER_INTERNAL_URL=http://fxconsole-web; fix the secret as above. EAs retry with backoff.
hello_err bad_sig (một EA)(one EA)Token trên terminal cũ/sai (vd sau Regenerate)Stale/wrong token on that terminal (e.g. after Regenerate)Gõ lại InpCloudBearerToken. EA chờ 5 phút sau bad_sig; broker cache key 60 s.Retype InpCloudBearerToken. The EA waits 5 minutes after bad_sig; the broker caches keys for 60 s.
hello_err unknown_eaSlug chưa đăng ký / product bị tắt / gõ sai slug trong InpCloudMyApiDomainSlug not registered / product disabled / slug typo in InpCloudMyApiDomainKiểm tra /admin/easupported và URL …/easupported/{slug}Check /admin/easupported and the …/easupported/{slug} URL
PanelPanel Link: DOWN, retry NsBroker không chạy, 9607 chưa forward, host không có trong Allow WebRequest, InpLinkHost saiBroker not running, 9607 not forwarded, host missing from Allow WebRequest, wrong InpLinkHostdocker logs fxconsole-ea-link-broker; openssl s_client -connect fxconsole.gamelau.uk:9607 -quiet; kiểm tra OVH + IPFire. EA vẫn chạy HTTP.check OVH + IPFire. The EA keeps working over HTTP.
PanelPanel Link: OFF (missing slug/token)InpCloudMyApiDomain không có dạng …/easupported/{slug} hoặc token trốngInpCloudMyApiDomain is not …/easupported/{slug} or the token is emptySửa inputFix the inputs
cfg … delivered=0 khi EA đang onlinewhile the EA is onlineslug / composite_id / magic Laravel publish không khớp HELLO của EAThe slug / composite_id / magic Laravel publishes differ from the EA's HELLOSo với presence hash; EA vẫn nhận config ở heartbeat kếCompare with the presence hash; the EA still gets config on its next heartbeat
Redis main error: getaddrinfo ENOTFOUND fxconsole-redisBroker không ở mạng fxconsole_default (fxconsole chưa chạy)Broker not on fxconsole_default (fxconsole not running)Bật fxconsole trước, rồi docker compose up -d ở brokerStart fxconsole first, then docker compose up -d in the broker folder
Heartbeat EA trảEA heartbeat returns 401 · panelpanel Server: NO SYNCInpCloudBearerToken ≠ easupported.secret_token (URL cũ /api/tmap thì so với TMAP_SECRET_KEY). 404 Unknown EA = slug sai.InpCloudBearerToken ≠ easupported.secret_token (the legacy /api/tmap URL compares with TMAP_SECRET_KEY). 404 Unknown EA = wrong slug.Copy lại token từ /admin/easupported, gõ trên terminalCopy the token again from /admin/easupported, type it on the terminal
WebRequest trảreturns -1URL chưa có trong Allow WebRequest, hoặc lỗi mạng. 4014 = chứng chỉ không hợp lệ (tự ký)URL not in Allow WebRequest, or a network error. 4014 = invalid (self-signed) certificateThêm https://fxconsole.gamelau.uk vào Allow WebRequestAdd https://fxconsole.gamelau.uk to Allow WebRequest
AccountStatusUpdater 401 Unauthorized bearer tokenInpApiBearer ≠ ea_api_bearer / EA_API_BEARERĐồng bộ bearerAlign the bearer
AccountStatusUpdater broker HELLO rejectedInpBrokerSecret ≠ BROKER_SECRET, hoặc EA/broker lệch phiên bản HELLO v2InpBrokerSecret ≠ BROKER_SECRET, or an EA/broker HELLO v2 version mismatchĐồng bộ secret; nâng EA và broker cùng lúcAlign the secret; upgrade EA and broker together
FATAL: TICK_BROKER_SECRET is empty / FATAL: BROKER_SECRET is empty.env mới tạo còn trốngFreshly created .env still blankĐiền secret, docker compose up -dFill the secret, docker compose up -d
FATAL: certs/server.{key,cert} missingThư mục certs/ không ghi được, openssl lỗi lúc boot đầucerts/ not writable, openssl failed on first bootSửa quyền thư mục, xem log openssl, khởi động lạiFix folder permissions, read the openssl log, restart
AgentAgent BROKER: HELLO rejected reason=bad_secretvpses.secret_key ≠ secret_key trongin vps-agent.iniCopy lại block ini từ /vps/{id} → Reveal SecretRe-copy the ini block from /vps/{id} → Reveal Secret
Cổng 9605 local mở nhưng remote bị từ chối / TLS handshake lỗiLocal 9605 open but remote refused / TLS handshake failsFirewall; hoặc CN không khớp giữa CERT_HOST và vps_broker_hostFirewall; or CN mismatch between CERT_HOST and vps_broker_hostMở 9605 trên OVH + IPFire; tạo lại cert đúng CN rồi chạy lại prepare-vm.ps1Open 9605 on OVH + IPFire; regenerate the cert with the right CN, re-run prepare-vm.ps1
prepare-vm.ps1: broker-config fetch failedfxconsole chưa có CA của brokerfxconsole does not have the broker CA yetKiểm tra mount /broker-certs hoặc chạy vps-stream-broker:cert-importCheck the /broker-certs mount or run vps-stream-broker:cert-import
Deploy tài khoản kẹt ở pendingAccount deploy stuck at pendingCallback /api/internal/broker/command-ack lỗi (BROKER_INTERNAL_URL / secret sai), hoặc agent không nhận lệnhThe /api/internal/broker/command-ack callback fails (wrong BROKER_INTERNAL_URL / secret), or the agent never got the commandXem log VpsStreamBroker và cmd-agent.log; sửa URL/secretRead the VpsStreamBroker log and cmd-agent.log; fix URL/secret
git pull: "local changes would be overwritten"File đã track bị sửa tay, hoặc file chưa track trùng tên với file mớiHand-edited tracked file, or an untracked file collides with a new onedeploy.sh đã git restore .; file chưa track thì dời đi rồi chạy lạideploy.sh already runs git restore .; move untracked files away and rerun
Cột mã hoá không giải mã được sau deployEncrypted columns undecryptable after a deployAPP_KEY đã bị đổiAPP_KEY was changedKhôi phục APP_KEY cũ từ bản sao lưu .envRestore the old APP_KEY from the .env backup
Task scheduler không chạy lạiScheduled task never runs againKhoá withoutOverlapping() kẹt sau crashA withoutOverlapping() lock stuck after a crashdocker compose restart scheduler (chạy schedule:clear-cache khi khởi động)(runs schedule:clear-cache on start)
Banner đỏRed banner "CLI cần đăng nhập lại"Refresh token OAuth hết hạn hoặc volume mấtOAuth refresh token expired or volume lostRe-login trên /admin/analysis hoặc docker compose exec -it claude-cli claude loginRe-login on /admin/analysis or docker compose exec -it claude-cli claude login
Guacamole: "Guacamole is not configured"Guacamole: "Guacamole is not configured"Thiếu GUAC_JSON_SECRET_KEY hoặc GUAC_PUBLIC_URLMissing GUAC_JSON_SECRET_KEY or GUAC_PUBLIC_URLĐiền cả hai (DB hoặc .env), cùng khoá với container guacamoleSet both (DB or .env), same key as the guacamole container
EA vẫn là bản cũ sau khi copy .ex5EA still the old build after copying the .ex5Dùng F7 thay vì gắn lạiUsed F7 instead of re-attachingGỡ EA rồi gắn lại, xem build trên tiêu đề panelRemove and re-attach, check the build in the panel title
Disk MySQL đầyMySQL disk fullBinlog tăng nhanhFast-growing binlogXem MySQL trên aaPanel; đảm bảo fxconsole ≥ 2026.09.04.1See MySQL on aaPanel; make sure fxconsole ≥ 2026.09.04.1
Client WireGuard mới không handshakeNew WireGuard client never handshakesChưa restart Docker trong CT 107Docker in CT 107 not restarteddocker restart wg-easy
/easupported trống dù account đang chạy EA/easupported empty although accounts run the EAfxconsole < 2026.09.14.1 (GoldenRobber gửi server = tên broker, composite_id chưa đồng bộ), hoặc EA không heartbeat tới /easupported/{slug}fxconsole < 2026.09.14.1 (GoldenRobber sends server = broker name, composite_id not synced), or the EA does not heartbeat to /easupported/{slug}Nâng fxconsole; xem account có ở /admin/easupported/{slug} không, không có thì sửa InpCloudMyApiDomain / tokenUpgrade fxconsole; check the account is listed on /admin/easupported/{slug}, otherwise fix InpCloudMyApiDomain / token
Menu tiền tệ báo "Chưa có tỷ giá", mục VND bị khoáCurrency menu says "No USDT/VND rate yet", VND disabledfx_rates chưa có dòng: scheduler chưa chạy lệnh, hoặc Binance trả lỗi (log fx.usdt_vnd.failed)fx_rates is empty: the scheduler hasn't run the command, or Binance returns errors (log fx.usdt_vnd.failed)php artisan fx:sync-usdt-vnd --force; docker compose restart schedulerphp artisan fx:sync-usdt-vnd --force; docker compose restart scheduler
Menu báo tỷ giá đã cũMenu says the rate is out of dateCác lần fetch gần đây đều lỗi, web giữ giá cũ. HTTP 403 / 418 / 429 = IP server bị chặn (tự dừng 15 phút)Recent fetches all failed, the web keeps the last rate. HTTP 403 / 418 / 429 = server IP blocked (backs off 15 minutes)Xem log fx.usdt_vnd.failed; tăng usdt_vnd_interval_minutes trên /admin/settingsRead the fx.usdt_vnd.failed log; raise usdt_vnd_interval_minutes on /admin/settings
Số tiền một account lớn gấp 10 hoặc 100 lầnOne account's money is 10× or 100× too largeAccount báo ×10 / ×100 (vd. cent) nhưng đang ở /1The account reports ×10 / ×100 (e.g. cent) but is at /1Chọn /10 hoặc /100 cho server ở /admin/brokers, hoặc chọn dòng → menu Hệ số chiaPick /10 or /100 for the server on /admin/brokers, or select the row → Money divisor menu
Account bị chia sai (số tiền quá nhỏ)An account is divided when it shouldn't be (money too small)Server của account có hệ số /10 / /100, hoặc account bị đặt tayThe account's server has a /10 / /100 divisor, or the account was set by handMenu Hệ số chia → /1 (thắng hệ số server), hoặc đưa server về /1 nếu cả server là standardMoney divisor menu → /1 (overrides the server), or set the server back to /1 if the whole server is standard