バージョン(2023年8月4日現在)
OS | Amazon Linux 2023 |
PHP | 8.2.7 |
Nginx | nginx/1.24.0 |
AWSでEC2インスタンス起動
AWSコンソールにログインし、EC2インスタンス起動します。
今回はAmazon Linux 2023をチョイスしました。
※セキュリティグループのアタッチメントやEIPの関連付けなどは省略
移行元の Amazon Linux AMI-2018.3
ではパッケージ管理に yum
が使われていましたが、 Amazon Linux 2023では dnf
が使われているようです。
dnf(Dandified Yum)
は、Fedora、CentOS、RHEL(Red Hat Enterprise Linux)などのRPMベースのディストリビューションで使用されています。dnfはyumの後継ツールとして開発され、より高速なパッケージ解決が可能のようです。(体感値ですが)dnfはyumに比べ、たしかにかなり早いような気がします。
注意点
コマンドを実行する際には適宜sudo
コマンドを使うなどして適切な権限で実行してください。
タイムゾーン変更
# date
Fri Aug 4 07:37:44 UTC 2023
# timedatectl set-timezone Asia/Tokyo
Fri Aug 4 16:38:08 JST 2023
Nginx
# dnf install -y nginx
# nginx -v
nginx version: nginx/1.24.0
Nginxのconfファイルの設定は以下のようになっています。参考まで。
user nginx nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 128;
server_tokens off;
log_format main '$remote_addr - $upstream_cache_status [$time_local] $request '
'$status - $body_bytes_sent "$http_referer" '
'$http_user_agent $http_x_forwarded_for';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
#gzip
gzip on;
gzip_types text/plain
text/xml
text/css
application/xml
application/xhtml+xml
application/rss+xml
application/atom_xml
application/javascript
application/x-javascript
application/x-httpd-php
application/x-font-ttf
font/opentype
font/x-woff
font/x-woff2
application/vnd.ms-fontobject
image/svg+xml
video/mp4;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 4 32k;
gzip_static on;
gzip_vary on;
#proxy
proxy_cache_path /var/cache/nginx
levels=1:2
keys_zone=czone:16m
inactive=7d
max_size=60g;
proxy_temp_path /var/tmp/nginx;
proxy_cache czone;
proxy_cache_valid 200 301 302 10m;
proxy_cache_valid 404 5m;
proxy_cache_key "$scheme://$host$request_uri";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering on;
proxy_buffers 8 32k;
proxy_buffer_size 64k;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
send_timeout 600;
#fast-cgi
fastcgi_buffers 8 128k;
fastcgi_buffer_size 256k;
fastcgi_cache_path /var/cache/fast-cgi
levels=1:2
keys_zone=fczone:15m
inactive=7d
max_size=1000m;
fastcgi_temp_path /var/tmp/fast-cgi 1 2;
fastcgi_connect_timeout 60;
fastcgi_read_timeout 90;
fastcgi_send_timeout 60;
fastcgi_cache_valid 200 2h;
fastcgi_cache_valid 302 2h;
fastcgi_cache_valid 301 4h;
fastcgi_cache_valid any 1m;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
upstream backend {
ip_hash;
server unix:/var/run/php-fpm/php-fpm.sock;
}
index index.php index.html index.htm;
client_max_body_size 80M;
client_body_buffer_size 50M;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
#ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:15m;
ssl_buffer_size 8k;
ssl_session_timeout 32m;
add_header X-Cache $upstream_cache_status;
include /etc/nginx/conf.d/*.conf;
}
server {
listen 80;
server_name example.com;
rewrite ^(.*)$ https://example.com$1 permanent;
}
server {
listen 443 ssl http2;
server_name example.com;
root /path/to/project_name/public;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ciphers ECDHE+AESGCM:DHE+AESGCM:HIGH:!aNULL:!MD5;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains;';
resolver 8.8.4.4 8.8.8.8 valid=300s;
resolver_timeout 10s;
location ~* \.(eot|ttf|otf|woff|woff2)$ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';
add_header 'Access-Control-Allow-Method' 'GET, POST, OPTIONS, PUT, DELETE';
}
location ~ /\. { deny all; access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ ^/static/img/favicon { expires max; access_log off; log_not_found off; }
location ~ .*\.(txt|xml|js|css|gz|ico|jpe?g|gif|png|wmv|flv|swf|mpg|eot|otf|ttf|woff|woff2) {
access_log off;
expires 30d;
etag off;
break;
}
location / {
try_files $uri $uri/ /index.php?q=$uri&$args;
}
location ~ \.php$ {
set $do_not_cache 0;
if ($request_method != "GET") {
set $do_not_cache 1;
}
if ($http_cookie ~ ^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$) {
set $do_not_cache 1;
}
if ($http_x_wap_profile ~ ^[a-z0-9\"]+) {
set $do_not_cache 1;
}
if ($http_profile ~ ^[a-z0-9\"]+) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^.*(2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800).*) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^(w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-).*) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^(DoCoMo/|J-PHONE/|J-EMULATOR/|Vodafone/|MOT(EMULATOR)?-|SoftBank/|[VS]emulator/|KDDI-|UP\.Browser/|emobile/|Huawei/|IAC/|Nokia|mixi-mobile-converter/)) {
set $do_not_cache 1;
}
if ($http_user_agent ~ (DDIPOCKET\;|WILLCOM\;|Opera\ Mini|Opera\ Mobi|PalmOS|Windows\ CE\;|PDA\;\ SL-|PlayStation\ Portable\;|SONY/COM|Nitro|Nintendo)) {
set $do_not_cache 1;
}
fastcgi_no_cache $do_not_cache;
fastcgi_cache_bypass $do_not_cache;
fastcgi_cache_key $scheme://$host$request_uri;
fastcgi_cache fczone;
fastcgi_pass backend;
}
location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /var/www/letsencrypt; }
location = /.well-known/acme-challenge/ { return 404; }
}
location ~ \.php$ {
set $do_not_cache 0;
if ($request_method != "GET") {
set $do_not_cache 1;
}
if ($http_cookie ~ ^.*(comment_author_|wordpress_logged_in|wp-postpass_).*$) {
set $do_not_cache 1;
}
if ($http_x_wap_profile ~ ^[a-z0-9\"]+) {
set $do_not_cache 1;
}
if ($http_profile ~ ^[a-z0-9\"]+) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^.*(2.0\ MMP|240x320|400X240|AvantGo|BlackBerry|Blazer|Cellphone|Danger|DoCoMo|Elaine/3.0|EudoraWeb|Googlebot-Mobile|hiptop|IEMobile|KYOCERA/WX310K|LG/U990|MIDP-2.|MMEF20|MOT-V|NetFront|Newt|Nintendo\ Wii|Nitro|Nokia|Opera\ Mini|Palm|PlayStation\ Portable|portalmmm|Proxinet|ProxiNet|SHARP-TQ-GX10|SHG-i900|Small|SonyEricsson|Symbian\ OS|SymbianOS|TS21i-10|UP.Browser|UP.Link|webOS|Windows\ CE|WinWAP|YahooSeeker/M1A1-R2D2|iPhone|iPod|Android|BlackBerry9530|LG-TU915\ Obigo|LGE\ VX|webOS|Nokia5800).*) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^(w3c\ |w3c-|acs-|alav|alca|amoi|audi|avan|benq|bird|blac|blaz|brew|cell|cldc|cmd-|dang|doco|eric|hipt|htc_|inno|ipaq|ipod|jigs|kddi|keji|leno|lg-c|lg-d|lg-g|lge-|lg/u|maui|maxo|midp|mits|mmef|mobi|mot-|moto|mwbp|nec-|newt|noki|palm|pana|pant|phil|play|port|prox|qwap|sage|sams|sany|sch-|sec-|send|seri|sgh-|shar|sie-|siem|smal|smar|sony|sph-|symb|t-mo|teli|tim-|tosh|tsm-|upg1|upsi|vk-v|voda|wap-|wapa|wapi|wapp|wapr|webc|winw|winw|xda\ |xda-).*) {
set $do_not_cache 1;
}
if ($http_user_agent ~ ^(DoCoMo/|J-PHONE/|J-EMULATOR/|Vodafone/|MOT(EMULATOR)?-|SoftBank/|[VS]emulator/|KDDI-|UP\.Browser/|emobile/|Huawei/|IAC/|Nokia|mixi-mobile-converter/)) {
set $do_not_cache 1;
}
if ($http_user_agent ~ (DDIPOCKET\;|WILLCOM\;|Opera\ Mini|Opera\ Mobi|PalmOS|Windows\ CE\;|PDA\;\ SL-|PlayStation\ Portable\;|SONY/COM|Nitro|Nintendo)) {
set $do_not_cache 1;
}
fastcgi_no_cache $do_not_cache;
fastcgi_cache_bypass $do_not_cache;
fastcgi_cache_key $scheme://$host$request_uri;
fastcgi_cache fczone;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_read_timeout 300;
include fastcgi_params;
}
PHPインストール
# dnf install -y wget php php-mysqli php-fpm php-json php-devel php-gd
# php -v
PHP 8.2.7 (cli) (built: Jun 6 2023 21:28:56) (NTS gcc x86_64)
Copyright (c) The PHP Group
Zend Engine v4.2.7, Copyright (c) Zend Technologies
with Zend OPcache v8.2.7, Copyright (c), by Zend Technologies
PHPもタイムゾーンを変更する必要があります。
あとはアップロードのファイルサイズの上限は最初にやっておいたほうがよさそうです。
date.timezone = "Asia/Tokyo"
memory_limit = 128M
upload_max_filesize = 32M
php-fpm側も設定しておきましょう。php-fpmの設定ファイルの実行ユーザーがapacheになっているので、nginxに変えます。
user = nginx
group = nginx
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
サービス起動
#systemctl start php-fpm
#systemctl start nginx
Let’s Encryptインストール
SSL証明書発行のため、あらかじめドメインレジストリサービスやRoute53などでルーティングの設定を行っておきましょう。
# dnf install -y python3 augeas-libs pip
# python3 -m venv /opt/certbot/
# /opt/certbot/bin/pip install --upgrade pip
# /opt/certbot/bin/pip install certbot
# ln -s /opt/certbot/bin/certbot /usr/bin/certbot
SSL証明書を発行します。
# systemctl stop nginx
# certbot certonly
Successfully received certificate.
SSL証明書は発行されましたが怒られました。
nginx: [emerg] BIO_new_file("/etc/nginx/dhparam.pem") failed (SSL: error:80000002:system library::No such file or directory:calling fopen(/etc/nginx/dhparam.p>
Nginxにdhparamのパラメータを入れておいたのですが、これがないことが原因だったようです。
NginxがSSL接続を設定するためのDiffie-Hellman(DH)パラメータファイル(dhparam.pem)を見つけられなかったみたいです。これは、SSL/TLS接続におけるPerfect Forward Secrecy(PFS)を有効にするために使用されるもので、存在しない場合には上記のエラーが出ます。
下記のコマンドで生成してください。
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
example.comにアクセスが可能になります。
さいごに
この環境ではWordPressを使用していますが、パフォーマンスが大きく改善されました。AWS(Amazon Linux 2023)+Nginx+php8で環境構築をご検討の方はぜひご参考にしてみてください。