Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 52 additions & 17 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ jobs:
GCE_ZONE: ${{ vars.IB_GATEWAY_ZONE }}
DEPLOY_PATH: ${{ vars.IB_GATEWAY_DEPLOY_PATH }}
IB_GATEWAY_MODE: ${{ vars.IB_GATEWAY_MODE }}
IB_GATEWAY_CONTAINER_NAME: ${{ vars.IB_GATEWAY_CONTAINER_NAME }}
IB_GATEWAY_COMPOSE_PROJECT_NAME: ${{ vars.IB_GATEWAY_COMPOSE_PROJECT_NAME }}
IB_GATEWAY_COMPOSE_SERVICE_NAME: ${{ vars.IB_GATEWAY_COMPOSE_SERVICE_NAME }}
IB_GATEWAY_UNIT_SUFFIX: ${{ vars.IB_GATEWAY_UNIT_SUFFIX }}
IB_GATEWAY_LIVE_HOST_PORT: ${{ vars.IB_GATEWAY_LIVE_HOST_PORT }}
IB_GATEWAY_PAPER_HOST_PORT: ${{ vars.IB_GATEWAY_PAPER_HOST_PORT }}
IB_GATEWAY_VNC_HOST_ADDRESS: ${{ vars.IB_GATEWAY_VNC_HOST_ADDRESS }}
IB_GATEWAY_VNC_HOST_PORT: ${{ vars.IB_GATEWAY_VNC_HOST_PORT }}
CLOUD_RUN_EGRESS_CIDR: ${{ vars.IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR }}
ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY: ${{ vars.IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY }}
TWS_ACCEPT_INCOMING: ${{ vars.IB_GATEWAY_TWS_ACCEPT_INCOMING }}
Expand Down Expand Up @@ -243,6 +251,17 @@ jobs:
"IBKR_2FA_MAX_SUBMISSIONS_PER_WINDOW": os.environ.get("IBKR_2FA_MAX_SUBMISSIONS_PER_WINDOW") or "1",
"IBKR_2FA_SUBMISSION_RESET_SECONDS": os.environ.get("IBKR_2FA_SUBMISSION_RESET_SECONDS") or "0",
}
optional_values = {
"IB_GATEWAY_CONTAINER_NAME": os.environ.get("IB_GATEWAY_CONTAINER_NAME", ""),
"COMPOSE_PROJECT_NAME": os.environ.get("IB_GATEWAY_COMPOSE_PROJECT_NAME", ""),
"IB_GATEWAY_COMPOSE_SERVICE_NAME": os.environ.get("IB_GATEWAY_COMPOSE_SERVICE_NAME", ""),
"IB_GATEWAY_UNIT_SUFFIX": os.environ.get("IB_GATEWAY_UNIT_SUFFIX", ""),
"IB_GATEWAY_LIVE_HOST_PORT": os.environ.get("IB_GATEWAY_LIVE_HOST_PORT", ""),
"IB_GATEWAY_PAPER_HOST_PORT": os.environ.get("IB_GATEWAY_PAPER_HOST_PORT", ""),
"IB_GATEWAY_VNC_HOST_ADDRESS": os.environ.get("IB_GATEWAY_VNC_HOST_ADDRESS", ""),
"IB_GATEWAY_VNC_HOST_PORT": os.environ.get("IB_GATEWAY_VNC_HOST_PORT", ""),
}
values.update({key: value for key, value in optional_values.items() if value})

