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

# Configure PrivateLink

> Connect your self-hosted xpander.ai environment to the deployment manager over AWS PrivateLink — no public internet traffic

## Overview

Your self-hosted xpander.ai environment must connect to the xpander **deployment manager** (the control plane). There are two connectivity options:

| Option                    | URL                                                 | Security                            | Guide                                                                       |
| ------------------------- | --------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------- |
| **Public (TLS)**          | `https://deployment-manager.xpander.ai`             | Encrypted over public internet      | No setup needed — skip to [Install the Helm Chart](/self-hosted/deployment) |
| **Private (PrivateLink)** | `https://deployment-manager-privatelink.xpander.ai` | Encrypted over AWS private backbone | **This guide**                                                              |

Choose **Public** for simplicity or **Private** if your security policy requires traffic to stay within the AWS network.

<Note>
  If you choose the public option, no additional infrastructure is needed. Your cluster nodes just need outbound HTTPS access to the internet (via NAT Gateway if in private subnets). Skip this guide entirely and proceed to [Install the Helm Chart](/self-hosted/deployment) with:

  ```bash theme={"dark"}
  --set urls.deploymentManager=https://deployment-manager.xpander.ai
  ```
</Note>

***

## How PrivateLink Works

AWS PrivateLink is a two-sided connection. xpander exposes the deployment manager as a **VPC Endpoint Service** (provider). You create a **VPC Endpoint** (consumer) in your VPC, which provisions a private ENI with a `10.x.x.x` IP address. Your pods connect to this private IP — traffic goes over the AWS backbone, never the internet.

### xpander VPC Endpoint Service Details

| Property            | Value                                                               |
| ------------------- | ------------------------------------------------------------------- |
| Service Name        | `com.amazonaws.vpce.us-west-2.vpce-svc-0101884b32f655197`           |
| Service Region      | `us-west-2`                                                         |
| Supported Regions   | `us-west-2`, `us-west-1`, `eu-west-2`, `eu-central-1`, `ap-south-1` |
| Acceptance Required | No (auto-accepted for allowed accounts)                             |
| Private DNS Name    | `deployment-manager-privatelink.xpander.ai`                         |

<Warning>
  Contact xpander to have your AWS account ID added as an allowed principal before creating the VPC endpoint.
</Warning>

***

## 1. Create VPC Endpoint

<Warning>
  The xpander endpoint service is in `us-west-2`. If your cluster is in a different region, you **must** include the `--service-region us-west-2` flag. This is the most common mistake — see [Troubleshooting](/self-hosted/troubleshooting#privatelink-invalidservicename-cross-region) if you hit `InvalidServiceName`.
</Warning>

```bash theme={"dark"}
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --vpc-endpoint-type Interface \
  --service-name com.amazonaws.vpce.us-west-2.vpce-svc-0101884b32f655197 \
  --service-region us-west-2 \
  --subnet-ids <PRIVATE_SUBNET_A_ID> <PRIVATE_SUBNET_B_ID> \
  --no-private-dns-enabled \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=xpander-privatelink}]' \
  --region <REGION> --profile <PROFILE>
```

Save the following values from the output:

* `VpcEndpointId` (e.g., `vpce-0abc123...`)
* `Groups[0].GroupId` — the security group ID
* `DnsEntries[0].DnsName` — the endpoint DNS name
* `DnsEntries[0].HostedZoneId` — the hosted zone ID for the alias record

<Tip>
  If your cluster is in `us-west-2` (same region as the service), you can omit `--service-region`.
</Tip>

## 2. Update Security Group

The VPC endpoint is created with the VPC's default security group, which only allows inbound traffic from itself. You must allow HTTPS from your VPC CIDR:

```bash theme={"dark"}
aws ec2 authorize-security-group-ingress \
  --group-id <ENDPOINT_SG_ID> \
  --protocol tcp \
  --port 443 \
  --cidr <VPC_CIDR> \
  --region <REGION> --profile <PROFILE>
```

## 3. Wait for Endpoint to Become Available

The endpoint transitions from `pending` to `available` in 1-3 minutes (auto-accepted):

```bash theme={"dark"}
aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids <VPCE_ID> \
  --query 'VpcEndpoints[0].State' \
  --region <REGION> --profile <PROFILE>
```

## 4. Create Private DNS

Create a private hosted zone so `deployment-manager-privatelink.xpander.ai` resolves to the endpoint ENI inside your VPC:

```bash theme={"dark"}
# Create private hosted zone
aws route53 create-hosted-zone \
  --name deployment-manager-privatelink.xpander.ai \
  --caller-reference "xpander-privatelink-$(date +%s)" \
  --vpc VPCRegion=<REGION>,VPCId=<VPC_ID> \
  --hosted-zone-config PrivateZone=true \
  --profile <PROFILE>
```

Save the `HostedZone.Id` from the output, then create the alias record:

```bash theme={"dark"}
cat <<EOF > /tmp/privatelink-dns.json
{
  "Changes": [{
    "Action": "UPSERT",
    "ResourceRecordSet": {
      "Name": "deployment-manager-privatelink.xpander.ai.",
      "Type": "A",
      "AliasTarget": {
        "DNSName": "<VPCE_DNS_NAME>",
        "HostedZoneId": "<VPCE_HOSTED_ZONE_ID>",
        "EvaluateTargetHealth": true
      }
    }
  }]
}
EOF

aws route53 change-resource-record-sets \
  --hosted-zone-id <PRIVATE_ZONE_ID> \
  --change-batch file:///tmp/privatelink-dns.json \
  --profile <PROFILE>
```

## 5. Verify Connectivity

```bash theme={"dark"}
kubectl run curl-test --restart=Never --image=curlimages/curl:latest -n default \
  --command -- sh -c "curl -sk -o /dev/null -w '%{http_code}' \
  --connect-timeout 10 https://deployment-manager-privatelink.xpander.ai/health; echo"

sleep 15 && kubectl logs curl-test
# Expected output: 200

kubectl delete pod curl-test
```

If you get a timeout or `000`, see [Troubleshooting](/self-hosted/troubleshooting#privatelink-connection-timeout-http-000).

***

## Next Steps

PrivateLink is configured. When you [Install the Helm Chart](/self-hosted/deployment), use the PrivateLink URL:

```bash theme={"dark"}
--set urls.deploymentManager=https://deployment-manager-privatelink.xpander.ai
```
