如何將伺服器遷移至新的 VPS
以演練式切換將正式伺服器遷移至新的 VPS:先盤點資產並重建主機,再傾印資料庫、提前降低 DNS TTL,完成驗證後切換。
將伺服器遷移至新的 VPS,並以演練式切換完成
將伺服器遷移至新的 VPS 時,應把這次搬遷視為演練式切換,而不是單純複製。從頭建立新主機,分兩次同步資料;先確認新主機能以自己的 IP 位址獨立運作,再修改 DNS;切換記錄後,讓舊主機繼續運作,直到確定一切正常。複製資料是最容易的部分。作業順序才決定搬遷能否順利完成,或造成高昂成本。
本指南涵蓋一台執行 Web 應用程式、資料庫及 TLS(transport layer security)憑證的 Linux 伺服器。這足以涵蓋大多數單伺服器環境。流程會使用兩台主機,因此每個範例都會在註解中說明執行位置。位址使用文件範圍中的位址:198.51.100.10 是舊伺服器,203.0.113.20 是新伺服器。
開始前先閱讀完整操作手冊。第一個步驟是降低 DNS TTL,必須在實際進行切換前數天完成。
建立任何內容前,先完成資產盤點
在尚未描述舊伺服器前,無法重建它。花一小時記錄舊伺服器目前負責的工作,因為遷移後出問題的,總是沒有人記得的項目:cron job、防火牆例外,或放在應用程式目錄之外的環境檔案。
在舊伺服器上執行以下指令,並將輸出儲存到新伺服器也能讀取的位置。
# old server: packages you asked for, not the dependencies they pulled in
apt-mark showmanual > ~/inv-packages.txt
# old server: what runs now, and what starts at boot
systemctl list-units --type=service --state=running --no-pager > ~/inv-services.txt
systemctl list-unit-files --state=enabled --no-pager >> ~/inv-services.txt
systemctl list-timers --all --no-pager > ~/inv-timers.txt
# old server: what is listening, on which address and port
sudo ss -tulpn > ~/inv-ports.txt
# old server: human accounts, skipping the system ones
awk -F: '$3 >= 1000 && $3 < 65534 {print $1, $3, $6, $7}' /etc/passwdapt-mark showmanual 之所以值得保留,是因為它會列出所有作為相依性安裝的項目。對使用五年的伺服器執行完整的 dpkg --get-selections,會產生兩千行輸出,卻無法說明安裝目的。
排程工作會出現在兩個位置,因此兩者都要檢查。每月才執行一次的工作,通常會在遷移六週後才被發現。
# old server: per-user crontabs, then the system drop-ins
for u in $(cut -d: -f1 /etc/passwd); do sudo crontab -lu "$u" 2>/dev/null | sed "s/^/$u: /"; done
sudo ls -la /etc/cron.d /etc/cron.daily /etc/cron.hourly接著檢查不是一般檔案的項目:防火牆規則、憑證、資料庫,以及實際要遷移多少資料。
# old server
sudo ufw status verbose # or: sudo nft list ruleset
sudo certbot certificates
sudo -u postgres psql -c '\l' # or: sudo mysql -e 'SHOW DATABASES;'
sudo du -xh --max-depth=1 / | sort -hcertbot certificates 會列印每張憑證的名稱、涵蓋的網域、到期日,以及檔案在磁碟上的路徑。這份輸出就是 TLS 檢查清單。du -x 只會留在同一個檔案系統中,因此不會進入已掛載的備份磁碟區,避免回報大十倍的數值。
有兩項資訊位於伺服器外部,而且每次都會被遺漏。第一,任何將伺服器 IP 位址列入 allowlist 的第三方,例如付款閘道、代管資料庫、SMTP relay 或合作夥伴 API。新伺服器會使用新的位址,因此必須在切換前將新 IP 加入這些 allowlist,而不是切換後才處理。第二,並非由你自行建立的 DNS 記錄,例如 MX 記錄,或文字內容中仍指向舊 IP 的 SPF 記錄。
為什麼要重建,而不是複製舊的 root 檔案系統
將整個 root 檔案系統複製到新的 VPS 看似較快,實際上也確實較快,直到問題出現為止。已在正式環境執行多年的 root 檔案系統,通常包含無人記錄的手動編輯設定、來自已不存在之 repository 的套件,以及針對舊平台虛擬硬體建立的開機設定。你會把所有內容一併匯入,也包括當初必須搬遷的原因。
重建在第一天較慢,但之後每天都能降低維護成本。先安裝目前的版本並套用基礎強化設定,再只複製資料:應用程式目錄、網站設定、資料庫傾印、憑證及使用者上傳檔案。任何無法解釋的內容都不要搬過來。先按照設定任何伺服器的方式啟動新主機,參考 新 VPS 的前 10 分鐘,再依照清單逐一加入服務。每加入一項,就先確認其運作正常,再加入下一項。
映像或 snapshot 還原是正確選擇的情況
重建有一個合理的例外。如果舊伺服器無法開機,或應用程式已經無法從原始碼重新建置,還原 provider image 或 snapshot 是務實的做法。但這有明確限制:還原通常只能在同一個 provider 內運作,且往往只能在同一個方案系列內使用,因為還原的磁碟會依賴該平台的虛擬裝置與網路命名方式。
對執行中的伺服器建立 snapshot,也會有和其他即時資料庫檔案層級複本相同的一致性問題。請將 image 還原視為復原途徑,而不是遷移計畫;在以此建立計畫前,請先閱讀 為何 snapshot 不等同於 backup。
檔案如何傳輸:透過 SSH 使用 rsync
請從舊伺服器執行 rsync,將資料推送到新伺服器。推送通常較簡單,因為資料已位於舊伺服器上,而且可在 sudo 下讀取所有資料。
# old server: dry run first, and read what it says it will do
sudo rsync -aHAX --dry-run --itemize-changes \
-e 'ssh -i /root/.ssh/id_ed25519' \
/srv/app/ deploy@203.0.113.20:/srv/app/
# old server: the real bulk pass
sudo rsync -aHAX --info=progress2 \
-e 'ssh -i /root/.ssh/id_ed25519' \
/srv/app/ deploy@203.0.113.20:/srv/app/各個旗標都很重要。-a 會保留權限、時間戳記、符號連結與擁有者。-H 會將硬連結保留為硬連結,而不是展開成個別副本。-A 會複製 POSIX ACL(存取控制清單),-X 會複製延伸屬性。缺少最後兩項時,檔案即使看起來完全相同,行為也可能不同,因為 SELinux 標籤與 ACL 儲存在延伸屬性中,其他資訊不會記錄這些內容。
這裡的失敗原因大多來自兩個細節。
結尾的斜線會決定資料的寫入位置。 /srv/app/ 代表該目錄的內容。/srv/app 代表目錄本身。如果弄錯,新伺服器上就會出現 /srv/app/app,應用程式雖然能啟動,接著卻會回報找不到檔案,因為設定中的路徑現在少了一層。
在 sudo 中,波浪號代表 root 的家目錄。 在 sudo rsync 中寫入 -e 'ssh -i ~/.ssh/id_ed25519' 時,SSH 會到 /root/.ssh 尋找金鑰,而不是到你自己的家目錄。如果金鑰不在該處,SSH 會輸出 Permission denied (publickey),rsync 會輸出 rsync: connection unexpectedly closed 並以非零狀態結束。請完整寫出金鑰路徑。如果修正路徑後仍持續出現該驗證訊息,publickey 驗證失敗的原因不多,接著應檢查新伺服器上的目錄權限。
擁有權需要先做一項決定。以 root 執行時,rsync 預設會依名稱對應擁有者與群組。因此,舊主機上由 www-data 擁有的檔案,即使數值 UID(使用者 ID)不同,在新主機上也會由 www-data 擁有。這適合重建環境。只有在複製檔案系統,且目標端不存在對應帳號時,才加入 --numeric-ids。接著使用 ls -ln 檢查結果,因為由沒有對應帳號的 UID 擁有的檔案會顯示為單純的數字,所有讀取該檔案的服務都會被拒絕存取。
請在舊伺服器仍提供網路流量期間,提前數天執行主要同步。你可以依需求重複執行:rsync 只會傳送變更內容,因此第二次同步只需幾分鐘,而不是數小時。在切換期間執行最後一次同步時,加入 --delete,讓舊伺服器上已刪除的檔案也從新伺服器移除。
# old server: final pass, inside the window, after the app has stopped writing
sudo rsync -aHAX --delete --info=progress2 \
-e 'ssh -i /root/.ssh/id_ed25519' \
/srv/app/ deploy@203.0.113.20:/srv/app/--delete 會刪除目的端中來源端已不存在的檔案,因此錯誤的來源路徑搭配 --delete 可能會清空目的端目錄。每次執行前都先使用 --dry-run。長時間傳輸也可能因筆電上的 SSH 工作階段中斷而停止,因此請在舊伺服器上使用 tmux 或 screen 啟動傳輸。如果複製作業在舊伺服器仍服務使用者期間佔滿連線頻寬,請加入 --bwlimit=20M。
資料庫的搬遷方式:使用原生傾印
資料庫不是檔案目錄,雖然看起來像是。它由檔案、記憶體狀態與 write-ahead log 組成,只有在資料庫本身定義的時間點才保持一致。請使用資料庫自身的工具。
PostgreSQL 需要建立 2 個傾印,因為角色是整個叢集共用的,而 pg_dump 不包含角色:
# old server
sudo -u postgres pg_dumpall --globals-only -f /var/backups/globals.sql
sudo -u postgres pg_dump -Fc -f /var/backups/appdb.dump appdb# new server: restore in this order
sudo -u postgres psql -f /var/backups/globals.sql
sudo -u postgres createdb -O appuser appdb
sudo -u postgres pg_restore -d appdb --no-owner /var/backups/appdb.dump略過 globals.sql 會導致所有資料表都還原完成,卻沒有任何應用程式角色能夠讀取,因為 GRANT 陳述式所參照的使用者並不存在。-Fc 會寫入 custom archive 格式;這種格式只能由 pg_restore 讀取,也能讓你日後只還原選定的資料表。請還原至相同或較新的 major version。例如從 17 往回還原至 16 並不受支援;pg_restore 會在寫入任何內容前,先因檔案標頭中的版本不受支援而拒絕該 archive。
MySQL 與 MariaDB 使用單一命令,並且需要指定 4 個預設未啟用的選項:
# old server
sudo mysqldump --single-transaction --routines --triggers --events \
--databases appdb > /var/backups/appdb.sql# new server
sudo mysql < /var/backups/appdb.sql--single-transaction 會建立一致的 snapshot,且不會阻塞寫入,但只適用於 InnoDB 資料表。同一個資料庫中的 MyISAM 資料表則不具備這項保證,因此在信任傾印前,請先確認儲存引擎。--routines、--triggers 與 --events 預設為停用,這表示 plain dump 會還原資料,卻默默留下未還原的 stored procedures 與 scheduled events。資料庫使用者及其 grants 位於 mysql system database 中,而 --databases appdb dump 絕不會處理該資料庫,因此請在新伺服器上使用 CREATE USER 與 GRANT 重新建立。MariaDB 11 發行時提供相同工具,名稱為 mariadb-dump,並保留 mysqldump 作為 symbolic link,因此截至 August 2026,兩個名稱皆可使用。
SQLite 是單一檔案;應用程式寫入時複製該檔案,會產生不完整的檔案。SQLite 有自己的安全作法:
# old server
sqlite3 /var/lib/app/app.db ".backup '/var/backups/app.db'"無論使用哪種引擎,都應在信任傾印前先檢查。若傾印因磁碟已滿而提早停止,還原時可能不會顯示錯誤,直到處理到遭截斷的位置才會失敗。
# old server: a complete mysqldump ends with a line reading "-- Dump completed on ..."
tail -n 3 /var/backups/appdb.sql
# new server: after restore, count rows in a table whose size you know
sudo mysql -e 'SELECT COUNT(*) FROM appdb.orders;'為什麼不能對執行中的資料庫使用 rsync
rsync 會逐一複製檔案。執行中的資料庫會同時寫入多個檔案,因此 rsync 複製到最後一個檔案時,第一個檔案可能早已過時。這份副本包含來自不同時間點的頁面,而資料庫從未處於這種狀態。結果可能是伺服器拒絕啟動;更嚴重的情況是伺服器可以啟動,並持續一週提供正確結果,直到某個查詢存取損毀的頁面後才失敗。中間不會出現任何警告。
若要直接搬移檔案,有兩種安全方式。停止資料庫、複製檔案,再重新啟動:這種方式正確且簡單,但停機時間會等於複製所需的時間。另一種方式是使用專為複製執行中伺服器的實體資料而設計的工具。對 PostgreSQL 而言,這是 pg_basebackup。它會與伺服器協調,確保副本保持一致:
# new server: pull a physical copy from the old one
pg_basebackup -h 198.51.100.10 -U replicator -D /var/lib/postgresql/16/main -X stream -P這需要具備 REPLICATION 屬性的 role,以及舊伺服器中相符的 pg_hba.conf 設定,因此所需準備工作比 dump 多。當資料庫大到無法在維護時段內完成 dump 與 restore 時,這種方式值得採用。一般的單一伺服器遷移則以 dump 為佳。
在切換前重新建立憑證,不要等到切換後
TLS 憑證綁定的是網域名稱,而不是 IP 位址,因此憑證檔案本身可以直接搬移。無法順利搬移的是續期流程。Certbot 預設的 HTTP-01 challenge 會要求憑證授權單位透過 port 80,從目前申請憑證的名稱抓取檔案。在 DNS 指向新伺服器之前,該請求仍會送到舊伺服器,導致新伺服器的續期失敗。
第一個選項是複製現有憑證及其續期狀態。無論憑證位於哪台伺服器,在到期日前都仍然有效。
# old server
sudo rsync -aHAX -e 'ssh -i /root/.ssh/id_ed25519' \
/etc/letsencrypt/ root@203.0.113.20:/etc/letsencrypt//etc/letsencrypt/renewal/ 下的每個檔案都會記錄簽發該憑證的驗證器 plugin。因此,請在新伺服器上安裝相同的 plugin(例如 python3-certbot-nginx),否則第一次續期時會因找不到驗證器而失敗。先確認續期可以正常運作,再依賴這套流程:
# new server, after DNS has moved
sudo certbot renew --dry-run第二個選項是在新伺服器上使用 DNS-01 challenge 簽發新憑證。此 challenge 透過 TXT 記錄證明網域控制權,完全不需要使用 port 80。在遷移前即可執行,因為此時該名稱仍解析到舊伺服器。如果能將 DNS provider 自動化,這通常是較簡潔的選擇。使用 DNS-01 challenge 簽發憑證 說明 plugin 與認證資料的設定方式。
無論採用哪個選項,都應在不變更 DNS 的情況下,確認新伺服器實際提供的憑證:
# your laptop
echo | openssl s_client -connect 203.0.113.20:443 -servername example.com 2>/dev/null \
| openssl x509 -noout -subject -dates -issuer-servername 會傳送 SNI(server name indication),讓網頁伺服器選擇正確的 virtual host。若省略此參數,伺服器會提供該 IP 位址的預設憑證,並產生看似嚴重但實際上不是真正問題的名稱不符錯誤。
在切換前數日降低 DNS TTL
DNS 是即使謹慎執行遷移仍可能出錯的環節,因為延遲已經存在,而且無法在切換當天縮短。解析器快取 A 記錄後,會在該記錄提供的 TTL(存留時間)期間持續回傳原值。現在降低 TTL,對 10 分鐘前仍以舊值快取該記錄的解析器沒有作用:它會在舊 TTL 剩餘期間繼續保留舊值,之後才會取得新的較短 TTL。因此,至少要提前完整一個舊 TTL 週期降低 TTL,再進行切換。提前 1 天是較寬裕的做法。如果你不熟悉這些運作環節,記錄、解析器與快取的操作說明可提供背景資訊。
以下數字是根據 TTL 本身計算而來,不是測量結果。
The data behind this chart
[
{
"label": "TTL 3600 s (common default)",
"ttl_seconds": 3600,
"worst_case_stale_minutes": 60
},
{
"label": "TTL 900 s",
"ttl_seconds": 900,
"worst_case_stale_minutes": 15
},
{
"label": "TTL 300 s (lowered for cutover)",
"ttl_seconds": 300,
"worst_case_stale_minutes": 5
},
{
"label": "TTL 60 s (short window)",
"ttl_seconds": 60,
"worst_case_stale_minutes": 1
}
]TTL 為 3600 秒的 A 記錄,在你變更記錄後,最久仍可能將使用者導向舊 IP 60 分鐘。將 TTL 降至 300 秒後,最長延遲會降至 5 分鐘。這些數字應視為下限,不是保證。有些解析器會自行套用最小 TTL,忽略更短的值;有些應用程式執行環境則會在處理程序存續期間快取解析後的位址。因此,在變更前已啟動的用戶端,可能要等到重新啟動後才會再次查詢。
確認較低的 TTL 已生效時,應讀取權威回覆,而不是讀取自己的快取:
# your laptop: ask the zone's own nameserver, so no cache is involved
dig +short NS example.com
dig +noall +answer @$(dig +short NS example.com | head -n1) example.com A該回覆行的第二個欄位就是以秒為單位的 TTL。接著檢查容易遺漏的記錄:如果舊伺服器使用 IPv6,則檢查 AAAA 記錄;如果 www 名稱是獨立的 A 記錄而非 CNAME,則檢查該名稱;檢查任何指向伺服器本身的 MX 記錄、列出舊 IP 的 SPF 記錄,以及新位址上的反向 DNS(PTR)記錄。如果伺服器會寄送郵件,請在切換前透過供應商的控制面板設定 PTR,因為收信郵件伺服器會檢查該記錄。缺少 PTR 可能在其他項目看似正常數小時後,導致郵件遭拒收。
在變更 DNS 前,先透過 IP 驗證新伺服器
DNS 仍指向舊伺服器時,您可以在新伺服器上測試整個應用程式。只針對單一請求覆寫名稱解析:
# your laptop: force one name to the new IP, for this request only
curl -sS --resolve example.com:443:203.0.113.20 \
-o /dev/null -w '%{http_code} %{ssl_verify_result}\n' https://example.com/--resolve只會變更連線的目的地。TLS 憑證仍會依實際名稱進行驗證,因此這同時能確認憑證與服務是否正常。驗證憑證鏈後,%{ssl_verify_result}會輸出0。
若要在瀏覽器中操作網站,請在筆電的/etc/hosts中加入一行,以覆寫整台電腦的名稱解析;Windows 則請修改C:\Windows\System32\drivers\etc\hosts:
203.0.113.20 example.com www.example.com接著依照使用者的操作方式完整測試應用程式。登入。載入會從資料庫讀取資料的頁面。送出會寫入資料庫的表單。上傳檔案,確認檔案已寫入磁碟。觸發會寄送電子郵件的功能,並確認郵件已送達,因為新 IP 的對外 SMTP 常會產生預期外的問題。完成後立即移除 hosts 設定。若保留該設定,您可能會花一小時除錯一個其他所有人都能正常存取的網站。
逐步切換
- 提前幾天:降低 TTL,執行大量 rsync,建置新伺服器,並透過 hosts 覆寫測試新伺服器。
- 切換當天、維護時段開始前:將新 IP 加入所有第三方允許清單,並確認新伺服器已設定備份工作,且備份目標指向你的儲存庫。
- 開始維護時段:在舊伺服器上將應用程式設為維護模式,使其停止接受寫入。
- 取得最後一次資料庫傾印,然後使用
--delete執行最後一輪 rsync。 - 在新伺服器還原傾印,並啟動服務。
- 再次透過
--resolve和 hosts 覆寫進行測試,其中包括一次實際寫入。 - 將 A 和 AAAA 記錄變更為新 IP。
- 監看兩台伺服器。舊伺服器的存取日誌會顯示仍在連入該伺服器的用戶端,數量應在 TTL 期間逐漸降至接近 0。
- 移除維護頁面。
- 讓舊伺服器維持執行狀態且不要變更,至少保留 1 週。
維護模式是最常被跳過的步驟,但也是保護你的關鍵。新資料庫接受寫入後,回復切換不僅可能遺失該筆寫入,還可能需要傾印新資料庫,再將資料載回舊資料庫。幾分鐘的唯讀時段成本很低。兩個資料庫都已接受寫入後,可能需要數天手動整合資料。
回復計畫
回復只需執行一個動作:將 DNS 記錄改回 198.51.100.10。這之所以可行,是因為你先前完成了以下 4 件事。
- 舊伺服器仍在執行,服務正常運作,資料也保持完整。你已停止對它寫入資料,但沒有將它除役。
- TTL 仍然較低,因此回復的速度會和原先切換的速度一樣快。
- 你將新 IP 位址加入第三方允許清單,而不是取代舊位址。若移除舊位址,付款閘道的回復路徑就會失效。
- 新伺服器沒有收到任何你無法辨識的寫入,因為到目前為止,唯一的寫入都是你自己的測試交易。
在維護時段開始前,先決定哪些情況會觸發回復。設定 2 個觸發條件即可:任何無法在固定分鐘數內診斷的錯誤,以及任何資料遺失。事先寫下這些條件,才能避免在故障時持續猜測,讓原本 10 分鐘的中斷變成長時間中斷。
驗證遷移是否成功
網站可以載入,並不代表遷移已完成。請檢查那些只會在稍後才失敗的項目。
# new server
systemctl --failed
journalctl -p err -b --no-pager | tail -n 40
sudo certbot certificates
sudo systemctl list-timers --all --no-pagersystemctl --failed reporting 0 loaded units listed 是您要的結果。certbot certificates 應顯示預期的到期日期,而 list-timers 應從您的清單中顯示每個已排程的工作,並提供實際的下次執行時間,而不是空白。
接著,在您監看時,刻意將新伺服器重新開機一次。有人手動啟動但從未設為啟用的服務,在第一次於凌晨 3 點非預期重新開機前,通常都能正常運作。
# new server
sudo reboot
# your laptop, once it comes back
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/如果應用程式在容器中執行,這個陷阱會以不同形式出現,因為 compose stack 必須明確設定 restart policy,才能在重新開機後恢復執行。
最後一項檢查最容易延後,卻最重要:備份工作。以未備份的伺服器結束遷移,只是將一種風險換成另一種風險。請在新伺服器上手動執行備份,然後從備份還原單一檔案到暫存目錄。實際測試過還原的 restic repository,才是在需要時真正有幫助的版本。如果您讓舊伺服器與新伺服器並行運作一週,一致的主機連線與設定方式 可避免兩台伺服器同時上線時逐漸產生差異。
切換完成後:舊伺服器與最後幾項工作
保留舊伺服器 1 到 2 週。這只需支付原本準備取消的方案 1 個月費用,而且這是唯一可用的回復方式。接著完成其餘收尾工作。
- 在
~/.ssh/config中為新主機重複使用相同的主機名稱時,第一次連線會顯示WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!,因為該名稱現在會對應不同的主機金鑰。確認變更原因後,再使用ssh-keygen -R example.com清除過時的項目,不要反射性地執行,因為相同的警告也可能表示遭到攔截攻擊。遷移也是檢視哪些金鑰可以存取哪些資源的好時機;小型伺服器群組的 SSH 金鑰管理即是為此而設。 - 對舊伺服器建立最後一份 snapshot 或備份,並將其儲存在舊供應商以外的位置。
- 依序從監控檢查、SPF 記錄及第三方允許清單中移除舊 IP。這應最後執行。
- 確認最後一份副本可在其他位置正常讀取後,才取消舊方案。
FAQ
將伺服器遷移到新的 VPS 需要多久?
使用者可感知的中斷通常只發生在最後一次資料庫傾印、最後一次 rsync 複製,以及啟動服務的期間,因此小型應用程式通常需要 10 到 30 分鐘。整體準備時間會更長,因為切換前至少要提前一個原有 TTL 週期降低 DNS TTL;提前一天會更安全。大量資料的初次複製也應提早幾天規劃。這項複製可在執行中的伺服器上進行,之後再次執行時只會傳輸上次複製後變更的內容。
可以直接對執行中的 MySQL 或 PostgreSQL 資料庫執行 rsync,而不先傾印嗎?
不行。rsync 會逐一複製檔案,但資料庫會同時寫入多個檔案,因此複製結果可能包含不同時間點的頁面,代表資料庫從未處於的狀態。資料庫可能拒絕啟動,也可能先啟動,直到查詢讀取損壞的頁面時才失敗。請使用 pg_dump 搭配 pg_dumpall --globals-only,或使用 mysqldump --single-transaction;也可以先停止資料庫,再複製檔案。對於大型 PostgreSQL cluster,pg_basebackup 可從執行中的伺服器建立一致的實體複本。
修改 DNS 前,如何測試新的 VPS?
在自己的電腦上覆寫名稱解析。若只測試單一請求,curl --resolve example.com:443:203.0.113.20 https://example.com/ 會將連線傳送到新的 IP,同時仍以實際名稱驗證憑證。若要使用瀏覽器測試,請在筆記型電腦的 /etc/hosts 加入 203.0.113.20 example.com,依序測試登入、資料庫讀取、表單寫入與檔案上傳,完成後移除該行。若只要檢查憑證,請執行 openssl s_client -connect 203.0.113.20:443 -servername example.com。
應設定多少 TTL?何時降低 TTL?
將 A 與 AAAA 記錄降低為 300 秒,並在切換前至少一個完整的原有 TTL 週期完成設定。若 resolver 在變更前已快取該記錄,會在原有 TTL 剩餘期間繼續使用舊值;因此,如果原有 TTL 是 86400,提前 1 小時降低 TTL 不會產生效果。遷移完成幾天後,確認舊伺服器的存取日誌已停止新增,再恢復為平常使用的值。
應該複製 TLS 憑證,還是在新伺服器重新簽發?
兩種方式都可以。複製 /etc/letsencrypt/ 可讓憑證沿用原有的有效期限,但新伺服器必須安裝相同的 certbot authenticator plugin,否則第一次續期會失敗。因此,DNS 切換後請執行 certbot renew --dry-run 進行確認。若能使用 DNS-01 challenge,重新簽發會更簡潔,因為它透過 TXT 記錄證明網域控制權,而且在 DNS 指向新伺服器前即可運作。新伺服器在 DNS 完成切換前不能使用 HTTP-01 challenge,因為驗證請求會送達舊伺服器。