
Automate Kubernetes image updates and deliver Harbor registry events to a private cluster
Keel is a self-hosted Kubernetes operator that updates eligible workloads when new container images become available. In this guide, we install Keel from its official Helm chart, inspect the resulting resources, verify the deployment locally, configure an example workload, and prepare the Harbor webhook route. We then use a Localtonet HTTP tunnel as a separate integration step so an external Harbor registry can reach Keel without opening an inbound router port or assigning a public IP address to the cluster. The workflow deliberately discovers the installed Kubernetes Service and port instead of assuming values that may differ between chart versions or custom configurations.
๐ What's in this guide
How Keel, Harbor, Kubernetes, and Localtonet fit together
Keel runs inside Kubernetes and watches for workloads that opt into automated image updates. Its provider system supports regular Kubernetes resources and Helm releases. Its trigger system can react to registry webhooks, registry polling, and supported pub/sub integrations. This separation matters because the update policy answers one question, while the trigger answers another: the policy determines which image versions are acceptable, and the trigger determines how Keel learns that a candidate image exists.
For a webhook-driven Harbor workflow, Harbor sends an HTTP request after a relevant registry event. Keel accepts Harbor webhook requests at POST /v1/webhooks/harbor, identifies affected workloads, evaluates their annotations and update policy, and updates eligible resources. Keel does not make every Kubernetes workload automatically mutable merely because it is installed. A workload must be configured for Keel, and its policy still controls which updates qualify.
A private cluster creates a networking challenge. Harbor must be able to reach the webhook endpoint, but the Keel Service normally exists only inside the cluster network. Publishing a Kubernetes node, API server, or broad ingress solely to receive one webhook can create unnecessary exposure. A narrower workflow is to make the Keel Service available on a loopback port through Kubernetes port forwarding, then point a Localtonet HTTP tunnel at that local listener.
The Localtonet client establishes an outbound connection to one of our relay servers. The resulting HTTP tunnel provides a public URL without inbound router port forwarding, firewall changes, VPN setup, or a public IP address. The tunnel exists only while the selected Localtonet client is connected and the tunnel is running. Harbor sends requests to the public URL, our relay forwards them through the outbound tunnel, the local Kubernetes port-forward process carries them to the Keel Service, and Keel handles the Harbor route.
A Localtonet HTTP tunnel targets a local IP address and port. It does not, by itself, restrict forwarding to /v1/webhooks/harbor. If the same Keel listener also serves an API or administrative interface, those routes may become reachable through the public URL. Review the installed Keel configuration, enable appropriate Keel authentication where supported, avoid weak credentials, and place a route-filtering reverse proxy in front of Keel if only the Harbor path should be public.
Prerequisites and decisions to make first
Complete the installation from an administrative workstation or a trusted management host that can reach the target Kubernetes cluster. The same machine is a convenient place to run both kubectl port-forward and the Localtonet client, although another device can run the client if it can reach the forwarded service. A loopback-only port forward is reachable only from the machine on which it runs.
Required tools and access
You need a working Kubernetes cluster, kubectl configured for that cluster, and Helm. Keel's current repository identifies Kubernetes and Helm as prerequisites for the Helm quick start. The official documentation also assumes that the active kubectl context can access the intended Kubernetes environment.
Confirm the client tools before changing the cluster:
kubectl version --client
helm version
kubectl config current-context
kubectl cluster-info
If any command fails, fix that prerequisite before installing Keel. A successful client version command confirms that a binary is available, but kubectl cluster-info is the more important access check because it contacts the selected cluster. If you administer multiple clusters, inspect the active context carefully. Installing an operator into the wrong cluster is more consequential than an ordinary local application installation.
The evidence for this workflow does not define minimum Kubernetes or Helm versions. We therefore do not guess a compatibility range. Check the Keel chart and release information against the versions used by your cluster, especially when operating an older Kubernetes environment.
Required permissions
The Helm identity must be permitted to create and manage the resources rendered by the Keel chart in the selected namespace. Later verification also requires permission to read Deployments, Pods, Services, events, and logs. Keel itself needs the Kubernetes permissions created by the chart so it can inspect and update opted-in workloads.
This guide follows the repository's current quick-start command and installs the release named keel into kube-system. The kube-system namespace normally already exists in a Kubernetes cluster. If your organization does not permit application operators there, do not silently substitute a namespace and assume identical behavior. Review the chart configuration, namespace policy, and Helm provider requirements for your environment first.
Registry and workload information
Before enabling automation, identify the exact workloads Keel should manage, their image repositories, whether their tags follow semantic versioning, and whether the images are public or private. For a private Harbor project, the workload must be able to pull the image through the normal Kubernetes mechanism. Keel supports using a Docker registry pull secret referenced by the workload's imagePullSecrets field or by Keel's image-pull-secret annotation.
Harbor project names remain in repository paths. For example, the library project remains part of an image name such as harbor.example.com/library/ai-rag:1.2.3. Do not remove the project segment when configuring the workload or diagnosing registry lookups.
Localtonet requirements
For the remote-access stage, you need a Localtonet account, a device-specific authentication token, and the current Localtonet client for the operating system on the machine that will run the tunnel. Authentication tokens identify client devices and must not be pasted into manifests, logs, screenshots, or this article's example commands. Available relay servers and regions must be selected from the current dashboard rather than copied from an old tutorial.
| Component | Purpose | Verification before installation |
|---|---|---|
| Kubernetes | Runs Keel and the workloads it manages | kubectl cluster-info reaches the intended cluster |
| kubectl | Inspects resources, logs, Services, and events | kubectl config current-context shows the intended context |
| Helm | Installs and manages the Keel chart release | helm version completes successfully |
| Harbor | Stores images and sends registry webhook events | The project, repository path, credentials, and webhook administration access are known |
| Localtonet client | Creates the outbound connection used by the HTTP tunnel | The client can run on a device that can reach the selected local port |
Install Keel on Kubernetes with Helm
The current Keel repository publishes its chart repository at https://keel-hq.github.io/keel/. Some older documentation pages show other repository addresses or older Helm-era instructions. Use one internally consistent installation path rather than combining current and historical commands. The following sequence is based on the current repository quick start.
Confirm the target Kubernetes context
Run kubectl config current-context and verify the result against your intended cluster. If it is wrong, select the correct context using your established Kubernetes administration procedure before continuing.
Add the official Keel chart repository
Register the current chart repository with Helm by running helm repo add keel https://keel-hq.github.io/keel/. Helm uses the local repository name keel in the remaining commands.
Refresh Helm repository metadata
Run helm repo update so Helm retrieves the available chart metadata before installation. This avoids relying on stale local repository information.
Install or upgrade the Keel release
Run helm upgrade --install keel --namespace=kube-system keel/keel. The command creates the release if it does not exist and upgrades the release if it already exists. The Helm provider is enabled by default in this installation path and targets Helm 3. Helm 2 and Tiller are no longer supported.
helm repo add keel https://keel-hq.github.io/keel/
helm repo update
helm upgrade --install keel --namespace=kube-system keel/keel
Do not treat a successful Helm command as the end of verification. Helm may have accepted the release while a Pod remains pending, an image cannot be pulled, or a container repeatedly restarts. Inspect both the release and the Kubernetes resources before configuring workloads or webhooks.
The quick-start command resolves the chart version available from the configured repository. In a controlled production workflow, inspect the available chart versions and values, test the selected version in a non-production cluster, and record the version in your deployment process. This guide does not invent a version pin because the appropriate release depends on the environment and the chart versions currently published.
Optional installation without the Helm provider
Keel's current repository also documents an installation for teams that primarily manage ordinary Kubernetes manifests and do not need Keel to update Helm releases:
helm upgrade --install keel --namespace=keel keel/keel --set helmProvider.enabled="false"
This is an alternative installation, not an additional command to run after the default installation. It uses a different namespace and disables Helm provider support. Choose the provider model before deployment. If you already installed the default release in kube-system, do not run the alternative blindly because it changes the namespace and configuration assumptions used by later commands in this guide.
Keel is stateless for its core operation and does not require a database or persistent disk to obtain workload information from the cluster. Optional capabilities can have additional persistence considerations, so review the chart values before assuming that every type of audit or historical data will survive a restart.
Verify the Keel release, Pods, and Service

