Skip to main content

Run the controller on 443 with the console on an internal port

End state: the Ziti controller (edge client API, management API, and router control plane) is served on external 443, while the Traefik ingress fronting the Ziti Console is on an internal-only port (8443 in the examples). Applies to NetFoundry Self-Hosted 1.1.0 and later, except 2.0.0, where the console's HTTPS redirect ignores the moved port.

Prerequisites​

  • K3s already running. This procedure reconfigures the Traefik ingress that K3s ships, so K3s must be up before you start Step 1 — do not rely on nf-quickstart to install it here, because Traefik must exist first. If you don't have K3s yet, install it the same way the installer does, then continue:
    curl -sfL https://get.k3s.io | sh -s - --disable local-storage
    nf-quickstart detects and reuses the existing K3s cluster.
  • A DNS name for the controller that resolves to the node's public address. IP addresses are not supported as the controller advertise address.
  • NetFoundry registry credentials (REGISTRY_USERNAME / REGISTRY_PASSWORD) — required to install the Ziti Console Enterprise.
  • The support stack installed (the default). The installer deploys the Enterprise console only alongside the support stack.

Step 1: Move the Traefik ingress to 8443 (before installing)​

On a single K3s node, the controller's LoadBalancer service and the Traefik ingress LoadBalancer both want host port 443 — they cannot both have it. Move Traefik's HTTPS (websecure) entrypoint off 443 first, so 443 is free for the controller. Create a K3s HelmChartConfig that overrides the entrypoint:

cat <<'EOF' | kubectl apply -f -
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
valuesContent: |-
ports:
websecure:
exposedPort: 8443
EOF

If kubectl get helmchartconfig traefik -n kube-system already returns one, add the ports block to its valuesContent with kubectl edit helmchartconfig traefik -n kube-system instead, so the settings already in it are kept.

K3s reconciles Traefik automatically. Confirm the ingress now serves on 8443 and 443 is free:

kubectl get svc traefik -n kube-system -o jsonpath='{.spec.ports}' | tr ',' '\n' | grep -A2 websecure
# websecure ... "port":8443 ...

curl -sk -o /dev/null -w "%{http_code}\n" https://localhost:8443/ # 404 (Traefik up, no route yet)
curl -sk -o /dev/null -w "%{http_code}\n" https://localhost:443/ # connection refused (443 free)

Step 2: Install with the controller on 443​

Run the quickstart and set the controller client API port to 443.

Interactive:

nf-quickstart

When prompted for "What would you like to use as the clientApi port?" enter 443. Provide your controller DNS name and registry credentials when asked, and leave the support stack enabled.

Non-interactive (env file):

cat > env-quickstart.sh <<'EOF'
export CTRL_ADDR=controller.example.com # your controller DNS name
export CLIENT_PORT=443
export REGISTRY_USERNAME='<your-registry-username>'
export REGISTRY_PASSWORD='<your-registry-password>'
EOF

nf-quickstart -y -f env-quickstart.sh

After the install, the host port map looks like this:

Host portServiceExposure
443Ziti controller (edge client API, management API, router control plane)External
8443Traefik ingress → Ziti Console (Enterprise)Internal only
3022Ziti router edge listener (client data plane)External (if clients connect through this appliance)

The Enterprise console is reachable at https://<controller-dns>:8443/.

The controller ships a legacy console (ZAC) served on the controller's own port at https://<controller-dns>:443/zac/. Because it rides the controller port, it is reachable externally on 443. For this deployment pattern — where the console must be internal-only — disable it so nothing console-related is exposed on 443. The Enterprise console on 8443 is unaffected.

Persist the setting in controller-values.yml — do not use a transient helm --set. nf-upgrade re-applies the controller from controller-values.yml, so a --set flag is reverted (and ZAC comes back) on the next upgrade. Edit controller-values.yml (in the install directory, reachable with nf) and add:

console:
enabled: false

Then re-apply only the controller:

nf-upgrade -y --controller
kubectl rollout status deploy/ziti-controller -n ziti
note

Because the setting lives in controller-values.yml, it survives future nf-upgrade runs.

Step 4: Firewall / security group​

"Internal only" is enforced at your network boundary — the port split does not restrict access by itself:

  • Open 443 inbound from the internet (controller edge/management API + router control plane).
  • Open 3022 inbound if endpoints connect to the router on this appliance.
  • Do NOT open 8443 to the internet — leave it reachable only from inside your network so the console stays internal.

Verification​

Run these from a host on the internal network (so 8443 is reachable):

H=controller.example.com

curl -sk -o /dev/null -w "controller :443/version -> %{http_code}\n" https://$H:443/version # 200
curl -sk -o /dev/null -w "legacy ZAC :443/zac/ -> %{http_code}\n" https://$H:443/zac/ # 404 (disabled in Step 3)
curl -sk -o /dev/null -w "console :8443/ -> %{http_code}\n" https://$H:8443/ # 302 (login redirect)

Confirm the controller answers a Ziti login on 443:

ziti edge login $H:443 -u admin -p <admin-password>

The admin password is stored in the ziti-controller-admin-secret secret; nf-install-notes prints it.

Notes​

  • Console DNS. On K3s the console ingress uses the controller DNS name by default. To give the console its own internal hostname, edit ingress.tlsHosts in ziti-console-enterprise-values.yml (in the install directory, reachable with nf) and run helm upgrade ziti-console-enterprise ./helm-charts/ziti-console-enterprise/ -n ziti --values ziti-console-enterprise-values.yml.
  • Any ingress port works. 8443 is used here as an example; substitute any free port in the HelmChartConfig and your firewall rules.
  • HTTPS redirect follows the port. The console's HTTP-to-HTTPS redirect targets Traefik's HTTPS port, read at install and on each nf-upgrade. If you move the port after installing, run nf-upgrade again. See Console HTTPS redirect port.
note

Validated end-to-end on a clean K3s v1.35.5 install with NetFoundry Self-Hosted 1.1.0 (ziti-controller chart 3.2.0): controller reachable and Ziti login succeeding on 443, legacy ZAC returning 404 after Step 3, and the Enterprise console reachable only on 8443.