[Yandex Cloud documentation](../../../index.md) > [Tutorials](../../index.md) > Application solutions > Creating a website > WordPress website > [WordPress website on a MySQL® database](index.md) > Terraform

# Creating a WordPress website with a MySQL® database cluster using Terraform

To create an infrastructure for a [WordPress website with a MySQL® database cluster](index.md) using Terraform:

To set up a WordPress website with a MySQL® cluster:
1. [Get your cloud ready](#before-you-begin).
1. [Create the infrastructure](#deploy).
1. [Configure Nginx web server](#configure-nginx).
1. [Install WordPress and additional components](#install-wordpress).
1. [Complete WordPress configuration](#configure-wordpress).
1. [Test the website](#test-site).

If you no longer need the resources you created, [delete them](#clear-out).

## Get your cloud ready {#before-you-begin}

Sign up for Yandex Cloud and create a [billing account](../../../billing/concepts/billing-account.md):
1. Navigate to the [management console](https://console.yandex.cloud) and log in to Yandex Cloud or create a new account.
1. On the **[Yandex Cloud Billing](https://center.yandex.cloud/billing/accounts)** page, make sure you have a billing account linked and it has the `ACTIVE` or `TRIAL_ACTIVE` [status](../../../billing/concepts/billing-account-statuses.md). If you do not have a billing account, [create one](../../../billing/quickstart/index.md) and [link](../../../billing/operations/pin-cloud.md) a cloud to it.

If you have an active billing account, you can create or select a [folder](../../../resource-manager/concepts/resources-hierarchy.md#folder) for your infrastructure on the [cloud page](https://console.yandex.cloud/cloud).

[Learn more about clouds and folders here](../../../resource-manager/concepts/resources-hierarchy.md).

### Required paid resources {#paid-resources}

* VM instance: use of computing resources, storage, public IP address, and OS (see [Compute Cloud pricing](../../../compute/pricing.md)).

* Managed Service for MySQL® cluster: computing resources allocated to hosts, size of storage and backups (see [Managed Service for MySQL® pricing](../../../managed-mysql/pricing.md)).
* Public IP addresses if public access is enabled for cluster hosts (see [Virtual Private Cloud pricing](../../../vpc/pricing.md)).
* Public DNS queries and [DNS zones](../../../dns/concepts/dns-zone.md) (see [Cloud DNS pricing](../../../dns/pricing.md)).

## Create your infrastructure {#deploy}

With [Terraform](https://www.terraform.io/), you can quickly create a cloud infrastructure in Yandex Cloud and manage it using configuration files. These files store the infrastructure description written in HashiCorp Configuration Language (HCL). If you change the configuration files, Terraform automatically detects which part of your configuration is already deployed, and what should be added or removed.

Terraform is distributed under the [Business Source License](https://github.com/hashicorp/terraform/blob/main/LICENSE). The [Yandex Cloud provider for Terraform](https://github.com/yandex-cloud/terraform-provider-yandex) is distributed under the [MPL-2.0](https://www.mozilla.org/en-US/MPL/2.0/) license.

For more information about the provider resources, see the guides on the [Terraform](https://www.terraform.io/docs/providers/yandex/index.html) website or [its mirror](../../../terraform/index.md).

To create an infrastructure using Terraform:
1. [Install Terraform](../../infrastructure-management/terraform-quickstart.md#install-terraform), [get the credentials](../../infrastructure-management/terraform-quickstart.md#get-credentials), and specify the source for installing the Yandex Cloud provider (see [Configure your provider](../../infrastructure-management/terraform-quickstart.md#configure-provider), Step 1).
1. Prepare the infrastructure description files:

   {% list tabs group=infrastructure_description %}

   - Ready-made archive {#ready}

     1. Create a directory.
     1. Download the [archive](https://storage.yandexcloud.net/doc-files/wordpress-mysql.zip) (1 KB).
     1. Unpack the archive to the directory. As a result, the `wordpress-mysql.tf` configuration file should appear in it.

   - Manually {#manual}

     1. Create a directory.
     1. Create a configuration file named `wordpress-mysql.tf` in the folder:

        {% cut "wordpress-mysql.tf" %}

        ```hcl
        terraform {
          required_providers {
            yandex = {
              source  = "yandex-cloud/yandex"
              version = ">= 0.47.0"
            }
          }
        }
        
        provider "yandex" {
          zone = "ru-central1-a"
        }
        
        resource "yandex_compute_disk" "boot-disk" {
          name     = "bootvmdisk"
          type     = "network-hdd"
          zone     = "ru-central1-a"
          size     = "20"
          image_id = "<image_ID>"
        }
        
        resource "yandex_compute_instance" "vm-wordpress-mysql" {
          name        = "wp-mysql-tutorial-web"
          platform_id = "standard-v3"
          zone        = "ru-central1-a"
        
          resources {
            core_fraction = 20
            cores         = 2
            memory        = 2
          }
        
          boot_disk {
            disk_id = yandex_compute_disk.boot-disk.id
          }
        
          network_interface {
            subnet_id          = yandex_vpc_subnet.subnet-1.id
            security_group_ids = ["${yandex_vpc_security_group.sg-1.id}"]
            nat                = true
          }
        
          metadata = {
            ssh-keys = "<username>:<SSH_key_contents>"
          }
        }
        
        resource "yandex_mdb_mysql_cluster" "wp-cluster" {
          name                = "wp-mysql-tutorial-db-cluster"
          environment         = "PRESTABLE"
          network_id          = yandex_vpc_network.network-1.id
          version             = "8.0"
          security_group_ids  = ["${yandex_vpc_security_group.sg-1.id}"]
        
          resources {
            resource_preset_id = "s2.small"
            disk_type_id       = "network-ssd"
            disk_size          = "10"
          }
        
          host {
            zone             = "ru-central1-a"
            subnet_id        = yandex_vpc_subnet.subnet-1.id
            assign_public_ip = false
          }
        
          host {
            zone             = "ru-central1-b"
            subnet_id        = yandex_vpc_subnet.subnet-2.id
            assign_public_ip = false
          }
        
          host {
            zone             = "ru-central1-d"
            subnet_id        = yandex_vpc_subnet.subnet-3.id
            assign_public_ip = false
          }
        }
        
        resource "yandex_mdb_mysql_database" "wp-db" {
          cluster_id = yandex_mdb_mysql_cluster.wp-cluster.id
          name       = "wp-mysql-tutorial-db"
        }
        
        resource "yandex_mdb_mysql_user" "wp-user" {
          cluster_id            = yandex_mdb_mysql_cluster.wp-cluster.id
          name                  = "wordpress"
          password              = "password"
          authentication_plugin = "MYSQL_NATIVE_PASSWORD"
          permission {
            database_name = yandex_mdb_mysql_database.wp-db.name
            roles         = ["ALL"]
          }
        }
        
        resource "yandex_vpc_security_group" "sg-1" {
          name        = "wordpress"
          description = "Description for security group"
          network_id  = yandex_vpc_network.network-1.id
        
          ingress {
            protocol       = "TCP"
            description    = "ext-http"
            v4_cidr_blocks = ["0.0.0.0/0"]
            port           = 80
          }
        
          ingress {
            protocol       = "TCP"
            description    = "ext-ssh"
            v4_cidr_blocks = ["0.0.0.0/0"]
            port           = 22
          }
        
          ingress {
            protocol       = "TCP"
            description    = "ext-msql"
            v4_cidr_blocks = ["0.0.0.0/0"]
            port           = 3306
          }
        
          ingress {
            protocol       = "TCP"
            description    = "ext-https"
            v4_cidr_blocks = ["0.0.0.0/0"]
            port           = 443
          }
        
          egress {
            protocol       = "ANY"
            description    = "any"
            v4_cidr_blocks = ["0.0.0.0/0"]
          }
        }
        
        resource "yandex_vpc_network" "network-1" {
          name = "network1"
        }
        
        resource "yandex_vpc_subnet" "subnet-1" {
          name           = "subnet1"
          zone           = "ru-central1-a"
          network_id     = yandex_vpc_network.network-1.id
          v4_cidr_blocks = ["192.168.1.0/24"]
        }
        
        resource "yandex_vpc_subnet" "subnet-2" {
          name           = "subnet2"
          zone           = "ru-central1-b"
          network_id     = yandex_vpc_network.network-1.id
          v4_cidr_blocks = ["192.168.2.0/24"]
        }
        
        resource "yandex_vpc_subnet" "subnet-3" {
          name           = "subnet3"
          zone           = "ru-central1-d"
          network_id     = yandex_vpc_network.network-1.id
          v4_cidr_blocks = ["192.168.3.0/24"]
        }
        
        resource "yandex_dns_zone" "zone-1" {
          name        = "example-zone-1"
          description = "Public zone"
          zone        = "example.com."
          public      = true
        }
        
        resource "yandex_dns_recordset" "rs-1" {
          zone_id = yandex_dns_zone.zone-1.id
          name    = "example.com."
          ttl     = 600
          type    = "A"
          data    = ["${yandex_compute_instance.vm-wordpress-mysql.network_interface.0.nat_ip_address}"]
        }
        
        resource "yandex_dns_recordset" "rs-2" {
          zone_id = yandex_dns_zone.zone-1.id
          name    = "www"
          ttl     = 600
          type    = "CNAME"
          data    = ["example.com"]
        }
        ```

        {% endcut %}

   {% endlist %}

   For more on the properties of resources used in Terraform, see these provider guides:

    * [Network](../../../vpc/concepts/network.md#network): [yandex_vpc_network](../../../terraform/resources/vpc_network.md).
    * [Subnets](../../../vpc/concepts/network.md#subnet): [yandex_vpc_subnet](../../../terraform/resources/vpc_subnet.md).
    * [Security groups](../../../vpc/concepts/security-groups.md): [yandex_vpc_security_group](../../../terraform/resources/vpc_security_group.md).
    * [VM instance](../../../compute/concepts/vm.md): [yandex_compute_instance](../../../terraform/resources/compute_instance.md).
    * [MySQL® cluster](../../../managed-mysql/concepts/index.md): [yandex_mdb_mysql_cluster](../../../terraform/resources/mdb_mysql_cluster.md).
    * [PostgreSQL database](../../../managed-mysql/index.md): [yandex_mdb_postgresql_database](../../../terraform/resources/mdb_mysql_database.md).
    * [DB user](../../../managed-mysql/concepts/user-rights.md): [yandex_mdb_mysql_user](../../../terraform/resources/mdb_mysql_user.md).
    * [DNS zone](../../../dns/concepts/dns-zone.md): [yandex_dns_zone](../../../terraform/resources/dns_zone.md).
    * [DNS resource record](../../../dns/concepts/resource-record.md): [yandex_dns_recordset](../../../terraform/resources/dns_recordset.md).

1. Under `metadata`, specify the [metadata](../../../compute/concepts/vm-metadata.md) for creating a VM: `<username>:<SSH_key_contents>`. Regardless of the username specified, the key is assigned to the user set in the image configuration. Such users differ depending on the image. For more information, see [Keys processed in public images Yandex Cloud](../../../compute/concepts/metadata/public-image-keys.md).
1. Under `boot_disk`, specify the ID of a VM [image](../../../compute/operations/images-with-pre-installed-software/get-list.md) with relevant components:
   * [Debian 11](https://yandex.cloud/en/marketplace/products/yc/debian-11).
   * [Ubuntu 20.04 LTS](https://yandex.cloud/en/marketplace/products/yc/ubuntu-20-04-lts).
   * [CentOS 7](https://yandex.cloud/en/marketplace/products/yc/centos-7).
1. Create the resources:

   1. In the terminal, navigate to the configuration file directory.
   1. Make sure the configuration is correct using this command:
   
      ```bash
      terraform validate
      ```
   
      If the configuration is valid, you will get this message:
   
      ```bash
      Success! The configuration is valid.
      ```
   
   1. Run this command:
   
      ```bash
      terraform plan
      ```
   
      You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
   1. Apply the configuration changes:
   
      ```bash
      terraform apply
      ```
   
   1. Type `yes` and press **Enter** to confirm the changes.

After creating the infrastructure, [configure the Nginx web server](#configure-nginx).
## Configure the Nginx web server {#configure-nginx}

After the `wp-mysql-tutorial-web` VM's status changes to `RUNNING`:
1. Under **Network** on the VM page in the [management console](https://console.yandex.cloud), find the VM's public IP address.
1. [Connect](../../../compute/operations/vm-connect/ssh.md) to the VM via SSH. You can use the `ssh` utility in Linux or macOS, or [PuTTY](https://www.chiark.greenend.org.uk/~sgtatham/putty/) in Windows.

   The recommended authentication method when connecting over SSH is using a key pair. Make sure to configure the generated key pair so that the private key matches the public key sent to the VM.
1. Install Nginx, PHP-FPM process manager, and additional packages:

   {% list tabs group=operating_system %}

   - Debian/Ubuntu {#ubuntu}

      ```bash
      sudo apt-get update
      sudo apt-get install -y nginx-full php-fpm php-mysql
      sudo systemctl enable nginx
      ```

   - CentOS {#centos}

      ```bash
      sudo yum -y install epel-release
      sudo yum -y install nginx
      sudo rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
      sudo yum -y --enablerepo=remi-php74 install php php-mysql php-xml php-soap php-xmlrpc php-mbstring php-json php-gd php-mcrypt
      sudo yum -y --enablerepo=remi-php74 install php-fpm
      sudo systemctl enable nginx
      sudo systemctl enable php-fpm
      ```

   {% endlist %}

1. Use the Nginx configuration files to configure the web server:

   {% list tabs group=operating_system %}

   - Debian/Ubuntu {#ubuntu}

      1. You can edit files in the `nano` editor:

         ```bash
         sudo nano /etc/nginx/sites-available/wordpress
         ```

      1. Edit the file as follows:

         ```nginx
         server {
             listen 80 default_server;

             root /var/www/wordpress;
             index index.php;

             server_name <DNS-server_name>;

             location / {
                 try_files $uri $uri/ =404;
             }

             error_page 404 /404.html;
             error_page 500 502 503 504 /50x.html;
             location = /50x.html {
                 root /usr/share/nginx/html;
             }

             location ~ \.php$ {
                 try_files $uri =404;
                 fastcgi_split_path_info ^(.+\.php)(/.+)$;
                 fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
                 fastcgi_index index.php;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                 include fastcgi_params;
             }
         }
         ```

      1. Allow launching your site:

         ```bash
         sudo rm /etc/nginx/sites-enabled/default
         sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
         ```

   - CentOS {#centos}

      You can edit the files `nginx.conf` and `wordpress.conf` in the `nano` editor:
      1. Open `nginx.conf`:

         ```bash
         sudo nano /etc/nginx/nginx.conf
         ```

      1. Edit the file as follows:

         ```nginx
         user nginx;
         worker_processes auto;
         error_log /var/log/nginx/error.log;
         pid /run/nginx.pid;
         include /usr/share/nginx/modules/*.conf;

         events {
           worker_connections 1024;
         }

         http {
           log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                             '$status $body_bytes_sent "$http_referer" '
                             '"$http_user_agent" "$http_x_forwarded_for"';

           access_log  /var/log/nginx/access.log main;

           sendfile            on;
           tcp_nopush          on;
           tcp_nodelay         on;
           keepalive_timeout   65;
           types_hash_max_size 2048;

           include             /etc/nginx/mime.types;
           default_type        application/octet-stream;

           include /etc/nginx/conf.d/*.conf;
         }
         ```

      1. Open `wordpress.conf`:

         ```bash
         sudo nano /etc/nginx/conf.d/wordpress.conf
         ```

      1. Edit the file as follows:

         ```nginx
         server {
             listen 80 default_server;

             root /usr/share/nginx/wordpress/;
             index index.php;

             server_name <DNS-server_name>;

             location / {
                 try_files $uri $uri/ =404;
             }

             error_page 404 /404.html;
             error_page 500 502 503 504 /50x.html;
             location = /50x.html {
                 root /usr/share/nginx/html;
             }

             location ~ \.php$ {
                 try_files $uri =404;
                 fastcgi_split_path_info ^(.+\.php)(/.+)$;
                 fastcgi_pass 127.0.0.1:9000;
                 fastcgi_index index.php;
                 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                 include fastcgi_params;
             }
         }
         ```

   {% endlist %}

## Install WordPress and additional components {#install-wordpress}

1. Download and unpack the latest WordPress version:

   {% list tabs group=operating_system %}

   - Debian/Ubuntu {#ubuntu}

     ```bash
     wget https://wordpress.org/latest.tar.gz
     tar -xzf latest.tar.gz
     mv wordpress/wp-config-sample.php wordpress/wp-config.php
     sudo mv wordpress /var/www/wordpress
     sudo chown -R www-data:www-data /var/www/wordpress
     ```

   - CentOS {#centos}

     ```bash
     curl https://wordpress.org/latest.tar.gz --output latest.tar.gz
     tar -xzf latest.tar.gz
     mv wordpress/wp-config-sample.php wordpress/wp-config.php
     sudo mv wordpress /usr/share/nginx/wordpress
     sudo chown -R nginx:nginx /usr/share/nginx/wordpress/
     ```

     Change the SELinux settings:

     ```bash
     sudo semanage fcontext -a -t httpd_sys_content_t "/usr/share/nginx/wordpress(/.*)?"
     sudo semanage fcontext -a -t httpd_sys_rw_content_t "/usr/share/nginx/wordpress(/.*)?"
     sudo restorecon -R /usr/share/nginx/wordpress
     sudo setsebool -P httpd_can_network_connect 1
     ```

   {% endlist %}

1. Get WordPress security keys:

   ```bash
   curl --silent https://api.wordpress.org/secret-key/1.1/salt/
   ```

   Save the command output. You will need the keys in the next step.
1. Add the security keys to the WordPress configuration file: `wp-config.php`. You can edit files in the `nano` editor:

   {% list tabs group=operating_system %}

   - Debian/Ubuntu {#ubuntu}

     ```bash
     sudo nano /var/www/wordpress/wp-config.php
     ```

   - CentOS {#centos}

     ```bash
     sudo nano /usr/share/nginx/wordpress/wp-config.php
     ```

   {% endlist %}

   Replace the configuration section for the values from the previous step:

   ```php
   define('AUTH_KEY',         't vz,|............R lZ5]');
   define('SECURE_AUTH_KEY',  '@r&pPD............dK-A%=');
   define('LOGGED_IN_KEY',    '%6TuLl............9>/dNE');
   define('NONCE_KEY',        'DO(u.H............$?ja-e');
   define('AUTH_SALT',        '|G Vo<............Xeb.~y');
   define('SECURE_AUTH_SALT', 'Y5tIYA............7Lxf8J');
   define('LOGGED_IN_SALT',   'gR]>WZ............<>|;YY');
   define('NONCE_SALT',       '=]nQIb............HLT2:9');
   ```

1. Go to the connection configuration section for the `wp-mysql-tutorial-db-cluster` cluster:

   ```php
   // ** MySQL® settings - You can get this info from your web host. ** //
   /** The name of the database for WordPress. */

   define( 'DB_NAME', '<DB_NAME>' );
   /** MySQL® database username. */
   define( 'DB_USER', '<DB_USER>' );

   /** MySQL® database password. */
   define( 'DB_PASSWORD', '<DB_PASSWORD>' );

   /** MySQL® hostname. */
   define( 'DB_HOST', '<DB_HOST>' );
   ```

   Replace the placeholders in the file:
   * `<DB_NAME>`: `wp-mysql-tutorial-db` DB name.
   * `<DB_USER>`: `wordpress` user name.
   * `<DB_PASSWORD>`: Password you set when creating the database cluster.
   * `<DB_HOST>`: MySQL® host name in `XXXX-XXXXXXXXXX.mdb.yandexcloud.net` format.

     To find out the FQDN of your MySQL® host:

	 {% list tabs group=instructions %}

	 - Management console {#console}

	   1. Go to the MySQL® cluster page in the [management console](https://console.yandex.cloud).
       1. On the **Databases** tab next to the DB, click ![image](../../../_assets/options.svg) → **Connect**.
       1. Find the `mysql --host=ХХХХ-ХХХХХХХХХХ.mdb.yandexcloud.net` line, where `ХХХХ-ХХХХХХХХХХ.mdb.yandexcloud.net` is the FQDN of the host with the `MASTER` role.

     - CLI {#cli}

       [Get a host list](../../../managed-mysql/operations/hosts.md#list) and copy the `MASTER` host's `NAME`:

       ```bash
       yc managed-mysql host list --cluster-name <MySQL®>_cluster_name
       ```

       
       ```text
       +------------------------+----------------------+---------+--------+-------------------+-----------+
       |           NAME         |      CLUSTER ID      |  ROLE   | HEALTH |      ZONE ID      | PUBLIC IP |
       +------------------------+----------------------+---------+--------+-------------------+-----------+
       | rc1a-...mdb.yandexcloud.net | c9quhb1l32unm1sdn0in | MASTER  | ALIVE  | ru-central1-a | false     |
       | rc1b-...mdb.yandexcloud.net | c9quhb1l32unm1sdn0in | REPLICA | ALIVE  | ru-central1-b | false     |
       +------------------------+----------------------+---------+--------+-------------------+-----------+
       ```


     {% endlist %}

1. Restart Nginx and PHP-FPM:

   {% list tabs group=operating_system %}

   - Debian/Ubuntu {#ubuntu}

     ```bash
     sudo systemctl restart nginx.service
     sudo systemctl restart php7.4-fpm.service
     ```

   - CentOS {#centos}

     ```bash
     sudo systemctl restart nginx.service
     sudo systemctl restart php-fpm.service
     ```

   {% endlist %}

## Complete WordPress configuration {#configure-wordpress}

1. Under **Network** on the VM page in the [management console](https://console.yandex.cloud), find the VM's public IP address.
1. Open the VM by entering its address in your browser.
1. Select the language and click **Continue**.
1. Fill out information to access the website:
   * Enter any website name, for example, `wp-your-project`.
   * Specify the username to be used to log in to the admin panel (for example, `admin`).
   * Enter the password to be used to log in to the admin panel.
   * Enter your email address.
1. Click **Install WordPress**.
1. If the installation is successful, click **Log in**.
1. Log in to the website with the username and password specified in the previous steps. This will open the admin panel where you can start working with your website.

## Test the website {#test-site}

To test the site, enter its IP address or domain name in your browser:
* `http://<public_IP_of_VM>`
* `http://www.example.com`

To access the WordPress control panel, use `http://www.example.com/wp-admin/`.

## How to delete the resources you created {#clear-out}

To stop paying for the resources you created:

1. Open the `single-node-file-server.tf` file and delete your infrastructure description from it.
1. Apply the changes:

    1. In the terminal, navigate to the configuration file directory.
    1. Make sure the configuration is correct using this command:
    
       ```bash
       terraform validate
       ```
    
       If the configuration is valid, you will get this message:
    
       ```bash
       Success! The configuration is valid.
       ```
    
    1. Run this command:
    
       ```bash
       terraform plan
       ```
    
       You will see a list of resources and their properties. No changes will be made at this step. Terraform will show any errors in the configuration.
    1. Apply the configuration changes:
    
       ```bash
       terraform apply
       ```
    
    1. Type `yes` and press **Enter** to confirm the changes.

#### See also {#see-also}

* [Creating a WordPress website with a MySQL® database cluster using the management console](console.md)