Headless broker login¶
Set broker credentials in .env and the gateway logs into MT5 on boot — no VNC,
any broker, just the broker's server name. You do not need the broker's IP or a
pre-built broker directory.
| Var | Meaning |
|---|---|
MT5_LOGIN |
broker account number |
MT5_PASSWORD |
master (trading) password |
MT5_SERVER |
broker server name, e.g. Exness-MT5Trial9, ICMarketsSC-Demo |
MT5_ENABLE_ALGO_TRADING |
optional; defaults to 1. Set 0, false, no, off, or disabled to launch headless with MT5 Expert/live trading disabled. |
Leaving MT5_LOGIN empty keeps the manual VNC flow and the persisted-volume login,
unchanged.
Why a name is enough¶
MT5 under Wine cannot discover a broker by name on a fresh volume — it needs the
broker's record (access-point address + keys) in the encrypted servers.dat
directory, and there is no headless way to make MT5 fill that in from a name alone.
The gateway sidesteps this: it resolves the server name to a raw access-point
address (host:port) using a broker-directory search service, then hands MT5
Server=<host:port> in its startup config. MT5 connects to the access point
directly, authorises, and writes the servers.dat record itself. So after the first
login the volume is self-seeded and later boots are instant — the login is
idempotent.
e.g. MT5_SERVER=Exness-MT5Trial9 → resolver returns an access-point
host:port → MT5 authorises on Exness-MT5Trial9, AutoTrading on unless
MT5_ENABLE_ALGO_TRADING=0.
Resolution cascade¶
Addresses come from three sources, tried in order, with automatic fallthrough — the boot tries each candidate address until MT5 authorises, so a stale entry or an unknown broker falls through on its own:
- Baked table —
app/broker_servers.json, aname → [host:port]map shipped in the image (see harvesting). Offline, instant, no network. Covers the popular brokers. - Resolver services —
GET /Search?company=<keyword>againstMT5_RESOLVER_URL(default: publicmt5.mtapi.io, then the optional self-hosted sidecar). These mirror MetaQuotes' live directory, so they cover every real MT5 broker. - The server name itself — last resort, against a baked/persisted
servers.dat.
So the image runs as a single container out of the box (baked table + mtapi.io). Resolution happens at most once per broker (its first boot); after that MT5 has self-seeded the directory and no lookup is made.
For a zero-third-party setup, start the bundled self-hosted resolver and make it the only one:
docker compose --profile self-hosted-resolver up
# and set MT5_RESOLVER_URL=http://mt5-resolver:80 to drop mtapi.io
Refreshing the baked table¶
scripts/harvest-broker-servers.py regenerates app/broker_servers.json from the
public directory. Run it occasionally (broker addresses change rarely, and MT5
self-seeds the current directory on first connect, so a slightly stale table still
bootstraps a login), then rebuild the image.
Baked terminal (no installer at boot)¶
The MT5 terminal is installed at image build time into the seeded Wine
template (/opt/wine-template), under a virtual display with the same
timeout+retry watchdog the runtime installer used. A cold boot therefore never
runs the GUI installer — it copies the terminal out of the template together
with Mono/Python, then goes straight to login. What was baked is recorded in
/config/.wine/.mt5-install-info (stub URL + checksum, install date, terminal
build).
MetaQuotes rotates the stub installer, so its SHA-256 is pinned in two places
that must move together: ARG MT5_SETUP_SHA256 in the Dockerfile (build-time
install) and mt5setup_sha256 in scripts/02-common.sh (runtime fallback for
volumes created before the template included MT5). A rotation fails the build
loudly — re-pin both.
Tuning knobs (all optional)¶
| Var | Default | Meaning |
|---|---|---|
MT5_SERVER_ADDR |
unset | Explicit host:port — skip resolution and connect here directly. |
MT5_ENABLE_ALGO_TRADING |
1 |
Enables MT5 Expert/live trading in the startup ini. Set 0, false, no, off, or disabled to opt out. |
MT5_RESOLVER_URL |
https://mt5.mtapi.io,http://mt5-resolver:80 |
Comma-separated resolver base URLs, tried in order (after the baked table). |
MT5_AUTORESOLVE |
1 |
0 disables the network resolvers — use the baked table + name only. |
MT5_SETUP_URL |
generic MT5 | A broker-branded installer URL (e.g. .../exness5setup.exe). Installs at runtime over the baked generic terminal (its bundled directory also resolves the broker by name); the install is recorded so later boots keep the branded terminal. |
MT5_SETUP_ATTEMPTS / MT5_SETUP_TIMEOUT |
3 / 600 |
Watchdog for the runtime install path (custom MT5_SETUP_URL, or old volumes without a baked terminal): bound each silent-install attempt (seconds) and retry, so a stuck Wine installer can't hang the boot forever. |
servers.dat (broker directory)¶
Still baked into the image (~728 KB, major brokers) as an offline fallback for name-based login, but it is no longer required for headless login — the resolver covers brokers it doesn't list, and MT5 self-seeds the directory on first connect.
Override without rebuilding: mount your own at /defaults/servers.dat, or set
QKT_ARTIFACTS_TOKEN to fetch it from a private repo on first boot.
Verify¶
curl -s http://localhost:5001/account | python3 -m json.tool
# expect: "login": <yours>, "server": "<your server name>",
# "trade_allowed": true, "trade_expert": true