EC2
sudo su -l
passwd ec2-user
timedatectl set-timezone Asia/Tokyo
cp -rp /etc/sysconfig/clock /etc/sysconfig/clock.org
/etc/sysconfig/clock
-ZONE="UTC"
-UTC=true
+ZONE="Asia/Tokyo"
+UTC=false
/etc/sysconfig/i18n
-LANG=en_US.UTF-8
+LANG=ja_JP.UTF-8
dnf update
#cron
dnf install -y cronie
#rsyslog
dnf install -y rsyslog
#nginx
dnf install -y nginx
nginx -v
#nginx version: nginx/1.28.0
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.org
#php8.4
# dnf list --available php8.4*
dnf install -y php8.4 php8.4-fpm php8.4-bcmath php8.4-common php8.4-cli php8.4-pdo php8.4-mysqlnd php8.4-gd php8.4-mbstring php8.4-opcache php8.4-devel php8.4-xml php8.4-intl php8.4-zip
php -v
#PHP 8.4.13 (cli)
systemctl start php-fpm
systemctl enable php-fpm.service
#imagick
dnf install -y ImageMagick-devel php-pear
pecl install imagick
PHP
/etc/php.ini
date.timezone = "Asia/Tokyo"
memory_limit = 256M
expose_php = Off
post_max_size = 8M
upload_max_filesize = 4M
#memory_limit > post_max_size > upload_max_filesize
#3 days
session.gc_maxlifetime = 259200
#7 days
#session.gc_maxlifetime = 604800
#session.name = PHPSESSID
#session.cookie_lifetime = 0
[mbstring]
mbstring.language = Japanese
[imagick]
extension=imagick.so
/etc/php-fpm.d/www.conf
-user = apache
+user = nginx
-group = apache
+group = nginx
phpMyAdmin
cd /var/www/
wget https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.tar.gz
tar zxvf phpMyAdmin-5.2.1-all-languages.tar.gz
rm phpMyAdmin-5.2.1-all-languages.tar.gz
mv phpMyAdmin-5.2.1-all-languages phpmyadmin
cd /var/www/phpmyadmin/
cp config.sample.inc.php config.inc.php
/var/www/phpmyadmin/config.inc.php
/* Authentication type */
$cfg['Servers'][$i]['auth_type'] = 'http';//BASIC認証
/* Server parameters */
$cfg['Servers'][$i]['host'] = 'localhost';
Nginx
適宜
/etc/nginx/nginx.conf
events {
worker_connections 1024;
}
http {
index index.php;
charset UTF-8;
server_tokens off;
#FastCGI CACHE
fastcgi_cache_path /var/cache/nginx levels=1:2 keys_zone=FCKZ:32m inactive=1d max_size=128m;
fastcgi_cache_use_stale error timeout invalid_header http_500;
server {
listen 80;
listen [::]:80;
server_name example.com;
root /usr/share/nginx/html;
#root /var/www/html;
client_max_body_size 4m;
#include /etc/nginx/default.d/*.conf;
#FastCGI CACHE
set $do_not_cache 0;
if ($request_method !~ ^(GET)$) {
set $do_not_cache 1;
}
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $do_not_cache 1;
}
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $do_not_cache 1;
}
fastcgi_cache_key "$scheme://$host$request_uri";
# ドットファイルはすべて拒否
# Let's Encrypt の証明書更新で使う /.well-known/ は除外
location ~ /\.(?!well-known) {
deny all;
}
location = /xmlrpc.php {
deny all;
return 403;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php{
try_files $uri =404;
fastcgi_pass php-fpm;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
include fastcgi_params;
fastcgi_cache_bypass $do_not_cache;
fastcgi_no_cache $do_not_cache;
fastcgi_cache FCKZ;
fastcgi_cache_valid 200 5m;
fastcgi_cache_valid any 10m;
fastcgi_pass_header X-Accel-Expires;
fastcgi_ignore_headers Cache-Control Expires;
add_header x-cache $upstream_cache_status;
}
location ~* ^.+.(jpe?g|gif|png|css|js|flv|swf|ico|xml|txt|eot|svg|ttf|woff|woff2){
access_log off;
log_not_found off;
expires 30d;
}
location ~ /(\.ht|\.user.ini|\.git|\.hg|\.bzr|\.svn) {
deny all;
}
}
# 443は後述のLet's Encryptがやってくれるんで追記するやつがあれば
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name _;
location ^~ /phpmyadmin {
#allow 0.0.0.0;#IP制限
deny all;
alias /var/www/phpmyadmin;
index index.php;
location ~ \.php {
fastcgi_pass php-fpm;
fastcgi_index index.php;
fastcgi_split_path_info ^/phpmyadmin(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME /var/www/phpmyadmin$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}
}
}
}
systemctl start nginx
systemctl enable nginx.service
再起動設定
/lib/systemd/system/nginx.service
[Service]
+Restart=always
+RestartSec=5s
systemctl daemon-reload
systemctl restart nginx
systemctl show nginx | grep Restart
Git
dnf install -y git
#GitHub
cd /var/www/
git clone https://github.com/[path_to_git].git html
chown -R nginx:nginx /var/lib/php/session
chown -R nginx:nginx /var/www/html
確認
/usr/share/nginx/html/phpinfo.php
<?php
phpinfo();
Let's Encrypt
dnf install -y certbot
dnf install -y python3-certbot-nginx
certbot --version
certbot --nginx --agree-tos --register-unsafely-without-email
crontab
# At 03:00, 15:00
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 3,15 * * * certbot renew --deploy-hook "systemctl reload nginx" >> /var/log/certbot-renew.log 2>&1
sudo tee /etc/logrotate.d/certbot-renew > /dev/null <<'EOF'
# certbot 自動更新(crontab)の実行ログのローテーション
/var/log/certbot-renew.log {
weekly
rotate 12
missingok
notifempty
compress
delaycompress
create 0640 root root
}
EOF
sudo logrotate -d /etc/logrotate.d/certbot-renew
Hostname
hostnamectl set-hostname [example]
MariaDB
dnf install -y mariadb114-server mariadb114
/etc/my.cnf.d/mariadb-server.cnf
[mysqld]
+character-set-server = utf8mb4
#インスタンスのメモリに合わせる
+innodb_buffer_pool_size=256M
+max_connections=50
+performance_schema=OFF
/etc/my.cnf.d/client.cnf
[client]
+default-character-set = utf8mb4
systemctl start mariadb
systemctl enable mariadb.service
mariadb --version
DBとユーザーを作成
DB_NAME="dbname"
DB_USER="username"
DB_PASS=$(openssl rand -base64 32 | tr -d '/+=' | cut -c1-24)
mariadb -u root <<EOF
CREATE DATABASE \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SHOW GRANTS FOR '${DB_USER}'@'localhost';
EOF
echo "ユーザー: ${DB_USER}"
echo "パスワード: ${DB_PASS}"
#表示されたパスワードを保管
mariadb -u username -p dbname
#ログインできたらパスワードの変数を削除
unset DB_PASS
落ちても自動で再起動させる
mkdir -p /etc/systemd/system/mariadb.service.d
cat > /etc/systemd/system/mariadb.service.d/override.conf <<'EOF'
[Service]
Restart=on-failure
RestartSec=5s
EOF
systemctl daemon-reload
systemctl show mariadb -p Restart -p RestartUSec
systemctl restart mariadb
systemctl status mariadb
WordPress
wget https://ja.wordpress.org/latest-ja.tar.gz
# zsh
# curl https://ja.wordpress.org/latest-ja.tar.gz -O
tar zxvf latest-ja.tar.gz
rm latest-ja.tar.gz
cp -rpf wordpress/* ./
rm -rf wordpress
cp wp-config-sample.php wp-config.php
wp-config.php
$env = match($_SERVER['HTTP_HOST']) {
'production.com' => 'production',
'staging.com' => 'staging',
default => 'local',
};
$db = match ($env) {
'production' => [
'name' => 'dbname',
'user' => 'dbuser',
'pass' => 'dbpass',
'host' => 'localhost',
],
'staging' => [
'name' => 'dbname',
'user' => 'dbuser',
'pass' => 'dbpass',
'host' => 'localhost',
],
'local' => [
'name' => 'dbname',
'user' => 'dbuser',
'pass' => 'dbpass',
'host' => 'localhost',
],
};
switch ($env) {
case 'production':
define('WP_DEBUG', false);
define('FORCE_SSL_ADMIN', true);
if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === "https" ) {
$_SERVER['HTTPS'] = 'on';
}
break;
case 'staging':
define('WP_DEBUG', false);
define('FORCE_SSL_ADMIN', true);
if ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === "https" ) {
$_SERVER['HTTPS'] = 'on';
}
break;
default:
define('WP_DEBUG', true);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', true);
define('WP_DISABLE_FATAL_ERROR_HANDLER', true);
break;
}
define('WP_ENVIRONMENT_TYPE', $env);
function is_production() {
return ( wp_get_environment_type() === 'production' );
}
function is_staging() {
return ( wp_get_environment_type() === 'staging' );
}
function is_local() {
return ( wp_get_environment_type() === 'local' );
}
define('DB_NAME', $db['name']);
define('DB_USER', $db['user']);
define('DB_PASSWORD', $db['pass']);
define('DB_HOST', $db['host']);
define('DB_CHARSET', 'utf8mb4');
define('DB_COLLATE', '');
functions.php
// XML-RPCの全メソッドを無効化(xmlrpc_enabledより確実)
add_filter('xmlrpc_methods', function () {
return [];
});
// ヘッダーからpingback情報を除去
remove_action('wp_head', 'rsd_link');
add_filter('wp_headers', function ($headers) {
unset($headers['X-Pingback']);
return $headers;
});
/**
* REST APIを管理画面ログイン済みユーザーのみに制限する
*/
add_filter('rest_authentication_errors', function ($result) {
if ( ! empty($result) ) {
return $result;
}
if ( ! is_user_logged_in() ) {
return new WP_Error(
'rest_not_logged_in',
'REST APIへのアクセスには管理画面へのログインが必要です。',
['status' => 401]
);
}
return $result;
});
BASIC認証
dnf install -y httpd-tools
BA_USER="admin"
BA_PASS=$(openssl rand -base64 32 | tr -d '/+=' | cut -c1-16)
htpasswd -bcB /etc/nginx/.htpasswd "${BA_USER}" "${BA_PASS}"
chown root:nginx /etc/nginx/.htpasswd
chmod 640 /etc/nginx/.htpasswd
echo "ユーザー: ${BA_USER}"
echo "パスワード: ${BA_PASS}"
unset BA_PASS
#サイト全体にかける場合
server {
...
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
...
}
#特定のパスだけにかける場合
location /admin/ {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
}
#Let's Encrypt
location = /.well-known/acme-challenge/ {
auth_basic off;
}
nginx -t
systemctl reload nginx