<?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>Install on Tarragon</title><link>https://tarrragon.github.io/blog/tags/install/</link><description>Recent content in Install 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/install/index.xml" rel="self" type="application/rss+xml"/><item><title>Linux 安裝與機器初始化</title><link>https://tarrragon.github.io/blog/linux/install/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/</guid><description>&lt;p>這個系列處理一件編號模組預設你已經完成的事：把一台機器從「空的」變成「能接收 dotfile 的」。模組零到九教你怎麼用 code 管理工作環境，但它們都假設你手上已經有一台裝好 Linux、裝了基本工具、能從外部連入的機器。這個系列補的就是那段地基——OS 怎麼裝、裝完缺什麼、怎麼連進去跑 bootstrap。&lt;/p>
&lt;p>這段地基平常被跳過，是因為多數人是在一台早就裝好的機器上開始管理 dotfile。但只要你換到全新環境——開一台 VM、租一台雲端主機、拿到一台空機器——就會直接撞上這層：安裝程式問你十幾個選項該怎麼選、裝完發現連 &lt;code>sudo&lt;/code> 都沒有、想從本機連進去卻還沒有 SSH key。這些都不在編號模組的範圍，卻是跑 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八的 bootstrap script&lt;/a> 之前必須先過的關。&lt;/p>
&lt;p>本系列的內容來自一次完整的 VM 實測：在 Apple Silicon 的 UTM 上從 archboot（Arch 的獨立網路安裝環境 ISO）裝 Arch Linux ARM、跑 dotfile 的 &lt;code>install.sh&lt;/code>、一路把 Hyprland 桌面拉起來。實測中每個卡關點都被記錄下來，這裡把它們蒸餾成可重用的判讀與決策，不綁特定發行版或虛擬化軟體。&lt;/p>
&lt;h2 id="在學習路徑中的位置">在學習路徑中的位置&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>階段&lt;/th>
 &lt;th>對應內容&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>地基（本系列）&lt;/td>
 &lt;td>OS 安裝決策、工具驗證、外部連入與 bootstrap 前置&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>為什麼管理 dotfile&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/00-dotfile-mindset/" data-link-title="模組零：Dotfile 心智模型" data-link-desc="換機器、開 VM、重灌系統時需要快速還原開發環境，或想釐清哪些配置該版控、哪些該排除時回來讀">模組零：心智模型&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>怎麼管理&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/" data-link-title="模組一：管理工具與目錄結構" data-link-desc="要把散落在家目錄的配置檔集中版控時，選 bare repo、stow 還是 chezmoi、目錄該怎麼組織">模組一到七&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>怎麼一鍵還原&lt;/td>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步與 Bootstrap&lt;/a>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/00-dotfile-mindset/setup-order-guide/" data-link-title="環境建置的操作順序" data-link-desc="第一次從零建立 Linux 或 macOS 開發環境、不確定先做什麼後做什麼時讀 — 依賴順序路線圖，每一步附對應模組連結">模組零的操作順序指引&lt;/a> 列出從 OS 安裝到桌面就緒的完整依賴鏈，但只把「安裝作業系統」標成一步。本系列是那一步的展開：安裝程式每個選項背後的取捨、裝完之後的驗證、以及連入機器的幾種路徑。&lt;/p>
&lt;h2 id="文章">文章&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>文章&lt;/th>
 &lt;th>主題&lt;/th>
 &lt;th>回答什麼問題&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="basic-operations/">安裝過程用到的基礎操作&lt;/a>&lt;/td>
 &lt;td>系列用到的基礎操作：&lt;code>su -&lt;/code>、nano 編輯、檔名/指令大小寫、shell 符號（已熟可跳過）&lt;/td>
 &lt;td>照做時撞到沒見過的基礎指令怎麼辦&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="install-option-decisions/">Linux 安裝選項判讀&lt;/a>&lt;/td>
 &lt;td>安裝程式各選項的決策方針：locale、網路、鏡像、磁碟分割、檔案系統、bootloader&lt;/td>
 &lt;td>安裝程式問我這個選項，我該根據什麼選&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="minimal-install-verify/">最小安裝後的工具驗證與補足&lt;/a>&lt;/td>
 &lt;td>最小系統缺哪些必要工具、怎麼驗證、怎麼補&lt;/td>
 &lt;td>為什麼裝完連 sudo 都沒有、bootstrap 跑不起來&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="package-and-network-troubleshooting/">安裝期套件與網路故障排除&lt;/a>&lt;/td>
 &lt;td>第一次抓套件就失敗：分「連不到（DNS/mirror）」vs「連得到但被拒（db lock/簽章/partial/404）」&lt;/td>
 &lt;td>剛裝好跑 pacman 就報錯，是網路還是套件管理器的問題&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="ssh-keyless-bootstrap/">外部連入、SSH key 與無 key 的 bootstrap 路徑&lt;/a>&lt;/td>
 &lt;td>啟用 sshd、從本機連入、設 SSH key，以及還沒有 key 時怎麼把 dotfile 弄進去&lt;/td>
 &lt;td>怎麼從舒適的本機終端機操作新機器、沒有 key 時怎麼辦&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="observable-bootstrap/">可除錯的 bootstrap：把可觀測性內建進安裝腳本&lt;/a>&lt;/td>
 &lt;td>bootstrap 失敗時怎麼留下可診斷的痕跡：log 落地、錯誤定位、狀態 dump&lt;/td>
 &lt;td>安裝腳本失敗時，為什麼我只能瞎找&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="unattended-remote-work/">讓機器跑無人值守的長任務&lt;/a>&lt;/td>
 &lt;td>無人值守執行的三個障礙與解：NOPASSWD sudo、終端機多工器、推送認證，以及 agent 權限放行的取捨&lt;/td>
 &lt;td>怎麼讓機器在我離開後自己跑完任務、把成果送回來&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="platform-divergence-map/">平台與發行版差異的判讀地圖&lt;/a>&lt;/td>
 &lt;td>差異的四層（套件管理器 / 套件名 / 存在性 / 版本節奏）、除錯前先定平台、bootstrap 分歧判準&lt;/td>
 &lt;td>跨平台的清單與腳本該怎麼切、除錯時先確認什麼&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="gui-apps-install-verify/">GUI 應用的安裝驗證&lt;/a>&lt;/td>
 &lt;td>拆包生態（本體與功能模組分離）、首跑同意對話框、播放驗證鏈、VM 硬體解碼回退&lt;/td>
 &lt;td>GUI 應用裝了打不開 / 無聲 / 不能播該查哪一層&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>機器裝好、能連入之後若出問題（連不上、終端機亂、程式行為怪），除錯與診斷自成一組，見同層的 &lt;a href="../debug/">Linux 除錯與診斷&lt;/a>。&lt;/p>
&lt;h2 id="依情境的讀法">依情境的讀法&lt;/h2>
&lt;p>主線那幾篇照「安裝 → 驗證 → 連入 → 可除錯 → 無人值守」的順序，是「從零開一台新機器、到讓它自己跑活」的完整路線，但不是每個讀者都從零開始：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>接手一台別人已裝好的機器&lt;/strong>：OS 已經在，從 &lt;a href="minimal-install-verify/">最小安裝後的工具驗證與補足&lt;/a> 切入，確認它缺不缺你流程要的工具。&lt;/li>
&lt;li>&lt;strong>雲端主機初始化&lt;/strong>：雲端主機多半已附 OS image、已有 sudo 與注入的 key，適用的是 &lt;a href="ssh-keyless-bootstrap/">外部連入、SSH key 與無 key 的 bootstrap 路徑&lt;/a> 跟 &lt;a href="observable-bootstrap/">可除錯的 bootstrap&lt;/a>，前兩篇的 ISO 安裝可略過。&lt;/li>
&lt;li>&lt;strong>bootstrap 失敗來 debug&lt;/strong>：直接讀 &lt;a href="observable-bootstrap/">可除錯的 bootstrap&lt;/a>，它也涵蓋「腳本不是你寫的、只想 debug 一次失敗」的情況。&lt;/li>
&lt;li>&lt;strong>讓機器無人值守跑活&lt;/strong>：機器已能連入操作，只想設好讓它在你離開後自己跑長任務或 agent，直接讀 &lt;a href="unattended-remote-work/">讓機器跑無人值守的長任務&lt;/a>。&lt;/li>
&lt;li>&lt;strong>遇到問題要除錯&lt;/strong>：機器已在跑但出狀況（連不上、終端機亂、程式行為怪），進 &lt;a href="../debug/">Linux 除錯與診斷&lt;/a>，從 &lt;a href="../debug/diagnosis-read-authoritative-state/">診斷心法&lt;/a> 建立判讀紀律，再依症狀分流。&lt;/li>
&lt;li>&lt;strong>裝好後想讓它自己顧&lt;/strong>：服務跑起來後，主動確認這台有沒有在監控自己的服務死活（&lt;code>systemctl show sshd -p OnFailure&lt;/code>），沒有就從最簡單的 OnFailure + ntfy 建起——遠端機器至少把 sshd 掛上，掛了就失聯。見 &lt;a href="../debug/service-failure-monitoring/">服務掛了怎麼自動知道&lt;/a>。&lt;/li>
&lt;/ul>
&lt;h2 id="跟其他模組的交叉引用">跟其他模組的交叉引用&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八：Bootstrap script 設計&lt;/a>——本系列是它的前置；bootstrap 假設套件清單完整、機器可連入，本系列補「在那之前」。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/" data-link-title="Hyprland VM 環境設定與測試矩陣" data-link-desc="要在 VM 裡測試 Hyprland 配置、或判斷某個設定該在 VM 還是實機驗證時回來讀">模組五：Hyprland VM 測試&lt;/a>——本系列的 VM 安裝是它的下游前置；裝好機器才能測 Hyprland。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/07-desktop-maintenance/log-reading-diagnostic-tools/" data-link-title="日誌判讀與診斷工具" data-link-desc="知道桌面出了問題但不確定原因時回來讀 — journalctl、dmesg、hyprctl、systemctl 的使用方式和常見 log pattern">模組七：日誌判讀與診斷工具&lt;/a>——「可除錯的 bootstrap」與它呼應：前者談怎麼產生可診斷的 log，後者談怎麼讀。&lt;/li>
&lt;li>&lt;a href="../debug/">Linux 除錯與診斷&lt;/a>——本系列裝好、連入之後的下游；出問題時的判讀紀律與情境分流。&lt;/li>
&lt;li>&lt;a href="../tools/">Linux 工具選單&lt;/a>——安裝與除錯要用的工具（CLI / 圖形桌面 / 遠端）有哪些選擇、推薦用哪些。&lt;/li>
&lt;li>&lt;a href="https://tarrragon.github.io/blog/infra/00-infra-mindset/first-day-with-cloud-account/" data-link-title="拿到雲端帳號的第一天" data-link-desc="被指派 infra 工作、拿到 AWS 或 GCP 帳號、不確定該先做什麼時讀 — 第一小時安全底線、帳號現況判讀、後續學習路線分流">Infra 心智模型：拿到雲端帳號的第一天&lt;/a>——雲端主機的機器初始化是本系列的上游情境；被指派 infra 工作、拿到一台雲端主機後，先過本系列的 OS 連入與 bootstrap 前置，再進 infra 的資源管理。&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>這個系列處理一件編號模組預設你已經完成的事：把一台機器從「空的」變成「能接收 dotfile 的」。模組零到九教你怎麼用 code 管理工作環境，但它們都假設你手上已經有一台裝好 Linux、裝了基本工具、能從外部連入的機器。這個系列補的就是那段地基——OS 怎麼裝、裝完缺什麼、怎麼連進去跑 bootstrap。</p>
<p>這段地基平常被跳過，是因為多數人是在一台早就裝好的機器上開始管理 dotfile。但只要你換到全新環境——開一台 VM、租一台雲端主機、拿到一台空機器——就會直接撞上這層：安裝程式問你十幾個選項該怎麼選、裝完發現連 <code>sudo</code> 都沒有、想從本機連進去卻還沒有 SSH key。這些都不在編號模組的範圍，卻是跑 <a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八的 bootstrap script</a> 之前必須先過的關。</p>
<p>本系列的內容來自一次完整的 VM 實測：在 Apple Silicon 的 UTM 上從 archboot（Arch 的獨立網路安裝環境 ISO）裝 Arch Linux ARM、跑 dotfile 的 <code>install.sh</code>、一路把 Hyprland 桌面拉起來。實測中每個卡關點都被記錄下來，這裡把它們蒸餾成可重用的判讀與決策，不綁特定發行版或虛擬化軟體。</p>
<h2 id="在學習路徑中的位置">在學習路徑中的位置</h2>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>對應內容</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>地基（本系列）</td>
          <td>OS 安裝決策、工具驗證、外部連入與 bootstrap 前置</td>
      </tr>
      <tr>
          <td>為什麼管理 dotfile</td>
          <td><a href="/blog/linux/dotfile/00-dotfile-mindset/" data-link-title="模組零：Dotfile 心智模型" data-link-desc="換機器、開 VM、重灌系統時需要快速還原開發環境，或想釐清哪些配置該版控、哪些該排除時回來讀">模組零：心智模型</a></td>
      </tr>
      <tr>
          <td>怎麼管理</td>
          <td><a href="/blog/linux/dotfile/01-dotfile-management/" data-link-title="模組一：管理工具與目錄結構" data-link-desc="要把散落在家目錄的配置檔集中版控時，選 bare repo、stow 還是 chezmoi、目錄該怎麼組織">模組一到七</a></td>
      </tr>
      <tr>
          <td>怎麼一鍵還原</td>
          <td><a href="/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步與 Bootstrap</a></td>
      </tr>
  </tbody>
