# How to set up a site-to-site or remote-access VPN to Quake AI

Source: https://docs.quake.ai/docs/network/how-to/site-to-site-vpn
Markdown: https://docs.quake.ai/docs/network/how-to/site-to-site-vpn.md

---

# How to set up a site-to-site or remote-access VPN to Quake AI

Connect an on-premises network or remote clients to a private Quake AI network by running a VPN gateway on a Compute instance.



Run a VPN daemon (WireGuard, OpenVPN, or IPsec) on a Compute instance attached to your private network. This how-to walks through gateway sizing, key exchange, routing, and security groups for a self-managed site-to-site or remote-access VPN on Quake AI. Quake AI does not expose the OpenStack Neutron VPN-as-a-Service (VPNaaS) extension from the Console, CLI, or API. For background on the VPN concept, see the [glossary entry for virtual private network](/docs/glossary).



<PrerequisiteBlock methods={["console", "cli"]}>

- A [private network and subnet](/docs/network/how-to/create-network) for the workloads that the VPN serves.
- A [router](/docs/network/how-to/create-router) attached to the private subnet and to the `PublicStatic` external network.
- An [SSH key pair](/docs/tools/add-ssh-key) for the gateway instance.
- The remote peer's public endpoint IP and the network ranges (CIDRs) on each side. The two sides must not use overlapping CIDRs.

</PrerequisiteBlock>

## How the gateway pattern works

A single Compute instance on your private subnet runs the VPN daemon and forwards traffic between the encrypted tunnel and the private network. The instance carries one floating IP, which is the public endpoint the remote peer or remote clients connect to. You allocate exactly **one floating IP** for the whole VPN gateway, regardless of how many peers or clients connect to it.

The same instance pattern serves two shapes:

- **Site-to-site:** a fixed tunnel between the Quake AI gateway and a remote gateway (an on-premises firewall or another cloud), so the two private networks route to each other.
- **Remote-access (road-warrior):** individual clients (laptops, phones) each hold a key and connect to the same gateway to reach the private network.

If you prefer a declarative build, the [Private Network + VPN template](/resources/iac-templates/private-network-vpn) provisions this same topology (private network, router, gateway security group, gateway instance, and one floating IP) with OpenTofu.

## Create the gateway security group

The gateway needs an inbound rule for the VPN protocol port and a rule for SSH administration. The example opens UDP 51820 for WireGuard. For IPsec, open UDP 500 and UDP 4500 instead; for OpenVPN, open UDP 1194.

<MethodTabs>
<Method label="Console">

1. Select **Network** > **Security Groups** > **Create Security Group**.
2. Name the group `vpn-gateway` and provide a description.
3. Select **OK**.
4. On the `vpn-gateway` row, open the **Settings** gear icon dropdown and select **Create Rule**.
5. Add an ingress rule: **Protocol** `UDP`, **Port** `51820`, **Source** `CIDR`, **CIDR** the remote peer endpoint (for example `203.0.113.10/32`) for site-to-site, or `0.0.0.0/0` for remote-access clients with no fixed address. Select **OK**.
6. On the same row, open **Settings** again and select **Create Rule** to add a second ingress rule: **Protocol** `TCP`, **Port** `22`, **Source** `CIDR`, **CIDR** your administrative network. Select **OK**.

</Method>
<Method label="CLI">

Create the security group:

```bash
openstack security group create vpn-gateway \
  --description "Self-managed VPN gateway"
```

Allow the WireGuard port from the remote peer (use `0.0.0.0/0` for remote-access clients):

```bash
openstack security group rule create vpn-gateway \
  --protocol udp --dst-port 51820 --remote-ip 203.0.113.10/32
```

Allow SSH from your administrative network:

```bash
openstack security group rule create vpn-gateway \
  --protocol tcp --dst-port 22 --remote-ip 198.51.100.0/24
```

</Method>
</MethodTabs>

For more detail on rule syntax, see [how to create security group rules](/docs/network/how-to/create-security-group-rules).

## Launch the gateway instance and assign a floating IP

Launch one instance on the private subnet with the `vpn-gateway` security group, then attach the single floating IP. Disable port security on the gateway port (or set allowed address pairs) so the instance can forward packets whose source or destination address is not its own. The gateway needs this behavior to route tunnel traffic.

<MethodTabs>
<Method label="Console">

1. Follow [how to create a VM on a private network](/docs/compute/how-to/create-vm-private-network) to launch an instance on your private subnet. Apply the `vpn-gateway` security group and your SSH key pair.
2. After the instance is active, open **Network** > **Floating IPs** > **Allocate IP**. Select `PublicStatic` in **Network**, leave **Owned Subnet** blank unless you need a specific subnet, leave **Batch Allocate** off, and select **OK**.
3. On the allocated address row, select **Associate**. In the dialog, select the gateway instance under **Instance IP**.
4. Open the gateway instance's port under **Network** > **Networks** > your network > **Ports**, then turn off **Port Security**. Confirm the change.

</Method>
<Method label="CLI">

Launch the gateway on the private network:

