Migrating from NGINX Ingress¶
This guide covers migrating the Traceable Platform from NGINX Ingress to the Envoy-based routing mode (traceable-router). It applies to both Kurl-based (VM/bare-metal) and cloud-managed Kubernetes deployments.
Overview¶
The legacy NGINX Ingress mode routes external traffic directly to individual platform services using NGINX Ingress objects. Migrating to Envoy mode consolidates all routing, authentication, and header rewriting inside a single traceable-router (Envoy) Service, which can then be fronted by any ingress controller or exposed directly as a cloud load balancer.
Choosing a Migration Option¶
Use the matrix below to identify the right option for your environment before proceeding.
| Option | Deployment | TPA Location | When to use | Guide |
|---|---|---|---|---|
| Option A: Migrate to Traefik | VM / Kurl or cloud-managed Kubernetes | Inside or outside the cluster | Use Traefik as the edge router. For VM / Kurl, deploy Traefik as a DaemonSet with host ports. For cloud, expose Traefik as a LoadBalancer Service. |
Option A |
| Option B: Migrate to DaemonSet Router | VM / Kurl | TPA runs on a separate VM | Run traceable-router as a DaemonSet and bind host ports 80 and 443 directly on every node. |
Option B |
| Option C: LB Type Router | Cloud-managed Kubernetes (EKS / GKE / AKS) | Inside or outside the cluster | Expose traceable-router directly as a cloud LoadBalancer Service. Use this when you do not need a separate ingress controller. |
Option C |
TPA = Traceable Platform Agent.
Prerequisites¶
- Traceable Installer (TI) version: 0.1.344 or later
- Platform version: 1.40.x or later
kubectlaccess to the cluster with sufficient permissions- Access to the Traceable Installer UI with admin credentials
Firewall: Docker Hub domains¶
If your nodes pull images from Docker Hub, allowlist the following domains:
| Domain | Purpose |
|---|---|
*.docker.io |
Docker Hub image registry (includes registry-1.docker.io) |
production.cloudflare.docker.com |
CDN-backed image layer storage |
Reference: Docker Desktop Allowlist
If You Are Running on an Older Version (below 1.40.x)¶
If your platform is currently on a version older than 1.40.x, you must first upgrade to 1.40.2 before performing the NGINX migration. Follow these steps:
Step 1 — Download the 1.40.2 Workflow File¶
Follow the Download Workflow File guide to pull the 1.40.2 workflow bundle to your local machine.
Step 2 — Upload the Workflow File via TI¶
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Upgrade Cluster.
- Click Upload Cluster Version and upload the
workflow-1.40.2.tgzfile. - Select the uploaded version in the dropdown and click Next.
- Review the changes and click Apply.
Step 3 — Complete the Migration¶
Once the workflow file is applied and you are on the Install Workflow page, proceed with the migration steps for your deployment type:
- VM / Kurl-based — Follow Option A: Migrate to Traefik or Option B: Migrate to DaemonSet Router below.
- Cloud (EKS / GKE / AKS) — Follow Option A: Migrate to Traefik or Option C: LB Type Router below.
Step 4 — Upgrade the Platform¶
After the NGINX migration is complete, follow the Upgrading the Platform guide to complete the 1.40.2 upgrade rollout.
Migration Options¶
Choose one of the options below based on your deployment type and desired edge routing model.
⚠️ Downtime notice (VM deployments) On Kurl-based clusters, NGINX binds host ports
80and443directly on every node. Any new component that also requires those host ports — Traefik (Option A) ortraceable-routerin DaemonSet mode (Option B) — will be deployed successfully but its pods will remain inPendingstate until NGINX is removed and the ports are freed. Plan for approximately 5 minutes of downtime between removing NGINX and the new pods becomingRunning.
Option A: Migrate to Traefik¶
Use this option when you want Traefik to remain the external entry point and route traffic to traceable-router through Traefik IngressRoute CRDs.
- VM / Kurl deployments: Deploy Traefik as a
DaemonSetwithhostPortbindings on ports80and443. - Cloud deployments: Deploy Traefik with a
LoadBalancerService so the cloud provider provisions an external load balancer for Traefik.
Step 1 — Install Traefik¶
VM / Kurl: Use Traefik with host ports¶
Deploy Traefik as a DaemonSet so it binds host ports 80 and 443, and expose it via a ClusterIP Service.
Note: The Helm install will succeed, but Traefik pods will remain in
Pendingstate because NGINX is currently holding ports80and443. The pods will start automatically once NGINX is scaled down in Step 4.
Apply the following Helm values override when installing the Traefik chart:
deployment:
enabled: true
kind: DaemonSet
ports:
web:
hostPort: 80
websecure:
hostPort: 443
service:
enabled: true
spec:
type: ClusterIP
ingressClass:
name: traefik
Install Traefik:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik \
--namespace traefik --create-namespace \
-f traefik-values.yaml
Confirm the Helm install succeeded and the ingress class is registered (pods will be Pending at this point — this is expected):
kubectl get pods -n traefik # STATUS: Pending (port conflict with NGINX)
kubectl get ingressclass traefik
Cloud: Use Traefik as a LoadBalancer¶
For cloud-managed Kubernetes clusters, expose Traefik directly with a cloud LoadBalancer Service. The cloud provider provisions the external load balancer, and Traefik forwards traffic to traceable-router using the IngressRoute CRDs rendered by traceable-ingress.
Apply the following Helm values override when installing the Traefik chart:
deployment:
enabled: true
kind: Deployment
service:
enabled: true
spec:
type: LoadBalancer
ports:
web:
port: 80
websecure:
port: 443
ingressClass:
name: traefik
Install Traefik:
helm repo add traefik https://traefik.github.io/charts
helm repo update
helm install traefik traefik/traefik \
--namespace traefik --create-namespace \
-f traefik-values.yaml
Wait for the external IP/hostname to be assigned:
Retrieve the Traefik load balancer address:
kubectl get svc traefik -n traefik \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}{.status.loadBalancer.ingress[0].ip}'
Update your DNS record for traceable.yourcompany.com to point to the Traefik load balancer before validation.
Step 2 — Install traceable-router¶
Deploy the traceable-router Helm chart via the Traceable Installer UI.
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Install Workflow.
- Click on the
traceable-router - Click Helm Upgrade to apply the changes.
Confirm the pod is ready:
Step 3 — Switch traceable-ingress to Envoy + Traefik¶
Update the traceable-ingress chart to render Traefik IngressRoute CRDs that point to traceable-router instead of the legacy per-service NGINX Ingress objects.
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Install Workflow.
- Click on the
traceable-ingress - Open the user values (
user-values.yaml) for thetraceable-ingresschart and add the following:
- Click Helm Upgrade to apply the changes.
Step 4 — Cut Over Traffic and Validate¶
For VM / Kurl deployments, scale down NGINX to release host ports 80 and 443 so Traefik pods can start. For cloud deployments, update DNS to point to the Traefik load balancer address. This lets you validate the new routing path before committing to uninstallation.
⏱️ Downtime starts here (~5 minutes). For VM / Kurl deployments, scaling down NGINX frees host ports
80and443. Traefik pods will transition fromPendingtoRunningwithin a few seconds, after which traffic resumes. For cloud deployments, downtime depends on DNS TTL propagation.
For VM / Kurl deployments, if NGINX is running as a DaemonSet, scale it down by applying a non-matching nodeSelector:
kubectl -n <nginx-namespace> patch daemonset <nginx-daemonset-name> \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"non-existing": "true"}}}}}'
For VM / Kurl deployments, watch Traefik pods come up once the ports are freed:
Step 5 — Validate¶
Verify the new routing path is fully functional:
# Confirm IngressRoutes were created
kubectl get ingressroute -n traceable
# End-to-end check — login page should return 200 or 302
curl -kI https://traceable.yourcompany.com
# Check traceable-router logs for traffic
kubectl logs -n traceable -l app.kubernetes.io/name=traceable-router --tail=50
Step 6 — Uninstall NGINX¶
Once validated, permanently remove NGINX. See Uninstalling NGINX below.
If you need to roll back before uninstalling, see Rolling Back below.
Option B: Migrate to DaemonSet Router¶
In this approach, traceable-router runs as a Kubernetes DaemonSet and binds host ports 80 and 443 directly on every node. This eliminates the need for a separate ingress controller — the Envoy proxy itself acts as the edge.
Step 1 — Upgrade traceable-router to DaemonSet mode¶
Note: The Helm upgrade will succeed, but
traceable-routerpods will remain inPendingstate because NGINX is currently holding ports80and443. The pods will start automatically once NGINX is scaled down in Step 3.
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Install Workflow.
- Click on the
traceable-router - Open the user values (
user-values.yaml) for thetraceable-routerchart and add the following:
- Click Helm Upgrade to apply the changes.
Confirm the Helm upgrade succeeded and the DaemonSet exists (pods will be Pending at this point — this is expected):
kubectl get daemonset -n traceable traceable-router
kubectl get pods -n traceable -l app.kubernetes.io/name=traceable-router -o wide # STATUS: Pending
Step 2 — Switch traceable-ingress to Envoy mode¶
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Install Workflow.
- Click on the
traceable-ingress - Open the user values (
user-values.yaml) for thetraceable-ingresschart and add the following:
- Click Helm Upgrade to apply the changes.
Step 3 — Scale Down NGINX and Validate¶
Before fully removing NGINX, scale it down to release host ports 80 and 443 so traceable-router pods can start. This lets you validate the new routing path before committing to uninstallation.
⏱️ Downtime starts here (~5 minutes). Scaling down NGINX frees host ports
80and443.traceable-routerpods will transition fromPendingtoRunningwithin a few seconds, after which traffic resumes.
If NGINX is running as a DaemonSet, scale it down by applying a non-matching nodeSelector:
kubectl -n <nginx-namespace> patch daemonset <nginx-daemonset-name> \
-p '{"spec": {"template": {"spec": {"nodeSelector": {"non-existing": "true"}}}}}'
Watch traceable-router pods come up once the ports are freed:
Step 4 — Validate¶
Verify the new routing path is fully functional:
# End-to-end check — login page should return 200 or 302
curl -kI https://traceable.yourcompany.com/
# Check traceable-router logs for traffic
kubectl logs -n traceable -l app.kubernetes.io/name=traceable-router --tail=50
Step 5 — Uninstall NGINX¶
Once validated, permanently remove NGINX. See Uninstalling NGINX below.
If you need to roll back before uninstalling, see Rolling Back below.
Option C: LB Type Router¶
Use this option if you are running Traceable on a managed Kubernetes cluster and want to expose traceable-router directly through a cloud LoadBalancer Service.
⚠️ Downtime notice (cloud deployments) Unlike VM deployments, NGINX on cloud clusters does not bind host ports directly on nodes, so
traceable-routercan be provisioned as a LoadBalancer Service independently — pods will not enter aPendingstate due to port conflicts. However, approximately 5 minutes of downtime occurs at the DNS cutover: until the DNS TTL expires and clients refresh, agents and users will continue to send traffic to the old NGINX load balancer. To minimise this window, lower the TTL of your DNS record to 60 seconds at least one full TTL cycle before starting the migration (e.g. if your current TTL is 3600 seconds, lower it 1 hour in advance) and restore it after.
Step 1 — Deploy traceable-router with a LoadBalancer Service¶
Switch traceable-ingress to Envoy mode with controller: none and expose traceable-router directly via a cloud LoadBalancer Service. No ingress controller is needed.
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Install Workflow.
- Click on the
traceable-router - Open the user values (
user-values.yaml) and update both charts as follows:
# traceable-router values
httpEnabled: false
httpsEnabled: true
service:
type: LoadBalancer
primaryPortDef:
name: https
port: 443
targetPort: https
secondaryPortDef:
port: 0
- Click Helm Upgrade to apply the changes.
- Click on the
traceable-ingress - Open the user values (
user-values.yaml) and update both charts as follows:
- Click Helm Upgrade to apply the changes.
For TLS passthrough or ACM-terminated TLS on AWS, see the AWS EKS scenarios in the Platform Connectivity guide.
Wait for the external IP/hostname to be assigned:
Step 2 — Point DNS to the New Load Balancer¶
Retrieve the new load balancer address:
kubectl get svc traceable-router -n traceable \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}{.status.loadBalancer.ingress[0].ip}'
Update your DNS record for traceable.yourcompany.com:
- Create a CNAME record if the output is a hostname (typical on EKS with NLB).
- Create an A record if the output is an IP address (typical on GKE/AKS).
Allow DNS TTL to propagate before proceeding.
Step 3 — Validate¶
# Service should show an external address
kubectl get svc traceable-router -n traceable
# End-to-end
curl -kI https://traceable.yourcompany.com/
Step 4 — Uninstall NGINX Ingress¶
Once validated, permanently remove NGINX. See Uninstalling NGINX below.
If you need to roll back before uninstalling, see Rolling Back below.
Uninstalling NGINX¶
Self-managed NGINX (installed independently)¶
If you installed NGINX yourself (outside of the Traceable installer), uninstall it using whichever method you used to deploy it.
Helm-managed:
# Find the release name and namespace
helm list -A | grep nginx
helm uninstall <release-name> --namespace <namespace>
YAML-managed:
# Delete all nginx-ingress resources applied from a manifest
kubectl delete -f nginx-ingress-deploy.yaml
# Or delete by label selector if the manifest is unavailable
kubectl delete all,clusterrole,clusterrolebinding,ingressclass \
-l app.kubernetes.io/name=ingress-nginx --all-namespaces
Verify removal:
NGINX deployed via Traceable Installer¶
If NGINX was installed and managed by the Traceable installer (i.e. the traceable-nginx chart is present in your cluster), disable it through the installer rather than deleting it manually.
- Log in to the Traceable Installer (TI) using your admin credentials.
- Navigate to Upgrade Cluster.
- Click on Upgrade Operator.
- Add the following in the helm override section:
- Click Trigger Upgrade to apply the changes.
Verify the NGINX pods are terminated:
Rolling Back¶
If you need to revert to NGINX before permanently uninstalling it, restore the NGINX DaemonSet by removing the temporary nodeSelector patch:
kubectl -n <nginx-namespace> patch daemonset <nginx-daemonset-name> \
--type json \
-p='[{"op": "remove", "path": "/spec/template/spec/nodeSelector/non-existing"}]'
This scales NGINX back up. Once NGINX pods are Running again, revert the traceable-ingress and traceable-router Helm values through the Traceable Installer.
Post-Migration Checklist¶
-
traceable-routerpod isRunning - DNS resolves to the new load balancer / Traefik host port
-
https://traceable.yourcompany.com/returns HTTP200or302 - NGINX pods and ingress resources are gone (
kubectl get pods,ingress -A | grep nginx) - Agent connectivity is confirmed (agents send traces and receive config)
- Installer UI (TI) WebSocket (
/ti/ws) is functional
Troubleshooting¶
502 / 503 after switching to Envoy mode¶
Envoy's HTTP listener speaks h2c (HTTP/2 cleartext) on port 8000. Ensure the ingress controller targets port 8000 with HTTP/2 enabled. For Traefik this is handled automatically by the rendered IngressRoute; for other controllers verify backend-protocol: h2c or equivalent.
Login redirects to wrong hostname or loops¶
Ensure passHostHeader: true is set so the original Host header reaches Envoy. Envoy uses the :authority header to build login redirect URLs.
WebSocket (/ti/ws) drops¶
The /ti/ws path must use HTTP/1.1. The Traefik templates in traceable-ingress render a dedicated route for this automatically. For custom setups, ensure Upgrade headers are forwarded and the path is not forced to HTTP/2.
DNS not resolving after update¶
Check TTL expiry (dig traceable.yourcompany.com +ttl) and confirm the old NGINX-facing CNAME or A record has been replaced. During transition, both paths can coexist until the TTL drains.
Traceable Installer UI is inaccessible¶
If the TI UI is unreachable (for example, during the migration window while NGINX is down), you can access it directly via kubectl port-forward:
- Port-forward the
traceable-installer-0pod to your local machine:
-
Open a browser and navigate to
http://<node-ip>:8000(orhttp://localhost:8000if running locally). -
Log in using your TI admin credentials.
Note: Ensure port
8000is allowed through your firewall/security group on the machine where you are running the port-forward command.
Related Guides¶
- Platform Connectivity — full reference for all routing options and TLS strategies
- Overriding Helm Chart Values
- Upgrading the Platform
- TLS Certificates
- Update DNS
Support¶
For migration assistance, contact support@harness.io.
When requesting support, provide:
- Your deployment type (Kurl/VM or cloud-managed Kubernetes)
- The
traceable-ingressandtraceable-routervalues currently in use - Output of
kubectl get svc,ingress,ingressroute,pods -n traceable - Relevant
traceable-routerand ingress controller pod logs