</table>
<p><a href="/blog/linux/dotfile/00-dotfile-mindset/setup-order-guide/" data-link-title="環境建置的操作順序" data-link-desc="第一次從零建立 Linux 或 macOS 開發環境、不確定先做什麼後做什麼時讀 — 依賴順序路線圖，每一步附對應模組連結">模組零的操作順序指引</a> 列出從 OS 安裝到桌面就緒的完整依賴鏈，但只把「安裝作業系統」標成一步。本系列是那一步的展開：安裝程式每個選項背後的取捨、裝完之後的驗證、以及連入機器的幾種路徑。</p>
<h2 id="文章">文章</h2>
<table>
  <thead>
      <tr>
          <th>文章</th>
          <th>主題</th>
          <th>回答什麼問題</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="basic-operations/">安裝過程用到的基礎操作</a></td>
          <td>系列用到的基礎操作：<code>su -</code>、nano 編輯、檔名/指令大小寫、shell 符號（已熟可跳過）</td>
          <td>照做時撞到沒見過的基礎指令怎麼辦</td>
      </tr>
      <tr>
          <td><a href="install-option-decisions/">Linux 安裝選項判讀</a></td>
          <td>安裝程式各選項的決策方針：locale、網路、鏡像、磁碟分割、檔案系統、bootloader</td>
          <td>安裝程式問我這個選項，我該根據什麼選</td>
      </tr>
      <tr>
          <td><a href="minimal-install-verify/">最小安裝後的工具驗證與補足</a></td>
          <td>最小系統缺哪些必要工具、怎麼驗證、怎麼補</td>
          <td>為什麼裝完連 sudo 都沒有、bootstrap 跑不起來</td>
      </tr>
      <tr>
          <td><a href="package-and-network-troubleshooting/">安裝期套件與網路故障排除</a></td>
          <td>第一次抓套件就失敗：分「連不到（DNS/mirror）」vs「連得到但被拒（db lock/簽章/partial/404）」</td>
          <td>剛裝好跑 pacman 就報錯，是網路還是套件管理器的問題</td>
      </tr>
      <tr>
          <td><a href="ssh-keyless-bootstrap/">外部連入、SSH key 與無 key 的 bootstrap 路徑</a></td>
          <td>啟用 sshd、從本機連入、設 SSH key，以及還沒有 key 時怎麼把 dotfile 弄進去</td>
          <td>怎麼從舒適的本機終端機操作新機器、沒有 key 時怎麼辦</td>
      </tr>
      <tr>
          <td><a href="observable-bootstrap/">可除錯的 bootstrap：把可觀測性內建進安裝腳本</a></td>
          <td>bootstrap 失敗時怎麼留下可診斷的痕跡：log 落地、錯誤定位、狀態 dump</td>
          <td>安裝腳本失敗時，為什麼我只能瞎找</td>
      </tr>
      <tr>
          <td><a href="unattended-remote-work/">讓機器跑無人值守的長任務</a></td>
          <td>無人值守執行的三個障礙與解：NOPASSWD sudo、終端機多工器、推送認證，以及 agent 權限放行的取捨</td>
          <td>怎麼讓機器在我離開後自己跑完任務、把成果送回來</td>
      </tr>
      <tr>
          <td><a href="platform-divergence-map/">平台與發行版差異的判讀地圖</a></td>
          <td>差異的四層（套件管理器 / 套件名 / 存在性 / 版本節奏）、除錯前先定平台、bootstrap 分歧判準</td>
          <td>跨平台的清單與腳本該怎麼切、除錯時先確認什麼</td>
      </tr>
      <tr>
          <td><a href="gui-apps-install-verify/">GUI 應用的安裝驗證</a></td>
          <td>拆包生態（本體與功能模組分離）、首跑同意對話框、播放驗證鏈、VM 硬體解碼回退</td>
          <td>GUI 應用裝了打不開 / 無聲 / 不能播該查哪一層</td>
      </tr>
  </tbody>
