Hosting of WordPress on Azure Ubuntu VM with LEMP Stack
This guide provides a complete walkthrough for setting up a WordPress site on an Azure VM running Ubuntu. We will configure a LEMP (Linux, Nginx, MySQL, PHP) stack and set up WordPress.
Step 1: Create a VM in Azure
Log in to your Azure Portal.
Navigate to Virtual machines and click on + Create.
Choose your subscription and resource group (create a new one if necessary).
Enter a Virtual machine name.
Choose a Region.
Select an Image (e.g., Ubuntu 20.04 LTS).
Choose a Size for your VM.
Set up Administrator account with a username and SSH public key (or password).
Under Inbound port rules, allow SSH (22) and HTTP (80).
Click
Next:Disk
and thenNext:Networking
, check the boxDelete public IP and NIC when VM is deleted
Click Review + create and then Create after validation passes.
And download the ssh key.
Your VM
will be successfully created.
Step 2: Connect to Your VM
Once your
VM
is deployed, clickHome
andVirtual Machine
and go to its Overview page and note the Public IP address.Open the terminal where your ssh file
.pem
file is located and Connect to your VM via SSH:ssh -i your_username@your_vm_public_IP
.
Step 3: Create a bash file script.sh
nano script.sh
and paste following configuration and save the file, ctrl s
and ctrl x
.
#!/bin/bash
# Exit on error
set -e
# Strict mode
set -euo pipefail
IFS=$'\n\t'
#---------------------------------------
# CONFIGURATION VARIABLES - MODIFY THESE
#---------------------------------------
# Domain Settings
HOSTNAME="aisolutions.com" # Your domain name
# Database Settings
WP_DB_NAME="aisolution_db" # WordPress database name
WP_DB_ADMIN_USER="siddhant" # WordPress database user
MYSQL_ROOT_PASSWORD="YourStr0ng!RootPass" # MySQL root password
MYSQL_WP_ADMIN_USER_PASSWORD="YourStr0ng!WPPass" # WordPress database user password
# Installation Directories
WP_ROOT="/var/www/html/wordpress"
WP_BLOG_DIR="${WP_ROOT}/blog"
WP_SRC_DIR="${WP_ROOT}/src"
# PHP Version
PHP_VERSION="8.3"
# Nginx Settings
NGINX_CONFIG_DIR="/etc/nginx/sites-available"
CLIENT_MAX_BODY_SIZE="128M" # Maximum upload size
# WordPress Memory Limits
WP_MEMORY_LIMIT="256M"
WP_MAX_MEMORY_LIMIT="512M"
# WordPress Settings
WP_POST_REVISIONS=5 # Number of post revisions to keep
WP_AUTO_UPDATE_CORE="minor" # WordPress auto-update setting
WP_DEBUG=false # WordPress debug mode
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m'
#---------------------------------------
# Function Definitions
#---------------------------------------
print_status() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# Check if script is run as root
if [[ "$EUID" -ne 0 ]]; then
print_status "$RED" "Error: Please run as root with sudo."
exit 1
fi
# Update system
print_status "$GREEN" "Updating system packages..."
apt-get update
apt-get -y upgrade
apt-get -y autoremove
# Install required software repositories
print_status "$GREEN" "Adding required repositories..."
apt-get install -y software-properties-common
add-apt-repository -y ppa:ondrej/php
apt-get update
# Install LEMP stack and WordPress dependencies
print_status "$GREEN" "Installing LEMP stack and WordPress dependencies..."
apt-get install -y \
nginx \
mysql-server \
"php${PHP_VERSION}-fpm" \
"php${PHP_VERSION}-cli" \
"php${PHP_VERSION}-curl" \
"php${PHP_VERSION}-mysql" \
"php${PHP_VERSION}-gd" \
"php${PHP_VERSION}-intl" \
"php${PHP_VERSION}-mbstring" \
"php${PHP_VERSION}-soap" \
"php${PHP_VERSION}-xml" \
"php${PHP_VERSION}-zip" \
"php${PHP_VERSION}-imagick" \
"php${PHP_VERSION}-redis" \
unzip
# Configure Nginx
print_status "$GREEN" "Configuring Nginx..."
cat > "${NGINX_CONFIG_DIR}/${HOSTNAME}" <<EOF
server {
listen 80;
listen [::]:80;
server_name ${HOSTNAME} www.${HOSTNAME};
root ${WP_BLOG_DIR};
index index.php index.html index.htm;
# Increase body size limit for larger uploads
client_max_body_size ${CLIENT_MAX_BODY_SIZE};
# Gzip compression
gzip on;
gzip_vary on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# WordPress specific rules
location / {
try_files \$uri \$uri/ /index.php?\$args;
}
# PHP handling
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php${PHP_VERSION}-fpm.sock;
fastcgi_param SCRIPT_FILENAME \$document_root\$fastcgi_script_name;
include fastcgi_params;
fastcgi_intercept_errors on;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
# Security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Deny access to sensitive files
location ~ /\. {
deny all;
}
location = /favicon.ico {
log_not_found off;
access_log off;
}
location = /robots.txt {
log_not_found off;
access_log off;
allow all;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires max;
log_not_found off;
}
}
EOF
rm -f /etc/nginx/sites-enabled/default
ln -sf "${NGINX_CONFIG_DIR}/${HOSTNAME}" /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# Configure MySQL
print_status "$GREEN" "Configuring MySQL..."
mysql -u root <<EOF
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '${MYSQL_ROOT_PASSWORD}';
FLUSH PRIVILEGES;
EOF
# Secure MySQL installation
print_status "$GREEN" "Securing MySQL installation..."
mysql_secure_installation --user=root --password="${MYSQL_ROOT_PASSWORD}" --use-default
# Create WordPress database and user
print_status "$GREEN" "Creating WordPress database and user..."
mysql -u root --password="${MYSQL_ROOT_PASSWORD}" <<EOF
CREATE DATABASE IF NOT EXISTS ${WP_DB_NAME} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER '${WP_DB_ADMIN_USER}'@'localhost' IDENTIFIED BY '${MYSQL_WP_ADMIN_USER_PASSWORD}';
GRANT ALL PRIVILEGES ON ${WP_DB_NAME}.* TO '${WP_DB_ADMIN_USER}'@'localhost';
FLUSH PRIVILEGES;
EOF
# Install WordPress
print_status "$GREEN" "Installing WordPress..."
mkdir -p "${WP_SRC_DIR}" "${WP_BLOG_DIR}"
cd "${WP_SRC_DIR}"
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
mv latest.tar.gz "wordpress-$(date '+%Y-%m-%d').tar.gz"
cp -a wordpress/. "${WP_BLOG_DIR}/"
# Configure WordPress
print_status "$GREEN" "Configuring WordPress..."
WP_SECURE_SALTS=$(curl -s https://api.wordpress.org/secret-key/1.1/salt/)
cat > "${WP_BLOG_DIR}/wp-config.php" <<EOF
<?php
define('DB_NAME', '${WP_DB_NAME}');
define('DB_USER', '${WP_DB_ADMIN_USER}');
define('DB_PASSWORD', '${MYSQL_WP_ADMIN_USER_PASSWORD}');
define('DB_HOST', 'localhost');
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');
${WP_SECURE_SALTS}
\$table_prefix = 'wp_';
define('WP_DEBUG', ${WP_DEBUG});
define('WP_POST_REVISIONS', ${WP_POST_REVISIONS});
define('AUTOMATIC_UPDATER_DISABLED', false);
define('WP_AUTO_UPDATE_CORE', '${WP_AUTO_UPDATE_CORE}');
define('WP_MEMORY_LIMIT', '${WP_MEMORY_LIMIT}');
define('WP_MAX_MEMORY_LIMIT', '${WP_MAX_MEMORY_LIMIT}');
if ( ! defined('ABSPATH') ) {
define('ABSPATH', __DIR__ . '/');
}
require_once ABSPATH . 'wp-settings.php';
EOF
# Set correct permissions
print_status "$GREEN" "Setting permissions..."
chown -R www-data:www-data "${WP_ROOT}"
find "${WP_BLOG_DIR}" -type d -exec chmod 755 {} \;
find "${WP_BLOG_DIR}" -type f -exec chmod 644 {} \;
# Final status
print_status "$GREEN" "WordPress installation complete!"
echo "
Installation Summary:
--------------------
WordPress URL: https://${HOSTNAME}
WordPress directory: ${WP_BLOG_DIR}
Database name: ${WP_DB_NAME}
Database user: ${WP_DB_ADMIN_USER}
"
Cleanup Script
#!/bin/bash
# Exit on error
set -e
# Strict mode
set -euo pipefail
IFS=$'\n\t'
# Configuration variables from the installation script
HOSTNAME="aisolutions.com"
WP_ROOT="/var/www/html/wordpress"
NGINX_CONFIG_DIR="/etc/nginx/sites-available"
WP_DB_NAME="aisolution_db"
WP_DB_ADMIN_USER="siddhant"
MYSQL_ROOT_PASSWORD="YourStr0ng!RootPass"
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'
print_status() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
}
# Check if script is run as root
if [[ "$EUID" -ne 0 ]]; then
print_status "$RED" "Error: Please run as root with sudo."
exit 1
fi
print_status "$GREEN" "Starting cleanup process..."
# Step 1: Remove WordPress Files
if [[ -d "${WP_ROOT}" ]]; then
print_status "$GREEN" "Removing WordPress files..."
rm -rf "${WP_ROOT}"
else
print_status "$YELLOW" "WordPress files not found. Skipping..."
fi
# Step 2: Remove Nginx Configuration
if [[ -f "${NGINX_CONFIG_DIR}/${HOSTNAME}" ]]; then
print_status "$GREEN" "Removing Nginx configuration..."
rm -f "${NGINX_CONFIG_DIR}/${HOSTNAME}" /etc/nginx/sites-enabled/${HOSTNAME}
nginx -t && systemctl reload nginx || print_status "$RED" "Nginx reload failed. Please check manually."
else
print_status "$YELLOW" "Nginx configuration not found. Skipping..."
fi
# Step 3: Remove MySQL Database and User
print_status "$GREEN" "Removing MySQL database and user..."
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" <<EOF
DROP DATABASE IF EXISTS ${WP_DB_NAME};
DROP USER IF EXISTS '${WP_DB_ADMIN_USER}'@'localhost';
FLUSH PRIVILEGES;
EOF
# Step 4: Uninstall PHP and Nginx (Optional)
read -p "Do you want to uninstall PHP and Nginx as well? [y/N]: " uninstall_choice
if [[ "$uninstall_choice" =~ ^[Yy]$ ]]; then
print_status "$GREEN" "Uninstalling PHP and Nginx..."
apt-get purge -y php* nginx*
apt-get autoremove -y
apt-get autoclean
else
print_status "$YELLOW" "Skipping PHP and Nginx uninstallation..."
fi
# Step 5: Final Cleanup
print_status "$GREEN" "Performing final cleanup..."
apt-get autoremove -y
apt-get autoclean
print_status "$GREEN" "WordPress and its dependencies have been successfully removed."
How to Run the Script
Save the script as
wordpress-uninstall.sh
.Make the script executable:
chmod +x wordpress-uninstall.sh
Run the script as root or with
sudo
:sudo bash wordpress-uninstall.sh
What It Does
Removes WordPress files from
/var/www/html/wordpress
.Deletes the Nginx configuration for the domain.
Removes the MySQL database and user.
Optionally uninstalls PHP and Nginx.
Cleans up unused dependencies and packages.