def quote(value: str) -> str:
return "'" + value.replace("'", "'\"'\"'") + "'"
Expand Down Expand Up @@ -360,15 +379,23 @@ jobs:
set -euo pipefail
cd '${DEPLOY_PATH}'
echo "[\$(date -u +%FT%TZ)] Scheduled keepalive mode: skip docker build"
sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true
set -a
. ./.env
set +a
. ./scripts/ibkr_gateway_units.sh
container_name="\${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}"
compose_service_name="\${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}"
resolve_ibkr_gateway_unit_names "\${container_name}" "\${IB_GATEWAY_UNIT_SUFFIX:-}"
sudo systemctl stop "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "\${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true
sudo systemctl stop "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "\${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true
sudo bash ./scripts/ensure_host_swap.sh
sudo bash ./scripts/install_2fa_bot_watcher.sh
sudo bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}'
sudo bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}'
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_2fa_bot_watcher.sh
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}'
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}'
sudo docker compose ps
sudo systemctl status ibkr-2fa-bot.timer --no-pager
sudo systemctl status ibkr-gateway-healthcheck.timer --no-pager
sudo systemctl status ibkr-gateway-daily-restart.timer --no-pager
sudo systemctl status "\${IBKR_2FA_BOT_TIMER}" --no-pager
sudo systemctl status "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" --no-pager
sudo systemctl status "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" --no-pager
echo "[\$(date -u +%FT%TZ)] Keepalive complete."
EOF
)
Expand All @@ -377,22 +404,30 @@ jobs:
set -euo pipefail
cd '${DEPLOY_PATH}'
echo "[\$(date -u +%FT%TZ)] Full deploy mode: rebuilding container"
sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true
set -a
. ./.env
set +a
. ./scripts/ibkr_gateway_units.sh
container_name="\${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}"
compose_service_name="\${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}"
resolve_ibkr_gateway_unit_names "\${container_name}" "\${IB_GATEWAY_UNIT_SUFFIX:-}"
sudo systemctl stop "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "\${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true
sudo systemctl stop "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "\${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true
sudo bash ./scripts/ensure_host_swap.sh
sudo docker compose build
sudo docker compose build "\${compose_service_name}"
sudo docker compose down
sudo docker compose up -d
sudo docker compose up -d "\${compose_service_name}"

sudo bash ./scripts/install_2fa_bot_watcher.sh
sudo bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}'
sudo bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}'
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_2fa_bot_watcher.sh
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh '${IB_GATEWAY_MODE}'
sudo env IB_GATEWAY_CONTAINER_NAME="\${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="\${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="\${IB_GATEWAY_UNIT_SUFFIX:-}" bash ./scripts/install_gateway_health_watcher.sh '${IB_GATEWAY_MODE}'
sudo docker compose ps
sudo systemctl status ibkr-2fa-bot.timer --no-pager
sudo systemctl status ibkr-gateway-healthcheck.timer --no-pager
sudo systemctl status ibkr-gateway-daily-restart.timer --no-pager
sudo systemctl status "\${IBKR_2FA_BOT_TIMER}" --no-pager
sudo systemctl status "\${IBKR_GATEWAY_HEALTHCHECK_TIMER}" --no-pager
sudo systemctl status "\${IBKR_GATEWAY_DAILY_RESTART_TIMER}" --no-pager

echo "Deployment complete. Bot is monitoring the login window."
echo "Run 'docker exec ib-gateway tail -f /home/ibgateway/2fa.log' for real-time status."
echo "Run 'docker exec \${container_name} tail -f /home/ibgateway/2fa.log' for real-time status."
EOF
)
fi
Expand Down
74 changes: 51 additions & 23 deletions .github/workflows/remote-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
GCE_ZONE: ${{ vars.IB_GATEWAY_ZONE }}
DEPLOY_PATH: ${{ vars.IB_GATEWAY_DEPLOY_PATH }}
IB_GATEWAY_MODE: ${{ vars.IB_GATEWAY_MODE }}
IB_GATEWAY_CONTAINER_NAME: ${{ vars.IB_GATEWAY_CONTAINER_NAME }}
IB_GATEWAY_COMPOSE_SERVICE_NAME: ${{ vars.IB_GATEWAY_COMPOSE_SERVICE_NAME }}
IB_GATEWAY_UNIT_SUFFIX: ${{ vars.IB_GATEWAY_UNIT_SUFFIX }}
SSH_PRIVATE_KEY_SECRET_NAME: ${{ vars.IB_GATEWAY_SSH_PRIVATE_KEY_SECRET_NAME }}
MAINTENANCE_ACTION: ${{ github.event.inputs.action }}
steps:
Expand Down Expand Up @@ -92,38 +95,51 @@ jobs:
)
deploy_path_quoted="$(printf '%q' "${DEPLOY_PATH}")"
gateway_mode_quoted="$(printf '%q' "${IB_GATEWAY_MODE:-paper}")"
container_name_quoted="$(printf '%q' "${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}")"
compose_service_name_quoted="$(printf '%q' "${IB_GATEWAY_COMPOSE_SERVICE_NAME:-ib-gateway}")"
unit_suffix_quoted="$(printf '%q' "${IB_GATEWAY_UNIT_SUFFIX:-}")"

