Skip to main content
BlogVocab Challenge
Tools
New PasswordConvert TextTimersRoster
Games
Online XiangqiOnline ChessOnline GomokuOnline GoOnline BanqiOnline AvalonFarm Manager
About
||
Login
Leave a message

從 Ubuntu 20.04 搬到 Debian 13:一次 VPS 換機紀錄

起因

2026 年 10 月底,Linux 核心爆出一個 CVSS 9.8 的漏洞(CVE-2026-98432),網路上不用登入就能遠端拿到 root,前提是機器上有 MPTCP listener。我想確認自己的 VPS 有沒有受影響,順手查了一下:

cat /etc/os-release; uname -r
sysctl net.mptcp.enabled

結果:

  • Ubuntu 20.04,kernel 5.4.0-170
  • /proc/sys/net/mptcp 不存在。MPTCP 要到 5.6 才進主線,所以這個漏洞剛好打不到我

不過真正的問題比這個漏洞大:

  • Ubuntu 20.04 的標準支援在 2025 年 5 月就結束了
  • pro status 顯示這台沒有接 Ubuntu Pro,等於收不到 ESM 的安全更新
  • 5.4.0-170 大約是 2024 年初的核心,將近兩年沒有核心修補

這次能躲過,純粹是因為核心太舊。下一個漏洞就不一定了。

決定:換一台新機,而不是補舊機

接 Ubuntu Pro(個人免費)可以讓 20.04 撐到 2030 年,但那也只是延長壽命。整站本來就是用 docker compose 跑,資料集中在一個目錄,換機成本不高,所以乾脆重開一台。

OS 選了 Debian 13(trixie),原因如下:

  • 機器只有 1 核 1G,Debian 沒有 snapd、預設服務少,比較省記憶體
  • 這次的核心漏洞是 Debian 先出修補,Ubuntu 比較晚
  • apt、systemd 的用法跟原本一樣,部署腳本幾乎不用改
  • 代價是支援期比 Ubuntu LTS 加 ESM 短(大約到 2030 年),也沒有免費的 livepatch

這次真正學到的事

回頭看,問題不在選了 Ubuntu,而是沒有開自動更新,也沒有人注意 EOL。所以新機第一件事就是把自動安全更新打開。

新機準備

1. 使用者與 SSH

adduser --uid 1001 kawa      # uid 跟舊機一致,後面搬檔案會用到
usermod -aG sudo kawa

確認金鑰登入和 sudo 都能用之後,才關閉密碼登入和 root 登入:

sudo tee /etc/ssh/sshd_config.d/00-kawa.conf <<'EOT'
PermitRootLogin no
PasswordAuthentication no
EOT
sudo sshd -t && sudo systemctl reload ssh
sudo sshd -T | grep -Ei '^(permitrootlogin|passwordauthentication)'

2. IPv6、swap

這台沒有可用的 IPv6,但 IPv6 stack 預設是開的,程式會先試 IPv6 再失敗,所以整台關掉。Vultr 的映像檔已經內建 2.3G 的 swapfile,只需要調整 swappiness。

3. Docker

用 Docker 官方的 apt 來源,不用 Debian 套件庫裡的 docker.io。

4. fail2ban

設定照抄舊機,只有一個地方要改:Debian 12 以後預設沒有 /var/log/auth.log,要改用 systemd journal。

[sshd]
enabled  = true
backend  = systemd
maxretry = 3
findtime = 600
bantime  = 1h
bantime.increment = true
bantime.factor    = 24
bantime.maxtime   = 8w

5. 自動安全更新加自動重開機

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
sudo tee /etc/apt/apt.conf.d/52kawa-reboot <<'EOT'
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "20:00";
EOT

主機時區是 UTC,20:00 就是台灣凌晨 4 點。

踩到的坑

1. 舊機的 uid 不是 1000

我原本以為第一個使用者一定是 1000,查了才發現舊機的 kawa 是 1001。搬檔案時要原樣保留擁有者,兩邊的 uid 一定要一樣。建 VPS 時也不要勾 Vultr 的「Limited User Login」,它會先建一個 linuxuser,把 uid 1000 佔走。

2. sshd 的設定被 cloud-init 靜默蓋掉

