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

# Deploy Gateways Without Public IPs

> This guide explains how to deploy an Aviatrix gateway without a public IP address using the Assign Private IP Only setting, covering prerequisites, the CoPilot procedure, and connectivity verification.

Deploy an Aviatrix gateway in a private subnet without assigning it a public IP
address, using the **Assign Private IP Only** setting. This guide covers
prerequisites, the CoPilot procedure for enabling Assign Private IP Only on a
new Spoke or Transit Gateway, and how to verify that the gateway keeps
connectivity to the Aviatrix Controller (and CoPilot, if deployed) without
direct internet access.

This guide covers greenfield deployment of a new gateway with Assign Private IP
Only enabled. It does not cover gateway high availability — see

<a href={"/docs/enterprise/" + "10.1" + "/guides/gateways/gateway-ha-about"}>High Availability Gateways</a>
to configure HA instances after deployment.

<Note>
  Assign Private IP Only is a different capability from the **Private Mode**
  global Controller setting described in the

  <a href={"/docs/enterprise/" + "10.1" + "/reference/general/aviatrix-glossary#private-mode"}>Aviatrix glossary</a>
  . Private Mode routes gateway traffic through web proxies and native cloud
  constructs as a Controller-wide setting. Assign Private IP Only is a per-gateway
  setting that relies on your subnet's route table to reach the Controller. As of
  Controller 10.1.0, Private Mode is no longer accessible through the product UI.
</Note>

## Prerequisites

Before you deploy a gateway with Assign Private IP Only, confirm the following:

* Your Aviatrix Controller is running version 10.1.0 or later, and CoPilot is
  running version 4.36 or later.
* Assign Private IP Only supports gateway creation and replacement for **AWS**
  and **Azure** Transit and Spoke Gateways only. It is not available for GCP,
  OCI, or Alibaba Cloud gateways in this release.
* If your Controller currently has the legacy Private Mode global setting
  enabled, disable it before upgrading. A Controller with the legacy setting
  enabled cannot upgrade to a version that includes this feature.
* The subnet you deploy into does not need direct internet access, but its route
  table must have one of the following:
  * A default route (`0.0.0.0/0`) to a NAT gateway or other centralized egress
    path (for example, a transit gateway, VPN gateway, or peering connection)
    that can reach the Controller's public IP.
  * An explicit `/32` route to the Controller's IP address, and to CoPilot's IP
    address if CoPilot is deployed.
* If gateways deployed this way need to tunnel to each other across VPC/VNets,
  private connectivity must already exist between them (native VPC/VNet peering,
  a transit gateway, or equivalent) — gateways with Assign Private IP Only
  enabled do not establish tunnels over the public internet.
* The public IP address of the NAT gateway or firewall that provides the
  gateway's egress path must be added to **NAT-ed Gateway IP Address CIDRs** on
  the Controller (`aviatrix_controller_security_group_management_config`'s
  `gateway_egress_cidrs` in Terraform), so the Controller and CoPilot accept
  management traffic from it.

<Note>
  - This setting applies to the entire gateway, including any HA instance you add
    later, and cannot be changed after you create the gateway. To move a gateway
    between Assign Private IP Only and a public-IP deployment, delete and recreate
    it.
  - Assign Private IP Only does not support air-gapped environments — the gateway
    still requires an outbound path to the internet, even though the path does not
    need to be direct.
  - Single-IP SNAT is not supported on a gateway with Assign Private IP Only
    enabled. Use Customized SNAT instead, including for Kubernetes egress use
    cases.
  - A third-party IPsec connection cannot terminate on a gateway with Assign
    Private IP Only enabled.
</Note>

## Enable Assign Private IP Only on a New Gateway

