[一撃]CentOS7にWordPressをインストールする一撃シェルスクリプト


以前、CentOS6にWordPressをインストールする一撃シェルスクリプトを公開しましたが、2014/12/25にさくらのクラウド パブリックアーカイブにCentOS7が追加されたので、CentOS7にWordPressを一撃インストールするスタートアップスクリプトを作成しました。また、ISOイメージからインストールした素っぴんのCentOS7でも動くことも確認しています。

※ ネットワークが繋がらない場合

パブリックアーカイブのCentOS7はeth0のインターフェイスが自動起動するようになっていますが、ISOイメージからインストールした場合、connection.autoconnectがnoになっていることによりインターフェイスが自動起動しないことがあります。コンソールからrootユーザーでログインし、以下のコマンドを実行します。

# nmcli con mod eth0 connection.autoconnect "yes"
# systemctl reboot

再起動後、sshログインができればOKですが、nmcliコマンドで以下のように確認します。

# nmcli connection show eth0 | grep ^connection.autoconnect
connection.autoconnect:                 yes

上記のようにconnection.autoconnectがyesになっていればOKです。なお、これはバッドノウハウですが、OSのインストーラーでネットワークインターフェイスをOFF/ONし、IPアドレスが127.0.0.1から変われば上記対応は不要なはずです。。。

さて、ここから本題ですが、今回作成したスタートアップスクリプトの仕様は主に以下の通りです。

  • ドキュメントルートは /home/vhosts/${HOSTNAME}/public_html
  • DB名、DBユーザー名は /home/vhosts 以下のディレクトリ数で自動採番(バーチャルホスト削除時のデクリメントには対応していません)
  • MySQLのrootユーザーおよびWordPress用のユーザーのパスワードは自動生成
  • ブログ名、ブログのログイン名、ブログのパスワード、ブログ管理者メールアドレスは変数にて設定。基本的にここしかメンテナンスしなくてよい。

なお、制約事項として、インストール対象のサーバーはhostsかDNSで名前解決できている必要があります。IPアドレス直での運用はテストしていませんw それでは、主な箇所について説明します。

■ 変数設定

#!/bin/bash
# @sacloud-once

BLOGTITLE=nullpopopo
BLOGADMIN=nullpopopo
BLOGPW=Bl0Gp@SsW0rD
ADMINMAIL=root@localhost.localdomain

最初に、上記のようにブログタイトル(BLOGTITLE)から管理者メールアドレス(ADMINMAIL)までを変数に格納するようにしました。ブログタイトルは日本語が使えます(ただし、「(」「)」を使うと不具合出るっぽい)。スペースなどが含まれるときはダブルクォートで囲みましょう。管理者メールアドレスですが「root@localhost」のような形式だとPostfixに怒られるので、username@FQDNの形式にしましょう。

■ リポジトリのインストール

一部のパッケージでepelからインストールするものがあるのと、PHPは5.6を使いたいのと、gdライブラリを2015/01/03時点で最新のものを利用したい(php5.6のphp-gdがbaseリポジトリのgdではなくremiリポジトリのgd-lastを要求する)ので、remiリポジトリをインストールします。さくらのパブリックアーカイブからインストールしたマシン(以下さくらのクラウド)では最初からこれらのリポジトリが使えるようになっていますが、汎用性をもたせるために、リポジトリのファイル有無をtestコマンドで確認して条件分岐するようにしています。

if [ ! -f /etc/yum.repos.d/epel.repo ];
then
  yum -y install epel-release
  mkdir /etc/yum.repos.d/BACKUP/
  cp -p /etc/yum.repos.d/epel.repo{,.orig}
  sed -i "s/enabled=1/enabled=0/" /etc/yum.repos.d/epel.repo
fi

if [ ! -f /etc/yum.repos.d/remi.repo ];
then
  yum -y install http://remi.kazukioishi.net/enterprise/remi-release-7.rpm
fi

epelリポジトリはインストールすると自動で有効になっているので、一旦無効化します。remiリポジトリはデフォルトで無効設定なので特に何もしません。以降、これらのリポジトリを使って何かインストールするときは「--enablerepo=〜〜」します。

■ firewalld設定

