AWS Lightsail で運用してた個人用ブログの終活作業履歴③

[AWS Lightsail で運用してた個人用ブログの終活作業履歴②](https://qiita.com/imo_tikuwa/items/47542e688eb52eb33ebe) の続きです

これまで実施したのは以下の6手順です

```
1. 切替先となる Route 53 のホストゾーン作成
2. 既存の DNS レコード設定情報を参考に Route 53 のレコード設定
3. ネームサーバーを お名前.com → Route 53 に切り替え
4. ACM 証明書を発行
5. 既存のサーバーレスアプリケーションに設定中のACM証明書の切替
6. 不要となった方のACM証明書を削除
```

今回は続きとして以下を実施します

```
7. Lightsail内で稼働中のWordPressサイト、その他をバックアップ
8. WordPressサイトについてローカルでの動作環境を構築
9. Lightsailインスタンスを削除
10. Route 53 レコード設定から Lightsail インスタンスのIPv6に向けた設定を削除
```

## 7. Lightsail内で稼働中のWordPressサイト、その他をバックアップ

:::note warn
長年運用してきたこともありインスタンス内には Docker が入ってたり、nvm 経由での Node.js、rbenv 経由での Ruby インストールなどが行われてました...
また OS は Amazon Linux 2 でした...:sob:
:::

後で必要になるかは不明ですがインスタンス内の情報について控える作業を実施します。
情報の取得には主に以下のようなコマンドを実行しました（一部のコマンドは取得した内容まで記載するととても長くなるので記事内ではコマンドのみの紹介とします）

`# ~~~` は `root`、`$ ~~~` は `ec2-user` ユーザーで実行したものになります

---

```bash:OS・セキュリティ情報
# cat /etc/os-release
NAME="Amazon Linux"
VERSION="2"
ID="amzn"
ID_LIKE="centos rhel fedora"
VERSION_ID="2"
PRETTY_NAME="Amazon Linux 2"
ANSI_COLOR="0;33"
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
HOME_URL="https://amazonlinux.com/"

# hostnamectl

# cat /etc/hosts

# cat /etc/group

# getenforce
Disabled

# iptables -L
```

---

```bash:起動中のサービス情報
# systemctl list-units --type=service --state=running
UNIT                       LOAD   ACTIVE SUB     DESCRIPTION
acpid.service              loaded active running ACPI Event Daemon
amazon-ssm-agent.service   loaded active running amazon-ssm-agent
atd.service                loaded active running Job spooling tools
auditd.service             loaded active running Security Auditing Service
chronyd.service            loaded active running NTP client/server
containerd.service         loaded active running containerd container runtime
crond.service              loaded active running Command Scheduler
dbus.service               loaded active running D-Bus System Message Bus
docker.service             loaded active running Docker Application Container Engine
getty@tty1.service         loaded active running Getty on tty1
gssproxy.service           loaded active running GSSAPI Proxy Daemon
irqbalance.service         loaded active running irqbalance daemon
libstoragemgmt.service     loaded active running libstoragemgmt plug-in server daemon
lvm2-lvmetad.service       loaded active running LVM2 metadata daemon
mysqld.service             loaded active running MySQL Server
network.service            loaded active running LSB: Bring up/down networking
nginx.service              loaded active running The NGINX HTTP and reverse proxy server
php-fpm.service            loaded active running The PHP FastCGI Process Manager
rngd.service               loaded active running Hardware RNG Entropy Gatherer Daemon
rpcbind.service            loaded active running RPC bind service
rsyslog.service            loaded active running System Logging Service
serial-getty@ttyS0.service loaded active running Serial Getty on ttyS0
snapd.service              loaded active running Snap Daemon
sshd.service               loaded active running OpenSSH server daemon
systemd-journald.service   loaded active running Journal Service
systemd-logind.service     loaded active running Login Service
systemd-udevd.service      loaded active running udev Kernel Device Manager

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

27 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
```

---

```bash:バージョン情報
# httpd -v
Server version: Apache/2.4.61 ()
Server built:   Jul 16 2024 16:34:56

# nginx -v
nginx version: nginx/1.21.3

# php -v
PHP 8.0.30 (cli) (built: Aug 24 2023 20:32:30) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
    with Zend OPcache v8.0.30, Copyright (c), by Zend Technologies

# composer --version

# mysql --version
mysql  Ver 8.0.31 for Linux on x86_64 (MySQL Community Server - GPL)

# openssl version

# ruby -v

# docker version

# snap version

# node -v

# npm -v

# certbot --version

# ffmpeg -version
```

- php,mysql は古いものを使用し続けてしまっていたみたいです...
- httpd は過去に使用してたもので現在は停止中
- snap は certbot をインストールするのに使用してました
- Node.js と ffmpeg は何のためにインストールしたのかわかりませんでした...

---

```bash:cron 設定情報
# crontab -l

$ crontab -l
no crontab for ec2-user
```

- `root` と `ec2-user` のそれぞれで設定内容を確認

---

```bash:httpd（Apache）詳細情報
# apachectl -M
```

- ロード済みのモジュールを一覧表示しています

---

```bash:nginx 詳細情報
# nginx -V
```

- configure のオプションだとか、ビルドに使用した OpenSSL のバージョンとかを含めて確認しています

---

```bash:php 詳細情報
# php -m

# cat /etc/php.ini

# diff /etc/php.ini /etc/php.ini.org
```

- ロード済みのモジュールを一覧表示しています
- `/etc/php.ini` についてオリジナルがバックアップとして控えてあったので差異を確認してます

---

```bash:composer 詳細情報
# which composer
/bin/composer
```

---

```bash:mysql 詳細情報
# ls -al /etc/my.cnf.d/
total 12
drwxr-xr-x  2 root root    6 Sep 14  2022 .
drwxr-xr-x 94 root root 8192 Mar 30 22:37 ..

# cat /etc/my.cnf

# diff /etc/my.cnf /etc/my.cnf.org

# mysql -u root -p
mysql> show databases;
mysql> select Host, User, plugin, authentication_string from mysql.user;
```

- mysql の設定ファイルについて `/etc/my.cnf.d` 以下には存在しないことを確認
- `/etc/my.cnf` についてオリジナルがバックアップとして控えてあったので差異を確認してます
- MySQL サーバーに接続し、データベースの一覧とユーザーの一覧を確認しています

---

```bash:ruby 詳細情報
# which ruby
/usr/local/rbenv/shims/ruby

# rbenv versions
* 2.6.0 (set by /usr/local/rbenv/version)

# gem list
```

- Ruby (Sinatra) を使った単ページのアプリを作ったときの名残

---

```bash:docker 詳細情報
# docker ps -a

# docker images

# docker network ls
```

---

```bash:node.js 詳細情報
# which node
/root/.nvm/versions/node/v10.16.0/bin/node

# nvm ls

# nvm current
v10.16.0

# npm list -g --depth=0
```

- めっちゃ古い Node.js が入ってた:innocent:
- 何の用途でインストールしたものだったか思い出せず...:sob:

---

```bash:パッケージ詳細情報
# yum list installed

# snap list
```

各種情報の取得はここまで

---

ここからは ↑ の作業で得た情報を参考に WordPress サイトのコンテンツ、データダンプ、その他の情報など必要なバックアップを実施していきます

```bash:データベースバックアップ
# mkdir -p /home/ec2-user/databases
# mysqldump -u root -p hoge | gzip > /home/ec2-user/databases/hoge.dump.gz
# mysqldump -u root -p startssl_wordpress | gzip > /home/ec2-user/databases/startssl_wordpress.dump.gz
# mysqldump -u root -p wordpress | gzip > /home/ec2-user/databases/wordpress.dump.gz
# mysqldump -u root -p fuga | gzip > /home/ec2-user/databases/fuga.dump.gz
```

- `ec2-user` のホームディレクトリ以下に databases というディレクトリを作成してその中にデータベース別でデータダンプを取得しました
- WordPress サイトが2つ存在することにはこのタイミングで気づきました:flushed:

---

```bash:WordPress サイトのコンテンツバックアップ
# mkdir -p /home/ec2-user/sites
# cd /var/www
# tar zcvf /home/ec2-user/sites/hoge.tar.gz hoge/
# tar zcvf /home/ec2-user/sites/wp.tar.gz wp/
```

- `ec2-user` のホームディレクトリ以下に sites というディレクトリを作成して、WordPressサイトや静的ページに関するコンテンツについてtarアーカイブを作成しました
- `/var/www/wp` ディレクトリ内で2つの独立したWordPressブログを1ドメイン配下に配置するような構成をとってました
  - バックアップ自体を分ける必要は無いと思ったのでまとめて取得しています

```bash:WordPress ブログが2つ存在した件
# ll /var/www/wp/
total 24
-rw-r--r-- 1 nginx nginx   59 Oct 24  2021 ads.txt
-rw-r--r-- 1 nginx nginx   59 Sep  7  2024 app-ads.txt
-rw-r--r-- 1 nginx nginx 1150 Oct 24  2021 favicon.ico
-rw-r--r-- 1 nginx nginx  426 Oct 24  2021 index.php ⇐ '/ssl-2016' 以外へのリクエストを 'webmemo' 内の WordPress に送るためのインデックス
drwxr-xr-x 5 nginx nginx 4096 Apr 21 23:56 ssl-2016 ⇐ '/ssl-2016' で動かしてる WordPress
drwxr-xr-x 5 nginx nginx 4096 Apr 21 11:05 webmemo ⇐ '/' で動かしてる WordPress
```

---

```bash:設定ファイルバックアップ
# mkdir -p /home/ec2-user/etc
# cd /
# tar zcvf /home/ec2-user/etc/etc.tar.gz etc/
```

- `/etc` 以下は全部を1つのアーカイブとして作成（30数MBくらい）
- nginx、php、mysql などの重要な設定ファイルは別途ファイル別でもバックアップしています

---

取得したバックアップは SFTP でローカルにダウンロードしました

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/c42e9721-2f95-4fff-bf65-006b3cc05fb5.png)