case "${MAINTENANCE_ACTION}" in
stop-2fa-bot)
REMOTE_COMMAND=$(cat <<'EOF'
set -euo pipefail
sudo systemctl stop ibkr-2fa-bot.timer ibkr-2fa-bot.service 2>/dev/null || true
sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true
sudo docker exec ib-gateway pgrep -a -f 2fa_bot.py 2>/dev/null || echo "2FA bot stopped"
sudo systemctl status ibkr-2fa-bot.timer ibkr-2fa-bot.service --no-pager || true
cd __DEPLOY_PATH__
container_name=__IB_GATEWAY_CONTAINER_NAME__
unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__
. ./scripts/ibkr_gateway_units.sh
resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}"
sudo systemctl stop "${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" 2>/dev/null || true
sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true
sudo docker exec "${container_name}" pgrep -a -f 2fa_bot.py 2>/dev/null || echo "2FA bot stopped"
sudo systemctl status "${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" --no-pager || true
EOF
)
;;
restart-2fa-bot)
REMOTE_COMMAND=$(cat <<'EOF'
set -euo pipefail
sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true
sudo /usr/local/bin/ensure-ibkr-2fa-bot-running
sudo docker exec ib-gateway pgrep -a -f 2fa_bot.py
sudo docker exec ib-gateway tail -n 40 /home/ibgateway/2fa.log 2>/dev/null || true
container_name=__IB_GATEWAY_CONTAINER_NAME__
sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true
sudo env CONTAINER_NAME="${container_name}" /usr/local/bin/ensure-ibkr-2fa-bot-running
sudo docker exec "${container_name}" pgrep -a -f 2fa_bot.py
sudo docker exec "${container_name}" tail -n 40 /home/ibgateway/2fa.log 2>/dev/null || true
EOF
)
;;
stop-gateway)
REMOTE_COMMAND=$(cat <<'EOF'
set -euo pipefail
cd __DEPLOY_PATH__
container_name=__IB_GATEWAY_CONTAINER_NAME__
unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__
. ./scripts/ibkr_gateway_units.sh
resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}"
sudo systemctl disable --now \
ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service \
ibkr-gateway-daily-restart.timer ibkr-gateway-daily-restart.service \
ibkr-2fa-bot.timer ibkr-2fa-bot.service 2>/dev/null || true
sudo docker exec ib-gateway pkill -f 2fa_bot.py 2>/dev/null || true
sudo docker update --restart=no ib-gateway 2>/dev/null || true
"${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" \
"${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" \
"${IBKR_2FA_BOT_TIMER}" "${IBKR_2FA_BOT_SERVICE}" 2>/dev/null || true
sudo docker exec "${container_name}" pkill -f 2fa_bot.py 2>/dev/null || true
sudo docker update --restart=no "${container_name}" 2>/dev/null || true
sudo docker compose down
sudo docker compose ps
EOF
Expand All @@ -133,12 +149,17 @@ jobs:
REMOTE_COMMAND=$(cat <<'EOF'
set -euo pipefail
cd __DEPLOY_PATH__
sudo systemctl stop ibkr-gateway-healthcheck.timer ibkr-gateway-healthcheck.service 2>/dev/null || true
sudo systemctl stop ibkr-gateway-daily-restart.timer ibkr-gateway-daily-restart.service 2>/dev/null || true
sudo docker compose up -d --no-build ib-gateway
sudo bash ./scripts/install_2fa_bot_watcher.sh
sudo bash ./scripts/recover_ib_gateway_ready.sh __IB_GATEWAY_MODE__
sudo bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__
container_name=__IB_GATEWAY_CONTAINER_NAME__
compose_service_name=__IB_GATEWAY_COMPOSE_SERVICE_NAME__
unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__
. ./scripts/ibkr_gateway_units.sh
resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}"
sudo systemctl stop "${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_HEALTHCHECK_SERVICE}" 2>/dev/null || true
sudo systemctl stop "${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_SERVICE}" 2>/dev/null || true
sudo docker compose up -d --no-build "${compose_service_name}"
sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_UNIT_SUFFIX="${unit_suffix}" bash ./scripts/install_2fa_bot_watcher.sh
sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="${compose_service_name}" bash ./scripts/recover_ib_gateway_ready.sh __IB_GATEWAY_MODE__
sudo env IB_GATEWAY_CONTAINER_NAME="${container_name}" IB_GATEWAY_COMPOSE_SERVICE_NAME="${compose_service_name}" IB_GATEWAY_UNIT_SUFFIX="${unit_suffix}" bash ./scripts/install_gateway_health_watcher.sh __IB_GATEWAY_MODE__
sudo docker compose ps
EOF
)
Expand All @@ -147,11 +168,15 @@ jobs:
REMOTE_COMMAND=$(cat <<'EOF'
set -euo pipefail
cd __DEPLOY_PATH__
container_name=__IB_GATEWAY_CONTAINER_NAME__
unit_suffix=__IB_GATEWAY_UNIT_SUFFIX__
. ./scripts/ibkr_gateway_units.sh
resolve_ibkr_gateway_unit_names "${container_name}" "${unit_suffix}"
sudo docker compose ps
sudo systemctl status ibkr-gateway-healthcheck.timer ibkr-gateway-daily-restart.timer ibkr-2fa-bot.timer --no-pager || true
sudo docker exec ib-gateway pgrep -a -f "2fa_bot.py|ibgateway|socat|Xvfb|x11vnc|ibcstart" 2>/dev/null || true
sudo docker exec ib-gateway bash -lc 'ss -ltnp 2>/dev/null | grep -E ":(4001|4002|4003|4004|5900)\b" || true' || true
sudo docker exec ib-gateway tail -n 80 /home/ibgateway/2fa.log 2>/dev/null || true
sudo systemctl status "${IBKR_GATEWAY_HEALTHCHECK_TIMER}" "${IBKR_GATEWAY_DAILY_RESTART_TIMER}" "${IBKR_2FA_BOT_TIMER}" --no-pager || true
sudo docker exec "${container_name}" pgrep -a -f "2fa_bot.py|ibgateway|socat|Xvfb|x11vnc|ibcstart" 2>/dev/null || true
sudo docker exec "${container_name}" bash -lc 'ss -ltnp 2>/dev/null | grep -E ":(4001|4002|4003|4004|5900)\b" || true' || true
sudo docker exec "${container_name}" tail -n 80 /home/ibgateway/2fa.log 2>/dev/null || true
EOF
)
;;
Expand All @@ -162,5 +187,8 @@ jobs:
esac
REMOTE_COMMAND="${REMOTE_COMMAND//__DEPLOY_PATH__/${deploy_path_quoted}}"
REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_MODE__/${gateway_mode_quoted}}"
REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_CONTAINER_NAME__/${container_name_quoted}}"
REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_COMPOSE_SERVICE_NAME__/${compose_service_name_quoted}}"
REMOTE_COMMAND="${REMOTE_COMMAND//__IB_GATEWAY_UNIT_SUFFIX__/${unit_suffix_quoted}}"