Verification should answer four separate questions: did Helm create a release, did the desired Kubernetes workload become available, are the Keel containers healthy, and does the installation expose a Service that can be reached locally? Checking only one of these can hide a partial failure.
Check the Helm release
helm status keel --namespace kube-system
helm list --namespace kube-system
Confirm that the release name and namespace match the installation command. Review the status output and any notes emitted by the chart. If Helm cannot find the release, first verify the current Kubernetes context and namespace rather than reinstalling immediately.
Inspect the Kubernetes resources
kubectl -n kube-system get deployments
kubectl -n kube-system get pods
kubectl -n kube-system get services
Locate the Keel resources in each result. A healthy Pod should eventually report a running state and all expected containers ready. The exact generated names can include chart or release naming conventions, so discover them from the output instead of hardcoding a Pod suffix.
For a more focused inventory, Helm applies release metadata that can be used as a selector:
kubectl -n kube-system get all -l app.kubernetes.io/instance=keel
If a particular chart version does not expose every resource through that selector, return to the unfiltered namespace queries and inspect the Helm manifest:
helm get manifest keel --namespace kube-system
Wait for the Deployment and inspect logs
First discover the Deployment name:
kubectl -n kube-system get deployments
Then substitute that observed name in the following commands:
kubectl -n kube-system rollout status deployment/<keel-deployment-name>
kubectl -n kube-system logs deployment/<keel-deployment-name>
The angle brackets indicate a placeholder, not text to paste literally. If multiple containers exist in the Pod, kubectl may require a container selection. Use kubectl -n kube-system describe pod <pod-name> to inspect container names, conditions, probes, image pull errors, scheduling events, and restart details.
Discover the Service and its ports
The installed Service is the source of truth for the port-forward configuration. Do not assume a Service name, Service port, target port, or Service type from an older example. Discover them:
kubectl -n kube-system get services
kubectl -n kube-system describe service <keel-service-name>
kubectl -n kube-system get service <keel-service-name> -o yaml
Record the Service name and the applicable value under spec.ports. Also verify that the Service has endpoints selected from healthy Keel Pods:
kubectl -n kube-system get endpoints <keel-service-name>
An empty endpoint list usually means the Service selector does not currently match a ready Pod. In that situation, a port-forward may start but requests will not reach a backend reliably. Resolve the Pod readiness or selector issue before adding Harbor or Localtonet.
Create a local-only port forward
Choose an unused local TCP port and map it to the Service port discovered above. The local and Service ports do not have to be the same:
kubectl -n kube-system port-forward service/<keel-service-name> <local-port>:<service-port>
Keep that command running in its terminal. By default, kubectl port-forward provides a local listener suitable for testing from the same machine. Use another terminal for the next request:
curl -i http://127.0.0.1:<local-port>/v1/webhooks/harbor
The Harbor integration expects POST, so a harmless GET may return 404, 405 Method Not Allowed, or another application response. That does not validate a Harbor event, but it can demonstrate that an HTTP server answered through the port forward. A connection-refused error means the local listener is absent or the wrong port was used. A timeout or backend error calls for checking the port-forward terminal, Service endpoints, Pod health, and logs.
Harbor webhook payloads carry event and repository information. Sending a fabricated payload can produce misleading errors or unintended processing. Use Harbor's own webhook test or delivery mechanism after the endpoint is configured, then correlate its delivery record with Keel logs and the targeted workload.
Configure workloads for Keel updates

