What rewrites and loads endpoints.yml when ctrl.endpointsFile is commented out?

Hi,

We are running OpenZiti Router v2.0.4. Our controller is exposed through an nginx TCP/SNI proxy on public port 443; its internal listener uses port 1280.

The router configuration contains:

ctrl:
  endpoint: tls:controller.example.com:443
  #endpointsFile: /var/lib/ziti-router/endpoints.yml

The public 443 endpoint works. Connecting directly to public port 1280 does not, as that port is only used internally behind nginx.

Despite endpointsFile being commented out, the router logs:

loading controller endpoints from [endpoints.yml]

The router successfully bootstraps through 443, but then receives this update from the controller:

update ctrl endpoints message received
endpoints=["tls:controller.example.com:1280"]

Afterward, endpoints.yml contains:

controllers:
  - id: controller
    endpoints:
      - address: tls:controller.example.com:1280

endpoints:
  - tls:controller.example.com:1280

Controller configuration:

v: 3

cluster:
  dataDir: "/var/lib/ziti-controller/raft"

ctrl:
  listener: tls:0.0.0.0:1280
  options:
    advertiseAddress: tls:controller.example.com:443

edge:
  api:
    sessionTimeout: 30m
    address: controller.example.com:443

web:
  - name: client
    bindPoints:
      - interface: 0.0.0.0:1280
        address: controller.example.com:443
    apis:
      - binding: edge-client
        options: {}
      - binding: edge-oidc
        options: {}
      - binding: health-checks
        options: {}

Questions:

  1. Why does the router default to endpoints.yml when ctrl.endpointsFile is not configured?
  2. Why does the generated endpoint use the controller’s internal listener port 1280 instead of the externally reachable 443 address?
  3. What takes precedence between ctrl.endpoint and the generated endpoints.yml?
  4. What is the supported configuration for preventing the router from learning or loading the unreachable internal endpoint?