</table>
<p>機器裝好、能連入之後若出問題（連不上、終端機亂、程式行為怪），除錯與診斷自成一組，見同層的 <a href="../debug/">Linux 除錯與診斷</a>。</p>
<h2 id="依情境的讀法">依情境的讀法</h2>
<p>主線那幾篇照「安裝 → 驗證 → 連入 → 可除錯 → 無人值守」的順序，是「從零開一台新機器、到讓它自己跑活」的完整路線，但不是每個讀者都從零開始：</p>
<ul>
<li><strong>接手一台別人已裝好的機器</strong>：OS 已經在，從 <a href="minimal-install-verify/">最小安裝後的工具驗證與補足</a> 切入，確認它缺不缺你流程要的工具。</li>
<li><strong>雲端主機初始化</strong>：雲端主機多半已附 OS image、已有 sudo 與注入的 key，適用的是 <a href="ssh-keyless-bootstrap/">外部連入、SSH key 與無 key 的 bootstrap 路徑</a> 跟 <a href="observable-bootstrap/">可除錯的 bootstrap</a>，前兩篇的 ISO 安裝可略過。</li>
<li><strong>bootstrap 失敗來 debug</strong>：直接讀 <a href="observable-bootstrap/">可除錯的 bootstrap</a>，它也涵蓋「腳本不是你寫的、只想 debug 一次失敗」的情況。</li>
<li><strong>讓機器無人值守跑活</strong>：機器已能連入操作，只想設好讓它在你離開後自己跑長任務或 agent，直接讀 <a href="unattended-remote-work/">讓機器跑無人值守的長任務</a>。</li>
<li><strong>遇到問題要除錯</strong>：機器已在跑但出狀況（連不上、終端機亂、程式行為怪），進 <a href="../debug/">Linux 除錯與診斷</a>，從 <a href="../debug/diagnosis-read-authoritative-state/">診斷心法</a> 建立判讀紀律，再依症狀分流。</li>
<li><strong>裝好後想讓它自己顧</strong>：服務跑起來後，主動確認這台有沒有在監控自己的服務死活（<code>systemctl show sshd -p OnFailure</code>），沒有就從最簡單的 OnFailure + ntfy 建起——遠端機器至少把 sshd 掛上，掛了就失聯。見 <a href="../debug/service-failure-monitoring/">服務掛了怎麼自動知道</a>。</li>
</ul>
<h2 id="跟其他模組的交叉引用">跟其他模組的交叉引用</h2>
<ul>
<li><a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八：Bootstrap script 設計</a>——本系列是它的前置；bootstrap 假設套件清單完整、機器可連入，本系列補「在那之前」。</li>
<li><a href="/blog/linux/dotfile/05-hyprland-config/hyprland-vm-setup/" data-link-title="Hyprland VM 環境設定與測試矩陣" data-link-desc="要在 VM 裡測試 Hyprland 配置、或判斷某個設定該在 VM 還是實機驗證時回來讀">模組五：Hyprland VM 測試</a>——本系列的 VM 安裝是它的下游前置；裝好機器才能測 Hyprland。</li>
<li><a href="/blog/linux/dotfile/07-desktop-maintenance/log-reading-diagnostic-tools/" data-link-title="日誌判讀與診斷工具" data-link-desc="知道桌面出了問題但不確定原因時回來讀 — journalctl、dmesg、hyprctl、systemctl 的使用方式和常見 log pattern">模組七：日誌判讀與診斷工具</a>——「可除錯的 bootstrap」與它呼應：前者談怎麼產生可診斷的 log，後者談怎麼讀。</li>
<li><a href="../debug/">Linux 除錯與診斷</a>——本系列裝好、連入之後的下游；出問題時的判讀紀律與情境分流。</li>
<li><a href="../tools/">Linux 工具選單</a>——安裝與除錯要用的工具（CLI / 圖形桌面 / 遠端）有哪些選擇、推薦用哪些。</li>
<li><a href="/blog/infra/00-infra-mindset/first-day-with-cloud-account/" data-link-title="拿到雲端帳號的第一天" data-link-desc="被指派 infra 工作、拿到 AWS 或 GCP 帳號、不確定該先做什麼時讀 — 第一小時安全底線、帳號現況判讀、後續學習路線分流">Infra 心智模型：拿到雲端帳號的第一天</a>——雲端主機的機器初始化是本系列的上游情境；被指派 infra 工作、拿到一台雲端主機後，先過本系列的 OS 連入與 bootstrap 前置，再進 infra 的資源管理。</li>
</ul>
]]></content:encoded></item><item><title>Linux 安裝選項判讀</title><link>https://tarrragon.github.io/blog/linux/install/install-option-decisions/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/install-option-decisions/</guid><description>&lt;p>Linux 安裝程式的每個選項都是一個會往後傳遞代價的決策。選錯的後果不會在當下浮現，而是在重開機進不了系統、磁碟某個分區先爆掉、或裝好的機器一重開就斷網時才出現。判斷一個選項該怎麼選，靠的是同一個問題：這台機器是用來幹嘛的。一台用完即丟的測試 VM、一台跑三年的主力機、一台對外服務的伺服器，同一個選項的正確答案可能完全不同。&lt;/p>
&lt;p>這篇給每個關鍵選項一條判斷軸，而不是一份「照著點」的步驟。底下用一次具體的安裝當作貫穿例子：在 Apple Silicon 的 UTM 上用 archboot ISO 裝 Arch Linux ARM，目標是一台演練 dotfile 部署的測試 VM。例子是具體的，但判斷軸跨發行版通用——locale、分割、bootloader 這些抉擇在多數 Linux 安裝程式裡都會以類似形式出現。&lt;/p>
&lt;p>怎麼建立 VM、燒錄並開機到安裝程式，是跟環境綁定的前置——UTM、VirtualBox、實體機各不相同——不在這條判讀軸的範圍；這篇從「安裝程式已經跑起來、開始問你選項」接手，給的是每個選項的判斷軸，不逐頁帶某個安裝程式的選單怎麼點。底下的指令與選單名稱以 archboot / Arch 呈現，換 Ubuntu（Subiquity 安裝程式）或 Fedora 時，選項的判斷軸一樣成立，但選單長相、套件組名稱、指令會不同。&lt;/p>
&lt;h2 id="系統語系與時間">系統語系與時間&lt;/h2>
&lt;p>系統語系決定的是錯誤訊息、log、系統工具輸出用哪種語言，不是你日常打字的語言。這兩件事容易混為一談。日常輸入中文是桌面層的字型與輸入法問題，跟系統 locale 無關；系統 locale 影響的是當某個服務崩潰、你在 &lt;code>journalctl&lt;/code> 裡讀它吐出來的那行訊息時，那行字是英文還是被翻譯過。&lt;/p>
&lt;p>把系統 locale 留在 &lt;code>en_US.UTF-8&lt;/code> 的理由是可搜尋性。當你把一段錯誤訊息貼到搜尋引擎或問別人，英文訊息能對上絕大多數的文件、issue、Stack Overflow 答案；翻譯過的訊息往往一個結果都搜不到。這條判斷軸對伺服器、開發機、任何你預期會除錯的機器都成立。會選非英文 locale 的情境通常是給終端使用者的桌面，且該使用者不除錯——那是另一種機器。&lt;/p>
&lt;p>時區的選擇影響 log 的時間戳跟排程任務的觸發時刻，挑你所在地即可。另一個相關的決策是「硬體時鐘存 UTC 還是本地時間」：選 UTC。Linux 慣例是硬體時鐘存 UTC、顯示時再換算成時區，這樣跨時區搬機器、或 NTP 校時都不會錯亂。會需要存本地時間的唯一常見情境是跟 Windows 雙開——Windows 預設把硬體時鐘當本地時間——而 VM 或純 Linux 機器沒有這個包袱。&lt;/p>
&lt;h2 id="網路">網路&lt;/h2>
&lt;p>安裝階段的網路設定要回答兩個層次：當下能不能連、以及這份設定會不會帶進裝好的系統。第一層通常很直覺——選到對的網卡、用 DHCP 讓它自動拿 IP。虛擬機的 NAT 網路會自動發 IP，所以選 DHCP、不要手動設 static，省去算網段的麻煩。&lt;/p>
&lt;p>第二層是真正會咬人的地方：安裝程式裡設好的網路，不保證會出現在重開機後的系統裡。這是 VM 裝 Linux 常見的斷網點——安裝時明明能上網裝套件，重開機後卻連不出去，因為安裝環境的網路設定沒被複製到目標系統。判讀方式是裝好首次開機後立刻驗證：看網卡有沒有拿到 IP、能不能解析一個域名。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">ip -brief a &lt;span class="c1"># 網卡有沒有 IP、狀態是不是 UP&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">ping -c &lt;span class="m">3&lt;/span> archlinux.org &lt;span class="c1"># 解析成功就證明對外連線 + DNS 都通&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>DNS 能把域名解析成 IP，本身就證明對外連線是通的（DNS 查詢就是一次網路往返），所以這條 &lt;code>ping&lt;/code> 即使對方不回 ICMP 也已經給了答案。在前述的 archboot 例子裡，網路設定確實有被複製進目標系統並由 systemd-networkd 接手，重開機後免再手動設——但這是該安裝程式的行為，不能假設每個安裝程式都這樣。把「首次開機驗網路」當成固定動作，比預設它一定會通安全。&lt;/p>
&lt;h2 id="套件鏡像">套件鏡像&lt;/h2>
&lt;p>鏡像源決定你從哪裡下載套件，挑地理上接近的那個。基礎系統加上一套桌面動輒上 GB，選對岸的鏡像跟選同城的鏡像，下載時間差好幾倍。安裝程式給的鏡像清單通常按國家排，往下捲找你所在地區的；找不到完全同國的，就退而求其次選同區域、且穩定的大型鏡像。&lt;/p>
&lt;p>這個選擇的另一個作用是順帶確認你裝的是哪個發行版分支。前述例子的鏡像清單全是 &lt;code>archlinuxarm.org&lt;/code>，這證實了 archboot 的 aarch64 ISO 裝出來的是 Arch Linux ARM（ARM 移植版），而不是 x86 的 Arch——同一條安裝路徑產出的是哪個分支，鏡像來源會洩漏給你看。&lt;/p>
&lt;h2 id="磁碟分割">磁碟分割&lt;/h2>
&lt;p>磁碟分割是整個安裝裡選項最多、也最不可逆的一段，但判斷軸只有一條：這台機器需不需要在分區層面做隔離。需要隔離的情境——多系統共存、加密、資料與系統分離以便重灌不丟資料——每多一個，分割就多一層結構。不需要的情境，多切一刀都只是增加「一邊爆一邊空」的風險。下面逐項拆解，但它們服務的是同一個判斷。&lt;/p>
&lt;h3 id="自動分割-vs-手動分割">自動分割 vs 手動分割&lt;/h3>
&lt;p>自動分割（清空整碟、安裝程式幫你建標準佈局）適用於整碟專屬、沒有要保留任何既有資料的機器。測試 VM 的磁碟是全新的、整碟給這個系統用，自動分割沒有任何代價，還省去手動算 EFI 大小、root 大小、對齊、格式化、掛載這一連串容易錯的步驟。&lt;/p>
&lt;p>手動分割的價值在你需要非標準佈局時才浮現：多系統共用某個分區、要留一塊不格式化的資料區、要套 LVM 或 LUKS。這些是真實主力機與伺服器會遇到的需求，但對一台「目標是驗證 dotfile 部署」的 VM 是純雜訊——它們屬於另一個主題，不該混進這次的安裝。判讀訊號很簡單：你說得出一個具體的隔離需求，才手動分割；說不出來，自動分割就是對的。&lt;/p>
&lt;h3 id="分區識別方式partuuid">分區識別方式（PARTUUID）&lt;/h3>
&lt;p>分區識別方式決定 &lt;code>fstab&lt;/code>（開機時決定哪個分區掛到哪的設定檔）跟 bootloader 怎麼指涉每個分區，在 GPT（現代 UEFI 機器的分區表格式）磁碟上選 PARTUUID。這個選擇的後果是「重開機後系統找不找得到自己的分區」。PARTUUID 綁在分區本身、跨重開機穩定，而且重新格式化檔案系統也不會變；相對地，檔案系統層級的 UUID 一重格就變，會讓 &lt;code>fstab&lt;/code> 失效，而 &lt;code>/dev/vda1&lt;/code> 那種 kernel 名稱會隨偵測順序浮動，最不穩。穩定性的排序是 PARTUUID 優於 FSUUID 優於 kernel 名稱，GPT 磁碟用最穩的那個（這三種識別方式的細節見 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/partition-identification/" data-link-title="分區識別（PARTUUID / FSUUID）" data-link-desc="在 fstab 或 bootloader 設定要指定一個分區、不確定該用 PARTUUID、UUID 還是 /dev/sda1、或重格式化後系統開不了機時讀 — 分區的穩定識別方式">分區識別卡&lt;/a>）。&lt;/p>
&lt;h3 id="efi-分區的掛載點與大小">EFI 分區的掛載點與大小&lt;/h3>
&lt;p>EFI 系統分區（ESP）放開機載入器與 kernel，掛載點的選擇取決於這台機器是不是單一作業系統。把 ESP 掛在 &lt;code>/boot&lt;/code>（單系統佈局）讓 kernel 跟開機檔住在同一個分區、維護最單純；把 ESP 掛在 &lt;code>/efi&lt;/code>、kernel 另放（多系統佈局）是為了多個 OS 共用同一個 ESP 才需要的結構。單系統的機器選多系統佈局，只是憑空多一層目錄。&lt;/p>
&lt;p>ESP 大小在單系統佈局下要算進 kernel 與 &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/knowledge-cards/initramfs/" data-link-title="initramfs" data-link-desc="看到 ESP 大小要算進 initramfs、或開機卡在掛載 root 之前、不知道 initramfs 是什麼時讀 — 開機初期掛真 root 之前的臨時根檔系統">initramfs&lt;/a>（開機初期把真正的 root 掛起來之前、用來載入驅動的小型臨時根檔系統）。一個 kernel 加上它的 initramfs（含 fallback）大約一兩百 MB，再加上 FAT32 ESP 約 260 MiB 的實務下限，512 MiB 是在下限之上留餘裕。會需要更大的情境是你要同時保留多個 kernel 版本——但單 kernel 的 VM 用不到，給太大只是浪費。&lt;/p></description><content:encoded><![CDATA[<p>Linux 安裝程式的每個選項都是一個會往後傳遞代價的決策。選錯的後果不會在當下浮現，而是在重開機進不了系統、磁碟某個分區先爆掉、或裝好的機器一重開就斷網時才出現。判斷一個選項該怎麼選，靠的是同一個問題：這台機器是用來幹嘛的。一台用完即丟的測試 VM、一台跑三年的主力機、一台對外服務的伺服器，同一個選項的正確答案可能完全不同。</p>
<p>這篇給每個關鍵選項一條判斷軸，而不是一份「照著點」的步驟。底下用一次具體的安裝當作貫穿例子：在 Apple Silicon 的 UTM 上用 archboot ISO 裝 Arch Linux ARM，目標是一台演練 dotfile 部署的測試 VM。例子是具體的，但判斷軸跨發行版通用——locale、分割、bootloader 這些抉擇在多數 Linux 安裝程式裡都會以類似形式出現。</p>
<p>怎麼建立 VM、燒錄並開機到安裝程式，是跟環境綁定的前置——UTM、VirtualBox、實體機各不相同——不在這條判讀軸的範圍；這篇從「安裝程式已經跑起來、開始問你選項」接手，給的是每個選項的判斷軸，不逐頁帶某個安裝程式的選單怎麼點。底下的指令與選單名稱以 archboot / Arch 呈現，換 Ubuntu（Subiquity 安裝程式）或 Fedora 時，選項的判斷軸一樣成立，但選單長相、套件組名稱、指令會不同。</p>
<h2 id="系統語系與時間">系統語系與時間</h2>
<p>系統語系決定的是錯誤訊息、log、系統工具輸出用哪種語言，不是你日常打字的語言。這兩件事容易混為一談。日常輸入中文是桌面層的字型與輸入法問題，跟系統 locale 無關；系統 locale 影響的是當某個服務崩潰、你在 <code>journalctl</code> 裡讀它吐出來的那行訊息時，那行字是英文還是被翻譯過。</p>
<p>把系統 locale 留在 <code>en_US.UTF-8</code> 的理由是可搜尋性。當你把一段錯誤訊息貼到搜尋引擎或問別人，英文訊息能對上絕大多數的文件、issue、Stack Overflow 答案；翻譯過的訊息往往一個結果都搜不到。這條判斷軸對伺服器、開發機、任何你預期會除錯的機器都成立。會選非英文 locale 的情境通常是給終端使用者的桌面，且該使用者不除錯——那是另一種機器。</p>
<p>時區的選擇影響 log 的時間戳跟排程任務的觸發時刻，挑你所在地即可。另一個相關的決策是「硬體時鐘存 UTC 還是本地時間」：選 UTC。Linux 慣例是硬體時鐘存 UTC、顯示時再換算成時區，這樣跨時區搬機器、或 NTP 校時都不會錯亂。會需要存本地時間的唯一常見情境是跟 Windows 雙開——Windows 預設把硬體時鐘當本地時間——而 VM 或純 Linux 機器沒有這個包袱。</p>
<h2 id="網路">網路</h2>
<p>安裝階段的網路設定要回答兩個層次：當下能不能連、以及這份設定會不會帶進裝好的系統。第一層通常很直覺——選到對的網卡、用 DHCP 讓它自動拿 IP。虛擬機的 NAT 網路會自動發 IP，所以選 DHCP、不要手動設 static，省去算網段的麻煩。</p>
<p>第二層是真正會咬人的地方：安裝程式裡設好的網路，不保證會出現在重開機後的系統裡。這是 VM 裝 Linux 常見的斷網點——安裝時明明能上網裝套件，重開機後卻連不出去，因為安裝環境的網路設定沒被複製到目標系統。判讀方式是裝好首次開機後立刻驗證：看網卡有沒有拿到 IP、能不能解析一個域名。</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">ip -brief a          <span class="c1"># 網卡有沒有 IP、狀態是不是 UP</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">ping -c <span class="m">3</span> archlinux.org   <span class="c1"># 解析成功就證明對外連線 + DNS 都通</span></span></span></code></pre></div><p>DNS 能把域名解析成 IP，本身就證明對外連線是通的（DNS 查詢就是一次網路往返），所以這條 <code>ping</code> 即使對方不回 ICMP 也已經給了答案。在前述的 archboot 例子裡，網路設定確實有被複製進目標系統並由 systemd-networkd 接手，重開機後免再手動設——但這是該安裝程式的行為，不能假設每個安裝程式都這樣。把「首次開機驗網路」當成固定動作，比預設它一定會通安全。</p>
<h2 id="套件鏡像">套件鏡像</h2>
<p>鏡像源決定你從哪裡下載套件，挑地理上接近的那個。基礎系統加上一套桌面動輒上 GB，選對岸的鏡像跟選同城的鏡像，下載時間差好幾倍。安裝程式給的鏡像清單通常按國家排，往下捲找你所在地區的；找不到完全同國的，就退而求其次選同區域、且穩定的大型鏡像。</p>
<p>這個選擇的另一個作用是順帶確認你裝的是哪個發行版分支。前述例子的鏡像清單全是 <code>archlinuxarm.org</code>，這證實了 archboot 的 aarch64 ISO 裝出來的是 Arch Linux ARM（ARM 移植版），而不是 x86 的 Arch——同一條安裝路徑產出的是哪個分支，鏡像來源會洩漏給你看。</p>
<h2 id="磁碟分割">磁碟分割</h2>
<p>磁碟分割是整個安裝裡選項最多、也最不可逆的一段，但判斷軸只有一條：這台機器需不需要在分區層面做隔離。需要隔離的情境——多系統共存、加密、資料與系統分離以便重灌不丟資料——每多一個，分割就多一層結構。不需要的情境，多切一刀都只是增加「一邊爆一邊空」的風險。下面逐項拆解，但它們服務的是同一個判斷。</p>
<h3 id="自動分割-vs-手動分割">自動分割 vs 手動分割</h3>
<p>自動分割（清空整碟、安裝程式幫你建標準佈局）適用於整碟專屬、沒有要保留任何既有資料的機器。測試 VM 的磁碟是全新的、整碟給這個系統用，自動分割沒有任何代價，還省去手動算 EFI 大小、root 大小、對齊、格式化、掛載這一連串容易錯的步驟。</p>
<p>手動分割的價值在你需要非標準佈局時才浮現：多系統共用某個分區、要留一塊不格式化的資料區、要套 LVM 或 LUKS。這些是真實主力機與伺服器會遇到的需求，但對一台「目標是驗證 dotfile 部署」的 VM 是純雜訊——它們屬於另一個主題，不該混進這次的安裝。判讀訊號很簡單：你說得出一個具體的隔離需求，才手動分割；說不出來，自動分割就是對的。</p>
<h3 id="分區識別方式partuuid">分區識別方式（PARTUUID）</h3>
<p>分區識別方式決定 <code>fstab</code>（開機時決定哪個分區掛到哪的設定檔）跟 bootloader 怎麼指涉每個分區，在 GPT（現代 UEFI 機器的分區表格式）磁碟上選 PARTUUID。這個選擇的後果是「重開機後系統找不找得到自己的分區」。PARTUUID 綁在分區本身、跨重開機穩定，而且重新格式化檔案系統也不會變；相對地，檔案系統層級的 UUID 一重格就變，會讓 <code>fstab</code> 失效，而 <code>/dev/vda1</code> 那種 kernel 名稱會隨偵測順序浮動，最不穩。穩定性的排序是 PARTUUID 優於 FSUUID 優於 kernel 名稱，GPT 磁碟用最穩的那個（這三種識別方式的細節見 <a href="/blog/linux/dotfile/knowledge-cards/partition-identification/" data-link-title="分區識別（PARTUUID / FSUUID）" data-link-desc="在 fstab 或 bootloader 設定要指定一個分區、不確定該用 PARTUUID、UUID 還是 /dev/sda1、或重格式化後系統開不了機時讀 — 分區的穩定識別方式">分區識別卡</a>）。</p>
<h3 id="efi-分區的掛載點與大小">EFI 分區的掛載點與大小</h3>
<p>EFI 系統分區（ESP）放開機載入器與 kernel，掛載點的選擇取決於這台機器是不是單一作業系統。把 ESP 掛在 <code>/boot</code>（單系統佈局）讓 kernel 跟開機檔住在同一個分區、維護最單純；把 ESP 掛在 <code>/efi</code>、kernel 另放（多系統佈局）是為了多個 OS 共用同一個 ESP 才需要的結構。單系統的機器選多系統佈局，只是憑空多一層目錄。</p>
<p>ESP 大小在單系統佈局下要算進 kernel 與 <a href="/blog/linux/dotfile/knowledge-cards/initramfs/" data-link-title="initramfs" data-link-desc="看到 ESP 大小要算進 initramfs、或開機卡在掛載 root 之前、不知道 initramfs 是什麼時讀 — 開機初期掛真 root 之前的臨時根檔系統">initramfs</a>（開機初期把真正的 root 掛起來之前、用來載入驅動的小型臨時根檔系統）。一個 kernel 加上它的 initramfs（含 fallback）大約一兩百 MB，再加上 FAT32 ESP 約 260 MiB 的實務下限，512 MiB 是在下限之上留餘裕。會需要更大的情境是你要同時保留多個 kernel 版本——但單 kernel 的 VM 用不到，給太大只是浪費。</p>
<h3 id="swap">Swap</h3>
<p>Swap 是記憶體不足時的安全墊，大小取決於這台機器的記憶體壓力型態，不是一個固定公式。對一台只有 4 GB RAM、且要在上面從原始碼編譯套件的 VM，編譯瞬間的記憶體尖峰很容易把實體記憶體吃爆、觸發 OOM 把進程殺掉。給 2 GB swap 當緩衝，擋住這種尖峰、避免安裝跑到一半被中斷。</p>
<p>swap 分區的磁碟成本不是一次付清的。<code>mkswap</code> 只寫一個 header，實際沒被換出的頁不會佔用宿主磁碟空間（在稀疏配置的虛擬磁碟上尤其明顯），用到才寫。所以「為了保險多給一點 swap」的代價，比直覺以為的小。判讀軸是看工作負載：會編譯、會跑吃記憶體的服務、RAM 又緊，就給足 swap；純文書、RAM 寬裕，小一點或不給都行。</p>
<p>swap 還有形態的選擇，這裡用分區 swap 是因為在安裝程式階段一併切好最省事，不代表它比另兩種好。swapfile（一個檔案，事後可隨時調大小或移除）避開了「分割最不可逆」的痛點；zram（壓縮記憶體 swap，不碰磁碟）對低 RAM 加編譯尖峰正是設計情境，現代發行版很多預設用它。換句話說，2 GB 這個量是看編譯尖峰定的，而「切成分區」只是配合安裝當下一次到位——若你跳過安裝期的 swap、事後用 swapfile 或 zram 補，是等價的可逆路徑。</p>
<h3 id="檔案系統">檔案系統</h3>
<p>檔案系統的選擇是在「簡單可靠」與「進階功能」之間取捨，預設往簡單那邊靠。<code>ext4</code> 簡單、穩、在各平台行為一致、修復工具成熟，對一台只要求「可靠地存取檔案」的機器是零驚喜的選擇。<code>btrfs</code> 提供快照、subvolume、透明壓縮，但代價是要規劃 subvolume 佈局、還要理解它寫時複製（CoW）的一些行為差異；這些功能在你會用快照回滾的主力機上很有價值，在演練 VM 上是雜訊。<code>xfs</code> 同樣穩定，但對這類用途相對 ext4 沒有決定性優勢。更特定的 <code>zfs</code>、<code>f2fs</code> 不在一般 VM 的考慮範圍——zfs 在 Arch / ARM 上是非主線 kernel 的 out-of-tree 模組、授權與維護成本高，f2fs 是為快閃裝置設計、VM 用不到。</p>
<p>判讀軸是你會不會用到進階功能。會固定用快照回滾系統狀態——選 btrfs 並接受它的佈局複雜度；只是要一個可靠的檔案系統——ext4。快照這類能力跟下面的獨立 <code>/home</code> 一樣，是真實機器的儲存規劃主題，值得另外深入，但別為了「聽起來比較強」就把它的複雜度帶進一台用完即丟的機器。</p>
<h3 id="獨立-home-vs-單一-root">獨立 /home vs 單一 root</h3>
<p>獨立 <code>/home</code> 分區的價值是「重灌系統不丟個人資料」，這是主力機的需求，不是每台機器都需要。把 <code>/home</code> 切成獨立分區，重裝系統時可以只格式化 root、保留 <code>/home</code> 裡的設定與檔案。一台用完即丟的演練 VM 沒有這個需求——它的整個生命週期就是裝起來、驗證、丟掉。如果你想跨多次實驗保留狀態，VM 情境更貼切的手段是宿主層的快照或共享資料夾，而不是在 guest 裡切獨立 <code>/home</code>——後者解決的是「重灌 OS 保資料」，不是「保留實驗狀態」。</p>
<p>把空間切兩半的隱性代價是失衡風險。假設總共十幾 GB，照預設切一塊給 <code>/</code>、剩下給 <code>/home</code>，所有系統套件（桌面全套依賴都裝在 <code>/usr</code>、算 <code>/</code>）擠在前者、容易先滿，而 <code>/home</code> 那邊空著——典型的一邊爆一邊空。把全部空間當一個池子用的單一 root 佈局，不會人為卡死任一邊，對不需要「重灌保資料」的機器最不容易出事。</p>
<h2 id="bootloader">Bootloader</h2>
<p>開機載入器決定韌體怎麼找到並載入 kernel，在虛擬機上選 GRUB 而非直接用 EFISTUB，理由是可靠性（韌體到 kernel 的整條交棒過程見 <a href="/blog/linux/dotfile/knowledge-cards/uefi-boot-chain/" data-link-title="UEFI 開機鏈" data-link-desc="在 bootloader 選型（GRUB / EFISTUB / systemd-boot）卡住、或機器重開後找不到 kernel、需要理解韌體怎麼找到並載入系統時讀 — 韌體到 kernel 的交棒過程">UEFI 開機鏈卡</a>）。EFISTUB 讓 UEFI 韌體直接載入 kernel、不經過獨立的 bootloader，最精簡，但它完全依賴寫進 UEFI NVRAM（韌體用來存開機項的非揮發記憶體）的開機項。問題在於 QEMU 系的虛擬機（UTM 底層即是）對 EFI 變數的儲存有時不穩，一旦 NVRAM 裡的開機項掉了，韌體就找不到 kernel、機器開不了——這在 VM 環境是會實際踩到的坑。</p>
<p>GRUB 的容錯來自它（以 removable 模式安裝時）多寫了一份。除了 NVRAM 開機項，<code>grub-install --removable</code> 會在 ESP 的標準 fallback 路徑（aarch64 是 <code>\EFI\BOOT\BOOTAA64.EFI</code>）也放一份，就算 NVRAM 開機項丟了，韌體仍會從 fallback 路徑找到 GRUB；VM 環境的安裝程式通常以這個模式裝 GRUB，正是看上這層保險。它還附帶一個開機選單，當 kernel 或 initramfs 出問題時，可以進選單救援、加開機參數除錯——演練時的容錯空間大很多。</p>
<p>判讀軸是環境的 NVRAM 可靠度。在 NVRAM 穩定的實體機上，EFISTUB 的極簡是漂亮的選擇；在 NVRAM 可能不穩的 VM 上，可靠性優先，GRUB 的「多寫一份 fallback + 救援選單」更穩妥。GRUB 不是唯一的可靠選擇——systemd-boot 同樣是有開機選單、能裝到 fallback 路徑的獨立 bootloader，又比 GRUB 輕，在 VM / 單系統同樣站得住；這裡落在 GRUB 是因為 archboot 安裝程式預設以 removable 模式裝它，不是 GRUB 獨佔可靠性。GRUB 自己的設定檔在 VM 上用預設值即可，不需要額外的 kernel 參數。</p>
<h2 id="下一步">下一步</h2>
<p>選項選完、系統裝好、重開機進得去之後，先別急著開始用——「裝好了」跟「能用了」之間往往還缺一截：這台最小系統不一定有你需要的基本工具。<a href="../minimal-install-verify/">最小安裝後的工具驗證與補足</a> 就是在補那一截。</p>
<p>從安裝到桌面就緒的完整依賴順序，見 <a href="/blog/linux/dotfile/00-dotfile-mindset/setup-order-guide/" data-link-title="環境建置的操作順序" data-link-desc="第一次從零建立 Linux 或 macOS 開發環境、不確定先做什麼後做什麼時讀 — 依賴順序路線圖，每一步附對應模組連結">模組零的操作順序指引</a>；本篇是它「安裝作業系統」那一步的展開。</p>
]]></content:encoded></item><item><title>最小安裝後的工具驗證與補足</title><link>https://tarrragon.github.io/blog/linux/install/minimal-install-verify/</link><pubDate>Wed, 01 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/minimal-install-verify/</guid><description>&lt;p>最小化安裝給你的是一台能開機的系統，但「能開機」跟「能用」之間隔著一組「大家都假設存在」但其實沒被裝進去的工具。最小安裝（多數發行版的 &lt;code>base&lt;/code> 之類的套件組）刻意只裝開機與基本運作所需的東西，把工具的選擇權留給你。代價是許多你以為理所當然會在的指令——&lt;code>sudo&lt;/code>、&lt;code>which&lt;/code>、&lt;code>rsync&lt;/code>——一個都沒有。驗證它們在不在，比假設它們在安全。&lt;/p>
&lt;p>這層落差最常在你跑自動化腳本時引爆。一支 bootstrap script 的第一行可能就是 &lt;code>sudo pacman -S ...&lt;/code>，在一台連 &lt;code>sudo&lt;/code> 都沒有的機器上，它連第一步都跨不過去。所以裝好系統後、跑任何自動化之前，先過一輪工具驗證，把缺的補上。&lt;/p>
&lt;h2 id="sudo先有雞還是先有蛋">sudo：先有雞還是先有蛋&lt;/h2>
&lt;p>&lt;code>sudo&lt;/code> 是最容易被假設存在、卻最常缺席的工具，而且它的缺席有一個結構性的麻煩：補它的動作本身需要 root 權限。最小安裝通常不含 sudo。某些安裝程式（如本例的 archboot）即使你勾了「把這個使用者設為管理員」，那個動作也往往只是把使用者加進 &lt;code>wheel&lt;/code> 群組，並沒有真的裝上 sudo、也沒有啟用 sudoers 裡 wheel 群組的授權行。結果就是使用者「名義上是管理員」，但系統裡並沒有 sudo 這支指令。&lt;/p>
&lt;p>這形成一個先有雞還是先有蛋的關卡：bootstrap script 要靠 sudo 來裝套件，但 sudo 自己得先存在。它的解法不能是「把 sudo 寫進套件清單」——那份清單正是靠 sudo 來安裝的。sudo 只能是「跑 bootstrap 之前的前置」，用 root 身分手動補上（&lt;code>su -&lt;/code> 成為 root、&lt;code>echo &amp;gt; 檔案&lt;/code> 重導向、&lt;code>chmod&lt;/code> 設權限這些基礎操作不熟的話，見 &lt;a href="../basic-operations/">安裝過程用到的基礎操作&lt;/a>）：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">su - &lt;span class="c1"># 切到 root（輸入 root 密碼）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">pacman -S --needed sudo &lt;span class="c1"># root 身分裝 sudo，不需要 sudo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nb">echo&lt;/span> &lt;span class="s1">&amp;#39;%wheel ALL=(ALL:ALL) ALL&amp;#39;&lt;/span> &amp;gt; /etc/sudoers.d/10-wheel &lt;span class="c1"># 啟用 wheel 群組授權&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">chmod &lt;span class="m">440&lt;/span> /etc/sudoers.d/10-wheel
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">visudo -c &lt;span class="c1"># 驗證 sudoers 語法，印 parsed OK 才安全&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">exit&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>切回一般使用者後用 &lt;code>sudo -v&lt;/code> 確認——能輸入密碼、沒報「不在 sudoers 檔」就成。這一步揭示一條通則：凡是 bootstrap 自身要依賴的工具，都不能由 bootstrap 來裝，必須當成前置先備好。&lt;code>sudo&lt;/code> 是這類前置最典型的一個。&lt;/p>
&lt;p>上面的指令以 Arch 的 &lt;code>pacman&lt;/code> 為例。Fedora 用 &lt;code>dnf&lt;/code>、Debian/Ubuntu 用 &lt;code>apt&lt;/code>；而 Debian 系的桌面與伺服器映像多半預設就裝了 sudo、也設好了授權，這個缺口主要出現在刻意精簡的 minimal 安裝。換句話說「sudo 是前置」這條判讀軸跨發行版成立，但「你這台到底缺不缺」要靠驗證、不是假設。&lt;/p>
&lt;h2 id="which腳本裡的隱形地雷">which：腳本裡的隱形地雷&lt;/h2>
&lt;p>&lt;code>which&lt;/code> 是另一個最小系統常缺、卻被腳本大量引用的指令，它的缺席會以一種隱晦的方式讓腳本出錯。很多腳本用 &lt;code>$(which zsh)&lt;/code> 之類的寫法取一支程式的完整路徑；在沒有 &lt;code>which&lt;/code> 的系統上，這個命令替換會吐出空字串，而下游拿到空字串的指令可能不會立刻報「找不到 which」，而是報一個看似無關的錯。實測中就遇過 &lt;code>chsh -s &amp;quot;$(which zsh)&amp;quot;&lt;/code> 因為 &lt;code>which&lt;/code> 不存在而變成 &lt;code>chsh -s &amp;quot;&amp;quot;&lt;/code>，最後報的是 &lt;code>chsh: shell must be a full path name&lt;/code>——錯誤訊息完全沒提到真正的元兇。&lt;/p>
&lt;p>正確的做法是用 &lt;code>command -v&lt;/code> 取代 &lt;code>which&lt;/code>。&lt;code>command -v&lt;/code> 是 POSIX 規範的 shell 內建，不依賴任何外部套件，在最小系統上一定存在。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="nb">command&lt;/span> -v zsh &lt;span class="c1"># 印出 /usr/bin/zsh；找不到則回傳非零、不印東西&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這條判讀對你自己寫的腳本是「把 &lt;code>which&lt;/code> 全換成 &lt;code>command -v&lt;/code>」，對別人的腳本是「在缺 &lt;code>which&lt;/code> 的系統上，先補 &lt;code>which&lt;/code> 套件或改腳本」。它跟 sudo 的差別在於：&lt;code>which&lt;/code> 的缺席會悄悄製造一個誤導性的下游錯誤，而不是當場大聲報錯，所以更值得在驗證階段主動排掉。&lt;/p>
&lt;h2 id="其他常缺的工具">其他常缺的工具&lt;/h2>
&lt;p>除了 sudo 與 which，最小系統還常缺幾類在自動化裡會用到的工具，各有各的補法。它們不像 sudo 是硬前置，但缺了會在特定步驟卡住。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>工具&lt;/th>
 &lt;th>缺了會怎樣&lt;/th>
 &lt;th>補法&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;code>rsync&lt;/code>&lt;/td>
 &lt;td>從本機同步 dotfile 進機器時 &lt;code>rsync: command not found&lt;/code>&lt;/td>
 &lt;td>進套件清單；急用時改用 &lt;code>tar&lt;/code> over SSH 過渡&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>ca-certificates&lt;/code>&lt;/td>
 &lt;td>HTTPS / 任何 TLS 連線在憑證驗證直接失敗（沒有信任根）&lt;/td>
 &lt;td>進套件清單；它是下一篇 HTTPS clone 的隱性前置&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;code>hostname&lt;/code>&lt;/td>
 &lt;td>某些腳本呼叫 &lt;code>hostname&lt;/code> 取主機名時失敗&lt;/td>
 &lt;td>補 &lt;code>inetutils&lt;/code>，或改用 &lt;code>hostnamectl&lt;/code> / 讀 &lt;code>/etc/hostname&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>編譯工具鏈&lt;/td>
 &lt;td>從原始碼或社群套件庫編譯時缺 &lt;code>gcc&lt;/code> / &lt;code>make&lt;/code>&lt;/td>
 &lt;td>補發行版的開發工具組（如 &lt;code>base-devel&lt;/code>）&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>&lt;code>rsync&lt;/code> 的缺席要特別點出，因為它常被當成理所當然的傳輸工具。最小系統沒有它時，第一次把檔案弄進機器可以用兩邊都有的 &lt;code>tar&lt;/code> 搭配 SSH 過渡：&lt;/p></description><content:encoded><![CDATA[<p>最小化安裝給你的是一台能開機的系統，但「能開機」跟「能用」之間隔著一組「大家都假設存在」但其實沒被裝進去的工具。最小安裝（多數發行版的 <code>base</code> 之類的套件組）刻意只裝開機與基本運作所需的東西，把工具的選擇權留給你。代價是許多你以為理所當然會在的指令——<code>sudo</code>、<code>which</code>、<code>rsync</code>——一個都沒有。驗證它們在不在，比假設它們在安全。</p>
<p>這層落差最常在你跑自動化腳本時引爆。一支 bootstrap script 的第一行可能就是 <code>sudo pacman -S ...</code>，在一台連 <code>sudo</code> 都沒有的機器上，它連第一步都跨不過去。所以裝好系統後、跑任何自動化之前，先過一輪工具驗證，把缺的補上。</p>
<h2 id="sudo先有雞還是先有蛋">sudo：先有雞還是先有蛋</h2>
<p><code>sudo</code> 是最容易被假設存在、卻最常缺席的工具，而且它的缺席有一個結構性的麻煩：補它的動作本身需要 root 權限。最小安裝通常不含 sudo。某些安裝程式（如本例的 archboot）即使你勾了「把這個使用者設為管理員」，那個動作也往往只是把使用者加進 <code>wheel</code> 群組，並沒有真的裝上 sudo、也沒有啟用 sudoers 裡 wheel 群組的授權行。結果就是使用者「名義上是管理員」，但系統裡並沒有 sudo 這支指令。</p>
<p>這形成一個先有雞還是先有蛋的關卡：bootstrap script 要靠 sudo 來裝套件，但 sudo 自己得先存在。它的解法不能是「把 sudo 寫進套件清單」——那份清單正是靠 sudo 來安裝的。sudo 只能是「跑 bootstrap 之前的前置」，用 root 身分手動補上（<code>su -</code> 成為 root、<code>echo &gt; 檔案</code> 重導向、<code>chmod</code> 設權限這些基礎操作不熟的話，見 <a href="../basic-operations/">安裝過程用到的基礎操作</a>）：</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">su -                                          <span class="c1"># 切到 root（輸入 root 密碼）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">pacman -S --needed sudo                        <span class="c1"># root 身分裝 sudo，不需要 sudo</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">echo</span> <span class="s1">&#39;%wheel ALL=(ALL:ALL) ALL&#39;</span> &gt; /etc/sudoers.d/10-wheel   <span class="c1"># 啟用 wheel 群組授權</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">chmod <span class="m">440</span> /etc/sudoers.d/10-wheel
</span></span><span class="line"><span class="ln">5</span><span class="cl">visudo -c                                      <span class="c1"># 驗證 sudoers 語法，印 parsed OK 才安全</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">exit</span></span></code></pre></div><p>切回一般使用者後用 <code>sudo -v</code> 確認——能輸入密碼、沒報「不在 sudoers 檔」就成。這一步揭示一條通則：凡是 bootstrap 自身要依賴的工具，都不能由 bootstrap 來裝，必須當成前置先備好。<code>sudo</code> 是這類前置最典型的一個。</p>
<p>上面的指令以 Arch 的 <code>pacman</code> 為例。Fedora 用 <code>dnf</code>、Debian/Ubuntu 用 <code>apt</code>；而 Debian 系的桌面與伺服器映像多半預設就裝了 sudo、也設好了授權，這個缺口主要出現在刻意精簡的 minimal 安裝。換句話說「sudo 是前置」這條判讀軸跨發行版成立，但「你這台到底缺不缺」要靠驗證、不是假設。</p>
<h2 id="which腳本裡的隱形地雷">which：腳本裡的隱形地雷</h2>
<p><code>which</code> 是另一個最小系統常缺、卻被腳本大量引用的指令，它的缺席會以一種隱晦的方式讓腳本出錯。很多腳本用 <code>$(which zsh)</code> 之類的寫法取一支程式的完整路徑；在沒有 <code>which</code> 的系統上，這個命令替換會吐出空字串，而下游拿到空字串的指令可能不會立刻報「找不到 which」，而是報一個看似無關的錯。實測中就遇過 <code>chsh -s &quot;$(which zsh)&quot;</code> 因為 <code>which</code> 不存在而變成 <code>chsh -s &quot;&quot;</code>，最後報的是 <code>chsh: shell must be a full path name</code>——錯誤訊息完全沒提到真正的元兇。</p>
<p>正確的做法是用 <code>command -v</code> 取代 <code>which</code>。<code>command -v</code> 是 POSIX 規範的 shell 內建，不依賴任何外部套件，在最小系統上一定存在。</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"><span class="nb">command</span> -v zsh        <span class="c1"># 印出 /usr/bin/zsh；找不到則回傳非零、不印東西</span></span></span></code></pre></div><p>這條判讀對你自己寫的腳本是「把 <code>which</code> 全換成 <code>command -v</code>」，對別人的腳本是「在缺 <code>which</code> 的系統上，先補 <code>which</code> 套件或改腳本」。它跟 sudo 的差別在於：<code>which</code> 的缺席會悄悄製造一個誤導性的下游錯誤，而不是當場大聲報錯，所以更值得在驗證階段主動排掉。</p>
<h2 id="其他常缺的工具">其他常缺的工具</h2>
<p>除了 sudo 與 which，最小系統還常缺幾類在自動化裡會用到的工具，各有各的補法。它們不像 sudo 是硬前置，但缺了會在特定步驟卡住。</p>
<table>
  <thead>
      <tr>
          <th>工具</th>
          <th>缺了會怎樣</th>
          <th>補法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>rsync</code></td>
          <td>從本機同步 dotfile 進機器時 <code>rsync: command not found</code></td>
          <td>進套件清單；急用時改用 <code>tar</code> over SSH 過渡</td>
      </tr>
      <tr>
          <td><code>ca-certificates</code></td>
          <td>HTTPS / 任何 TLS 連線在憑證驗證直接失敗（沒有信任根）</td>
          <td>進套件清單；它是下一篇 HTTPS clone 的隱性前置</td>
      </tr>
      <tr>
          <td><code>hostname</code></td>
          <td>某些腳本呼叫 <code>hostname</code> 取主機名時失敗</td>
          <td>補 <code>inetutils</code>，或改用 <code>hostnamectl</code> / 讀 <code>/etc/hostname</code></td>
      </tr>
      <tr>
          <td>編譯工具鏈</td>
          <td>從原始碼或社群套件庫編譯時缺 <code>gcc</code> / <code>make</code></td>
          <td>補發行版的開發工具組（如 <code>base-devel</code>）</td>
      </tr>
  </tbody>
</table>
<p><code>rsync</code> 的缺席要特別點出，因為它常被當成理所當然的傳輸工具。最小系統沒有它時，第一次把檔案弄進機器可以用兩邊都有的 <code>tar</code> 搭配 SSH 過渡：</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">tar czf - --exclude <span class="s1">&#39;.git&#39;</span> . <span class="p">|</span> ssh user@host <span class="s1">&#39;mkdir -p ~/dest &amp;&amp; tar xzf - -C ~/dest&#39;</span></span></span></code></pre></div><p>這條的好處是不依賴目標機有 rsync；缺點是它每次都傳全部、沒有 rsync 的增量。在反覆同步的工作流裡，值得早點把 rsync 補進套件清單換取增量傳輸。</p>
<p><code>ca-certificates</code> 最容易在下一步咬人。最小系統可能沒有 CA 信任根，這時任何 HTTPS 連線——包括下一篇主推的「公開 repo 用 HTTPS clone」——會在 TLS 憑證驗證直接失敗，而錯誤訊息常指向 SSL handshake 而非「缺信任根」，容易誤判成網路問題。打算走 HTTPS 取得 dotfile 的機器，先確認 <code>ca-certificates</code> 在。<code>git</code> 與 <code>curl</code> 同理：它們是 bootstrap 取得程式碼的基本工具，下面的驗證迴圈也會檢查，最小系統若沒有要一併補。</p>
<p>剩下兩項的缺席各有觸發時機。<code>hostname</code> 只在腳本明確呼叫它取主機名時才會浮現缺失，而用 <code>hostnamectl</code> 或直接讀 <code>/etc/hostname</code> 可以繞過，所以它常被當成「補了省事、不補也有替代」的軟缺口。編譯工具鏈則是在你要從原始碼或社群套件庫編譯時才需要——純跑預編譯套件的機器可以不裝，但只要你的 dotfile 流程會編譯任何東西（例如從社群套件庫裝桌面元件），它就得進清單。</p>
<h2 id="系統性的驗證">系統性的驗證</h2>
<p>裝好系統後先跑一輪集中驗證、把缺口一次盤出來，比等腳本跑到一半才逐一踩雷省事。驗證的對象是「你接下來的流程會用到、但最小系統可能沒有」的工具。</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"><span class="k">for</span> cmd in sudo git curl rsync tar zsh<span class="p">;</span> <span class="k">do</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="k">if</span> <span class="nb">command</span> -v <span class="s2">&#34;</span><span class="nv">$cmd</span><span class="s2">&#34;</span> &gt;/dev/null 2&gt;<span class="p">&amp;</span>1<span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;OK   </span><span class="nv">$cmd</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;缺   </span><span class="nv">$cmd</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="k">done</span></span></span></code></pre></div><p>這段刻意用 <code>command -v</code> 來檢查（而不是 <code>which</code>），因為要檢查的對象之一正是「外部工具在不在」，用一個一定存在的內建來檢查才不會自己先掛掉。盤出來的缺口分兩類處理：bootstrap 自身依賴的（如 sudo）當前置手動補；其餘的（如 rsync、編譯工具）進套件清單，交給 bootstrap 一起裝。</p>
<h2 id="跟-bootstrap-套件清單的界線">跟 Bootstrap 套件清單的界線</h2>
<p>這篇的驗證跟 <a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八的 bootstrap script 設計</a> 是兩件互補的事，界線在「假設」上。bootstrap script 的套件清單假設一個前提：機器已經有能力執行安裝（有 sudo、有 package manager、清單裡的東西都能被裝上）。這篇處理的正是那個前提成立之前的階段——最小系統到底有沒有滿足那些假設，缺的補上，讓 bootstrap 的假設變成事實。</p>
<p>換句話說，套件清單回答「這台機器最終要有哪些套件」，工具驗證回答「這台機器現在夠不夠資格開始跑那份清單」。把兩者分清楚，才不會把 sudo 這種前置誤塞進靠 sudo 安裝的清單裡。</p>
<h2 id="下一步">下一步</h2>
<p>工具補齊、機器有能力執行安裝之後，你還困在一個地方：擠在機器的主控台手打。怎麼從舒適的本機終端機操作它，以及還沒有 SSH key 時怎麼把 dotfile 弄進去，<a href="../ssh-keyless-bootstrap/">外部連入、SSH key 與無 key 的 bootstrap 路徑</a> 處理這兩件事。</p>
]]></content:encoded></item><item><title>安裝期套件與網路故障排除：pacman / DNS / mirror / keyring</title><link>https://tarrragon.github.io/blog/linux/install/package-and-network-troubleshooting/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/package-and-network-troubleshooting/</guid><description>&lt;p>裝好 OS、第一次跑套件管理器抓 bootstrap 要的東西時，最常撞的一類故障是「套件裝不下來」。這類故障的第一步判讀，是把它拆成兩層完全不同的問題：&lt;strong>連不到（網路 / DNS / mirror）&lt;/strong>，還是&lt;strong>連得到但被拒（套件管理器自己的狀態）&lt;/strong>。這兩層的檢查工具、根因、修法都不一樣，先分對層再往下查，才不會拿修 DNS 的方法去治簽章過期。這篇以 Arch 的 &lt;code>pacman&lt;/code> 為主要案例（本系列 VM 實測踩過的坑），其他發行版的套件管理器概念對應相同。&lt;/p>
&lt;h2 id="第一步分連不到還是連得到但被拒">第一步：分「連不到」還是「連得到但被拒」&lt;/h2>
&lt;p>錯誤訊息本身就能分層，不用猜：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>訊息提到主機名解不出、連線逾時、retrieving file 失敗&lt;/strong> → 連不到，往網路 / DNS / mirror 查。&lt;/li>
&lt;li>&lt;strong>訊息提到 database lock、signature、trust、conflicting、partial&lt;/strong> → 連得到、封包也拿到了，是套件管理器的狀態問題。&lt;/li>
&lt;/ul>
&lt;p>判準是問一句：「它到底有沒有成功連上 mirror？」有連上才談得到簽章、相依、db 狀態；連都沒連上，那些都還輪不到。剛裝好的最小系統最常見的是前者——網路設定還沒到位。&lt;/p>
&lt;h2 id="連不到那層從實體介面往上查到域名">連不到那層：從實體介面往上查到域名&lt;/h2>
&lt;p>網路不通有好幾層，從最底層往上逐層確認，哪一層斷了一目了然。這條鏈跟&lt;a href="../minimal-install-verify/">最小安裝後的驗證&lt;/a>裡的網路檢查同源，這裡聚焦在「抓套件失敗」這個症狀上：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">ip -brief a &lt;span class="c1"># 1. 有沒有拿到 IP？介面 UP 且有位址&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">ping -c1 8.8.8.8 &lt;span class="c1"># 2. IP 層對外通不通？（直接打 IP、跳過 DNS）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">getent hosts archlinux.org &lt;span class="c1"># 3. 域名解得出來嗎？&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">timedatectl &lt;span class="c1"># 4. 時間對嗎？（影響下一層的簽章驗證）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>第 2 步通、第 3 步不通 = DNS 問題&lt;/strong>，這是最小安裝最典型的落點：IP 層明明通（&lt;code>ping 8.8.8.8&lt;/code> 有回應），但域名解不出來，因為 &lt;code>/etc/resolv.conf&lt;/code> 還沒設 nameserver。這時 pacman 會卡在解析 mirror 主機名。修法是給系統一個 resolver——臨時可直接寫 &lt;code>/etc/resolv.conf&lt;/code>（&lt;code>nameserver 1.1.1.1&lt;/code>）。先看它是什麼（&lt;code>ls -l /etc/resolv.conf&lt;/code>）：啟用了 &lt;code>systemd-resolved&lt;/code> 或 NetworkManager 的系統上它是那些服務管理的 symlink，手寫會被覆蓋，治本要透過該網路管理服務設定 DNS；裸 Arch 最小安裝若沒啟用這些服務，它通常就是一個普通檔案，手寫即持久生效。&lt;/p>
&lt;p>&lt;strong>mirror 逾時 / 抓不到&lt;/strong>：DNS 通了、但某個 mirror 慢或掛了。換 &lt;code>/etc/pacman.d/mirrorlist&lt;/code> 到地理近且快的鏡像（實測不同 mirror 速度可差數倍）。這也接回&lt;a href="../install-option-decisions/">安裝選項判讀&lt;/a>裡選 mirror 的決策——裝機當下選錯 mirror，這裡就會慢。&lt;/p>
&lt;h2 id="連得到但被拒那層pacman-自己的狀態">連得到但被拒那層：pacman 自己的狀態&lt;/h2>
&lt;p>連上 mirror、封包也拿到了卻失敗，問題在 pacman 的本地狀態或簽章驗證。這幾種各有明確徵兆與修法：&lt;/p>
&lt;h3 id="database-lock上次沒清乾淨的殘留">database lock：上次沒清乾淨的殘留&lt;/h3>
&lt;p>&lt;code>error: failed to init transaction (unable to lock database)&lt;/code>。pacman 用 &lt;code>/var/lib/pacman/db.lck&lt;/code> 這個鎖檔保證同時只有一個 pacman 在動資料庫；上次 pacman 被中斷（斷電、Ctrl+C、當掉）沒清掉鎖檔就會殘留。&lt;strong>先確認真的沒有 pacman 在跑&lt;/strong>（&lt;code>pgrep -x pacman&lt;/code>），確認沒有再刪鎖檔：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">pgrep -x pacman &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">echo&lt;/span> &lt;span class="s2">&amp;#34;有 pacman 在跑、別刪&amp;#34;&lt;/span> &lt;span class="o">||&lt;/span> sudo rm /var/lib/pacman/db.lck&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>先查再刪這個順序重要——盲刪鎖檔時如果真的有另一個 pacman 在跑，兩個同時寫資料庫會弄壞它。&lt;/p>
&lt;h3 id="簽章--keyring-過期十之八九是時間不對">簽章 / keyring 過期：十之八九是時間不對&lt;/h3>
&lt;p>&lt;code>invalid or corrupted package (PGP signature)&lt;/code> 或 &lt;code>signature is unknown trust&lt;/code>。pacman 驗證每個套件的 GPG 簽章，驗證失敗最常見的根因是&lt;strong>系統時間不對&lt;/strong>——這正是第一步要 &lt;code>timedatectl&lt;/code> 的原因。時間差太多（新裝的 VM、主機板電池沒電的老機器）會讓「簽章的有效期」判斷錯誤，明明有效的簽章被判過期。先校時：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">sudo timedatectl set-ntp &lt;span class="nb">true&lt;/span> &lt;span class="c1"># 開 NTP 自動校時（SSH 進最小系統無 polkit 互動代理、裸跑會被拒，要 sudo）&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>時間對了還失敗，才是 keyring 本身的問題（archlinux-keyring 太舊）：&lt;code>sudo pacman -Sy archlinux-keyring&lt;/code> 更新 keyring，必要時 &lt;code>sudo pacman-key --refresh-keys&lt;/code>。順序是先校時再動 keyring，因為時間不對時連 keyring 都更新不了。&lt;/p>
&lt;h3 id="partial-upgrade只同步不升級造成的相依斷裂">partial upgrade：只同步不升級造成的相依斷裂&lt;/h3>
&lt;p>&lt;code>conflicting dependencies&lt;/code> 或裝完某個套件後系統行為異常。根因是在 rolling 發行版上只做了 &lt;code>pacman -Sy&lt;/code>（同步資料庫）就裝新套件，卻沒 &lt;code>-u&lt;/code>（升級既有套件）——新套件依賴新版函式庫，但系統還是舊的，相依對不上。Arch 只支援 full upgrade：&lt;strong>一律 &lt;code>pacman -Syu&lt;/code>，永遠不要單獨 &lt;code>-Sy&lt;/code> 之後裝東西&lt;/strong>。這條規則救掉這一整類故障。&lt;/p></description><content:encoded><![CDATA[<p>裝好 OS、第一次跑套件管理器抓 bootstrap 要的東西時，最常撞的一類故障是「套件裝不下來」。這類故障的第一步判讀，是把它拆成兩層完全不同的問題：<strong>連不到（網路 / DNS / mirror）</strong>，還是<strong>連得到但被拒（套件管理器自己的狀態）</strong>。這兩層的檢查工具、根因、修法都不一樣，先分對層再往下查，才不會拿修 DNS 的方法去治簽章過期。這篇以 Arch 的 <code>pacman</code> 為主要案例（本系列 VM 實測踩過的坑），其他發行版的套件管理器概念對應相同。</p>
<h2 id="第一步分連不到還是連得到但被拒">第一步：分「連不到」還是「連得到但被拒」</h2>
<p>錯誤訊息本身就能分層，不用猜：</p>
<ul>
<li><strong>訊息提到主機名解不出、連線逾時、retrieving file 失敗</strong> → 連不到，往網路 / DNS / mirror 查。</li>
<li><strong>訊息提到 database lock、signature、trust、conflicting、partial</strong> → 連得到、封包也拿到了，是套件管理器的狀態問題。</li>
</ul>
<p>判準是問一句：「它到底有沒有成功連上 mirror？」有連上才談得到簽章、相依、db 狀態；連都沒連上，那些都還輪不到。剛裝好的最小系統最常見的是前者——網路設定還沒到位。</p>
<h2 id="連不到那層從實體介面往上查到域名">連不到那層：從實體介面往上查到域名</h2>
<p>網路不通有好幾層，從最底層往上逐層確認，哪一層斷了一目了然。這條鏈跟<a href="../minimal-install-verify/">最小安裝後的驗證</a>裡的網路檢查同源，這裡聚焦在「抓套件失敗」這個症狀上：</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">ip -brief a              <span class="c1"># 1. 有沒有拿到 IP？介面 UP 且有位址</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">ping -c1 8.8.8.8         <span class="c1"># 2. IP 層對外通不通？（直接打 IP、跳過 DNS）</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">getent hosts archlinux.org   <span class="c1"># 3. 域名解得出來嗎？</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">timedatectl              <span class="c1"># 4. 時間對嗎？（影響下一層的簽章驗證）</span></span></span></code></pre></div><p><strong>第 2 步通、第 3 步不通 = DNS 問題</strong>，這是最小安裝最典型的落點：IP 層明明通（<code>ping 8.8.8.8</code> 有回應），但域名解不出來，因為 <code>/etc/resolv.conf</code> 還沒設 nameserver。這時 pacman 會卡在解析 mirror 主機名。修法是給系統一個 resolver——臨時可直接寫 <code>/etc/resolv.conf</code>（<code>nameserver 1.1.1.1</code>）。先看它是什麼（<code>ls -l /etc/resolv.conf</code>）：啟用了 <code>systemd-resolved</code> 或 NetworkManager 的系統上它是那些服務管理的 symlink，手寫會被覆蓋，治本要透過該網路管理服務設定 DNS；裸 Arch 最小安裝若沒啟用這些服務，它通常就是一個普通檔案，手寫即持久生效。</p>
<p><strong>mirror 逾時 / 抓不到</strong>：DNS 通了、但某個 mirror 慢或掛了。換 <code>/etc/pacman.d/mirrorlist</code> 到地理近且快的鏡像（實測不同 mirror 速度可差數倍）。這也接回<a href="../install-option-decisions/">安裝選項判讀</a>裡選 mirror 的決策——裝機當下選錯 mirror，這裡就會慢。</p>
<h2 id="連得到但被拒那層pacman-自己的狀態">連得到但被拒那層：pacman 自己的狀態</h2>
<p>連上 mirror、封包也拿到了卻失敗，問題在 pacman 的本地狀態或簽章驗證。這幾種各有明確徵兆與修法：</p>
<h3 id="database-lock上次沒清乾淨的殘留">database lock：上次沒清乾淨的殘留</h3>
<p><code>error: failed to init transaction (unable to lock database)</code>。pacman 用 <code>/var/lib/pacman/db.lck</code> 這個鎖檔保證同時只有一個 pacman 在動資料庫；上次 pacman 被中斷（斷電、Ctrl+C、當掉）沒清掉鎖檔就會殘留。<strong>先確認真的沒有 pacman 在跑</strong>（<code>pgrep -x pacman</code>），確認沒有再刪鎖檔：</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">pgrep -x pacman <span class="o">&amp;&amp;</span> <span class="nb">echo</span> <span class="s2">&#34;有 pacman 在跑、別刪&#34;</span> <span class="o">||</span> sudo rm /var/lib/pacman/db.lck</span></span></code></pre></div><p>先查再刪這個順序重要——盲刪鎖檔時如果真的有另一個 pacman 在跑，兩個同時寫資料庫會弄壞它。</p>
<h3 id="簽章--keyring-過期十之八九是時間不對">簽章 / keyring 過期：十之八九是時間不對</h3>
<p><code>invalid or corrupted package (PGP signature)</code> 或 <code>signature is unknown trust</code>。pacman 驗證每個套件的 GPG 簽章，驗證失敗最常見的根因是<strong>系統時間不對</strong>——這正是第一步要 <code>timedatectl</code> 的原因。時間差太多（新裝的 VM、主機板電池沒電的老機器）會讓「簽章的有效期」判斷錯誤，明明有效的簽章被判過期。先校時：</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 timedatectl set-ntp <span class="nb">true</span>     <span class="c1"># 開 NTP 自動校時（SSH 進最小系統無 polkit 互動代理、裸跑會被拒，要 sudo）</span></span></span></code></pre></div><p>時間對了還失敗，才是 keyring 本身的問題（archlinux-keyring 太舊）：<code>sudo pacman -Sy archlinux-keyring</code> 更新 keyring，必要時 <code>sudo pacman-key --refresh-keys</code>。順序是先校時再動 keyring，因為時間不對時連 keyring 都更新不了。</p>
<h3 id="partial-upgrade只同步不升級造成的相依斷裂">partial upgrade：只同步不升級造成的相依斷裂</h3>
<p><code>conflicting dependencies</code> 或裝完某個套件後系統行為異常。根因是在 rolling 發行版上只做了 <code>pacman -Sy</code>（同步資料庫）就裝新套件，卻沒 <code>-u</code>（升級既有套件）——新套件依賴新版函式庫，但系統還是舊的，相依對不上。Arch 只支援 full upgrade：<strong>一律 <code>pacman -Syu</code>，永遠不要單獨 <code>-Sy</code> 之後裝東西</strong>。這條規則救掉這一整類故障。</p>
<h3 id="stale-db-404裝機當下的資料庫已經過期">stale db 404：裝機當下的資料庫已經過期</h3>
<p><code>error: failed retrieving file '...' 404</code>，而且換好幾個 mirror 都一樣。這是 rolling 發行版特有的時序陷阱：Arch 的 mirror 不保留舊版檔案，你裝機時 ISO 內建的套件資料庫指向的檔名，可能幾天內就被輪替掉了——資料庫說有這個檔、mirror 上已經沒有。修法跟上一條同源：<code>pacman -Syu</code> 先把資料庫同步到最新，檔名對上了就抓得到。這也是為什麼「一律 <code>-Syu</code>」是 Arch 的鐵律，而不只是建議。</p>
<h2 id="判讀總表">判讀總表</h2>
<table>
  <thead>
      <tr>
          <th>症狀</th>
          <th>層</th>
          <th>權威檢查</th>
          <th>修法</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>主機名解不出</td>
          <td>網路</td>
          <td><code>getent hosts &lt;域名&gt;</code></td>
          <td>設 resolver（注意 symlink）</td>
      </tr>
      <tr>
          <td>ping IP 通、域名不通</td>
          <td>DNS</td>
          <td><code>ping 8.8.8.8</code> vs <code>getent</code></td>
          <td>設 <code>/etc/resolv.conf</code> 或網管服務</td>
      </tr>
      <tr>
          <td>mirror 慢 / 逾時</td>
          <td>網路</td>
          <td>換 mirror 測速</td>
          <td>改 mirrorlist</td>
      </tr>
      <tr>
          <td>unable to lock database</td>
          <td>pacman</td>
          <td><code>pgrep -x pacman</code></td>
          <td>確認無後刪 db.lck</td>
      </tr>
      <tr>
          <td>PGP signature / unknown trust</td>
          <td>pacman</td>
          <td><code>timedatectl</code>（先校時）</td>
          <td>校時 →（仍失敗）更新 keyring</td>
      </tr>
      <tr>
          <td>conflicting / partial</td>
          <td>pacman</td>
          <td>是否只跑了 <code>-Sy</code></td>
          <td><code>pacman -Syu</code>（永遠 full）</td>
      </tr>
      <tr>
          <td>retrieving file 404（多 mirror）</td>
          <td>pacman</td>
          <td>rolling stale db</td>
          <td><code>pacman -Syu</code> 同步再裝</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步">下一步</h2>
<ul>
<li>這幾步用到的網路驗證，完整版在<a href="../minimal-install-verify/">最小安裝後的工具驗證與補足</a>。</li>
<li>裝機時選 mirror / locale / 時區的決策，見<a href="../install-option-decisions/">Linux 安裝選項判讀</a>。</li>
<li>跨發行版時「這個套件名 / 這個旗標在別的發行版叫什麼」的差異判讀，見<a href="../platform-divergence-map/">平台與發行版差異的判讀地圖</a>。</li>
<li>套件抓下來了、但 bootstrap 腳本本身失敗要 debug，見<a href="../observable-bootstrap/">可除錯的 bootstrap</a>。</li>
<li>系統跑起來後才出的套件問題（AUR 建置失敗、<code>-bin</code> 包 soname 斷裂等），屬除錯範疇，見<a href="../../debug/">Linux 除錯與診斷</a>。</li>
</ul>
]]></content:encoded></item><item><title>GUI 應用的安裝驗證：拆包、首跑對話框與播放判讀</title><link>https://tarrragon.github.io/blog/linux/install/gui-apps-install-verify/</link><pubDate>Thu, 02 Jul 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/install/gui-apps-install-verify/</guid><description>&lt;p>GUI 應用的安裝驗證跟 CLI 工具走不同的判讀鏈：CLI 工具裝完 &lt;code>command -v&lt;/code> 加一次試跑就能定案，GUI 應用則有三個 CLI 沒有的失敗層——依賴鏈拆包（裝了本體、缺功能模組）、首跑同意對話框（程式要求使用者決策才繼續）、播放輸出鏈（視窗有了、聲音或畫面沒有）。這三層都有各自的權威判讀位置，本篇以一輪 VM 實測（檔案管理器、瀏覽器、媒體播放器、音樂串流）把它們走一遍。&lt;/p>
&lt;h2 id="拆包生態裝了本體不等於裝了功能">拆包生態：裝了本體不等於裝了功能&lt;/h2>
&lt;p>發行版為了控制依賴體積，會把一個應用的核心跟功能模組拆成多個套件，預設只裝核心。這個設計讓「安裝成功」跟「功能可用」變成兩件事，而缺件的症狀往往是靜默的：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>VLC 的解碼器是獨立 plugin&lt;/strong>：Arch 的 &lt;code>vlc&lt;/code> 本體開得起來、UI 完整，播 H.264 影片卻回報 &lt;code>Codec 'h264' is not supported&lt;/code>——解碼能力在 &lt;code>vlc-plugin-ffmpeg&lt;/code>（或整組 &lt;code>vlc-plugins-all&lt;/code>）。judgment 訊號是「應用正常啟動、特定格式失敗」，權威來源是應用自己的 log（&lt;code>vlc --verbose=2&lt;/code>）。&lt;/li>
&lt;li>&lt;strong>pipewire 的 session manager 是獨立套件&lt;/strong>：&lt;code>pipewire&lt;/code> 常被依賴鏈拉進來，但沒有 &lt;code>wireplumber&lt;/code> 就沒有人建立音訊 graph——daemon 在跑、&lt;code>wpctl status&lt;/code> 的 Sinks 段是空的、所有應用無聲且不報錯。補 &lt;code>wireplumber&lt;/code> + &lt;code>pipewire-pulse&lt;/code>（多數 GUI 應用走 PulseAudio API）後輸出裝置立即出現。&lt;/li>
&lt;li>&lt;strong>optional dependency 不會自動安裝&lt;/strong>：套件宣告的 optdepends 是「裝了會多什麼功能」的提示、不是安裝動作。影片縮圖、壓縮格式支援、硬體加速常落在這層，&lt;code>pacman -Qi &amp;lt;pkg&amp;gt;&lt;/code> 的 Optional Deps 段列出哪些沒裝。&lt;/li>
&lt;/ul>
&lt;p>判讀原則：GUI 應用「開得起來但某個功能不動」時，先查發行版有沒有把那個功能拆成獨立套件，再懷疑設定或相容性。&lt;/p>
&lt;h2 id="首跑同意對話框程式在等使用者決策">首跑同意對話框：程式在等使用者決策&lt;/h2>
&lt;p>不少 GUI 應用第一次啟動會彈出需要使用者決策的對話框，最典型的是 VLC 的「Privacy and Network Access Policy」：&lt;/p>
&lt;p>VLC 聲明自己不蒐集、不傳輸任何個人資料，但它能自動向第三方網路服務抓取播放清單裡媒體的中繼資料（封面圖、曲名、演出者）——這個行為等於把「你在播哪些檔案」暴露給第三方服務，所以 VLC 開發者要求使用者明示同意（Allow metadata network access 勾選框、預設勾選）後才允許自動連網。&lt;/p>
&lt;p>這個對話框的判讀是用途導向：拿 VLC 播本機影片、看下載的影片檔，中繼資料抓取沒有用處、取消勾選讓播放器完全離線工作；拿它管理音樂庫、想要自動補封面跟曲目資訊，才需要同意。同意與否都能在偏好設定（Privacy / Network Interaction）事後改。&lt;/p>
&lt;p>首跑對話框對自動化流程有一層額外影響：無人值守安裝驗證時，應用會停在對話框等輸入、腳本側只看到「程式起了但沒繼續」。VLC 把這兩個決策記在 &lt;code>~/.config/vlc/vlcrc&lt;/code> 的 &lt;code>qt-privacy-ask&lt;/code> 與 &lt;code>metadata-network-access&lt;/code> 兩個鍵——首跑後檔案才生成，而且 VLC 退出時會整檔重寫（幾千行的完整設定 dump），把它納入 dotfile 版控會持續產生無意義的 diff，比較合理的處理是讓首跑對話框留給人、或在自動化腳本裡預先寫入只含這兩鍵的最小 vlcrc。&lt;/p>
&lt;p>同型的首跑決策也出現在瀏覽器（預設瀏覽器詢問、錯誤回報同意）跟大型 GUI 應用（遙測同意）。它們的共通判讀：對話框問的是「要不要讓程式自動連外 / 回傳資料」，答案取決於這台機器的用途與隱私要求，安裝驗證流程要把「首跑會有互動」納入預期、不是當成故障。&lt;/p>
&lt;h2 id="播放驗證鏈三個權威位置">播放驗證鏈：三個權威位置&lt;/h2>
&lt;p>「有沒有真的在播」的驗證不靠肉眼跟喇叭，三個權威位置各管一段：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>驗證對象&lt;/th>
 &lt;th>權威來源&lt;/th>
 &lt;th>工具與判準&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>視窗存在&lt;/td>
 &lt;td>compositor 的視窗表&lt;/td>
 &lt;td>&lt;code>hyprctl clients&lt;/code> 有該應用的 class 條目&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>音訊真的在出&lt;/td>
 &lt;td>音訊伺服器 graph&lt;/td>
 &lt;td>&lt;code>wpctl status&lt;/code> Streams 段有該應用的 stream 且 &lt;code>[active]&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>失敗的原因&lt;/td>
 &lt;td>程式自己的 log&lt;/td>
 &lt;td>&lt;code>vlc --verbose=2&lt;/code>、瀏覽器 &lt;code>--enable-logging=stderr&lt;/code>&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>把「管線通不通」跟「應用會不會播」拆開驗證能大幅縮短歸因：先用本機音檔 &lt;code>pw-play &amp;lt;file&amp;gt;&lt;/code> 打通音訊路徑（stream 出現 &lt;code>[active]&lt;/code> 代表 guest 側無誤），再測應用層；應用層失敗就跟管線無關，往解碼器、DRM、應用 log 查。串流再多拆一層：先用無 DRM 的串流（一般影音網站）確立網路串流基線，DRM 內容（Spotify、Netflix 類）的失敗才能歸因到 DRM 層——DRM 在非 x86_64 架構的可用性判讀見 &lt;a href="../platform-divergence-map/">平台與發行版差異的判讀地圖&lt;/a> 的套件存在性段。&lt;/p>