gcloud compute ssh "${REMOTE_TARGET}" "${SSH_FLAGS[@]}" --command "${REMOTE_COMMAND}"
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ IB_GATEWAY_MODE=paper
IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR=10.128.0.0/20
IB_GATEWAY_GCE_USER=zwlddx0815
IB_GATEWAY_DEPLOY_PATH=/home/zwlddx0815/ib-docker
IB_GATEWAY_CONTAINER_NAME=ib-gateway
IB_GATEWAY_LIVE_HOST_PORT=4001
IB_GATEWAY_PAPER_HOST_PORT=4002
IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY=no
IB_GATEWAY_TWS_ACCEPT_INCOMING=accept
IB_GATEWAY_READ_ONLY_API=no
Expand All @@ -109,6 +112,8 @@ The workflow maps these shared values to the gateway container's `.env`:
- `IB_GATEWAY_ZONE` -> `GCE_ZONE`
- `IB_GATEWAY_GCE_USER` -> `GCE_USER`
- `IB_GATEWAY_DEPLOY_PATH` -> `DEPLOY_PATH`
- `IB_GATEWAY_CONTAINER_NAME` -> Docker container name
- `IB_GATEWAY_LIVE_HOST_PORT` / `IB_GATEWAY_PAPER_HOST_PORT` -> host API ports
- `IB_GATEWAY_TWOFA_DEVICE` -> `TWOFA_DEVICE`
- `IB_GATEWAY_2FA_AUTOFILL` -> `IBKR_2FA_AUTOFILL`

