Automating LEMP Stack Deployment on Google Cloud VM with Startup Scripts

Introduction

The LEMP (Linux, Nginx, MySQL, PHP) stack offers a powerful and scalable web hosting solution. This tutorial guides you through deploying a LEMP stack on Google Cloud Virtual Machines (VM) with custom metadata, optimizing performance and security.

Prerequisites

  1. Google Cloud account
  2. Basic knowledge of Linux commands
  3. Google Cloud Secret Manager API enabled

Create a Service Account for your Virtual Machine

A service account is a specialized Google Cloud account used exclusively by applications, compute workloads (e.g., Compute Engine instances) and automated services, rather than humans. Each service account features a unique email address for identification. For more information see Service accounts overview.

  1. Navigate to IAM & Admin > Service accounts.
  2. Click Create service account.
  3. Enter a Service account name.
  4. Write down the generated Email address.
  5. Click Done.

Configure MySQL Root Password with Google Cloud Secret Manager

  1. Navigate to Security > Secret Manager.
  2. Click Create secret.
  3. Enter the name: <your-site-name>-mysql-password.
  4. Enter the password as secret value.
  5. Click Create secret.
  6. Select the Permissions tab.
  7. Click Grant Access.
  8. Enter the newly created Service Account e-mail address as the New Principal
  9. Select the Secret Manager Secret Accessor role.
  10. Click Save

Create the Startup script

Replace DOMAIN, SECRET and EMAIL by the actual values.

#! /bin/bash
# General variables 
#
DOMAIN=yourdomain.com
SECRET=<your-site-name>-mysql-password
EMAIL=youremail@yourprovider.com
# Only installs/reinstalls SSL it finds if ~/done.txt
#
if [ -f ~/done.txt ]; then 
   python3 -m venv /opt/certbot/
   /opt/certbot/bin/pip install --upgrade pip
   /opt/certbot/bin/pip install certbot certbot-nginx
   ln -s /opt/certbot/bin/certbot /usr/bin/certbot
   certbot --nginx -d $DOMAIN -d www.$DOMAIN -m $EMAIL --agree-tos --keep-until-expiring
   exit 0;
fi
# Install packages
#
apt install nginx php-fpm php-mysql php8.2-gd python3 python3-venv libaugeas0 -y
# MySQL config
#
mysqlpwd=$(gcloud secrets versions access latest --secret=$SECRET)
echo "mysql-server mysql-server/root_password password $mysqlpwd" > mysql-server.preseed
echo "mysql-server mysql-server/root_password_again password $mysqlpwd" >> mysql-server.preseed
debconf-set-selections mysql-server.preseed
DEBIAN_FRONTEND=noninteractive apt-get install -y default-mysql-server
#rm mysql-server.preseed
# Nginx config file
#
cat <<EOF > /etc/nginx/sites-available/$DOMAIN.conf
server {
   listen 80 default_server;
   listen [::]:80 default_server;
   server_name _ www.$DOMAIN $DOMAIN;
   root /var/www/$DOMAIN;
   index index.php index.html;
   location / {
      try_files \$uri \$uri/ /index.php?\$args;
   }
   location ~ \.php$ {
      include snippets/fastcgi-php.conf;
      fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
   }
}
EOF
#  install a sample php file
#
mkdir /var/www/$DOMAIN
cat <<EOF > /var/www/$DOMAIN/index.php
<?php
echo "Hello World!";
?>
EOF
# Change ownership to nginx
#
chown -R www-data:www-data /var/www/$DOMAIN
find /var/www/$DOMAIN/ -type d -exec chmod 755 {} \;
find /var/www/$DOMAIN/ -type f -exec chmod 644 {} \;
# Enable the site
ln -s /etc/nginx/sites-available/$DOMAIN.conf /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
systemctl restart nginx
# Creates ~/done.txt
#
touch ~/done.txt

Create the Virtual Machine

  • Navigate to Compute Engine > VM Instances.
  • Click Create Instance.
  • In the Machine configuration section:
    • Enter a Name.
    • Select a Region (e.g., us-central1)
    • Choose a Machine type (e.g., e2-micro)
  • In the Networking section, allow http and https.
  • In the Security section:
    • Select the newly created Service account.
    • Choose Allow full access to all Cloud APIs.
  • In the Advanced section, paste script into Automation > Startup Script.
  • Click Create

Check the Startup scripts logs

  1. Navigate to Compute Engine > VM Instances.
  2. Find your VM and click the SSL button when it becomes available.
  3. Tail the syslog (tail -f /var/log/syslog) and look for either “google_metadata_script_runner” or “startup-script”.
  4. You will find records like the following when the script finishes.
google_metadata_script_runner[768]: startup-script exit status 0
google_metadata_script_runner[768]: Finished running startup scripts.

Verify if Nginx is working properly

  1. Navigate to Compute Engine > VM Instances.
  2. Find your VM and copy the External IP.
  3. Type http://<External IP> in the browser to check the results.
  4. You must see the Hello World! message.

Point your domain to the VM IP.

  1. Navigate to Compute Engine > VM Instances.
  2. Find your VM and copy the External IP.
  3. In your DNS provider console, point your domain’s “A Record” to the VM External IP (DNS changes can take a while to propagate).
  4. You must see the “Hello word!” (with the “not secure” message) when opening your domain on a browser.

Enable SSL

The Startup script is prepared to install or renew the certificates every time that the VM is restarted.

if [ -f ~/done.txt ]; then 
   python3 -m venv /opt/certbot/
   /opt/certbot/bin/pip install --upgrade pip
   /opt/certbot/bin/pip install certbot certbot-nginx
   ln -s /opt/certbot/bin/certbot /usr/bin/certbot
   certbot --nginx -d $DOMAIN -d www.$DOMAIN -m $EMAIL --agree-tos --keep-until-expiring
   exit 0;
fi
  1. Navigate to Compute Engine > VM Instances.
  2. Select your VM and press Reset.
  3. Verify the certificates deployment (cat /var/log/syslog | grep startup-script)
  4. You must see the “Hello word!” (without the “not secure” message) when opening your domain on a browser.

References

https://cloud.google.com/secret-manager/docs/accessing-the-api

https://certbot.org

Leave a Reply