&lt;h2 id="vm-特有硬體解碼回退">VM 特有：硬體解碼回退&lt;/h2>
&lt;p>在 VM 裡播放影片，第一次開檔常會閃一個錯誤對話框（&lt;code>failed to create video output&lt;/code>）然後正常播放——這是硬體解碼回退的痕跡：播放器預設先嘗試硬體加速解碼（VDPAU / VAAPI），虛擬 GPU（如 virtio-gpu）沒有視訊解碼能力，嘗試失敗後回退軟體解碼重建輸出。log 上的特徵是一次性的 decoder error 加上之後穩定的 &lt;code>avcodec decoder&lt;/code> 軟體解碼行；實體機器有 GPU 解碼時不會出現。VM 裡想要乾淨啟動，在播放器偏好設定停用 hardware-accelerated decoding 即可——這是機器特性設定，適合留在該機器本機、不進共用 dotfile。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>套件在這個平台 / 架構存不存在、名字叫什麼：&lt;a href="../platform-divergence-map/">平台與發行版差異的判讀地圖&lt;/a>&lt;/li>
&lt;li>音訊、行程、服務狀態的權威判讀：&lt;a href="../../debug/">Linux 除錯與診斷&lt;/a>&lt;/li>
&lt;li>GUI 應用清單怎麼進 bootstrap：&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八：Bootstrap script 設計&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>GUI 應用的安裝驗證跟 CLI 工具走不同的判讀鏈：CLI 工具裝完 <code>command -v</code> 加一次試跑就能定案，GUI 應用則有三個 CLI 沒有的失敗層——依賴鏈拆包（裝了本體、缺功能模組）、首跑同意對話框（程式要求使用者決策才繼續）、播放輸出鏈（視窗有了、聲音或畫面沒有）。這三層都有各自的權威判讀位置，本篇以一輪 VM 實測（檔案管理器、瀏覽器、媒體播放器、音樂串流）把它們走一遍。</p>
<h2 id="拆包生態裝了本體不等於裝了功能">拆包生態：裝了本體不等於裝了功能</h2>
<p>發行版為了控制依賴體積，會把一個應用的核心跟功能模組拆成多個套件，預設只裝核心。這個設計讓「安裝成功」跟「功能可用」變成兩件事，而缺件的症狀往往是靜默的：</p>
<ul>
<li><strong>VLC 的解碼器是獨立 plugin</strong>：Arch 的 <code>vlc</code> 本體開得起來、UI 完整，播 H.264 影片卻回報 <code>Codec 'h264' is not supported</code>——解碼能力在 <code>vlc-plugin-ffmpeg</code>（或整組 <code>vlc-plugins-all</code>）。judgment 訊號是「應用正常啟動、特定格式失敗」，權威來源是應用自己的 log（<code>vlc --verbose=2</code>）。</li>
<li><strong>pipewire 的 session manager 是獨立套件</strong>：<code>pipewire</code> 常被依賴鏈拉進來，但沒有 <code>wireplumber</code> 就沒有人建立音訊 graph——daemon 在跑、<code>wpctl status</code> 的 Sinks 段是空的、所有應用無聲且不報錯。補 <code>wireplumber</code> + <code>pipewire-pulse</code>（多數 GUI 應用走 PulseAudio API）後輸出裝置立即出現。</li>
<li><strong>optional dependency 不會自動安裝</strong>：套件宣告的 optdepends 是「裝了會多什麼功能」的提示、不是安裝動作。影片縮圖、壓縮格式支援、硬體加速常落在這層，<code>pacman -Qi &lt;pkg&gt;</code> 的 Optional Deps 段列出哪些沒裝。</li>
</ul>
<p>判讀原則：GUI 應用「開得起來但某個功能不動」時，先查發行版有沒有把那個功能拆成獨立套件，再懷疑設定或相容性。</p>
<h2 id="首跑同意對話框程式在等使用者決策">首跑同意對話框：程式在等使用者決策</h2>
<p>不少 GUI 應用第一次啟動會彈出需要使用者決策的對話框，最典型的是 VLC 的「Privacy and Network Access Policy」：</p>
<p>VLC 聲明自己不蒐集、不傳輸任何個人資料，但它能自動向第三方網路服務抓取播放清單裡媒體的中繼資料（封面圖、曲名、演出者）——這個行為等於把「你在播哪些檔案」暴露給第三方服務，所以 VLC 開發者要求使用者明示同意（Allow metadata network access 勾選框、預設勾選）後才允許自動連網。</p>
<p>這個對話框的判讀是用途導向：拿 VLC 播本機影片、看下載的影片檔，中繼資料抓取沒有用處、取消勾選讓播放器完全離線工作；拿它管理音樂庫、想要自動補封面跟曲目資訊，才需要同意。同意與否都能在偏好設定（Privacy / Network Interaction）事後改。</p>
<p>首跑對話框對自動化流程有一層額外影響：無人值守安裝驗證時，應用會停在對話框等輸入、腳本側只看到「程式起了但沒繼續」。VLC 把這兩個決策記在 <code>~/.config/vlc/vlcrc</code> 的 <code>qt-privacy-ask</code> 與 <code>metadata-network-access</code> 兩個鍵——首跑後檔案才生成，而且 VLC 退出時會整檔重寫（幾千行的完整設定 dump），把它納入 dotfile 版控會持續產生無意義的 diff，比較合理的處理是讓首跑對話框留給人、或在自動化腳本裡預先寫入只含這兩鍵的最小 vlcrc。</p>
<p>同型的首跑決策也出現在瀏覽器（預設瀏覽器詢問、錯誤回報同意）跟大型 GUI 應用（遙測同意）。它們的共通判讀：對話框問的是「要不要讓程式自動連外 / 回傳資料」，答案取決於這台機器的用途與隱私要求，安裝驗證流程要把「首跑會有互動」納入預期、不是當成故障。</p>
<h2 id="播放驗證鏈三個權威位置">播放驗證鏈：三個權威位置</h2>
<p>「有沒有真的在播」的驗證不靠肉眼跟喇叭，三個權威位置各管一段：</p>
<table>
  <thead>
      <tr>
          <th>驗證對象</th>
          <th>權威來源</th>
          <th>工具與判準</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>視窗存在</td>
          <td>compositor 的視窗表</td>
          <td><code>hyprctl clients</code> 有該應用的 class 條目</td>
      </tr>
      <tr>
          <td>音訊真的在出</td>
          <td>音訊伺服器 graph</td>
          <td><code>wpctl status</code> Streams 段有該應用的 stream 且 <code>[active]</code></td>
      </tr>
      <tr>
          <td>失敗的原因</td>
          <td>程式自己的 log</td>
          <td><code>vlc --verbose=2</code>、瀏覽器 <code>--enable-logging=stderr</code></td>
      </tr>
  </tbody>