Installing Keel does not define an update policy for existing applications. Configuration is attached to each eligible workload through annotations or to a Helm release through the relevant chart configuration. This lets teams opt in selectively and apply different risk boundaries to different applications.
Keel supports update automation for Kubernetes Deployments, StatefulSets, and DaemonSets, as well as Helm releases through its Helm provider. The exact rollout behavior after an image change remains subject to the Kubernetes workload specification, including readiness probes, rollout strategy, scheduling constraints, and image pull configuration.
Choose a policy that matches the image tag strategy
| Policy | Intended version behavior | Operational consideration |
|---|---|---|
all |
Accepts version bumps and new prerelease versions | Can move more broadly than minor or patch policies, including prereleases |
major |
Allows major, minor, and patch updates | May accept breaking semantic-version changes |
minor |
Allows minor and patch updates while ignoring major changes | Useful only when the publisher applies semantic versioning consistently |
patch |
Allows patch updates while ignoring minor and major changes | Narrower than minor, but still requires testing and rollback planning |
force |
Supports non-semantic or mutable tags such as latest |
Use tag matching when only a digest change for the same tag should trigger an update |
Keel also documents glob and regex-oriented policy options, but their exact expressions are application-specific. Validate such patterns against the current Keel policy documentation and your real registry tags before enabling unattended changes.
Example semantic-version workload
The following excerpt shows the core annotations for a Deployment that polls its registry and accepts minor and patch changes. Replace the image and complete the omitted workload details using your own tested manifest:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
namespace: default
annotations:
keel.sh/policy: minor
keel.sh/trigger: poll
spec:
template:
spec:
containers:
- name: example-app
image: harbor.example.com/library/example-app:1.2.3
imagePullPolicy: Always
The poll trigger instructs Keel to query the registry rather than waiting only for webhooks. Polling is a practical alternative when exposing an inbound webhook is undesirable or impossible. If this annotation is omitted, Keel's documented default is webhook-driven behavior. Do not add poll merely because it appears in an example if your intended design is Harbor webhook delivery.
Example mutable-tag workload
A mutable tag such as latest does not express a semantic version increase. Keel documents the force policy with tag matching so it can compare the manifest digest while requiring the same tag:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-rag
namespace: default
annotations:
keel.sh/policy: force
keel.sh/trigger: poll
keel.sh/matchTag: "true"
spec:
template:
spec:
containers:
- name: ai-rag
image: harbor.example.com/library/ai-rag:latest
imagePullPolicy: Always
Mutable tags make auditability and rollback more difficult because the tag does not uniquely identify image content. If you use this model, record immutable digests in your deployment evidence and make sure the previous digest remains available for rollback.
Private Harbor projects
Public Harbor projects do not require registry-specific credentials for image lookup. Private projects do. Configure a normal Kubernetes Docker registry pull secret and reference it from the workload through imagePullSecrets, or use the supported Keel image-pull-secret annotation. Never place a Harbor password directly in an annotation, public repository, or article example.
Test image pulls independently of Keel. If a Pod cannot pull its current image, automated updates will not solve the credential or connectivity problem. Inspect Kubernetes events for ImagePullBackOff and related messages, then verify the registry host, project path, secret namespace, secret reference, and certificate trust used by the cluster.
Apply least privilege to Keel, use narrowly scoped policies, test updates outside production, configure readiness and health checks, and maintain a rollback procedure. A valid registry event only means a candidate image exists. It does not prove that the image is compatible with your application, data, or cluster.
Prepare the Harbor webhook workflow
Keel's native Harbor webhook route is:
POST /v1/webhooks/harbor
The final Harbor destination will combine this path with the public URL assigned by the Localtonet HTTP tunnel:
https://<assigned-public-host>/v1/webhooks/harbor
Do not copy the placeholder host. Create and start the tunnel first, then use the exact public URL shown by our platform. HTTP and File Server process types can provide generated subdomains, supported selected subdomains, or custom domains, but availability and DNS requirements can vary. This guide uses the assigned URL and does not invent custom-domain records.
Decide whether webhook delivery is appropriate
Webhooks provide prompt event-driven notification, but they require a reachable endpoint. Polling keeps Keel entirely outbound from the registry-access perspective and avoids publishing a callback endpoint, although updates then depend on polling behavior rather than immediate Harbor delivery. Keel supports both approaches for Harbor.
Use a webhook when event-driven delivery is operationally valuable and you can protect, monitor, and maintain the public endpoint. Prefer polling when public exposure is not acceptable, when the tunnel cannot be kept continuously available, or when Harbor cannot be configured to trust and reach the assigned URL.
Understand the availability chain
A Harbor delivery succeeds only while every component in the chain is available:
- The Keel Pod is ready.
- The Keel Service selects a healthy endpoint.
- The
kubectl port-forwardprocess is running. - The Localtonet client is connected.
- The Localtonet HTTP tunnel is started.
- Harbor can resolve and reach the assigned public URL.
A tunnel configuration that exists in the dashboard is not necessarily running. Likewise, a Localtonet client can be connected while an individual tunnel remains stopped. Monitor the processes and states separately.
Use route minimization when possible
Directly tunneling the Keel Service is simple, but it may expose more routes than Harbor needs. A tighter production design places a local reverse proxy between Localtonet and Keel. The proxy should allow only the required method and path, reject unrelated requests, enforce request-size limits appropriate to Harbor events, and preserve enough logs for troubleshooting without recording credentials or sensitive payloads.
Exact reverse-proxy configuration depends on the proxy software, Keel authentication mode, and your security requirements, so this guide does not fabricate a universal configuration. The important topology is that Localtonet targets the proxy's local port, while the proxy forwards only permitted requests to the locally forwarded Keel Service.
Expose the working Harbor endpoint with Localtonet