- SSH クライアントソフトは [RLogin](https://kmiya-culti.github.io/RLogin/) が便利

## 8. WordPressサイトについてローカルでの動作環境を構築

Lightsailインスタンスのクローズ前に取得したバックアップを元にローカルで閲覧可能な環境を構築します。
環境の構築には Docker を使用します。

- php と nginx はコンテナを分けて作成（FastCGI 経由で PHP を動かす nginx → php-fpm の構成）
- mysql サーバーについて作成したいデータベースが2つ存在するため環境変数（`MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD`）での作成は行わず
  - 代わりに `/docker-entrypoint-initdb.d` のフック内での SQL ファイルを使用して DB 作成＆ユーザー作成を実施しました
- なお、[WordPress 公式の Docker イメージ](https://hub.docker.com/_/wordpress)の存在は把握していますが利用したことがなく、スムーズに使いこなせる気もしなかったので今回は使用しませんでした
- SSL 対応はせずに `http://localhost` でアクセス可能な形を目指します

---

以下作成したDocker環境情報（長いのでファイル別に折りたたんでいます）

<details>
<summary>compose.yml</summary>

```yaml
services:
  php:
    build:
      context: ./
      dockerfile: ./.docker/php/Dockerfile
    volumes:
      - ./html:/var/www/wp:cached
    depends_on:
      - mysql

  nginx:
    build:
      context: ./
      dockerfile: ./.docker/nginx/Dockerfile
    ports:
      - "80:80"
    volumes:
      - ./html:/var/www/wp:cached
    depends_on:
      - php

  mysql:
    build:
      context: ./
      dockerfile: ./.docker/mysql/Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
    volumes:
      - db_data:/var/lib/mysql
      - ./.docker/mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d:ro
    # SQLクライアントソフト用
    ports:
      - "3306:3306"

volumes:
  db_data:
```

- ホスト側の `./html` ディレクトリをコンテナ内の `/var/www/wp` にマウントします
- nginx⇒phpのfcgi経由のリクエスト処理が正しく動作されるようnginxとphpのコンテナ内のマウント先（ドキュメントルート）は揃える必要がありました

</details>

<details>
<summary>.docker/php/Dockerfile</summary>

```Dockerfile:
# 古いので警告出てる。ローカルなのでOKってことにする
FROM php:8.0.30-fpm

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    curl \
    unzip \
    libfreetype6-dev \
    libjpeg62-turbo-dev \
    libpng-dev \
    libonig-dev \
    libzip-dev \
    mariadb-client && \
    docker-php-ext-configure gd --with-freetype --with-jpeg && \
    docker-php-ext-install -j"$(nproc)" \
        gd \
        mbstring \
        mysqli \
        zip && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# wp-cliのインストール
RUN curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar && \
    chmod +x wp-cli.phar && \
    mv wp-cli.phar /usr/local/bin/wp

# UID=1000, GID=1000のユーザーとグループを作成
RUN groupadd -g 1000 wpgroup && \
    useradd -u 1000 -g wpgroup -m wpuser
USER wpuser

WORKDIR /var/www/wp

CMD ["php-fpm"]
```

- php コンテナ用の Dockerfile です
- WSL2 配下に構築してるのでコンテナの実行ユーザーをホスト側（UID=1000/GID=1000）に揃えています
- 後の手順として wp-cli を使用したデータベース書き換えを行うので [wp-cli](https://wp-cli.org/ja/) のインストールも行っています

</details>

<details>
<summary>.docker/nginx/Dockerfile</summary>

```Dockerfile
FROM nginx:1.27

# nginx ユーザーの UID/GID 書き換え
RUN groupmod -g 1000 nginx && \
    usermod -u 1000 nginx

# キャッシュフォルダ、ログフォルダの所有者を変更
RUN chown -R nginx:nginx /var/cache/nginx/ /var/run/ /var/log/nginx/

# 設定ファイルをコピー
COPY .docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY .docker/nginx/conf.d/blog.imo-tikuwa.com.conf /etc/nginx/conf.d/blog.imo-tikuwa.com.conf
# 以下2ファイルは blog.imo-tikuwa.com.conf の中からインクルードするので自動読み込みされないこのパスでOK
COPY .docker/nginx/wp/restrictions.conf /etc/nginx/wp/restrictions.conf
COPY .docker/nginx/wp/wordpress.conf /etc/nginx/wp/wordpress.conf

# デフォルトのWelcomeページを表示しようとする設定ファイルを削除
RUN rm -f /etc/nginx/conf.d/default.conf

USER nginx

WORKDIR /var/www/wp
```

- nginx コンテナはデフォルトだと root ユーザーで実行しつつ、nginx のプロセスは nginx ユーザーで実行されるような設定になってますが、この辺今回は php コンテナと同様に UID/GID 共に1000に揃える修正をしてみました

</details>

<details>
<summary>.docker/nginx/nginx.conf</summary>

```nginx
# user  nginx;
worker_processes  auto;

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


events {
    worker_connections  1024;
}


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"';

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

    sendfile        on;
    # tcp_nopush     on;

    keepalive_timeout  65;

    # gzip  on;

    # webp setting.
    map $http_accept $webp_suffix {
        default "";
        "~*webp" ".webp";
    }

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

- nginx の Dockerfile の中で `/etc/nginx/nginx.conf` にコピーしてる設定ファイルです
- 元々コンテナ内で稼働していた設定ファイルをベースとしつつ一部書き換えてます
- user ディレクティブは root ユーザーのときのみ指定する必要がある設定みたいで今回のように別のユーザーで実行する状態においてはワーニングが出るためコメントアウトしました
- 本番環境で webp に関する設定を行っていたのでその辺を追記しています
</details>

<details>
<summary>.docker/nginx/blog.imo-tikuwa.com.conf</summary>

```nginx
server {
    listen 80;
    server_name localhost;
    root /var/www/wp;
    index index.php;

    client_max_body_size 20M;

    gzip on;
    gzip_types text/css application/javascript application/json application/font-woff application/font-tff image/gif image/png image/jpeg application/octet-stream;

    rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml$ "/index.php?xml_sitemap=params=$2" last;
    rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.xml\.gz$ "/index.php?xml_sitemap=params=$2;zip=true" last;
    rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html$ "/index.php?xml_sitemap=params=$2;html=true" last;
    rewrite ^/sitemap(-+([a-zA-Z0-9_-]+))?\.html.gz$ "/index.php?xml_sitemap=params=$2;html=true;zip=true" last;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # 子サイトの設定 ここから
    if (!-e $request_filename) {
        rewrite ^/ssl-2016(.+)$ /ssl-2016/index.php?q=$1 last;
        break;
    }

    location ~^/ssl-2016/(.+\.php)$ {
        alias /var/www/wp/ssl-2016/$1;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    # http://wpdocs.osdn.jp/Nginx
    include /etc/nginx/wp/restrictions.conf;
    include /etc/nginx/wp/wordpress.conf;
}
```

- nginx の Dockerfile の中で `/etc/nginx/conf.d` ディレクトリ以下にコピーしてる設定ファイルです
- 元々本番環境で稼働してた頃の内容をベースとしつつ一部書き換えています（`http → https の301リダイレクト`、`IPv6 の listen`、`server_name`、`fastcgi_pass` 等）
- 設定の末尾でインクルードしている2ファイル（restrictions.conf と wordpress.conf）はコメントにあるサイトの情報を参考に作成したファイルです
  - WordPress は元々 LAMP を対象としたブログCMS（のはず）。それと nginx で動かす際に推奨される設定って感じだったと記憶しています
  - こちら今調べたら無くなってました...:sob:
  - 現在は [こちらのページ](https://ja.wordpress.org/support/article/nginx/) を参考にするとよさそう？

</details>

<details>
<summary>.docker/nginx/wp/restrictions.conf</summary>

```nginx
# 一般的な制限設定のファイル。
# どの server {} ブロックからもインクルードできるよう設計されています。
location = /favicon.ico {
        log_not_found off;
        access_log off;
}

location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
}

# .htaccess, .htpasswd, .DS_Store (Mac)といった隠しファイルへのアクセスを拒否します。
location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
}
```

- nginx の Dockerfile の中で `/etc/nginx/wp/restrictions.conf` にコピーしてる設定ファイルです
- コンテナ内にコピーした `/etc/nginx/conf.d/blog.imo-tikuwa.com.conf` からインクルードすることで反映してます

</details>

<details>
<summary>.docker/nginx/wp/wordpress.conf</summary>

```nginx
# webp setting.
location ~* ^.+\.(png|jpe?g)$ {
    add_header Vary Accept;
    try_files $uri$webp_suffix $uri =404;
}

rewrite /wp-admin$ $scheme://$host$uri/ permanent;

location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 7d;
        add_header Cache-Control "public, no-transform";
        log_not_found off;
}

location ~ \.php$ {
        try_files $uri =404;

        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass php:9000;
}
```

- nginx の Dockerfile の中で `/etc/nginx/wp/wordpress.conf` にコピーしてる設定ファイルです
- コンテナ内にコピーした `/etc/nginx/conf.d/blog.imo-tikuwa.com.conf` からインクルードすることで反映してます

</details>

<details>
<summary>.docker/mysql/Dockerfile</summary>

```Dockerfile
FROM mysql:8.0

CMD ["mysqld"]
```

</details>

<details>
<summary>.docker/mysql/docker-entrypoint-initdb.d/01_wordpress.sql</summary>

```sql
CREATE DATABASE IF NOT EXISTS wordpress CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci;

CREATE USER IF NOT EXISTS 'wp_user1'@'%' IDENTIFIED BY '**********';

GRANT ALL PRIVILEGES ON wordpress.* TO 'wp_user1'@'%';

FLUSH PRIVILEGES;
```

- mysql コンテナ内の `/docker-entrypoint-initdb.d` ディレクトリにマウントされるSQLファイルです
- wordpress データベースの作成とユーザーを作成しています
- `※ユーザー名とパスワードは記事用に書き換えています`

</details>

<details>
<summary>.docker/mysql/docker-entrypoint-initdb.d/02_startssl_wordpress.sql</summary>

```sql
CREATE DATABASE IF NOT EXISTS startssl_wordpress CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci;

CREATE USER IF NOT EXISTS 'wp_user2'@'%' IDENTIFIED BY '**********';

GRANT ALL PRIVILEGES ON startssl_wordpress.* TO 'wp_user2'@'%';

FLUSH PRIVILEGES;
```

- mysql コンテナ内の `/docker-entrypoint-initdb.d` ディレクトリにマウントされるSQLファイルです
- startssl_wordpress データベースの作成とユーザーを作成しています
- `※ユーザー名とパスワードは記事用に書き換えています`

</details>


---

Lightsail から取得したバックアップは以下のような感じで配置

- `.source/sites/wp.tar.gz`
  - WordPressサイト2つを固めたアーカイブ
- `.source/databases/wordpress.dump.gz`
  - `https://blog.imo-tikuwa.com` サイトのWordPressデータベースダンプ
- `.source/databases/startssl_wordpress.dump.gz`
  - `https://blog.imo-tikuwa.com/ssl-2016` サイトのWordPressデータベースダンプ

---

```bash:.gitignore
.source
html
```

- .gitignore を作成
- その後 `git init` & `git add .` で docker compose の構成をステージ
- `ローカルの .source ディレクトリ内に控えてるバックアップはGit管理しないので消さないよう注意`

---

WordPressのサイトコンテンツをまとめたアーカイブを空の html ディレクトリに展開

```bash
$ mkdir -p html
$ tar --strip-components=1 -xvzf .source/sites/wp.tar.gz -C html/
```

VSCode のエクスプローラーで見ると以下のような感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/3e7d4e5f-ec2d-4f0b-92f4-2c77bd2393e1.png)