CentOS7からは、iptablesのフロントエンドにfirewalldを利用するようになりました(firewalldを止めてiptablesを引き続き使うのも可)。さくらのクラウドでは、firewalldが停止しているため、これを起動してから設定することにします。外部からの穴あけはhttpを追加します。

if [ 3 = $(systemctl status firewalld.service > /dev/null ; echo $?) ];
then
  systemctl start firewalld.service
fi
systemctl enable firewalld.service
firewall-cmd --zone=public --add-service http
firewall-cmd --zone=public --add-service http --permanent

systemctlで起動するサービスは、systemctl status 〜〜〜.service で起動停止の確認ができます。停止していると終了ステータスが3なので、この場合に起動するようにしています。また、firewall-cmdでhttpサービスを追加するのですが、これだけでは再起動後に設定が失われるため、 --permanent をつけて恒久的な設定をします。ちなみに、 --permanent をつけない設定を省略してはダメみたいです。。。

■ mysql-serverインストールおよび設定

MySQLは最新版を利用したいので、mysql-community-releaseをインストールしてからmysql-community-serverパッケージをインストールします。初期設定ですが、対話式のmysql_secure_installationを使うと自動化できないので、スクリプト中で直接コマンドを実行しています。

yum -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
yum -y install mysql-community-server
systemctl start mysqld.service
systemctl enable  mysqld.service
mysql -u root -e "SET PASSWORD FOR root@localhost=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@\"${HOSTNAME}\"=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@127.0.0.1=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@\"::1\"=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "delete from mysql.user where user='';"
mysql -u root -p${ROOTPW} -e 'FLUSH PRIVILEGES;'

ここに出てくる変数ROOTPWですが、これはスクリプト前半で自動生成されるものです。rootユーザーのパスワード設定と匿名ユーザーの削除をしてから権限テーブルを再読み込みしています。

■ PHP設定

/etc/php.iniの設定は以下のようにしています。

sed -i 's/memory_limit = 128M/memory_limit = 256M/' /etc/php.ini
sed -i 's/post_max_size = 8M/post_max_size = 32M/' /etc/php.ini
sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 128M/' /etc/php.ini

今回は決め打ちで値を設定していますが、マシンパワーによって変更してみるとよいでしょう。 /etc/php.d/40-apcu.ini と /etc/php.d/10-opcache.ini は以下のようにしています。

sed -i 's/;apc.shm_size=32M/apc.shm_size=128M/' /etc/php.d/40-apcu.ini
sed -i 's/;opcache.revalidate_freq=2/opcache.revalidate_freq=60/' /etc/php.d/10-opcache.ini

こちらも性能試験をしながら変更してください。

chgrp nginx /var/lib/php/{session,wsdlcache}

/var/lib/php/session と /var/lib/php/wsdlcache の両ディレクトリは、グループがapacheになっていたので、nginxに変更しました。

■memcachedインストールおよび設定

インストール後はMAXCONNとCACHESIZEの変更だけしています。

yum -y --enablerepo=remi install memcached
mkdir -p /etc/sysconfig/BACKUP/
cp -p /etc/sysconfig/memcached /etc/sysconfig/BACKUP/memcached.orig
sed -i 's/MAXCONN="1024"/MAXCONN="1024"/' /etc/sysconfig/memcached
sed -i 's/CACHESIZE="64"/CACHESIZE="384"/' /etc/sysconfig/memcached
systemctl start memcached.service
systemctl enable memcached.service

上記の例ではMAXCONNは事実上変更なしですが、マシンパワーに合わせて変える余地としてコードにしています。CACHESIZEは、たぶんこのブログ1つを運用するくらいの記事数だったらこのくらいでいいかなーという値にしていますが、こちらも好きずきで変えてみてください。

■ WordPressインストール

実はちょっとハマりました。ココ。まずはハマりどころを解決したコードを見てみましょう。

su - nginx --shell=/bin/bash --command="${WP} core download --locale=ja --path=${VHDIR}/"
su - nginx --shell=/bin/bash --command="${WP} core config --dbname=${DBNAME} --dbuser=${DBUSER} --dbpass=${DBUSERPW} --path=${VHDIR}/  --extra-php <<PHP
define('FS_METHOD', 'direct');
PHP"
su - nginx --shell=/bin/bash --command="${WP} core install --url=${HOSTNAME} --title=${BLOGTITLE} --admin_user=${BLOGADMIN} --admin_password=${BLOGPW} --admin_email=${ADMINMAIL} --path=${VHDIR}/"

