<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Vm on Tarragon</title><link>https://tarrragon.github.io/blog/tags/vm/</link><description>Recent content in Vm on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Thu, 02 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/vm/index.xml" rel="self" type="application/rss+xml"/><item><title>拍照 vs 重建指令：環境重建的兩種思路</title><link>https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/snapshot-vs-rebuild/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/snapshot-vs-rebuild/</guid><description>&lt;p>環境重建是 dotfile 管理的最終目的：拿到一台空白機器，能在可預期的時間內還原成你熟悉的工作環境。這件事有兩條根本不同的路線，選哪條決定了你之後所有的管理策略。&lt;/p>
&lt;h2 id="拍照vm-快照與磁碟映像">拍照：VM 快照與磁碟映像&lt;/h2>
&lt;p>第一種是&lt;strong>拍照&lt;/strong>。VM 快照和磁碟映像（Clonezilla、&lt;code>dd&lt;/code>）做的事是把整台機器某一刻的完整狀態凍結存檔——整個虛擬硬碟的 block-level 複製，有時連記憶體狀態都包含。還原就是把映像寫回去，系統回到那一刻，像時光倒流。Docker 的 &lt;code>docker commit&lt;/code> 也屬於這個方向：把正在跑的 container 的檔案系統快照成一個 image。&lt;/p>
&lt;p>拍照產出的是&lt;strong>黑盒子&lt;/strong>。一個磁碟映像是二進制檔案，沒人能看出裡面到底做了什麼設定、裝了什麼、改過什麼。它大（動輒 GB 級）、跟硬體耦合（換不同架構或不同顯卡可能開不起來）、無法做 diff 或 code review。&lt;/p>
&lt;h2 id="重建指令dotfile-repo--install-script">重建指令：Dotfile repo + install script&lt;/h2>
&lt;p>第二種是&lt;strong>重建指令&lt;/strong>。Dotfile repo + install script 描述的是「怎麼從一台空白機器組出這個環境」，每次都從零開始執行。Dockerfile 也是重建指令——一份「照著做就能重現」的食譜，描述每一步該安裝什麼、複製什麼、怎麼啟動。&lt;/p>
&lt;p>重建指令產出的是&lt;strong>白盒子&lt;/strong>。每一步都是可讀的文字——這行裝 zsh、那行設定 Hyprland 的 keybind——可以被 review、被 diff、被另一個人讀懂。它小（通常幾十 KB）、跨硬體（同一份 script 加 OS 判斷就能跑在不同機器）、可以進版控走 PR 流程。&lt;/p>
&lt;p>dotfile 管理選的是重建指令這條路。代價是你必須把環境建構的過程記錄清楚——每裝一個新工具、每改一個配置都要同步更新 repo。回報是任何一台機器、任何時間點，都能用一份 Git repo 重現你的工作環境。&lt;/p>
&lt;h2 id="場景判讀">場景判讀&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>需求&lt;/th>
 &lt;th>VM 快照&lt;/th>
 &lt;th>Dotfile 重建&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>保留某一刻的完整系統狀態&lt;/td>
 &lt;td>適合（block-level 完整備份）&lt;/td>
 &lt;td>不適合（只管配置層）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>在新機器還原工作環境&lt;/td>
 &lt;td>不適合（硬體耦合、映像大）&lt;/td>
 &lt;td>適合（跨硬體、輕量）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>讓環境可被他人重現（onboarding）&lt;/td>
 &lt;td>勉強（黑盒子、難維護）&lt;/td>
 &lt;td>適合（白盒子、可 review）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>在多台機器維持一致&lt;/td>
 &lt;td>不適合（每台都要拍照）&lt;/td>
 &lt;td>適合（一份 repo、多台 apply）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>做實驗後回滾（改壞了想恢復）&lt;/td>
 &lt;td>適合（秒級回滾）&lt;/td>
 &lt;td>要靠 git revert + 重新 apply&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>讓桌面配置進 review 流程&lt;/td>
 &lt;td>不適合（二進制映像無法 diff）&lt;/td>
 &lt;td>適合（純文字、可 diff、可 PR）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>兩者不互斥——常見的組合是：用 dotfile 管理配置（長期可維護的基線），VM 快照用於短期實驗保護（改爛了可以秒回）。&lt;/p></description><content:encoded><![CDATA[<p>環境重建是 dotfile 管理的最終目的：拿到一台空白機器，能在可預期的時間內還原成你熟悉的工作環境。這件事有兩條根本不同的路線，選哪條決定了你之後所有的管理策略。</p>
<h2 id="拍照vm-快照與磁碟映像">拍照：VM 快照與磁碟映像</h2>
<p>第一種是<strong>拍照</strong>。VM 快照和磁碟映像（Clonezilla、<code>dd</code>）做的事是把整台機器某一刻的完整狀態凍結存檔——整個虛擬硬碟的 block-level 複製，有時連記憶體狀態都包含。還原就是把映像寫回去，系統回到那一刻，像時光倒流。Docker 的 <code>docker commit</code> 也屬於這個方向：把正在跑的 container 的檔案系統快照成一個 image。</p>
<p>拍照產出的是<strong>黑盒子</strong>。一個磁碟映像是二進制檔案，沒人能看出裡面到底做了什麼設定、裝了什麼、改過什麼。它大（動輒 GB 級）、跟硬體耦合（換不同架構或不同顯卡可能開不起來）、無法做 diff 或 code review。</p>
<h2 id="重建指令dotfile-repo--install-script">重建指令：Dotfile repo + install script</h2>
<p>第二種是<strong>重建指令</strong>。Dotfile repo + install script 描述的是「怎麼從一台空白機器組出這個環境」，每次都從零開始執行。Dockerfile 也是重建指令——一份「照著做就能重現」的食譜，描述每一步該安裝什麼、複製什麼、怎麼啟動。</p>
<p>重建指令產出的是<strong>白盒子</strong>。每一步都是可讀的文字——這行裝 zsh、那行設定 Hyprland 的 keybind——可以被 review、被 diff、被另一個人讀懂。它小（通常幾十 KB）、跨硬體（同一份 script 加 OS 判斷就能跑在不同機器）、可以進版控走 PR 流程。</p>
<p>dotfile 管理選的是重建指令這條路。代價是你必須把環境建構的過程記錄清楚——每裝一個新工具、每改一個配置都要同步更新 repo。回報是任何一台機器、任何時間點，都能用一份 Git repo 重現你的工作環境。</p>
<h2 id="場景判讀">場景判讀</h2>
<table>
  <thead>
      <tr>
          <th>需求</th>
          <th>VM 快照</th>
          <th>Dotfile 重建</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>保留某一刻的完整系統狀態</td>
          <td>適合（block-level 完整備份）</td>
          <td>不適合（只管配置層）</td>
      </tr>
      <tr>
          <td>在新機器還原工作環境</td>
          <td>不適合（硬體耦合、映像大）</td>
          <td>適合（跨硬體、輕量）</td>
      </tr>
      <tr>
          <td>讓環境可被他人重現（onboarding）</td>
          <td>勉強（黑盒子、難維護）</td>
          <td>適合（白盒子、可 review）</td>
      </tr>
      <tr>
          <td>在多台機器維持一致</td>
          <td>不適合（每台都要拍照）</td>
          <td>適合（一份 repo、多台 apply）</td>
      </tr>
      <tr>
          <td>做實驗後回滾（改壞了想恢復）</td>
          <td>適合（秒級回滾）</td>
          <td>要靠 git revert + 重新 apply</td>
      </tr>
      <tr>
          <td>讓桌面配置進 review 流程</td>
          <td>不適合（二進制映像無法 diff）</td>
          <td>適合（純文字、可 diff、可 PR）</td>
      </tr>
  </tbody>
</table>
<p>兩者不互斥——常見的組合是：用 dotfile 管理配置（長期可維護的基線），VM 快照用於短期實驗保護（改爛了可以秒回）。</p>
]]></content:encoded></item><item><title>機器連不到或起不來</title><link>https://tarrragon.github.io/blog/linux/debug/machine-unreachable/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/debug/machine-unreachable/</guid><description>&lt;p>一台原本能連的機器突然連不上，或一台虛擬機根本開不起來，判讀的方向是「從你這端往那台機器，一層一層確認哪裡斷了」，而不是反覆重試同一個連線動作。連線失敗是最終症狀，真正斷掉的可能是網路、可能是那台機器的某個服務沒起來、可能是虛擬機的宿主側出問題、也可能是一個把上面全部拖下水的共同根因：磁碟滿。這篇從網路層與宿主側的權威狀態切入，把「連不上」拆成可定位的環節。&lt;/p>
&lt;h2 id="遠端機器突然連不上先分清是哪一段斷">遠端機器突然連不上：先分清是哪一段斷&lt;/h2>
&lt;p>一台昨天還能 SSH 的機器今天連不上，第一步是確認「網路層通不通」，跟「SSH 服務在不在」分開。連線在 TCP 就 timeout（連 port 22 卡住沒回應），多半是網路層或機器沒在跑；連線有回應但被拒（&lt;code>Connection refused&lt;/code>），是網路通、但那台機器上沒有服務在聽 port 22。&lt;/p>
&lt;p>對虛擬機或同網段的機器，一個很有用的權威來源是&lt;strong>鄰居表&lt;/strong>（IP 對 MAC 的對應）。要填起來需要對方在鏈路層有回應，所以它直接反映「對方在不在」。用 &lt;code>ip neigh&lt;/code> 看目標 IP 的條目——優先用 &lt;code>ip neigh&lt;/code> 而不是 &lt;code>arp -a&lt;/code>，因為 &lt;code>ip&lt;/code>（iproute2）在現代最小系統一定有，&lt;code>arp&lt;/code>（net-tools）常常沒裝、跑了會 command not found 反而誤導。如果狀態是 &lt;code>INCOMPLETE&lt;/code>（&lt;code>arp -a&lt;/code> 顯示的是 &lt;code>incomplete&lt;/code>），代表這個 IP 在鏈路層上根本沒有機器回應——不是 SSH 的問題，是那台機器的網路沒起來、或根本沒在跑。一個實際案例：一台虛擬機 SSH timeout，鄰居表顯示整個網段的 guest 位址全是 incomplete、只有閘道（宿主那側的橋接介面）是好的——這就定位到「宿主的橋沒問題，但橋的另一頭沒有 VM 在講話」，方向立刻從「調 SSH」轉到「去看 VM 的網路或開機狀態」。&lt;/p>
&lt;p>定位到「機器在跑但網路沒起來」後，去那台機器的主控台（不是 SSH，SSH 正是連不上的東西）確認：&lt;code>ip -brief a&lt;/code> 看有沒有拿到 IP、&lt;code>systemctl status &amp;lt;網路服務&amp;gt;&lt;/code>（&lt;code>dhcpcd&lt;/code> / &lt;code>systemd-networkd&lt;/code>）看網路服務起了沒，需要時 &lt;code>sudo systemctl restart &amp;lt;網路服務&amp;gt;&lt;/code> 重拉。IP 回來、鄰居表的條目從 incomplete 變成有 MAC，就通了。&lt;/p>
&lt;p>還有一個常見誤區是 IP 變了。SSH 的別名、金鑰、&lt;code>known_hosts&lt;/code> 都綁在特定機器身分上；換機器 / 重裝 / DHCP 重配後 IP 或 host key 變了，用舊別名會連錯或被 host key 檢查擋。這條的判讀與修法（&lt;code>ssh user@新IP&lt;/code> 直連、&lt;code>ssh-keygen -R&lt;/code>）見 &lt;a href="../../install/ssh-keyless-bootstrap/">外部連入與無 key 的 bootstrap 路徑&lt;/a>。&lt;/p>
&lt;h2 id="網路通但域名解析不了">網路通、但域名解析不了&lt;/h2>
&lt;p>有一種故障看起來像「網路壞了」，其實是 DNS 解析斷了：能連 IP、卻連不上任何用域名的東西——&lt;code>ping 8.8.8.8&lt;/code> 通、但 &lt;code>ping google.com&lt;/code>、&lt;code>pacman -Sy&lt;/code>、&lt;code>curl https://...&lt;/code> 全失敗。判讀要跟前面「網路沒起來」分開，因為網路層是通的，斷的是「域名 → IP」這一步。權威檢查：&lt;code>ping &amp;lt;IP&amp;gt;&lt;/code> 通而 &lt;code>ping &amp;lt;域名&amp;gt;&lt;/code> 不通、或 &lt;code>getent hosts &amp;lt;域名&amp;gt;&lt;/code>（&lt;code>resolvectl query &amp;lt;域名&amp;gt;&lt;/code> 若有 systemd-resolved）解不出位址，就定位到 DNS。常見成因是 &lt;code>/etc/resolv.conf&lt;/code> 沒有可用的 nameserver（新裝或網路重設後沒填），或負責 DNS 的服務沒起來。修：確認 &lt;code>/etc/resolv.conf&lt;/code> 有一行 &lt;code>nameserver&lt;/code>（如 &lt;code>nameserver 1.1.1.1&lt;/code>）、&lt;code>systemctl status systemd-resolved&lt;/code>（若用它）。這一層在剛裝好的最小系統特別常撞到——&lt;code>ip -brief a&lt;/code> 明明有 IP，&lt;code>pacman&lt;/code> 或 bootstrap 卻抓不到套件，看起來像「網路好好的卻裝不了東西」，根因是 DNS 沒設。&lt;/p>
&lt;h2 id="虛擬機開不起來分清-guest-內部還是宿主側">虛擬機開不起來：分清 guest 內部還是宿主側&lt;/h2>
&lt;p>虛擬機開機失敗時，關鍵判斷是「錯誤來自 guest 內部（作業系統層）還是宿主側（虛擬化軟體 / QEMU 層）」。宿主側的錯誤訊息通常來自虛擬機軟體本身、在 guest 還沒開始開機前就跳出來，跟 guest 裡裝了什麼無關。&lt;/p>
&lt;p>一個實例是 QEMU 報「找不到某個 ROM 檔」（例如 &lt;code>efi-virtio.rom&lt;/code>）而拒絕啟動。第一反應可能是「檔案不見了要重裝」，但正確的第一步是&lt;strong>去確認那個檔在不在&lt;/strong>——實際去虛擬機軟體的安裝目錄裡找（&lt;code>find &amp;lt;安裝目錄&amp;gt; -name '&amp;lt;rom名&amp;gt;'&lt;/code>），會發現 ROM 檔明明就在。既然檔案在，「找不到」就不是缺檔，是 QEMU 執行時&lt;strong>在它預期的路徑下找不到&lt;/strong>——成因隨宿主 OS 不同。&lt;strong>在 macOS + UTM 宿主上&lt;/strong>，最常見的是 Gatekeeper app translocation：帶隔離屬性的 app 被搬到一個隨機唯讀路徑跑，讓 QEMU 解析資源的相對路徑失效，明明存在的檔案在那個執行路徑下就找不到。&lt;strong>在 Linux 宿主上&lt;/strong>（沒有 translocation 這回事），同樣的「找不到 ROM」通常是缺對應套件（&lt;code>ovmf&lt;/code> / &lt;code>ipxe-roms&lt;/code> / &lt;code>edk2-ovmf&lt;/code>）、libvirt XML 指的 ROM 路徑錯、或檔案權限不對——一樣先確認檔在哪、QEMU 是用哪個路徑去找。&lt;/p>
&lt;p>另外兩個常見的「VM 起不來」故障也順手一起排除，它們不會特定產生「找不到 ROM」但常伴隨出現：上一次崩潰殘留的 helper 行程卡著（&lt;code>pgrep -af 'qemu|&amp;lt;虛擬機軟體名&amp;gt;'&lt;/code> 找，沒清乾淨會佔住資源），以及宿主磁碟滿（&lt;code>df -h&lt;/code>，啟動要寫暫存 / 狀態檔）。多數情況下，完全退出虛擬機軟體（連殘留 helper 一起清）+ 清出宿主磁碟空間 + 重新啟動，就恢復了。&lt;/p></description><content:encoded><![CDATA[<p>一台原本能連的機器突然連不上，或一台虛擬機根本開不起來，判讀的方向是「從你這端往那台機器，一層一層確認哪裡斷了」，而不是反覆重試同一個連線動作。連線失敗是最終症狀，真正斷掉的可能是網路、可能是那台機器的某個服務沒起來、可能是虛擬機的宿主側出問題、也可能是一個把上面全部拖下水的共同根因：磁碟滿。這篇從網路層與宿主側的權威狀態切入，把「連不上」拆成可定位的環節。</p>
<h2 id="遠端機器突然連不上先分清是哪一段斷">遠端機器突然連不上：先分清是哪一段斷</h2>
<p>一台昨天還能 SSH 的機器今天連不上，第一步是確認「網路層通不通」，跟「SSH 服務在不在」分開。連線在 TCP 就 timeout（連 port 22 卡住沒回應），多半是網路層或機器沒在跑；連線有回應但被拒（<code>Connection refused</code>），是網路通、但那台機器上沒有服務在聽 port 22。</p>
<p>對虛擬機或同網段的機器，一個很有用的權威來源是<strong>鄰居表</strong>（IP 對 MAC 的對應）。要填起來需要對方在鏈路層有回應，所以它直接反映「對方在不在」。用 <code>ip neigh</code> 看目標 IP 的條目——優先用 <code>ip neigh</code> 而不是 <code>arp -a</code>，因為 <code>ip</code>（iproute2）在現代最小系統一定有，<code>arp</code>（net-tools）常常沒裝、跑了會 command not found 反而誤導。如果狀態是 <code>INCOMPLETE</code>（<code>arp -a</code> 顯示的是 <code>incomplete</code>），代表這個 IP 在鏈路層上根本沒有機器回應——不是 SSH 的問題，是那台機器的網路沒起來、或根本沒在跑。一個實際案例：一台虛擬機 SSH timeout，鄰居表顯示整個網段的 guest 位址全是 incomplete、只有閘道（宿主那側的橋接介面）是好的——這就定位到「宿主的橋沒問題，但橋的另一頭沒有 VM 在講話」，方向立刻從「調 SSH」轉到「去看 VM 的網路或開機狀態」。</p>
<p>定位到「機器在跑但網路沒起來」後，去那台機器的主控台（不是 SSH，SSH 正是連不上的東西）確認：<code>ip -brief a</code> 看有沒有拿到 IP、<code>systemctl status &lt;網路服務&gt;</code>（<code>dhcpcd</code> / <code>systemd-networkd</code>）看網路服務起了沒，需要時 <code>sudo systemctl restart &lt;網路服務&gt;</code> 重拉。IP 回來、鄰居表的條目從 incomplete 變成有 MAC，就通了。</p>
<p>還有一個常見誤區是 IP 變了。SSH 的別名、金鑰、<code>known_hosts</code> 都綁在特定機器身分上；換機器 / 重裝 / DHCP 重配後 IP 或 host key 變了，用舊別名會連錯或被 host key 檢查擋。這條的判讀與修法（<code>ssh user@新IP</code> 直連、<code>ssh-keygen -R</code>）見 <a href="../../install/ssh-keyless-bootstrap/">外部連入與無 key 的 bootstrap 路徑</a>。</p>
<h2 id="網路通但域名解析不了">網路通、但域名解析不了</h2>
<p>有一種故障看起來像「網路壞了」，其實是 DNS 解析斷了：能連 IP、卻連不上任何用域名的東西——<code>ping 8.8.8.8</code> 通、但 <code>ping google.com</code>、<code>pacman -Sy</code>、<code>curl https://...</code> 全失敗。判讀要跟前面「網路沒起來」分開，因為網路層是通的，斷的是「域名 → IP」這一步。權威檢查：<code>ping &lt;IP&gt;</code> 通而 <code>ping &lt;域名&gt;</code> 不通、或 <code>getent hosts &lt;域名&gt;</code>（<code>resolvectl query &lt;域名&gt;</code> 若有 systemd-resolved）解不出位址，就定位到 DNS。常見成因是 <code>/etc/resolv.conf</code> 沒有可用的 nameserver（新裝或網路重設後沒填），或負責 DNS 的服務沒起來。修：確認 <code>/etc/resolv.conf</code> 有一行 <code>nameserver</code>（如 <code>nameserver 1.1.1.1</code>）、<code>systemctl status systemd-resolved</code>（若用它）。這一層在剛裝好的最小系統特別常撞到——<code>ip -brief a</code> 明明有 IP，<code>pacman</code> 或 bootstrap 卻抓不到套件，看起來像「網路好好的卻裝不了東西」，根因是 DNS 沒設。</p>
<h2 id="虛擬機開不起來分清-guest-內部還是宿主側">虛擬機開不起來：分清 guest 內部還是宿主側</h2>
<p>虛擬機開機失敗時，關鍵判斷是「錯誤來自 guest 內部（作業系統層）還是宿主側（虛擬化軟體 / QEMU 層）」。宿主側的錯誤訊息通常來自虛擬機軟體本身、在 guest 還沒開始開機前就跳出來，跟 guest 裡裝了什麼無關。</p>
<p>一個實例是 QEMU 報「找不到某個 ROM 檔」（例如 <code>efi-virtio.rom</code>）而拒絕啟動。第一反應可能是「檔案不見了要重裝」，但正確的第一步是<strong>去確認那個檔在不在</strong>——實際去虛擬機軟體的安裝目錄裡找（<code>find &lt;安裝目錄&gt; -name '&lt;rom名&gt;'</code>），會發現 ROM 檔明明就在。既然檔案在，「找不到」就不是缺檔，是 QEMU 執行時<strong>在它預期的路徑下找不到</strong>——成因隨宿主 OS 不同。<strong>在 macOS + UTM 宿主上</strong>，最常見的是 Gatekeeper app translocation：帶隔離屬性的 app 被搬到一個隨機唯讀路徑跑，讓 QEMU 解析資源的相對路徑失效，明明存在的檔案在那個執行路徑下就找不到。<strong>在 Linux 宿主上</strong>（沒有 translocation 這回事），同樣的「找不到 ROM」通常是缺對應套件（<code>ovmf</code> / <code>ipxe-roms</code> / <code>edk2-ovmf</code>）、libvirt XML 指的 ROM 路徑錯、或檔案權限不對——一樣先確認檔在哪、QEMU 是用哪個路徑去找。</p>
<p>另外兩個常見的「VM 起不來」故障也順手一起排除，它們不會特定產生「找不到 ROM」但常伴隨出現：上一次崩潰殘留的 helper 行程卡著（<code>pgrep -af 'qemu|&lt;虛擬機軟體名&gt;'</code> 找，沒清乾淨會佔住資源），以及宿主磁碟滿（<code>df -h</code>，啟動要寫暫存 / 狀態檔）。多數情況下，完全退出虛擬機軟體（連殘留 helper 一起清）+ 清出宿主磁碟空間 + 重新啟動，就恢復了。</p>
<p>判讀通則：<strong>虛擬機開不起來，先讀錯誤訊息判斷是 guest 還是宿主側；宿主側報「找不到某資源」而資源其實存在時，往「QEMU 是用哪個路徑找、那條路徑對不對」查（macOS 是 translocation、Linux 是缺套件 / 路徑 / 權限），再順手排除殘留行程與磁碟滿，而不是急著重裝。</strong></p>
<h2 id="磁碟滿是連鎖故障的共同根因">磁碟滿是連鎖故障的共同根因</h2>
<p>很多看起來各自獨立的故障，共同根因是磁碟滿。磁碟一滿，寫入就會失敗，而系統裡太多東西依賴寫入：SSH session 可能因為寫不了而被斷、正在跑的編譯 / 安裝會中途失敗、log 寫不進去、虛擬機狀態檔存不下導致連不上或開不起來。所以當你在短時間內撞到「連線斷了 + 某個任務失敗 + 服務怪怪的」這種一串症狀時，<code>df -h</code> 應該是很早就要做的檢查——一個廉價的檢查就可能一次解釋掉全部。</p>
<p>這裡有一個容易搞錯的點：<strong>清錯了地方</strong>。宿主跟 guest 是兩個獨立的檔案系統；虛擬機的宿主磁碟滿，跟 guest 內部磁碟滿，是兩件事。如果你 SSH 進 guest 裡 <code>df</code> 看到還有空間就以為沒事，但真正滿的是宿主的磁碟，那問題不會解決。判讀時要分清這串故障是「哪一台機器的哪個檔案系統」滿了——在宿主上 <code>df -h</code> 看宿主、在 guest 裡 <code>df -h</code> 看 guest，兩邊都要確認。清空間也要清在對的那一側。</p>
<h2 id="判讀路由">判讀路由</h2>
<ul>
<li>SSH timeout（TCP 卡住）→ 網路層或機器沒跑，查 <code>ip neigh</code>（<code>INCOMPLETE</code> = 對方沒回應）→ 去主控台看 <code>ip -brief a</code> / 網路服務。</li>
<li><code>Connection refused</code> → 網路通、但沒有服務在聽 → 去機器上確認 sshd 起了沒。</li>
<li>能 ping IP、不能用域名（<code>pacman</code> / <code>curl</code> 失敗）→ DNS 解析問題，查 <code>/etc/resolv.conf</code> 有沒有 nameserver、<code>systemd-resolved</code> 起了沒，不是網路層斷。</li>
<li>連錯 / host key 被擋 → IP 或身分變了，見 <a href="../../install/ssh-keyless-bootstrap/">外部連入與無 key 的 bootstrap 路徑</a>。</li>
<li>虛擬機開不起來、宿主側報「找不到資源」但資源在 → 主因查路徑隔離，再排除殘留行程（<code>pgrep -af 'qemu\|...'</code>）/ 磁碟。</li>
<li>一串症狀同時發生 → 早點 <code>df -h</code>，宿主與 guest 兩側都查，磁碟滿常是共同根因。</li>
</ul>
<p>連不上只是最終症狀，真正的定位靠網路表、服務狀態、資源用量這些權威來源一層層往回推——完整的判讀紀律見 <a href="../diagnosis-read-authoritative-state/">診斷心法</a>。</p>
]]></content:encoded></item><item><title>Hyprland VM 環境設定與測試矩陣</title><link>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/</guid><description>&lt;p>VM 是 Hyprland 配置的演練場——用來驗證「配置邏輯對不對」，不是用來體驗「跑起來順不順」。GPU 加速在 VM 中受限，動畫和模糊效果會嚴重降級或無法使用，但配置檔語法、keybind 設計、window rules、workspace 邏輯都能在 VM 中完整測試。&lt;/p>
&lt;h2 id="utm-on-apple-silicon-設定">UTM on Apple Silicon 設定&lt;/h2>
&lt;p>Apple Silicon Mac 用 UTM（基於 QEMU）跑 ARM64 Linux VM：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>CPU&lt;/strong>：UTM 使用 Apple Hypervisor.framework，ARM64 guest 接近原生速度&lt;/li>
&lt;li>&lt;strong>GPU&lt;/strong>：使用 &lt;code>virtio-gpu-gl-pci&lt;/code>（UTM v4.1+ 新建 Linux VM 的預設）。UTM v5.0.0+ 的 GitHub release 版支援 Venus driver（guest Mesa → host MoltenVK → Apple Metal 的 Vulkan 轉送路徑），這是目前最好的 GPU 加速方案&lt;/li>
&lt;li>&lt;strong>Linux ISO&lt;/strong>：Arch Linux ARM（archlinuxarm.org）或 Fedora aarch64&lt;/li>
&lt;li>&lt;strong>建議配置&lt;/strong>：4 CPU cores、4GB+ RAM、40GB+ disk&lt;/li>
&lt;/ul>
&lt;h3 id="utm-建-vm-的注意事項">UTM 建 VM 的注意事項&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>第一頁選 Virtualize，不是 Emulate&lt;/strong>——同架構（Apple Silicon 跑 ARM64 guest）兩條都是 QEMU，差在 Virtualize 走 hvf 硬體虛擬化（CPU 接近原生）、Emulate 走 TCG 純軟體模擬（CPU 慢一個數量級；實測 C++ 大型編譯一小時只跑 1/3）。Emulate 只在跨架構（ARM Mac 跑 x86_64 guest）才需要。判別現有 VM：guest 裡 &lt;code>lscpu&lt;/code> 的 Model name 是 &lt;code>-&lt;/code> 為直通、顯示具體型號（如 Cortex-A72）為模擬&lt;/li>
&lt;li>選 「Linux」 虛擬機類型，不是 「Other」&lt;/li>
&lt;li>Display Card 選 &lt;code>virtio-gpu-gl-pci&lt;/code>（有 3D 加速），不是 &lt;code>virtio-gpu-pci&lt;/code>（無加速）；Emulate 精靈預設給無加速的 &lt;code>virtio-gpu-pci&lt;/code>、Virtualize 精靈通常直接給對&lt;/li>
&lt;li>&lt;strong>VM 視窗可能停在序列視圖、圖形顯示是另一個視圖&lt;/strong>——Virtualize 精靈預設多附一個序列裝置，UTM 視窗開機後可能顯示的是序列 console（文字登入、guest 裡 &lt;code>who&lt;/code> 顯示登入在 &lt;code>pts/0&lt;/code>），跟 virtio-gpu 的圖形輸出是兩個獨立視圖。切換：VM 視窗工具列的顯示器下拉選單 → 選 &lt;code>Display 1 (virtio-gpu)&lt;/code>。判讀圖形裝置本身有沒有掛上看 guest 的 &lt;code>ls /dev/dri/&lt;/code>（有 &lt;code>card0&lt;/code> = 裝置在、只是視窗看錯視圖）。不想每次切就到 VM 設定移除序列裝置。compositor 要在圖形視圖那側的 VT 上啟動、序列 console 起不了 Hyprland&lt;/li>
&lt;li>如果用 App Store 版的 UTM（不含 Venus），只有基本的 virtio-gpu-gl 加速&lt;/li>
&lt;li>GitHub release 版的 UTM 支援 Venus/MoltenVK，效能更好但仍不及裸金屬&lt;/li>
&lt;li>&lt;strong>修飾鍵：Mac 的 ⌘ 對應 guest 的 &lt;code>SUPER&lt;/code>，但 macOS 會先攔截部分 ⌘ 組合&lt;/strong>——Hyprland 的 keybind 幾乎都以 &lt;code>SUPER&lt;/code>（Meta）當主修飾鍵（見 &lt;a href="../hyprland-core-config/">核心配置的修飾鍵段&lt;/a>），而 UTM 裡 Mac 的 Command ⌘ 通常就是那顆 &lt;code>SUPER&lt;/code>。問題是 macOS 自己會先吃掉某些 ⌘ 組合（⌘+Q 結束 app、⌘+Space Spotlight…），VM 收不到。判讀：&lt;code>SUPER&lt;/code> 綁定沒反應、但焦點視窗打字正常，多半是宿主層攔截、不是 Hyprland 配置錯。解法：先確認 VM 視窗有 focus；在 UTM 的鍵盤/輸入設定開「把系統快捷鍵送進 VM（capture input）」讓 ⌘ 組合進 guest。臨時繞過：需要重載配置這類動作，直接在已開的終端機下指令（如 &lt;code>source&lt;/code> / &lt;code>hyprctl reload&lt;/code>），不必卡在 ⌘ 鍵上&lt;/li>
&lt;/ul>
&lt;h2 id="vm-必要環境變數">VM 必要環境變數&lt;/h2>
&lt;p>在 Hyprland 配置裡加入以下環境變數（只在 VM 中使用，實機要移除）：&lt;/p></description><content:encoded><![CDATA[<p>VM 是 Hyprland 配置的演練場——用來驗證「配置邏輯對不對」，不是用來體驗「跑起來順不順」。GPU 加速在 VM 中受限，動畫和模糊效果會嚴重降級或無法使用，但配置檔語法、keybind 設計、window rules、workspace 邏輯都能在 VM 中完整測試。</p>
<h2 id="utm-on-apple-silicon-設定">UTM on Apple Silicon 設定</h2>
<p>Apple Silicon Mac 用 UTM（基於 QEMU）跑 ARM64 Linux VM：</p>
<ul>
<li><strong>CPU</strong>：UTM 使用 Apple Hypervisor.framework，ARM64 guest 接近原生速度</li>
<li><strong>GPU</strong>：使用 <code>virtio-gpu-gl-pci</code>（UTM v4.1+ 新建 Linux VM 的預設）。UTM v5.0.0+ 的 GitHub release 版支援 Venus driver（guest Mesa → host MoltenVK → Apple Metal 的 Vulkan 轉送路徑），這是目前最好的 GPU 加速方案</li>
<li><strong>Linux ISO</strong>：Arch Linux ARM（archlinuxarm.org）或 Fedora aarch64</li>
<li><strong>建議配置</strong>：4 CPU cores、4GB+ RAM、40GB+ disk</li>
</ul>
<h3 id="utm-建-vm-的注意事項">UTM 建 VM 的注意事項</h3>
<ul>
<li><strong>第一頁選 Virtualize，不是 Emulate</strong>——同架構（Apple Silicon 跑 ARM64 guest）兩條都是 QEMU，差在 Virtualize 走 hvf 硬體虛擬化（CPU 接近原生）、Emulate 走 TCG 純軟體模擬（CPU 慢一個數量級；實測 C++ 大型編譯一小時只跑 1/3）。Emulate 只在跨架構（ARM Mac 跑 x86_64 guest）才需要。判別現有 VM：guest 裡 <code>lscpu</code> 的 Model name 是 <code>-</code> 為直通、顯示具體型號（如 Cortex-A72）為模擬</li>
<li>選 「Linux」 虛擬機類型，不是 「Other」</li>
<li>Display Card 選 <code>virtio-gpu-gl-pci</code>（有 3D 加速），不是 <code>virtio-gpu-pci</code>（無加速）；Emulate 精靈預設給無加速的 <code>virtio-gpu-pci</code>、Virtualize 精靈通常直接給對</li>
<li><strong>VM 視窗可能停在序列視圖、圖形顯示是另一個視圖</strong>——Virtualize 精靈預設多附一個序列裝置，UTM 視窗開機後可能顯示的是序列 console（文字登入、guest 裡 <code>who</code> 顯示登入在 <code>pts/0</code>），跟 virtio-gpu 的圖形輸出是兩個獨立視圖。切換：VM 視窗工具列的顯示器下拉選單 → 選 <code>Display 1 (virtio-gpu)</code>。判讀圖形裝置本身有沒有掛上看 guest 的 <code>ls /dev/dri/</code>（有 <code>card0</code> = 裝置在、只是視窗看錯視圖）。不想每次切就到 VM 設定移除序列裝置。compositor 要在圖形視圖那側的 VT 上啟動、序列 console 起不了 Hyprland</li>
<li>如果用 App Store 版的 UTM（不含 Venus），只有基本的 virtio-gpu-gl 加速</li>
<li>GitHub release 版的 UTM 支援 Venus/MoltenVK，效能更好但仍不及裸金屬</li>
<li><strong>修飾鍵：Mac 的 ⌘ 對應 guest 的 <code>SUPER</code>，但 macOS 會先攔截部分 ⌘ 組合</strong>——Hyprland 的 keybind 幾乎都以 <code>SUPER</code>（Meta）當主修飾鍵（見 <a href="../hyprland-core-config/">核心配置的修飾鍵段</a>），而 UTM 裡 Mac 的 Command ⌘ 通常就是那顆 <code>SUPER</code>。問題是 macOS 自己會先吃掉某些 ⌘ 組合（⌘+Q 結束 app、⌘+Space Spotlight…），VM 收不到。判讀：<code>SUPER</code> 綁定沒反應、但焦點視窗打字正常，多半是宿主層攔截、不是 Hyprland 配置錯。解法：先確認 VM 視窗有 focus；在 UTM 的鍵盤/輸入設定開「把系統快捷鍵送進 VM（capture input）」讓 ⌘ 組合進 guest。臨時繞過：需要重載配置這類動作，直接在已開的終端機下指令（如 <code>source</code> / <code>hyprctl reload</code>），不必卡在 ⌘ 鍵上</li>
</ul>
<h2 id="vm-必要環境變數">VM 必要環境變數</h2>
<p>在 Hyprland 配置裡加入以下環境變數（只在 VM 中使用，實機要移除）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">-- VM-only environment variables</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="n">env</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="s2">&#34;WLR_RENDERER_ALLOW_SOFTWARE, 1&#34;</span><span class="p">,</span>  <span class="c1">-- 允許軟體渲染 fallback</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="s2">&#34;WLR_NO_HARDWARE_CURSORS, 1&#34;</span><span class="p">,</span>      <span class="c1">-- 停用硬體 cursor（VM 常見問題）</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="s2">&#34;LIBGL_ALWAYS_SOFTWARE, 1&#34;</span><span class="p">,</span>        <span class="c1">-- 強制 Mesa 軟體渲染</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>如果上述仍無法啟動（virtio-gpu vGPU passthrough 的情況）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">env</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="s2">&#34;AQ_NO_KMS_REQUIREMENT, 1&#34;</span><span class="p">,</span>       <span class="c1">-- 繞過 KMS 需求</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="s2">&#34;WLR_RENDERER, pixman&#34;</span><span class="p">,</span>            <span class="c1">-- 強制 pixman 軟體 renderer</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><blockquote>
<p><strong>[已驗證]</strong> Hyprland 0.55（Aquamarine）+ UTM virtio-gpu-gl-pci 實測：GPU 加速模式下 Hyprland 直接走 VirGL/Venus，不需要 <code>WLR_RENDERER</code> 或 <code>WLR_RENDERER_ALLOW_SOFTWARE</code>。<code>AQ_NO_KMS_REQUIREMENT</code> 仍有效。軟體渲染 fallback 路徑（<code>WLR_RENDERER=pixman</code>）未測試——有 GPU 加速時不需要走這條。</p></blockquote>
<h2 id="vm-中應該關閉的效果">VM 中應該關閉的效果</h2>
<p>軟體渲染下，視覺效果是最大的效能殺手。建議在 VM 配置中停用：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-lua" data-lang="lua"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">hl.config</span><span class="p">({</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">decoration</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="n">blur</span> <span class="o">=</span> <span class="p">{</span> <span class="n">enabled</span> <span class="o">=</span> <span class="kc">false</span> <span class="p">},</span>     <span class="c1">-- 模糊是 GPU 最重的效果</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="n">shadow</span> <span class="o">=</span> <span class="p">{</span> <span class="n">enabled</span> <span class="o">=</span> <span class="kc">false</span> <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">        <span class="n">rounding</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="n">animations</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="n">enabled</span> <span class="o">=</span> <span class="kc">false</span><span class="p">,</span>                <span class="c1">-- 或設定極簡動畫</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">})</span></span></span></code></pre></div><p>這些效果關閉後，基本的平鋪操作（切換視窗、移動 workspace、開關 app）在 VM 中應該足夠流暢。</p>
<h2 id="效能預期">效能預期</h2>
<table>
  <thead>
      <tr>
          <th>功能</th>
          <th>軟體渲染</th>
          <th>virtio-gpu-gl</th>
          <th>裸金屬（實機）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>基本平鋪操作</td>
          <td>可用</td>
          <td>順暢</td>
          <td>順暢</td>
      </tr>
      <tr>
          <td>視窗動畫</td>
          <td>卡頓明顯</td>
          <td>勉強可接受</td>
          <td>流暢</td>
      </tr>
      <tr>
          <td>模糊/透明</td>
          <td>無法使用</td>
          <td>卡頓</td>
          <td>流暢</td>
      </tr>
      <tr>
          <td>Waybar + Wofi</td>
          <td>正常</td>
          <td>正常</td>
          <td>正常</td>
      </tr>
      <tr>
          <td>多 Workspace 切換</td>
          <td>正常</td>
          <td>正常</td>
          <td>正常</td>
      </tr>
      <tr>
          <td>Firefox 瀏覽</td>
          <td>明顯變慢</td>
          <td>可用</td>
          <td>正常</td>
      </tr>
  </tbody>
</table>
<p>VM 的價值在於驗證配置邏輯，不在於評估視覺體驗。如果在 VM 裡覺得「卡」，不代表 Hyprland 本身慢——多數情況是 VM 圖形加速的限制。</p>
<h2 id="sway-作為-vm-初步驗證工具">Sway 作為 VM 初步驗證工具</h2>
<p>如果 VM 中 Hyprland 跑得太吃力，可以先用 Sway 驗證 VM 的 Wayland 圖形棧是否正常：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">sudo pacman -S sway foot
</span></span><span class="line"><span class="ln">2</span><span class="cl">sway</span></span></code></pre></div><p>Sway 比 Hyprland 輕量（基於 wlroots、沒有華麗動畫），如果 Sway 能跑，代表 VM 的 Wayland 環境是正常的，Hyprland 的問題只是效能不夠。如果連 Sway 都跑不動，要回去檢查 VM 的 GPU 設定。</p>
<h2 id="vm-vs-實機測試矩陣">VM vs 實機測試矩陣</h2>
<h3 id="vm-中可完整驗證">VM 中可完整驗證</h3>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>說明</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>配置檔語法</td>
          <td>Lua config 是否解析正確、require 拆分是否正常</td>
      </tr>
      <tr>
          <td>Keybind 設計</td>
          <td>快捷鍵邏輯、submap、modifier 組合</td>
      </tr>
      <tr>
          <td>Window rules</td>
          <td>float / workspace assignment / opacity 規則是否生效</td>
      </tr>
      <tr>
          <td>Workspace 切換</td>
          <td>workspace 編號、切換邏輯</td>
      </tr>
      <tr>
          <td>Layout 選擇</td>
          <td>dwindle vs master 的行為差異</td>
      </tr>
      <tr>
          <td>Waybar 模組配置</td>
          <td>JSON config + CSS styling 是否正確顯示</td>
      </tr>
      <tr>
          <td>Wofi/Rofi 主題</td>
          <td>啟動器的功能和外觀設定</td>
      </tr>
      <tr>
          <td>Mako 通知樣式</td>
          <td>通知的位置、配色、timeout</td>
      </tr>
      <tr>
          <td>Hyprlock 佈局</td>
          <td>鎖屏的輸入框位置和文字配置</td>
      </tr>
      <tr>
          <td>Autostart 順序</td>
          <td>exec-once 的程式是否正確啟動</td>
      </tr>
      <tr>
          <td>環境變數</td>
          <td>XDG、Qt、GTK 等環境變數是否正確設定</td>
      </tr>
      <tr>
          <td>Stow 部署</td>
          <td>dotfile repo 的 stow 是否正確建立 symlink</td>
      </tr>
      <tr>
          <td>Bootstrap script</td>
          <td>install.sh 的完整流程（安裝套件 + deploy 配置）</td>
      </tr>
      <tr>
          <td>Caelestia CLI 指令</td>
          <td><code>caelestia shell</code>、<code>caelestia scheme</code> 等指令是否可執行</td>
      </tr>
  </tbody>
</table>
<h3 id="需要實機測試">需要實機測試</h3>
<table>
  <thead>
      <tr>
          <th>項目</th>
          <th>為什麼 VM 不行</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>多螢幕配置</td>
          <td>VM 通常只有一個虛擬顯示器</td>
      </tr>
      <tr>
          <td>HiDPI / fractional scaling</td>
          <td>虛擬顯示器不模擬真實解析度行為</td>
      </tr>
      <tr>
          <td>VRR / Adaptive Sync</td>
          <td>需要支援 VRR 的真實螢幕</td>
      </tr>
      <tr>
          <td>動畫流暢度</td>
          <td>VM 的 GPU 加速不足以評估真實效能</td>
      </tr>
      <tr>
          <td>模糊效果品質</td>
          <td>軟體渲染下模糊不可用或品質差</td>
      </tr>
      <tr>
          <td>觸控板 / 手勢</td>
          <td>VM 沒有觸控板裝置</td>
      </tr>
      <tr>
          <td>媒體鍵 / 亮度鍵</td>
          <td>需要實體鍵盤上的 XF86 keycodes</td>
      </tr>
      <tr>
          <td>NVIDIA 驅動設定</td>
          <td>VM 不走 NVIDIA 驅動，所有 NVIDIA 配置無法測試</td>
      </tr>
      <tr>
          <td>Screen sharing</td>
          <td>PipeWire + portal 的完整鏈路在 VM 中測試無意義</td>
      </tr>
      <tr>
          <td>Suspend / Resume</td>
          <td>虛擬機的 suspend 行為跟實機不同</td>
      </tr>
      <tr>
          <td>硬體 cursor 渲染</td>
          <td>VM 用軟體 cursor，無法測試硬體 cursor 問題</td>
      </tr>
      <tr>
          <td>藍牙 / WiFi 整合</td>
          <td>需要實際硬體</td>
      </tr>
      <tr>
          <td>電池 / 電源管理</td>
          <td>筆電專屬功能</td>
      </tr>
      <tr>
          <td>日常使用效能</td>
          <td>只有在實機跑一段時間才能評估「能不能當主力」</td>
      </tr>
  </tbody>
</table>
<h2 id="務實的-vm-使用策略">務實的 VM 使用策略</h2>
<p>VM 階段的目標是「把配置寫好、驗證邏輯、確認 bootstrap script 能跑」，不是「體驗 Hyprland 好不好用」。具體做法：</p>
<ol>
<li>在 VM 中完成 Arch Linux 安裝 + Hyprland 套件安裝（怎麼把那台 Linux 從 ISO 裝起來、安裝程式選項怎麼判讀、裝完怎麼驗工具與連入，見 <a href="/blog/linux/install/" data-link-title="Linux 安裝與機器初始化" data-link-desc="在 VM 或新機器從零裝好 Linux、判讀安裝程式選項、驗證最小系統、或要從外部連入跑 bootstrap 時回來讀">Linux 安裝與機器初始化</a>）</li>
<li>關閉所有視覺效果（blur / animation / shadow）</li>
<li>寫好完整的 Hyprland 配置（keybind / rules / workspace / autostart）</li>
<li>寫好 waybar / wofi / mako 配置</li>
<li>測試 stow 部署流程（從 dotfile repo clone → stow → 配置生效）</li>
<li>測試 bootstrap script（install.sh 從零到完整桌面）</li>
<li>把驗證過的配置 commit 進 dotfile repo</li>
</ol>
<p>到實機時，clone dotfile repo → 跑 install.sh → 補上硬體相關設定（monitor、GPU 驅動、觸控板）→ 打開視覺效果。VM 階段的工作在實機上幾乎不用重做。</p>
]]></content:encoded></item></channel></rss>