---

展開した WordPressの2サイトについてそれぞれ `wp-config.php` 内の設定を置換

```bash
$ sed -i "s/define('DB_HOST', 'localhost');/define('DB_HOST', 'mysql');/" ./html/webmemo/wp-config.php
$ sed -i "s/define('DB_HOST', 'localhost');/define('DB_HOST', 'mysql');/" ./html/ssl-2016/wp-config.php
```

- MySQL サーバーは mysql という名称の Docker コンテナで動かすので `localhost → mysql` の置換が必要

---

Docker コンテナ環境起動

```bash
$ docker compose up -d --build
```

---

2つの空のデータベースに対してバックアップを元にしたリストアを実施

```bash
$ gzip -cd .source/databases/wordpress.dump.gz | docker compose exec -T mysql mysql -u root -prootpassword wordpress
$ gzip -cd .source/databases/startssl_wordpress.dump.gz | docker compose exec -T mysql mysql -u root -prootpassword startssl_wordpress
```

- compose.yml に記載した root ユーザーのパスワードを使用してリストアしました

---

データベース内のサイトURL、ホームURLについて wp-cli で書き換えを実施

```bash
$ docker compose exec php wp --path=./webmemo option update siteurl 'http://localhost/webmemo'
$ docker compose exec php wp --path=./webmemo option update home 'http://localhost'

$ docker compose exec php wp --path=./ssl-2016 option update siteurl 'http://localhost/ssl-2016'
$ docker compose exec php wp --path=./ssl-2016 option update home 'http://localhost/ssl-2016'
```

