# WordPress on Single Instance

Deploys a single Instance running WordPress with Nginx, PHP, and MySQL. Everything runs on one server. Suitable for blogs, small sites, or quick CMS testing.

#### Architecture:

* 1 Instance (NanoBoost — 2 vCPU, 4 GB RAM)
* 1 private network (10.200.0.0/24)
* 1 floating IP (public access)
* 40 GB boot volume
* Security group allows HTTP, HTTPS, SSH

#### What is automated:

* Instance creation with selected flavor and image
* Private network, subnet, and router
* Floating IP assigned to Instance
* Security group with ports 22, 80, 443
* Nginx + PHP-FPM + MySQL installed
* MySQL database and user created with random passwords
* WordPress downloaded, extracted, and configured
* wp-config.php populated with DB credentials and salts
* Credentials saved to `/root/.wp_credentials`

#### Before you launch:

Update these parameters in the template or at launch time:

| Parameter        | Default                | What to change                                                                 |
| ---------------- | ---------------------- | ------------------------------------------------------------------------------ |
| `key_name`       | `stack-test`           | **Required.** Replace with your SSH keypair name from **Compute - Key Pairs**. |
| `image`          | `Ubuntu 22.04 Updated` | Change only if you need a different OS image.                                  |
| `flavor`         | `NanoBoost`            | Minimum recommended. Upgrade to MegaFuse for heavier traffic.                  |
| `volume_size`    | `40`                   | Increase if you plan to host media-heavy content (in GB).                      |
| `public_network` | `Public`               | Do not change unless your cloud has a different external network name.         |

{% hint style="info" %}
**key\_name is the only parameter you must change before launching.** Everything else works with defaults.
{% endhint %}

#### WordPress Template

Save as `wordpress-single.yaml` and upload via Orchestration or Past Direct.

