Để cài đặt WordPress với tên miền mới trên VPS/Cloud server khá là nhiều thao tác mất thời gian. Thế là tôi quyết định làm một Shell Script làm tất tần tật những việc đó.

Script create-wpblog.sh thực hiện những công việc sau:

  • Tạo file cấu hình Apache VirtualHost cho domain mới hỗ trợ PHP và CGI.
  • Tạo chứng chỉ SSL miễn phí thông qua dịch vụ Let’s Encrypt.
  • Cài đặt WordPress.

Cấu hình tên miền trỏ về web server

Đây là công việc duy nhất phải làm bằng tay, bởi vì mỗi nhà cung cấp tên miền sẽ có Control Panel để cấu hình tương ứng. Tôi cũng không đề cập cách làm cụ thể ở đây.

Chỉ lưu ý là sau khi cấu hình tên miền xong thì nên đợi khoảng 5 phút (nhiều khi lâu hơn) để DNS được cập nhật đầy đủ. Vì nếu không không những bạn không truy cập được mà còn dính DNS cache trên máy client.

Chuẩn bị môi trường

Chương trình này cần một số dependencies:

  • LAMP (Linux Apache2, MariaDB, PHP)
  • certbot
  • wp-cli

Tạo chứng chỉ SSL

Mặc định Apache2 có một web root, ví dụ trên Debian sẽ là /var/www/html. Ta sẽ sử dụng web root này để tạo chứng chỉ SSL cho các tên miền gắn với Server này bằng lệnh certbot.

/usr/local/bin/create-cert.sh

#!/bin/bash
# create-cert.sh [-a ALIASES ] [-m EMAIL] DOMAIN
# @author Nguyen Hong Hai
#

WEBROOT=/var/www/html

while getopts ":a:m:" o; do
    case "${o}" in
        a )
            # comma separated domain aliases
            ALIASES="${OPTARG}"
            ;;
        m )
            EMAIL="${OPTARG}"
            ;;
        \? )
            echo "Invalid Option: -${OPTARG}" 1>&2
            exit 1
            ;;
        : )
            echo "Invalid Option: -${OPTARG} requires an argument" 1>&2
            exit 1
            ;;
    esac
done
shift $((OPTIND-1))

DOMAIN="${1}"

certbot_ARGS=( certonly --non-interactive --webroot --agree-tos -w "${WEBROOT}" --expand -d "${DOMAIN}" )

if [ ! -z "${ALIASES}" ]; then
    IFS=',' read -ra ALIASES <<< "${ALIASES}"
    for domain in "${ALIASES[@]}"; do
        certbot_ARGS+=( -d "${domain}" )
    done
fi

if [ ! -z "${EMAIL}" ]; then
    certbot_ARGS+=( -m "${EMAIL}" )
else
    certbot_ARGS+=( --register-unsafely-without-email )
fi

certbot "${certbot_ARGS[@]}"

Tạo Apache2 VirtualHost

Ở đây file cấu hình VirtualHost sẽ được tự động sinh từ một template như dưới đây. Tất nhiên bạn có thể chỉnh sửa nếu muốn.

/etc/icreativ/sample-vhost.conf

<VirtualHost *:80>
    ServerName __MY_DOMAIN__
    ServerAlias __MY_ALIASES__
    ServerAdmin __MY_EMAIL__
    DocumentRoot __MY_HTDOCS__

    <Directory __MY_HTDOCS__>
        Options MultiViews SymLinksIfOwnerMatch IncludesNoExec
        AllowOverride All
        Require all granted
        php_admin_flag engine On
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerName __MY_DOMAIN__
        ServerAlias __MY_ALIASES__
        ServerAdmin __MY_EMAIL__
        DocumentRoot __MY_HTDOCS__

        <Directory __MY_HTDOCS__>
            Options MultiViews SymLinksIfOwnerMatch IncludesNoExec
            AllowOverride All
            Require all granted
            php_admin_flag engine On
        </Directory>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        SSLEngine on
        SSLCertificateFile /etc/letsencrypt/live/__MY_CERT__/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/__MY_CERT__/privkey.pem
    </VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Các biến __MY_DOMAIN__, __MY_ALIASES__, __MY_EMAIL__, __MY_HTDOCS____MY_CERT__ sẽ được script dưới đây xử lý thay thế tương ứng với tham số truyền vào.

Script create-vhost.sh tạo file VirtualHost theo template nêu trên và sẽ xin phép tạo chứng chỉ SSL bằng create-cert.sh nếu tên miền và các domain alias chưa được đăng ký.

/usr/local/bin/create-vhost.sh

#!/bin/bash
# create-vhost.sh [-a ALIASES ] [-w WEBROOT ] [-m EMAIL] DOMAIN
# @author Nguyen Hong Hai
#

