Security Hardening Guide¶
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.
The Golden Rules¶
- Never hardcode secrets. As of v10.10+, no password in config — remember-login handles credentials. Mount keys as files.
- 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.
Credential Handling¶
Remember-login (v10.10+)¶
FutuOpenD v10.10+ uses remember-login — credentials are cached after the first interactive login and reused automatically. Your FUTU_ACCOUNT environment variable identifies the account; no password in config.
Protect the data volume. The Docker volume
futuopend-datacontains the cached session. If compromised, an attacker could potentially access your trading account. Treat the volume as sensitive.
Your RSA private key — chmod 600, never commit it¶
Your RSA key is the most sensitive piece here. Guard it accordingly:
And keep it out of version control — the repo's .gitignore handles this.
FutuOpenD.xml — built-in default is usually sufficient¶
The image ships with a built-in FutuOpenD.xml at /usr/local/bin/FutuOpenD.xml. The deploy compose mounts your own ./FutuOpenD.xml over it (OpenD resolves ${VAR} placeholders itself).
If you need custom settings, mount your own at container startup — but keep sensitive values out of it. v10.10+ remember-login means no password in the config file.
Network Security¶
Local binding — the safe default¶
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:
Remote access — TLS is non-negotiable¶
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.pem
Better yet for remote access: use a VPN (WireGuard, Tailscale) or an SSH tunnel. Encryption without managing certificates.
Firewall — default deny¶
# 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 DROP
Or 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 default
Container Hardening¶
Read-only filesystem + dropped capabilities¶
This 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:
- ALL
What 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 |
Non-root user¶
The image already creates a futuopend user (UID 1000) and switches to it. No action needed.
External secrets managers¶
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 |
Monitoring & Audit¶
- 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.
Dependency Updates¶
Rebuild the image periodically to pull fresh OS security patches:
Pin the FutuOpenD version in production. Auto-upgrades at the wrong time can break your trading system.
Security Checklist¶
Run through this before going live:
- [ ] RSA private key has no password and
chmod 600 - [ ]
FutuOpenD.xmldoes not contain hardcoded credentials (v10.10+ uses remember-login) - [ ] 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
- [ ] Docker data volume (
futuopend-data) is backed up and secured
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.