Complete this section only after Keel works through the local port forward. That ordering isolates application and cluster problems from tunnel problems. If local access fails, adding a public URL cannot fix the Kubernetes Service, Pod readiness, or port mapping.
Install the current Localtonet client on the machine running the port forward, or on a device that can reach the chosen listener. Installation packages and platform details can change, so obtain the current client through our platform rather than copying an unverified package command. For the dashboard workflow and current fields, consult the Localtonet HTTP tunnel documentation.
Install and run the Localtonet client
Run the current client on the device that can reach the local Keel port forward. The client creates the outbound connection used by our relay. Keep both the client and kubectl port-forward running for webhook availability.
Authenticate or select the client device
Use the device-specific authentication token associated with that client. Treat the token as a secret. Do not embed it in Kubernetes YAML, shell history, Harbor configuration, or public logs.
Select an available relay server
Choose a currently available server or region from the Localtonet dashboard. Available values vary and must not be hardcoded from an article.
Create an HTTP tunnel to the local listener
Configure the local target as the IP address and port where the Keel port forward or protective reverse proxy is listening. For a port forward running on the same device, use its loopback listener and the local port selected during verification. Do not enter the Kubernetes Service port unless it is also the actual local listening port.
Start the tunnel and copy its assigned public URL
Creating a tunnel does not start it. Use the Start button, confirm that the selected client is connected, and copy the public URL assigned to the running HTTP tunnel.
Configure Harbor and test a real delivery
Append /v1/webhooks/harbor to the assigned public URL and enter the resulting HTTPS address in Harbor's webhook configuration. Use Harbor's supported test or event-delivery workflow, then verify the Harbor delivery result, Localtonet tunnel state, Keel logs, and the affected workload.
If the command is kubectl ... port-forward service/... 18080:9300, the Localtonet target is the local listener on port 18080, not the remote Service port 9300. These numbers are illustrative only. Use the local and Service ports you actually discovered and selected.
Verify the public transport path before enabling automation
Once the tunnel is running, make a non-event request to the public Harbor path:
curl -i https://<assigned-public-host>/v1/webhooks/harbor
As with the local test, a method-related application response can prove that the request reached an HTTP service, but it does not prove that a Harbor event is valid or that Keel will update a workload. Compare the public result with the local result. If local access works but public access does not, focus on the Localtonet client state, tunnel state, selected device, local target IP and port, and whether the target listener is reachable from the client process.
After transport verification, use a controlled Harbor project and a non-production workload for the first real event. Confirm all of the following:
- Harbor records a successful or explainable webhook delivery.
- Keel logs show that the request was received and evaluated.
- The repository path, including the Harbor project, matches the workload image.
- The workload has the intended Keel policy and trigger behavior.
- The candidate tag satisfies the configured policy.
- Kubernetes completes the resulting rollout successfully.
A successful HTTP delivery does not guarantee an update. Keel may correctly decline an event because no workload matches the repository, the candidate version falls outside the policy, registry credentials are unavailable, or the current tag and trigger mode do not support the expected comparison.
Routine operations, upgrades, removal, and troubleshooting
Keep the access chain running
The simple tutorial topology includes two long-running local processes: kubectl port-forward and the Localtonet client. Terminal closure, workstation sleep, network interruption, Kubernetes API connectivity loss, token selection changes, or a stopped tunnel can interrupt webhook delivery.
For durable operations, run the components under an approved process supervisor on a trusted host and monitor each layer. This guide does not prescribe a supervisor command because service managers and installation paths differ by operating system. Whatever mechanism you choose should restart failed processes, protect credentials, capture bounded logs, and avoid exposing the port-forward listener beyond the intended local interface.
Inspect health during an incident
Troubleshoot from the inside out. This prevents a Harbor symptom from being misdiagnosed as a tunnel issue when the actual failure is a Kubernetes Pod or Service.
helm status keel --namespace kube-system
kubectl -n kube-system get pods
kubectl -n kube-system get services
kubectl -n kube-system get endpoints <keel-service-name>
kubectl -n kube-system logs deployment/<keel-deployment-name>
curl -i http://127.0.0.1:<local-port>/v1/webhooks/harbor
curl -i https://<assigned-public-host>/v1/webhooks/harbor
| Symptom | Likely layer | Checks to perform |
|---|---|---|
| Keel Pod is pending or restarting | Kubernetes or chart configuration | Describe the Pod, inspect events, image pulls, scheduling, probes, and container logs |
| Service has no endpoints | Service selector or Pod readiness | Compare Service selectors with Pod labels and inspect readiness conditions |
| Local curl reports connection refused | Local port forward | Confirm the process is running and that curl uses the chosen local port |
| Local request works but public request fails | Localtonet client or tunnel | Confirm the selected device is connected, the tunnel is started, and the local target is correct |
| Harbor delivery arrives but no update occurs | Keel matching or policy evaluation | Inspect Keel logs, image repository paths, annotations, version policy, trigger, and registry access |
| Update starts but rollout fails | Application or Kubernetes workload | Inspect rollout status, events, readiness probes, image pull status, and application logs |
Upgrade Keel deliberately
Refreshing repository metadata and running the installation command again upgrades the existing release to the chart version selected by Helm:
helm repo update
helm upgrade --install keel --namespace=kube-system keel/keel
Before a production upgrade, review the chart changes, rendered manifest, image version, values, and release notes. Back up the current Helm values:
helm get values keel --namespace kube-system
helm get manifest keel --namespace kube-system
Store configuration output according to your organization's secret-handling policy because rendered or supplied values can contain sensitive settings. Test the upgrade against representative workloads, verify webhook reception again, and ensure the Service information used by the port forward has not changed.
Stop remote access without uninstalling Keel
Stop the Localtonet tunnel when Harbor no longer needs to reach the endpoint. You can later restart it while the selected client is connected. If the public URL changes after deleting and recreating a tunnel, update Harbor accordingly. Stopping the port-forward process also breaks the path while leaving Keel installed in Kubernetes.
Creating, stopping, and deleting are distinct lifecycle actions. Stop a tunnel for temporary suspension. Delete it when the public configuration is no longer needed. Remove stale webhook destinations from Harbor so it does not continue retrying an intentionally retired endpoint.
Uninstall the Helm release
To remove the release installed by this guide:
helm uninstall keel --namespace kube-system
Verify what remains:
helm list --namespace kube-system
kubectl -n kube-system get all -l app.kubernetes.io/instance=keel
Do not delete the kube-system namespace. It is a core Kubernetes namespace containing system components unrelated to Keel. Namespace deletion guidance from installations that use a dedicated keel namespace does not apply to the kube-system installation in this guide.
Uninstalling Keel does not necessarily revert image changes that Keel previously applied to workloads. Review managed Deployments, StatefulSets, DaemonSets, and Helm releases separately. Remove or revise Keel annotations if they are no longer part of the desired configuration.
Security checklist for an internet-reachable webhook
- Expose the webhook only when event-driven delivery is required.
- Keep the Kubernetes API server, worker nodes, and internal Service addresses private.
- Use a route-filtering proxy if the Keel listener serves more than the Harbor webhook.
- Enable appropriate Keel authentication controls supported by the deployed version.
- Do not reuse example usernames or passwords from old documentation.
- Protect Localtonet device tokens, Harbor credentials, registry pull secrets, and webhook secrets.
- Apply least privilege to the Keel service account and registry credentials.
- Monitor failed webhook deliveries, unexpected paths, repeated requests, and workload changes.
- Stop or delete the tunnel and Harbor webhook when the integration is retired.
- Use polling instead if the public endpoint cannot meet your security requirements.
Frequently asked questions
Does installing Keel immediately update every workload in the cluster?
No. Keel uses workload or Helm release configuration to determine what it should manage and which update policy applies. Installing the operator does not make every Deployment, StatefulSet, DaemonSet, or Helm release automatically accept arbitrary image changes.
What is the Harbor webhook path for Keel?
Keel accepts Harbor webhook requests at POST /v1/webhooks/harbor. Append that path to the public URL assigned to the running Localtonet HTTP tunnel. Use Harbor's supported event delivery rather than fabricating a production webhook payload.
Which port should I enter in the Localtonet HTTP tunnel?
Enter the local port on which kubectl port-forward or your protective reverse proxy is actually listening. Discover the Keel Service and its Service port from the installed cluster, then choose an unused local port for the mapping. Do not assume that the local port, Service port, and container port are identical.
Can Keel work with Harbor without a public webhook?
Yes. Keel supports Harbor through both native webhooks and polling. Polling is useful when exposing an endpoint is undesirable. The workload's trigger and policy must still match the desired behavior, and private projects require appropriate registry credentials.
Does Localtonet require inbound router port forwarding?
No. Our client establishes an outbound connection to a Localtonet relay server. The running HTTP tunnel provides a public URL without inbound router port forwarding, firewall changes, VPN setup, or a public IP address. The selected client must remain connected and the tunnel must remain running.
Does the HTTP tunnel expose only the Harbor webhook route?
Not automatically. A Localtonet HTTP tunnel forwards to a local IP address and port. If that listener serves other paths, those paths may also be reachable through the public URL. Use Keel's appropriate authentication controls and place a route-filtering reverse proxy in front of Keel when only POST /v1/webhooks/harbor should be exposed.
Why did Harbor report a successful delivery without a Kubernetes update?
HTTP delivery and update eligibility are separate stages. Keel may find no matching workload, reject the candidate under the configured semantic-version policy, lack private-registry access, or encounter a repository-path mismatch. Inspect Keel logs, annotations, the full Harbor project and repository path, image tags, and Kubernetes rollout events.
Can I uninstall Keel by deleting the kube-system namespace?
No. For the installation used in this guide, remove only the Helm release with helm uninstall keel --namespace kube-system. Never delete kube-system to remove Keel because that namespace contains essential Kubernetes system components.
Connect your private Keel webhook with Localtonet
After Keel is healthy and its Harbor route works through a local port forward, create a Localtonet HTTP tunnel to provide the controlled public URL Harbor needs. Keep the tunnel limited to the required service, protect the endpoint, and stop it when webhook delivery is no longer required.
Get Started Free โ