CONFIG_TEMPLATE="/etc/icreativ/template-vhost.conf"

# Escape SED command input
sed_esc()
{
    echo "$@" | sed -e 's/[]\/$*.^[]/\\&/g'
}

while getopts ":a:m:w:" o; do
    case "${o}" in
        a )
            # Comma separated domain aliases
            ALIASES="${OPTARG}"
            ;;
        m )
            EMAIL="${OPTARG}"
            ;;
        w )
            WEBROOT="${OPTARG}"
            ;;
        \? )
            echo "Invalid Option: -${OPTARG}" 1>&2
            exit 1
            ;;
        : )
            echo "Invalid Option: -${OPTARG} requires an argument" 1>&2
            exit 1
            ;;
    esac
done
shift $((OPTIND-1))

DOMAIN="${1}"

certbot_ARGS=( certificates -d "${DOMAIN}")

if [ ! -z "${ALIASES}" ]; then
    IFS=',' read -ra DOMAINS <<< "${ALIASES}"
    for domain in "${DOMAINS[@]}"; do
        certbot_ARGS+=( -d "${domain}" )
    done
fi

sed_ARGS=( -r )
sed_ARGS+=( -e "s/__MY_DOMAIN__/$(sed_esc "${DOMAIN}")/g" )
sed_ARGS+=( -e "s/__MY_EMAIL__/$(sed_esc "${EMAIL}")/g" )
sed_ARGS+=( -e "s/__MY_HTDOCS__/$(sed_esc "${WEBROOT}")/g" )

if [ ! -z "${ALIASES}" ]; then
    sed_ARGS+=( -e "s/__MY_ALIASES__/$(sed_esc "${DOMAINS[@]}")/" )
else
    # Remove ServerAlias directive
    sed_ARGS+=( -e "/.*__MY_ALIASES__.*/d" )
fi

while :; do
    # Find existing certificate for the following domains
    CERTS=( $(certbot "${certbot_ARGS[@]}" 2>/dev/null | \
        grep 'Certificate Name: ' | \
        sed -r -e 's/^\s+Certificate Name: //g') )
    if [ -z "${CERTS}" ]; then
        read -p "No available SSL certificate. Type 'c' to create: " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Cc]$ ]]; then
            # Attempt to obtain a Let's Encrypt SSL certificate
            create-cert.sh -a "${ALIASES}" -m "${EMAIL}"
        else
             # Remove the HTTPS settings
            sed_ARGS+=(-e '/^<IfModule mod_ssl.c>$/,$d')
            break
        fi
    else
        sed_ARGS+=( -e "s/__MY_CERT__/$(sed_esc "${CERTS[-1]}")/g" )
        break
    fi
done

echo "================================================================="
echo "VirtualHost: ${APACHE_SITE_CONF}"
echo "================================================================="
sed "${sed_ARGS[@]}" ${CONFIG_TEMPLATE} | tee ${APACHE_SITE_CONF}

a2ensite ${DOMAIN}.conf
systemctl reload apache2

Cài đặt WordPress

Chương trình sử dụng script wp-install.sh hỗ trợ cài đặt WordPress bằng wp-cli.

Script cài đặt nhanh website WordPress

Với những công cụ hỗ trợ ở trên, quy trình cài đặt nhanh một trang WordPress của tôi có thể được tóm gọn trong một script đơn giản như sau:

/usr/local/bin/create-wpblog.sh

#!/bin/bash
# create-wpblog.sh DOMAIN WEBROOT SITEURL
# @author Nguyen Hong Hai
#
DOMAIN="${1}"
WEBROOT="${2}"
WP_SITE_URL="${3}"
ALIASES="www.${DOMAIN}"

WEBMASTER_EMAIL="webmaster@icreativ.pro"
WP_SITE_NAME="WordPress"
WP_ADMIN_USER="icreativ"
WP_ADMIN_EMAIL="webmaster@icreativ.pro"

mkdir -p ${WEBROOT}
chown www-data:www-data ${WEBROOT}

create-vhost.sh -a "${ALIASES}" -m "${EMAIL}" -w "${WEBROOT}" "${DOMAIN}"

# Install WordPress as the user www-data
su -u www-data -i -- wp-install.sh \
    -t "${WP_SITE_NAME}" \
    -l "${WP_SITE_URL}" \
    -u "${WP_ADMIN_USER}" \
    -m "${WP_ADMIN_EMAIL}"

Phân quyền executable cho script.

sudo chmod +x \
    /usr/local/bin/create-cert.sh \
    /usr/local/bin/create-vhost.sh \
    /usr/local/bin/create-wpblog.sh

Cách sử dụng

$ sudo create-wpblog.sh mydomain.com /home/mydomain.com/public_html https://mydomain.com

Sau khi cài đặt xong, bạn có thể truy cập website qua địa chỉ https://mydomain.com.