Unable to configure Controller with split API

Hi all,

I've been building a basic network with 1 controller and 1 router, following the guides for deployment on Linux. When deployed with the usual defaults, everything is working fine.

However, before we put the system into Production, I have been asked to find a way to keep the management APIs for the controller separate, so it won't be accessible to the outside world.

I followed the solution proposed in this forum thread: Securing ZAC and management - openziti to create a new config.yml file, moving ZAC and edge-management onto port 1281, which is allowed by firewall to be only accessible from our internal network. Restarting the service shows that there are indeed now 2 ports open, however when running in this configuration I have experienced issues with configuring the system.

Firstly, when using 'ziti edge login', I have had what I believe to be a similar issue as in this forum thread: Ziti edge login fail because of zac on same port - openziti
Logging in providing localhost:1281 I receive only a screen-full of HTML, which I can only assume is ZAC. If I provide the full edge-management API path it appears to log in, but when I attempt to run a command to create an identity I receive multiple "connection refused" messages.

Secondly, although I am able to log into ZAC, I cannot create identies. When pressing save, I recieve only a message saying "Error Creating Identity - An unknown error occurred". I am unsure how to track ZAC errors to give more details.

The existing router I have on a seperate server appears to connect to the controller fine. I can also see it going online and offline in ZAC when I reboot it. I can also say the same for the 2 windows tunnelers I have installed in my test setup.

One of my suspicions was that the problem was caused by accessing ZAC and the CLI from a different address than the one programmed under the web listener configuration - at the moment the DNS record for this server resolves to it's public IP, on which port 1281 is blocked. Therefore I have been using the direct, private IP to access ZAC, and 'localhost' to access the CLI. However, changing the address section in config.yml did not appear to solve my issues.

Please let me know if I am missing a setting, or if there is a more practical way to go about taking the management UI off of the public internet.

Many thanks for your consideration.

Logs & Files:

Logging into ziti CLI on the controller:

linuxazureroot@<hostname>:~$ ziti edge login https://localhost:1281/edge/management/v1
Enter username: admin
Enter password:
Token: eb51e41b-be39-4837-bd33-6cd8b9d4b622
Saving identity 'default' to /home/linuxazureroot/.config/ziti/ziti-cli.json
linuxazureroot@<hostname>:~$ ziti edge create edge-router "newrouter2" --jwt-output-file newrouter2.jwt
RESTY 2025/03/11 13:14:54 ERROR Post "https://localhost:1281/edge/management/v1/edge-routers": EOF, Attempt 1
RESTY 2025/03/11 13:14:54 ERROR Post "https://localhost:1281/edge/management/v1/edge-routers": dial tcp 127.0.0.1:1281: connect: connection refused, Attempt 2
RESTY 2025/03/11 13:14:54 ERROR Post "https://localhost:1281/edge/management/v1/edge-routers": dial tcp 127.0.0.1:1281: connect: connection refused, Attempt 3
RESTY 2025/03/11 13:14:54 ERROR Post "https://localhost:1281/edge/management/v1/edge-routers": dial tcp 127.0.0.1:1281: connect: connection refused, Attempt 4
RESTY 2025/03/11 13:14:55 ERROR Post "https://localhost:1281/edge/management/v1/edge-routers": dial tcp 127.0.0.1:1281: connect: connection refused, Attempt 5
error: unable to create edge-routers instance in Ziti Edge Controller at https://localhost:1281/edge/management/v1. Error: Post "https://localhost:1281/edge/management/v1/edge-routers": dial tcp 127.0.0.1:1281: connect: connection refused

Relevant part of default config.yml (unchanged from after running bootstrap.bash)

web:
  - name: client-management
    bindPoints:
      - interface: 0.0.0.0:1280
        address: <serverdnsname>:1280
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms  
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-management
        options: { }
      - binding: edge-client
        options: { }
      - binding: fabric
        options: { }
      - binding: zac
        options:
          location: /opt/openziti/share/console
          indexFile: index.html

Relevant portion of my config.yml

web:
  - name: client
    bindPoints:
      - interface: 0.0.0.0:1280
        address: <serverdnsname>:1280
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-client
        options: { }
      - binding: fabric
        options: { }

web:
  - name: management
    bindPoints:
      - interface: 0.0.0.0:1281
        address: <server dns name>:1281 # <-- also tried this line with raw IP, no effect.
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-management
        options: { }
      - binding: zac
        options:
          location: /opt/openziti/share/console
          indexFile: index.html
1 Like

Hello! Welcome to the forum, @control_joe.

CLI

Which version of ziti are you using? It's the package named "openziti." The ziti CLI login bug that manifests with a split API was believed fixed in 1.3.0.

Console

Your example correctly shows the zac binding on the same web listener as the edge-management binding, but you have incorrectly shown a redundant list of web listeners. I expect that's an error since only one list is expected, i.e., a single top-level dict key "web."

I don't know its a problem, but I see you left the fabric api on the 'public' port. Move the fabric api, restart the controller and see if that fixes it. I haven't ever tried this exact configuration myself, I only have ever separated the client api/oidc api. That may be the issue?

Thanks for the response -

I am using Version 1.4.3 of openziti and openziti-controller.

I've updated the file to contain both under a single web key - ZAC now appears to work OK, I can create identities and routers where I couldn't before, thanks!

However, I'm still experiencing the same issue with logging in via the CLI.

New config.yml:

web:
  - name: client
    bindPoints:
      - interface: 0.0.0.0:1280
        address: <serverdnsname>:1280
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms  #http timeouts, new
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-client
        options: { }
      - binding: fabric
        options: { }
  - name: management
    bindPoints:
      - interface: 0.0.0.0:1281
        address: <serverdnsname>:1281
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-management
        options: { }
      - binding: zac
        options:
          location: /opt/openziti/share/console
          indexFile: index.html

I've moved this across to the 'private' port as well - I still have to provide the full URL to log-in, but once I do I can now create identities as I'd expect.

I think I got a little lost on the separation of duties between the different APIs and assumed this one had to be public to allow clients to enrol.

Will I have to reconfigure my routers to point at this new port?

New config with both fixes combined looks like this:

web:
  - name: client
    bindPoints:
      - interface: 0.0.0.0:1280
        address: <serverdnsname>:1280
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms  #http timeouts, new
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-client
        options: { }
  - name: management
    bindPoints:
      - interface: 0.0.0.0:1281
        address: <serverdnsname>:1281
    identity:
      ca:          "pki/root/certs/root.cert"
      key:         "pki/intermediate/keys/server.key"
      server_cert: "pki/intermediate/certs/server.chain.pem"
      cert:        "pki/intermediate/certs/client.chain.pem"
    options:
      idleTimeout: 5000ms
      readTimeout: 5000ms
      writeTimeout: 100000ms
      minTLSVersion: TLS1.2
      maxTLSVersion: TLS1.3
    apis:
      - binding: edge-management
        options: { }
      - binding: fabric
        options: { }
      - binding: zac
        options:
          location: /opt/openziti/share/console
          indexFile: index.html

No. Only the client API and oidc need to be public. The routers connect on the control plane port not the http apis. You'll be fine wrt port. It would only be a problem if you change the DNS entry as that affects the pki.