> ## Documentation Index
> Fetch the complete documentation index at: https://docs.akua.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct IP

> Route traffic directly to your worker nodes using Gateway API and DNS

<Frame>
  <img className="block dark:hidden" src="https://mintcdn.com/akua-1dce587a/KB6u5PJRNHAXrgro/images/heros/direct-ip-light.svg?fit=max&auto=format&n=KB6u5PJRNHAXrgro&q=85&s=a8112da061637906b041e260c94b63c8" alt="DNS A records point a domain at worker node public IPs; an envoy on the host network matches the Host header and routes to the pod." width="1536" height="864" data-path="images/heros/direct-ip-light.svg" />

  <img className="hidden dark:block" src="https://mintcdn.com/akua-1dce587a/KB6u5PJRNHAXrgro/images/heros/direct-ip-dark.svg?fit=max&auto=format&n=KB6u5PJRNHAXrgro&q=85&s=ded0082909f6aa271f81d5bc6f5c961e" alt="DNS A records point a domain at worker node public IPs; an envoy on the host network matches the Host header and routes to the pod." width="1536" height="864" data-path="images/heros/direct-ip-dark.svg" />
</Frame>

With direct IP routing, traffic reaches your applications through your worker nodes' public IP addresses. You point your domains at your workers via DNS, and a <Tooltip headline="Gateway API" tip="Gateway API is the Kubernetes standard for managing external traffic routing. It replaces older Ingress resources with a more expressive, role-oriented model.">Gateway API</Tooltip> controller on the cluster routes requests to the correct application based on the hostname.

This approach is ideal for **self-hosted clusters** where you manage the nodes and have direct access to their public IPs.

## How it works with Akua-managed clusters

Clusters created through Akua use <Tooltip headline="Cilium" tip="Cilium is a networking, observability, and security solution for Kubernetes that uses eBPF. Akua uses it as the default CNI (Container Network Interface), the plugin responsible for pod networking and traffic routing.">Cilium</Tooltip> as the <Tooltip headline="CNI" tip="Container Network Interface: the plugin that handles networking for pods in a Kubernetes cluster. Different CNIs provide different capabilities. Cilium, Calico, and Flannel are common examples.">CNI</Tooltip>, which includes a built-in Gateway API controller. Cilium's envoy proxy runs on every worker via host network mode, listening on ports 80 and 443:

```
Client → worker-node-ip:80 → Cilium envoy (host network) → Route match → Service → Pod
```

The envoy proxy checks the `Host` header against all configured routes and forwards matching traffic to the correct application, regardless of which node the app's pod runs on.

## Imported and cloud-hosted clusters

If you import an existing cluster into Akua, the Gateway API controller depends on your Kubernetes setup:

* **Cloud providers** (GKE, EKS, AKS): these typically include their own Gateway API controller backed by cloud load balancers. Traffic goes through the cloud's load balancer rather than directly to worker node IPs, so you don't need to manage A records yourself.
* **Self-hosted with Cilium**: works the same as Akua-managed clusters. Deploy a Cilium Gateway from your cluster's detail page.
* **Other CNIs**: consult the documentation for your CNI or Kubernetes distribution to set up a Gateway API controller. The route configuration workflow stays the same; only the underlying controller and how traffic enters the cluster differs.

## Prerequisites

* A cluster with a Gateway API controller (Cilium Gateway for Akua-managed and self-hosted clusters, or a cloud-provided controller)
* One or more worker nodes with public IP addresses (for direct IP setups)
* A domain you control with access to its DNS settings

## Set up a custom domain