わざわざnginxユーザーで実行するようにしています。rootユーザーでwp-cliを実行しようとするとエラーになってしまうのでこうしています。nginxユーザーはシェルを持たないので、シェルを指定して実行しています。

次にwp core configで最後に --extra-phpでヒアドキュメントの中に「define('FS_METHOD', 'direct');」を入れていますが、これはプラグインのダウンロードなどを行うときにFTP接続を必須としないようにしています。

というわけで、以下コード全文です。(クリックで大きくなります)

#!/bin/bash
# @sacloud-once

BLOGTITLE=nullpopopo
BLOGADMIN=nullpopopo
BLOGPW=Bl0Gp@SsW0rD
ADMINMAIL=root@localhost.localdomain

mkdir -p /home/vhosts/${HOSTNAME}
VHDIR=/home/vhosts/${HOSTNAME}/public_html
NUM=$(ls /home/vhosts/ | wc -l)
DBNAME=$(printf "wpdb%04d" ${NUM})
DBUSER=$(printf "user%04d" ${NUM})
WP=/usr/local/bin/wp
DOWNLOADURL=https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
PARAMDIR=${HOME}/.mysql
PARAMFILE=${PARAMDIR}/MySQLPARAM
mkdir -p ${PARAMDIR}
echo "user root $(cat /dev/urandom | tr -dc '[:alnum:]' | head -c 8)" > ${PARAMFILE}
echo "DBPARAM ${DBNAME} ${DBUSER} $(cat /dev/urandom | tr -dc '[:alnum:]' | head -c 8)" >> ${PARAMFILE}
ROOTPW=$(grep ^user ${PARAMFILE} | awk '{print $NF}')
DBUSERPW=$(grep ^"DBPARAM ${DBNAME} ${DBUSER}" ${PARAMFILE} | awk '{print $NF}')

cp -p /etc/selinux/config{,.orig}
sed -i 's/enforcing$/disabled/' /etc/selinux/config

if [ ! -f /etc/yum.repos.d/epel.repo ];
then
  yum -y install epel-release
  mkdir /etc/yum.repos.d/BACKUP/
  cp -p /etc/yum.repos.d/epel.repo{,.orig}
  sed -i "s/enabled=1/enabled=0/" /etc/yum.repos.d/epel.repo
fi

if [ ! -f /etc/yum.repos.d/remi.repo ];
then
  yum -y install http://remi.kazukioishi.net/enterprise/remi-release-7.rpm
fi

yum -y install bind-utils telnet wget nkf unzip git dstat mailx
yum -y --enablerepo=epel install htop

cp -p /etc/ssh/sshd_config{,.orig}
sed -i 's/#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
sed -i 's/GSSAPIAuthentication yes/GSSAPIAuthentication no/' /etc/ssh/sshd_config
sed -i 's/GSSAPICleanupCredentials yes/GSSAPICleanupCredentials no/' /etc/ssh/sshd_config
sed -i 's/#GSSAPIStrictAcceptorCheck yes/GSSAPIStrictAcceptorCheck no/' /etc/ssh/sshd_config
sed -i 's/#GSSAPIKeyExchange no/GSSAPIKeyExchange no/' /etc/ssh/sshd_config
systemctl restart sshd.service

yum -y update

cp -p /etc/postfix/main.cf{,.orig}
sed -i "s/#myhostname = virtual.domain.tld/#myhostname = virtual.domain.tld\nmyhostname = ${HOSTNAME}/" /etc/postfix/main.cf
sed -i "s/#inet_interfaces = all/inet_interfaces = all/" /etc/postfix/main.cf
sed -i "s/inet_interfaces = localhost/#inet_interfaces = localhost/" /etc/postfix/main.cf
sed -i 's/#myorigin = $myhostname/myorigin = $myhostname/' /etc/postfix/main.cf
sed -i "s/#home_mailbox = Maildir/home_mailbox = Maildir/" /etc/postfix/main.cf
systemctl restart postfix.service

if [ 3 = $(systemctl status firewalld.service > /dev/null ; echo $?) ];
then
  systemctl start firewalld.service
