--- title: "Troubleshooting" description: "Diagnose and resolve Pangolin Kubernetes deployment issues." --- This page covers troubleshooting Pangolin Kubernetes deployments across Helm, Kustomize, Argo CD, and Flux workflows. Start with the core checks, then use the section that matches the symptom. ## Core diagnostics Set the namespace and release name used by your installation: ```bash export PANGOLIN_NAMESPACE=pangolin export PANGOLIN_RELEASE=pangolin ``` ### Helm diagnostics Check the release: ```bash helm status "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" helm history "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all ``` Render the chart locally with your values file: ```bash helm repo update fossorial helm template "$PANGOLIN_RELEASE" fossorial/pangolin \ --namespace "$PANGOLIN_NAMESPACE" \ --values values-pangolin.yaml ``` Preview an upgrade: ```bash helm upgrade "$PANGOLIN_RELEASE" fossorial/pangolin \ --namespace "$PANGOLIN_NAMESPACE" \ --values values-pangolin.yaml \ --dry-run ``` `helm lint charts/pangolin` is only useful when you are working inside the Helm chart repository. For normal installs, use `helm template` and `helm upgrade --dry-run`. ### Kubernetes diagnostics Check workloads and events: ```bash kubectl get pods --namespace "$PANGOLIN_NAMESPACE" kubectl get deploy,statefulset,job,cronjob --namespace "$PANGOLIN_NAMESPACE" kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp ``` Inspect a pod: ```bash kubectl describe pod --namespace "$PANGOLIN_NAMESPACE" kubectl logs --namespace "$PANGOLIN_NAMESPACE" --all-containers --tail=200 ``` Check services, PVCs, and policies: ```bash kubectl get svc,pvc,secret,configmap --namespace "$PANGOLIN_NAMESPACE" kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE" ``` ### Traefik diagnostics In controller mode, the chart uses Traefik CRDs such as `IngressRoute`. Check whether Traefik CRDs are installed: ```bash kubectl get crd | grep traefik ``` Check rendered or applied Traefik resources: ```bash kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE" kubectl describe ingressroute --namespace "$PANGOLIN_NAMESPACE" ``` Depending on your Traefik setup, also check: ```bash kubectl get middleware,tlsoption,traefikservice --namespace "$PANGOLIN_NAMESPACE" ``` `kubectl get ingress` is only useful if your selected deployment mode renders standard Kubernetes Ingress resources. In controller mode, use `IngressRoute`. ### Database diagnostics If you use CloudNativePG, first check that the CRD exists: ```bash kubectl get crd | grep postgresql.cnpg.io ``` Then check CNPG resources: ```bash kubectl get cluster --namespace "$PANGOLIN_NAMESPACE" kubectl describe cluster --namespace "$PANGOLIN_NAMESPACE" kubectl get pods --namespace "$PANGOLIN_NAMESPACE" | grep -E 'pangolin-db|postgres' kubectl get secret --namespace "$PANGOLIN_NAMESPACE" | grep -E 'pangolin-db|postgres' ``` If you use external PostgreSQL, verify the connection Secret: ```bash kubectl get secret --namespace "$PANGOLIN_NAMESPACE" kubectl describe secret --namespace "$PANGOLIN_NAMESPACE" ``` Do not decode and paste database credentials into logs, screenshots, or issue reports. ## Common issues and solutions **Symptoms** * Gerbil pod crashes during a fresh install. * Logs mention missing setup data, missing exit node, or tunnel configuration not being ready. * Pangolin itself is not initialized yet. **Cause** On first install, Gerbil may start before Pangolin has completed the initial setup. The chart supports `gerbil.startupMode` for this case. **Resolution** Use delayed startup for the first install: ```yaml gerbil: startupMode: delayed ``` Install or upgrade with the values file: ```bash helm upgrade --install "$PANGOLIN_RELEASE" fossorial/pangolin \ --namespace "$PANGOLIN_NAMESPACE" \ --values values-pangolin.yaml ``` After Pangolin setup is complete, switch Gerbil to normal startup: ```bash helm upgrade "$PANGOLIN_RELEASE" fossorial/pangolin \ --namespace "$PANGOLIN_NAMESPACE" \ --reuse-values \ --set gerbil.startupMode=normal ``` Check Gerbil resources: ```bash kubectl get pods,svc,pvc --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=gerbil ``` **Symptoms** * Gerbil pod does not start. * Events mention Pod Security Admission. * Events mention forbidden capabilities. * Logs or events mention `NET_ADMIN`. **Cause** Gerbil requires the `NET_ADMIN` Linux capability for WireGuard interface management. A namespace using a restricted Pod Security profile can block this. **Resolution** Check namespace labels: ```bash kubectl get namespace "$PANGOLIN_NAMESPACE" --show-labels ``` For a namespace running Gerbil, use a policy profile that allows the required capability. Example: ```bash kubectl label namespace "$PANGOLIN_NAMESPACE" \ pod-security.kubernetes.io/enforce=privileged \ pod-security.kubernetes.io/warn=baseline \ pod-security.kubernetes.io/audit=restricted \ --overwrite ``` Then restart the affected pods: ```bash kubectl rollout restart deploy --namespace "$PANGOLIN_NAMESPACE" ``` Do not use a restricted Pod Security profile for Gerbil unless you have validated the selected chart mode and security context. Removing `NET_ADMIN` breaks WireGuard management. **Symptoms** * The dashboard URL does not load. * Browser shows timeout, bad gateway, 404, or TLS error. * API path `/api/v1` fails while the dashboard path works, or the reverse. **Common causes** * DNS points to the wrong load balancer or ingress endpoint. * Traefik CRDs are missing. * Traefik controller is not watching the namespace or selector labels. * `IngressRoute` host does not match the dashboard URL. * API route was changed and no longer matches `PathPrefix(/api/v1)`. * TLS resolver or TLS Secret is misconfigured. **Checks** Check DNS: ```bash nslookup pangolin.example.com ``` Check Traefik CRDs: ```bash kubectl get crd | grep traefik ``` Check IngressRoute resources: ```bash kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE" kubectl describe ingressroute --namespace "$PANGOLIN_NAMESPACE" ``` Check the rendered values: ```bash helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all | grep -A30 ingressRoute ``` Check Traefik logs. Adjust the namespace and label selector to your Traefik installation: ```bash kubectl logs --namespace traefik -l app.kubernetes.io/name=traefik --tail=100 ``` Temporary local check for the dashboard/UI service port: ```bash kubectl port-forward --namespace "$PANGOLIN_NAMESPACE" svc/pangolin 8080:3002 ``` Then open: ```text http://localhost:8080 ``` The dashboard/UI port is `3002`. The API/external port is `3000`. Port-forward `3002` when checking the dashboard locally. **Symptoms** * `IngressRoute` is created but TLS does not work. * Traefik logs mention TLS configuration problems. * Certificate is not issued or the TLS Secret is not found. **Cause** The dashboard `IngressRoute` TLS configuration should use either a Traefik certificate resolver or an existing TLS Secret. **Resolution** Use Traefik ACME certificate resolver: ```yaml pangolin: ingressRoute: dashboard: tls: enabled: true certResolver: letsencrypt secretName: "" ``` Or use an existing TLS Secret: ```yaml pangolin: ingressRoute: dashboard: tls: enabled: true certResolver: "" secretName: pangolin-dashboard-tls ``` Verify the Secret if using `secretName`: ```bash kubectl get secret pangolin-dashboard-tls --namespace "$PANGOLIN_NAMESPACE" ``` `certResolver` is a Traefik ACME resolver setting. It is not a cert-manager issuer reference. **Symptoms** * Newt shows repeated connection or tunnel errors. * Tunnel traffic does not pass. * WireGuard UDP ports are unreachable from the Newt location. **Common causes** * `pangolin.config.gerbil.base_endpoint` points to the wrong host. * Gerbil Service is not exposed as expected. * External firewall blocks UDP traffic. * NetworkPolicy blocks the required traffic. * `pangolin.config.gerbil.start_port` and `gerbil.ports.wg1` are not aligned. * `pangolin.config.gerbil.clients_start_port` and `gerbil.ports.wg2` are not aligned. **Checks** Check Gerbil Service: ```bash kubectl get svc --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=gerbil kubectl describe svc --namespace "$PANGOLIN_NAMESPACE" ``` Check Gerbil values: ```bash helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all | grep -A30 gerbil ``` Check NetworkPolicies: ```bash kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE" kubectl describe networkpolicy --namespace "$PANGOLIN_NAMESPACE" ``` Verify external firewall rules for the configured UDP ports. **Symptoms** * Newt peers do not establish stable handshakes. * Tunnel traffic drops even though Gerbil pods are healthy. * Logs show connection resets or malformed upstream traffic. **Cause** Proxy protocol handling is inconsistent between the upstream hop and Gerbil. If Gerbil is exposed through a reverse proxy or UDP gateway, keep proxy protocol settings aligned end-to-end. Do not enable proxy protocol on the upstream hop unless Gerbil is configured to accept it. **Checks** Check endpoint and port alignment: ```bash helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all | grep -A40 gerbil ``` Check Gerbil logs: ```bash kubectl logs --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=gerbil \ --tail=200 ``` Check Service exposure: ```bash kubectl get svc --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=gerbil -o wide ``` **Symptoms** * Pangolin pod crashes. * Logs mention database connection errors. * Events mention missing Secret or missing Secret key. **Cause** `database.mode=external` needs a valid database connection Secret unless the chart is configured to generate one from values. **Resolution** Create a connection Secret: ```bash kubectl create secret generic pangolin-db-connection \ --namespace "$PANGOLIN_NAMESPACE" \ --from-literal=connectionString='postgresql://pangolin:password@postgres.example.com:5432/pangolin?sslmode=require' ``` Reference it in values: ```yaml database: mode: external connection: existingSecretName: pangolin-db-connection existingSecretKey: connectionString ``` Check the Secret: ```bash kubectl describe secret pangolin-db-connection --namespace "$PANGOLIN_NAMESPACE" ``` Do not put database passwords directly in values files for production. Use an existing Secret or your normal secret-management workflow. **Symptoms** * CNPG Cluster resource is missing. * CNPG pods do not start. * Pangolin cannot connect to the generated CNPG database. * Secret such as `pangolin-db-app` is missing. **Common causes** * CloudNativePG CRDs/operator are not installed. * `cnpg-cluster.enabled` is false when you expected the chart to create a cluster. * `cnpg-operator.enabled` is false and no operator exists. * `database.cloudnativepg.cluster.name` does not match the CNPG cluster name. * StorageClass or PVC provisioning fails. **Checks** Check CRDs: ```bash kubectl get crd | grep postgresql.cnpg.io ``` Check CNPG operator pods: ```bash kubectl get pods --all-namespaces | grep -i cnpg ``` Check CNPG Cluster: ```bash kubectl get cluster --namespace "$PANGOLIN_NAMESPACE" kubectl describe cluster pangolin-db --namespace "$PANGOLIN_NAMESPACE" ``` Check PVCs and Secrets: ```bash kubectl get pvc --namespace "$PANGOLIN_NAMESPACE" kubectl get secret --namespace "$PANGOLIN_NAMESPACE" | grep pangolin-db ``` Expected naming when using the default example: ```yaml database: cloudnativepg: cluster: name: pangolin-db cnpg-cluster: enabled: true fullnameOverride: pangolin-db ``` **Symptoms** * DNS lookups fail. * Pangolin cannot connect to the database. * Controller cannot reach the Kubernetes API. * Gerbil or Newt traffic does not work. * External services such as SMTP, OIDC, or webhooks time out. **Cause** The chart can render NetworkPolicies. If your CNI enforces them, missing egress or ingress rules can break required paths. **Checks** ```bash kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE" kubectl describe networkpolicy --namespace "$PANGOLIN_NAMESPACE" ``` Check whether DNS is allowed: ```yaml networkPolicy: dns: enabled: true ``` Check database egress: ```yaml networkPolicy: database: enabled: true port: 5432 ``` Check controller API access: ```yaml networkPolicy: controller: egress: enabled: true kubernetesApi: enabled: true port: 443 ``` For external integrations, add scoped egress rules for the required services instead of allowing broad egress. For a temporary isolation test, disable NetworkPolicy and re-apply: ```yaml networkPolicy: enabled: false ``` If this fixes the issue, re-enable policies and add the missing rules. **Symptoms** * Pangolin pod restarts repeatedly. * Pod stays Pending. * Readiness never becomes true. **Checks** Find the pod: ```bash kubectl get pods --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=pangolin ``` Inspect it: ```bash kubectl describe pod --namespace "$PANGOLIN_NAMESPACE" kubectl logs --namespace "$PANGOLIN_NAMESPACE" --tail=200 kubectl logs --namespace "$PANGOLIN_NAMESPACE" --previous --tail=200 ``` Check PVCs: ```bash kubectl get pvc --namespace "$PANGOLIN_NAMESPACE" kubectl describe pvc --namespace "$PANGOLIN_NAMESPACE" ``` Common causes: | Status | Common causes | | ------------------ | ----------------------------------------------------------------------------------------------------- | | `CrashLoopBackOff` | Database connection issue, missing Secret, invalid config, startup dependency not ready | | `Pending` | PVC not bound, insufficient resources, node selector/affinity mismatch, Pod Security policy rejection | | `ImagePullBackOff` | Wrong image override, registry access issue, missing imagePullSecret | Do not assume tools such as `psql`, `curl`, or `dig` are available inside the Pangolin container. Use logs, Events, or a temporary debug pod when needed. Run a temporary debug pod for network tests: ```bash kubectl run net-debug \ --namespace "$PANGOLIN_NAMESPACE" \ --rm -it \ --image=curlimages/curl:latest \ --restart=Never \ -- sh ``` **Symptoms** * Helm template or install succeeds, but Traefik resources are not reconciled. * `kubectl get ingressroute` fails with unknown resource type. * Argo CD or Flux reports missing kind `IngressRoute`. **Cause** Controller mode expects Traefik CRDs and a Traefik controller. They must be installed separately or through the bundled dependency when enabled. **Checks** ```bash kubectl get crd | grep traefik kubectl get pods --all-namespaces | grep -i traefik ``` If you want the chart to install the bundled Traefik controller, enable it: ```yaml deployment: type: controller installTraefikController: true ``` If Traefik is already installed elsewhere, keep it disabled and make sure the controller watches the namespace and labels used by the Pangolin `IngressRoute`. **Symptoms** * `helm upgrade` fails. * Rendered resources changed unexpectedly. * Existing resources conflict with chart-managed resources. * GitOps reports immutable field changes or ownership conflicts. **Checks** Render before upgrading: ```bash helm template "$PANGOLIN_RELEASE" fossorial/pangolin \ --namespace "$PANGOLIN_NAMESPACE" \ --values values-pangolin.yaml > rendered.yaml ``` Run a server-side dry run: ```bash kubectl apply -f rendered.yaml --dry-run=server ``` Compare the current live release: ```bash helm get manifest "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" > live-release.yaml diff -u live-release.yaml rendered.yaml ``` Check ownership conflicts: ```bash kubectl get all --namespace "$PANGOLIN_NAMESPACE" -o yaml | grep -E "meta.helm.sh|app.kubernetes.io/managed-by" ``` Avoid `--force` unless you understand which resources will be recreated. `helm upgrade --force` can delete and recreate resources. That can interrupt traffic and may affect persistent workloads depending on the resource type. **Symptoms** * Kustomize build succeeds but changes are missing. * Patch target does not match any resource. * Patch breaks after chart upgrade. **Checks** List generated resource names: ```bash kustomize build base | grep -E "^(kind:| name:)" ``` Validate the overlay: ```bash kustomize build overlays/prod ``` Run a server-side dry run: ```bash kustomize build overlays/prod | kubectl apply -f - --dry-run=server ``` Preview live changes: ```bash kustomize build overlays/prod | kubectl diff -f - ``` Use modern Kustomize `patches` syntax: ```yaml patches: - path: patches/pangolin-resources.patch.yaml target: group: apps version: v1 kind: Deployment name: pangolin ``` For Helm-rendered bases, do not assume resource names. Check the rendered manifests after each chart upgrade. **Symptoms** * Argo CD Application is OutOfSync or Degraded. * Flux HelmRelease or Kustomization is not Ready. * Resources are missing or constantly reverted. **Argo CD checks** ```bash kubectl describe application pangolin --namespace argocd kubectl logs --namespace argocd deployment/argocd-application-controller --tail=100 argocd app diff pangolin argocd app sync pangolin ``` **Flux checks** ```bash flux get sources all --all-namespaces flux get helmreleases --all-namespaces flux get kustomizations --all-namespaces flux logs --all-namespaces --follow ``` Reconcile manually: ```bash flux reconcile helmrelease pangolin --namespace "$PANGOLIN_NAMESPACE" flux reconcile kustomization pangolin --namespace flux-system ``` Common causes: - chart repository or OCI source not reachable - wrong chart version - missing CRDs - invalid values - rendered resource ownership conflict - Secret not available in the expected namespace ## Routing issues to the right repository Use the repository that matches the failing area: | Area | Repository | | ----------------------------------------------------- | ------------------- | | Chart templates, values, examples, rendered manifests | `fosrl/helm-charts` | | Pangolin runtime, API, UI, auth, application behavior | `fosrl/pangolin` | | Newt client behavior or connectivity | `fosrl/newt` | | Documentation | `fosrl/docs-v2` | ## Before opening an issue, collect Collect this information before opening an issue: * chart version * Pangolin app version * Kubernetes version * Helm version * deployment method: Helm, Kustomize, Argo CD, or Flux * sanitized values file * pod logs * namespace events * Traefik logs, if routing is involved * rendered manifests from `helm template` or `kustomize build` * Helm release status or GitOps sync status * reproduction steps Collect basic diagnostics: ```bash kubectl version helm version helm status "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all > pangolin-values.yaml helm get manifest "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" > pangolin-manifest.yaml kubectl get pods --namespace "$PANGOLIN_NAMESPACE" -o wide > pangolin-pods.txt kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp > pangolin-events.txt ``` Before sharing diagnostics, remove: * database passwords * `SERVER_SECRET` * API keys * OAuth/OIDC client secrets * TLS private keys * internal hostnames, if sensitive ## Useful command reference ```bash # General cluster info kubectl cluster-info kubectl version # Namespace overview kubectl get all --namespace "$PANGOLIN_NAMESPACE" kubectl get pvc,secret,configmap --namespace "$PANGOLIN_NAMESPACE" kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp # Logs kubectl logs --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=pangolin \ --tail=200 kubectl logs --namespace "$PANGOLIN_NAMESPACE" \ -l app.kubernetes.io/name=gerbil \ --tail=200 # Dashboard local test kubectl port-forward --namespace "$PANGOLIN_NAMESPACE" svc/pangolin 8080:3002 # Traefik resources kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE" # Resource usage kubectl top pod --namespace "$PANGOLIN_NAMESPACE" kubectl top node ``` ## Next steps Review Pangolin chart options. Install Pangolin with Helm. Install Pangolin with rendered manifests and Kustomize overlays. Deploy Pangolin with Argo CD or Flux.