- php コンテナ内の WORKDIR は `var/www/wp` なのでそこからの相対なパスを指定します

---

↑ のサイトURL、ホームURLの書き換えだけだと画像をラップするようなアンカータグのリンクが本番を向いてしまっていました。。:sob:
追加で [search-replace](https://developer.wordpress.org/cli/commands/search-replace/) コマンドを使用して一括で書き換えを実施

```bash
$ docker compose exec php wp --path=./webmemo search-replace 'https://blog.imo-tikuwa.com/' 'http://localhost/' --skip-columns=guid
$ docker compose exec php wp --path=./ssl-2016 search-replace 'https://blog.imo-tikuwa.com/ssl-2016' 'http://localhost/ssl-2016' --skip-columns=guid
```

---

ブラウザで `http://localhost` にアクセス。
Dockerで動作中のWordPress2サイトについて問題なく閲覧できることが確認できました。:yum:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/5d964bb5-2b39-42e4-8ff3-d3e469a03144.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/ad04dae0-5868-4bac-bbc2-79880875175c.png)

## 9. Lightsailインスタンスを削除

ドキュメントによると Lightsail インスタンスの削除を aws-cli で行う場合に必要となるのは ARN ではなくインスタンス名称の模様。
まずはインスタンスの一覧を取得するコマンドから名称を取得します。