<Steps>
  <Step title="Expose a port">
    For Packages that expose web ports through Akua's generated install flow, go to the installation's **Settings > Ports** and toggle **Expose externally** on the port you want to make public. Enter your domain (for example, `app.yourdomain.com`) as the hostname.

    For chart sources, configure the route hostname through the Package inputs when the Package exposes those values.
  </Step>

  <Step title="Set up DNS">
    The gateway runs on every worker node, so any worker with a public IP can receive traffic. Choose a DNS strategy based on your setup:

    <Tabs>
      <Tab title="Single worker">
        Create one A record pointing your domain at the worker's public IP:

        | Record type | Name                 | Value              |
        | ----------- | -------------------- | ------------------ |
        | A           | `app.yourdomain.com` | Worker's public IP |
      </Tab>

      <Tab title="Round-robin">
        Add an A record for each worker. DNS automatically distributes requests across them:

        | Record type | Name                 | Value              |
        | ----------- | -------------------- | ------------------ |
        | A           | `app.yourdomain.com` | Worker 1 public IP |
        | A           | `app.yourdomain.com` | Worker 2 public IP |
        | A           | `app.yourdomain.com` | Worker 3 public IP |
      </Tab>

      <Tab title="Shared base record">
        Create A records for a base hostname (for example, `workers.eu.yourdomain.com`) pointing to all workers in a region, then CNAME your app domains to it. When you add or remove workers, you only update the base record:

        | Record type | Name                        | Value                       |
        | ----------- | --------------------------- | --------------------------- |
        | A           | `workers.eu.yourdomain.com` | Worker 1 public IP          |
        | A           | `workers.eu.yourdomain.com` | Worker 2 public IP          |
        | CNAME       | `app.yourdomain.com`        | `workers.eu.yourdomain.com` |
      </Tab>
    </Tabs>

    DNS propagation can take a few minutes to a few hours depending on your provider and TTL settings.
  </Step>

  <Step title="Verify">
    Once DNS has propagated, open `http://app.yourdomain.com` in your browser. The gateway routes the request to your application based on the hostname.
  </Step>
</Steps>

## Test before DNS propagation

You can verify that gateway routing works correctly before creating DNS records. Use `curl` with an explicit `Host` header to simulate what a browser does after DNS resolves:

```bash theme={null}
curl -H 'Host: app.yourdomain.com' http://<server-ip>/
```

Replace `<server-ip>` with your worker node's public IP and `app.yourdomain.com` with the hostname you configured.

* **If you see your app's response**: the routing is correct. Create the DNS record and you're done.
* **If you get a 404 from envoy**: the hostname doesn't match any route. Double-check that the hostname in your app's port configuration matches exactly what you're passing in the `Host` header.

This works because HTTP routing is based entirely on the `Host` header. The `curl` command sends the same header a browser would send after resolving your domain through DNS. The only difference is you're connecting directly to the server IP instead of going through DNS.

## Troubleshooting

<AccordionGroup>
  <Accordion title="404 Not Found from envoy">
    The gateway is running but no route matches the request's `Host` header. Check that:

    * The hostname in your app's port configuration matches your domain exactly.
    * The port has **Expose externally** toggled on.
    * The route was created (check the app's status).
  </Accordion>

  <Accordion title="Connection refused on port 80">
    The gateway's envoy proxy isn't running on the worker node. Verify that:

    * A Cilium Gateway is deployed to the cluster.
    * The gateway pod is running and healthy.
    * Host network mode is enabled in the Cilium configuration.
  </Accordion>

  <Accordion title="Gateway status shows AddressNotAssigned">
    This is normal with Cilium's host network mode. The gateway creates a ClusterIP service (not a LoadBalancer), so the status never reports an external IP. Traffic still flows correctly through the host network envoy proxy.
  </Accordion>

  <Accordion title="DNS not resolving">
    DNS propagation can take time. While waiting, use the `curl` test above to confirm routing works. If `curl` returns your app, the issue is DNS propagation, not routing.
  </Accordion>
</AccordionGroup>

## Related topics

<CardGroup cols={2}>
  <Card title="Networking overview" icon="globe" href="/networking">
    Compare all options for exposing applications.
  </Card>

  <Card title="Cloudflare Tunnel" icon="cloud" href="/networking/cloudflare-tunnel">
    Route custom domains without public IPs.
  </Card>

  <Card title="Preview domains" icon="link" href="/networking/preview-domains">
    Instant URLs managed by Akua.
  </Card>

  <Card title="Add workers" icon="microchip" href="/clusters/add-workers">
    Connect compute with public IPs to your cluster.
  </Card>
</CardGroup>
