Apache基本設定

更新途中。

環境

  • Apache2.2, 2.4
  • AWS ELB

モジュールの確認

$ /usr/sbin/httpd -l
Compiled in modules:
  core.c
  prefork.c
  http_core.c
  mod_so.c

DSO(Dynamic Shared Object)

実行時にモジュールを組み込める。
“httpd.conf” ファイルで “LoadModule” ディレクティブを使い、モジュールを指定する。

KeepAlive

ELBヘルスチェックの設定

ルート「/」へのチェックは、毎回トップへアクセスし、動的処理が入るため、負荷が高い。
ライトにする為、”_health_check.html”等適当にファイルを用意し、ヘルスチェック先を変更する。

アクセスログに正常にスタンプされることを確認。

"GET /_health_check.html HTTP/1.1" 200

ELBのタイムアウト時間/ApacheのKeepAliveを調整

ELBのデフォルトタイムアウト時間は、”60秒”である。
ELBは、コネクション生成コスト削減の為、常設コネクション(セッション維持)を確立を生成し、60秒毎(デフォルト)に再生成している。
Apache2.4系では、”mod_reqtimeout”がデフォルトで有効になっており、デフォルト値は”header=20-40,MinRate=500 body=20,MinRate=500″である。
TCPコネクション接続後、”20-40秒”のうちにHTTPヘッダーの応答がないコネクションは、破棄を行う。
デフォルト値ではbodyは20秒、headerは20秒以内に受信できないときはタイムアウトとみなし、データ送信中は500Bytes受信するごとに1秒、タイムアウトまでの時間を延長し、最大30秒まで延長することが可能。

ELBで常設コネクション(セッション維持)を行っているのに、Apache側でタイムアウトすると、408エラーが起こってしまう。セッションが切れてしまう為、切断されたセッションを繋ぎ直す余計な処理も走ることになる。

ELBのタイムアウト設定を変更し、Apache側のタイムアウトは変更しない場合

“KeepAliveTimeout”を設定している環境であれば、”KeepAliveTimeout”>”ELBアイドルタイムアウト”とし、そうでなければ、”ELBアイドルタイムアウト”を”5秒-50秒”に設定するのがよい(Apache2.2、2.4系では、”KeepAliveTimeout”のデフォルト値が”5秒”であり、5秒後に接続を遮断しコネクション再接続のコスト削減とサーバ側リソースとの調整を行っている為、ELBの”アイドルタイムアウト”を”5秒”まで短くしても問題ない。)。

ELBのタイムアウト設定を変更せず、Apache側のタイムアウトを変更する場合

“KeepAliveTimeout”を設定している環境であれば、”KeepAliveTimeout”の値 > “ELBアイドルタイムアウト”の値 とする。
AWSのドキュメントでは、ApacheのTimeout値は120秒を推奨値としている。
例えば、ELBのアイドルタイムアウト値を”60秒”のままにする場合、以下のように設定する。

  • Apacheタイムアウト時間: 120sec
  • keepalive: 90sec

▼設定例
/path/to/httpd.conf

<VirtualHost *:80>
  ServerName   www.example.com
  DocumentRoot /var/www/html/
  # Enable TCP keepalive
  Timeout 120
  KeepAlive On
  KeepAliveTimeout 90
  MaxKeepAliveRequests 100
  LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" combined
</VirtualHost>

ELB配下のApacheアクセスログにClientIPを表示する(Apache2.2系)

ELB配下のApacheアクセスログは、デフォルトだとClientIPではなくELBのIPが表示されてしまう。

10.20.0.80 - - [05/Sep/2017:16:45:08 +0900] "GET /_health_check.html HTTP/1.1" 200 227 "-" "ELB-HealthChecker/2.0"
10.20.1.168 - - [05/Sep/2017:16:45:08 +0900] "GET /_health_check.html HTTP/1.1" 200 227 "-" "ELB-HealthChecker/2.0"
$ yum --enablerepo=epel install mod_extract_forwarded

/etc/httpd/conf.d/mod_extract_forwarded.conf

LoadModule extract_forwarded_module modules/mod_extract_forwarded.so
MEForder refuse,accept
MEFrefuse all
MEFaccept all

Apacheの再起動を行う。

$ service httpd graceful

ELB配下のApacheアクセスログにClientIPを表示する(Apache2.4系)

“mod_remoteip”モジュールが読み込まれていることを確認する。
/etc/httpd/conf.modules.d/00-base.conf

LoadModule remoteip_module modules/mod_remoteip.so
$ apachectl -M | grep remoteip
 remoteip_module (shared)

/path/to/httpd-vhosts.conf