```bash:CloudShell で Lightsail インスタンスの一覧名を取得
$ aws lightsail get-instances | jq '.instances[].name'
"20240811new_imo-tikuwa.com"
```

- 1つのみ存在することを確認

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lightsail/get-instances.html

---

一応マネジメントコンソール上でも確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/33a14fcb-02a4-4a6e-86f3-221444b73564.png)

---

↑ で確認したインスタンス名称を元に削除を実施

```bash:CloudShell で Lightsail インスタンスを削除
$ aws lightsail delete-instance --instance-name 20240811new_imo-tikuwa.com
{
    "operations": [
        {
            "id": "********-****-****-****-************",
            "resourceName": "20240811new_imo-tikuwa.com",
            "resourceType": "Instance",
            "createdAt": "2025-04-23T08:40:34.132000+00:00",
            "location": {
                "availabilityZone": "ap-northeast-1a",
                "regionName": "ap-northeast-1"
            },
            "isTerminal": true,
            "operationDetails": "",
            "operationType": "DeleteInstance",
            "status": "Succeeded",
            "statusChangedAt": "2025-04-23T08:40:34.132000+00:00"
        }
    ]
}
```

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lightsail/delete-instance.html

---

削除後マネジメントコンソール上のインスタンス一覧画面から消えてることを確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/52c92ba9-18a2-4758-8ce8-9ab82bc3bd9e.png)