Expand All @@ -128,6 +133,20 @@ sudo bash ./scripts/install_gateway_health_watcher.sh

> Manual `workflow_dispatch` defaults to `keepalive`. If you really need to rebuild the image, choose `deploy_mode=full` when dispatching it.

### Multiple Gateway Sessions on One VM

The default deployment remains one container named `ib-gateway` exposing live/paper API ports `4001`/`4002`. To run another IBKR username on the same VM, use a separate deploy directory or `COMPOSE_PROJECT_NAME`, and give that instance unique container and host ports:

```bash
IB_GATEWAY_CONTAINER_NAME=ib-gateway-u1234567
COMPOSE_PROJECT_NAME=ib-gateway-u1234567
IB_GATEWAY_LIVE_HOST_PORT=4011
IB_GATEWAY_PAPER_HOST_PORT=4012
IB_GATEWAY_UNIT_SUFFIX=u1234567
```

The compose service name stays `ib-gateway` unless you intentionally change the YAML service key. The scripts use `IB_GATEWAY_COMPOSE_SERVICE_NAME` for compose operations and `IB_GATEWAY_CONTAINER_NAME` for `docker exec`/health checks. Systemd watcher units are suffixed automatically when the container name is not the default, so multiple Gateway sessions do not overwrite each other's timers.

### 4. Verify on GCE VM

```bash
Expand Down Expand Up @@ -208,6 +227,12 @@ If you temporarily keep the values in GitHub Secrets during migration, you can r
| `IB_GATEWAY_INSTANCE_NAME` | VM instance name |
| `IB_GATEWAY_ZONE` | VM zone |
| `IB_GATEWAY_MODE` | `paper` or `live` |
| `IB_GATEWAY_CONTAINER_NAME` | Optional Docker container name. Defaults to `ib-gateway`. Use a unique value per Gateway session. |
| `IB_GATEWAY_COMPOSE_PROJECT_NAME` | Optional compose project name. Use this or a unique deploy path when running multiple sessions on one VM. |
| `IB_GATEWAY_COMPOSE_SERVICE_NAME` | Optional compose service name. Defaults to `ib-gateway`; only change it if the compose service key changes. |
| `IB_GATEWAY_UNIT_SUFFIX` | Optional systemd suffix. Inferred from non-default container names when unset. |
| `IB_GATEWAY_LIVE_HOST_PORT` | Optional host port mapped to container live API port `4003`. Defaults to `4001`. |
| `IB_GATEWAY_PAPER_HOST_PORT` | Optional host port mapped to container paper API port `4004`. Defaults to `4002`. |
| `IB_GATEWAY_CLOUD_RUN_EGRESS_CIDR` | Cloud Run Direct VPC egress or connector CIDR (example `10.8.0.0/26`) |
| `IB_GATEWAY_ALLOW_CONNECTIONS_FROM_LOCALHOST_ONLY` | Set to `no` for Cloud Run private IP access |
| `IB_GATEWAY_TWS_ACCEPT_INCOMING` | Optional. Recommended `accept`. |
Expand Down
8 changes: 4 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
services:
ib-gateway:
build: .
container_name: ib-gateway
container_name: ${IB_GATEWAY_CONTAINER_NAME:-ib-gateway}
restart: always
environment:
# Read variables from the host's .env file
Expand Down Expand Up @@ -42,9 +42,9 @@ services:
ports:
# The base image exposes remote API access through socat on container
# ports 4003/4004 while keeping IB Gateway itself localhost-only.
- "4001:4003"
- "4002:4004"
- "${IB_GATEWAY_LIVE_HOST_PORT:-4001}:4003"
- "${IB_GATEWAY_PAPER_HOST_PORT:-4002}:4004"

# VNC Desktop Port for visual monitoring (Default: 5900)
# Strongly recommended to keep blocked by firewall or tunnel only.
- "127.0.0.1:5900:5900"
- "${IB_GATEWAY_VNC_HOST_ADDRESS:-127.0.0.1}:${IB_GATEWAY_VNC_HOST_PORT:-5900}:5900"
Loading