fi
systemctl enable firewalld.service
firewall-cmd --zone=public --add-service http
firewall-cmd --zone=public --add-service http --permanent

yum -y install http://dev.mysql.com/get/mysql-community-release-el7-5.noarch.rpm
yum -y install mysql-community-server
systemctl start mysqld.service
systemctl enable  mysqld.service
mysql -u root -e "SET PASSWORD FOR root@localhost=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@\"${HOSTNAME}\"=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@127.0.0.1=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "SET PASSWORD FOR root@\"::1\"=PASSWORD('${ROOTPW}');"
mysql -u root -p${ROOTPW} -e "delete from mysql.user where user='';"
mysql -u root -p${ROOTPW} -e 'FLUSH PRIVILEGES;'

yum -y --enablerepo=remi install gd-last fontconfig fontpackages-filesystem jbigkit-libs libX11 libX11-common libXau libXpm libjpeg-turbo libpng libtiff libvpx libxcb
yum -y --enablerepo=epel --enablerepo=remi-php56 install php-cli php-pdo php-pear php-pecl-igbinary php-pecl-jsonc php-pecl-msgpack php-process php-common php-fpm php-gd php-intl php-mbstring php-mcrypt php-mysqlnd php-opcache php-pecl-apcu php-pecl-geoip php-pecl-memcache php-pecl-memcached php-pecl-zip php-xml GeoIP libevent libmcrypt libmemcached libtool-ltdl libxslt t1lib libicu

cp -p /etc/php-fpm.d/www.conf{,.orig}
sed -i 's/^user\ \= apache/\;user\ \= apache\nuser\ \=\ nginx/' /etc/php-fpm.d/www.conf
sed -i 's/^group\ \= apache/\;group\ \= apache\ngroup\ \=\ nginx/' /etc/php-fpm.d/www.conf
cp -p /etc/php.ini{,.orig}
sed -i 's/\;date.timezone\ \=/\;##--@--##date.timezone\ \=\ndate.timezone\ \=\ Asia\/Tokyo/' /etc/php.ini
sed -i 's/memory_limit = 128M/memory_limit = 256M/' /etc/php.ini
sed -i 's/post_max_size = 8M/post_max_size = 32M/' /etc/php.ini
sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 128M/' /etc/php.ini 
mkdir /etc/php.d/BACKUP
cp -p /etc/php.d/40-apcu.ini /etc/php.d/BACKUP/40-apcu.ini.orig
sed -i 's/;apc.shm_size=32M/apc.shm_size=128M/' /etc/php.d/40-apcu.ini
cp -p /etc/php.d/10-opcache.ini /etc/php.d/BACKUP/10-opcache.ini.orig
sed -i 's/;opcache.revalidate_freq=2/opcache.revalidate_freq=60/' /etc/php.d/10-opcache.ini

yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
cp -p /etc/yum.repos.d/nginx.repo{,.orig}
sed -i 's/centos/mainline\/centos/' /etc/yum.repos.d/nginx.repo
yum -y install nginx

chgrp nginx /var/lib/php/{session,wsdlcache}

cp -p /etc/nginx/nginx.conf{,.orig}
cat << _EOL_ | tee /etc/nginx/nginx.conf
user  nginx;
worker_processes  $(cat /proc/cpuinfo | grep processor | wc -l);

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

worker_rlimit_nofile  2560;
events {
    worker_connections  1536;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    #log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
    #                  '\$status \$body_bytes_sent "\$http_referer" '
    #                  '"\$http_user_agent" "\$http_x_forwarded_for"';

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    tcp_nopush      on;
    tcp_nodelay     on;
    log_not_found   off;
    server_tokens   off;
    gzip            on;
    gzip_http_version 1.0;
        gzip_types text/plain
        text/xml
        text/css
        text/php
        application/xml
        application/xhtml+xml
        application/rss+xml
        application/atom_xml
        application/javascript
        application/x-javascript 
        application/x-httpd-php; 
        gzip_disable "MSIE [1-6]\.";
    gzip_disable "Mozilla/4"; 
    gzip_comp_level 9;
    gzip_vary on;
    gzip_static     on;
    gzip_min_length 1024;
    gzip_buffers 4 8k;
    limit_conn_zone   \$binary_remote_addr  zone=addr:10m;


    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}