</table>
<p>把「管線通不通」跟「應用會不會播」拆開驗證能大幅縮短歸因：先用本機音檔 <code>pw-play &lt;file&gt;</code> 打通音訊路徑（stream 出現 <code>[active]</code> 代表 guest 側無誤），再測應用層；應用層失敗就跟管線無關，往解碼器、DRM、應用 log 查。串流再多拆一層：先用無 DRM 的串流（一般影音網站）確立網路串流基線，DRM 內容（Spotify、Netflix 類）的失敗才能歸因到 DRM 層——DRM 在非 x86_64 架構的可用性判讀見 <a href="../platform-divergence-map/">平台與發行版差異的判讀地圖</a> 的套件存在性段。</p>
<h2 id="vm-特有硬體解碼回退">VM 特有：硬體解碼回退</h2>
<p>在 VM 裡播放影片，第一次開檔常會閃一個錯誤對話框（<code>failed to create video output</code>）然後正常播放——這是硬體解碼回退的痕跡：播放器預設先嘗試硬體加速解碼（VDPAU / VAAPI），虛擬 GPU（如 virtio-gpu）沒有視訊解碼能力，嘗試失敗後回退軟體解碼重建輸出。log 上的特徵是一次性的 decoder error 加上之後穩定的 <code>avcodec decoder</code> 軟體解碼行；實體機器有 GPU 解碼時不會出現。VM 裡想要乾淨啟動，在播放器偏好設定停用 hardware-accelerated decoding 即可——這是機器特性設定，適合留在該機器本機、不進共用 dotfile。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>套件在這個平台 / 架構存不存在、名字叫什麼：<a href="../platform-divergence-map/">平台與發行版差異的判讀地圖</a></li>
<li>音訊、行程、服務狀態的權威判讀：<a href="../../debug/">Linux 除錯與診斷</a></li>
<li>GUI 應用清單怎麼進 bootstrap：<a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">模組八：Bootstrap script 設計</a></li>
</ul>
]]></content:encoded></item></channel></rss>