又搬家了:從 Zeabur 遷移到 AWS Lightsail
是的,又搬家了。
前一篇「部落格遷移紀錄」才記錄了從 WordPress 搬到 Ghost,主機也從 SugarHosts、GCP 一路輾轉到了 Zeabur。原本覺得以這個部落格的流量與使用方式來說,Zeabur 簡單方便,應該可以安穩地用上一段時間。
近期 Zeabur 發生的資安事件,剛好讓我重新思考一直沒去想想這個筆記到底放哪好的問題,能符合掛這個小站的經濟效益,我又能在有餘裕時利用主機做一些嘗試,最後決定搬到 AWS Lightsail。
選擇 Lightsail
其實沒有太多 AWS 的使用經驗,一開始在查看時,想過是不是直接用 EC2,但研究了一會,對我這種單純放部落格的小站來說,建一個 EC2 能調整的東西很多,相對也代表需要理解與管理的東西更多,殺雞何需牛刀呢..
於是又看到了 Lightsail ,看起來比較接近我需要的樣子:一台固定規格的 VM、一個 Static IP,加上相對單純的計價方式(😄)。
最後選擇 Hong Kong Region 的 Ubuntu 主機:
- 2 vCPU
- 2 GB RAM
- 60 GB SSD
- Ubuntu 24.04
對我的小部落格來說已經很夠用了,價格也略低於 Zeabur 停用共享叢集及漲價後的總計,藉著 AI 的幫助,花了大約 2 個小時的時間完成備份與搬家。
新的環境維持原有架設在 Zeabur 的版本:
- Ghost 6.43.1
- MySQL 8.0
只是沒有 Zeabur 的方便了,需要小小學習一下大致的架構:
Internet → AWS Lightsail [Caddy → Ghost → MySQL]
Ghost、MySQL 與 Caddy 都透過 Docker Compose 管理。其中只有 Caddy 對外開放 443,Ghost 與 MySQL 都只留在 Docker 內部網路。
我對 Caddy 其實是不熟悉的,讓 AI 帶著實際設定後,發現它就是站在 Ghost 前面接收 HTTPS Request,再把流量轉給 Ghost,跟我以往熟悉的 Nginx 做的事一樣,只是配置上單純許多,連 Let's Encrypt Certificate 的申請與續期都可以自動完成。
準備 Docker Compose
前置工作是建立一個 Lightsail 執行個體後,先在 Lightsail 安裝 Docker,接著透過 docker compose 建立服務,過程中是逐步進行的,一開始先建立好 MySQL 和 Ghost,最初的 compose 大致如下:
services:
mysql:
image: mysql:8.0
restart: unless-stopped
environment:
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
ghost:
image: ghost:6.43.1
restart: unless-stopped
depends_on:
- mysql
environment:
database__client: mysql
database__connection__host: mysql
database__connection__port: 3306
database__connection__user: ${MYSQL_USER}
database__connection__password: ${MYSQL_PASSWORD}
database__connection__database: ${MYSQL_DATABASE}
url: https://josnote.com
volumes:
- ghost_content:/var/lib/ghost/content
volumes:
mysql_data:
ghost_content:
ghost url 要換成自己的網址,docker compose file 中的 ${變數} ,都是存放在 .env檔案裡,不直接寫進 compose。
備份與還原資料
Ghost 需要搬兩個部分:
- MySQL Database
/var/lib/ghost/content
Database 包含文章、設定等資料,而 content 裡則有 images、themes 等檔案。
從 Zeabur 備份
MySQL Database
mysqldump -u"$MYSQL_USERNAME" -p"$MYSQL_PASSWORD" --single-transaction --quick --lock-tables=false --default-character-set=utf8mb4 "$MYSQL_DATABASE" > /tmp/josnote.sql
Ghost content
cd /var/lib/ghost
tar -czf /tmp/josnote-content.tar.gz content
最後得到兩個檔案:
# MySQL Database 匯出的備份
josnote.sql
# Ghost content 壓縮檔備份
josnote-content.tar.gz
下載後透過 SCP 傳到 Lightsail。
還原到 Lightsail
資料庫
Lightsail 上的 Ghost 在第一次啟動時已經建立了一套新的 Database,所以正式還原前先停掉 Ghost,重新建立乾淨的 Database。
接著將 MySQL Database 備份檔透過以下的指令還原到 Lightsail 上的 MySQL:
docker compose exec -T mysql sh -c 'mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' < backup/josnote.sql
完成後簡單確認文章筆數:
docker compose exec mysql sh -c 'mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE" -e "SELECT COUNT(*) AS posts FROM posts;"'
執行後會看到類似以下的結果:
+-------+
| posts |
+-------+
| 31 |
+-------+
數值大於 0 也就代表有匯入成功了。
還原 Ghost Content
透過以下指令,把原本新 Ghost 建立的 content 清掉,再將備份解壓縮還原回來。
docker run --rm -v josnote_ghost_content:/target -v /opt/josnote/backup:/backup alpine sh -c 'tar -xzf /backup/josnote-content.tar.gz -C /target --strip-components=1'
確認 images、themes 等目錄都有回來後,重新啟動 Ghost。
docker compose start ghost到這裡,文章資料與圖片其實都已經在 AWS Lightsail 上了,只是外面的流量還進不來。
讓 Caddy 接收請求轉發到 Ghost
建立 Caddyfile ,並且在 compose 加上 Caddy 的服務。
Caddyfile 只有很簡單的設定,以我的網站為例:
josnote.com {
reverse_proxy ghost:2368
}
意思就是:收到 josnote.com 的請求,就轉發給 Ghost 的 2368 port。
Docker Compose 新增 caddy service,對外開 443 port,經由 Caddyfile 的設定,請求會轉發到 Ghost ,讓 Ghost 不需要直接對外。
caddy:
image: caddy:2
restart: unless-stopped
depends_on:
- ghost
ports:
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
原本想像 HTTPS 可能會是搬家比較麻煩的一段,結果 Caddy 幾乎都幫忙處理掉了。
小插曲:DNS Cache。
當我將 josnote.com 的 DNS 指向 Lightsail Static IP 後,網站其實已經可以正常開啟,但 Caddy 的 log 一直出現 Let's Encrypt Certificate 申請失敗:
authorization failed
remote error: tls: no application protocol
錯誤訊息裡顯示 Let's Encrypt 連線的 IP,竟然還是 Zeabur 原本的 IP。
檢查了 Google DNS 與 Cloudflare DNS,都已經解析到新的 Lightsail IP
nslookup josnote.com 8.8.8.8
nslookup josnote.com 1.1.1.1只有在 Lightsail 主機裡,仍然得到 Zeabur 的 IP
nslookup josnote.com
這是 Ubuntu 本機的 DNS Cache,在 AI 的指導下,透過以下指令清掉:
sudo resolvectl flush-caches
重新查詢後就變成新的 Lightsail IP。
後記
好像每搬一次家,就會多理解到一些網站平常不太需要注意的東西,但希望不用常常透過搬家來了解,希望這次可以住久一點😅