```
heat_template_version: 2021-04-16
description: >
  NeevCloud: WordPress on Single Instance with Nginx, MySQL, and PHP.
  Flavor minimum: NanoBoost (2 vCPU, 4 GB RAM).

parameters:
  image:
    type: string
    default: Ubuntu 22.04 Updated
  flavor:
    type: string
    default: NanoBoost
  volume_size:
    type: number
    description: Boot volume size in GB
    default: 40
  public_network:
    type: string
    default: Public
  key_name:
    type: string
    default: stack-test

resources:
  net:
    type: OS::Neutron::Net
    properties:
      name: wordpress-net

  subnet:
    type: OS::Neutron::Subnet
    properties:
      network: { get_resource: net }
      cidr: 10.200.0.0/24
      dns_nameservers: [8.8.8.8, 8.8.4.4]

  router:
    type: OS::Neutron::Router
    properties:
      external_gateway_info:
        network: { get_param: public_network }

  router_interface:
    type: OS::Neutron::RouterInterface
    properties:
      router: { get_resource: router }
      subnet: { get_resource: subnet }

  sg:
    type: OS::Neutron::SecurityGroup
    properties:
      name: wordpress-sg
      rules:
        - { direction: ingress, protocol: tcp, port_range_min: 22, port_range_max: 22, remote_ip_prefix: 0.0.0.0/0 }
        - { direction: ingress, protocol: tcp, port_range_min: 80, port_range_max: 80, remote_ip_prefix: 0.0.0.0/0 }
        - { direction: ingress, protocol: tcp, port_range_min: 443, port_range_max: 443, remote_ip_prefix: 0.0.0.0/0 }
        - { direction: ingress, protocol: icmp, remote_ip_prefix: 0.0.0.0/0 }

  server:
    type: OS::Nova::Server
    properties:
      name: wordpress-server
      flavor: { get_param: flavor }
      key_name: { get_param: key_name }
      networks:
        - network: { get_resource: net }
      security_groups:
        - { get_resource: sg }
      block_device_mapping_v2:
        - boot_index: 0
          delete_on_termination: true
          image: { get_param: image }
          volume_size: { get_param: volume_size }
      user_data_format: RAW
      user_data: |
        #!/bin/bash
        set -e

        DB_NAME="wordpress"
        DB_USER="wpuser"
        DB_PASS=$(openssl rand -hex 16)
        DB_ROOT_PASS=$(openssl rand -hex 16)

        export DEBIAN_FRONTEND=noninteractive

        apt-get update -y
        apt-get install -y nginx mysql-server php-fpm php-mysql php-xml php-mbstring php-curl php-zip php-gd php-intl unzip curl

        # Secure MySQL
        mysqladmin -u root password "${DB_ROOT_PASS}"
        mysql -u root -p"${DB_ROOT_PASS}" -e "CREATE DATABASE ${DB_NAME};"
        mysql -u root -p"${DB_ROOT_PASS}" -e "CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';"
        mysql -u root -p"${DB_ROOT_PASS}" -e "GRANT ALL PRIVILEGES ON ${DB_NAME}.* TO '${DB_USER}'@'localhost'; FLUSH PRIVILEGES;"

        # Download WordPress
        cd /tmp
        curl -sO https://wordpress.org/latest.tar.gz
        tar -xzf latest.tar.gz
        cp -a wordpress/. /var/www/html/
        chown -R www-data:www-data /var/www/html
        rm -f /var/www/html/index.nginx-debian.html

        # wp-config.php
        cp /var/www/html/wp-config-sample.php /var/www/html/wp-config.php
        sed -i "s/database_name_here/${DB_NAME}/" /var/www/html/wp-config.php
        sed -i "s/username_here/${DB_USER}/" /var/www/html/wp-config.php
        sed -i "s/password_here/${DB_PASS}/" /var/www/html/wp-config.php

        # Generate WordPress salts
        SALTS=$(curl -s https://api.wordpress.org/secret-key/1.1/salt/)
        # Remove existing placeholder salts and append real ones
        sed -i "/AUTH_KEY/d;/SECURE_AUTH_KEY/d;/LOGGED_IN_KEY/d;/NONCE_KEY/d;/AUTH_SALT/d;/SECURE_AUTH_SALT/d;/LOGGED_IN_SALT/d;/NONCE_SALT/d" /var/www/html/wp-config.php
        echo "${SALTS}" >> /var/www/html/wp-config.php

        # Determine PHP-FPM socket
        PHP_VER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
        FPM_SOCK="/run/php/php${PHP_VER}-fpm.sock"

        # Nginx vhost
        cat > /etc/nginx/sites-available/wordpress <<NGINX
        server {
            listen 80 default_server;
            root /var/www/html;
            index index.php index.html;
            server_name _;
            client_max_body_size 64M;

            location / {
                try_files \$uri \$uri/ /index.php?\$args;
            }

            location ~ \.php\$ {
                include snippets/fastcgi-php.conf;
                fastcgi_pass unix:${FPM_SOCK};
            }

            location ~ /\.ht {
                deny all;
            }
        }
        NGINX

        ln -sf /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/default
        nginx -t && systemctl restart nginx
        systemctl enable nginx mysql php${PHP_VER}-fpm

        # Save credentials
        cat > /root/.wp_credentials <<EOF
        MySQL Root Password: ${DB_ROOT_PASS}
        WordPress DB: ${DB_NAME}
        WordPress DB User: ${DB_USER}
        WordPress DB Pass: ${DB_PASS}
        EOF
        chmod 600 /root/.wp_credentials

  fip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: { get_param: public_network }

  fip_assoc:
    type: OS::Neutron::FloatingIPAssociation
    properties:
      floatingip_id: { get_resource: fip }
      port_id: { get_attr: [server, addresses, { get_resource: net }, 0, port] }

outputs:
  web_url:
    description: WordPress URL (complete setup via browser)
    value:
      str_replace:
        template: http://HOST
        params:
          HOST: { get_attr: [fip, floating_ip_address] }
  floating_ip:
    description: Public IP
    value: { get_attr: [fip, floating_ip_address] }
  credentials_note:
    description: Database credentials location
    value: "SSH into server and run: cat /root/.wp_credentials"
```

#### Access:

* Web: <http://floating-ip> (WordPress setup wizard)
* SSH: ssh ubuntu\@floating-ip

#### Deploy:

1. Go to [Orchestration](/neevcloud-products/orchestration-infrastructure-as-code/web-server-stack-template.md)
2. Upload wordpress-single.yaml
3. Select keypair, flavor, image
4. Launch stack
5. Open the floating IP in your browser and complete WordPress setup

{% hint style="info" %}
**Note:** First boot takes 3–5 minutes for all packages to install. If you see the default Nginx page, wait and refresh.
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.neevcloud.com/neevcloud-guide/stack-automation-library/web-and-applications/wordpress-on-single-instance.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
