WordPress Deployment on OpenStack Flex
Quickly and easily deploying WordPress on Rackspace OpenStack Flex
Heat Orchestration Template (HOT) deploys a fully functional WordPress site on an Ubuntu VM in Rackspace OpenStack Flex. This template uses the practice of "infrastructure as code" and automates all the prerequisites needed for a working OpenStack environment. This means that it does the work of network stack provisioning - but it also handles server configuration, WordPress installation, and HTTPS certificate setup using Let's Encrypt.
If you're interested in learning how to use OpenStack Orchestration, see our guide here
NOTE: This does not allow you to assign an existing floating IP to the VM built by the Orchestration Stack
Features
- Creates private network, subnet, router, and security group
- Launches a single Ubuntu-based VM
- Installs Apache, PHP, MySQL, and WordPress
- Automatically installs a free HTTPS certificate via Let's Encrypt
- Continues checking for 1.5hrs for DNS to resolve the domain correctly so that it can install the certificate
- Opens HTTP (80) and HTTPS (443) to the world
Requirements
Before launching the stack:
- Ensure you have access to manage your DNS (e.g.,
blog.example.com) so that you can update the record which will point your domain name to the floating IP that will be assigned. - Have a key pair already uploaded to your OpenStack Flex account .
Template
heat_template_version: '2018-03-02'
description: >
HOT template to deploy a WordPress server with automatic HTTPS using Certbot,
installed via a systemd service that retries DNS resolution post-boot.
parameters:
private_net_cidr:
type: string
default: 10.0.0.0/24
private_net_gateway:
type: string
default: 10.0.0.1
image:
type: string
default: ubuntu-20.04
flavor:
type: string
default: m1.small
public_net:
type: string
description: ID of the public network
key_name:
type: string
description: Name of the key pair to use for the VM instance
site_domain:
type: string
description: The full domain name to be used (e.g. wpsite.example.com)
admin_email:
type: string
description: Email address for Let's Encrypt registration
resources:
private_network:
type: OS::Neutron::Net
private_subnet:
type: OS::Neutron::Subnet
properties:
network_id: { get_resource: private_network }
cidr: { get_param: private_net_cidr }
gateway_ip: { get_param: private_net_gateway }
dns_nameservers: [8.8.8.8, 8.8.4.4]
router:
type: OS::Neutron::Router
properties:
external_gateway_info:
network: { get_param: public_net }
router_interface:
type: OS::Neutron::RouterInterface
properties:
router_id: { get_resource: router }
subnet_id: { get_resource: private_subnet }
vm_security_group:
type: OS::Neutron::SecurityGroup
properties:
rules:
- { protocol: tcp, port_range_min: 22, port_range_max: 22, remote_ip_prefix: 0.0.0.0/0 }
- { protocol: tcp, port_range_min: 80, port_range_max: 80, remote_ip_prefix: 0.0.0.0/0 }
- { protocol: tcp, port_range_min: 443, port_range_max: 443, remote_ip_prefix: 0.0.0.0/0 }
- { protocol: icmp, remote_ip_prefix: 0.0.0.0/0 }
vm_port:
type: OS::Neutron::Port
properties:
network_id: { get_resource: private_network }
security_groups: [ { get_resource: vm_security_group } ]
floating_ip:
type: OS::Neutron::FloatingIP
properties:
floating_network_id: { get_param: public_net }
port_id: { get_resource: vm_port }
wordpress_server:
type: OS::Nova::Server
properties:
name: wordpress_server
image: { get_param: image }
flavor: { get_param: flavor }
key_name: { get_param: key_name }
networks:
- port: { get_resource: vm_port }
user_data_format: RAW
user_data:
str_replace:
params:
__DOMAIN__: { get_param: site_domain }
__EMAIL__: { get_param: admin_email }
template: |
#!/bin/bash
apt-get update
apt-get install -y apache2 mysql-server php php-mysql libapache2-mod-php certbot python3-certbot-apache
mysql -e "CREATE DATABASE wordpress;"
mysql -e "CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'password';"
mysql -e "GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';"
mysql -e "FLUSH PRIVILEGES;"
cd /var/www/html
wget https://wordpress.org/latest.tar.gz
tar -xvzf latest.tar.gz
rm latest.tar.gz
mv wordpress/* .
rmdir wordpress
cp wp-config-sample.php wp-config.php
sed -i "s/database_name_here/wordpress/" wp-config.php
sed -i "s/username_here/wpuser/" wp-config.php
sed -i "s/password_here/password/" wp-config.php
chown -R www-data:www-data /var/www/html
chmod -R 755 /var/www/html
cat <<EOF > /usr/local/bin/wait-for-dns-certbot.sh
#!/bin/bash
IP=$(curl -s http://169.254.169.254/latest/meta-data/public-ipv4)
for i in {1..180}; do
RESOLVED=$(getent ahosts __DOMAIN__ | awk '{print $1; exit}')
if [ "$RESOLVED" == "$IP" ]; then
certbot --apache --non-interactive --agree-tos --email __EMAIL__ -d __DOMAIN__
systemctl reload apache2
exit 0
fi
sleep 30
done
echo "DNS failed to resolve to correct IP after waiting."
EOF
chmod +x /usr/local/bin/wait-for-dns-certbot.sh
cat <<EOF > /etc/systemd/system/certbot-wait.service
[Unit]
Description=Wait for DNS then run Certbot
After=network.target
[Service]
ExecStart=/usr/local/bin/wait-for-dns-certbot.sh
Type=oneshot
RemainAfterExit=true
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reexec
systemctl daemon-reload
systemctl enable certbot-wait.service
systemctl start certbot-wait.service
systemctl restart apache2
outputs:
instance_ip:
description: IP address of the WordPress server
value: { get_attr: [ floating_ip, floating_ip_address ] }
Stack Parameters
| Parameter | Description | Default Value |
|---|---|---|
private_net_cidr | CIDR block for internal network | 10.0.0.0/24 |
private_net_gateway | Gateway IP for subnet | 10.0.0.1 |
image | Image to use for the VM (must be Ubuntu 20.04+) | Ubuntu 24.04 |
flavor | Flavor (hardware profile) of the VM | gp.5.2.4 |
public_net | ID or name of the public network | PUBLICNET |
key_name | SSH key name registered in OpenStack | (required) |
site_domain | Domain name for the WordPress site (e.g., blog.example.com) | (required) |
admin_email | The email address for the Let's Encrypt registration | (required) |
Note: The
flavorcan be changed to something more powerful if needed. See our guide on flavors here.
Accessing Your WordPress Site
Once the stack is deployed and DNS is configured:
- Visit
https://yourdomain.com/wp-adminto finish WordPress setup. - If HTTPS isn’t working initially, verify DNS is resolving before stack creation.
Security Notes
- SSH (port 22), HTTP (port 80), and HTTPS (port 443) are open to the internet.
- You may want to restrict SSH access further in a production environment.
Troubleshooting
- DNS should be updated soon after launching the stack, Certbot will fail.
- If your DNS is updated but the site is not accessible via https:// yet - give it at least 5-10 minutes to perform the automated checks and installations.
- Redeploy the stack only after fixing DNS.
- Certbot will not retry unless the server is rebooted.
Updated about 1 month ago