<Steps>
  <Step title="Open the gateway creation dialog">
    In Aviatrix CoPilot, go to **Cloud Fabric** > **Gateways** > **Spoke Gateways**
    (or **Transit Gateways**), then click **+ Spoke Gateway** (or **+ Transit
    Gateway**).
  </Step>

  <Step title="Configure the gateway and select a subnet">
    Provide the **Cloud**, **Account**, **Region**, and **VPC/VNet** for the
    gateway. In **Attach to Subnet**, select a subnet whose route table meets the
    [Prerequisites](#prerequisites) — a subnet routed through a NAT gateway or other
    centralized egress path, or a subnet with an explicit route to the Controller's
    (and CoPilot's) IP address.
  </Step>

  <Step title="Expand Advanced Settings">
    Expand **Advanced Settings**.
  </Step>

  <Step title="Turn on Assign Private IP Only">
    Turn on **Assign Private IP Only**. This deploys the gateway without a public IP
    address; the gateway still requires internet access to communicate with the
    Controller through another existing path, such as a NAT gateway on its subnet.

    <Note>
      If the gateway also has High Performance Encryption enabled, CoPilot displays an
      additional **Gateway Internet Egress Next Hop** field. Specify where the gateway
      should route outbound traffic — a NAT gateway ID, an IP address (Azure only), or
      any other valid next hop.
    </Note>
  </Step>

  <Step title="Complete the remaining gateway settings">
    Configure any remaining required fields, then click **Save**.
  </Step>
</Steps>

## Verify the Deployment

* In **Cloud Fabric** > **Gateways** > **Spoke Gateways** (or **Transit
  Gateways**), confirm the new gateway's **Status** shows **Up**.
* Click the gateway name to open its Details tab. Confirm **GW Instance Public
  IP** shows **None** and **GW Instance Private IP** shows an address.
* If the gateway is attached to a Transit Gateway or has active tunnels, confirm
  the attachment or connection **Status** shows **Active** (or **Up**).
* Confirm the gateway shows as connected to the Controller (and to CoPilot, if
  deployed) despite having no public IP.

<Note>
  If the gateway does not come up or does not connect to the Controller, recheck
  the subnet's route table against [Prerequisites](#prerequisites) — a missing NAT
  gateway route, a missing `/32` route to the Controller, or an unreachable
  CoPilot path are the most common causes.
</Note>

## Deploy a Kubernetes Firewall Gateway

Use this pattern to deploy an Aviatrix gateway for Distributed Cloud Firewall
(DCF) enforcement and source address translation for an existing Kubernetes
cluster. The gateway sits inline in the cluster VPC or VNet, between the
worker-node subnet and its existing internet egress, so all pod traffic passes
through it for inspection. It does not become the cluster's primary routing
fabric.

<Note>
  This section assumes your cluster is already onboarded to DCF and worker-node
  SNAT is disabled, as described in

  <a href={"/docs/enterprise/" + "10.1" + "/reference/dcf/kubernetes-prerequisites"}>Kubernetes Onboarding Prerequisites</a>
  . DCF identifies workloads by pod source IP; if worker nodes still perform SNAT,
  DCF sees only the node IP and per-pod policy does not work.
</Note>

**How this pattern works:**

* The Aviatrix gateway runs with **Assign Private IP Only** enabled in the same
  VPC or VNet as the Kubernetes cluster, so it adds no new public IP surface.
* You redirect the worker-node subnet's outbound traffic to the gateway, so DCF
  can see and enforce policy on individual pod IPs.
* Because the gateway, not the worker nodes, now performs source address
  translation, you configure **Customized SNAT** on the gateway for pod egress
  instead of relying on node-level SNAT.
* Translated traffic continues to your existing centralized egress (a transit
  attachment to centralized NAT, or the cluster VPC's own NAT gateway).

<Steps>
  <Step title="Deploy the gateway into the cluster VPC">
    Deploy a Spoke Gateway into a private subnet in the same VPC or VNet as the
    Kubernetes cluster, following
    [Enable Assign Private IP Only on a New Gateway](#enable-assign-private-ip-only-on-a-new-gateway).
    In a mature landing zone, the gateway's outbound path is often the transit
    gateway attachment the cluster already uses to route to centralized egress.
  </Step>

  <Step title="Validate management connectivity">
    Before you change any cluster routing, confirm the gateway shows connected to
    the Controller (and CoPilot, if deployed) as described in
    [Verify the Deployment](#verify-the-deployment).
  </Step>

  <Step title="Redirect worker-node subnet traffic to the gateway">
    Point the worker-node subnet's outbound route at the gateway so its traffic is
    inspected:

    * **AWS**: Edit the route table associated with the worker-node subnet so the
      relevant route (for example, `0.0.0.0/0`) targets the Aviatrix gateway's
      elastic network interface instead of the NAT gateway or transit attachment it
      currently uses. If the cluster already routes through an AWS Transit Gateway,
      you can instead enable **Transparent Inspection via AWS TGW** on the Spoke
      Gateway to inspect the traffic without editing the VPC route table, and use
      **Customize Inspection by Route Tables** to limit inspection to the
      worker-node subnet's route table.
    * **Azure**: Add or edit a user-defined route (UDR) on the worker-node subnet's
      route table so the relevant route targets the gateway's private IP address
      with next hop type **Virtual appliance**.

    <Warning>
      Changing the worker-node subnet's route table affects live traffic. Make this
      change during a maintenance window, and confirm the gateway shows **Up** first.
    </Warning>
  </Step>

  <Step title="Configure Customized SNAT for pod egress">
    On the gateway, go to **Cloud Fabric** > **Gateways**, select the gateway, open
    its **Settings** tab, and expand **Network Address Translation (NAT)**. Turn on
    **Source NAT**, click **Customized SNAT**, then click **+ Rule** and enter:

    | Field            | Value                                                                  |
    | ---------------- | ---------------------------------------------------------------------- |
    | Source CIDR      | The cluster's pod CIDR                                                 |
    | Destination CIDR | Leave blank to match all internet-bound traffic                        |
    | SNAT IPs         | A secondary private IP on the gateway, or another address you nominate |

    Click **Save**, then turn on **Apply Route Entry** to commit the rule.
  </Step>

  <Step title="Validate pod-to-internet connectivity">
    From a pod, curl an external address and confirm the response reaches the pod.
    Then confirm the translation is working as expected:

    * Check DCF flow logs in CoPilot — connections initiated by the pod should show
      the pod's original IP as the source before the gateway, and the **SNAT IPs**
      address after the gateway.
    * Confirm the traffic continues through your environment's centralized egress (a
      transit attachment to centralized NAT, or the cluster VPC's existing NAT
      gateway).
  </Step>
</Steps>

<Note>
  Disable SNAT on Kubernetes worker nodes as described in

  <a href={"/docs/enterprise/" + "10.1" + "/reference/dcf/kubernetes-snat"}>Disable SNAT for Kubernetes Workloads</a>
  . That setting is separate from Customized SNAT on the Aviatrix gateway, which
  handles pod-egress translation at the gateway. Size the shared egress path for
  both management traffic and NAT'd pod workload traffic.
</Note>

## Deploy in Terraform

Assign Private IP Only is configurable through the Aviatrix Terraform provider
using the `private_network` argument on the gateway group resource and the
`private_subnet_egress_target` argument on the gateway instance resource:

```hcl theme={null}
resource "aviatrix_spoke_group" "this" {
  name            = "private-spoke"
  cloud_type      = 1 # AWS
  account_name    = var.account
  vpc_id          = var.vpc_id
  private_network = true
}

resource "aviatrix_spoke_instance" "this" {
  name                          = "private-spoke-gw"
  group_name                    = aviatrix_spoke_group.this.name
  private_subnet_egress_target  = "nat-xxxxxxxx" # or transit attachment ID
  # allocate_new_eip and eip do not apply to private-network instances
}

resource "aviatrix_controller_security_group_management_config" "this" {
  gateway_egress_cidrs = ["203.0.113.50/32"] # public address of your NAT or firewall egress
}
```

`gateway_egress_cidrs` is the Terraform equivalent of **NAT-ed Gateway IP
Address CIDRs** on the Controller.

For Transit Gateways, use the equivalent `aviatrix_transit_group` and
`aviatrix_transit_instance` resources. See the

<a href={"/docs/enterprise/" + "10.1" + "/reference/terraform/provider"}>
  Aviatrix Terraform provider
</a>

reference for the full set of arguments.

<Note>
  Do not enable Single IP SNAT (`enable_nat`) on a private-network group.
</Note>

## Related Topics

* <a href={"/docs/enterprise/" + "10.1" + "/reference/terraform/provider"}>Aviatrix Terraform provider</a>
  — configure Assign Private IP Only through the Aviatrix Terraform provider.
* <a href={"/docs/enterprise/" + "10.1" + "/guides/gateways/gateway-ha-about"}>High Availability Gateways</a>
  — configure HA instances for a gateway after deployment.
* <a href={"/docs/enterprise/" + "10.1" + "/reference/general/aviatrix-glossary#private-mode"}>Private Mode (legacy glossary entry)</a>
  — the separate, older global Controller setting. As of Controller 10.1.0,
  Private Mode is no longer accessible through the product UI.
* <a href={"/docs/enterprise/" + "10.1" + "/reference/dcf/kubernetes-prerequisites"}>Kubernetes Onboarding Prerequisites</a>
  — onboard a cluster to DCF and disable worker-node SNAT before deploying a
  Kubernetes firewall gateway.
* <a href={"/docs/enterprise/" + "10.1" + "/reference/dcf/kubernetes-snat"}>Disable SNAT for Kubernetes Workloads</a>
  — the worker-node SNAT setting required for per-pod DCF policy.