一開始我把設定檔取名 99-kawa.conf,sshd -T 一查才發現 passwordauthentication 還是 yes。原因是 sshd_config.d/ 照檔名順序讀,同一個設定以第一次出現的值為準。cloud-init 放了一個 50-cloud-init.conf,裡面寫著 PasswordAuthentication yes,排在我的設定前面。改名成 00-kawa.conf 就解決了。

教訓:改完 sshd 設定,要用 sshd -T 看實際生效的值,不要只看設定檔。

3. 改主機名稱後 sudo 一直跳警告

sudo: unable to resolve host 是因為 /etc/hosts 裡沒有新的主機名稱。另外 cloud-init 每次開機都可能把主機名稱改回去,所以要設定 preserve_hostname: true 和 manage_etc_hosts: false。

4. PostgreSQL 的資料目錄本來就只有 postgres 讀得到,搬家要用 root

這不是設定錯誤,而是 PostgreSQL 的安全設計:資料目錄的權限比 0700 寬鬆的話,它會直接拒絕啟動(data directory has invalid permissions)。官方的 postgres:18-alpine image 啟動時,也會把掛載進來的目錄改成容器內 postgres 使用者(uid 70)擁有。所以從主機上看,這個目錄是 uid 70 擁有,一般使用者讀不到,這是正常的。

出錯的是我的搬家文件,它假設用一般使用者就能 rsync 全部的資料。這段指令以前從來沒實際跑過,這次動手前讀文件時才發現。

最後的做法是在舊機用 root 推過去,加上 --numeric-ids 保留數字 uid,新機那端暫時開放免密碼 sudo rsync:

rsync -a --numeric-ids --delete \
  -e "ssh -i ~/.ssh/id_ed25519" --rsync-path="sudo rsync" \
  /srv/kawa/ kawa@<新機>:/srv/kawa/

PostgreSQL 版本一樣(這次兩邊都是 18),所以可以直接搬資料目錄。跨大版本的話就要改用 pg_dump 匯出、在新機匯入。

5. 文件寫的和實際的不一樣

我的部署文件寫著 Cloudflare 上 api、media 這幾個子網域有各自的 DNS 紀錄,實際打開一看,只有根網域、*、www 三筆 A record,子網域都是透過萬用紀錄連過去的。fail2ban 的設定也跟文件寫的不同。動手前先看實際狀態,不要照文件推論,這次又驗證了一次。

搬家流程

整站資料只有大約 350MB(資料庫 253M、上傳的圖片 95M),所以流程很單純:

  1. 停站前:新機先同步部署設定、先拉好 image、先申請憑證(DNS-01 驗證不需要流量已經切過來),再預熱同步一次資料庫以外的檔案
  2. 停站:舊機 docker compose down,然後完整 rsync 一次(含資料庫)
  3. 新機起服務:docker compose up -d,用 curl --resolve 直接打新機本機,確認 TLS 和回應都正常
  4. 切流量:在 Cloudflare 改 3 筆 A record 的 IP。因為有橘雲,改完幾乎馬上生效
  5. 改 CI:把 GitHub secret 裡的主機位址改成新機,然後 push 一次,確認 CI 真的部署到新機

停站時間大約幾分鐘。舊機的資料都留著,萬一出問題,把 Cloudflare 的 IP 改回去,再在舊機 docker compose up -d 就能回復。

最後還有一個容易忽略的收尾:搬資料時為了讓舊機能連到新機,在新機加了舊機的 SSH 公鑰。搬完一定要移除,否則沒有在更新的舊機一旦被入侵,就能直接登入新機。

還沒做的事

  • 觀察幾天,沒問題再退租舊機
  • 異地備份。舊機退租後,資料就只剩新機這一份

Contents

  • 從 Ubuntu 20.04 搬到 Debian 13:一次 VPS 換機紀錄
  • 起因
  • 決定:換一台新機,而不是補舊機
  • 這次真正學到的事
  • 新機準備
  • 1. 使用者與 SSH
  • 2. IPv6、swap
  • 3. Docker
  • 4. fail2ban
  • 5. 自動安全更新加自動重開機
  • 踩到的坑
  • 搬家流程
  • 還沒做的事

Comments