# Deploy the private network + VPN template with OpenTofu

Source: https://docs.quake.ai/resources/deployments/deploy-private-network-vpn-template
Markdown: https://docs.quake.ai/resources/deployments/deploy-private-network-vpn-template.md
> Stand up a WireGuard site-to-site VPN gateway on a private subnet with one floating IP using the private-network-vpn OpenTofu template.

---

# Deploy the private network + VPN template with OpenTofu

Stand up a WireGuard site-to-site VPN gateway on a private subnet using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `private-network-vpn`. One floating IP terminates UDP traffic for the tunnel; cloud-init installs WireGuard and writes `/etc/wireguard/wg0.conf`.

<PricingCompanion
  components={[
    { kind: "template", slug: "private-network-vpn", required: true },
  ]}
/>

<Figure size="md" caption="Private network VPN topology: WireGuard gateway on a private subnet, one floating IP for UDP 51820, site-to-site tunnel to a remote peer">

```d2
direction: right

peer: WireGuard peer\n192.168.99.0/24

cloud: Quake AI {
  fip: Floating IP\nUDP 51820
  private: Private network\n10.0.0.0/24 {
    gw: VPN gateway\nWireGuard
  }
  router: Router\nto PublicStatic
}

peer -> cloud.fip: WireGuard tunnel
cloud.fip -> cloud.private.gw
cloud.router -> cloud.private
```

</Figure>

## Prerequisites

You need:

- A Quake AI account with [application credentials](/docs/tools/generate-app-credentials)
- OpenTofu 1.6.0 or later ([installation guide](https://opentofu.org/docs/intro/install/))
- OpenStack credentials sourced into the shell (`source openrc.sh`). See [the OpenStack CLI guide](/docs/tools/openstack-cli).
- An SSH key pair already uploaded to the project. See [Add an SSH key](/docs/tools/add-ssh-key).
- A copy of the `private-network-vpn` template from [the template reference page](/resources/iac-templates/private-network-vpn)
- Enough project quota for one `s1a.small` instance, one 20 GB boot volume, one router, one private network, and one floating IP
- A WireGuard-capable peer outside Quake AI with a UDP path to your public IP on port `51820`
- `wireguard-tools` installed on the peer machine

## Step 1: Generate a WireGuard key pair for your peer

On the machine that acts as the remote peer, generate a key pair:

```bash
umask 077
wg genkey | tee peer-private.key | wg pubkey > peer-public.key
cat peer-public.key
```

Save the public key for `remote_wireguard_public_key`. Record your peer public IP:

```bash
curl -4 -s https://ifconfig.me
```

Use `192.168.99.0/24` on the peer side with address `192.168.99.2/32` after the tunnel is up.

## Step 2: Configure variables and apply

Copy `terraform.tfvars.example` to `terraform.tfvars` and set:

```hcl
key_name                    = "YOUR_KEY_NAME"
remote_cidr                 = "192.168.99.0/24"
remote_endpoint             = "YOUR_PEER_PUBLIC_IP"
remote_wireguard_public_key = "YOUR_PEER_PUBLIC_KEY"
```

Defaults for `private_cidr`, `vpn_port`, and gateway flavor are documented on the [Private Network + VPN](/resources/iac-templates/private-network-vpn) reference page.

From the template directory, run:

```bash
tofu init
tofu plan
tofu apply
```

Type `yes` when prompted. When the run finishes, note `vpn_endpoint` and `gateway_private_ip` from the outputs.

## Step 3: Confirm WireGuard on the gateway

SSH to the gateway through its floating IP and confirm cloud-init finished and WireGuard is running:

```bash
GATEWAY_FIP=$(tofu output -raw vpn_endpoint | cut -d: -f1)
ssh -i ~/.ssh/YOUR_KEY -o StrictHostKeyChecking=accept-new ubuntu@"${GATEWAY_FIP}" 'cloud-init status --wait && sudo wg show wg0'
```

Copy the gateway public key:

```bash
GATEWAY_WG_PUB=$(ssh -i ~/.ssh/YOUR_KEY ubuntu@"${GATEWAY_FIP}" 'sudo wg show wg0 public-key')
echo "${GATEWAY_WG_PUB}"
```

## Step 4: Configure your peer and reach the gateway private IP

On your workstation, create a WireGuard client configuration:

```ini
[Interface]
PrivateKey = YOUR_PEER_PRIVATE_KEY
Address = 192.168.99.2/32

[Peer]
PublicKey = YOUR_GATEWAY_WG_PUBLIC_KEY
Endpoint = YOUR_GATEWAY_FIP:51820
AllowedIPs = 10.0.0.0/24
PersistentKeepalive = 25
```

Bring the interface up (Linux example):

```bash
sudo cp peer-wg0.conf /etc/wireguard/wg0.conf
sudo wg-quick up wg0
```

From your workstation, ping the gateway private address through the tunnel:

```bash
PRIVATE_IP=$(tofu output -raw gateway_private_ip)
ping -c 3 "${PRIVATE_IP}"
```

Successful replies confirm site-to-site routing through WireGuard.

When you finish testing, tear down the workstation interface:

```bash
sudo wg-quick down wg0
```

## Next steps

- [Private Network + VPN template](/resources/iac-templates/private-network-vpn)
- [Three-Tier Application template](/resources/iac-templates/three-tier-app)
- [SSH bastion access into a private subnet](/docs/network/how-to/ssh-bastion-access)

## Clean up

Run `tofu destroy` from the project directory when finished. Bring down any local `wg-quick` interface you created.
