IB Gateway
IB Gateway Docker packages Interactive Brokers Gateway with IBC, Xvfb, and TCP proxies. The HelmForge chart deploys that community-maintained runtime as a private singleton with safe paper defaults, immutable image pinning, Secret-backed credentials, persistent settings, and product-aware probes.
The image is not published by Interactive Brokers. HelmForge and the image project are not affiliated with or endorsed by Interactive Brokers. The image includes proprietary IB Gateway software, and operators remain responsible for all IBKR agreements, permissions, subscriptions, and trading controls.
What this chart provides
ghcr.io/gnzsnz/ib-gateway:10.50.1fpinned by immutable amd64 and arm64 manifest digest;- paper trading, read-only API, blind trading disabled, VNC disabled, and ClusterIP exposure by default;
- exactly one Deployment replica with
Recreateupgrades to prevent overlapping account sessions; - managed Secret, existing Secret key mapping, and External Secrets Operator resources;
- password-file projection through upstream
_FILEvariables; - persistent TWS settings with retained PVC support;
- live, paper, or simultaneous Service port mapping;
- internal-listener readiness checks and conservative process liveness;
- NetworkPolicy, dual-stack Services, scheduling controls, and baseline Pod hardening.
The IBKR API is raw TCP without chart-provided authentication or encryption. The chart intentionally does not create Ingress or Gateway API resources.
Install for paper trading
Create a mode-0600 password file outside the repository, then create the credential Secret without putting the
password in shell history:
kubectl create namespace ib-gateway
kubectl -n ib-gateway create secret generic ib-gateway-credentials \
--from-literal=username='your-paper-username' \
--from-file=password=/secure/path/ibkr-password
Protect that temporary file and remove it securely after confirming the Secret exists.
Install the chart:
helm repo add helmforge https://repo.helmforge.dev
helm repo update
helm install ib-gateway helmforge/ib-gateway \
--version 1.0.0 \
--namespace ib-gateway \
--set auth.existingSecret=ib-gateway-credentials
Watch the logs and approve the expected mobile two-factor request:
kubectl -n ib-gateway logs deployment/ib-gateway --follow
kubectl -n ib-gateway rollout status deployment/ib-gateway
Connect a paper client
Keep the Service internal. For temporary workstation access:
kubectl -n ib-gateway port-forward service/ib-gateway 4002:4002
Connect the client to 127.0.0.1:4002. The live API uses Service port 4001. The container internally proxies those
ports through 4004 and 4003 respectively, matching the upstream image contract.
Set networkPolicy.apiIngressFrom to explicit namespace or Pod selectors when clients run elsewhere in the cluster.
Use a private encrypted network for any path outside the cluster. Never expose the Service directly to the internet.
Manage credentials
The existing Secret defaults to these keys:
| Mode | Username key | Password key |
|---|---|---|
| Live or paper | username |
password |
Additional paper session in both mode |
paper-username |
paper-password |
Override the auth.*Key values when your secret manager uses different names. Passwords are mounted as files;
usernames use secretKeyRef because upstream does not expose username-file variables. Inline credential values exist
only for evaluation and are stored in Helm release history.
External Secrets can materialize the exact Secret consumed by the Deployment:
auth:
existingSecret: ib-gateway-credentials
externalSecrets:
enabled: true
items:
- fullnameOverride: ib-gateway-credentials
spec:
secretStoreRef:
name: production
kind: ClusterSecretStore
data:
- secretKey: username
remoteRef:
key: trading/ibkr/username
- secretKey: password
remoteRef:
key: trading/ibkr/password
Credential rotation ends the current session and usually requires fresh two-factor approval. Coordinate rotation with trading operations and restart the singleton Deployment after the target Secret synchronizes.
Understand readiness
The public container listeners belong to socat and can start before authentication finishes. With credentials
configured, startup and readiness inspect the active internal Gateway listener instead. An empty evaluation install
only checks that the credential-waiting process runs; its Service is not usable.
Readiness does not prove that an account can place orders, that market data is subscribed, or that IBKR services are healthy. Monitor those domain conditions from the trading client.
Enable live trading deliberately
Use paper trading first. Before changing gateway.tradingMode to live:
- Verify the intended account Secret and two-factor device.
- Prove client behavior and reconnect handling against paper trading.
- Keep
gateway.readOnlyApi: trueuntil write access is separately approved. - Review
gateway.allowBlindTrading; the safe default is false. - Confirm NetworkPolicy and private transport restrict every API client.
The chart does not implement order limits, reconciliation, or trading-risk policy.
Persist and recover settings
The default PVC stores /home/ibgateway/tws_settings. It does not store credentials, account state, or generated IBC
configuration. Back up customized settings with your storage platform and test recovery in an isolated paper-trading
release.
A persisted jts.ini can retain the initial timezone. Changing gateway.timeZone may therefore require a deliberate
backup and cleanup of that setting so upstream can regenerate it.
Use VNC for maintenance
VNC is disabled by default. When visual diagnostics are necessary, enable vnc.enabled, supply a Secret-backed
password, and use kubectl port-forward to the separate VNC Service. Keep it private and disable it after maintenance.
Complete configuration reference
Use the playground and select IB Gateway to generate a non-secret starting values file. The tables below cover the complete public values contract.
Naming and image
| Value | Default | Purpose |
|---|---|---|
nameOverride |
"" |
Override the chart name in resource names |
fullnameOverride |
"" |
Override the complete resource name |
replicaCount |
1 |
Enforced singleton account session |
commonLabels |
{} |
Labels on chart resources |
podLabels |
{} |
Additional non-selector Pod labels |
podAnnotations |
{} |
Additional Pod annotations |
imagePullSecrets |
[] |
Registry credential references |
image.repository |
ghcr.io/gnzsnz/ib-gateway |
Community upstream image repository |
image.tag |
10.50.1f |
Exact upstream release |
image.digest |
pinned SHA-256 | Immutable multi-architecture manifest |
image.pullPolicy |
IfNotPresent |
Kubernetes pull policy |
Credentials and External Secrets
| Value | Default | Purpose |
|---|---|---|
auth.existingSecret |
"" |
Existing credential Secret |
auth.username |
"" |
Evaluation live or paper username |
auth.password |
"" |
Evaluation live or paper password |
auth.paperUsername |
"" |
Additional paper username for both mode |
auth.paperPassword |
"" |
Additional paper password for both mode |
auth.usernameKey |
username |
Live or paper username Secret key |
auth.passwordKey |
password |
Live or paper password Secret key |
auth.paperUsernameKey |
paper-username |
Additional paper username key |
auth.paperPasswordKey |
paper-password |
Additional paper password key |
externalSecrets.enabled |
false |
Render ExternalSecret resources |
externalSecrets.refreshInterval |
1h |
Default ESO synchronization interval |
externalSecrets.items |
[] |
Complete ExternalSecret item definitions |
Gateway behavior
| Value | Default | Purpose |
|---|---|---|
gateway.tradingMode |
paper |
paper, live, or both |
gateway.readOnlyApi |
true |
Restrict API actions to reads |
gateway.acceptIncoming |
manual |
Incoming API connection handling |
gateway.masterClientId |
"" |
Optional TWS master client identifier |
gateway.allowBlindTrading |
false |
Preserve upstream order precaution |
gateway.timeZone |
Etc/UTC |
Initial TWS IANA timezone |
gateway.javaHeapSize |
1024 |
Java heap in MiB |
gateway.twoFactorTimeoutAction |
restart |
Action after approval timeout |
gateway.twoFactorExitInterval |
60 |
Seconds after mobile approval |
gateway.twoFactorDevice |
"" |
Optional approval-device selector |
gateway.reloginAfterTwoFactorTimeout |
true |
Retry login after timeout |
gateway.existingSessionDetectedAction |
primary |
Concurrent-session handling |
gateway.autoRestartTime |
11:59 PM |
Daily IBC restart schedule |
gateway.autoLogoffTime |
"" |
Optional daily logoff schedule |
gateway.coldRestartTime |
"" |
Optional cold restart in HH:MM |
gateway.saveSettingsAt |
"" |
Optional IBC settings-save schedule |
gateway.customConfig |
false |
Use operator-mounted upstream configuration |
Workload extensions and state
| Value | Default | Purpose |
|---|---|---|
workload.command |
[] |
Container command override |
workload.args |
[] |
Container argument override |
workload.extraEnv |
[] |
Additional non-secret environment entries |
workload.envFrom |
[] |
Additional Secret or ConfigMap sources |
workload.extraVolumeMounts |
[] |
Additional container mounts |
workload.extraVolumes |
[] |
Additional Pod volumes |
workload.initContainers |
[] |
Additional init containers |
workload.sidecars |
[] |
Additional sidecars |
persistence.enabled |
true |
Persist TWS settings |
persistence.existingClaim |
"" |
Existing settings PVC |
persistence.storageClass |
"" |
StorageClass or - for static provisioning |
persistence.size |
2Gi |
Settings PVC capacity |
persistence.accessModes |
[ReadWriteOnce] |
PVC access modes |
persistence.retain |
true |
Retain generated PVC after uninstall |
persistence.annotations |
{} |
Additional PVC annotations |
Services and VNC
| Value | Default | Purpose |
|---|---|---|
service.type |
ClusterIP |
Private raw-TCP Service |
service.annotations |
{} |
API Service annotations |
service.livePort |
4001 |
Client-facing live API port |
service.paperPort |
4002 |
Client-facing paper API port |
service.ipFamilyPolicy |
"" |
Optional Service family policy |
service.ipFamilies |
[] |
Ordered Service IP families |
service.loadBalancerSourceRanges |
[] |
Source ranges for explicit LoadBalancer use |
vnc.enabled |
false |
Private visual maintenance listener |
vnc.existingSecret |
"" |
Existing VNC password Secret |
vnc.password |
"" |
Evaluation VNC password |
vnc.passwordKey |
vnc-password |
VNC password Secret key |
vnc.service.type |
ClusterIP |
VNC Service type |
vnc.service.port |
5900 |
VNC Service port |
vnc.service.annotations |
{} |
VNC Service annotations |
vnc.service.ipFamilyPolicy |
"" |
Optional VNC family policy |
vnc.service.ipFamilies |
[] |
Ordered VNC IP families |
Network policy and probes
| Value | Default | Purpose |
|---|---|---|
networkPolicy.enabled |
true |
Restrict API and VNC clients |
networkPolicy.apiIngressFrom |
[] |
Explicit API client peers |
networkPolicy.vncIngressFrom |
[] |
Explicit VNC client peers |
networkPolicy.egressIsolation |
false |
Opt-in maintained egress allowlist |
networkPolicy.dnsEgress |
namespace selector | DNS destinations for isolated egress |
networkPolicy.extraEgress |
[] |
Complete IBKR or tunnel egress rules |
probes.startup.enabled |
true |
Enable startup validation |
probes.startup.command |
[] |
Startup command override |
probes.startup.periodSeconds |
10 |
Startup check interval |
probes.startup.timeoutSeconds |
3 |
Startup check timeout |
probes.startup.failureThreshold |
90 |
2FA-aware startup budget |
probes.readiness.enabled |
true |
Enable readiness validation |
probes.readiness.command |
[] |
Readiness command override |
probes.readiness.periodSeconds |
10 |
Readiness check interval |
probes.readiness.timeoutSeconds |
3 |
Readiness check timeout |
probes.readiness.failureThreshold |
3 |
Failures before removal from endpoints |
probes.liveness.enabled |
true |
Enable conservative process liveness |
probes.liveness.command |
[] |
Liveness command override |
probes.liveness.periodSeconds |
30 |
Liveness check interval |
probes.liveness.timeoutSeconds |
3 |
Liveness check timeout |
probes.liveness.failureThreshold |
5 |
Failures before restart |
Platform and security controls
| Value | Default | Purpose |
|---|---|---|
serviceAccount.create |
true |
Create a dedicated ServiceAccount |
serviceAccount.name |
"" |
Existing or custom ServiceAccount name |
serviceAccount.annotations |
{} |
ServiceAccount annotations |
serviceAccount.automountServiceAccountToken |
false |
Mount Kubernetes API credentials |
terminationGracePeriodSeconds |
90 |
Allow IBC and Gateway shutdown |
resources.requests.cpu |
250m |
Requested CPU |
resources.requests.memory |
1Gi |
Requested memory |
resources.limits.cpu |
2 |
CPU limit |
resources.limits.memory |
2Gi |
Memory limit |
podSecurityContext |
UID/GID 1000, seccomp |
Pod-level upstream identity and hardening |
securityContext |
no escalation, drop ALL |
Container-level hardening |
nodeSelector |
{} |
Node label selection |
tolerations |
[] |
Pod tolerations |
affinity |
{} |
Pod affinity rules |
priorityClassName |
"" |
Workload priority class |
topologySpreadConstraints |
[] |
Singleton placement constraints |
extraManifests |
[] |
Additional arbitrary Kubernetes resources |
Operational limitations
- IBC was retired by its maintainers on 2026-09-01 and receives limited maintenance.
- Concurrent sessions do not provide safe horizontal availability; the chart rejects multiple replicas.
- A
Recreateupgrade intentionally introduces downtime and can require two-factor approval. - No documented Prometheus endpoint exists, so the chart does not publish a misleading ServiceMonitor.
- IBKR endpoints can change, so egress isolation requires an operator-maintained gateway or allowlist.
Uninstall
helm uninstall ib-gateway --namespace ib-gateway
The generated settings PVC is retained by default. Confirm backup and remove it separately only when the settings are no longer required.