# Deploy the MySQL/MariaDB database template with OpenTofu

Source: https://docs.quake.ai/resources/deployments/deploy-mysql-database-template
Markdown: https://docs.quake.ai/resources/deployments/deploy-mysql-database-template.md
> Stand up MariaDB on a private subnet with a dedicated Cinder data volume using the mysql-database OpenTofu template.

---

# Deploy the MySQL/MariaDB database template with OpenTofu

Stand up MariaDB on a private subnet with a dedicated Cinder data volume using the [validated OpenTofu template](/docs/platform/validation#how-infrastructure-templates-are-checked) `mysql-database`. The database listens on a private address only; cloud-init formats the data volume at `/var/lib/mysql` and installs a scheduled `mysqldump` backup script.

<PricingCompanion
  components={[
    { kind: "template", slug: "mysql-database", required: true },
  ]}
/>

<Figure size="md" caption="MySQL/MariaDB topology: private network, database instance on a dedicated data volume, router to PublicStatic, no floating IP">

```d2
direction: right

cloud: Quake AI {
  router: Router\nto PublicStatic
  private: Private network\n192.168.50.0/24 {
    mysql: MariaDB\nport 3306
  }
  vol: Block volume\n50 GB\n/var/lib/mysql
  sg: Security group\nSSH + MySQL
}

cloud.router -> cloud.private
cloud.vol -> cloud.mysql: /dev/sdb
cloud.sg -> cloud.mysql
```

</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 `mysql-database` template from [the template reference page](/resources/iac-templates/mysql-database)
- Enough project quota for one `m2a.large` instance and one 50 GB block volume (defaults)
- A host that routes to the private subnet for SSH after apply (bastion, VPN, or another instance on the same network). See [SSH bastion access into a private subnet](/docs/network/how-to/ssh-bastion-access).

## Step 1: Configure variables

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

```hcl
key_name      = "YOUR_KEY_NAME"
allowed_cidrs = ["192.168.50.0/24"]
db_password   = "CHOOSE_A_STRONG_PASSWORD"
```

| Variable | Purpose |
| --- | --- |
| `key_name` | Existing SSH key pair name Nova uses at boot |
| `allowed_cidrs` | IPv4 ranges that may connect to MySQL/MariaDB on port 3306 |
| `db_password` | Password cloud-init assigns to `appuser` |

Defaults for flavor, volume size, engine package, and network CIDR are documented on the [MySQL/MariaDB Database](/resources/iac-templates/mysql-database) reference page.

## Step 2: Apply the template

From the template directory, run:

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

Type `yes` when prompted. Provisioning takes several minutes while Nova builds the boot volume, Cinder provisions the data volume, and cloud-init formats `/dev/sdb` and installs MariaDB.

When the run finishes, note `private_ip` from the outputs.

## Step 3: Verify MySQL/MariaDB and the data volume

Cloud-init can take a few more minutes after `tofu apply` returns. SSH to the instance private IP from a host that routes to the subnet:

```bash
PRIVATE=$(tofu output -raw private_ip)
ssh -i ~/.ssh/YOUR_KEY ubuntu@${PRIVATE}
```

On the instance, confirm the data volume is mounted and MariaDB is running:

```bash
df -h /var/lib/mysql
sudo systemctl is-active mariadb
sudo mysql -e "SHOW DATABASES;" | grep appdb
```

Connect as the application user and run a test query:

```bash
mysql -h 127.0.0.1 -u appuser -p'CHOOSE_A_STRONG_PASSWORD' appdb -e "CREATE TABLE deploy_check (id INT); INSERT INTO deploy_check VALUES (1); SELECT * FROM deploy_check;"
```

The query returns one row, which confirms the database stores data on the attached volume.

Optional: confirm the backup cron:

```bash
ls -l /usr/local/bin/mysql-backup.sh /etc/cron.d/mysql-backup
```

## Next steps

- [MySQL/MariaDB Database template](/resources/iac-templates/mysql-database)
- [Three-Tier Application template](/resources/iac-templates/three-tier-app)
- [WordPress + MySQL template](/resources/iac-templates/wordpress-mysql)
- [Self-hosting the vibecoding stack](/resources/solutions/self-hosted-vibecode-stack)

## Clean up

Run `tofu destroy` from the project directory when finished. Type `yes` to confirm. Verify in the Console that the instance and data volume are gone.
