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
- Google Cloud account
- Basic knowledge of Linux commands
- 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.
- Navigate to IAM & Admin > Service accounts.
- Click Create service account.
- Enter a Service account name.
- Write down the generated Email address.
- Click Done.
Configure MySQL Root Password with Google Cloud Secret Manager
- Navigate to Security > Secret Manager.
- Click Create secret.
- Enter the name: <your-site-name>-mysql-password.
- Enter the password as secret value.
- Click Create secret.
- Select the Permissions tab.
- Click Grant Access.
- Enter the newly created Service Account e-mail address as the New Principal
- Select the Secret Manager Secret Accessor role.
- 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
- Navigate to Compute Engine > VM Instances.
- Find your VM and click the SSL button when it becomes available.
- Tail the syslog (
tail -f /var/log/syslog
) and look for either “google_metadata_script_runner” or “startup-script”. - 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
- Navigate to Compute Engine > VM Instances.
- Find your VM and copy the External IP.
- Type http://<External IP> in the browser to check the results.
- You must see the Hello World! message.
Point your domain to the VM IP.
- Navigate to Compute Engine > VM Instances.
- Find your VM and copy the External IP.
- In your DNS provider console, point your domain’s “A Record” to the VM External IP (DNS changes can take a while to propagate).
- 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
- Navigate to Compute Engine > VM Instances.
- Select your VM and press Reset.
- Verify the certificates deployment (
cat /var/log/syslog | grep startup-script
) - 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