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
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
flavor
can 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-admin
to 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 19 hours ago