```bash
openstack server create vpn-gateway \
  --flavor s1a.small \
  --image "Ubuntu-24.04" \
  --boot-from-volume 10 \
  --key-name YOUR_KEY_NAME \
  --security-group vpn-gateway \
  --network YOUR_PRIVATE_NETWORK
```

`s1a.small` is a zero-disk flavor, so `--boot-from-volume 10` provisions a 10 GB root volume for the gateway. Without it the create call returns HTTP 403.

Disable port security so the gateway can forward traffic for the remote subnet. Find the gateway port, clear its security groups, then disable port security:

```bash
GATEWAY_PORT=$(openstack port list --server vpn-gateway -f value -c ID)
openstack port set "$GATEWAY_PORT" --no-security-group --disable-port-security
```

Allocate one floating IP and associate it with the gateway:

```bash
openstack floating ip create PublicStatic
openstack server add floating ip vpn-gateway YOUR_FLOATING_IP
```

</Method>
</MethodTabs>

The gateway instance now answers on one public address. See [how to allocate floating IPs](/docs/network/how-to/allocate-floating-ips) for more on floating IP management.



The in-guest commands below run inside the Linux gateway instance. Connect to it over SSH from any platform. See [Set up a Linux CLI environment on Windows](/docs/tools/windows-cli-environment) for SSH client options.



## Configure the VPN daemon in the guest

SSH into the gateway instance using its floating IP, then configure the VPN daemon. The examples below use WireGuard. For an IPsec peer (for example, a remote AWS or Azure VPN gateway, or a hardware firewall), install the `strongswan` or `libreswan` package instead and follow the peer vendor's IPsec parameters.

Enable IP forwarding so the instance routes packets between the tunnel and the private network:

```bash
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-vpn.conf
sudo sysctl --system
```

Install WireGuard and generate a key pair for the gateway:

```bash
sudo apt-get update && sudo apt-get install -y wireguard
wg genkey | sudo tee /etc/wireguard/private.key | wg pubkey | sudo tee /etc/wireguard/public.key
sudo chmod 600 /etc/wireguard/private.key
```

### Site-to-site tunnel

Create `/etc/wireguard/wg0.conf` on the gateway. The `Address` is the tunnel interface address, `AllowedIPs` lists the remote network the tunnel reaches, and `Endpoint` is the remote peer's public address:

```ini
[Interface]
Address = 10.10.0.1/24
ListenPort = 51820
PrivateKey = GATEWAY_PRIVATE_KEY

[Peer]
PublicKey = REMOTE_PEER_PUBLIC_KEY
Endpoint = 203.0.113.10:51820
AllowedIPs = 192.168.50.0/24
PersistentKeepalive = 25
```

On the remote gateway, mirror the configuration: set its peer `Endpoint` to the Quake AI floating IP, set `AllowedIPs` to the Quake AI private subnet CIDR, and exchange public keys.

Start the tunnel and enable it at boot:

```bash
sudo systemctl enable --now wg-quick@wg0
```

Add a route so instances on the private subnet reach the remote network through the gateway. Set this as a host route on the subnet, pointing the remote CIDR at the gateway's fixed IP:

```bash
openstack subnet set YOUR_PRIVATE_SUBNET \
  --host-route destination=192.168.50.0/24,gateway=GATEWAY_FIXED_IP
```

### Remote-access (road-warrior) variant

For individual clients, keep the same `[Interface]` block on the gateway and add one `[Peer]` block per client. Each client uses a unique address inside the tunnel range and lists the Quake AI private subnet in its own `AllowedIPs`:

```ini
[Peer]
# laptop-alice
PublicKey = CLIENT_PUBLIC_KEY
AllowedIPs = 10.10.0.2/32
```

On the client, set the gateway as the peer `Endpoint` (the floating IP and port `51820`) and list the private subnet CIDR you want to reach in the client's `AllowedIPs`. Reload the gateway after adding peers:

```bash
sudo systemctl restart wg-quick@wg0
```

## Verify the tunnel

Check the WireGuard handshake on the gateway. A recent handshake and non-zero transfer counters confirm an active peer:

```bash
sudo wg show
```

```text
interface: wg0
  public key: <gateway public key>
  listening port: 51820

peer: <remote peer public key>
  endpoint: 203.0.113.10:51820
  allowed ips: 192.168.50.0/24
  latest handshake: 18 seconds ago
  transfer: 1.21 MiB received, 842.00 KiB sent
```

From an instance on the private subnet, reach a host on the remote network to confirm routing across the tunnel:

```bash
ping -c 3 192.168.50.10
```

## See also

- [Private Network + VPN template](/resources/iac-templates/private-network-vpn): OpenTofu build of this topology
- [How to create a network](/docs/network/how-to/create-network)
- [How to create a router](/docs/network/how-to/create-router)
- [How to create a security group](/docs/network/how-to/create-security-group)
- [How to allocate floating IPs](/docs/network/how-to/allocate-floating-ips)
- [Floating IPs concept](/docs/network/concepts/floating-ips)
- [Security groups concept](/docs/network/concepts/security-groups)
- [Network CLI reference](/reference/network/cli)
- [Network API reference](/reference/network/api)