## 10. Route 53 レコード設定から Lightsail インスタンスのIPv6に向けた設定を削除

お名前.com → Route 53 に移行したDNSレコードについて、LightsailインスタンスのIPv6アドレスの設定を一括削除します

---

まずはDNSレコード設定のうち削除対象の IPv6 アドレスに合致するものを取得し、それを `route53 change-resource-record-sets` コマンドの `change-batch` オプションで渡すフォーマットに沿った json ファイル（`delete-records.json`）を作成します

```bash:CloudShell で Route 53 ホストゾーンに含まれるレコード設定のうち削除対象のレコードを取得
$ aws route53 list-resource-record-sets \
  --hosted-zone-id "/hostedzone/Z***************KXJ2S" \
  | jq --arg target "2406:****:***:****:****:****:****:8a40" '{
    Changes: [
      .ResourceRecordSets[]
      | select(.Type == "AAAA" and .ResourceRecords[0].Value == $target)
      | {
          Action: "DELETE",
          ResourceRecordSet: {
            Name: .Name,
            Type: .Type,
            TTL: .TTL,
            ResourceRecords: [
              {
                Value: .ResourceRecords[0].Value
              }
            ]
          }
        }
    ]
  }' > delete-records.json
```

6レコードを削除する json が作成できました。

```json:delete-records.json
{
  "Changes": [
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "imo-tikuwa.com.",
        "Type": "AAAA",
        "TTL": 3600,
        "ResourceRecords": [
          {
            "Value": "2406:****:***:****:****:****:****:8a40"
          }
        ]
      }
    },
    {
      "Action": "DELETE",
      "ResourceRecordSet": {
        "Name": "blog.imo-tikuwa.com.",
        "Type": "AAAA",
        "TTL": 3600,
        "ResourceRecords": [
          {
            "Value": "2406:****:***:****:****:****:****:8a40"
          }
        ]
      }
    },
~~~ 省略 ~~~
  ]
}
```