_EOL_

VHOSTS=${HOSTNAME}
A=$(echo ${VHOSTS} | sed -e 's/ /,/g')
echo "mkdir -p /home/logs/$A /home/vhosts/$A/{src,public_html}" | sh
chown -R nginx:root /home/vhosts
chmod -R g+w /home/vhosts

mkdir /etc/nginx/conf.d/BACKUP/
mv /etc/nginx/conf.d/*.conf /etc/nginx/conf.d/BACKUP/
for A in ${VHOSTS}
do
cat << _EOL_ | tee /etc/nginx/conf.d/${A}.conf
server {
    listen       80;
    server_name  ${A};
    access_log  /home/logs/${A}/access_log  main;
    error_log  /home/logs/${A}/error_log;

    location / {
        root   /home/vhosts/${A}/public_html;
        index  index.php index.html index.htm;

        ## WordPressのパーマリンク設定をカスタム構造に ##
        if (-f \$request_filename) {
                expires 30d;
        }
        if (!-e \$request_filename) {
                rewrite ^.+?(\$/wp-.*) \$1 last;
                rewrite ^.+?(/.*\.php)\$ \$1 last;
                rewrite ^ /index.php last;
        }
        ## ここまで ##
    }

    location ~ \.php\$ {
        root   /home/vhosts/${A}/public_html;
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  \$document_root/\$fastcgi_script_name;
        client_max_body_size 256M;
        include        fastcgi_params;
    }

    error_page  404              /404.html;
    location = /404.html {
        root   /usr/share/nginx/html;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

_EOL_

done

curl -o ${WP} ${DOWNLOADURL}
chmod 755 ${WP}

yum -y --enablerepo=remi install memcached
mkdir -p /etc/sysconfig/BACKUP/
cp -p /etc/sysconfig/memcached /etc/sysconfig/BACKUP/memcached.orig
sed -i 's/MAXCONN="1024"/MAXCONN="1024"/' /etc/sysconfig/memcached
sed -i 's/CACHESIZE="64"/CACHESIZE="384"/' /etc/sysconfig/memcached
systemctl start memcached.service
systemctl enable memcached.service

systemctl start php-fpm.service
systemctl enable php-fpm.service

systemctl start nginx.service
systemctl enable nginx.service

mkdir -p /etc/logrotate.d/BACKUP/
cp -p /etc/logrotate.d/nginx /etc/logrotate.d/BACKUP/nginx.orig
cat << _EOL_ | tee /etc/logrotate.d/nginx
/var/log/nginx/*.log /home/logs/*/access_log /home/logs/*/error_log {
        daily
        missingok
        rotate 52
        compress
        delaycompress
        notifempty
        create 640 nginx root
        sharedscripts
        postrotate
                [ -f /var/run/nginx.pid ] && kill -USR1 \`cat /var/run/nginx.pid\`
        endscript
}
_EOL_

mysql -u root -p${ROOTPW} -e "CREATE DATABASE ${DBNAME} DEFAULT CHARACTER SET utf8;"
mysql -u root -p${ROOTPW} -e "GRANT ALL PRIVILEGES ON ${DBNAME}.* TO ${DBUSER}@localhost IDENTIFIED BY \"${DBUSERPW}\";"
mysql -u root -p${ROOTPW} -e "FLUSH PRIVILEGES;"
su - nginx --shell=/bin/bash --command="${WP} core download --locale=ja --path=${VHDIR}/"
su - nginx --shell=/bin/bash --command="${WP} core config --dbname=${DBNAME} --dbuser=${DBUSER} --dbpass=${DBUSERPW} --path=${VHDIR}/  --extra-php <<PHP
define('FS_METHOD', 'direct');
PHP"
su - nginx --shell=/bin/bash --command="${WP} core install --url=${HOSTNAME} --title=${BLOGTITLE} --admin_user=${BLOGADMIN} --admin_password=${BLOGPW} --admin_email=${ADMINMAIL} --path=${VHDIR}/"

systemctl reboot

いかがでしたでしょうか?これでさくらのクラウドや素っぴんのCentOS7にWordPressを一撃インストールすることができました。次回はブログ運用時に有用なコマンドライン(WP-CLIのtips)をご紹介したいと思います。

wordpress_20140103