<VirtualHost *:80>
    ServerName xxx.net
    # IP check through ELB
    RemoteIPHeader X-Forwarded-For
    RemoteIPTrustedProxy 10.20.0.80/32
    RemoteIPTrustedProxy 10.20.1.168/32
    DocumentRoot /var/www/vhosts/xxx/htdocs/yyy
    <Directory "/var/www/vhosts/xxx/htdocs/yyy">
        Require all granted
    </Directory>
</VirtualHost>

LogFormatを変更する。

<IfModule log_config_module>
    #
    # The following directives define some format nicknames for use with
    # a CustomLog directive (see below).
    #
    #LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined # 追加
    #LogFormat "%h %l %u %t \"%r\" %>s %b" common
    LogFormat "%a %l %u %t \"%r\" %>s %b" common # 追加

access.logへ、ClientIPがスタンプされるようになる。

61.xxx.x.xxx - - [05/Sep/2017:17:16:01 +0900] "GET / HTTP/1.1" 200 65387 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"

Apacheの再起動を行う。

$ service httpd graceful

アクセス制限

全てのアクセスを許可

2.4系

<Directory "/admin">
  Require all granted
</Directory>

2.2系

<Directory "/admin">
  Order allow,deny
  Allow from all
</Directory>

全てのアクセスを拒否

2.4系

<Directory "/admin">
  Require all denied
</Directory>

2.2系

<Directory "/admin">
  Order allow,deny
  Deny from all
</Directory>

特定のIPのみ許可

2.4系

<Directory "/admin">
  Require ip xxx.xxx.xxx.xxx
</Directory>

2.2系

<Directory "/admin">
  Order deny,allow
  Deny from all
  Allow from xxx.xxx.xxx.xxx
</Directory>

IPによるアクセス等、設定したServerName以外でのアクセスには “403 Forbidden” を返す。

セキュリティの向上

“Trace method” を無効にする。
XSSの脆弱性がある場合に、APサーバー側でTrace methodが有効になっていると、”クロスサイトトレーシング”という脆弱性が発生する可能性があり、暗号化されていないBasic認証のID/パスワード/Cookieが漏洩する可能性がある。

/etc/httpd/conf/httpd.conf

TraceEnable off

反映を確認する。
“405 Method Not Allowed” と出力されていることを確認する。

$ curl -I https://{YOUR_DOMAIN}
HTTP/1.1 405 Method Not Allowed
Allow: GET
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/plain
Date: Mon, 25 Sep 2017 04:36:35 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Connection: keep-alive

welcomeページを非表示に。

$ cd /etc/httpd/conf.d/
$ mv welcome.conf welcome.conf.org

[AWS][WordPress] サーバー移管/初期設定

環境例

環境 Ver.
OS Amazon Linux AMI 2017.03.1.20170812 x86_64 HVM GP2
WordPress 4.8.1
Apache 2.4
MySQL 5.7
PHP 7.0
EC2 type t2.micro

環境構築

インスタンスを立てる

VPCの構築、Security Groupの設定、ELBの設定、RDSの構築、DNSの登録、Certificate Managerから証明書の発行等は今回、省略する。

既存サーバの状況確認

ミドルウェアインストール状況、DBの状態、バージョン確認等。

$ php -m
mysql> SELECT HOST, USER FROM `mysql`.`user`;
mysql> SHOW GRANTS FOR '{USER_NAME}'@'{HOST_NAME}'\G;

パッケージアップデート

$ yum update

# セキュリティパッケージの更新のみの場合
$ yum update --security

パッケージインストール

$ yum install tree dstat sysstat iotop htop

Crontab(オプション)

開発環境の場合、節約の為に例えば毎日22時にインスタンスが停止するよう設定する。
/etc/crontab

0 22 * * *     root    /sbin/shutdown -h now >/dev/null 2>&1

TimeZoneの変更

# オリジナルをバックアップ
$ cp /etc/localtime /etc/localtime.org
$ diff /etc/localtime /etc/localtime.org

$ ln -sf  /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ cp /etc/sysconfig/clock /etc/sysconfig/clock.org
$ diff /etc/sysconfig/clock /etc/sysconfig/clock.org

/etc/sysconfig/clock

# ZONEの変更
ZONE="Asia/Tokyo"
# falseにするとハードウェアのクロックもローカルタイムで設定されてしまう為、変更しない
UTC=true

反映の確認

$ /etc/init.d/crond restart
$ strings /etc/localtime
TZif2
TZif2
JST-9

ntpdateの起動

Amazon Linuxは初期状態でNTPによるシステムクロックの同期を行っている。

$ chkconfig ntpdate on
$ chkconfig --list | grep ntpdate

iptablesの停止