---

削除前に一応画面からも確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/6b6f7dcf-4418-47de-844a-66616b054038.png)

---

作成した `delete-records.json` を元に Route 53 レコードの更新（6レコードの削除）を実施

```bash:CloudShell で Route 53 レコードの更新（削除）を実施
$ aws route53 change-resource-record-sets \
  --hosted-zone-id "/hostedzone/Z***************KXJ2S" \
  --change-batch file://delete-records.json
```

---

コマンド実施後に画面上でレコードを読み込みなおし6件存在したレコードが削除できてることを確認できました:innocent:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/38cbbd08-60b2-4093-a4f3-8c80fa6fc626.png)

## 感想、備考

これで全ての作業が完了しました。
今回実施した 9 と 10 の作業は書きながら手順逆だなぁと思いました。
できる限りの作業について CloudShell 上から行うことで aws-cli の操作の勉強になりました（特に jq コマンドを使った操作など）。

なお、今回閉鎖した WordPress ブログのうち価値のありそうなコンテンツは Nuxt3 の SSG を活用する形で安価な静的サイトとして復活させるといったことを検討しています。

```txt:ざっくり以下のような方法で実現できる（予定）
1. ローカルの Docker コンテナ環境起動
2. WordPress の RestAPI を使用して投稿やメディアなど必要な情報を収集
3. 収集した情報を元に SSG でビルド
4. 成果物一式を S3 にアップして静的サイトとして公開
```

記事内に含まれる WordPress プラグイン固有のショートシンタックスとかを除いたり、コードブロックのシンタックスハイライトをうまいこと処理できるかが課題となりそうです。

---

ちなみに直近14か月の AWS の料金は以下のような感じ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2384986/cc511458-e6cc-452c-bcae-49546ae63d8e.png)

- 4月分以降、Route 53 ホストゾーンを1つ作ったのでその料金（0.5$）が生えました:innocent:
- 2024/9月頃に Lightsail について IPv4&6 ⇒ IPv6 にしたことで少し安くはなりました


## 参考サイト

今回使用した aws-cli に関するドキュメントは以下

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lightsail/get-instances.html

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lightsail/delete-instance.html