Your trading credentials live inside this container. This guide shows you how to keep them there.
Disclaimer: This is an unofficial community packaging. Not affiliated with, endorsed by, or supported by Futu Securities or moomoo.
- Never hardcode secrets. Use MD5 for passwords, mount keys as files, pass nothing in plaintext.
- Least privilege. Run as non-root, drop capabilities, lock down the filesystem.
- Network is enemy territory. TLS on everything that crosses a wire. Firewall everything else.
- Rotate. Keys wear out. Change them periodically via the Futu OpenAPI dashboard.
The <login_pwd_md5> tag takes a one-way MD5 hash. Your actual password never touches the disk.
Generate it:
# Linux
echo -n "your_password" | md5sum | cut -d' ' -f1
# macOS
echo -n "your_password" | md5 -r
# Python (works everywhere)
python3 -c "import hashlib; print(hashlib.md5(b'your_password').hexdigest())"The -n suppresses the trailing newline. Omit it and the hash is wrong.
Your RSA key is the most sensitive piece here. Guard it accordingly:
chmod 600 secrets/rsa_key.txtAnd keep it out of version control — the repo's .gitignore handles this.
It contains your account ID and credential paths. Lock it down:
chmod 600 secrets/FutuOpenD.xmlIn production, pull it from a secrets manager — HashiCorp Vault, AWS Secrets Manager. Don't leave it sitting on a filesystem longer than needed.
FutuOpenD binds to 127.0.0.1 by default. Only local processes can reach it — the network can't touch it. This is the right mode for single-machine setups:
<ip>127.0.0.1</ip>
<api_port>11111</api_port>If another machine needs to connect, the WebSocket traffic must be encrypted. Generate a certificate and key, then:
<ip>0.0.0.0</ip>
<websocket_private_key>/run/secrets/ws_key_nopass.pem</websocket_private_key>
<websocket_cert>/run/secrets/ws_cert.pem</websocket_cert>Generate a self-signed cert for testing:
openssl req -x509 -newkey rsa:4096 \
-keyout secrets/key.pem -out secrets/cert.pem \
-days 365 -nodes -subj "/CN=futuopend"
# Strip the password — FutuOpenD doesn't handle encrypted keys
openssl rsa -in secrets/key.pem -out secrets/key_nopass.pemBetter yet for remote access: use a VPN (WireGuard, Tailscale) or an SSH tunnel. Encryption without managing certificates.
# Allow only your client subnet
iptables -A INPUT -p tcp --dport 11111 -s 10.0.0.0/8 -j ACCEPT
iptables -A INPUT -p tcp --dport 11111 -j DROPOr isolate FutuOpenD inside a Docker internal network so it can't reach the outside world except where you explicitly allow:
services:
futuopend:
networks:
- futu-internal
networks:
futu-internal:
internal: true # No external egress by defaultThis is the production baseline. Add it to your docker-compose.yaml:
services:
futuopend:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALLWhat each line does:
| Option | What it does |
|---|---|
no-new-privileges |
Prevents the container from gaining privileges via suid binaries |
read_only |
Filesystem is immutable except for mounted volumes |
tmpfs |
Temp data lives in RAM, not on disk |
cap_drop: ALL |
Strips every Linux capability the process doesn't need |
The image already creates a futuopend user (UID 1000) and switches to it. No action needed.
For larger deployments, pull secrets at runtime:
| Tool | How it works |
|---|---|
| HashiCorp Vault | Vault Agent sidecar injects secrets into the container |
| AWS Secrets Manager | aws-secrets-manager-sidecar pulls keys at startup |
| Azure Key Vault | akv-sidecar handles injection |
- Start with
log_level=debugduring setup. Once everything is stable, switch toinfo. - Ship logs somewhere centralized — ELK, Loki, CloudWatch.
- Set up alerts on authentication failures.
- Watch resource usage. Sudden spikes in CPU or memory can be an early warning.
Rebuild the image periodically to pull fresh OS security patches:
cd ../futuopend
docker build --no-cache -t shing1211/futuopend:latest .Pin the FutuOpenD version in production. Auto-upgrades at the wrong time can break your trading system.
Run through this before going live:
- RSA private key has no password and
chmod 600 -
FutuOpenD.xmlis not committed to version control - Remote access uses TLS (both
websocket_private_keyandwebsocket_certset) - Firewall restricts port
11111to known client IPs - Container runs with
read_only: true,cap_drop: ALL, andno-new-privileges: true - Logs are forwarded to a central system and reviewed for auth failures
- FutuOpenD version is pinned (not
latest) - Separate keys used for dev and production
- Password hash is not reused across environments
This project is an unofficial community packaging. Not affiliated with, endorsed by, or supported by Futu Securities or moomoo. All trademarks belong to their respective owners.