セキュリティグループを利用しているため、iptablesは停止する。

chkconfig iptables off
chkconfig ip6tables off
chkconfig --list | grep ip

文字コードの変更

/etc/sysconfig/i18n

LANG="ja_JP.UTF-8"

ホスト名の変更

/etc/sysconfig/network

HOSTNAME={YOUR_HOSTNAME}

各種パッケージインストール

$ yum install httpd24 php70 mysql php70-mysqlnd php70-mbstring php70-bcmath php70-gd php70-pecl-imagick php70-imap php70-intl php70-pecl-oauth php70-pgsql php70-soap php70-xmlrpc php70-opcache
$ service httpd start
$ chkconfig httpd on

# httpdが有効であることを確認。実行レベル 2/3/4/5 がonの必要がある。
$ chkconfig --list httpd
httpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

Apacheのテストページがブラウザへ表示されることを確認。
PHP情報ページが表示されることを確認。

$ echo "<?php phpinfo(); ?>" > /var/www/html/phpinfo.php

現行環境とPHPモジュールの差異がないことを確認。

PHP設定ファイル更新

$ cp /etc/php.ini /etc/php.ini.org

/etc/php.ini

# 検証/開発環境のみ
display_errors = On
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
date.timezone = Asia/Tokyo
expose_php = Off
[imagick]
extension=imagick.so

RDSのパラメータグループの設定

以下の設定でRDSのパラメータグループを作成/適用。

  • character-set-client-handshake: 1
  • skip-character-set-client-handshake: 1
  • character_set_client: utf8
  • character_set_connection: utf8
  • character_set_database: utf8
  • character_set_filesystem: utf8
  • character_set_results: utf8
  • character_set_server: utf8
  • time_zone: Asia/Tokyo
  • collation_connection: utf8_general_ci
  • collation_server: utf8_general_ci
  • max_connect_errors: 999999999
  • max_connections: 2048
  • wait_timeout: 100

httpd.confとVirtualHostの設定

$ cd /etc/httpd/conf/
$ cp -p httpd.conf httpd.conf.org
$ mkdir /etc/httpd/conf/vhosts
$ mkdir -p /var/www/vhosts/xxx/htdocs

/etc/httpd/conf/httpd.conf

# 96行目付近
#ServerName www.example.com:80
ServerName xxx.com:80

# 121行目付近
DocumentRoot "/var/www/vhosts"

#
# Relax access to content within /var/www.
#
#<Directory "/var/www">
#    AllowOverride None
#    # Allow open access:
#    Require all granted
#</Directory>

# 133行目付近
#<Directory "/var/www/html">
<Directory "/var/www/vhosts">

# 154行目付近
#AllowOverride None
AllowOverride All

# 最終行付近
Include /etc/httpd/conf/vhosts/*.conf
KeepAlive On
KeepAliveTimeout 15
Timeout 300
$ mkdir /var/www/dvh

/etc/httpd/conf/vhosts/00_default_virtualhost.conf

<VirtualHost *:80>
    DocumentRoot /var/www/dvh/
    ServerName dummy
    ServerSignature Off
    <Location />
       Order deny,allow
       Deny from All
       Allow from 172
    </Location>
</VirtualHost>

/etc/httpd/conf/vhosts/httpd-vhosts.conf

<VirtualHost *:80>
    ServerName xxx.com
    DocumentRoot /var/www/vhosts/xxx/htdocs/wordpress
    <Directory "/var/www/vhosts/xxx/htdocs/wordpress">
        Require all granted
    </Directory>
</VirtualHost>

コンテンツ/DBデータを復元

# コンテンツ/dumpの取得
$ mysqldump --databases {DB_NAME} --default-character-set=utf8 --add-drop-database --user={USER_NAME} --password --host={HOST_NAME} > ./xxx.sql
$ GZIP=-9 tar czf xxx.tar.gz /path/to/directory

$ scp -P {PORT_NUM} -p {USER_NAME}@{HOST_NAME}:/path/to/xxx.sql.tar.gz ~/

# コンテンツ/dumpの復元
$ tar -zxf contents.tar.gz
$ tar -zxf dump.sql.tar.gz
$ mysql --databases {DB_NAME} --user={USER_NAME} --password --host={HOST_NAME} < ./xxx.sql

コンテンツディレクトリのPermission変更

$ chown apache:apache htdocs
$ find . -type d -exec chmod 0755 {} \;
$ find . -type f -exec chmod 0644 {} \;
$ chown -R apache:apache .
$ chmod -R g+w .
$ chmod 400 wp-config.php
$ chmod 644 .htaccess

wp-config.php の書き換え

/var/www/vhosts/xxx/htdocs/xxx/wp-config.php

define('DB_NAME', '{DB_NAME}');

/** MySQL のユーザー名 */
define('DB_USER', '{DB_USER}');

/** MySQL のパスワード */
define('DB_PASSWORD', '{DB_PASS}');

/** MySQL のホスト名 (ほとんどの場合変更する必要はありません。) */
define('DB_HOST', '{DB_HOST}:3306');

/** データベーステーブルのキャラクターセット (ほとんどの場合変更する必要はありません。) */
define('DB_CHARSET', 'utf8');

# 開発環境の場合は、Jetpackを開発者モードへ変更する。
define( 'JETPACK_DEV_DEBUG', true );

DB日付確認

日本時間となっていることを確認する。

mysql> SELECT now();
+---------------------+
| now()               |
+---------------------+
| 2017-04-xx 17:39:19 |
+---------------------+
1 row in set (0.00 sec)

DB内URL置換

xxx.jp → xxx.com/xxx 等へURLを変換する。
https://interconnectit.com/products/search-and-replace-for-wordpress-databases/ のツールを利用する。
“Search Regex” というWordPressプラグインでも置換が可能。

管理画面のサイトURL

http://xxx/wp-admin/options-general.php
サイトURLが新規URLへ変更されていることを確認する。

.htaccessの設定

  • wp-config.phpのアクセス制御
  • SSLへリダイレクト (ELB/CloudFrontへも対応)

/var/www/vhosts/xxx/htdocs/wordpress/wp-config.php

<?php
# add under for ELB
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
    $_SERVER['HTTPS'] = 'on';
}
/**
 * The base configuration for WordPress

/var/www/vhosts/xxx/htdocs/wordpress/.htaccess

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !^https$
RewriteCond %{HTTP:CloudFront-Forwarded-Proto} !=https
RewriteCond %{REQUEST_URI} !^_health_check\.html$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>


<files wp-config.php>
    order allow,deny
    deny from all
</files>

# Not allowed access to .htaccess and .htpasswd
<Files ~ "^\.ht">
    Order allow,deny
    Deny from all
    Satisfy All
</Files>

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress

/var/www/vhosts/xxx/htdocs/wordpress/wp-admin/.htpasswd

# http://www.luft.co.jp/cgi/htpasswd.php で作成した値を貼り付け。

/var/www/vhosts/xxx/htdocs/wordpress/wp-admin/.htaccess

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.php$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
</IfModule>

# Basic Auth
AuthType Basic
AuthName "Input your ID and Password."
AuthUserFile /var/www/vhosts/xxx/htdocs/wordpress/wp-admin/.htpasswd
AuthGroupfile /dev/null
require valid-user

# Not allowed access to .htaccess and .htpasswd
<Files ~ "^\.ht">
    Order allow,deny
    Deny from all
    Satisfy All
</Files>

# maybe admin-ajax.php used by some plugin
<FilesMatch "(admin-ajax.php)$">
    Satisfy Any
    Order allow,deny
    Allow from all
    Deny from none
</FilesMatch>

Swapの作成

MB単位でTotal行のメモリ出力を行う。

$ free -tm
total       used       free     shared    buffers     cached
Mem:          3953       3315        637          0        161       2501
-/+ buffers/cache:        652       3300
Swap:            0          0          0
Total:        3953       3315        637

同程度のSwap容量を確保。

$ dd if=/dev/zero of=/swapfile bs=1M count=4000
4000+0 レコード入力
4000+0 レコード出力
4194304000 バイト (4.2 GB) コピーされました、 55.568 秒、 75.5 MB/秒
$ mkswap /swapfile
$ swapon /swapfile
$ chmod 600 /swapfile
$ free -tm

/etc/fstab

/swapfile swap swap defaults 0 0

サーバ構築後の管理画面設定

個人的に下記をインストール/有効化/設定している。

SEO対策プラグインの有効化

“All In One SEO Pack” をインストール/有効化

BackWPup

“AWS S3” へDump/コンテンツのBackupを定期的に行っている。

Better Delete Revision

作成した記事の “Revision” 等を削除し、動作を軽くする。

Comet Cache

キャッシュを消す。

SyntaxHighlighter Evolved

ソースコードのSyntaxをハイライト表示させる。

WordPressのツールバーを利用しないように設定

メニュー > JetPack > Writing > WordPress.com toolbar

“WordPress.com ツールバーを有効化” のチェックを外す。

Markdown設定

メニュー > ジェットパック > 設定 > composing

“プレーンテキストの Markdown 構文で投稿やページに書き込み” にチェック。

メニュー > あなたのプロフィール > ビジュアルエディター

“ビジュアルリッチエディターを使用しない” にチェック。